コンテンツへスキップ

フック

コンパイル時に、特定の状況でフックとして呼び出される特殊なマクロが存在します。

  • 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_missingmethod_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]が出力されます。