I noticed the other day that methods defined using define_method have very strange behavior when given the wrong number of arguments. For example, here is a class with a bunch of methods defined using define_method:
class Foo define_method :no_args do p "no args" end define_method :one_arg do |one| p one end define_method :two_args do |one, two| p one p two end end
Now, if we call no_args with an argument, it will silently ignore the argument:
>> Foo.new.no_args(1) "no args" => nil
However, if we have a method that expects one argument but receives either none or more than one, we get a warning:
>> Foo.new.one_arg ./foo.rb:6: warning: multiple values for a block parameter (0 for 1) from (irb):3 nil => nil >> Foo.new.one_arg(1,2,3) ./foo.rb:6: warning: multiple values for a block parameter (3 for 1) from (irb):2 [1, 2, 3] => nil
In the second case, it took all three arguments and passed them as an array into the method expecting one argument.
It gets even stranger with a method that expects two arguments. Now, we actually get errors:
>> Foo.new.two_args ArgumentError: wrong number of arguments (0 for 2) from (irb):2:in 'two_args' from (irb):2 >> Foo.new.two_args(1,2,3) ArgumentError: wrong number of arguments (3 for 2) from ./foo.rb:10:in 'two_args' from (irb):3
I’m not sure why a one argument method gives a warning while a two argument method gives an error. Clearly, define_method is very different from using def.