Linguagem de Programação Crystal

Macro methods

Macro defs allow you to define a method for a class hierarchy and have that method be evaluated at the end of the type-inference phase, as a macro, for that type and subtype. For example:

class Object
  macro def instance_vars_names : Array(String)
    {{ @type.instance_vars.map &.name.stringify }}
  end
end

class Person
  def initialize(@name : String, @age : Int32)
  end
end

person = Person.new "John", 30
person.instance_vars_names #=> ["name", "age"]

Note that in the case of macro defs you need to specify the return type.

In macro definitions arguments are passed as their AST nodes, giving you access to them in macro expansions ({{some_macro_argument}}). However that is not true for macro defs, here the argument list is that of the method generated by the macro def, you cannot not access their compile time value.

class Object
  macro def has_instance_var?(name) : Bool
    # We cannot access name inside the macro expansion here,
    # instead we need to use the macro language to construct an array
    # and do the inclusion check at runtime.
    {{ @type.instance_vars.map &.name.stringify }}.includes? name
  end
end

person = Person.new "John", 30
person.has_instance_var?("name") #=> true
person.has_instance_var?("birthday") #=> false