钩子¶
在编译时,某些情况下会调用一些特殊宏作为钩子。
- 当定义子类时会调用
inherited
。@type
是继承类型。 - 当包含模块时会调用
included
。@type
是包含类型。 - 当扩展模块时会调用
extended
。@type
是扩展类型。 - 当找不到方法时会调用
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
的第二个声明,finished
宏将被运行,它将打印 [bar]
。