我希望能够完全透明地包装任何Ruby proc(包括我自己没有编写源代码的那些),并记录其执行时间。
my_proc
也就是说,我想创建一个调用my_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>
# }
然后我想把它包起来,它应该表现得完全一样:
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>
# }
看起来透明的函数包装器应该很难,但我无法解决这个问题。
答案 0 :(得分:3)
这里唯一的技巧是处理λ.call
和&λ
传递阻塞案例,因为在后一种情况下 Proc#call
未被调用。 SIC。
我的第一个[错误]意图是:
def wrap λ
λ.singleton_class.prepend(Module.new do
def call(*args, &cb)
puts "⇓⇓⇓"
super
puts "⇑⇑⇑"
end
end)
end
但正如我已经说过的那样,specific_eval
不会调用Proc#call
也不调用Proc#to_proc
而我放弃了。
另一方面,我们可能只是在接收器的上下文中instance_exec
包裹了λ,但是没有办法将块作为参数传递给instance_exec
因为它本身已经接收到了λ。
情节变浓。由于我们无法将块作为参数传递给instance_exec
,因此我们的包装器的使用者也不能。是的,这解决了任务:
def wrap λ
-> (*args, &cb) do
puts "⇓⇓⇓"
(cb ? λ.call(*args, &cb) : instance_exec(*args, &λ)).tap do |result|
puts result.inspect
puts "⇑⇑⇑"
end
end
end
你走了。