見出し画像

Moduleのミックスインと名前空間に関して [Ruby]

Rubyのチェリー本を参考に、Rubyの基本的な部分の理解を深めたいと思います。中でも今回はモジュールについて記載します。

Module の概要

  1. 継承を使わずにクラスにメソッドの追加・上書きできる (= ミックスイン)

  2. 名前空間を作る

クラスの継承は、「is-a の関係」に基づいています。継承関係ではないが、共通のメソッドを利用できるようにしたい。そんなときに選択肢として挙がるのがモジュールです。
ちなみにモジュールのクラスと異なる特徴は以下の通りです

  1. インスタンスを作成できない

  2. 他のモジュールやクラスを継承できない

ミックスイン: クラスにメソッドの追加・上書き

結論 / サンプルコード

モジュールの役割の1つ、ミックスインとは、いくつかのクラスに共通のメソッド・定数を利用可能にすることです。ミックスインはモジュールをモジュールに組み込むこともできます。

# モジュールを作成
module Hello
    def hello_world
        puts "Hello world!!"
    end
end

class User
    # 上で作ったモジュールをミックスインする
    include Hello
end

user=User.new
user.hello_world
#=> Hello world!!

また1つのクラスに複数のモジュールをミックスインすることもできるます。これによりRubyではミックスインを利用することで多重継承に似たしくみを実現することできます。

include module_name

モジュールにメソッドを定義し、そのモジュールをクラスでincludeすると、モジュールで定義したメソッドがインスタンスメソッドとして利用可能になります。

# モジュールをミックスイン (include)
include Hello

user=User.new
user.hello_world
#=> Hello world!!

モジュール内でメソッドを private メソッドにした場合は、ミックスイン先でも private メソッドとして扱われます。
またincludeと似た機能として、prependがあります。prependの場合、モジュールとミックスイン先のクラスに同名のメソッドがあった場合には、prependされたモジュール内のメソッドが優先されるようになります。

extend module_name

モジュールをincludeではなくextend を用いてミックスインした場合、そのクラスの特異メソッド (=クラスメソッド) として扱われます。

# モジュールをミックスイン (extend)
extend Hello

User.hello_world
#=> Hello world!!

名前空間

結論 / サンプルコード

モジュールのもう2つ目の機能は名前空間です。モジュール構文の中にクラス定義を書くと「そのモジュールに属するクラス」という意味になり、名前の衝突を防ぐことができます

# モジュール配下にクラスを定義
Module Baseball
    Class Second
        def initialize
            puts 'Baseballモジュールの中の、Secondクラスのインスタンスが作成されました'
        end
    end
end
# 該当クラスは、"モジュール名::クラス名" として認識される
Baseball::Second.new
#=> Baseballモジュールの中の、Secondクラスのインスタンスが作成されました

名前空間のその他

既に定義されているBaseballモジュールを名前空間として使いたい場合は、以下のように記述することでクラスを該当の名前空間内に定義できます。

# 既に定義済み
module Baseball
    :
end
# モジュール::クラス名の形でクラスを定義
Class Baseball::Second
    :
end

モジュールのその他

代表的な Ruby が提供する標準 モジュール

Rubyでは、公式で定義されているモジュールがいくつか存在します。これはRuby が動的型付け言語であるため、「メソッドを実行する瞬間にそのメソッドが呼び出せれば良い」という考え方に基づいています。(ここではその説明は省略)。

以下にそれらの紹介を、主にチェリー本の引用ベースで説明します。

Enumerable モジュール

Enumerableモジュールは配列やハッシュ、範囲(Range)など、何かしらの繰り返し処理ができるクラスにincludeされているモジュール

プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで

Array や Hash といったクラスには標準で組み込まれており、以下はその代表的なメソッドです。

map, select, find, countなど

# Arrayクラスには既にinclude済み
Array.include?(Enumerable) #=> true

参考: module Enumerable

Comparable モジュール

Comparableモジュールは比較演算を可能にする(つまり値の大小を識別できるようにする)モジュール

プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで

これは計算 / 演算子用のメソッドがまとまっているモジュールで、以下はその代表的なメソッドです。

<, <=, ==,  >, >=, between?

ただしこのモジュールをincludeして利用する為には、以下の条件を満たす必要があります。

Comparableモジュールのメソッドを使えるようにするための条件は、include先のクラスで<=>演算子を実装しておくことです。<=>演算子はその形状から「UFO演算子」とも呼ばれる

プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで

参考: module Comparable

Kernel モジュール

当たり前の様に利用している、以下のメソッド達が定義されているモジュール

puts p print require loop

ただしこのモジュールは自作クラスやモジュールで組み込むことはありません。なぜなら、このモジュールはデフォルトのクラスの継承元、ObjectクラスがKernelモジュールをincludeしているからです。

参考: module Kernel

include?, ancesters

表題の2つのメソッドは引数のオブジェクトに対して、該当の module が組み込まれているか確認するメソッド です。
include? は引数にモジュールを取り、クラスが引数のモジュールをミックスインしているかどうか真偽値を返します。

Object.include?(Kernel)
#=> true

ancesters はクラスやモジュールに対して呼び出し、そのオブジェクトが「継承しているクラス」と「ミックスインしているモジュール」を全て表示します。その際に継承しているクラスがミックインしているモジュールも表示され、返り値の順番は参照する優先順になります。

DVD.ancestors
#=> [DVD,B,A,Product,Object,Kernel,BasicObject]

module のその他の機能

Rubyのチェリー本には、モジュールの4つの機能を紹介していました。残りの2つの機能に関しては以下になりますが、ここでは説明を省かせて頂きます。

  1. 関数や定数を提供するモジュール ( ≒ シングルトンパターン)

  2. 状態を保持するモジュールの作成 ( ≒ 定数管理)

ちなみに上記の2つ機能は、モジュールがインスタンスを作成する必要がない (できない)、というメリットを活かした機能になっています。

モジュールと require メソッドの違い

調べていく内に、以下の疑問を抱きました。
「include」と「require」って何が違う?
気になったので調べた結果、あくまでrequireメソッドは引数のファイルを読み込むためのメソッドだそうです。なので読み込んだだけでは、特に変化はありません。例えばその読み込んだファイルがモジュールを定義したファイルだった場合、そのモジュールを include module_name で読み込まない限りはミックスインされない、という感じの違いです。(恐らく)

reauire 'app/dir1/dir2/file_name'

require

おわり

前回の記事に引き続き、RailsではなくRubyの基礎的なメソッドの理解を深める目的の記事でした!
今回のモジュールに関しても、よく見かけるにも関わらず全然理解できていないものでしたので、一度立ち戻って理解を深めることができてよかったです!

最後までお読み頂きありがとうございましたー ^_^

参考

https://www.amazon.co.jp/プロを目指す人のためのRuby入門-言語仕様からテスト駆動開発・デバッグ技法まで-Software-Design-plusシリーズ/dp/4774193976
http://blog.livedoor.jp/sasata299/archives/51268600.html

この記事が気に入ったらサポートをしてみませんか?