先日 perl の SQL::Maker を ruby に移植したのだけれど、そこでは perl の EXPORT を ruby の include で代用したと書いた。
まぁ、それはそれでいいんだけど、
class Hoge
include SQL::Maker::Helper
def hoge
sql_raw('*')
end
end
とした場合に、Hoge.new.hoge
の中で sql_raw が呼べるのはいいんだけど、 Hoge.new.sql_raw('*')
のようにもメソッドが呼べてしまうのがなんか嫌だなぁと思った。 (正確には private にしているのでコレでは呼べないのだが、send(:sql_raw) とでもすれば呼べてしまう)。
なので、実際に使うファイルスコープだけに制限したいよね、と思って、ファイルスコープと言えば、ruby 2.1 には refinement があるのでそれを使って実現してみようと思った。
refinement は普通は例えば、
module モジュール
refine クラス do
def method1
end
def method2
end
end
end
class Hoge
using モジュール # 「クラス」がこのファイルでのみ拡張される
end
のようにして、拡張したいクラスを refine の引数に指定して使うのだけど、今回は拡張したいクラスが
class Hoge #<= こいつ
みたいな任意のクラスなのでちょっと工夫する必要がある。モジュール定義を
module SQL::Maker::Helper
def self.included(klass)
refine klass do
def method1
end
def method2
end
end
# klass.__send__(:using, SQL::Maker::Helper) # これダメだった...メソッドの中で呼ぶなと怒られた
end
end
こんなかんじにして、利用するクラスのほうで
class Hoge
include SQL::Maker::Helper
using SQL::Maker::Helper
def hoge
sql_raw('*')
end
end
のようにしたら、
Hoge.new.hoge #=> 中では sql_raw が使える
Hoge.new.sql_raw('*') #=> undefined method !!!
となっていい感じになった。けど、include
と using
二回呼んでるのがなぁ...
あったらうれしい
def self.included(klass)
の using 版 def self.usinged(klass)
(名前が微妙 ^^;) みたいな using をフックするメソッドがあると、 using
1回で実現できるようになるのでよさそう。
おわりに
なにか良いやり方があったら教えてください!^^