gpt4 book ai didi

Ruby - 捕获从方法体发送的方法调用

转载 作者:数据小太阳 更新时间:2023-10-29 08:37:20 24 4
gpt4 key购买 nike

我正在寻找确保我的对象中定义的一组方法都调用特定方法的方法。为了说明,假设我有对象 A 和 B,它们都有如下方法:

class A
def method_a
important_method!
end
end

class B
def method_b
important_method!
end
end

我如何轻松确保来自 A 的 method_amethod_b 都调用了 important_method!

在这种情况下,important_method 将来自一个模块,该模块将包含在 A 和 B 中(实际上在它们的公共(public)父类(super class)中)。

到目前为止,我尝试的是将两个对象包装在定义 method_missing 和收集方法调用的代理中,但这只告诉我 method_amethod_b 被调用。有任何想法吗?

最佳答案

我的答案最初是使用 TracePoint,但后来我读到 @user2074840 如何使用 alias,这让我想到了使用 aliascaller 结合,这导致了一个非常直接的解决方案。我在下面将其呈现为 #2 Use Caller

#1 使用 TracePoint

在 Ruby 2.0+ 中你可以使用 TracePoint获取您需要的信息。 (在早期版本中,您可以使用 Kernel#set_trace_point 。)

为了了解这是如何工作的,让我们写一些示例代码:

def a
puts "a"
c
important
end

def b
puts "b"
important
end

def c
puts "c"
end

def important
puts "important"
end

我们现在设置跟踪,指定两个感兴趣的事件,:call:return,以及我们要保存的信息,事件 (:call or :return) 和方法 (:a, :b or :c):

events = []
trace = TracePoint.trace(:call, :return) { |tp|
events << { event: tp.event, method: tp.method_id } }

然后执行代码:

4.times { send([:a, :b, :c][rand(0..2)]) }
# b
# important
# b
# important
# a
# c
# important
# c

禁用跟踪:

trace.disable

并检查收集到的信息:

p events
# [{:event=>:call, :method=>:b},
# {:event=>:call, :method=>:important},
# {:event=>:return, :method=>:important},
# {:event=>:return, :method=>:b},
# {:event=>:call, :method=>:b},
# {:event=>:call, :method=>:important},
# {:event=>:return, :method=>:important},
# {:event=>:return, :method=>:b},
# {:event=>:call, :method=>:a},
# {:event=>:call, :method=>:c},
# {:event=>:return, :method=>:c},
# {:event=>:call, :method=>:important},
# {:event=>:return, :method=>:important},
# {:event=>:return, :method=>:a},
# {:event=>:call, :method=>:c},
# {:event=>:return, :method=>:c}]

请注意,这不能在 IRBPRY 中运行。

我们现在可以提取对 :important 的调用,如下所示:

def calls_to_method(events, method) 
stack = []
events.each_with_object([]) do |h, calling_methods|
stack << h
while stack.size > 1 &&
stack[-1][:event] == :return &&
stack[-2][:event] == :call &&
stack[-1][:method] == stack[-2][:method] do
if (stack.size > 2 && (stack[-1][:method] == method))
calling_methods << stack[-3][:method]
end
stack.pop
stack.pop
end
end
end

calls = calls_to_method(events, :important)
#=> [:b, :b, :a]

calls.uniq
#=> [:b, :a]

#2 使用来电

此方法使用 aliasKernel#caller :

@calling_methods = []
alias :old_important :important

def important
@calling_methods << caller.first[/`(.*)'/,1]
old_important
end

4.times { send([:a, :b, :c][rand(0..2)]) }
# b
# important
# c
# a
# c
# important
# a
# c
# important
# b
# a
# a

p @calling_methods
#=> ["b", "a", "a"]

这是 caller 返回的数组示例:

caller
#=> ["abc.rb:9:in `b'",
# "abc.rb:32:in `block in <main>'",
# "abc.rb:32:in `times'",
# "abc.rb:32:in `<main>'"]

这只是我们使用的第一个元素:

caller.first
#=> "abc.rb:9:in `b'",

我们应用正则表达式来提取方法名称,方法名称前面是 ''` (Ascii 96),后面是单引号。

关于Ruby - 捕获从方法体发送的方法调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28591480/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com