Ruby 定义;方法u称为";。。如何创建一个钩子方法,每次调用类的任何函数时都会调用它?

Ruby 定义;方法u称为";。。如何创建一个钩子方法,每次调用类的任何函数时都会调用它?,ruby,metaprogramming,hook,Ruby,Metaprogramming,Hook,我想创建一个钩子方法,每次调用类的任何函数时都会调用它。 我尝试了方法_added,但它在类定义时只执行一次 class Base def self.method_added(name) p "#{name.to_s.capitalize} Method's been called!!" end def a p "a called." end def b p "b called." end end t1 = Base.new t1.a t1.b

我想创建一个钩子方法,每次调用类的任何函数时都会调用它。 我尝试了方法_added,但它在类定义时只执行一次

class Base

  def self.method_added(name)
    p "#{name.to_s.capitalize} Method's been called!!"
  end
  def a
    p "a called."
  end
  def b
    p "b called."
  end
end
t1 = Base.new
t1.a
t1.b
t1.a
t1.b

Output:

"A Method's been called!!"
"B Method's been called!!"
"a called."
"b called."
"a called."
"b called."
但我的要求是,在程序中任何地方调用的类的任何函数都会触发“method_called”,hook方法

Expected Output:
"A Method's been called!!"
"a called."
"B Method's been called!!"
"b called."
"A Method's been called!!"
"a called."
"B Method's been called!!"
"b called."
如果有任何定义的现有钩子方法工作原理相同,那么请告诉我们

提前感谢..

看一看。它允许您指定在事件(如方法调用)发生时调用的proc。下面是一个例子:

class Base
  def a
    puts "in method a"
  end

  def b
    puts "in method b"
  end
end

set_trace_func proc { |event, file, line, id, binding, classname|
  # only interested in events of type 'call' (Ruby method calls)
  # see the docs for set_trace_func for other supported event types
  puts "#{classname} #{id} called" if event == 'call'
}

b = Base.new
b.a
b.b
产出:

Base a called
in method a
Base b called
in method b

method\u added
在类中添加了新方法后,是否可以运行代码;它不报告方法何时被调用。(正如你发现的那样。)

如果您不想遵循mikej的答案,下面是一个实现您的规范的类:

#!/usr/bin/ruby

class Base
  def self.method_added(name)
    if /hook/.match(name.to_s) or method_defined?("#{name}_without_hook")
      return
    end
    hook = "def #{name}_hook\n p 'Method #{name} has been called'\n #{name}_without_hook\nend"
    self.class_eval(hook)

    a1 = "alias #{name}_without_hook #{name}"
    self.class_eval(a1)

    a2 = "alias #{name} #{name}_hook"
    self.class_eval(a2)
  end
  def a
    p "a called."
  end
  def b
    p "b called."
  end
end
t1 = Base.new
t1.a
t1.b
t1.a
t1.b
和输出:

$ ./meta.rb
"Method a has been called"
"a called."
"Method b has been called"
"b called."
"Method a has been called"
"a called."
"Method b has been called"
"b called."

我最近写了一些可能有用的东西,尽管有一些限制条件(见下文)。 以下是您要将钩子添加到的类:

class Original  
  def regular_old_method msg
    puts msg
  end

private

  def always_called method_called
    puts "'#{method_called.to_s.capitalize}' method's been called!"
  end
end
下面是添加该钩子的代码:

class << Original
  def new(*args)
    inner = self.allocate
    outer_name = self.name + 'Wrapper'
    outer_class = Class.new do
      def initialize inner_object
        @inner = inner_object
      end
      def method_missing method_called, *args
        @inner.send method_called, *args
        @inner.send :always_called, method_called
      end
    end
    outer_class_constant = Object.const_set(outer_name, outer_class)
    inner.send :initialize, *args
    outer_class_constant.new inner
  end
end
您将获得以下输出:

这一点没什么不寻常的

已调用“常规旧方法”方法

如果您的代码检查类名,这种方法将是一个坏主意,因为即使您请求了类“Original”的对象,但您得到的却是类“OriginalWrapper”的对象


此外,我认为,使用“新”方法可能还有其他缺点,但是我对Ruby元编程的了解还没有那么深入。

Ya我肯定很尊敬他们,感谢你的回答。mikej的意思是,你应该回顾你以前的问题,并单击任何答案上的复选框,以充分解决你的问题。我喜欢这一点。它似乎比一个全局的
set\u trace\u func
入侵性更小,因为这个黑客只限于这个类。非常聪明!遗憾的是,没有一种语言特性可以让这项工作在没有重量级的情况下变得更容易。
o = Original.new
o.regular_old_method "nothing unusual about this bit"