Then when run load_src the second time, above literal load_src macro will be run, then get expected result.
am i misunderstanding something? as a rubyist, I’m not the best, but I’m pretty good, i almost read done the documents in reference, the only challenge is macro.
No, you guessed exactly what happen here .
As far as know, the compiler has the following behavior: while there are macro calls or {{ / {%, it expend these, until there are no more to expand. Then it executes semantics recursively on inner of defs, and expands macros inside each until there are no more.
Yeah macro are not the simplest part, but once mastered, it’s really a powerful feature, you can just does almost everything you want at compile time. (except perhaps coffee )
Still one more question, as in above example, we have to use nested macro to make it work
i guess the reason is, there is no way to make {{ROOT.id}} in regex to expand correct in this case.
because, {{ROOT.id}} should interpolate into the regex literal.
For only this reason, which we need nested macro, maybe overkill i think.
if there is another more simple way to do same things, but not need nested macro?
In fact, we need use __DIR__[ROOT.size-1..] instead of __DIR__[ROOT.size..], and we don’t need the starts_with? check, because it always true.
following is my refactored version use your’s hack, it works.
{% begin %}
ROOT = "{{system("pwd").strip.id}}"
{% end %}
{% begin %}
# strip the ROOT part of spec_helper.cr, and replace the left folder name with ..
# then strip the first dot.
# e.g. it replace `/home/zw963/Study/Crystal/test_macro/src/config` to `./..`
PATH = {{__DIR__[ROOT.size+1..].gsub(%r{[^/]+}, "..")[1..]}}
{% end %}
macro spec(file)
require "{{PATH.id}}/spec/{{file.id}}"
end
macro src(file)
require "{{PATH.id}}/src/{{file.id}}"
end
Though, i have one more question about macro.
Why macro not designed to like ERB, that is, all {% … %} use same context scope, if that is true, we can replace the ROOT and PATH with it lowercase version, and use it in only one begin/end block, like this:
{% begin %}
root = "{{system("pwd").strip.id}}"
path = {{__DIR__[root.size+1..].gsub(%r{[^/]+}, "..")[1..]}}
{% end %}
macro spec(file)
require "{{path.id}}/spec/{{file.id}}"
end
macro src(file)
require "{{path.id}}/src/{{file.id}}"
end
Above code not work, with two error:
code when define path variable could not see the root variable in same begin/end scope.
code in macro could not see path variable in another begin/end scope.
It’s because each macro act independently and gets they own variables. I thinks it would be a mess if all macro vars were global. Under each call, it can have several macro triggered. The name collision would be big.
Something like that works too^^: (be careful to declare root inside a macro interpolation and not like a normal local var, this value would not be accessible at compile time ).
{% begin %}
{% root = system("pwd").strip.id %}
PATH = {{__DIR__[root.size..].gsub(%r{[^/]+}, "..")[1..]}}
{% end %}
macro spec(file)
require "{{PATH.id}}/spec/{{file.id}}"
end
macro src(file)
require "{{PATH.id}}/src/{{file.id}}"
end
this should be the final(simplest version) (NOT WORK)
{% begin %}
{% root = system("pwd").strip.id %}
# strip the ROOT part of spec_helper.cr, and replace the left folder name with ..
# then strip the first dot.
# e.g. it replace `/home/zw963/Study/Crystal/test_macro/src/config` to `./..`
PATH = {{__DIR__[root.size+1..].gsub(%r{[^/]+}, "..")[1..]}}
{% end %}
macro spec(file)
require "{{PATH.id}}/spec/{{file.id}}"
end
macro src(file)
require "{{PATH.id}}/src/{{file.id}}"
end
write this need so many knowledge of macro, i learned a lot, thank you very much!