当然不是self.class.send :method, args...
。我想在类和实例级别上创建一个相当复杂的方法,而不需要复制代码。
更新:
@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
答案 0 :(得分:12)
以下是与问题同时发布的代码段。在类定义中使用“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的给定实例不同。
不要把我的答案作为最终答案。我当然不是专家,但我想提供一个代码片段,以便其他尝试回答的人都有正确的私有类方法。
答案 1 :(得分:3)
让我为这个或多或少奇怪的解决方案和非解决方案列表做出贡献:
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
答案 2 :(得分:0)
如果您的方法仅仅是utility function(也就是说,它不依赖于任何实例变量),您可以将该方法放入模块include
和extend
class,以便它可用作私有类方法和私有实例方法。
答案 3 :(得分:0)
这是使用“真正的”私有类方法的方法。
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"
欢呼声
答案 4 :(得分:0)
现在你不再需要辅助方法了。您可以使用方法定义简单地内联它们。这对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
在私有嵌套类中将私有类方法实现为 public 类方法辅助方法。有关详细信息,请参阅this blogpost。
答案 5 :(得分:0)
这可能是最“原生香草红宝石”的方式:
class Foo
module PrivateStatic # like Java
private def foo
'foo'
end
end
extend PrivateStatic
include PrivateStatic
def self.static_public_call
"static public #{foo}"
end
def public_call
"instance public #{foo}"
end
end
Foo.static_public_call # 'static public foo'
Foo.new.public_call # 'instance public foo'
Foo.foo # NoMethodError: private method `foo' called for Foo:Class
Foo.new.foo # NoMethodError: private method `foo' called for #<Foo:0x00007fa154d13f10>
通过一些Ruby元编程,您甚至可以使其看起来像:
class Foo
def self.foo
'foo'
end
extend PrivateStatic
private_static :foo
end
Ruby的元编程功能非常强大,因此您可以从技术上实现您可能想要的任何作用域规则。话虽如此,我仍然希望第一个变体的清晰度和minimal surprise。
答案 6 :(得分:-1)
除非我误解,否则你不需要这样的事情:
class Foo
private
def Foo.bar
# Complex logic goes here
puts "hi"
end
public
def bar
Foo.bar
end
end
当然,如果你想避免硬编码类名,你可以改变第二个定义来使用你的self.class.send方法......