问题
I want to create a class method that takes a block of method definitions and injects it into the class. Now, self
is indeed the Tom
object so class << self
does open it up, but yield
doesn't seem to work. My theoretical knowledge is not that deep, so I am not sure why this is not working. I might be getting this totally wrong, so feel free to discuss alternatives.
class Tom < Person
mega_methods do
def hiya!
puts 'hiYA!'
end
end
end
class Person
def self.mega_methods
...
class << self
yield
end
end
end
Tom.hiya!
I am aware I could just define the methods in Tom
using class << self
or that I could include class << self
in the block.
I also figured out this alternative:
def self.mega_methods &block
if block_given?
extension = Module.new(&Proc.new)
self.extend(extension)
end
end
This question is more about helping me understand the workings of Ruby rather than solving a specific issue.
回答1:
It's a little bit weird, but OK if you are exploring Ruby.
class Person
puts "evaluating Person's body ..."
def self.mega_methods
puts 'in Person#self.mega_methods, about to yield ...'
yield
end
end
class Tom < Person
puts "evaluating Tom's body ..."
print 'Tom.singleton_methods : '; p Tom.singleton_methods
mega_methods do
puts 'in Tom, about to define self.hiya!'
def self.hiya!
puts 'hiYA!'
end
end
print 'Tom.singleton_methods : '; p Tom.singleton_methods
end
Tom.hiya!
Execution :
$ ruby -w t.rb
evaluating Person's body ...
evaluating Tom's body ...
Tom.singleton_methods : ["mega_methods"]
in Person#self.mega_methods, about to yield ...
in Tom, about to define self.hiya!
Tom.singleton_methods : ["mega_methods", "hiya!"]
hiYA!
Note that the exclamation point in the name of a method is, by convention, reserved for destroying methods, such as String#sub!
which modifies the receiver string.
See also What does def `self.function` name mean?
It's all about self !
class Person2
def self.mega_methods
print 'in Person2 self='; p self
class << self
print 'in class << self self='; p self
yield
end
end
end
class Tom2 < Person2
mega_methods do
puts "in Tom2, about to define self.hiya! for self=#{self}"
def self.hiya!
puts 'hiYA!'
end
def hi
puts 'hi'
end
end
end
print 'Tom2.singleton_methods : '; p Tom2.singleton_methods
print 'Tom2.instance_methods : '; p Tom2.instance_methods(false)
Tom2.hiya!
Tom2.new.hi
Execution :
$ ruby -w t2.rb
in Person2 self=Tom2
in class << self self=#<Class:Tom2>
in Tom2, about to define self.hiya! for self=Tom2
Tom2.singleton_methods : ["mega_methods", "hiya!"]
Tom2.instance_methods : ["hi"]
hiYA!
hi
来源:https://stackoverflow.com/questions/14547516/yield-in-class-self-in-class-method