💎
Ruby の method メソッドは対象の可視性を破壊する
前置き
検証環境
- Ruby (CRuby) 2.7.0
Object#method とは
オブジェクトのメソッド name をオブジェクト化した Method オブジェクトを返します。
(継承関係はありませんが)Method は Proc と似た存在であり、
#call
メソッドを呼び出すことで、オブジェクト化されたメソッドの処理を実行することができます。
class Klass
def value_2x(value)
value * 2
end
end
m = Klass.new.method(:value_2x)
m.call(1) #=> 2
Proc 同様、ブロック付きメソッドの呼び出しなどに使うことが多いかと思います。
class Klass
def array_2x(arr)
arr.map(&method(:value_2x))
end
private
def value_2x(value)
value * 2
end
end
arr = [1, 2, 3]
Klass.new.array_2x(arr) #=> [2, 4, 6]
Object#method は可視性を破壊する
本題です。
この Object#method
ですが、private メソッドからも Method オブジェクトを生成することができ、
生成されたオブジェクトはどこからでも処理の呼び出しが可能になります。
class Klass
private
def value_2x(value)
value * 2
end
end
klass = Klass.new
# 普通に実行する
klass.value_2x(1) #=> NoMethodError: private method `value_2x' called
# Method 化してから実行する
klass.method(:value_2x).call(1) #=> 2
この挙動が意図されたものかはわかりませんが、少なくとも今日 (2021/03/16) 現在、
Method オブジェクトには元のメソッドの可視性を外部から参照する手段が提供されていません。
結論
Object#public_method
が用意されているので、可視性の考慮が必要な場合はそちらを使いましょう。
class Klass
def value_2x(value)
private_value_2x(value)
end
private
def private_value_2x(value)
value * 2
end
end
klass = Klass.new
klass.public_method(:value_2x) #=> #<Method: Klass#value_2x(value) (pry):2>
klass.public_method(:private_value_2x) #=> NameError: method `private_value_2x' for class `Klass' is private
おまけ(考察)
(あくまでも私の個人的な考えです)
-
Object#public_method
やModule#public_instance_method
などが定義されている -
Method#visibility
が(現状)存在しない
これらの事実から、
- Method オブジェクトは生成できれば call できるべき
- call できないのであればオブジェクトが生成できないべき
と考えられているのではないかと思っています。
Discussion