views:

110

answers:

3

Hey,

I have recently started a project in Ruby on Rails. I used to do all my projects before in Python but decided to give Ruby a shot.

In the projects I wrote in Python I used a nice little technique explained by the correct answer in this post:

http://stackoverflow.com/questions/277965/dictionary-or-if-statements-jython

I use this technique due to Python not having a native switch function and it also get rid of big if else blocks

I have been trying to do recreate the above method in Ruby but can't seem to quite get it.

Could anyone help me out?

Thanks

Eef

+1  A: 

While nothing prevents you from using the class-based approach, why avoid rubys case statement?

case thing
when 'something'
   do_something
when 'nothing'
   do_nothing
else
   do_fail
end
ezpz
Am I missing something with your `method_missing`? Surely the object can never respond to `call` if it reached method_missing.
glenn jackman
Indeed! Nice catch. Since I was defining the methods anyway the `method_missing` only ever triggered an exception. I will update to remove the redundant code example.
ezpz
+2  A: 

If you only need to call a method by its name stored in a string, standard Ruby way of doing it is using method Object#send:

def extractTitle dom
  puts "title from #{dom}"
end

def extractMetaTags dom
  puts "metatags from #{dom}"
end

dom = 'foo'

type = 'extractTitle'
send type, dom
#=> title from foo
type = 'extractMetaTags'
send type, dom
#=> metatags from foo

Otherwise, you can use Ruby's case statement, as already suggested.

Mladen Jablanović
you don't need the #to_sym call (send accepts both Strings and Symbols)
banister
I just wasn't sure about earlier Ruby versions. Thanks, I will update the answer now.
Mladen Jablanović
A: 

As others have said, there are alternative ways of doing this in Ruby, but if you are just curious then an equivalent to that Python approach in Ruby (making use of Object#send once you have determined the method name) would be:

class MyHandler
  def handle_test(arg)
    puts "handle_test called with #{arg}"
  end

  def handle_other(arg)
    puts "handle_other called with #{arg}"
  end

  def handle(type, *args)
    method_name = "handle_#{type}"
    if respond_to? method_name
      send(method_name, args)
    else
      raise "No handler method for #{type}"
    end
  end
end

You can then do:

h = MyHandler.new
h.handle 'test', 'example'
h.handle 'other', 'example'
h.handle 'missing', 'example'

and the output would be:

handle_test called with example
handle_other called with example
handle.rb:15:in `handle': No handler method for missing (RuntimeError)
        from handle.rb:23
mikej