You can’t use Enumerable#map to look up the same value from each element an array of
hashes using the &:method_name shortcut:
# INVALID:
[{a:'bar', b:'world'}, {a:'baz', b:'boston'}].map &:[:a]
But you can get around this by adding a #to_proc method to String. You can write this new #to_proc method so that
you use pass &”key” to the enumerator to look up a value by the key.
res = [{a:'bar', b:'world'}, {a:'baz', b:'boston'}].map &":a"
puts res.inspect
#=> ["bar", "baz"]
Compare to what you have to write otherwise:
res = [{a:'bar', b:'world'}, {a:'baz', b:'boston'}].map {|x| x[:a]}
Here is how you would patch the String class to make this work:
class String
def to_proc
->(x) { x.send :[], (self[0] == ':' ? self[1..-1].to_sym : self) }
end
end
Note that this will
only work with hashes with string or symbol keys.
My question: Is this safe to do and OK as far as good Ruby practices go? It’s
a rather global change, but I’m not aware of any side effects this could have,
and it would arguably make my code more concise in a lot of places.
Instead of using hashes, consider using OpenStruct:
You pay the price up front by having to wrap hashes in OpenStruct, but later use becomes easier, and without the potentially confounding effects of amending the behavior of base classes.
If the hashes have behavior, consider making them regular ol’ classes.