Last Updated: February 25, 2016
·
3.363K
· alxndr

lambdas in ruby case (switch)

A little class that has code and message attributes (ignore the bizarre HTML link, I can't prevent Markdown from putting it in?):

class Response
  attr :code, :message
  def initialize(c, m)
    @code, @message = c, m # the <a> should not be here...
  end
end

...and a method that analyzes those attributes. The interesting part is in a case, where two of the whens use some local methods that return lambdas:

def analyze(resp)
  def code_is(c)
    lambda { |r| r.code == c }
  end

  def message_is(m)
    lambda { |r| r.message == m }
  end

  case resp
  when code_is(200)
    "we are good to go"
  when message_is("Not Modified")
    "not a 200, but it's okay anyway"
  else
    "uh oh, we got a problem... #{resp.inspect}"
  end
end

Now let's see it in action:

response = Response.new(200, "whatever")
puts "first up", analyze(response), ""

response = Response.new(300, "Not Modified")
puts "next", analyze(response), ""

response = Response.new(404, "No Way")
puts "and finally", analyze(response)

This works because the whens do a ===, which lambdas/Procs use to run themselves.

More: http://www.aimred.com/news/developers/2008/08/14/unlocking_the_power_of_case_equality_proc/

3 Responses
Add your response

Another way of doing this would be to set constants to lambdas and use them as matchers, such as this:

SUCCESS = ->(response) { response.code == 200 }
NOT_MODIFIED =->(response) { response.message == 'Not Modified' }

case response
when SUCCESS then "we are good to go"
when NOT_MODIFIED then "not a 200, but it's okay anyway"
else
  "uh oh, we got a problem... #{response.inspect}"
end
over 1 year ago ·

@brickattack Yeah, very nice!

over 1 year ago ·

So the point is you don't need lambda.call because the === operator (which is what gets called by the case statement under the hood) invokes that on the lambda by default?

over 1 year ago ·