はじめに
これまで個人開発をしていて、Railsでmoduleを使うことはほとんど使うことはありませんでした。
実際にインターンをしてみると、moduleってかなり使われているなという印象です(特に名前空間としての役割)。
moduleがclassとどう違うのかや、どんな使われ方をするのかなどをまとめたいと思います。
moduleとclassの違いについて
moduleとclassの違いは以下の記事がとてもわかりやすいです。
- moduleはインスタンスを生成できないが、classはできる
- moduleは他のmoduleやclassを継承することはできないが、classは継承することができる
主な使い方
- 名前空間として使う
- メソッドを格納する場所として使う
名前空間としての使い方
特にこの使い方が多いのかなと思います。
moduleを使ってネストさせることによって名前空間を作ることができます。
小さなプロジェクトであれば名前の衝突をすることはほとんどありませんが、企業のリポジトリとなるとそうはいきません。
クラス名が同じだったとしても、それをラッピングするmoduleが異なれば衝突することはありません。
module Rspec
module Rails
class ActiveRecordConfiguration
# ...
end
end
end
↑ RSpec::Rails::ActiveRecordConfiguration
参照の際には::
を使って表すことができます。
メソッド格納としての使い方
moduleではメソッドを格納することができます。
mixinして他のクラスで使うこともできますし、そのmodule単体のメソッドとして使うこともできます。
module単体で使いたいとき
module Mod
def return_hello
'hello'
end
module_function :mod_only
end
module_functionで指定することでmodule単体のメソッドとして定義されます。
=> Mod.return_hello
で参照することができます。
mixinして使う場合
-
moduleをインスタンスメソッドとしてmixinしたいとき
↓ Post classでMod moduleをmixinすると想定します
module Mod
def return_hello
'hello'
end
def return_self_instance
return self
end
def return_self_attribute_title
return self.title
end
def mod_only
return 'only_module'
end
module_function :mod_only
end
使いたいクラス内でincludeします。
class Post < ApplicationRecord
include Mod
end
post = Post.first
post.return_hello # => "hello"
post.return_self_instance # => #<Post:0x000056107ac12fd8...
post.return_self_attribute_title # => postインスタンスがtitle attributeを持っていた場合にはその値が返される(なければundefined method `title'が返される)
post.mod_only # => no method errorが返される
どのクラスにincludeすることもできます。
attributeが一致しているならばself.attributeのようにmoduleでメソッドを定義しても、呼び出したクラスから使うことができます。
module_functionで指定しているものはmodule単体でしか使えないためinclude先で使うことはできません。
複数のクラスに共通する処理はmoduleに切り出すのがいいのかなと思います。
-
moduleをクラスメソッドとしてmixinしたいとき
クラスメソッドとしてmixinしたい場合にはextend
を使います。
要領はインスタンスメソッドとしてmixinするときと全く同じです。
class Post < ApplicationRecord
extend Mod
end
Post.return_hello # => 'hello'が返ってくる
Post.return_self_instance # => selfを返すクラスメソッドであるためPost classが返ってくる
# => Post(id: integer, title: string, content: string, user_id: integer, created_at: datetime, updated_at: datetime)