5.モジュール
1.モジュール
モジュールは、基本的にはクラスと同じものです。
クラスは、このモジュールを継承しています。
モジュールの用途は、主に名前空間とミックスインとしての利用です。

クラスを使用しても同じことが多いですが、
基本的にインスタンスの作成を目的としないものにはモジュールを使用します。
2.クラスとの違い
1.インスタンス生成の可否
モジュールはインスタンスを作成することができません。
module Mod
end
Mod.new   # => ERROR
2.継承の可否
モジュールは、サブクラスを持つことができません。
module SuperMod
end
module Mod < SuperMod  # => ERROR
end
ただし、ミックスインで同等のことが可能です。
module SuperMod
end
module Mod
  include SuperMod
end
3.Mix-in の可否
モジュールは、ミックスインすることができますが、クラスはできません。
module Mod
end
class Hoge
  include Mod
end
include Hoge  # => ERROR
4.メソッドの有無
Class は、Module を継承しているため Module のメソッドをすべて使用できますが、例外もあります。
Module#module_function、Module#extend_object、Module#append_features
これら、3つのメソッドはクラスで使用することができません。
3.名前空間
名前空間は、名前の衝突を防ぐための手段です。

関連する定数やクラスやモジュールをグループにまとめます。
同名のものがあっても望んだオブジェクトを参照できます。
通常は、グローバル空間への定義は避けるので、クラスや定数はモジュールに内包します。
CONST = 0
module ABC
  CONST = 123
  module DEF
    CONST = 456
  end
end

p CONST, ABC::CONST, ABC::DEF::CONST
include ABC
p CONST, ABC::CONST, DEF::CONST
4.モジュール関数
モジュール関数は、オブジェクト指向プログラミングが不要なときに使用します。
module_function メソッドを使用すると、以降のメソッドをモジュール関数として定義します。
モジュール関数は、プライベートメソッドとクラスメソッドの2つの同じメソッドが定義されたものです。

例えば、RGSS 組み込み関数の load_data と save_data のようなものをモジュール関数として定義します。
# 実装は省略
module RVData
  DIR_DATA = "Data"
  F_ACTOR = "#{DIR_DATA}/Actors.rvdata"
  
  module_function
  def load(filename)
  end
  def save(obj, filename)
  end
end

$data_actors = RVData.load(RVData::F_ACTOR)
include RVData
save($data_actors, F_ACTOR)
こうすることで、冗長な名前を付けずに名前のバッティングを防ぐことができます。
また、関連するメソッドをまとめることができるため、管理も楽になります。
5.ミックスイン
クラスには、継承という機能があり同じような機能を持つクラスを別々に作る必要はありません。
しかし、同じような機能でも、まったく別の目的のクラスであれば、継承での共有化は適切ではありません。
このような場合に、モジュールを使用すると、継承階層から独立した実装を共有することができます。

ミックスインには、クラスオブジェクトに行うincludeと特定のオブジェクトへ行うextendがあります。
module Mod
end
class Hoge
  # モジュールのメソッドを追加
  include Mod
  # モジュールのインスタンスメソッドをクラスメソッドとして追加
  extend Mod
  
  def initialize
    # include と同じ意味
    self.extend(Mod)
  end
end
# 特異メソッドとして追加
Hoge.new.extend(Mod)
クラスは、単一継承のみをサポートしていますが、このミックスインを使うと多重継承を行うことができます。
複数のモジュールをインクルードした場合は、インクルード順に新しいものが上位となります。
include と extend の引数は、複数指定することができます。

モジュールをミックスインすると、そのクラスの継承階層にモジュールを割り込ませることができます。
クラスがモジュールを継承した形になりまので、super を使用するとモジュールのメソッドが呼ばれます。
また、モジュールと is_a の関係が作られます。
module M
  def a; "M"; end
  def b; "M"; end
  def c; "M"; end
end
class A
  def a; "A"; end
  def c; "A"; end
end
class B < A
  include M
  def b; "B"; end
  def c; super; end
end

p B.ancestors     # => [B, M, A, Object, Kernel]
a = B.new
p a.a, a.b, a.c   # => "M", "B", "M"
p a.is_a?(M)      # => true
6.今回のポイント
・ インスタンスの作成が不要なクラスはモジュールで実装する
・ 関連のないクラスで機能を共有するためにモジュールを使用する
・ グローバル空間での定数やメソッドの定義は避ける