Using define_method isn't the same as defining a method

I apologize if this has been brought up before. A cursory search
through the archives didn’t come up with anything that addressed this
same subject.

I know that creating a Proc (at least a lambda-style Proc) will do
argument checking upon call, and I realize (even though I don’t like
it) that those arguments are handled a little oddly:

irb(main):001:0> x = lambda { ‘hi’ }
=> #Proc:0x0000ec54@:1(irb)
irb(main):002:0> x.call
=> “hi”
irb(main):003:0> x.call(5)
=> “hi”
irb(main):004:0> x = lambda { |arg| p arg }
=> #Proc:0x000843a0@:4(irb)
irb(main):005:0> x.call
(irb):4: warning: multiple values for a block parameter (0 for 1)
from (irb):5
nil
=> nil
irb(main):006:0> x.call(5)
5
=> nil
irb(main):007:0> x.call(5,6)
(irb):4: warning: multiple values for a block parameter (2 for 1)
from (irb):7
[5, 6]
=> nil
irb(main):008:0> x = lambda { |arg1, arg2| ‘hello’ }
=> #Proc:0x00067674@:8(irb)
irb(main):009:0> x.call
ArgumentError: wrong number of arguments (0 for 2)
from (irb):9
from (irb):9:in call' from (irb):9 from :0 irb(main):010:0> x.call(5) ArgumentError: wrong number of arguments (1 for 2) from (irb):8 from (irb):10:incall’
from (irb):10
from :0
irb(main):011:0> x.call(5,6)
=> “hello”
irb(main):012:0> x.call(5,6,7)
ArgumentError: wrong number of arguments (3 for 2)
from (irb):8
from (irb):12:in `call’
from (irb):12
from :0

What I really don’t like is how define_method, since it takes a block,
uses this same sort of argument handling. That means

define_method :meth do |arg|
end

is the equivalent of

def meth(*arg)
end

with a warning.

If I want to create a method that takes one argument and acts like a
normal method, what are my choices? Apparently, I get to use only
‘def’ itself, but that means I need string eval if the method name is
contained in a variable.

Am I wrong? Is there a better way?

Yossef M. wrote:

with a warning.

If I want to create a method that takes one argument and acts like a
normal method, what are my choices? Apparently, I get to use only
‘def’ itself, but that means I need string eval if the method name is
contained in a variable.

Am I wrong? Is there a better way?

This may not be what you’re looking for, but if you need define_method
in order to use a variable from the outer scope, you could do something
like:
some_value = 42
define_method :meth do |*args|
_meth(some_value, *args)
end

…which would bomb if the number of args was incorrect

Daniel

Sorry, I’m kind of tired right now, plus an irb dump that big is hard
to read - kinda line-noisey - but just one tiny useful note here. At
Ruby East Ezra Z. from EngineYard did a talk on Ruby performance, and
apparently define_method :foo is slower than def foo not just in the
definition but the invocation as well.

Anyway, he also said eval was slow, which was a bummer for me, because
I do like a bit of eval now and then, but other than the slowness, why
not just use eval? Wrestling with that whole args/blocks thing looks
crazy-making and then some.


Giles B.

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
Tumblelog: http://giles.tumblr.com/

On Oct 10, 1:29 am, “Giles B.” [email protected] wrote:


Giles B.

Blog:http://gilesbowkett.blogspot.com
Portfolio:http://www.gilesgoatboy.org
Tumblelog:http://giles.tumblr.com/

It’s not something against eval, but more against string eval, which
is what I’d need if the method name is held in a variable. And
define_method is RIGHT THERE, so I thought I’d use it. The trouble
comes when you realize it’s not the same as def.

You’re right about the irb dump. I was just trying to point out the
behavior I was seeing.