学び直し Rubyがミニツク Part9

今日の教科書
[モジュール](http://www.minituku.net/courses/566428009/contents/720335719.html)

#モジュール
モジュールは手続きの部分だけのまとめ。
moduleでモジュールを定義。

```
module ＜モジュール名＞
  ＜モジュールの定義＞
end
```

```
module Foo
  def foo
    puts("module foo")
  end
end
```

クラスとモジュールの違いは
 - モジュールはインスタンスを作ることができない
 - モジュールは継承ができない

 > クラスは継承をおこなうことでスーパークラスから機能を渡せました。
しかし、クラスの継承ではスーパークラスがひとつしか指定できません。
そのため、複数のスーパークラスを継承して新しいサブクラスを作れません。そのようなクラスに異なる機能を渡したい時にRubyではモジュールを使います。このさまざまな機能を混ぜ合わせるやり方のことをMix-inと呼びます。

#include
モジュールに含まれているメソッドや定数をクラスの中に取り込む。

```
module Greeting
  def hello
    puts("Hello, Ruby!")
  end
end
class Foo
  include Greeting
end
class Bar
  include Greeting
end
Foo.hello  #=> Hello, Ruby!
Bar.hello  #=> Hello, Ruby!
```

同じクラスへ複数のモジュールをインクルード

```
module Foo
  def foo
    puts("foo")
  end
end
module Bar
  def bar
    puts("bar")
  end
end
class Baz
  include Foo
  include Bar
end
baz = Baz.new
baz.foo  #=> foo
baz.bar  #=> bar
```

別のモジュールに機能を渡す
```
module Foo
  def foo
     puts("foo")
  end
end
module Bar
  include Foo
end
class Baz
  include Bar
end
baz = Baz.new
baz.foo  #=> foo
```

#モジュール関数

```
module Foo
  def foo
    puts("foo")
  end
  module_function :foo
end
Foo.foo #=> foo
```

モジュールで定義したインスタンスメソッドはレシーバを指定した定式では呼べない。
レシーバにモジュールを指定してメソッド呼び出しを行う。モジュール内でmodule_functionの引数にメソッド名をシンボルで指定することで設定できる。このようなメソッドをモジュール関数と呼ぶ。

#名前空間の提供

 > 別の人が開発していたライブラリを使ったり、複数のメンバーで開発をおこなっていると使いたい名前が被ってしまうことがあります。
ただし、同じ名前のクラスやメソッドを定義すると、前に定義していたものを上書きしてしまいます。上書きする前に使っていたものと違う機能になってしまうと、上書きする前の機能を使っていたところでエラーが発生するかもしれません。このような名前が衝突することによって生まれる問題を避け、自由に名前を付けることができることを名前空間と呼びます。Rubyではモジュールを使うことによって、名前空間を提供することができます。

```
module Foo
  def foo
    puts("module foo")
  end
  module_function :foo
end
module Bar
  def foo
    puts("module bar")
  end
  module_function :foo
end
Foo.foo  #=> module foo
Bar.foo  #=> module bar
```

#特異メソッド
特定の一つのオブジェクトだけで使えるメソッド。
メソッド定義時に`オブジェクト.メソッド名`で使える。

```
obj = Object.new
def obj.foo
  puts("foo")
end
```

クラスやモジュールも特異メソッドを定義できる。クラスメソッドも特異メソッドの一種。
クラスメソッドはクラスをレシーバにして呼び出す。

```
# def self.メソッド名; end
module Foo
  def self.foo
    puts("foo")
  end
end
Foo.foo  #=> foo
 
# def モジュール.メソッド名; end
module Bar
  def Bar.bar
    puts("bar")
  end
end
Bar.bar  #=> bar
```

モジュールには似たようなモジュール関数がある。両方ともレシーバにモジュールを指定する。
モジュール関数ではインクルードした際のインスタンスメソッドとして。
特異メソッドではインクルードしたときに渡さない。

```
module Foo
  def self.foo
    puts("foo")
  end
end
module Bar
  include Foo
end
Foo.foo  #=> foo
Bar.foo
NoMethodError: undefined method `foo' for Bar:Module
    from (irb):9
    from :0
```

モジュール関数はインクルードすることによって、インスタンスメソッドとしてインクルード先で使うことができる。

```
module Foo
  def foo
    puts("foo")
  end
  module_function :foo
end
class Bar
  include Foo
  def bar
    foo
  end
end
bar = Bar.new
bar.foo  #=> foo
```

#extend
オブジェクトに対して引数に指定したモジュールのインスタンスメソッドを特異メソッドとして渡す。

```
module Foo
  def foo
    puts("foo")
  end
end
class Bar
end
str = ""
str.extend(Foo)
str.foo  #=> foo
 
Bar.extend(Foo)
Bar.foo  #=> foo
```

定義しているクラスやモジュールの中でも呼び出せる。

```
module Foo
  def foo
    puts("foo")
  end
end
module Bar
  extend Foo
end
Bar.foo  #=> foo
```

#組み込みモジュール
Rubyに最初から組み込まれているモジュール。

##Comparableモジュール
比較演算子をクラスに加えるモジュールです。ArrayやStringなどの大小関係があるオブジェクトはこのモジュールをインクルードしている。使用時には<=>演算子を定義する。
この演算子を使って比較するメソッドの集まりがComparableモジュール。

```
class Foo
  include Comparable
  attr_accessor :num
  def initialize(num)
    @num = num
  end
  def <=>(other)
    return @num <=> other.num
  end
end
foo = Foo.new(10)
bar = Foo.new(5)
p foo < bar
p foo > bar
```

[Comparableリファレンス](http://doc.okkez.net/static/1.8.7/class/Comparable.html)

##Enumerableモジュール
繰り返しを行うクラスのためのモジュール。eachメソッドを必要とする。
これで様々なイテレータを定義できる。

```
class MetaSyntax
  include Enumerable
  def initialize
    @variables = []
  end
  def add(value)
    @variables << value
  end
  def each
    @variables.each do |variable|
      yield variable
    end
  end
end
ary = MetaSyntax.new
ary.add("foo")
ary.add("bar")
ary.add("baz")
ary.each do |i| puts i end
ary.each_with_index do |item, index|
  puts("これは#{index}番目の#{item}です")
end
```

クラス内にeachを定義すると、Enumerableモジュールをインクルードする。
そしてeach_with_indexメソッドといったメソッドが使えるようになる。

[Enumerableモジュール](http://doc.okkez.net/static/1.8.7/class/Enumerable.html)