rubyidiomsmethod-dispatch

Ruby: How do I invoke a function via an object reference?


Consider this contrived example:

# Dispatch on value of fruit_kind:

TYPE_A = :apple
TYPE_B = :banana
TYPE_C = :cherry

eating_method = nil

case fruit_kind
  # Methods to use for different kinds of fruit (assume these are
  #  already defined)
  when TYPE_A then eating_method = bite
  when TYPE_B then eating_method = peel
  when TYPE_C then eating_method = om_nom_nom
end

Now I'd like to invoke the target of eating_method with some arguments:

# Doesn't work; this tries to invoke a method called "eating_method",
# not the reference I defined earlier.
eating_method(some_fruit)

What's the right way to do this in Ruby?


Solution

  • Use send. Send takes the function name, so use symbols:

    case fruit_kind
      # Methods to use for different kinds of fruit (assume these are
      #  already defined)
      when TYPE_A then eating_method = :bite
      when TYPE_B then eating_method = :peel
      when TYPE_C then eating_method = :om_nom_nom
    end
    
    send(eating_method, some_fruit)
    

    EDIT:

    By the way, did you know you can make that case a little prettier by doing something like this:

    eating_method = case fruit_kind
      # Methods to use for different kinds of fruit (assume these are
      #  already defined)
      when TYPE_A then :bite
      when TYPE_B then :peel
      when TYPE_C then :om_nom_nom
      else nil
    end
    

    Or, as Sii mentions, use a hash instead:

    fruit_methods = {:apple => :bite, :banana => :peel, :cherry => :om_nom_nom}
    send(fruit_methods[fruit_kind], some_fruit)