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@(irb):1>
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@(irb):4>
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@(irb):8>
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:in `call'
        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

Yossef Mendelssohn wrote:

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?

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 Bowkett

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.

···

On Oct 10, 1:29 am, "Giles Bowkett" <gil...@gmail.com> wrote:

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 Bowkett

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

--
-yossef