定义“method_called”..如何调用每次调用类的任何函数时调用的钩子方法?

我想创建一个钩子方法,每次调用类的任何函数时都会调用它。 我已经尝试过method_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." 

如果有任何已定义的现有钩子方法可以正常工作,那么请告诉它。

提前致谢..

看看Kernel#set_trace_func 。 它允许您指定在发生事件(例如方法调用)时调用的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 ba bb 

输出:

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

method_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\np '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 

如果你这样称呼它......

 o = Original.new o.regular_old_method "nothing unusual about this bit" 

您将获得以下输出:

这一点没什么不寻常的

'regular_old_method'方法被调用了!

如果您的代码检查了类名,这种方法将是一个坏主意,因为即使您已经要求提供类“原始”类的对象,您得到的是“OriginalWrapper”类的对象。

另外,我想可能还有其他的缺点,搞乱'新'方法,但我对Ruby元编程的了解并没有延伸到那么远。