用于打印类中所有方法调用和返回的 Ruby 模块
Posted
技术标签:
【中文标题】用于打印类中所有方法调用和返回的 Ruby 模块【英文标题】:Ruby module to print all method calls and returns in class 【发布时间】:2020-09-08 11:55:19 【问题描述】:我正在尝试编写一个模块,无论其内容如何,它都可以用于每个类:
该模块应执行以下操作:
每当调用方法时打印名称方法及其参数。
打印该方法的返回值。
举个例子:
class A
extend Loginator
def add(a, b)
a + b
end
def sub(a, b)
a - b
end
logify_me #this where the "logging happens!"
end
a = A.new
a.add(3, 5)
a.sub(7, 4)
输出
Methode add(3, 5) called
returns 8
Methode sub(7, 4) called
returns 3
我不知道从哪里开始。 我已经阅读了以下链接:
Difference between a class and a module / *** ref.
Writing Module for Ruby / *** ref.
Ruby - Modules, and Mixins
Ruby modules: Include vs Prepend vs Extend
Modules in Ruby: Part I
所以我做了以下但我有点卡住了:
第一次尝试
module Loginator
def logify_me(name)
attr_reader name
define_method("#name=") do |val|
puts "#name=#val"
instance_variable_set("@#name", val)
end
end
end
class Example
extend Loginator
logify_me :an_attribute
end
e = Example.new
e.an_attribute = 12
p e.an_attribute
此代码的问题是,首先我必须为每个方法严格编写logify_me
,如果我单独编写logify_me
,则不会打印任何内容
第二次尝试
module Loginator
def logify_me
self.instance_methods.each do |method|
define_method(method) do |*args|
puts "Method #method(#args.join(', '))"
puts "returns #args"
args#problem this return the args not the results of each method?!
end
end
end
end
请注意,我可以使用TracePoint.trace(:call)
,但这不是我们想要的:)。
感谢用户@pedrosfdcarneiro 指出包装模块 解决方案并提供此ref
【问题讨论】:
欢迎来到 SO。你的问题问得不好。您向我们提出了要求,但没有向我们展示自己解决问题的任何尝试。 SO 不是代码编写服务,我们帮助您调试您编写的代码。请参阅“How to Ask”、“Stack Overflow question checklist”和“MCVE”及其所有链接页面。 @theTinMan 添加了我目前所在的位置。因此,如果您打算提供帮助,这是正确的时间:) 【参考方案1】:您可以通过为执行所需日志逻辑的类的每个公共实例方法定义一个新的包装器方法来实现。
module Loginator
def logify_me
self.public_instance_methods.each do |method|
proxy = Module.new do
define_method(method) do |*args|
puts "Method #method(#args.join(', ')) called"
# added join to match the exact desired output
value = super *args
puts "returns #value"
value
end
end
self.prepend proxy
end
end
end
class A
extend Loginator
def add(a, b)
a + b
end
def sub(a, b)
a - b
end
logify_me
end
产生以下输出:
>> A.new.sub(1,2)
Method 'sub' called with args '[1, 2]'
returns -1
=> -1
>> A.new.add(4,7)
Method 'add' called with args '[4, 7]'
returns 11
=> 11
对未来的解释:)
define_method(method)
:
在接收器中定义一个实例方法。方法参数可以是 Proc、Method 或 UnboundMethod 对象。如果指定了块,则将其用作方法体。此块使用 instance_eval ref. can be found here 评估
prepend
prepend 会将模块插入到链的底部,甚至在类本身之前。fourth ref on my post
@pedrosfdcarneiro 编辑的部分
请添加一些关于第二个内部模块proxy = Module.new do end
的简要说明,以及为什么它对返回值和 super 的使用很重要。
加上你为什么更喜欢使用public_instance_methods
而不是instance_methods
。
请添加一些关于它的解释,因为首先它对我来说有点不清楚,其次对于那里的其他菜鸟。 在此先感谢:)
这个答案很大程度上基于这个奇妙的答案:https://***.com/a/23898539/1781212。
【讨论】:
这工作得很好,但是请您添加一些关于proxy = Module.new do end
的用法以及为什么它对返回值很重要的解释。另外,我有点不明白super *args
,所以如果你能为我以及未来的人添加一些关于这些事情的解释,我将不胜感激。再次感谢:)以上是关于用于打印类中所有方法调用和返回的 Ruby 模块的主要内容,如果未能解决你的问题,请参考以下文章