Re: Call macro with new root
"John Redford" <[email protected]>
| Newsgroups | gmane.comp.web.freemarker.user |
|---|---|
| Message-ID | <[email protected]> |
Indeed, it's clearly not possible. This is more of a "feature request". The
suggestion of using a passed parameter won't quite solve the problem here,
because there is a fundamental inconsistency between how macros are called
from other macros and how they are called from Java.
+ When invoked from Java, you pass a "root", which _itself_ cannot be
accessed, but which provides names to the macro.
+ When invoked from a macro, you (can) pass one-or-more named objects which
can contain names & other objects.
I am using macros both directly from Java and from other macros, and I don't
want to replicate a complex set of macros to be able to accommodate both
calling conventions. This is really two or three feature requests:
1. It should be possible to invoke a macro from a macro as if it were being
invoked from Java with a given "root" value. This will facilitate
reusability of macros.
2. When invoked from Java, the "root" object itself should be available
(i.e. ${root}). This may not be useful when the root is an actual Map, but
it would be useful when the root is an actual object/bean.
3. It should be possible to invoke a top-level macro from Java with passed
parameters, if as it were being invoked by another macro. (I have no
immediate use for this, but I am sure it would be useful for someone.)
Between the three, I am most interested in #1, because I think that the
simpler a macro is, the better -- and while having the complex
parameter-passing features is great when they're needed, I'd prefer to not
use them excessively -- particularly as the content of the macros themselves
is somewhat complicated.
Thus I can have a macro:
<#macro Foo>...long, complicated text, coditionals, etc....
${name}...${url}...${something}...</#macro>
And then call it from Java (Where I have a wrapper around a Configuration
with an auto-import that takes a macro name and simply returns the string)
as:
for (Widget w : widgets ) { String s = fm.macro("Library.Foo", w); ... }
And call it from within another macro (here in the same namespace):
<#list widgets as w>
<@Foo=w/>
</#list>
If #2 were implemented, then I could write the somewhat uglier version:
<#macro Foo c>...long, complicated text, coditionals, etc....
${c.name}...${c.url}...${c.something}...</#macro>
<#macro JavaFoo><@Foo c=${.root}</#macro>
The present implementation necessitates having the Java layer wrap the root
object in a hash, pass that, and then use the uglier macros:
<#macro Foo c>...long, complicated text, coditionals, etc....
${c.name}...${c.url}...${c.something}...</#macro>
<#macro JavaFoo><@Foo c=${.root}</#macro>
Map<String,T> wrapRoot(T root) { ...return map with key "root" mapped to
the root value }
for (Widget w : widgets ) { Map<String,Widget> wrapper = wrapRoot(w);
String s = fm.macro("Library.Foo", wrapper); ... }
The "macro" wrapper I am using could be updated do this wrapping
automatically, so the Java code could still look reasonably nice; but having
to have "Java entry point" macros and qualifier parameters would be nice to
do without.
Daniel Dekany wrote:
>
> It's not possible to do as far as I see. Especially as it should be
lexically scoped
> (in most applications at least). The best you can do is something like:
>
> <#macro Product>
> <#local c = latestProduct> <#-- c for context -->
> ${c.name} (${c.url})
> </#macro>
>
> Then at least it's obvious what's going on...
>
> Thursday, July 28, 2011, 9:24:14 PM, John Redford wrote:
>
> > I want to be able to call a macro with a given node used as the
effective
> "root"
> > for the called macro. For example, given the data model:
> >
> > (root)
> > |
> > +- user = "Big Joe"
> > |
> > +- latestProduct
> > |
> > +- url = "products/greenmouse.html"
> > |
> > +- name = "green mouse"
> >
> > I want to have these macros:
> >
> > <#macro Product>
> > ${name} (${url})
> > </#macro>
> >
> > <#macro Describe>
> > ${user}'s latest product is <@Product=latestProduct/>.
> > </#macro>
> >
> > Such that the result is:
> >
> > Big Joe's latest product is green mouse (products/greenmouse.html).
> >
> > I have looked into ways to achieve something like this using
> > TemplateDirectiveModel to writing a directive that re-roots the
> environment, but
> > that does not seem possible.
------------------------------------------------------------------------------
Got Input? Slashdot Needs You.
Take our quick survey online. Come on, we don't ask for help often.
Plus, you'll get a chance to win $100 to spend on ThinkGeek.
http://p.sf.net/sfu/slashdot-survey