From: Keats K. <ke...@xa...> - 2006-08-18 15:17:36
|
The #attribute and #param directives are equivalent, as is the #const directive and even the #set directive if the RHS can be resolved to a constant value at build time. I think we should deprecate #attribute and #param in favor of #const. Keats Alex Fiennes wrote: > Webmacro Gurus, > > I've been having a little bit of a poke around the ParamDirective > functionality to get my head round it and I've just ended up confusing myself > and I wonder if anyone could give me a quick heads up... > > Where in the codebase does the value the #param get into the Map that is > picked up in the WMTemplate.parse() functionality and stored in the > newParameters and then the _parameters variable? > > I'm presuming that it must be in the BlockBuilder.build(BuildContext), but it > is a twisty turny mazy of passages and I can't work it out. > > I'm also confused by the difference between #attribute and #param. As far as > I can tell they both do the same thing (ie set an external parameter and > update the value in the Context for the template to refer to if it likes). > However, after diffing between the two they are not the same, i.e:- > > - ParamDirective has a named DirectiveDescription, although I'm assuming that > this is irrelevant > > - ParamDirective returns a new SetDirective as the result of the > build(DirectiveBuilder, BuildContext) whereas AttributeDirective returns > null. I haven't as yet worked out what this SetDirective is used for because > AttributeDirective seems to set the value in the context quite fine. There > is no functional difference (that I can spot) between:- > #attribute $foo = "bar" > $foo > and > #param $foo = "bar" > $foo > even though the javadoc for ParamDirective implies that there should be a > change. > What is the difference and if there isn't one then why not make a single class > and then extend it for compatability if required? > > There is one more question that I have about params. > http://www.webmacro.org/ParamDirective & > http://www.webmacro.org/AttributeDirective both state that "The $variable > argument must be a simple variable (only one term) and the expression > argument must be able to be evaluated statically (not depend on anything in > the context.)" but this is not strictly speaking true which leads to some > slightly confusing situations in differences between external resolutions of > params and in-template resolution of params that can be ambiguous / > confusing. > > Suppose that I write the following:- > > #set $a = "A" > #param $b = $a > $a > > When I evaluate the template I get "A" which is what I would expect if I was > to treat #param as equal to #set within the template space. > > However, if I invoke template.getParam("b") then I get back a PropertyVariable > wrapper around $a, which if I was to just assume that my #param was a String > (which under legitimate usage it should be) would give me "property:a" with > no warning that I was doing anything at all contrary to the expected usage of > #param. > > Is there a reason why #param doesn't throw an exception when it has a RHS that > is *not* statically parseable? Doing so would not break anything that wasn't > broken anyway and would make it completely unambiguous. > > In fact I would even go so far as to say that given the target usage of #param > that the RHS should just be a single basic datatype. While it is very nice > to be able to say:- > > #attribute $a = 1 > #attribute $b = $a+1 > > and have it statically compile to {a=1,b=2} as external parameters, but my > feeling is that this is still giving you the ability to perform clever hacks > which may well have very unintended side effects. Trying to get #param to > play ball with the in-template code can lead you to start trying to say > things like:- > > #if ($dynamicCondition) { > #param $foo = "bar" > } > $foo > > which will have the external param *always* set to bar with the internal value > of $foo conditional on $dynamicCondition. > > Finally there is a bug (feature?) in the implementation of #param and > #attribute that causes a namespace feature in the Context of the evaluating > template. > > Consider the following three cases:- > > 1. > #set $a = 1 > #set $a = 2 > $a > > 2. > #set $a = 1 > #param $a = 2 > $a > > 3. > #param $a = 1 > #set $a = 2 > $a > > One would expect the value of $a in the Context to be the same for all three > items, with the value of the external param to be (undefined,2,1) > respectively but in fact case 3 fails with a:- > > org.webmacro.servlet.HandlerException: Unexpected Error > org.webmacro.resource.InvalidResourceException: Error while parsing template: > jndi:/localhost/spa/WEB-INF/templates/spa/home.wm.html > org.webmacro.directive.Directive$NotVariableBuildException: #set: Argument > must be a variable > java.lang.ClassCastException: java.lang.Integer at > jndi:/localhost/spa/WEB-INF/templates/spa/home.wm.html:39.2 > > (line 39 is actually line 2 of my test case above) > > On further investigation, you also get this situation:- > > #param $a = 1 > #param $a = 2 > $a > > which gives you a:- > > org.webmacro.servlet.HandlerException: Unexpected Error > org.webmacro.resource.InvalidResourceException: Error while parsing template: > jndi:/localhost/spa/WEB-INF/templates/spa/home.wm.html > org.webmacro.directive.Directive$NotVariableBuildException: #null: Argument > must be a variable > java.lang.ClassCastException at > jndi:/localhost/spa/WEB-INF/templates/spa/home.wm.html:39.2 > > So there is obviously some quite odd things going on in terms of the way that > #param sort of behaves like a #set variable apart from the fact that you > can't change the value in the template once you've set it (although you can > override an existing value) and it doesn't honour any other template flow > logic (but does kind of parse dynamic objects which could then be resolved > against the context to give a value). > > I'd be tempted to be a little bit radical and state the following (with > blatent disregard as to whether or not it is possible within the > implementation framework):- > > 1. #param can only take really static things, ie static strings or simple > numbers (ie no arithmetic). To accept anything else just adds confusion and > I cannot think of a real-world situation when you would want to do so. > > 2. #params must occur at the beginning of the template in a kind of "static > declaration block". By forcing them to come before all other directives > (content?) it would remove the possible ambiguity with putting them inside > directives that have no static meaning (#if) yet have very definite dynamic > meaning. > > 3. I can understand why a template would want dynamic access to the statically > declared variable. I can also understand why you would want to make this > variable immutable (ie if the external world is always going to see a given > value then the internal template should also see the same value). But the > error message when it is redefined should make it clear what it is that > you've done wrong. > > Actually, to tell you the truth I'm not sure about 3 any more either. Here's > a nice test case:- > > **template1.wm** > #param $a = 1 > Template 1-pre: $a > #include as template "template2.wm" > Template 1-post $a > > **template2.wm** > #param $a = 2 > Template 2: $a > > Now we have the external value of $a on template1.wm being 1, the external > value of $a on template2.wm being 2 and the output of the parse being:- > > Template 1-pre: 1 > Template 2: 2 > Template 1-post: 1 > > And if you change template2.wm to:- > > #set $a=2 > Template 2: $a > > then you still get:- > > > Template 1-pre: 1 > Template 2: 2 > Template 1-post: 1 > > which is really odd and in-consistent, ie if you chop your template up into > sub-templates and invoke them linearly they would behave differently to if > you just re-assembled the templates back into a single master template which > feels really odd. So I'd say that if #param variables are readable inside > the template then they should be *really* immutable, not just immutable > within their current template. Otherwise you should go:- > > #param $foo = "bar" > #set $foo = "bar" > > and have two namespaces, one immutable external and one mutable internal. > > I appear to have strayed somewhat from my original brief (getting my head > around the character encodings in a sensible fashion) but there is a method > to my madness - I just need to get a couple of things straight first... > Alex > > ------------------------------------------------------------------------- > Using Tomcat but need to do more? Need to support web services, security? > Get stuff done quickly with pre-integrated technology to make your job easier > Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo > http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 > _______________________________________________ > Webmacro-devel mailing list > Web...@li... > https://lists.sourceforge.net/lists/listinfo/webmacro-devel > > |