tags:

views:

697

answers:

2

I'm trying to dynamically define functions that call through to another function that takes an options parameter:

class MyClass
    ["hour", "minute", "second"].each do |interval|
        define_method "get_#{interval}" do |args|
           some_helper(interval, args)
        end
    end
    def some_helper(interval, options={})
        # Do something, with arguments
    end
end

I'd like to be able to call the different methods on MyClass in these two ways (with and without optional arguments):

mc = MyClass.new
mc.get_minute( :first_option => "foo", :second_option => "bar")
mc.get_minute  # This fails with: warning: multiple values for a block parameter (0 for 1)

On the second call to minute, I see this warning:

warning: multiple values for a block parameter (0 for 1)

  1. Is there a way to write the block for the "get_*" method so that this warning won't come up?
  2. Am I abusing define_method?
+9  A: 

The only change you need to make is to change args to *args. The * indicates that args will contain an array of optional arguments to the block.

Gordon Wilson
Thanks for pointing that out!
Readonly
+1  A: 

I agree with Gordon adding * to your args will make it go away.

Another way of doing this is to use method_missing()

Something like this:

class MyClass

  def method_missing(m, *args)  
    if /get_(.+)/.match(m.to_s)
      some_helper($1, args) 
    else
      raise 'Method not found...'
    end
  end  

  def some_helper(interval, *args)
    puts interval + ' -> ' + args.inspect
  end

end

m = MyClass.new
m.get_minute( :first_option => "foo", :second_option => "bar" )
stjernstrom
I'd rather call 'super' in method missing instead of 'raise' so it will perform a default Ruby action when method is really missing.
Priit