Ruby 检查时,我可以在类中获得传递给attr_访问器的符号列表吗?
假设我定义了一个类,该类具有使用attr\u accessor定义的访问器: 是否有一个内置方法提供传递给attr_访问器调用的方法名列表?或者我必须用符号定义一个常量,并将其传递给attr\u accessor吗?Grep Setter方法的实例 一种方法是为setter grep类的实例。例如:Ruby 检查时,我可以在类中获得传递给attr_访问器的符号列表吗?,ruby,class,metaprogramming,Ruby,Class,Metaprogramming,假设我定义了一个类,该类具有使用attr\u accessor定义的访问器: 是否有一个内置方法提供传递给attr_访问器调用的方法名列表?或者我必须用符号定义一个常量,并将其传递给attr\u accessor吗?Grep Setter方法的实例 一种方法是为setter grep类的实例。例如: A.new.methods.grep(/\p{alnum}+=\z/) #=> [:alpha=, :beta=, :gamma=] Grep Setter方法的实例 一种方法是为sette
A.new.methods.grep(/\p{alnum}+=\z/)
#=> [:alpha=, :beta=, :gamma=]
Grep Setter方法的实例
一种方法是为setter grep类的实例。例如:
A.new.methods.grep(/\p{alnum}+=\z/)
#=> [:alpha=, :beta=, :gamma=]
不,那是不可能的。由attr_访问器、attr_读取器和attr_编写器生成的方法与手工编写的方法无法区分。事实上,他们一定是无法区分的手写 比如说,您有一个简单的attr_访问器,但稍后您希望对其进行重构以实现更智能的功能,例如缓存。这是一个纯粹的内部更改,客户端不能观察到差异,否则将违反封装 如果您只是想要一个setter列表,这很简单:setter是名称以=符号结尾的方法: 对于getter来说,这更为棘手:任何不接受参数的方法都可能是getter,但也可能是副作用方法,例如:
不,那是不可能的。由attr_访问器、attr_读取器和attr_编写器生成的方法与手工编写的方法无法区分。事实上,他们一定是无法区分的手写 比如说,您有一个简单的attr_访问器,但稍后您希望对其进行重构以实现更智能的功能,例如缓存。这是一个纯粹的内部更改,客户端不能观察到差异,否则将违反封装 如果您只是想要一个setter列表,这很简单:setter是名称以=符号结尾的方法: 对于getter来说,这更为棘手:任何不接受参数的方法都可能是getter,但也可能是副作用方法,例如:
没有内置的方法。只要您事先知道并能够控制方法名称,在创建时存储方法名称的解决方案就可以工作 在对的回答中,我演示了如何在事后使用跟踪点动态获取方法的名称。我在下面更新了它,包括:attr\u reader和:attr\u writer 我已经将方法名存储在Methods常量中,但是很明显,您可以在最方便的地方存储它们
定义/删除MethodTracer上添加的方法确保不会破坏您自己定义的任何添加的Foo.method。但是,这种方法确实要求,如果在调用attr_*之前定义Foo.method_,则需要在其中调用super。否则,您将跳过MethodTracer定义的添加的临时方法。没有内置方法。只要您事先知道并能够控制方法名称,在创建时存储方法名称的解决方案就可以工作 在对的回答中,我演示了如何在事后使用跟踪点动态获取方法的名称。我在下面更新了它,包括:attr\u reader和:attr\u writer 我已经将方法名存储在Methods常量中,但是很明显,您可以在最方便的地方存储它们
定义/删除MethodTracer上添加的方法确保不会破坏您自己定义的任何添加的Foo.method。但是,这种方法确实要求,如果在调用attr_*之前定义Foo.method_,则需要在其中调用super。否则,您将跳过MethodTracer定义的临时方法。您的意思是@alpha吗?@zishe否,OP可能表示self.alpha=1。用符号定义常量并将其传递给attr\u访问器是什么意思?请澄清,最好是用一个包含期望结果的例子。我建议重新打开这个,因为提供的答案是正确的。我想做的是不可能的,@JörgWMittag在回答中解释得很好。你是说@alpha吗?@zishe不,OP可能意味着self.alpha=1。你用符号定义常量并将其传递给attr_访问器是什么意思?请澄清,最好是用一个包含期望结果的例子。我建议重新打开这个,因为提供的答案是正确的。我想做的是不可能的,@JörgWMittag在回答中很好地解释了这一点。这不一定会产生正确的名称,因为可以手动定义setter。谁知道这是否会对op产生影响?这不一定会产生正确的名称,因为可以手动定义setter。这是否会对op产生影响,谁知道呢?这确实是一个令人信服的解决方案。非常感谢你发布它。我把你的答案改为正确答案。这真是一个令人信服的解决方案。非常感谢你的来信 把它弄得乱七八糟。我把你的答案改成正确的。
A.public_instance_methods(false).grep(/=$/)
# => [:alpha=, :beta=, :gamma=]
A.public_instance_methods(false).select {|m|
A.public_instance_method(m).arity.zero?
}
# => [:alpha, :beta, :gamma]
module MethodTracer
TracePoint.trace(:c_call) do |t|
if %i[attr_accessor attr_writer attr_reader].include?(t.method_id)
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 %i[attr_accessor attr_writer attr_reader].include?(t.method_id)
MethodTracer.send(:remove_method, :method_added)
end
end
end
class Foo
attr_accessor :a
attr_reader :b
attr_writer :c
def foo; end
end
Foo::Methods # => [:a, :a=, :b, :c=]