What's wrong with my metaprogramming?

def define_my_method(method_name)
define_method method_name do
yield
end
end

class X
define_my_method :method1 do
puts “Method 1”
end
define_my_method :method2 do
puts “Method 2”
method1
end
end

X.new.method2
<<<<<

Gives:

C:\wrk\johnk\wiksprint-001>define.rb
Method 2
C:/wrk/johnk/wiksprint-001/define.rb:13: undefined local variable or
method met hod1' for X:Class (NameError) from C:/wrk/johnk/wiksprint-001/define.rb:3:inmethod2’
from C:/wrk/johnk/wiksprint-001/define.rb:17

Hi –

On Sun, 15 Oct 2006, John Ky wrote:

end

C:\wrk\johnk\wiksprint-001>define.rb
Method 2
C:/wrk/johnk/wiksprint-001/define.rb:13: undefined local variable or method
met hod1' for X:Class (NameError) from C:/wrk/johnk/wiksprint-001/define.rb:3:inmethod2’
from C:/wrk/johnk/wiksprint-001/define.rb:17

The problem is that define_method creates instance methods – in this
case, method1 and method2. In method2 you call method1… but you’re
calling it on the class object X, when you’ve defined it for
instances of X.

If you replace method1 with new.method1, in the second call to
define_my_method, you’ll see the difference.

David

John Ky wrote:

try this one:

def define_my_method(method_name,&blk)
define_method method_name, &blk
end

class X
define_my_method :method1 do
puts “Method 1”
end
define_my_method :method2 do
puts “Method 2”
method1
end
end

X.new.method2

lopex

On Sun, 15 Oct 2006, John Ky wrote:

end

C:\wrk\johnk\wiksprint-001>define.rb
Method 2
C:/wrk/johnk/wiksprint-001/define.rb:13: undefined local variable or method
met hod1' for X:Class (NameError) from C:/wrk/johnk/wiksprint-001/define.rb:3:inmethod2’
from C:/wrk/johnk/wiksprint-001/define.rb:17

you don’t want yield here as the context of that yield is bound to the
class (think of what self is at the time of call) and you want it
bould to
the instance.

harp:~ > cat a.rb
def define_my_method *a, &b
define_method *a, &b
end

class X
define_my_method :method1 do
puts “Method 1”
end
define_my_method :method2 do
puts “Method 2”
method1
end
end

X.new.method2

harp:~ > ruby a.rb
Method 2
Method 1

your metaprogramming is fine - this is an issue of blocks and scoping.

regards.

-a

John Ky wrote:

def define_my_method(method_name)
define_method method_name do
yield
end
end

Yea, funny thing about Ruby, closures go a long ways. Have a look at
what self is in one fo your definitions:

class X
define_my_method :method1 do
puts “Method 1”
end
define_my_method :method2 do
puts “Method 2”
p self
method1
end
end

X.new.method2

This is why define_method takes a block. So a fix would be:

def define_my_method(method_name, &block)
define_method method_name, &block
end

Unfortuantely that’s not always the prefect solution since you might
want to wrap extra code around the yield . In that case, you can use
#instance_eval if you don’t need to pass parameters. If you do need to
pass parameters you’ll have to use more complicated tricks until 1.9
introduces #instance_exec.

On a related note, I still think it would be helpful if we could create
clean-closure blocks.

T.