rubyhashbranchcase-statement

Ruby case statement on a hash?


This is going to sound weird, but I would love to do something like this:

case cool_hash
  when cool_hash[:target] == "bullseye" then do_something_awesome
  when cool_hash[:target] == "2 pointer" then do_something_less_awesome
  when cool_hash[:crazy_option] == true then unleash_the_crazy_stuff
  else raise "Hell"
end

Ideally, I wouldn't even need to reference the has again since it's what the case statement is about. If I only wanted to use one option then I would "case cool_hash[:that_option]", but I'd like to use any number of options. Also, I know case statements in Ruby only evaluate the first true conditional block, is there a way to override this to evaluate every block that's true unless there is a break?


Solution

  • in ruby 3.0 you can do the following with pattern matching

    # assuming you have these methods, ruby 3 syntax
    def do_something_awesome = "something awesome 😎"
    def do_something_less_awesome = "something LESS awesome"
    def unleash_the_crazy_stuff = "UNLEASH the crazy stuff 🤪"
    

    you can do

    def do_the_thing(cool_hash)
      case cool_hash
      in target: "bullseye" then do_something_awesome
      in target: "2 pointer" then do_something_less_awesome
      in crazy_option: true then unleash_the_crazy_stuff
      else raise "Hell"
      end
    end
    

    will return

    do_the_thing(target: "bullseye")
    => "something awesome 😎"
    
    do_the_thing(target: "2 pointer")
    => "something LESS awesome"
    
    do_the_thing(crazy_option: true)
    => "UNLEASH the crazy stuff 🤪"
    

    in ruby 2.7 it still works

    # need to define the methods differently
    def do_something_awesome; "something awesome 😎"; end
    def do_something_less_awesome; "something LESS awesome"; end
    def unleash_the_crazy_stuff; "UNLEASH the crazy stuff 🤪"; end
    
    # and when calling the code above to do the switch statement
    # you will get the following warning
    warning: Pattern matching is experimental, and the behavior may change
             in future versions of Ruby!