Определение “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", метод рычага.

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."

Если существует какой-либо определенный существующий метод рычага, который работает все равно, то скажите об этом.

Заранее спасибо..

12
задан mikej 13 July 2010 в 11:11
поделиться

2 ответа

Взгляните на Ядро # set_trace_func . Он позволяет вам указать процедуру, которая вызывается всякий раз, когда происходит событие (например, вызов метода). Вот пример:

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
17
ответ дан 2 December 2019 в 04:08
поделиться

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\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."
18
ответ дан 2 December 2019 в 04:08
поделиться