今日の教科書
モジュール
#モジュール
モジュールは手続きの部分だけのまとめ。
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
##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メソッドといったメソッドが使えるようになる。