From: Marc P. <ma...@an...> - 2005-03-11 13:18:08
|
Hi, Long time no speak! I finally got around to getting 2.0b1 (only a year late!) and am working on the start of CMS using WM. I wonder if I'm being really stupid, but I want some of the content, which is pulled in from String data, to be treated as a WM template. So given a content string loaded from the CMS, say "<p>Hello, $name</p>", I want to use this in my page, a template itself, but have $name evaluate. i.e. something like this in the main CMS rendering template: <div> #eval $content.Data using { "contextData": $someData } </div> ...but eval only works with Macro objects to my knowledge. Does anybody know how I can do this? I effectively want the same as #include but from a String instead of a file. I've tried: <div> #templet $block $content.Data #end #eval $block using { "contextData": $someData } </div> ...but of course this is not correct as $content.Data is not evaluated at the time the templet is defined. I also tried #setblock as macro etc. It's a bit confusing. I'd like to not have to write a helper/directive to load a Macro tempalte from a String unless I have to... Thanks in advance. -- Marc Palmer - - - wj...@wa... Wangjammers, J2ME Developers ~ http://www.wangjammers.org/games/ Blog ~ http://www.jroller.com/page/Wangjammer5 |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2005-03-11 13:39:07
|
On Friday 11 March 2005 13:16, Marc Palmer wrote: > Hi, > > Long time no speak! > > I finally got around to getting 2.0b1 (only a year late!) and am working > on the start of CMS using WM. > > I wonder if I'm being really stupid, but I want some of the content, > which is pulled in from String data, to be treated as a WM template. > > So given a content string loaded from the CMS, say "<p>Hello, > $name</p>", I want to use this in my page, a template itself, but have > $name evaluate. i.e. something like this in the main CMS rendering > template: > > <div> > #eval $content.Data using { "contextData": $someData } > </div> > > ...but eval only works with Macro objects to my knowledge. > > Does anybody know how I can do this? I effectively want the same as > #include but from a String instead of a file. > > I've tried: > > <div> > #templet $block > $content.Data > #end > #eval $block using { "contextData": $someData } > </div> > > ...but of course this is not correct as $content.Data is not evaluated > at the time the templet is defined. I also tried #setblock as macro etc. > > It's a bit confusing. I'd like to not have to write a helper/directive > to load a Macro tempalte from a String unless I have to... Would it not be possible to have an implementation of TemplateProvider that used the name of the template as the contents of the template itself? This would let you say:- #include as template "<p>Hello, $name</p>" or #include as template "$templateSource" Of course, this would rather cripple your normal template loading, so there could be a switch which looked for a given header such as:- #include as template "evaluate:$templateSource" and if it didn't start with "evaluate:" then it would just delegate the request to the default template loader. If this fixed your problem then it would be relatively easy to implement... Alex |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2005-03-11 14:14:09
|
On Friday 11 March 2005 13:41, Alex Twisleton-Wykeham-Fiennes wrote: <Snip> > > It's a bit confusing. I'd like to not have to write a helper/directive > > to load a Macro tempalte from a String unless I have to... > > Would it not be possible to have an implementation of TemplateProvider that > used the name of the template as the contents of the template itself? > > This would let you say:- > > #include as template "<p>Hello, $name</p>" > > or > > #include as template "$templateSource" > > Of course, this would rather cripple your normal template loading, so there > could be a switch which looked for a given header such as:- > > #include as template "evaluate:$templateSource" > > and if it didn't start with "evaluate:" then it would just delegate the > request to the default template loader. Actually I was a bit wrong. What you want is a TemplateLoader. Here is proof of concept:- package org.cord.node; import org.webmacro.*; import org.webmacro.engine.*; import org.webmacro.resource.*; public class EvaluatingTemplateLoader extends AbstractTemplateLoader { public void setConfig(String config) { } public Template load(String query, CacheElement ce) throws ResourceException { return new StringTemplate(broker, query); } } Then put this in your template evaluater:- TemplateLoaderPath.n=evaluate: TemplateLoader.evaluate=org.cord.node.EvaluatingTemplateLoader where n is higher than any other TemplateLoaderPath to ensure that it doesn't jump on other templates. and then you can do:- #include as template "<p>Hello, \$name</p>" note that the escape of the $ in the passed template is necessary to prevent it getting prematurely evaluated... You can now do the same thing off variables like so:- #set $templateSource = "<p>Hello, \$name</p>" #include as template "$templateSource" and this all works fine... Alex ps thought that it would be funky to be able to chain these like so:- #include as template "#include as text "<normalTemplatePath>"" but WebMacro obviously thinks that this is on crack... |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2005-03-11 14:20:54
|
Last message (promise) :-) Here is a more efficient implementation:- package org.cord.node; import org.webmacro.*; import org.webmacro.engine.*; import org.webmacro.resource.*; public class EvaluatingTemplateLoader extends AbstractTemplateLoader { public final static String PROTOCOL = "evaluate:"; public void setConfig(String config) { } public Template load(String query, CacheElement ce) throws ResourceException { if (! query.startsWith(PROTOCOL)) { return null; } return new StringTemplate(broker, query.substring(PROTOCOL.length())); } } TemplateLoaderPath.1=evaluate: TemplateLoader.evaluate=org.cord.node.EvaluatingTemplateLoader #include as template "evaluate:<p>Hello, \$name</p>" This will now get invoked first of all out of the chain of TemplateLoaders and will rapidly discard any request that doesn't start with "evaluate:" thereby grabbing any requests as possible. The advantage with this is that the contents of the string that you are going to evaluate are going to change across a wide range of values. If the EvaluatingTemplateLoader is the last in the chain then all your default template loaders are going to have to scan their sources for each of your dynamic templates which will end up being very expensive. Hope this helps Alex |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2005-03-11 14:36:05
|
All, a question this time: If I want to extend my EvaluatingTemplateLoader to play nice with the caching construct then I am a little bit confused about the logic of the CacheReloadContext. If I have the following code:- package org.cord.node; import org.webmacro.*; import org.webmacro.engine.*; import org.webmacro.resource.*; public class EvaluatingTemplateLoader extends AbstractTemplateLoader { public final static String PROTOCOL = "evaluate:"; public void setConfig(String config) { } public Template load(String query, CacheElement ce) throws ResourceException { if (! query.startsWith(PROTOCOL)) { return null; } ce.setReloadContext(new CacheReloadContext() { public boolean shouldReload() { return false; } }); return new StringTemplate(broker, query.substring(PROTOCOL.length())); } } then does that mean for a given value of query (which in this case actually holds the evaluatable content of the template) that the CacheManager will not invoke load(query,ce) on the EvaluatingTemplateLoader after the initial request? If this is the case, then will the CacheManager expire the mapping of query:StringTemplate after some time (based around the implementation of CacheManager) or does it mean that it will try and hold onto it forever, thereby polluting the cache space? My gut reaction is that the above is correct because the CacheReloadContext appears to relate to whether or not the relationship between query & resolvedQueryContent has changed, which in this case is guaranteed never to happen. Thanks for you help Alex |
From: Marc P. <ma...@an...> - 2005-03-11 15:44:36
|
Alex Twisleton-Wykeham-Fiennes wrote: > Last message (promise) :-) > > Here is a more efficient implementation:- Thanks for this. I'm trying it out now but not having any luck, I get: 15:38:43 resource WARNING BrokerTemplateProvider: Template not found: string: My webmacro.properties has: TemplateLoader.string=org.webmacro.resource.StringTemplateLoader Providers.template=org.webmacro.resource.DelegatingTemplateProvider TemplateLoaderPath.1=string: TemplateLoaderPath.2=broker: Is this correct? I've used your code verbatim apart from I called it StringTemplateLoader and made the protocol "string:" Cheers for the help! -- Marc Palmer - - - wj...@wa... Wangjammers, J2ME Developers ~ http://www.wangjammers.org/games/ Blog ~ http://www.jroller.com/page/Wangjammer5 |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2005-03-11 15:52:08
|
On Friday 11 March 2005 15:43, Marc Palmer wrote: > Alex Twisleton-Wykeham-Fiennes wrote: > > Last message (promise) :-) > > > > Here is a more efficient implementation:- > > Thanks for this. I'm trying it out now but not having any luck, I get: > > 15:38:43 resource WARNING BrokerTemplateProvider: Template not found: > string: > My webmacro.properties has: > > TemplateLoader.string=org.webmacro.resource.StringTemplateLoader > > Providers.template=org.webmacro.resource.DelegatingTemplateProvider > > TemplateLoaderPath.1=string: > TemplateLoaderPath.2=broker: > > Is this correct? I've used your code verbatim apart from I called it > StringTemplateLoader and made the protocol "string:" > > Cheers for the help! Two questions:- 1. what package did you put your StringTemplateLoader class into? 2. what was in the WebMacro template that threw the error? Alex |
From: Marc P. <ma...@an...> - 2005-03-11 15:59:11
|
> > Two questions:- > > 1. what package did you put your StringTemplateLoader class into? package org.webmacro.resource; ...I have an orthogonal source tree for my framework WebMacro Ignition, which was/will probably still be open source and this stuff is in the non-Ignition specific packages of stuff that will work with WM standalone... > 2. what was in the WebMacro template that threw the error? #include "pagebegin.wm" <p> #foreach $contentItem in $content #if ($contentItem.View) #include "views/$(contentItem.View).wm" #else #if ($contentItem.ContentType = "text/html") <div> <h1>$contentItem.Description</h1> #include as template "string:$contentItem.Data" </div> #end #end #end </p> #include "pageend.wm" The String returned by $contentItem.Data is the text to use as the template, i.e. "<p>Hello, $name</p>" Cheers -- Marc Palmer - - - wj...@wa... Wangjammers, J2ME Developers ~ http://www.wangjammers.org/games/ Blog ~ http://www.jroller.com/page/Wangjammer5 |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2005-03-11 16:11:11
|
On Friday 11 March 2005 15:57, Marc Palmer wrote: > > Two questions:- > > > > 1. what package did you put your StringTemplateLoader class into? > > package org.webmacro.resource; OK. maybe put the following into your StringTemplateLoader:- static { System.err.println("StringTemplateLoader booting up"); } which will tell you whether or not the class is being loaded from the WebMacro.properties file. <snip> > > 2. what was in the WebMacro template that threw the error? > > #include "pagebegin.wm" > <p> > #foreach $contentItem in $content > #if ($contentItem.View) > #include "views/$(contentItem.View).wm" > #else > #if ($contentItem.ContentType = "text/html") > <div> > <h1>$contentItem.Description</h1> > #include as template "string:$contentItem.Data" > </div> > #end > #end > #end > </p> > #include "pageend.wm" > > The String returned by $contentItem.Data is the text to use as the > template, i.e. "<p>Hello, $name</p>" This all looks fine as far as I can see. Try sticking a debug message in the load method of the StringTemplateLoader to see whether or not it is actually getting invoked. Can you mail me the source to your StringTemplateLoader off list and I'll run it besides my EvaluatingTemplateProvider and see if they behave differently... Alex |
From: Marc P. <ma...@an...> - 2005-03-11 16:22:12
|
Alex Twisleton-Wykeham-Fiennes wrote: > On Friday 11 March 2005 15:57, Marc Palmer wrote: > >>>Two questions:- >>> >>>1. what package did you put your StringTemplateLoader class into? >> >>package org.webmacro.resource; > > > OK. maybe put the following into your StringTemplateLoader:- Yep it is loading, and setConfig gets called. However load() is never called. More info - my content in the previous example was empty. I changed the template to do this: #include as template "string:testing" And the error is: 16:15:38 resource WARNING BrokerTemplateProvider: Template not found: string:testing org.webmacro.ignition.cms.ViewEngineException: org.webmacro.PropertyException: #include string:testing: Not found by template provider So for some reason the string: handler is being overlooked and its just using the Broker which of course fails. DelegatingTemplateProvider.load is not being called either. Odd. Src: public class StringTemplateLoader extends AbstractTemplateLoader { public final static String PROTOCOL = "string:"; public void setConfig(String config) { } public Template load(String query, CacheElement ce) throws ResourceException { if (!query.startsWith(PROTOCOL)) { return null; } return new StringTemplate(broker, query.substring(PROTOCOL.length())); } } Cheers -- Marc Palmer - - - wj...@wa... Wangjammers, J2ME Developers ~ http://www.wangjammers.org/games/ Blog ~ http://www.jroller.com/page/Wangjammer5 |
From: Marc P. <ma...@an...> - 2005-03-11 16:26:19
|
Argh no! Don't worry... I've just worked out the problem. This is not normal template processing code... the setup code does some funny stuff to the template provider ;-( So the template provider assignment in wm properties is being overridden. Duh. Thanks for you help, I'm sure it'll be working soon now. :) -- Marc Palmer - - - wj...@wa... Wangjammers, J2ME Developers ~ http://www.wangjammers.org/games/ Blog ~ http://www.jroller.com/page/Wangjammer5 |
From: Keats K. <ke...@xa...> - 2005-03-11 16:28:47
|
It's been a long time, but I'm fairly certain you can do this with the #templet/#eval mechanism. I'll try to dredge up my memories of how it works. There is also a $template tool that can do this: org.webmacro.servlet.TemplateTool. Keats Marc Palmer wrote: > Alex Twisleton-Wykeham-Fiennes wrote: > >> On Friday 11 March 2005 15:57, Marc Palmer wrote: >> >>>> Two questions:- >>>> >>>> 1. what package did you put your StringTemplateLoader class into? >>> >>> >>> package org.webmacro.resource; >> >> >> >> OK. maybe put the following into your StringTemplateLoader:- > > > Yep it is loading, and setConfig gets called. > > However load() is never called. > > More info - my content in the previous example was empty. I changed > the template to do this: > > > #include as template "string:testing" > > And the error is: > > 16:15:38 resource WARNING BrokerTemplateProvider: Template > not found: string:testing > org.webmacro.ignition.cms.ViewEngineException: > org.webmacro.PropertyException: #include string:testing: Not found by > template provider > > So for some reason the string: handler is being overlooked and its > just using the Broker which of course fails. > > DelegatingTemplateProvider.load is not being called either. Odd. > > Src: > > public class StringTemplateLoader extends AbstractTemplateLoader > { > public final static String PROTOCOL = "string:"; > > public void setConfig(String config) > { > } > > public Template load(String query, > CacheElement ce) > throws ResourceException > { > if (!query.startsWith(PROTOCOL)) > { > return null; > } > return new StringTemplate(broker, > query.substring(PROTOCOL.length())); > } > } > > Cheers > > |
From: Keats K. <ke...@xa...> - 2005-03-11 16:45:28
|
Looking at the test case in CVS ( http://cvs.sourceforge.net/viewcvs.py/webmacro/webmacro/test/unit/org/webmacro/template/TestEvalTemplet.java?rev=1.1&view=markup) I see that I created a convenience class for doing this during testing: //** Convenience class to evaluate a string template as a Macro *// *public* *class* StringMacro *implements* org.webmacro.Macro { *private* String s = *""*; *public* StringMacro(String text) { s = text; } *public* Object evaluate(Context context) *throws* org.webmacro.PropertyException { org.webmacro.engine.StringTemplate t = *new* org.webmacro.engine.StringTemplate(context.getBroker(), s); *return* t.evaluateAsString(context); } *public* *void* write(org.webmacro.FastWriter fw, Context context) { } } This let's you use arbitrary strings as macros, e.g., StringMacro m = *new* StringMacro(*"$A $B $C"*); I think the $Template tool can be used similarly. Keats Keats Kirsch wrote: > It's been a long time, but I'm fairly certain you can do this with the > #templet/#eval mechanism. I'll try to dredge up my memories of how it > works. There is also a $template tool that can do this: > org.webmacro.servlet.TemplateTool. > > Keats > > Marc Palmer wrote: > >> Alex Twisleton-Wykeham-Fiennes wrote: >> >>> On Friday 11 March 2005 15:57, Marc Palmer wrote: >>> >>>>> Two questions:- >>>>> >>>>> 1. what package did you put your StringTemplateLoader class into? >>>> >>>> >>>> >>>> package org.webmacro.resource; >>> >>> >>> >>> >>> OK. maybe put the following into your StringTemplateLoader:- >> >> >> >> Yep it is loading, and setConfig gets called. >> >> However load() is never called. >> >> More info - my content in the previous example was empty. I changed >> the template to do this: >> >> >> #include as template "string:testing" >> >> And the error is: >> >> 16:15:38 resource WARNING BrokerTemplateProvider: Template >> not found: string:testing >> org.webmacro.ignition.cms.ViewEngineException: >> org.webmacro.PropertyException: #include string:testing: Not found by >> template provider >> >> So for some reason the string: handler is being overlooked and its >> just using the Broker which of course fails. >> >> DelegatingTemplateProvider.load is not being called either. Odd. >> >> Src: >> >> public class StringTemplateLoader extends AbstractTemplateLoader >> { >> public final static String PROTOCOL = "string:"; >> >> public void setConfig(String config) >> { >> } >> >> public Template load(String query, >> CacheElement ce) >> throws ResourceException >> { >> if (!query.startsWith(PROTOCOL)) >> { >> return null; >> } >> return new StringTemplate(broker, >> query.substring(PROTOCOL.length())); >> } >> } >> >> Cheers >> >> > > > > > ------------------------------------------------------- > SF email is sponsored by - The IT Product Guide > Read honest & candid reviews on hundreds of IT Products from real users. > Discover which products truly live up to the hype. Start reading now. > http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click > _______________________________________________ > Webmacro-user mailing list > Web...@li... > https://lists.sourceforge.net/lists/listinfo/webmacro-user > |
From: Alex Twisleton-Wykeham-F. <al...@fi...> - 2005-03-11 16:33:43
|
On Friday 11 March 2005 16:21, Marc Palmer wrote: > Alex Twisleton-Wykeham-Fiennes wrote: > > On Friday 11 March 2005 15:57, Marc Palmer wrote: > >>>Two questions:- > >>> > >>>1. what package did you put your StringTemplateLoader class into? > >> > >>package org.webmacro.resource; > > > > OK. maybe put the following into your StringTemplateLoader:- > > Yep it is loading, and setConfig gets called. > > However load() is never called. very odd. > More info - my content in the previous example was empty. I changed the > template to do this: > > > #include as template "string:testing" > > And the error is: > > 16:15:38 resource WARNING BrokerTemplateProvider: Template not found: > string:testing > org.webmacro.ignition.cms.ViewEngineException: > org.webmacro.PropertyException: #include string:testing: Not found by > template provider > > So for some reason the string: handler is being overlooked and its just > using the Broker which of course fails. > > DelegatingTemplateProvider.load is not being called either. Odd. if DelegatingTemplateProvider.load isn't being invoked then I wouldn't expect the StringTemplateProvider to be invoked as the BrokerTemplateProvider will not know about it. Maybe it is something to do with the BrokerTemplateProvider being a little bit aggressive and messing with DelegatingTemplateProvider? It looks like it has actually replaced DelegatingTemplateProvider as the Provider for the system (which might be a bug). Can you try using a different implementation of TemplateLoader other than "broker" as your secondary loader and see if that makes any difference? Alex |
From: Eric B. R. <eb...@tc...> - 2005-03-11 23:03:55
|
> #include as template "string:$contentItem.Data" This is really nasty. If this is what we want to do, why not change the #include directive: #include as inline-template "\$contentItem.Data" (You'd have to escape all WM tokens like # and $ to keep them from being evaluated in the current template). Although, I like Keats' idea of #eval "\$contentItem.Data" using { ... } much better. eric |
From: Marc P. <ma...@an...> - 2005-03-11 16:03:24
|
Alex Twisleton-Wykeham-Fiennes wrote: > On Friday 11 March 2005 15:43, Marc Palmer wrote: > >>Alex Twisleton-Wykeham-Fiennes wrote: >> >>>Last message (promise) :-) >>> >>>Here is a more efficient implementation:- >> >>Thanks for this. I'm trying it out now but not having any luck, I get: >> >>15:38:43 resource WARNING BrokerTemplateProvider: Template not found: >>string: I notice the apparent source of the problem is BrokerTemplateProvider, which implies that DelegatingTemplateProvider is not handling it, or has and gave up. Hmmm -- Marc Palmer - - - wj...@wa... Wangjammers, J2ME Developers ~ http://www.wangjammers.org/games/ Blog ~ http://www.jroller.com/page/Wangjammer5 |
From: Marc P. <ma...@an...> - 2005-03-11 16:01:20
|
Again, I'm a year later but I remember the heated discussion on the changes to ContextTool mechanisms :) I finally got around to using it today. Nice work, Brian. I was frustrated that I could not just get ordinary objects into the context using WM config... until I rediscovered the ContextAutoLoader stuff :) Thanks for the hard work. Cheers -- Marc Palmer - - - wj...@wa... Wangjammers, J2ME Developers ~ http://www.wangjammers.org/games/ Blog ~ http://www.jroller.com/page/Wangjammer5 |
From: Keats K. <ke...@xa...> - 2005-03-11 17:53:22
|
Looking back at the old TemplateTool code, it does what you want, but not in a particularly elegant way: #set $m = $Template.fromString($content.Data) $m.eval({ "contextData": $someData }) For some reason the MacroTemplate class doesn't implement the Macro interface. This would be a simple change that would allow you to say: #set $m = $Template.fromString($content.Data) #eval $m using { "contextData": $someData } I could make this change if anyone is interested. Keats Marc Palmer wrote: > Hi, > > Long time no speak! > > I finally got around to getting 2.0b1 (only a year late!) and am > working on the start of CMS using WM. > > I wonder if I'm being really stupid, but I want some of the content, > which is pulled in from String data, to be treated as a WM template. > > So given a content string loaded from the CMS, say "<p>Hello, > $name</p>", I want to use this in my page, a template itself, but have > $name evaluate. i.e. something like this in the main CMS rendering > template: > > <div> > #eval $content.Data using { "contextData": $someData } > </div> > > ...but eval only works with Macro objects to my knowledge. > > Does anybody know how I can do this? I effectively want the same as > #include but from a String instead of a file. > > I've tried: > > <div> > #templet $block > $content.Data > #end > #eval $block using { "contextData": $someData } > </div> > > ...but of course this is not correct as $content.Data is not evaluated > at the time the templet is defined. I also tried #setblock as macro etc. > > It's a bit confusing. I'd like to not have to write a helper/directive > to load a Macro tempalte from a String unless I have to... > > Thanks in advance. > |
From: Keats K. <ke...@xa...> - 2005-03-11 18:16:15
|
Continuing the conversation with myself ... Another interesting option would be to change the #eval directive to work with Strings as well as Macros. (I would automatically convert the String to a StringMacro). This would be a simple change. The only downside is that it might make it a bit harder to catch some errors. Then you could simply say: #eval $content.Data using { "contextData": $someData } This is kind of cool. You could even do stuff like: #eval "Hello, $userName" using { "userName": $User.Name } Keats Keats Kirsch wrote: > Looking back at the old TemplateTool code, it does what you want, but > not in a particularly elegant way: > > #set $m = $Template.fromString($content.Data) > $m.eval({ "contextData": $someData }) > > For some reason the MacroTemplate class doesn't implement the Macro > interface. This would be a simple change that would allow you to say: > > #set $m = $Template.fromString($content.Data) > #eval $m using { "contextData": $someData } > > I could make this change if anyone is interested. > > Keats > > Marc Palmer wrote: > >> Hi, >> >> Long time no speak! >> >> I finally got around to getting 2.0b1 (only a year late!) and am >> working on the start of CMS using WM. >> >> I wonder if I'm being really stupid, but I want some of the content, >> which is pulled in from String data, to be treated as a WM template. >> >> So given a content string loaded from the CMS, say "<p>Hello, >> $name</p>", I want to use this in my page, a template itself, but >> have $name evaluate. i.e. something like this in the main CMS >> rendering template: >> >> <div> >> #eval $content.Data using { "contextData": $someData } >> </div> >> >> ...but eval only works with Macro objects to my knowledge. >> >> Does anybody know how I can do this? I effectively want the same as >> #include but from a String instead of a file. >> >> I've tried: >> >> <div> >> #templet $block >> $content.Data >> #end >> #eval $block using { "contextData": $someData } >> </div> >> >> ...but of course this is not correct as $content.Data is not >> evaluated at the time the templet is defined. I also tried #setblock >> as macro etc. >> >> It's a bit confusing. I'd like to not have to write a >> helper/directive to load a Macro tempalte from a String unless I have >> to... >> >> Thanks in advance. >> |
From: Lane S. <la...@op...> - 2005-03-11 18:30:36
|
why don't you go ahead and do this implementation? -Lane Keats Kirsch wrote: > Continuing the conversation with myself ... > > Another interesting option would be to change the #eval directive to > work with Strings as well as Macros. (I would automatically convert > the String to a StringMacro). This would be a simple change. The > only downside is that it might make it a bit harder to catch some errors. > > Then you could simply say: > > #eval $content.Data using { "contextData": $someData } > > This is kind of cool. You could even do stuff like: > > #eval "Hello, $userName" using { "userName": $User.Name } > > Keats > > Keats Kirsch wrote: > >> Looking back at the old TemplateTool code, it does what you want, but >> not in a particularly elegant way: >> >> #set $m = $Template.fromString($content.Data) >> $m.eval({ "contextData": $someData }) >> >> For some reason the MacroTemplate class doesn't implement the Macro >> interface. This would be a simple change that would allow you to say: >> >> #set $m = $Template.fromString($content.Data) >> #eval $m using { "contextData": $someData } >> >> I could make this change if anyone is interested. >> >> Keats >> >> Marc Palmer wrote: >> >>> Hi, >>> >>> Long time no speak! >>> >>> I finally got around to getting 2.0b1 (only a year late!) and am >>> working on the start of CMS using WM. >>> >>> I wonder if I'm being really stupid, but I want some of the content, >>> which is pulled in from String data, to be treated as a WM template. >>> >>> So given a content string loaded from the CMS, say "<p>Hello, >>> $name</p>", I want to use this in my page, a template itself, but >>> have $name evaluate. i.e. something like this in the main CMS >>> rendering template: >>> >>> <div> >>> #eval $content.Data using { "contextData": $someData } >>> </div> >>> >>> ...but eval only works with Macro objects to my knowledge. >>> >>> Does anybody know how I can do this? I effectively want the same as >>> #include but from a String instead of a file. >>> >>> I've tried: >>> >>> <div> >>> #templet $block >>> $content.Data >>> #end >>> #eval $block using { "contextData": $someData } >>> </div> >>> >>> ...but of course this is not correct as $content.Data is not >>> evaluated at the time the templet is defined. I also tried #setblock >>> as macro etc. >>> >>> It's a bit confusing. I'd like to not have to write a >>> helper/directive to load a Macro tempalte from a String unless I >>> have to... >>> >>> Thanks in advance. >>> > > > > > ------------------------------------------------------- > SF email is sponsored by - The IT Product Guide > Read honest & candid reviews on hundreds of IT Products from real users. > Discover which products truly live up to the hype. Start reading now. > http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click > _______________________________________________ > Webmacro-user mailing list > Web...@li... > https://lists.sourceforge.net/lists/listinfo/webmacro-user > |
From: Marc P. <ma...@an...> - 2005-03-11 19:08:09
|
Keats Kirsch wrote: > Continuing the conversation with myself ... > > Another interesting option would be to change the #eval directive to > work with Strings as well as Macros. (I would automatically convert the > String to a StringMacro). This would be a simple change. The only > downside is that it might make it a bit harder to catch some errors. > > Then you could simply say: > > #eval $content.Data using { "contextData": $someData } > > This is kind of cool. You could even do stuff like: > > #eval "Hello, $userName" using { "userName": $User.Name } That would be the cleanest of them all. #eval was the first thing I tried. However, is there a shortcut for #eval to make it pass in the caller's context, so you don't have to pass all the stuff in? I know, it's less safe... but we live in an imperfect world ;-) Cheers -- Marc Palmer - - - wj...@wa... Wangjammers, J2ME Developers ~ http://www.wangjammers.org/games/ Blog ~ http://www.jroller.com/page/Wangjammer5 |
From: Keats K. <ke...@xa...> - 2005-03-11 19:40:42
|
Marc Palmer wrote: > Keats Kirsch wrote: > >> Continuing the conversation with myself ... >> >> Another interesting option would be to change the #eval directive to >> work with Strings as well as Macros. (I would automatically convert >> the String to a StringMacro). This would be a simple change. The >> only downside is that it might make it a bit harder to catch some >> errors. >> >> Then you could simply say: >> >> #eval $content.Data using { "contextData": $someData } >> >> This is kind of cool. You could even do stuff like: >> >> #eval "Hello, $userName" using { "userName": $User.Name } > > > That would be the cleanest of them all. #eval was the first thing I > tried. > > However, is there a shortcut for #eval to make it pass in the caller's > context, so you don't have to pass all the stuff in? As documented on the Wiki pages, you can access variables from the callers context via the $OuterVars reference. You can also evaluate a templet (or any Macro) directly in the current context, e.g., #templet $t { Hello $User } $t This would work for your String case however, since you wouldn't have a Macro reference. You'd be back to converting the string to a Macro first. We could create a new option on #templet or #setblock, or a new directive like #stemplet to handle this, or fix the $Template tool as mentioned before. Or maybe a $toTemplet function would fit the bill? Keats > I know, it's less safe... but we live in an imperfect world ;-) > > Cheers > |
From: Marc P. <ma...@an...> - 2005-03-11 20:14:56
|
Keats Kirsch wrote: > Marc Palmer wrote: > >> Keats Kirsch wrote: >> >>> Continuing the conversation with myself ... >>> >>> Another interesting option would be to change the #eval directive to >>> work with Strings as well as Macros. (I would automatically convert >>> the String to a StringMacro). This would be a simple change. The >>> only downside is that it might make it a bit harder to catch some >>> errors. >>> >>> Then you could simply say: >>> >>> #eval $content.Data using { "contextData": $someData } >>> >>> This is kind of cool. You could even do stuff like: >>> >>> #eval "Hello, $userName" using { "userName": $User.Name } >> >> >> >> That would be the cleanest of them all. #eval was the first thing I >> tried. >> >> However, is there a shortcut for #eval to make it pass in the caller's >> context, so you don't have to pass all the stuff in? > > > As documented on the Wiki pages, you can access variables from the > callers context via the $OuterVars reference. Yeah, I meant without any qualification though, so that these template fragments to not need to know they are in a #eval block. They shouldn't know after all, it is an implementation detail of the calling template. #eval <string> using { x } Would make me happy. At least then I can put the data in as a $contentInfo Map and thus hide the $OuterVars concept. Cheers -- Marc Palmer - - - wj...@wa... Wangjammers, J2ME Developers ~ http://www.wangjammers.org/games/ Blog ~ http://www.jroller.com/page/Wangjammer5 |
From: marcel.huijkman <mar...@ra...> - 2005-03-12 07:50:05
Attachments:
EvalStringTemplateDirective.wmt
|
/* * Copyright (C) 2005. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted under the terms of either of the following * Open Source licenses: * * The GNU General Public License, version 2, or any later version, as * published by the Free Software Foundation * (http://www.fsf.org/copyleft/gpl.html); * * This software is provided "as is", with NO WARRANTY, not even the * implied warranties of fitness to purpose, or merchantability. You * assume all risks and liabilities associated with its use. * * See www.webmacro.org for more information on the WebMacro project. * * @author Mike Weerdenburg * * @version 14-01-2005 * */ package org.webmacro.directive; import org.webmacro.*; import org.webmacro.engine.*; /** * EvalStringTemplateDirective allows you to evaluate a string just like it is a include / template against the current context.<p> * * Syntax:<pre> * #EvalStringTemplate $valueToEvaluateAsString [to $variable] *</pre> * */ public class EvalStringTemplateDirective extends Directive { /* the argument is NOT a file, but a string represending the template! */ private static final int PARSE_VALUE = 1; private static final int PARSE_TO = 2; private static final int PARSE_TO_VARIABLE = 3; private Variable _varTarget = null; private static final UndefinedMacro UNDEF = UndefinedMacro.getInstance(); private static final ArgDescriptor[] _args = new ArgDescriptor[] { new StringArg(PARSE_VALUE), new OptionalGroup(2), new KeywordArg(PARSE_TO, "to"), new LValueArg(PARSE_TO_VARIABLE), }; private static final DirectiveDescriptor _desc = new DirectiveDescriptor("evalStringTemplate", null, _args, null); public static DirectiveDescriptor getDescriptor () { return _desc; } // // these values are customized for this directive during build() // /** Logging can be good */ protected Log _log; /** the value as a Macro, if the value arg is a Macro */ protected Macro _macroValue; /** * the name given to the directive by webmacro configuration. */ protected String _directiveName; public final Object build (DirectiveBuilder builder, BuildContext bc) throws BuildException { // Get a log-instance. // In webmacro.properties : LogLevel.directive=DEBUG _log = bc.getLog("directive"); // name of this directive _directiveName = builder.getName(); // if a target provided, then output to the target! if (builder.getArg(PARSE_TO_VARIABLE, bc) != null) { try { _varTarget = (Variable) builder.getArg(PARSE_TO_VARIABLE, bc); } catch (ClassCastException e) { // throw new NotVariableBuildException(myDescr.name, e); } } Object o = builder.getArg(PARSE_VALUE, bc); if (o instanceof Macro) { // The value passed to us was a Macro (needs to be evaluated later). // If u use : #evalStringTemplate $myDatabaseFilledStringToEvaluate _macroValue = (Macro) o; } else { // If it's not a Macro, then generate an BuildException. // If u use : #evalStringTemplate "This is a string with nothing to parse!" throw new BuildException("#" + _directiveName + " was expecting a non-static value to evaluate, example: #" + _directiveName + " \"$myDatabaseFilledStringToEvaluate is very interesting!\""); } return this; } /** * Write out the included file to the specified FastWriter. If the * included file is actually a template, it is evaluated against the * <code>context</code> parameter before being written to the FastWriter */ public void write (FastWriter out, Context context) throws PropertyException { Broker broker = context.getBroker(); String strValue = null; // the value arg passed to us was a Macro, so evaluate and check it now. if (_macroValue != null) { Object obValue = _macroValue.evaluate(context); // Only set the value if the macro provided not is null and not Undefined. if ( (obValue != null) && (obValue != UNDEF) ) { strValue = obValue.toString(); } } if (strValue == null) { throw new PropertyException("#" + _directiveName + " value cannot be undefined or null"); } // Use the current templateName as templateName for the StringTemplate. // exampl. c:/wwwroot/templates/test.wm String templateName = context.getTemplateEvaluationContext()._templateName; // Use the current template location & directive name, so whe can re-trace error's. // exampl. c:/wwwroot/templates/test.wm:46.2 #evalStringTemplate if (templateName.indexOf(" #" + _directiveName) == -1) templateName = context.getCurrentLocation() + " #" + _directiveName; if (_log.loggingDebug()) { _log.debug("#" + _directiveName + " \"valueToEvaluateAsStringTemplate\"" + ((_varTarget == null) ? "" : " to $" + _varTarget.getVariableName())); } if (_log.loggingWarning()) { if (strValue.indexOf("#" + _directiveName) > -1) { // when in debug or warning mode, output a warning if a evalStringTemplate tries to use a evalStringTemplate // there could be situtations where this is desired, but it's good to make // the user aware of what they're doing _log.warning("#" + _directiveName + " uses a #" + _directiveName + ", maybe itself? (endless loop!) at " + context.getCurrentLocation()); } } // Create the new StringTemplate. Template tmplTemplate = new StringTemplate (broker, strValue, templateName); if (_varTarget != null) { // if a target variable provided, then output to the target. _varTarget.setValue(context, tmplTemplate.evaluateAsString(context)); } else { // else output to the specified FastWriter. out.write(tmplTemplate.evaluateAsBytes(out.getEncoding(), context)); } } public void accept (TemplateVisitor v) { v.beginDirective(_desc.name); v.visitDirectiveArg("EvalStringTemplate", _macroValue); if (_varTarget != null) v.visitDirectiveArg("EvalStringTemplateTarget", _varTarget); v.endDirective(); } } |
From: Mike W. <M.W...@tr...> - 2005-03-14 07:46:38
|
Hello everybody, I use this 'evalStringTemplate' to convert text from a database (or other source) to a 'parsed' text. In the database there is a value like this: 'This is a very cool $trick'. In some kind of way we put this String in $myEvalVar #set $trick = "Super trick!" Now we can use (put's the output in the context): #evalStringTemplate $myEvalVar or #evalStringTemplate $myEvalVar to $myOutput myOutput :<BR>$myOutput And the output will be: This is a very cool Super trick! It is clean, simple and does the trick that I personally (and I also think others) need! And yes, it does not use innervar or outervar things, but I don't care. I just want the same functionality like an include, but from a string! Not a file! Before I wrote this directive, I used to save the string in a file called 'DATETIMESTAMP.inc' and then used include as template 'DATETIMESTAMP.inc' (but this is such an overkill for your system) It would be fun if this include would be used by the community! And if not, than I hope that someone likes it for personal usage. Just have fun with it! Just keep things simple! Than people will understand it, and use WebMacro! Greetings from the Netherlands, out of a town called Hillegom next to the Keukenhof, Mike Weerdenburg (Ex-colleague of Marcel Huijkman) _____ Van: web...@li... [mailto:web...@li...] Namens marcel.huijkman Verzonden: zaterdag 12 maart 2005 8:48 Aan: web...@li... Onderwerp: Re: [WebMacro-user] A WM brain bender: The solution Please don't do this via the #include directive. It's not an include and it sounds like a workaround for a specific problem! Don't misuse directive for other tasks as for where they were made for. A ex-collegue of mine made this allready and handed me the code, to see if it is good enough for the community (nice he), and I'm sure he won't mind that I put het source with this email. (and a template too!) The trick that you want: get a string from somewhere and use is as a kind of stamp and it works like this: #evalStringTemplate $myEvalVar to $myOutput myOutput :<BR>$myOutput The $myEvalVar in this example can be filled with: webmacro stuff (and yes, that's cool!) The string stays intact and the parsed string $myOutput has the result after evaluation of the $myEvalVar. Simple, efficient and just what you need. Please take a good look at it, and if it's suitable, give Mike Weerdenburg all the credits. |