Code generation using macros

Hello all, new to macros and would love if someone can explain what’s going on here. I’m attempting to write a macro that would add a few methods to the caller but it plain refuses to work. Pasting the same method that would be generated by the macro into the class works as expected. I’m confused by the behavior of @type.instance_vars and @type.class_vars, I understand they return [] when used outside a method but I’m baffled it works only when used inside the class declaration itself and not within a macro? Hope this makes sense…


macro m1
    def quux
        {% p! @type %}
        {% p! @type.class_vars %}
        {% p! @type.instance_vars %}
    end
end


class Foo
    @@table = "foo"
    property id : Int32 = 123

    def quux
        {% p! @type %}
        {% p! @type.class_vars %}
        {% p! @type.instance_vars %}
    end
    # m1
end

Foo.new.quux # prints Foo, [table], [id] when quux is defined in the class
Foo.new.quux # prints Foo, [], [] if I comment out Foo#quux and use m1 macro to generate quux method instead

Thanks for any help!

The gist of it is your macro code within m1 is running when the macro expands, not in the context of the method when you call it. Given that’s the behavior you want you’d need to do like:

macro m1
  def quux
    \{% p! @type %}
    \{% p! @type.class_vars %}
    \{% p! @type.instance_vars %}
  end
end

See Macros - Crystal.

Using verbatim is more suitable for the current context?

macro m1
  {% verbatim do %}
    def quux
      {% p! @type %}
      {% p! @type.class_vars %}
      {% p! @type.instance_vars %}
    end
  {% end %}
end

class Foo
  @@table = "foo"
  property id : Int32 = 123

  m1
end