Strange behavior with define_method and the wrong number of arguments
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.