モジュール内の特定のメソッドだけ include する(Ruby)
Ruby のモジュールは include でメソッドを Mix-in できますが、定義したすべてのメソッドが include されてしまって、特定のものだけ include するわけにはいきません。そのくらいできそうなので何か簡単なやり方があるのかもしれません。とにかく、考えてみました。
まず、こんなメソッドを Object クラスと Module クラスに付け加えます。
add_methods.rb
class Object def add_methods(module_to_include, *method_names) method_names.each do |m| pr = module_to_include.method(m).to_proc define_method(m, &pr) end end end class Module def register_all_methods instance_methods.each do |m| module_function m end end end
で、メソッドを定義するモジュールを書きます。そのとき、(必要な)すべてのメソッドを module_function で指定するか、上の register_all_methods をモジュールの最後に書きます。(すべて module_function で指定する場合は、register_all_methods メソッドを書く必要はありません。いちいち指定するのが面倒なので作りました。)
module A def run_f f end def run_g g end def f puts "f called" end def g puts "g called" end register_all_methods end
Mix-in するモジュールとメソッドを add_methods() で指定します。すると指定されたメソッドだけ使えるようになります。
add_methods A, :run_f, :run_g run_f #=>f called run_g #=>g called f #=>`<main>': undefined local variable or method `f' for main:Object (NameError)
確かに指定されたメソッドだけ使えるようになっています。
クラスの中だとこんな風になります。
class B add_methods A, :run_f, :run_g def go run_f run_g f end end B.new.go
こんなことも可能。
c1 = Object.new c2 = Object.new class << c1 add_methods A, :run_f end c1.run_f #=>f called c2.run_f #=>`<main>': undefined method `run_f' for #<Object:***> (NoMethodError)
なお、これは上の例で例えばメソッド f を絶対に外から呼び出せないようにしたわけではなく、A.f
などとすれば呼び出せてしまいます(まあしかし、モジュールが名前空間として使いやすくなったりとか、利点もあるのではないかと思います)。けれども、少なくとも間違えて f を呼び出す可能性はだいぶ低くなると思います。
そうそう、注意点ですが、これらと include を併用すると予期しづらい誤動作の原因になる可能性があります。まあ、そんなことをする意味はありませんが。
Gem化
Gem 'kaki-utils' に同梱しておきました(ver. 0.0.10)。使い方は
require 'kaki/utils/add_methods'
で Object#add_methods と Module#register_all_methods が使えます。