書くこと
先日書いた、こちらの記事の続きとなります。
前回の記事の概要をまとめると
Rubyのクラスとインスタンスの関係から、メソッドはどのように扱われているのか?
ということをまとめました。
今回の記事は、前回の内容を元に、Rubyのモジュールから本題のincludeについて、説明していきます。
includeとは?
早速ですが、Rubyのincludeについて少し触れていきましょう。
実際に見てもらったほうが早いので、まずはこちらをご覧ください。
class QuestionAnswer
include ActiveModel::Model #ActiveModel::Modelというモジュールをincludeしています。
end
このように、QuestionAnswer
というクラスに、ActiveModel::Model
というモジュールをincludeしています。こうすることで、
クラスにinclude モジュール名と記述することで、そのモジュールのインスタンスメソッドをクラスで使用出来るようになります。
これが、includeの大枠の役割となります。
includeとメソッドの旅
以上のincludeの役割と踏まえると、このクラスから生成されたインスタンスは、includeされたmoduleのところまでメソッドを探しに行けるというということが言えそうです。
この話は、前回の記事の最大のテーマ
インスタンスはメソッドを持つのではなく、生成されたクラスに参照しに行く性質を持つ
ということにつながってきます。このことを、もう少し端的な例で見てみましょう。
Module Alpha
def module_a_method
@a_method
end
end
class Beta
include Alpha #モジュールをincludeしました。
def class_b_method
@class_b_method
end
end
Ceta = B.new
Ceta.module_a_method
ここで、Betaクラス
から生成されたインスタンスがCeta
に代入されています。
そして、Ceta
はModule Alpha
で定義されたインスタンスメソッドmodule_a_method
を利用しています。
通常、スコープの性質上、あるクラスから生成されたインスタンスはそのクラス内に記述されたインスタンスメソッドのみを用いることができます。しかし、今回はモジュールをincludeしているので、そこで定義されているmodule_a_method
を利用することができます。
これは、以下の図で理解してもらうと良いかもしれません。
このように、生成されたインスタンスは、メソッドを参照しに行く性質があるからこそ、includeの役割が果たされるのだと理解することができました。
まとめ
- includeは、記述したクラスにそのモジュールのインスタンスメソッドを利用させることを許可(?)している
- Rubyのメソッドは、インスタンスには属さず、クラスに属している。その代わり、インスタンスはメソッドを探しに行くという性質を持つ。
- 2より、includeが成り立つのはrubyのメソッドの性質が寄与していることがわかる
おまけ
Githubを確認したところ、
module Model
extend ActiveSupport::Concern
include ActiveModel::AttributeAssignment
include ActiveModel::Validations #ActiveModelから、Validationsをincludeしている
include ActiveModel::Conversion
(中略)
end
このことから、バリデーションを設定することも可能になります。
class QuestionAnswer
include ActiveModel::Model
validates :answer, presence: true
ActiveModel::Model
も、上位のモジュールをincludeしているのですねぇ。
感想
このincludeが理解できたことで、今まで形式的に覚えていたことが芯から理解できるようになる気がします。こういう根本を知っていくって、楽しいですよね。
最後に
最後まで読んでいただき、ありがとうございます。
ソースコード、記事の書き方について「もっとこうしたほうがいいよ!」というご意見、「そこどうなっているの?」というご質問など、お待ちしております。