amitkumarusc
amitkumarusc

Reputation: 872

Replace case statement with Hash in ruby

I want to replace case statement in ruby with Hash. But the Hash seems to call the default value first every time when I try to lookup for other keys in the hash.

def perform_operation_one
  puts 'Performing operation ONE'
end

def perform_operation_two
  puts 'Performing operation TWO'
end

def exit_program
  puts 'Program is exiting now'
  exit(0)
end

def perform_operation(operation_code)
  case operation_code
    when 1
      perform_operation_one
    when 2
      perform_operation_two
    else
      exit_program
  end
end

I replaced the above case statement with the Hash

def perform_operation(operation_code)
  operations = Hash.new exit_program    #Default value if no operation is present in operations corresponding to operation_code key
  operations[1] = perform_operation_one
  operations[2] = perform_operation_two
  operations[operation_code]
end

Now when I execute following:

perform_operation(2)

Expected Output:

Performing operation TWO

Current Output:

Program is exiting now

Upvotes: 0

Views: 1453

Answers (2)

Eric Duminil
Eric Duminil

Reputation: 54233

First, I think your case is fine. It's readable and might be less bug-prone than a solution with a hash.

With a hash, you could write :

def perform_operation(operation_code)
  operations = { 1 => :perform_operation_one, 2 => :perform_operation_two }
  operations.default = :exit_program
  send(operations[operation_code])
end

Since send doesn't care about method privacy, you could set exit_program, perform_operation_{one,two} as private. As a matter of fact, they're already private when defined in main.

Upvotes: 1

max pleaner
max pleaner

Reputation: 26768

The problem is this line:

operations = Hash.new exit_program

evaluates exit_program right when that line of code is reached.

What you're trying to do here is pass a method as a value, which you can do, but it's not quite as simple as say Javascript, where just typing the method name would suffice. Remember, in Ruby parenthesis are optional for method calls, so your default value ends up being the return value of the exit_program (in this case, that's undefined since the program exits).

You can lambda-fy your methods (let them be passed as values) like so:

def perform_operation(operation_code)
  operations = Hash.new(-> { exit_program })
  operations[1] = -> { input_from_file }
  operations[2] = -> { input_from_console }
  operations[operation_code].call
end

I'm basically wrapping every method in -> { } (an anonymous function / lambda). The .call is there because you specify that it's time to evaluate the lambda (calling the method).

Rather than using -> { } you could also use method(:exit_program), method(:input_from_file), etc. It converts to a proc but it's basically the same thing, you still use .call.

Upvotes: 3

Related Questions