[stringtemplate-interest] Attribute not found exception? Revisited
Caleb Lyness
caleb.lyness at ezswitch.net
Fri Nov 10 08:04:51 PST 2006
> With ref to the following thread:
> http://www.antlr.org:8080/pipermail/stringtemplate-interest/2006-March/000291.html
>
> * I am looking for a way to ask a template what attributes it is
> using/wanting.
> [John Snyders] This is interesting and seems to imply that the
> template (view) is in charge of defining the set of attributes. I
> usually think of the model/controler as being the one that defines
> the set of attributes available to the view. Perhaps a minor
> distinction since they both have to work together. Are you asking
> this question to determine if the model is generating stuff that
> the view does need? Like a good Java IDE will tell you when you
> have unused variables.
>
That is the idea. This comes from the position where some one else
designs the view (customer department, web designer or whoever) and the
developer is responsible for providing the necessaries data. While most
of the time the data will fit the model, occasionally the model needs
to be updated to contain the data needed to achieve the desired output.
As a developer I don't want to sift through N (esp as N gets big)
templates to find the parameters that are new and need to be added to
the model.
>
> So far I have overloaded a Map class which records which keys are
> requested.
> I pass this in as the attributes list. At the end of a template
> gen I know what was
> requested and what was not.
> [John Snyders] Nice solution but how does it handle conditional
> logic in the template?
>
Conditional logic in the template does cause a problem, in that if a
certain path is followed then it will not know all the parameters...
Hmmm, but do we really want to know all the parameters, or only those
that we need to complete the given concrete instance....
>
> Also this would force a particular data model. Specifically all
> access would need to go throught the map or something that looked
> like a map. How could you tell that a scalar attribute ($foo$) was
> used?
>
Err. But this is situation current in ST as far as I know. ST refers to
a map internally which has name->object. One can either set this map up via
|*setAttribute
<http://www.stringtemplate.org/doc/api/org/antlr/stringtemplate/StringTemplate.html#setAttribute%28java.lang.String,%20java.lang.Object%29>*(java.lang.String name,
java.lang.Object value)| and friends or via |*setAttributes
<http://www.stringtemplate.org/doc/api/org/antlr/stringtemplate/StringTemplate.html#setAttributes%28java.util.Map%29>*(java.util.Map attributes).
I am using | |*setAttributes
<http://www.stringtemplate.org/doc/api/org/antlr/stringtemplate/StringTemplate.html#setAttributes%28java.util.Map%29>.*|
Perhaps I am missing your point, but the scalar attribute is handled in
the normal way.
>
> *Q:* Can I do this with out actually rendering, (via
> toString())... i.e. is there another way?
> [John Snyders] In theory the parsed template should know about all
> the attribute references. An alternate tree walk could report on
> all possible attribute references. What it wouldn't know is if the
> references was to a map key, property, field etc.
>
Hmmm, I it wonder... could be possible to use this approach to find the
conditional blocks... hmmm. i.e. As I have it now I do not know if the
attribute was being queried for a condition or for a value. As far as I
understand the conditional blocks are controlled by an attribute (either
null/set or true/false). The attributes in a conditional block are not
neccessarily required for a given rendering of the template. The query
for any/all attributes is marked using the extended map. Once you know
the attribute is part of a conditional block you can toggle its state
and rerun the process above to give a new set of attributes... Then you
land up with a bunch of attributes needed for a given set of "states".
references to maps can be resolved by querying the template group for a
map with the given name. For example:
System.out.println("-----\nmissed keys");
Set<String> keys = attributes.getMissedKeys();
for (String key: keys) {
// Check if the key was a map reference:
Map result = templateGroup.getMap(key);
if (result == null) {
System.out.println("key: "+key);
}
}
Properties are something I have not though about yet... will have to
think about it for a while:
$user.name$
$user.gender$
Currently I know that I need an attribute user. But I am not checking if
the properties exists.
Perhaps a dynamic wrapper/proxy class, which my map will insert when the
value is requested... I will have to think some more on this.
One needs a way to handle $user.name.lastname$ and
$user.bla.bla........fred$
>
>
> * Sometimes its useful to know (say for testing) that a "required"
> string is missing. What is
> required and what is not is quite specific to the template. Here
> is how I do it for the HTML
> I am generating:
> [John Snyders] This is a seperate problem right? This is the
> case I think is more interesting and important.
>
It is separate, but at the same time related.
>
> The model/controler defines what attributes will be available
> under what conditions. This contract should be unit testable.
> Using a template to do this as you describe is a nice way to unit
> test the contract without having to instrument the
> model/controler. Your example has instrumented the actual template.
>
Correct
>
> I think it would be better to somehow substitute a special unit
> test template. It should check more than just what is required but
> what is expected for a given request. Has anyone created
> extensions to JUnit to do this?
>
This is where that relationship above comes in... There is only a
marginal difference between required and expected in my eyes (unless you
can provide me with solid counter example). By querying the template for
what attributes it uses you can find out what is "expected". Expected by
this definition is different in that the value may be unset. Or have I
miss understood you?
>
> $if (checkAttributes)$
> <!--
> $reqAttr;null=missingAttribute("reqAttr")$
> $serviceCode;null=missingAttribute("serviceCode")$
> -->
> $endif$
>
> If the checkAttributes attribute is true/specified the html
> comment is "rendered". If the
> value is "required" by this template then it is listed in this
> comment. When the comment
> is rendered either the value is rendered or if the attribute is
> missing it spits out a string
> which can be easily found including the name of the missing attribute.
>
> The template shown is defined in a group file as:
>
> missingAttribute(attributeName) ::= "TEST:FAIL - Missing
> attribute: \$$attributeName$\$"
>
> The output will look something like this:
>
> <p>
>
> <!--
> TEST:FAIL - Missing attribute: $reqAttr$
> 1
> -->
> You have recei
>
> The unit tests can then search for these failure messages and make
> the test fall over. The comments prevent
> the test stuff from breaking the final output... :-)
>
> For maps you can use a default to generate a string which can be
> caught in the test too. Its a pity
> the key of the map is not treated as an attribute. That would make
> this possible:
> [John Snyders] From my view I would not be as concerned with maps
> because they are under the control of the template and therefore
> not part of the boundary I would want to test.
>
Ah, but the key may be defined by the model and not the template.
Consider: $amap.(num)$, where num is coming from the data model. Then
we have case for wanting to test...
>
>
> amap ::= [
> "2": "value 2",
> "5": "Other",
> default: "Unknown reason: $key$"
> ]
>
> With this you could generate the fail message AND report the
> failing value....
> Perhaps someone else can think of a way to solve this one...
> [John Snyders] Not off the top of my head
>
:-)
Thanks for the lively discussion :-D
I have streamlined the template a bit... I got bit annoyed with having
to entering the comment :-P
requiredAttribute(ref,attr) ::= <<
$if (checkRequiredAttributes)$
$if(!attr)$
<!-- #FAILED ~ Missing attribute: \$$ref$\$ -->
$endif$
$endif$
>>
Now I have one liners...
$requiredAttribute(ref="code",attr=code)$
Can anyone think of way of avoid the the double parameter....
Also not that this check will have false positives for boolean
attributes set to false.
Cheers
Caleb
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.antlr.org:8080/pipermail/stringtemplate-interest/attachments/20061110/8f3c47cb/attachment.html
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 3269 bytes
Desc: S/MIME Cryptographic Signature
Url : http://www.antlr.org:8080/pipermail/stringtemplate-interest/attachments/20061110/8f3c47cb/attachment.bin
More information about the stringtemplate-interest
mailing list