> because it is quite slow and because of inherent namespace pollution
you mention two very important problems I wanted to name in my talk
- performance: One needs to reduce runtime as much as possible, like by memoization
- namespace polution: The effects of the embedded language must be contained to a lexical scope.
You are already using one basic tool to achieve this: blocks.
performance
All your html/xml elements take a code-block as *{$_} = sub(&) { _elem($name, @_) }; and should per default
memorize the result and return the pre-calculated result.
Of course one would need exception for cases where dynamic elements have to be interpolated,
like in loops, either by explicitly deactivating memoization or by parsing the block for closed over variables.
namespace
1. The most obvious solution is to use a package , something like
render { package HTML::DSL;
HTML {
HEAD {
TITLE { "foo bar"};
};
...
}
2. Of course it would be syntactically "sweeter" if the package was automatically included.
The way to go is to use B::Deparse 's coderef2text to get the source and to re-eval it with an included package declaration in the first line.
Actually it's a bit more complicated, because you might have closed over variables inside the block which would loose their binding after evaluation.
That's why you need to inspect to take care for this, I already wrote code for this in my Macro module (github only).
This is actually the way how many (most) DSL's are constructed in Ruby, they "re-eval" the code (instance_eval or instance_exec) from inside a block.
And since they ran into the same problem with lost bindings of closure vars, a module called Docile was created to reestablish the bindings ...
... or in their own words "the hard part", where most folks making a DSL in Ruby throw up their hands
|