我知道可以用ruby中的钩子前后装饰方法,但是可以为给定方法的每一行做这个吗?
例如,我有一个自动化测试,我想验证每个步骤后页面上没有显示错误。错误显示为红色div,并且对于raise
或类似的东西不可见,因此我必须手动检查它(还有其他一些用例)。
我知道可以使用set_trace_func
。但我认为这可能带来更多问题而不是好处,因为它可以在整个调用树上运行(并且需要我自己过滤它)。
更新(澄清):
我有兴趣拦截在给定方法中执行的所有操作(或调用)。这意味着调用了未指定数量的类,因此我不能只截取任何给定的类/方法集。
答案 0 :(得分:2)
是的,您可以在The Ruby Programming Language的第8.9节中详细了解如何操作。在每次调用方法时运行代码涉及将方法发送到具有TracedObject
实现的method_missing
类。每当收到消息时,它就会调用method_missing
并执行您分配给它的任何代码。 (当然,这是一般的追踪)。
这是对此过程的一般描述,您可以参考本书了解详情。
答案 1 :(得分:2)
听起来你想跟踪每个对象上的每个方法调用,但仅限于每次调用一个 特定的方法。在这种情况下,您可以重新定义方法以打开和关闭仪器。首先,使用Pinochle's answer中提出的通用仪器,然后重新定义相关方法,如下所示:
# original definition, in /lib/foo.rb:
class Foo
def bar(baz)
do_stuff
end
end
# redefinition, in /test/add_instrumentation_to_foo.rb:
Foo.class_eval do
original_bar = instance_method(:bar)
def bar(baz)
TracedObject.install!
original_bar.bind(self).call(baz)
TracedObject.uninstall!
end
end
您需要编写install!
和uninstall
方法,但它们应该非常简单:只需设置或取消设置类变量并在检测逻辑中检查它。
答案 2 :(得分:0)
怎么样(只是尝试)
class User
def initialize(name)
@name = name
end
def say_hello
puts "hello #{@name}"
end
def say_hi(friend)
puts "hi #{@name} from #{friend}"
end
def say_bye(a, b = 'Anna')
puts "bye #{a} and #{b}"
end
end
User.class_eval do
User.instance_methods(false).each do |method|
original = instance_method(method)
define_method method do |*options|
parameters = original.parameters
if parameters.empty?
original.bind(self).call
else
original.bind(self).call(*options)
end
puts __method__
end
end
end
user = User.new("John")
user.say_hello
user.say_hi("Bob")
user.say_bye("Bob")
user.say_bye("Bob", "Lisa")
输出:
hello John
say_hello
hi John from Bob
say_hi
bye Bob and Anna
say_bye
bye Bob and Lisa
say_bye