なぜプライベートクラスメソッドを作成するこのアプローチが機能するのか:
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
private
は、明示的なオブジェクト(場合によってはself
)でメソッドを定義している場合は機能しないようです。 private_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
ExiRe 書き込み:
Rubyのこのような動作は本当にイライラさせられます。プライベートセクションself.methodに移動する場合、プライベートではありません。しかし、クラス<< selfに移動すると、突然動作します。それはただ嫌です。
それを混乱させるのはおそらくイライラするかもしれませんが、嫌なことは間違いありません。
Rubyのオブジェクトモデルと対応する メソッドルックアップフロー を理解すると、特にprivate
がではなくアクセス/可視性修飾子ですが、実際にはメソッド呼び出し(クラスをその受信者として)前述のように ここ ...そのようなことはありませんas "プライベートセクション" Rubyの場合。
プライベートinstanceメソッドを定義するには、インスタンスのクラスでprivate
を呼び出して、後で定義されるメソッドのデフォルトの可視性をprivate ...に設定します。したがって、クラスのクラスでprivate
を呼び出すことにより、プライベートclassメソッドを定義することは完全に理にかなっています。そのメタクラス。
他の主流の自称OO言語は、構文がわかりにくいかもしれませんが、紛らわしく、一貫性の低い混乱とトレードオフします(矛盾する?)パワーのないオブジェクトモデルRubyのメタプログラミング機能。
デフォルトでは、すべてのクラスメソッドはパブリックです。それらを非公開にするには、 Module#private_class_method を使用します。
class << self
private
def method_name
...
end
end
class << self
はselfのシングルトンクラスを開き、メソッドを現在のselfオブジェクトに対して再定義できるようにします。これは、クラス/モジュール(「静的」)メソッドを定義するために使用されます。そこにのみ、プライベートメソッドを定義すると、実際にプライベートクラスメソッドが提供されます。
完全を期すために、private_class_methodを別の行で宣言することも避けられます。私は個人的にこの使用法が好きではありませんが、それが存在することを知っているのは良いことです。
private_class_method def self.method_name
....
end
私も、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 ...」を使用するように強制されます。
インスタンスメソッドは、クラス定義ブロック内で定義されます。クラスメソッドは、クラスのシングルトンクラスのシングルトンメソッドとして定義され、「メタクラス」または「固有クラス」とも呼ばれます。 private
はキーワードではなくメソッドです( Module#private )。
これはメソッドself#private
/A#private
への呼び出しです。これは、他の方法でトグルされるまで、今後のすべてのインスタンスメソッド定義に対してプライベートアクセスを「トグル」します。
class A
private
def instance_method_1; end
def instance_method_2; end
# .. and so forth
end
前述のように、クラスメソッドは実際にはシングルトンクラスで定義されたシングルトンメソッドです。
def A.class_method; end
または、特別な構文を使用して、Aの匿名のシングルトンクラスの定義本体を開きます。
class << A
def class_method; end
end
「メッセージプライベート」の受信者-self-inside class A
はクラスオブジェクトA. class << A
ブロック内のself別のオブジェクト、シングルトンクラスです。
次の例は、実際にはprivateという2つの異なるメソッドを呼び出し、呼び出しに2つの異なる受信者またはターゲットを使用しています。最初の部分では、プライベートインスタンスメソッド(「クラスA」)を定義し、後者では、プライベートクラスメソッド(実際にはAのシングルトンクラスオブジェクトのシングルトンメソッド)を定義します。
class A
# self is A and private call "A.private()"
private def instance_method; end
class << self
# self is A's singleton class and private call "A.singleton_class.private()"
private def class_method; end
end
end
次に、この例を少し書き換えます。
class A
private
def self.class_method; end
end
[Ruby言語設計者]が犯した間違いを見ることができますか? Aのすべての今後のインスタンスメソッドに対してプライベートアクセスをオンにしますが、別のクラス、シングルトンクラスでシングルトンメソッドを宣言します。