获取通过`attr_accessor`定义的所有变量,而不覆盖`attr_accessor`

n_x*_*x_l 8 ruby metaprogramming

我正在我的程序上设置一些跟踪代码,并想知道通过哪些方法定义attr_accessor.使用TracePoint,我可以检测何时attr_accessor被调用,但我不知道如何让它告诉我它收到的论据.有任何想法吗?

use*_*951 6

在问题标题中,您要求提供变量列表,但这会回答问题正文,该正文要求提供已定义方法的列表.

此方法不会检查实例变量,如果您开始手动更新或创建其他实例变量,则会引入噪声.

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=]
Run Code Online (Sandbox Code Playgroud)

我已将方法名称存储在Methods常量中,但显然您可以将它们存储在最方便的地方.

定义/删除method_addedMethodTracer确保不影响任何Foo.method_added你自己定义.但是,这种方法确实要求如果您Foo.method_added在调用之前定义attr_accessor,则需要在其中调用super.否则你将跳过临时method_added定义的MethodTracer.

  • 这似乎是唯一正确的答案. (3认同)
  • 我试过了.OP也是如此.这就是问题的重点.只有你达成了解决方案. (2认同)
  • 惊人的东西.我也在c_call上有跟踪,并检查方法是否为attr_accessor,然后卡在那里.在`method(:attr_accessor)`上调用#parameters告诉我它接收了一些(返回`[[:rest]]`),但不知道如何得到它,因为它接收传统的splat参数. (2认同)

man*_*bot 0

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