rubyのmoduleメソッドの可視性操作
あたふたしたので備忘録。
rubyのmoduleメソッドは基本的に不可視らしいので、モジュール自体をレシーバーにしても、はたまたモジュール内部で関数形式で呼んだとしても、みれないみたい。
code:ruby
module A
def pub
p "in pub!"
end
end
A.pub # => 当然エラー
⇑これはわかる。
pubをモジュールAの特異クラスにおける特異メソッドとして定義してあげればもちろん呼べる=>つまりself.pubとすればよべるのだが、そのなかで同じモジュール内の他の関数はもちろん見えない。(よくわかってないけど、これは恐らくモジュール内の関数はインスタンスメソッドで、moduleはインスタンスになれないので、このままでは一生誰からも呼ばれない。includeとかされない限り。)
code:ruby
module A
def self.pub
p "in pub!"
prv
end
def prv
p "in prv!"
end
end
A.pub # => prvがないよ!と怒られる
見るようにするにはmodule_functionにするかself.prvのように特異メソッドにすればよい。
ないしは、classを定義してincludeしてインスタンスメソッドにすればよい。
code:ruby
module A
def pub
p "in pub!"
prv
end
def prv
p "in prv!"
end
end
class B
include A
end
B.new.pub # => in pub! in prv!
ここで、あくまでモジュールAに対して特異メソッドとしてpubを使いたい!さらにpubのなかでprvをつかいたい!と思ったとする。(この時点でclassにしろよ、、、て話はあるがそこは捨て置く)
一個の解決案としtextend selfするというのもある。こうすることで、Aの特異クラスAに対して特異メソッドとしてmodule Aのdefを拡張できる(と、思っている)
しかし問題は、prvももちろん暴露してしまう。
code:ruby
module A
extend self
def pub
p "in pub!"
prv
end
def prv
p "in prv!"
end
end
A.pub # => in pub! in prv!
A.prv # => in prv! いやだ!
これを回避するためにprvに対して、privateをセットする。
code:ruby
module A
extend self
def pub
p "in pub!"
prv
end
private
def prv
p "in prv!"
end
end
A.pub # => in pub! in prv!
A.prv # => error
これで目的は達成した。
見事モジュールAの公開メソッドと非公開メソッドを定義できた。
一方で、疑問が残る。
どうしてpubメソッドからprvメソッドがみえたのか?
理解としては、
extend selfによってひとまずmodule Aの特異クラスに対して特異メソッドpubとprvが生えた
さらにprvに対してprivateな装飾がついた
prvは特異メソッドでありながらprivateになった
ということなのだが、問題は3番めの気持ち悪さ。
特異メソッドでprivate・・・?そんなのアリエルの?
いやでももともとやりたかったことってそれなんだけどさ、、、
って調べたら、
private_class_method
というのが標準で存在していたというオチ。