Reputation: 86147
This is confusing me:
class Person
attr_accessor :id, :name
def initialize(init)
init.each_pair do |key, val|
instance_variable_set('@' + key.to_s, val)
end
end
end
@adam = Person.new(:id => 1, :name => "Adam")
@eve = Person.new(:id => 2)
@people = [ @adam, @eve, nil ]
print @people
@people.map! do |person|
person ||= Person.new(:id => 3, :name => "Some default")
if person.name.nil?
person.name = "Eve"
end
end
print @people
# outputs
# [#<Person:0x007ff184303900 @id=1, @name="Adam">, #<Person:0x007ff184303770 @id=2>, nil]
# [nil, "Some default", "Some default"]
I'd like to fully populate @people so that I end up with something along the lines of:
[#<Person:0x007ff184303900 @id=1, @name="Adam">, #<Person:0x007ff184303770 @id=2, @name="Eve">, #<Person:0x007ff184301111 @id=3, @name="Some default">]
What am I doing wrong?
Upvotes: 0
Views: 124
Reputation: 230346
What map
does is it calls the block you supplied, passes an element of a collection to it and grabs value returned from the block. In absence of explicit return
keyword, value of a block is the value of last evaluated expression. That would be the if
expression in your example. It can return either nil
or a name. And those values are mapped to the original collection. Fix is easy: just make sure that you return a Person
from the block (by evaluating it last, for example).
@people.map! do |person|
person ||= Person.new(:id => 3)
if person.name.nil?
person.name = "Some default"
end
person
end
print @people
# >> [#<Person:0x007fb5f288b288 @id=1, @name="Adam">, #<Person:0x007fb5f288b0f8 @id=2, @name="Some default">, #<Person:0x007fb5f288ae28 @id=3, @name="Some default">]
Upvotes: 2
Reputation: 867
.map! replaces each element with whatever is returned from the .map! method (which in this case is person.name). Add a "return person" at the end of your .map! method. Or do a .each instead of .map
Upvotes: 1