即时确定方法的可见性 [英] Determining method's visibility on the fly
问题描述
我正在编写一个将在类中定义实例方法的方法;类似于 attr_accessor 的东西:
I am writing a method that will define an instance method inside a class; something similar to attr_accessor:
class Foo
custom_method(:foo)
end
我已经通过向 Module 模块添加 custom_method 函数并使用define_method 定义方法来实现这一点,该方法工作正常.但我无法弄清楚如何考虑类的可见性属性.例如,在下面的类中
I have implemented that by adding custom_method function to the Module module, and defining the method with define_method, which works fine. But I cannot figure out how to take into account visibility attributes from the class. For example, in the following class
class Foo
custom_method(:foo)
private
custom_method(:bar)
end
第一个生成的方法 (foo) 必须是公共的,第二个 (bar) 必须是私有的.我怎么做?或者,我如何找到调用我的 custom_method 的上下文:private、public 或 protected?
the first generated method (foo) must be public, and the second one (bar) must be private. How do I do that? Or, how do I find the context in which my custom_method is called: private, public, or protected?
谢谢!
推荐答案
在尝试了一段时间后,我完全感到困惑.最初,我认为 Ruby 在调用 Module#define_method
时考虑了默认可见性(公共、私有或受保护).但事实证明,在 Ruby 版本 <= 2.0 上,情况并非如此:
After experimenting with this for a bit, I'm completely baffled. Initially, I thought that Ruby took the default visibility (public, private, or protected) into account when you call Module#define_method
. It turns out though that on Ruby versions <= 2.0, that's not the case:
class Foo
private
define_method :foo do
puts "Foo called!"
end
end
Foo.new.foo # Prints "Foo called!"
在 Ruby 2.1+ 上,它更令人困惑.Module#define_method
似乎考虑了默认方法的可见性:
On Ruby 2.1+, it's even more confusing. Module#define_method
seems to take default method visibility into account:
class Foo
private
define_method :foo do
puts "Foo called!"
end
end
Foo.new.foo # NoMethodError: private method `foo' called for #<Foo:0x8cb75ac>
但它仅在您直接从类内部调用 define_method
时才有效.调用一个方法,然后调用 define_method
不起作用:
But it only works when you are calling define_method
from directly inside the class. Calling a method which then calls define_method
doesn't work:
class Foo
def self.hello_on name
define_method name do
puts "Hello, #{name}!"
end
end
private
hello_on :foo
end
Foo.new.foo # Prints "Hello, foo!"
该死的红宝石!为什么?
好的,这需要采取绝望的措施......
Okay, this calls for desperate measures...
module DefaultMethodVisibilityAccessor
attr_reader :current_default_method_visibility
def public(*args)
@current_default_method_visibility = :public if args.empty?
super
end
def protected(*args)
@current_default_method_visibility = :protected if args.empty?
super
end
def private(*args)
@current_default_method_visibility = :private if args.empty?
super
end
end
class Module
prepend DefaultMethodVisibilityAccessor
end
module MethodDefiner
def hello_on name
define_method name do
puts "Hello, #{name}!"
end
case current_default_method_visibility
when :public
public name
when :protected
protected name
when :private
private name
end
end
end
用法:
class Foo
extend MethodDefiner
hello_on :foo
private
hello_on :bar
end
Foo.new.foo # Prints "Hello, foo!"
Foo.new.bar # NoMethodError: private method `bar' called for #<Foo:0x8ec18fc>
那里,固定!
这篇关于即时确定方法的可见性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!