不覆盖`attr_accessor`的情况下获取所有通过`attr_accessor`定义的变量

9

我正在我的程序中设置一些跟踪代码,并想知道哪些方法是通过attr_accessor定义的。使用TracePoint,我可以检测到何时调用了attr_accessor,但我不知道如何让它告诉我它接收到的参数。有什么想法吗?


1
你只能获取所有实例变量。如果这还不够好,那么你就必须以某种方式对attr_accessor进行调试。无法避免这一点。 - Sergio Tulentsev
使用attr_accessor定义方法和查找实例变量的访问器方法有区别吗? - Wand Maker
attr_accessor 就是我想要的,其他的我可以用 TracePoint 轻松获取。 - n_x_l
2个回答

8
在问题标题中,您要求列出变量的列表,但这个答案是针对问题主体的,问题主体要求列出定义的方法。
该方法不会检查实例变量,如果您开始手动更新或创建其他实例变量,则会引入噪声。
module MethodTracer
  TracePoint.trace(:c_call) do |t|
    if (t.method_id == :attr_accessor)
      t.self.extend(MethodTracer)

      methods = t.self::Methods ||= []
      MethodTracer.send(:define_method, :method_added) {|m| methods << m }
    end
  end

  TracePoint.trace(:c_return) do |t|
    if (t.method_id == :attr_accessor)
      MethodTracer.send(:remove_method, :method_added)
    end
  end
end

class Foo
  attr_accessor :a, :b
  attr_accessor :c

  def foo; end
end

Foo::Methods # => [:a, :a=, :b, :b=, :c, :c=]

我已将方法名称存储在Methods常量中,但是您显然可以将它们存储在最方便的地方。在MethodTracer上定义/删除method_added确保您不会覆盖您自己定义的任何Foo.method_added。然而,这种方法需要在调用attr_accessor之前定义Foo.method_added,并且您需要在其中调用super。否则,您将跳过由MethodTracer定义的临时method_added

1
顺便提一下,我花了一些时间尝试使用TracePoint来获取传递给attr_accessor的方法名称。我发现这几乎是不可能的。 - user513951
2
我尝试了。 OP 也是这样做的。这就是问题的全部意义所在。只有你找到了解决方案。 - sawa
2
太棒了。我也在c_call上留下了痕迹,并检查了方法是否为attr_accessor,但卡在那里了。调用method(:attr_accessor)的#parameters告诉我它接收了一些参数(返回[[:rest]]),但不知道如何获取它,因为它接收了一个传统的splat参数。 - n_x_l
1
非常好的答案,因为这个答案我学到了新东西。 - Wand Maker
1
问题在于我是在IRB中运行它的。 :-) - Cary Swoveland

0

你可以使用obj.methods()来查找实例中所有可用的方法(包括超类中的方法),并使用obj.methods(false)仅获取当前单例对象上定义的方法。但我不确定是否可能检测这些方法是通过attr_accessor创建的。


1
那么这并没有真正回答问题,是吧? :) - Sergio Tulentsev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接