有没有办法从Ruby中的实例调用私有的类方法?

问题描述:

当然不是self.class.send :method, args...。我希望在类和实例级别都可以使用相当复杂的方法,而无需重复代码。有没有办法从Ruby中的实例调用私有的类方法?


UPDATE:

@Jonathan Branam:那是我的假设,但我想,以确保没有其他人发现了周围的一种方式。 Ruby中的可见性与Java中的可见性非常不同。你也相当正确的,private不类方法工作,尽管这将宣布一个私人类方法:

class Foo 
    class <<self 
    private 
    def bar 
     puts 'bar' 
    end 
    end 
end 

Foo.bar 
# => NoMethodError: private method 'bar' called for Foo:Class 

下面的代码片段与问题走。在类定义中使用“private”不适用于类方法。您需要使用“private_class_method”,如下例所示。

class Foo 
    def self.private_bar 
    # Complex logic goes here 
    puts "hi" 
    end 
    private_class_method :private_bar 
    class <<self 
    private 
    def another_private_bar 
     puts "bar" 
    end 
    end 
    public 
    def instance_bar 
    self.class.private_bar 
    end 
    def instance_bar2 
    self.class.another_private_bar 
    end 
end 

f=Foo.new 
f=instance_bar # NoMethodError: private method `private_bar' called for Foo:Class 
f=instance_bar2 # NoMethodError: private method `another_private_bar' called for Foo:Class 

我看不出有办法解决这个问题。该文件说,你不能指定接收私人方法。您也只能从同一个实例访问私有方法。 Foo类是与Foo的给定实例不同的对象。

不要把我的答案作为最终答案。我当然不是专家,但我想提供一个代码片段,以便其他尝试回答的人将拥有适当的私有类方法。

除非我误解,你不只是需要这样的:

class Foo 
    private 
    def Foo.bar 
     # Complex logic goes here 
     puts "hi" 
    end 

    public 
    def bar 
     Foo.bar 
    end 
end 

当然你可以改变使用您的self.class.send方法,如果你想避免硬编码类名称的第二个定义...

如果你的方法仅仅是utility function(也就是说,它不依赖于任何实例变量),你可以把方法变成一个模块,includeextend类,以便它可以同时作为私有的类方法和一个私人实例方法。

这是玩“真正的”私人类方法的方式。

class Foo 
    def self.private_bar 
    # Complex logic goes here 
    puts "hi" 
    end 
    private_class_method :private_bar 
    class <<self 
    private 
    def another_private_bar 
     puts "bar" 
    end 
    end 
    public 
    def instance_bar 
    self.class.private_bar 
    end 
    def instance_bar2 
    self.class.another_private_bar 
    end 
    def calling_private_method 
    Foo.send :another_private_bar 
    self.class.send :private_bar 
    end 
end 
f=Foo.new 
f.send :calling_private_method 
# "bar" 
# "hi" 
Foo.send :another_private_bar 
# "bar" 

欢呼

+0

获取第一个示例的错误:`1.9。3p327:078> F = Foo.new =># 1.9.3p327:079> f.class.send:calling_private_method NoMethodError:未定义的方法\`calling_private_method”的富:从 类(IRB) :79 from〜/ .rvm/rubies/ruby​​-1.9.3-p327/bin/irb:16:in \'

'` – TrinitronX 2013-02-22 21:57:36

+0

是的,这不起作用(或者可能不再有效)。 – 2017-09-01 00:44:57

让我或多或少奇怪的解决方案和非方案的这个名单贡献:

puts RUBY_VERSION # => 2.1.2 

class C 
    class << self 
    private def foo 
     'Je suis foo' 
    end 
    end 

    private define_method :foo, &method(:foo) 

    def bar 
    foo 
    end 
end 

puts C.new.bar # => Je suis foo 
puts C.new.foo # => NoMethodError 

现在你不需要辅助方法了。你可以简单地将它们与你的方法定义联系起来。对于Java人来说,这应该是非常熟悉的:

class MyClass 

    private_class_method def self.my_private_method 
    puts "private class method" 
    end 

    private def my_private_method 
    puts "private instance method" 
    end 

end 

而且,不能从实例方法调用私有类方法。但是,您可以改为实现在私人嵌套类的私人类方法,如公共类方法,而不是使用private_constant helper方法。有关更多详细信息,请参阅this blogpost