フック¶
コンパイル時に、特定の状況でフックとして呼び出される特殊なマクロが存在します。
inherited
は、サブクラスが定義されたときに呼び出されます。@type
は継承する型です。included
は、モジュールがincludeされたときに呼び出されます。@type
はincludeする型です。extended
は、モジュールがextendされたときに呼び出されます。@type
はextendする型です。method_missing
は、メソッドが見つからないときに呼び出されます。method_added
は、現在のスコープに新しいメソッドが定義されたときに呼び出されます。finished
は、解析が完了した後、すべての型とそのメソッドが認識された後に呼び出されます。
inherited
の例
class Parent
macro inherited
def lineage
"{{@type.name.id}} < Parent"
end
end
end
class Child < Parent
end
Child.new.lineage # => "Child < Parent"
method_missing
の例
macro method_missing(call)
print "Got ", {{call.name.id.stringify}}, " with ", {{call.args.size}}, " arguments", '\n'
end
foo # Prints: Got foo with 0 arguments
bar 'a', 'b' # Prints: Got bar with 2 arguments
method_added
の例
macro method_added(method)
{% puts "Method added:", method.name.stringify %}
end
def generate_random_number
4
end
# => Method added: generate_random_number
method_missing
とmethod_added
は、マクロが定義されているクラスとその子孫、またはマクロがクラスの外で定義されている場合はトップレベルでのみ、呼び出しまたはメソッドに適用されます。例えば
macro method_missing(call)
puts "In outer scope, got call: ", {{ call.name.stringify }}
end
class SomeClass
macro method_missing(call)
puts "Inside SomeClass, got call: ", {{ call.name.stringify }}
end
end
class OtherClass
end
# This call is handled by the top-level `method_missing`
foo # => In outer scope, got call: foo
obj = SomeClass.new
# This is handled by the one inside SomeClass
obj.bar # => Inside SomeClass, got call: bar
other = OtherClass.new
# Neither OtherClass or its parents define a `method_missing` macro
other.baz # => Error: Undefined method 'baz' for OtherClass
finished
は、型が完全に定義された後(そのクラスに対する拡張も含む)に呼び出されます。次のプログラムを考えてみましょう。
macro print_methods
{% puts @type.methods.map &.name %}
end
class Foo
macro finished
{% puts @type.methods.map &.name %}
end
print_methods
end
class Foo
def bar
puts "I'm a method!"
end
end
Foo.new.bar
print_methods
マクロは、最初に遭遇した時点で実行され、その時点ではメソッドが定義されていないため、空のリストを出力します。Foo
の2番目の宣言がコンパイルされると、finished
マクロが実行され、[bar]
が出力されます。