在Ruby中,有没有一种方法可以从一个示例中调用一个私有的Class方法?

olmpazwi  于 2023-08-04  发布在  Ruby
关注(0)|答案(8)|浏览(98)

当然,除了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

字符串

of1yzvn4

of1yzvn41#

下面是一个代码片段来沿着这个问题。在类定义中使用“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

字符串
我不知道有什么办法可以解决这个问题。文档说你不能指定私有方法的receive。此外,您只能从同一个示例访问私有方法。类Foo是一个不同于给定的Foo示例的对象。
不要把我的回答当作最后的决定。我当然不是一个Maven,但我想提供一个代码片段,以便其他试图回答的人将有适当的私有类方法。

0h4hbjxa

0h4hbjxa2#

让我为这个或多或少奇怪的解决方案和非解决方案列表做出贡献:

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

字符串

x7rlezfr

x7rlezfr3#

现在你不再需要辅助方法了。您可以简单地将它们与方法定义内联。这对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辅助方法,将private类方法实现为public嵌套类中的public类方法。请参阅this blogpost了解更多详细信息。

sxissh06

sxissh064#

如果你的方法仅仅是一个utility function(也就是说,它不依赖于任何示例变量),你可以把这个方法放到一个模块中,把includeextend放到类中,这样它就可以作为一个私有类方法和一个私有示例方法。

laximzn5

laximzn55#

这是使用“真实的的”私有类方法的方法。

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"

字符串
干杯

ruoxqz4g

ruoxqz4g6#

这可能是最“原生的Ruby”方式:

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

slhcrj9b

slhcrj9b7#

以前的例子(不再?)工作。不能直接调用私有类方法;即使是在同一个班级。因此,您需要使用send

class Foo
  def self.a_method
    puts "uses #{private_method} from class method"
  end

  def a_method
    # normally this would be done with an alias or include+extend a module or calling self.class.a_method
    puts "uses #{private_method} from instance method"
  end

  class << self
    private

    def private_method
      "private class method"
    end
  end

  private

  def private_method
    self.class.send(:private_method)
  end
end

Foo.a_method => 'uses private class method from class method'
Foo.new.a_method => 'uses private class method from instance method'

字符串

9lowa7mx

9lowa7mx8#

除非我误会了,你不需要这样的东西吗:

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

    public
    def bar
        Foo.bar
    end
end

字符串
当然,如果您想避免硬编码类名,可以更改第二个定义以使用self.class.send方法……

相关问题