动态扩展ruby中的现有方法或重写send方法

动态扩展ruby中的现有方法或重写send方法,ruby,metaprogramming,Ruby,Metaprogramming,假设我们有A、B、C班 A def self.inherited(sub) # meta programming goes here # take class that has just inherited class A # and for foo classes inject prepare_foo() as # first line of method then run rest of the code end def prepare_foo # =

假设我们有A、B、C班

A
 def self.inherited(sub)
   # meta programming goes here
   # take class that has just inherited class A
   # and for foo classes inject prepare_foo() as 
   # first line of method then run rest of the code
 end

 def prepare_foo
   # => prepare_foo() needed here
   # some code
 end

end

B < A
  def foo
    # some code
  end
end

C < A
  def foo
    # => prepare_foo() needed here
    # some code
  end
end
A
def自我继承(sub)
#这里是元编程
#以刚继承了类A的类为例
#对于foo类,将prepare_foo()作为
#方法的第一行,然后运行其余代码
结束
def准备好了吗
#=>此处需要准备_foo()
#一些代码
结束
结束
B此处需要准备_foo()
#一些代码
结束
结束
正如您所看到的,我正在尝试将
foo\u prepare()
调用注入到每个
foo()
方法中

如何做到这一点

另外,我一直在考虑在
class A
中重写
send
类,这样我就可以运行
foo\u prepare
,而不是让
send
(super)来完成该方法的其余部分


你们认为,解决这个问题的最佳方法是什么?

这里有一个解决方案。虽然它基于模块包含,而不是从类继承,但我希望您仍然会发现它很有用

module Parent
  def self.included(child)
    child.class_eval do
      def prepare_for_work
        puts "preparing to do some work"
      end
  
      # back up method's name
      alias_method :old_work, :work
  
      # replace the old method with a new version, which has 'prepare' injected
      def work
        prepare_for_work
        old_work
      end
    end
  end
end

class FirstChild
  def work
    puts "doing some work"
  end

  include Parent # include in the end of class, so that work method is already defined.
end

fc = FirstChild.new
fc.work
# >> preparing to do some work
# >> doing some work
我推荐解决方案(已被接受)。以下是我所做的符合我需要的事情

class A
  def send(symbol,*args)
    # use array in case you want to extend method covrage
    prepare_foo() if [:foo].include? symbol
    __send__(symbol,*args)
  end
end


从Ruby 2.0开始,您可以使用“prepend”简化Sergio的解决方案:

module Parent
  def work
    puts "preparing to do some work"
    super
  end
end

class FirstChild
  prepend Parent

  def work
    puts "doing some work"
  end
end

fc = FirstChild.new
fc.work

这允许模块重写类的方法,而不需要alias_方法。

非常感谢非常干净的oop解决方案。我使用了更简单的修复方法,但我将大胆地在未来记住这一点。
module Parent
  def work
    puts "preparing to do some work"
    super
  end
end

class FirstChild
  prepend Parent

  def work
    puts "doing some work"
  end
end

fc = FirstChild.new
fc.work