242

プライベートクラスメソッドを作成するこのアプローチが機能するのはなぜですか。

class Person

  def self.get_name
    persons_name
  end

  class << self

    private

    def persons_name
      "Sam"
    end
  end
end

puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name  #=> raises "private method `persons_name' called for Person:Class (NoMethodError)"

しかし、これはしません:

class Person

  def self.get_name
    persons_name
  end

  private

  def self.persons_name
    "Sam"
  end
end

puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
4

8 に答える 8

296

private明示的なオブジェクトでメソッドを定義している場合(あなたの場合)は機能しないようですselfprivate_class_methodクラスメソッドをプライベートとして(または説明したように)定義するために使用できます。

class Person
  def self.get_name
    persons_name
  end

  def self.persons_name
    "Sam"
  end

  private_class_method :persons_name
end

puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name

あるいは (ruby 2.1 以降)、メソッド定義はメソッド名のシンボルを返すため、次のように使用することもできます。

class Person
  def self.get_name
    persons_name
  end

  private_class_method def self.persons_name
    "Sam"
  end
end

puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
于 2011-02-10T03:26:38.263 に答える
111

ExiRe さんが書きました:

ruby のこのような振る舞いは本当にもどかしいです。つまり、プライベート セクションの self.method に移動すると、プライベートではなくなります。しかし、それを class << self に移動すると、突然機能します。それはただ嫌です。

混乱するかもしれませんし、イライラするかもしれませんが、うんざりすることは絶対にありません。

Ruby のオブジェクト モデルと対応するメソッド ルックアップ フローprivateを理解すれば、特にそれがアクセス/可視性修飾子ではなく、実際にはここで説明されているメソッド呼び出し(受信者としてクラスを使用) であることを考慮すると、完全に理にかなっています... Ruby には「プライベート セクション」というものはありません。

プライベートインスタンスメソッドを定義するには、インスタンスのクラスを呼び出して、後で定義されるメソッドのデフォルトの可視性をプライベートに設定します。したがって、クラスのクラスを呼び出してプライベートクラスprivateメソッドを定義することは完全に理にかなっています。そのメタクラス。private

他の主流の自称 OO 言語は、構文の混乱が少ないかもしれませんが、Ruby のメタプログラミング機能のない、混乱して一貫性の低い(一貫性のない?)オブジェクト モデルとのトレードオフは間違いありません。

于 2013-02-28T11:23:37.580 に答える
87

デフォルトでは、すべてのクラス メソッドは public です。それらをプライベートにするには、 @tjwallace が書いたようにModule#private_class_methodを使用するか、別の方法で定義することができます。

class << self

  private

  def method_name
    ...
  end
end

class << self自己のシングルトン クラスを開き、現在の自己オブジェクトのメソッドを再定義できるようにします。これは、クラス/モジュール (「静的」) メソッドを定義するために使用されます。そこでのみ、プライベート メソッドを定義すると、実際にプライベート クラス メソッドが得られます。

于 2012-09-07T04:07:20.077 に答える
19

完全を期すために、private_class_method を別の行で宣言することを避けることもできます。個人的にはこの使い方は好きではありませんが、存在することを知ってよかったです。

private_class_method  def self.method_name
 ....
end
于 2015-11-05T15:35:04.033 に答える
6

私も、Ruby (または少なくともそれに関する私の知識) は、この分野では的外れだと思います。たとえば、次は私が望むことを行いますが、不器用です。

class Frob
    attr_reader :val1, :val2

    Tolerance = 2 * Float::EPSILON

    def initialize(val1, val2)
        @val2 = val1
        @val2 = val2
        ...
    end

    # Stuff that's likely to change and I don't want part
    # of a public API.  Furthermore, the method is operating
    # solely upon 'reference' and 'under_test' and will be flagged as having
    # low cohesion by quality metrics unless made a class method.
    def self.compare(reference, under_test)
        # special floating point comparison
        (reference - under_test).abs <= Tolerance
    end
    private_class_method :compare

    def ==(arg)
        self.class.send(:compare, val1, arg.val1) &&
        self.class.send(:compare, val2, arg.val2) &&
        ...
    end
end

上記のコードに関する私の問題は、Ruby の構文要件と私のコード品質指標が共謀して扱いにくいコードを作成することです。コードを希望どおりに機能させ、メトリックを静かにするには、compare() をクラス メソッドにする必要があります。クラスのパブリック API の一部にしたくないので、プライベートにする必要がありますが、「プライベート」自体は機能しません。代わりに、「private_class_method」またはそのような回避策を使用する必要があります。これにより、'==()' でテストする変数ごとに 'self.class.send(:compare...' の使用が強制されます。

于 2014-09-22T22:40:03.750 に答える