Reputation: 11
I'm struggling with a ruby loop. I have a set of 102 items pulled from a website captured in strings. In those strings are listed characteristics about that item. I want to parse the string and put some of the item characteristics into a hash. Each hash is meant to be an instance of my Item Class. The code below kinda works (meaning it doesn't), in that it does create SOME Item class objects in the manner expected. But it doesn't capture all 102. Instead it seems to capture only a subset. I think it is overwriting some earlier iterations. I'm stumped. I'm a novice and this is the hardest project I've taken on, so all advice welcome and appreciated!
Here's my class definition, kept in a separate file pulled in by require_relative:
class Item
attr_accessor :char1, :char2, :char4, :char6, :char8, :char10, :char11
def initialize(args)
@char2 = args[:char2]
@char1 = args[:char1]
@char4 = args[:char4]
@char6 = args[:char6] || 4
@char8 = args[:char8]
@char10 = args[:char10]
end
Running my script file in IRB, I get:
2.6.3 :028 > @item_cards.count
=> 102
2.6.3 :030 > @item_cards.first.text
=> "42\Characteristic1\Characteristic2\Characteristic3\Characteristic4\Characteristic1\Characteristic5\Characteristic6\Characteristic7\Characteristic8\Characteristic9\Characteristic10\"
Then I parse that string for the characteristics I care about, put them into an array, and then try use that array to build an object in my Item class.
def factory
@item_cards.each do |x|
s = x.text
arry = {
:char2 => s.split(%'\')[2].strip,
:char1 => s.split(%'\')[1].strip,
:char4 => s.split(%'\')[4].strip,
:char6 => s.split(%'\')[6].strip,
:char8 => s.split(%'\')[8].strip,
:char10 => s.split(%'\')[10].strip,
}
@item = Item.new(char2: arry[:char2], char1: arry[:char1], char4:
arry[:char4], char6: arry[:char6], sqft: char8[:char8], char10:
arry[:char10])
puts "** here is the new Item CLASS object #{@item.inspect}"
puts "*** there are #{Item.count} Item Objects now"
puts "*** Against this many @item_cards #{@item_cards.count}"
puts "*** end of this iteration of loop ***"
end
puts "********** OUT OF THE LOOP NOW **********"
puts "There are this many Item objects: #{Item.all.count}"
end
During each iteration of the loop, it looks to me that (1) the text is parsing correctly, and (2) that data is properly captured in the @item variable. However, sometimes the #{Item.count} ticker doesn't increase. E.g., it will create the third Item object with the characteristics of the that item, but then seems to overwrite the third Item object with the fourth. Yet other Item objects are created correctly. The final result is a smaller number of Item objects than would be suggested by the number of @item_cards originally captured (i.e, less than 102).
When I run the factory command in IRB, this is what I get at the end, having skipped or overwritten 30 items by the time it gets to the end:
here is the initial array {#parsing correctly for item 71}
*** And here is the New Item CLASS object #<Item:0x00007f96c25162c8 @char2="Item 71's Char2", @char1="Item 71's Char1", "#and so on...">
*** there are 71 Item Objects now
*** Against this many @item_cards 102
*** end of this iteration of loop ***
Return value is: nil
here is the initial array {#parsing correctly for item 72}
*** And here is the New Item CLASS object #<Item:0x00007f96c454a6c0 @char2="Item 72's Char 2", @char1="Item 72's Char 1", #and so on...>
*** there are 71 Item Objects now
*** Against this many @item_cards 102
*** end of this iteration of loop ***
Return value is: nil
#then process repeats, working correctly to create new Item object.
*** there are 72 Item Objects now
*** Against this many @item_cards 102
*** end of this iteration of loop ***
Return value is: nil
********** OUT OF THE LOOP NOW **********
There are this many Item objects: 72
Return value is: nil
I hope that is clear, if not concise. Very much a novice so all input/correction is welcome.
Upvotes: 1
Views: 117
Reputation: 121000
Array#each
just iterates the collection. You, on contrary, need to map the input to some data, returned by your parsing. That said, something like the below would work.
def factory
@items = # an array of items!
@item_cards.map do |x|
...
Item.new(...) # should be the last line in a loop
end
# @items contains the array of `Item` objects now
end
Upvotes: 0
Reputation: 6445
Your issue is you're only initializing a new Item object with certain attributes, you're not saving it to the database. Every time you do @item = Item.new
, you're overwriting the previous version of @item
. Changing new
to create
should solve your issue, assuming your Item
passes validation:
def factory
@item_cards.each do |x|
s = x.text
arry = {
:char2 => s.split(%'\')[2].strip,
:char1 => s.split(%'\')[1].strip,
:char4 => s.split(%'\')[4].strip,
:char6 => s.split(%'\')[6].strip,
:char8 => s.split(%'\')[8].strip,
:char10 => s.split(%'\')[10].strip,
}
@item = Item.create( # <-- Change this bit here
char2: arry[:char2],
char1: arry[:char1],
char4: arry[:char4],
char6: arry[:char6],
sqft: char8[:char8],
char10: arry[:char10]
)
puts "** here is the new Item CLASS object #{@item.inspect}"
puts "*** there are #{Item.count} Item Objects now"
puts "*** Against this many @item_cards #{@item_cards.count}"
end
puts "********** OUT OF THE LOOP NOW **********"
puts "There are this many Item objects: #{Item.all.count}"
end
Upvotes: -1