Yield in class << self in class method

最后都变了- 提交于 2019-12-24 00:47:45

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!