我倾向于在类前面添加一个动态创建的匿名模块,其实例方法使用super
在打印方法进入消息之后和打印方法退出消息之前调用同名类的实例方法。
让我们首先创建一个具有两个实例方法的类,其中一个在调用时传递一个块。
class C
def mouse(nbr_mice, impairment)
puts "%d %s mice" % [nbr_mice, impairment]
end
def hubbard(*args)
puts yield args
end
end
C.ancestors
#=> [C, Object, Kernel, BasicObject]
c = C.new
c.mouse(3, 'blind')
# 3 blind mice
c.hubbard('old', 'mother', 'hubbard') { |a| a.map(&:upcase).join(' ') }
# OLD MOTHER HUBBARD
现在我们构造一个方法来创建匿名模块并将其添加到类的前面。
def loggem(klass, *methods_to_log)
log_mod = Module.new do
code = methods_to_log.each_with_object('') { |m,str| str <<
"def #{m}(*args); puts \"entering #{m}\"; super; puts \"leaving #{m}\"; end\n" }
class_eval code
end
klass.prepend(log_mod)
end
现在,我们准备使用等于要添加模块的类以及要记录的该类的实例方法的参数来调用此方法。
loggem(C, :mouse, :hubbard)
C.ancestors
#=> [#<Module:0x007fedab9ccf48>, C, Object, Kernel, BasicObject]
c = C.new
c.method(:mouse).owner
#=> #<Module:0x007fedab9ccf48>
c.method(:mouse).super_method
#=> #<Method: Object(C)#mouse>
c.method(:hubbard).owner
#=> #<Module:0x007fedab9ccf48>
c.method(:hubbard).super_method
#=> #<Method: Object(C)#hubbard>
c.mouse(3, 'blind')
# entering mouse
# 3 blind mice
# leaving mouse
c.hubbard('old', 'mother', 'hubbard') { |a| a.map(&:upcase).join(' ') }
# entering hubbard
# OLD MOTHER HUBBARD
#leaving hubbard
See 模块::新 https://ruby-doc.org/core-2.2.0/Module.html#method-c-new and 模块#prepend http://ruby-doc.org/core-2.4.0/Module.html#method-i-prepend.