What's wrong with my metaprogramming?

J

John Ky

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:in `method2'
from C:/wrk/johnk/wiksprint-001/define.rb:17
 
D

dblack

Hi --

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:in `method2'
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

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
M

Marcin Mielżyński

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
 
A

ara.t.howard

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:in `method2'
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
 
T

Trans

John said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
DewittMill
Top