Hello,
I'm writing a method that builds rss and atom feeds and I've noticed
something strange when I try updating the content array by using a map.
I’m new to ruby and must confess that I don’t know how array maps work
so well.
I am formatting some of the rss content array by updating it’s contents
w/ a map like so:
@entities = Space.find :all
@new_entities = @entities.map do |entity|
open_closed = entity.complete? ? "[x] " : "[ ] "
entity.title = open_closed + entity.title
entity.title += (' due on ' + local_date_time(entity.due_on)) if
entity.due_on
entity.title += " (#{entity.status_title})"
end if @entities
then when I try to use the @new_entities array in the feed, I get an
error
for entity in @new_entities #-->>error!
xml.item do
xml.title(entity.title)
xml.description(entity.description)
xml.pubDate(entity.date.strftime("%a, %d %b %Y %H:%M:%S %z"))
xml.link("http://www.recentrambles.com/pragmatic/view/" +
entity.id.to_s)
xml.guid("http://www.recentrambles.com/pragmatic/view/" +
entity.id.to_s)
end
end
but, if I use the original @entities array it works perfectly
for entity in @entities #-->>works!
xml.item do
xml.title(entity.title)
xml.description(entity.description)
xml.pubDate(entity.date.strftime("%a, %d %b %Y %H:%M:%S %z"))
xml.link("http://www.recentrambles.com/pragmatic/view/" +
entity.id.to_s)
xml.guid("http://www.recentrambles.com/pragmatic/view/" +
entity.id.to_s)
end
end
How, exactly, is that @entities array getting updated by the map?
Thanks for your help!
2 things are going on here
- i don’t believe you are getting back what you think you are getting
back from .map
- the entity you are working with in your block is the actual entity,
not a copy. so you are basically overwriting your original array of
entities
.map returns a new array based on whatever it is you do in within the
block
[1,2,3].map { |x| x*3 } #=> [3,6,9]
in your case the last statement in the block is
entity.title += " (#{entity.status_title})"
so your block is going to return whatever that evaluates to, not the
entity object you are expecting.
in addition, your block is actually overwriting all the values of the
@entities objects you are passing in. if you were to compare the
titles of the @entities objects before and then after .map is called,
you’re going to see that they are different.
ex:
class Thing
attr_accessor :foo
end
a = Thing.new
a.foo = “abc”
b = Thing.new
b.foo = “xyz”
x = [a,b].map { |c| c.foo += " modified" }
a.foo # => “abc modified”
b.foo # => “xyz modified”
x = [“abc modified”, “xyz modified”] # you expected this to be an
array of Thing objects
if you do want to overwrite the attributes of your objects, just use
.each
@entities.each do |entity|
…
end
Chris,
Thanks for your help - this is great.
Ruby does things I never expect - in the best of ways.
Cheers!
Chris H. wrote:
2 things are going on here
- i don’t believe you are getting back what you think you are getting
back from .map
- the entity you are working with in your block is the actual entity,
not a copy. so you are basically overwriting your original array of
entities
.map returns a new array based on whatever it is you do in within the
block
[1,2,3].map { |x| x*3 } #=> [3,6,9]
in your case the last statement in the block is
entity.title += " (#{entity.status_title})"
so your block is going to return whatever that evaluates to, not the
entity object you are expecting.
in addition, your block is actually overwriting all the values of the
@entities objects you are passing in. if you were to compare the
titles of the @entities objects before and then after .map is called,
you’re going to see that they are different.
ex:
class Thing
attr_accessor :foo
end
a = Thing.new
a.foo = “abc”
b = Thing.new
b.foo = “xyz”
x = [a,b].map { |c| c.foo += " modified" }
a.foo # => “abc modified”
b.foo # => “xyz modified”
x = [“abc modified”, “xyz modified”] # you expected this to be an
array of Thing objects
if you do want to overwrite the attributes of your objects, just use
.each
@entities.each do |entity|
…
end