我正在编写一个方法来定义类中的实例方法;类似于attr_accessor:
class Foo
custom_method(:foo)
end
我已经通过将custom_method函数添加到Module模块并使用define_method定义方法来实现,这可以正常工作。但我无法弄清楚如何从课程中考虑可见性属性。例如,在以下类
中class Foo
custom_method(:foo)
private
custom_method(:bar)
end
第一个生成的方法(foo)必须是公共的,第二个(bar)必须是私有的。我怎么做?或者,如何找到调用custom_method的上下文:private,public或protected?
谢谢!
答案 0 :(得分:7)
经过一番实验后,我感到非常困惑。最初,我认为当您致电Module#define_method
时,Ruby会将默认的可见性(公共,私有或受保护)考虑在内。事实证明,在Ruby版本< = 2.0上,情况并非如此:
class Foo
private
define_method :foo do
puts "Foo called!"
end
end
Foo.new.foo # Prints "Foo called!"
在Ruby 2.1+上,它更令人困惑。 Module#define_method
似乎考虑了默认方法可见性:
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
的方法不起作用:
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!"
Dang it Ruby!为什么?
好的,这需要绝望的措施......
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>
在那里,修好了!
答案 1 :(得分:2)
我认为这是不可能的,因为Module.private
设置的范围可见性级别是在C虚拟机级别管理的,而不是暴露给Ruby。
编辑:并且它仅在与其被调用的语法范围相同的情况下可用,因此当您调用custom_method
时,它会丢失类声明中设置的可见性级别。
它在set_visibility()中设置,并在vm_define_method()中使用,但我找不到对Ruby提供的相应变量的任何引用。
我建议使用某种自定义参数来指定方法的可见性级别。
答案 2 :(得分:-1)
您可以使用Module#private_method_defined?来验证方法是否定义为私有