What’s the best way to avoid the classic method_added/define_method
infinite loop?
class X
def self.method_added(name)
p name
define_method(name)
# do something else
end
end
def foo; end
end
This will, of course, print “foo” forever.
As an aside, anyone else think method_added should also receive a
block of the method definition? E.g. this would be a “push” (less the
infinite loop issue):
def self.method_added(name, &block)
define_method(name, &block)
end
cfp:~ > cat a.rb
class X
class << self
def ignoring_added_methods
ignoring_added_methods = @ignoring_added_methods @ignoring_added_methods = true
yield
ensure @ignoring_added_methods = ignoring_added_methods
end
def ignoring_added_methods?
defined? @ignoring_added_methods and @ignoring_added_methods
end
def method_added name
return if ignoring_added_methods?
ignoring_added_methods do
p name
define_method(:bar){}
end
end
As an aside, anyone else think method_added should also receive a
block of the method definition? E.g. this would be a “push” (less the
infinite loop issue):
def self.method_added(name, &block)
define_method(name, &block)
end
I might be missing something, but I cannot think of a practical use
for that. It re-defined the method with the same name and
content…Why?
I might be missing something, but I cannot think of a practical use
for that. It re-defined the method with the same name and
content…Why?
I’m impractical ?
meta-programming. In this instance, I was working on a Traits idea. I
need to rename every method defined and keep track of it and replace
it with a method that weaves together these renamed methods.
only question i have is about thread safety --could the instance var
pose a potential problem with that?
probably. maybe (untested):
cfp:~ > cat a.rb
class X
class << self
def ignoring_added_methods
ignoring_added_methods = @ignoring_added_methods @ignoring_added_methods = true
yield
ensure @ignoring_added_methods = ignoring_added_methods
end
def ignoring_added_methods?
defined? @ignoring_added_methods and @ignoring_added_methods
end
def method_added name
Thread.critical = true
return if ignoring_added_methods?
ignoring_added_methods do
p name
define_method(:bar){}
end
ensure
Thread.critical = false
end
end
def foo
end