The Enumerable mixin’s #map/#collect methods are fantastic for mutating the values in an array but have an inconsistent behavior when applied to a hash. So since using #map/#collect on an array gives you this:
you might expect the hash to behave something like this:
but instead you get:
SyntaxError: (irb):1: syntax error, unexpected ':', expecting '}'
You can get around this by wrapping your key-value pair in curly braces
but now you have an array of key-value pairs which still is not the behavior that we are shooting for.
Pretty straight forward if you have seen inject, right? The hash (creatively called hash inside the block) acts as a collector. Passing a key-value pair into the #merge method called on the collector hash essentially says ‘Hey, Ruby! Here’s a hash with one key-value pair to merge into #inject’s collector!’ Then the merged hash is passed back to #inject to be the collector for the next key-value pair.
But that’s odd…
The weird bit is between the pipes. What’s going on there?
So the pair is passed into the block as an array containing the key and value as separate elements. By replacing
we match up
k to the first value in the array and
v to the second value in the array through Multiple Assignment along the lines of:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
So, inside the block we tell Ruby to make
1 2 3
then recreate the key-value pair with some sort of mapping executed on the key or value (or maybe even both)
k => v*v and merge them into the collector hash
hash.merge( k=> v*v ) and then let inject do its' thing and return the collector hash.
Vois là! You’ve built a more semantic Hash#map. Don’t go monkey-patching anything. Maybe try a refinement instead?