rubyのrequire/include/extend/継承/クラス拡張ミックスインまとめ
require/include/extend/継承の違い
require
- 外部ライブラリファイルの読み込み
include
- クラスでモジュールをインクルードすると、モジュールのインスタンスメソッドが手に入る obj.my_method
- クラスメソッドを手に入れるには、クラスの特異クラスでモジュールをインクルードする:MyClass.my_method
- それをショートカットするのがextends。:MyClass.my_method
module A def hello "hello" end end class B include A end test = B.new test.hello => #"hello" B.hello => #"NoMethodError"
extend
- includeはインスタンスメソッドを差し込むのに対して、extendは特異メソッドをインクルードするかたちになる
- だからクラス定義の中でextendすると、クラスの特異メソッド=クラスメソッドになる
- クラスの特異メソッドにインクルード = extend
class C extend A end C.hello => #"hello" test = C.new test.hello => #"NoMethodError" test.extend(A) test.hello => #"hello"
module M1 module ClassMethods def print01 puts "#print01" end end end class C1 extend M1::ClassMethods end C1.print01
クラスの特異メソッドにインクルード
class T01 class << self include Post3 end end T01.print_post3
継承
- rubyでは単一継承のみ
- 多重継承は、mix-in(後述)という概念で対応している
class Ex01 def print01 puts "#print01" end class << self def print02 puts "#print02" end end end class T04 < Ex01 end t04 = T04.new t04.print01 T04.print02
クラス拡張ミックスイン
module Foo def self.included base base.send :include, InstanceMethods base.extend ClassMethods end module InstanceMethods def bar1 puts 'bar1' end end module ClassMethods def bar2 puts 'bar2' end end end class Test include Foo bar2 end t1 = Test.new t1.bar1
実行結果
bar1 bar2
注意点
base.include InstanceMethods
これだと
mixin.rb:3:in `included': private method `include' called for Test:Class (NoMethodError)
といって、怒られる includeは、プライベートメソッドなので、base.sendが必要
ruby - Inheriting class methods from mixins - Stack Overflow
includeしているmoduleをextendする
module Mod1 def module_method1 puts "#module_method1" end end module Core include Mod1 end class T01 extend Core end # Core.module_method1 => error T01.module_method1 t01 = T01.new # t01.module_method1 => error module Mod1 def module_method1 puts "#module_method1" end end module Core include Mod1 end class T01 extend Core module_method1 end
実行結果
#module_method1 #module_method1
メソッド内でのinclude/extend
- メソッドをコールした時にinclude/extendすることができる
module Post def print_post puts "#print_post" end end module Post2 def print_post2 puts "#print_post2" end end class T03 class << self def register # includeでは、エラー extend Post end def register2 class << self include Post2 end end end end # registerを実行してはじめて、extendされる # その後、print_post1が実行できる T03.register T03.print_post # register2を実行してはじめて、includeされる # その後、print_post2が実行できる T03.register2 T03.print_post2