使用super with class_eval

Nat*_*han 2 ruby metaprogramming

我有一个应用程序,其中包含用于添加客户端自定义的核心类的模块.

我发现class_eval是覆盖核心类中方法的好方法,但有时我想避免重写整个方法,只需遵循原始方法.

例如,如果我有一个调用的方法account_balance,那么在我的模块中执行类似这样的操作会很好(即包含在类中的模块):

module CustomClient
  def self.included base
    base.class_eval do
      def account_balance
        send_alert_email if balance < min
        super # Then this would just defer the rest of the logic defined in the original class
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

但是使用class_eval似乎将该super方法从查找路径中取出.

有谁知道如何解决这个问题?

谢谢!

Eri*_*ker 11

我认为有几种方法可以做你想做的事情.一种是打开类并为旧实现添加别名:

class MyClass
  def method1
    1
  end
end

class MyClass
  alias_method :old_method1, :method1
  def method1
    old_method1 + 1
  end
end

MyClass.new.method1
 => 2 
Run Code Online (Sandbox Code Playgroud)

这是猴子修补的一种形式,所以最好是适度使用这个成语.此外,有时需要的是一个保持常用功能的独立辅助方法.

编辑:有关更全面的选项,请参阅JörgWMittag的答案.


Jör*_*tag 9

我发现instance_eval是覆盖核心类中方法的好方法,

你不是压倒一切.你正在覆盖又名monkeypatching.

但有时我想避免重写整个方法,只需遵循原始方法.

您不能遵循原始方法.没有原创方法.你把它覆盖了.

但是使用instance_eval似乎将该super方法从查找路径中取出.

您的示例中没有继承.super甚至没有发挥作用.

有关可能的解决方案和替代方案,请参阅此答案:当猴子修补方法时,是否可以从新实现中调用重写方法?