包装Ruby函数
我希望能够完全透明地包装任何Ruby进程(包括那些我没有为自己编写源代码的进程),并记录其执行时间包装Ruby函数,ruby,Ruby,我希望能够完全透明地包装任何Ruby进程(包括那些我没有为自己编写源代码的进程),并记录其执行时间 my_proc 也就是说,我想创建一个调用my_proc的proc 上下文/接收者 争论 街区 并打印出调用时的执行时间 例如: my_proc = proc { |*args, &block| p self: self, args: args, block: block } Object.new.instance_eval &my_proc #=> { # :sel
my_proc
也就是说,我想创建一个调用my_proc
的proc
例如:
my_proc = proc { |*args, &block| p self: self, args: args, block: block }
Object.new.instance_eval &my_proc
#=> {
# :self=>#<Object:0x007fd4c985f3e0>,
# :args=>[#<Object:0x007fd4c985f3e0>],
# :block=>nil
# }
Object.instance_exec '5', &my_proc
#=> {
# :self=>Object,
# :args=>["5"],
# :block=>nil
# }
my_proc.call(1, 2) { }
#=> {
# :self=>main,
# :args=>[1, 2],
# :block=>#<Proc:0x007fd4c985e9b8>
# }
my_proc=proc{|*args,&block | p self:self,args:args,block:block}
Object.new.instance\u eval和my\u proc
#=> {
#:self=>#,
#:args=>[#],
#:block=>nil
# }
Object.instance_exec'5',my_proc
#=> {
#:self=>对象,
#:args=>[“5”],
#:block=>nil
# }
我的进程调用(1,2){
#=> {
#:self=>main,
#:args=>[1,2],
#:block=>#
# }
然后我想包装它,它的行为应该完全相同:
def wrap(prc)
# what does this look like?
end
wrapped_proc = wrap(my_proc)
Object.new.instance_eval(&wrapped_proc)
# took 1s
#=> {
# :self=>#<Object:0x007fd4c985f3e0>,
# :args=>[#<Object:0x007fd4c985f3e0>],
# :block=>nil
# }
Object.instance_exec '5', &wrapped_proc
# took 2s
#=> {
# :self=>Object,
# :args=>["5"],
# :block=>nil
# }
wrapped_proc.call(1, 2) { }
# took 3s
#=> {
# :self=>main,
# :args=>[1, 2],
# :block=>#<Proc:0x007fd4c985e9b8>
# }
def包裹(prc)
#这是什么样子的?
结束
wrapped_proc=wrapp(我的_proc)
Object.new.instance\u eval(&wrapped\u proc)
#花了1秒
#=> {
#:self=>#,
#:args=>[#],
#:block=>nil
# }
Object.instance_exec“5”、&wrapped_proc
#花了2秒
#=> {
#:self=>对象,
#:args=>[“5”],
#:block=>nil
# }
包装过程调用(1,2){
#花了3秒
#=> {
#:self=>main,
#:args=>[1,2],
#:block=>#
# }
透明函数包装器似乎并不难,但我无法理解这一点。这里唯一的技巧是处理
λ.call
和传递块情况,因为在后一种情况下,Proc#call
不会被调用。原文如此
我的第一个[错误]意图只是:
def wrap λ
λ.singleton_class.prepend(Module.new do
def call(*args, &cb)
puts "⇓⇓⇓"
super
puts "⇑⇑⇑"
end
end)
end
但是,正如我已经说过的那样,没有调用Proc#call
也没有调用Proc#to_Proc
,我放弃了
另一方面,我们可以简单地将λ包装在接收器的上下文中,但无法将块作为参数传递给instance\u exec
,因为它已经接收到λ本身
情节越来越复杂。由于我们不能将块作为参数传递给实例_exec
,因此包装器的使用者也不能。是的,这就解决了任务:
def wrap λ
-> (*args, &cb) do
puts "⇓⇓⇓"
(cb ? λ.call(*args, &cb) : instance_exec(*args, &λ)).tap do |result|
puts result.inspect
puts "⇑⇑⇑"
end
end
end
给你。你的代码不适合我。你是说p self、args、block
和实例评估(&wrapped\u proc)
?在第一个示例中,您可能希望my_proc
而不是wrapped_proc
。@mudasobwa:检查我的答案编辑历史记录。这是我发布的第一件事。但是,它不符合包装的条件。@mudasobwa:不,这是克隆:)您肯定熟悉装饰器的概念。那是包装。获取一个新对象(新标识),但是一些功能被委托给包装的对象。当然是这样。然而,它仍然是一个委托
模式,这意味着在这种特殊情况下它仍然是零值。我甚至不能复制OP的未包装示例。“我们包装的消费者也不能”-啊!我怎么没想到@SergioTulentsev坦率地说,我仍在深入研究ruby代码(ruby本身的代码:),试图理解在&λ调用中绕过Proc#call
的原因。我找不到。我发布的第一个片段对我来说更有意义。很好的解决方案,第一次尝试也会有意义。UTF-8代码是否正在大型官方Ruby项目中使用?“我们包装器的消费者也不能这样做”不太正确。如果修改self对象,则可以传递self、arg和block<代码>a=Object.new;a、 定义单例法:foo,λ;a、 λ(arg){}
@EricDuminil-Mike-Perham's是一个大型的官方项目。是的,这更像是一个笑话,但根据我的经验(linux/ext{2,4}),自2000年以来,我从未遇到过UTF8的任何问题,我不断地将这些符号引入我们公司的代码库。例如,使用⚐代码>和⚑代码>作为“警报方法名称,✎代码>用于内部日志和❤
forOK
状态使我的代码既古怪又可爱。另外,rails使用✓
作为每个请求的params
中UTF-8的值,请检查日志:)