Rubyいわゆるフックメソッドまとめ
参考 Effective Ruby 項目28あたり
まとめないと覚えられない
- 全て特異メソッドとして定義する
- privateメソッドになる
- Object.private_methods(false).grep(/ed\z/) # => [:inherited]
- Kernel.private_methods(false).grep(/ed\z/) # => [:method_added, :method_removed, :method_undefined, :protected, :included, :extended, :prepended] (:protectedは無視で)
- 項目29で突然「クラスフック」という言葉が出てきたんだが、たぶんこいつら全部のことでいいんですよね?
- 基本、superを呼び出す事
Module
- メソッド内でselfを参照すると処理されるmoduleが参照される
Module.included(class_or_module) | include | された |
Module.prepended(class_or_module) | prepend | された |
Module.extended(object) | extend | された |
フックじゃないけどこちらに併記
- 上記の3つのメソッド直前に呼び出され、実際の処理を行う
- メソッド内でselfを参照すると処理されるmoduleが参照される
Module.append_features | include | された時に実際に処理を行い、その後 | included | が呼び出される |
Module.prepend_features | prepend | された時に実際に処理を行い、その後 | prepended | が呼び出される |
Module.extend_object | extend | された時に実際に処理を行い、その後 | extended | が呼び出される |
module M1
class << self
def included(class_or_module)
super
p "included: #{self}, #{class_or_module}"
end
def prepended(class_or_module)
super
p "prepended: #{self}, #{class_or_module}"
end
def extended(object)
super
p "extended: #{self}, #{object}"
end
def append_features(class_or_module)
super
p "append_features: #{self}, #{class_or_module}"
end
def prepend_features(class_or_module)
super
p "prepend_features: #{self}, #{class_or_module}"
end
def extend_object(object)
super
p "extend_object: #{self}, #{object}"
end
end
end
module M2
include M1
# => "append_features: M1, M2"
# => "included: M1, M2"
prepend M1
# => "prepend_features: M1, M2"
# => "prepended: M1, M2"
extend M1
# => "extend_object: M1, M2"
# => "extended: M1, M2"
end
class C2
include M1
# => "append_features: M1, C2"
# => "included: M1, C2"
prepend M1
# => "prepend_features: M1, C2"
# => "prepended: M1, C2"
extend M1
# => "extend_object: M1, C2"
# => "extended: M1, C2"
end
Class
- メソッド内でselfを参照すると継承される自分自身が参照される
- 呼び出された時点ではsub_classは空のクラスが定数に当てられた状態
Class.inherited(sub_class) | 継承された(されそうだ) |
class C1
class << self
def inherited(sub_class)
super
p "inherited: #{self}, #{sub_class}"
p sub_class.instance_methods(false)
end
end
end
class C2 < C1
def test_method
end
end
# => "inherited: C1, C2"
# => []
p C2.instance_methods(false)
# => [:test_method]
Module or Class
- selfを参照すると対象のModule_or_Classが参照される
- singleton_method_added は自分自身の追加に反応する
Module_or_Class.method_added(method_name_sym) | インスタンスメソッドが | add | された |
Module_or_Class.method_removed(method_name_sym) | インスタンスメソッドが | remove | された |
Module_or_Class.method_undefined(method_name_sym) | インスタンスメソッドが | undef | された |
Module_or_Class.singleton_method_added(method_name_sym) | 特異メソッドが | add | された |
Module_or_Class.singleton_method_removed(method_name_sym) | 特異メソッドが | remove | された |
Module_or_Class.singleton_method_undefined(method_name_sym) | 特異メソッドが | undef | された |
module M1
class << self
def method_added(method_name_sym)
super
p "method_added: #{self} #{self.class} #{method_name_sym}"
end
def method_removed(method_name_sym)
super
p "method_removed: #{self} #{self.class} #{method_name_sym}"
end
def method_undefined(method_name_sym)
super
p "method_undefined: #{self} #{self.class} #{method_name_sym}"
end
end
def method1
end
# => "method_added: M1 Module method1"
define_method(:method2) do
end
# => "method_added: M1 Module method2"
remove_method(:method1)
# => "method_removed: M1 Module method1"
undef_method(:method2)
# => "method_undefined: M1 Module method2"
end
class C1
class << self
def method_added(method_name_sym)
super
p "method_added: #{self} #{self.class} #{method_name_sym}"
end
def method_removed(method_name_sym)
super
p "method_removed: #{self} #{self.class} #{method_name_sym}"
end
def method_undefined(method_name_sym)
super
p "method_undefined: #{self} #{self.class} #{method_name_sym}"
end
end
def method3
end
# => "method_added: C1 Class method3"
define_method(:method4) do
end
# => "method_added: C1 Class method4"
remove_method(:method3)
# => "method_removed: C1 Class method3"
undef_method(:method4)
# => "method_undefined: C1 Class method4"
end
module M1
class << self
def singleton_method_added(method_name_sym)
super
p "singleton_method_added: #{self} #{self.class} #{method_name_sym}"
end
# => "singleton_method_added: M1 Module singleton_method_added"
def singleton_method_removed(method_name_sym)
super
p "singleton_method_removed: #{self} #{self.class} #{method_name_sym}"
end
# => "singleton_method_added: M1 Module singleton_method_removed"
def singleton_method_undefined(method_name_sym)
super
p "singleton_method_undefined: #{self} #{self.class} #{method_name_sym}"
end
# => "singleton_method_added: M1 Module singleton_method_undefined"
end
class << self
def method1
end
# => "singleton_method_added: M1 Module method1"
end
define_singleton_method(:method2) do
end
# => "singleton_method_added: M1 Module method2"
class << self
remove_method(:method1)
# => "singleton_method_removed: M1 Module method1"
end
class << self
undef_method(:method2)
# => "singleton_method_undefined: M1 Module method2"
end
end
module C1
class << self
def singleton_method_added(method_name_sym)
super
p "singleton_method_added: #{self} #{self.class} #{method_name_sym}"
end
# => "singleton_method_added: C1 Module singleton_method_added"
def singleton_method_removed(method_name_sym)
super
p "singleton_method_removed: #{self} #{self.class} #{method_name_sym}"
end
# => "singleton_method_added: C1 Module singleton_method_removed"
def singleton_method_undefined(method_name_sym)
super
p "singleton_method_undefined: #{self} #{self.class} #{method_name_sym}"
end
# => "singleton_method_added: C1 Module singleton_method_undefined"
end
class << self
def method3
end
# => "singleton_method_added: C1 Module method3"
end
define_singleton_method(:method4) do
end
# => "singleton_method_added: C1 Module method4"
class << self
remove_method(:method3)
# => "singleton_method_removed: C1 Module method3"
end
class << self
undef_method(:method4)
# => "singleton_method_undefined: C1 Module method4"
end
end