Moduleの使い方。
ディレクトリにMyMathModule.rbとMyApp.rbの2つのファイルを作成してみる。
# MyMathModule.rb module MyMathModule def plus(x, y) x + y end end
# MyApp.rb require "./MyMathModule" class MyApp include MyMathModule end myapp = MyApp.new p myapp.plus(1,2)
シェルから次のコマンドを実行してみる。
$ ruby MyApp.rb 3
これがrubyのmoduleの一般的な使い方である。
moduleはC++の名前空間とは少し概念が異なり、
module内に定義したメソッドはそのままでは呼び出せない。
以下のように呼び出そうとしても怒られてしまう。
~/ruby_test$ irb irb(main):001:0> require "./MyMathModule" => true irb(main):002:0> MyMathModule::plus(1,2) NoMethodError: undefined method `plus' for MyMathModule:Module from (irb):2 from /Users/pebble8888/.rbenv/versions/2.0.0-p643/bin/irb:12:in `<main>' irb(main):003:0>
moduleにメソッドを定義する場合、クラスにMix-inして使う場合がほとんどである。
includeを使ってモジュールをMix-inすることができ、そのモジュール内のメソッドが全てクラス内
に追加される。クラスのメソッドとして利用することができる。
他のrubyソースファイルを読み込むにはrequireを使う。ファイルの拡張子が.rbになっている場合は 省略することができる。ファイル名はダブルクォーテーションまたはシングルクォーテーションで囲む必要があり 通常は相対パスで指定するが、ロードパスに含まれていればパス指定は不要になる。
ロードパスは$:というrubyのグローバル変数に入っている。 ちなみに私の環境では以下のようになっていた。
ruby -e 'p $:' ["/Users/pebble8888/.rbenv/rbenv.d/exec/gem-rehash", "/Users/pebble8888/.rbenv/versions/2.0.0-p643/lib/ruby/site_ruby/2.0.0", "/Users/pebble8888/.rbenv/versions/2.0.0-p643/lib/ruby/site_ruby/2.0.0/x86_64-darwin14.1.1", "/Users/pebble8888/.rbenv/versions/2.0.0-p643/lib/ruby/site_ruby", "/Users/pebble8888/.rbenv/versions/2.0.0-p643/lib/ruby/vendor_ruby/2.0.0", "/Users/pebble8888/.rbenv/versions/2.0.0-p643/lib/ruby/vendor_ruby/2.0.0/x86_64-darwin14.1.1", "/Users/pebble8888/.rbenv/versions/2.0.0-p643/lib/ruby/vendor_ruby", "/Users/pebble8888/.rbenv/versions/2.0.0-p643/lib/ruby/2.0.0", "/Users/pebble8888/.rbenv/versions/2.0.0-p643/lib/ruby/2.0.0/x86_64-darwin14.1.1"]
さて、動的言語であるrubyのmoduleのミックスインでは恐ろしく動的なことができる。
2つのソースファイルを以下のように書き換えて実行してみる。
# MyMathModule.rb module MyMathModule def plus(x, y) x + y + @something end end
# MyApp.rb require './MyMathModule' class MyApp include MyMathModule def initialize @something = 4 end end myapp = MyApp.new p myapp.plus(1,2)
実行してみた結果がこちら。
$ ruby MyApp.rb 7
エラーにもならずに実行された。しかも、答えが7である。
@で始まる変数はインスタンス変数と呼ばれ、同じインスタンス内で参照、変更が可能な変数である。
module定義の中でMixinされるはずのクラスのインスタンス変数の参照ができてしまうのである。なんて恐ろしい機能だろうか。ちなみにmodule側でMixinされるはずのクラスインスタンス自体の参照も可能なようだが、次回にまわすことにする。