読者です 読者をやめる 読者になる 読者になる

Pebble's Diary

プログラマーの作業メモ

ruby文法その2

ruby

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されるはずのクラスインスタンス自体の参照も可能なようだが、次回にまわすことにする。