[stringtemplate-interest] Renderer "modes"
Kunle Odutola
Kunle_Odutola at hotmail.com
Tue Jun 20 16:33:41 PDT 2006
Ter,
> > Formatter ojects are currently the prescribed way. See the types in
> > the
> > "Antlr.StringTemplate.Utils" namespace. You wrap each entry in your
> > array.
> >
> > Hey Kunle,
> > Yeah, I considered that option, but it seems to me a little awkward.
>
> It is a pain to manually wrap each object before you inject.
Yep.
> > For instance, formatter/renderer combination makes this easy:
> >
> > $people:{
> > <h2>$it.Name$</h2>
> >
> > $it.Relations:{<a onclick="registerRelation('$it.Value;
> > format="js"$');">$it.Value$</a> }$
> >
> > }$
> >
> > Without using formatters on renderers, it would be possible, but
> > the controller would be overly complex with several wrapper classes.
>
> Well, you'd need one for javascript but what others would you need?
I think he means several instances of the wrapper class. One per item in
list.
> > Perhaps. I wonder if formalizing the concept of Formatters would be
> > a better
> > approach. Formatters expose arbitrary properties that ST templates can
> > already access directly. All that is needed is a way to compose a
> > renderer
> > and a formatter before registering with ST. This would remove the
> > formatter-per-attribute association as well.
>
> So you'd only have a singleton renderer as before but that accepted
> an Object *and* a formatter String:
>
> class StringRenderer implements AttributeRenderer {
> toString(Object data) {...}
> toString(Object data, String format) {...}
> }
>
> Is that what you mean? If you registered a StringRenderer to deal
> with all Strings then $name$ would call the first method toString
> (name). If you did $name; format="js"$ then it would call toString
> (name, "js"). Interesting...
Not quite. I thought we could just alter the following method:
rawGetObjectProperty(StringTemplate self, Object o, String propertyName)
It would need to understand that an AttributeRender may also have a
formatter that exposes additional properties.
interface AttributeRenderer {
AttributeFormatter getFormatter();
string toString(Object data);
}
interface AttributeFormatter {
string toString(Object data, String propertyName);
}
class StringRenderer implements AttributeRenderer {
public StringRenderer() {}
public StringRenderer(AttributeFormatter formatter) {...}
AttributeFormatter getFormatter() { return formatter; }
toString(Object data) {...}
}
class JsAndHtmlStringRenderer implements AttributeFormatter {
toString(Object data, String propertyName) {
if ( propertyName.equals("js") )
return this.JsEncode(data);
else if ( propertyName.equals("url") )
return this.UrlEncode(data);
...
}
}
1. The rawGetObjectProperty() method can check if renderer has a formatter
(via AttributeRenderer's getFormatter() accessor) and if so, use it
directly.
2. Not sure that the formatter needs to implement a specific interface or
indeed be a separate object from the renderer.
3. Perhaps we can mandate that the "format string" is actually an exposed
property on the formatter, ST already has the machinery to query
properties/methods on arbitary object instances.
Haven't thought about any other options yet. Sean's idea is neat but it's
use of attributes will require Java 1.5+. It doesn't quite equate to
allowing passing arbitary strings to be passed from templates to controller
though.
> Instead, let's follow what I think you originally posted: registering
> formatter objects as renderers but we expose some properties. The
> key efficiency thing here is that the wrapper/formatter can be a
> singleton now--you don't have to wrap every string in an formatter
> object. $name.toUpper$ would be converted to
>
> r = renderer.get("String");
> r.toUpper(name);
>
> So, in the controller you register String->SeansHTMLRendererThingie
> and then call $name.seansMethodForManipulatingStringsInACoolWay$.
>
> This prevents the user from passing arbitrary data; the format string
> must be a valid method name, preventing methods called "SELECT * FROM
> USER", though for a few cases, you could actually do this. This hole
> already exists though.
>
> In summary, the syntax is identical but we'd have to modify
>
> ASTExpr:
>
> protected Object rawGetObjectProperty(StringTemplate self, Object o,
> String propertyName) {...}
>
> so that it checked for a renderer for o's type before doing anything
> else. A renderer registered for o's type would take precedence over
> anything else even if o is a Map or StringTemplate. This way we can
> automatically add properties essentially to any type of object.
>
> How does this sound? I like it.
Sounds like you're saying the AtributeRenderer exposes the additional
properties (i.e. renderer and formatter combined).
Kunle
More information about the stringtemplate-interest
mailing list