RubyのMixinを簡単にだけ整理したメモ
たまにはRubyを。
元ネタというかメインで参照したのはこちら
prependって結局どうなんだっけ?prependをクラスメソッドにするにはどうするんだっけ?というところを整理したかったので。
実行環境は、ruby2.3.1p112
ruby --version ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]
サンプルコード
Abstract moduleを各クラスに突っ込む。
module Abstract def self.included(klass) puts "" puts "Included hook: #{klass}" puts "ancestors: #{klass.ancestors}" puts "singleton: #{klass.singleton_class.ancestors}" end def self.prepended(klass) puts "" puts "Prepended hook: #{klass}" puts "ancestors: #{klass.ancestors}" puts "singleton: #{klass.singleton_class.ancestors}" end def self.extended(klass) puts "" puts "Extended hook: #{klass}" puts "ancestors: #{klass.ancestors}" puts "singleton: #{klass.singleton_class.ancestors}" end def say puts "Hello, World!" end end class Include include Abstract def say puts "Hello!" end end Include.new.say class Prepend prepend Abstract def say puts "Hello!" end end Prepend.new.say class Extend extend Abstract def self.say puts "Hello!" end end Extend.say class SelfPrepend class << self prepend Abstract def say puts "Hello!" end end end SelfPrepend.say class ClassPrepend singleton_class.prepend Abstract def self.say puts "Hello!" end end ClassPrepend.say
アウトプット
Included hook: Include ancestors: [Include, Abstract, Object, Kernel, BasicObject] singleton: [#<Class:Include>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject] Hello! Prepended hook: Prepend ancestors: [Abstract, Prepend, Object, Kernel, BasicObject] singleton: [#<Class:Prepend>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject] Hello, World! Extended hook: Extend ancestors: [Extend, Object, Kernel, BasicObject] singleton: [#<Class:Extend>, Abstract, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject] Hello! Prepended hook: #<Class:SelfPrepend> ancestors: [Abstract, #<Class:SelfPrepend>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject] singleton: [#<Class:#<Class:SelfPrepend>>, #<Class:#<Class:Object>>, #<Class:#<Class:BasicObject>>, #<Class:Class>, #<Class:Module>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject] Hello, World! Prepended hook: #<Class:ClassPrepend> ancestors: [Abstract, #<Class:ClassPrepend>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject] singleton: [#<Class:#<Class:ClassPrepend>>, #<Class:#<Class:Object>>, #<Class:#<Class:BasicObject>>, #<Class:Class>, #<Class:Module>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject] Hello, World!
理解したこと
prependはancestorsで考えたときに、子孫側に挿入される。
include/extendはancestorsで考えたときに、祖先側に挿入される。
extendは、singleton_class(特異クラス)に対して挿入される。
クラスメソッド(として扱うもの)をprepend
する書き方は2パターンある。(詳しく追っていないので、どちらかがまずい方法だ、みたいなツッコミ歓迎。)