In Progress
Unit 1, Lesson 1
In Progress

# Hash To Proc

Video transcript & code

Today's theme is a grocery store setting. We're writing software for a point-of-sale system, and we need an easy way to price food as it comes in off of the conveyor belt.

Accordingly, we have a pricing hash, which maps food types to prices in cents..

``````PRICING = {
"milk"   => 3_82,
"eggs"   => 2_97,
"juice"  => 2_98,
"cheese" => 6_00,
}
``````

Let's say we have a belt full of food, waiting to be scanned and bagged.

To get a price for items, we can use the `#map` method. We give it a block, which takes each item and looks it up in the pricing map.

``````require "./pricing"

belt = %w[ juice eggs milk bread eggs cheese juice milk bread ]

belt.map{|item| PRICING[item]}
# => [298, 297, 382, 230, 297, 600, 298, 382, 230]
``````

An interesting fact about associative array data structures, such as Ruby hashes, is that they can also be seen as a function. That is, they are a function which, given a key, returns a value.

In Ruby we can already apply procs and lambdas as if they were hashes. Here's a lambda that behaves just like our pricing hash.

We can "look up" items in this lambda using the square bracket operator, and get prices in return. This works because the square brackets are aliased to the `#call` method for procs and lambdas.

``````pricing = ->(item){
case item
when "milk" then 3_82
when "eggs" then 2_97
when "juice" then 2_98
when "cheese" then 6_00
end
}

pricing["juice"]                # => 298
``````

…so why can't we turn things around? Why can't we treat hashes as if they were procs?

Well in Ruby 2.3, we finally can. Instead of passing a block, we can just pass the `PRICING` hash with an ampersand in front of it, the same as we would with any other proc or proc-convertible object. The result is exactly the same as we got with our explicit block.

``````require "./pricing"

belt = %w[ juice eggs milk bread eggs cheese juice milk bread ]

RUBY_VERSION                    # => "2.3.0"
belt.map(&PRICING)
# => [298, 297, 382, 230, 297, 600, 298, 382, 230]
``````

How is this possible? Well, in Ruby 2.3, `Hash` gains a `#to_proc` conversion method.

If we send this message to a hash, we get back a proc. We can call this proc with keys, and get back values.

``````require "./pricing"

pricer = PRICING.to_proc
# => #<Proc:0x005557fcdd0618>
pricer.call("eggs")             # => 297
pricer.call("cheese")           # => 600
``````

And of course we can do more than just map keys to values. We can use this trick to pass our hashes in lieu of blocks for many enumerable methods. For instance, remember the `#sort_by` method we learned about in episode #181?

After unique-ing the groceries, we can use our pricing hash as an ampersand-argument to `#sort_by` to sort them by price!

``````require "./pricing"
belt = %w[ juice eggs milk bread eggs cheese juice milk bread ]

belt.uniq.sort_by(&PRICING)
# => ["bread", "eggs", "juice", "milk", "cheese"]
``````

So, that's another of the small but helpful changes to look forward to in Ruby 2.3. Happy hacking!