17

以外self.class.send :method, args...はもちろん。コードを複製せずに、クラス レベルとインスタンス レベルの両方でかなり複雑なメソッドを使用できるようにしたいと考えています。


アップデート:

@ジョナサン・ブラナム:それは私の仮定でしたが、他の誰も方法を見つけていないことを確認したかった. 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
4

7 に答える 7

13

質問に沿ったコードスニペットを次に示します。クラス定義で「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 の特定のインスタンスとは異なるオブジェクトです。

私の答えを最終的なものと見なさないでください。私は確かに専門家ではありませんが、コード スニペットを提供して、回答を試みる他のユーザーが適切にプライベート クラス メソッドを使用できるようにしたいと考えました。

于 2008-08-21T18:42:39.663 に答える
4

多かれ少なかれ奇妙な解決策と非解決策のこのリストに貢献させてください。

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
于 2014-06-14T20:33:35.910 に答える
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"

乾杯

于 2012-07-04T05:15:42.613 に答える
0

This is probably the most "native vanilla Ruby" way:

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>

With some Ruby metaprogramming, you could even make it look like:

class Foo
  def self.foo
    'foo'
  end

  extend PrivateStatic
  private_static :foo
end

Ruby's metaprogramming is quite powerful, so you could technically implement any scoping rules you might want. That being said, I'd still prefer the clarity and minimal surprise of the first variant.

于 2019-04-03T02:43:23.053 に答える
0

メソッドが単なるユーティリティ関数である場合(つまり、インスタンス変数に依存しない場合)、メソッドをモジュールとincludeクラスextendに配置して、プライベート クラス メソッドとプライベート インスタンス メソッドの両方として使用できるようにすることができます。 .

于 2011-12-17T07:13:49.500 に答える
-1

私が誤解していない限り、次のようなものが必要ではないでしょうか。

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

    public
    def bar
        Foo.bar
    end
end

もちろん、クラス名のハードコーディングを避けたい場合は、self.class.send アプローチを使用するように 2 番目の定義を変更できます...

于 2008-08-21T18:10:05.170 に答える