0
0

More than 3 years have passed since last update.

学び直し Rubyがミニツク Part9

Posted at

今日の教科書
モジュール

モジュール

モジュールは手続きの部分だけのまとめ。
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リファレンス

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モジュール

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0