Macro argument precedence

What would be the correct way to write this macro? My intention is to just wrap some logging statements in a conditional that would not be included when --no-debug is passed to the compiler.

macro debug(args)
  {% if flag?(:debug) %}
    puts {{ args }}
  {% end %}
end

debug "Hello" # => Hello
debug [1,2,3] # => [1, 2, 3]
debug [1,2,3].map { |r| r.to_s }.join(", ") # => Error: 'Array(Int32)#map' is expected to be invoked with a block, but no block was given
debug([1,2,3].map { |r| r.to_s }.join(", ")) # => Error: 'Array(Int32)#map' is expected to be invoked with a block, but no block was given

Is this possibly an error in parsing argument precedence with macros?

Thank you!

Macro interpolation always transforms { ... } into do; ...; end, so the solution is to use parentheses for the puts call inside debug

You can also invoke the isinstance or typeof to check whether the input is of string type or not. If string type then directly join or else .to_s and then join

Is this by design? Or a bug that nobody was interested in fixing?

IMO it would be confusing if the same thing can be written in two different ways to affect macro parsing behind the scenes, so this is likely by design

1 Like