
json-template - issue #4
Provide a standard way for formatters to take arguments, e.g. for implementing include statement
It would be quite useful to allow a template to include another template passing it a section as the "root". Here is an example:
Template 1: {.section items} <h1>{name}</h1> {.repeater section @} <a href="{urlbase}{url}"></a> {.end} {.end}
Template 2: {.section shoppingCart} {.template 'Template 1' @} {.end}
OR
Template 2: {.template 'Template 1' shoppingCart}
Its a tad bit funky since currently templating (I am using the javascript version) takes in a string and substitutes.
What would be nice is the ability to pass in custom template finders so we can specify the rules of how to retrieve another template string.
Comment #1
Posted on Apr 1, 2009 by Quick HippoI just documented two template reuse patterns that I think are superior to adding an include feature:
http://code.google.com/p/json-template/source/browse/trunk/python/examples/reusing_the_outside.py
http://code.google.com/p/json-template/source/browse/trunk/python/examples/reusing_the_inside.py
There's an explanation inline with the comments.
Live examples are here:
http://chubot.org/json-template/cgi-bin/examples/reusing_the_inside.py/ http://chubot.org/json-template/cgi-bin/examples/reusing_the_outside.py/
(Note the trailing slash)
Let me know what you think. I'm going to write a "Design Minimalism" blog post the explains this point and another design decision (about the metacharacters). One of the virtues is that I'm trying to cover a lot of use cases with the bare minimum of features. This keeps the code size small, and lowers the barrier for implementations in other languages.
Comment #2
Posted on Apr 5, 2009 by Helpful RhinoI wrote a very long-winded response to this (you weren't the only one to ask for this; it was the most obvious hole):
http://json-template.googlecode.com/svn/trunk/doc/On-Design-Minimalism.html
If there's some problem you have that you those methods won't solve, or you find them deficient in some way, feel free to comment here. Closing for now.
Comment #3
Posted on Apr 5, 2009 by Happy PandaSorry I just have to press on for my idea. Though not in the same incarnation as it was originally.
After first seeing your response on my blackberry I could not really read the full examples normally, but it got some gears turning in my head, after reading your inside method I think I finally refined what exactly we want to do... There is still one major limitation which cannot be resolved by either methods I provided OR you.
Formatter parameters is the necessary features... example:
{userProfile|template(user/profiles/v1.tpl)}
I think you can pretty much see where I am going with this. This is a slight modification of the inside pattern that you have except that I don't need to specify EVERY type of template inclusion fomratter I will ever need globally, instead I just create a "template" formatter which finds the template files in the way that I define in my server. I just need the ability to pass it parameters like which template to render.
Now for the problem with all methods (and this is more of a nice-to-have than a necessity like the formatter parameters):
Each template has different .js and .css requirements. It would be great if I could have templates really define "what they need" to work. Without the includer ever having to know/care about it (leaky abstractions but you get the idea).
Example:
Page1 (shell) -- no requirements. user-summary.tpl (inner template) -- user-summary.css, user-summary.js requirements.
the inner template wants to tell the shell that where it renders .css files it must also render user-summary.css, where it renders .js files it must render user-summary.js.
The question is: Do the dependency statements that I describe above fit in with the JSON template philosophy or do they go somewhere to the side?
Comment #4
Posted on Apr 5, 2009 by Quick HippoAh I just added that to the article! Someone else didn't like the level of indirection between formatter names and templates. I used the % character, but there's no reason you can't use template() -- since formatter names are raw strings that the application interprets. (See the second definition of MoreFormatters)
I didn't even realize this at first, but this scheme is turning out to be quite flexible.
Good point about .js and .css dependencies. Perhaps we could define extensible metadata per template. There already is constructor metadata (FromFile/FromString). I'll have to think about this a bit. Do other template systems have a solution for this problem?
But try out the first thing and see if it works for you.
Comment #5
Posted on Apr 5, 2009 by Happy PandaYou do have a nice point about the fact that MoreFormatters in your inner example can easily parse out the template((.*)) and keep going. I just feel that maybe that's what the framework should provide. I see this construct being useful for other cases beyond simply templates. The way the formatter function could be constructed is:
MoreFormatters(format,args /* an array */ )
Definitely a recipe for template inclusions should be specified in the API for the framework. I realize this is not "part of the framework" but it is just as important as it might not be immediately obvious to people about how to approach this when they first see JSON template.
Regarding dependencies... Ruby on Rails has a sort-of kind-of thingy like this. Basically the <% yeild for='foo' %>
So my shell can have:
<% yield for='css' %> ... <% yield for='js' %> <% yield %>
Or something similar sorry the ruby syntax is fading from my brain I haven't used it in over a year.
However that is NOT what I meant... its more of a repeating section in how JSON template defines it... my ideal solution quickly manifested, I haven't given this syntax much thought but hopefully it illustrates what I am trying to get at.
{.dependencySection css}
{.repeat section @}
<link rel="Stylesheet" media="{media}" href="{server-base}/{relpath}">
{.end}
{.end}
<title>Hello Templating World!</title>
<!-- some js files that are statically included -->
<script type="text/javascript src="{server-base}/..."></script>
{.dependencySection js}
{.repeat section @}
<script type="text/javascript src="{server-base}/{relpath}"></script>
{.end}
{.end}
{mainData|template(foo.tpl)}
Comment #6
Posted on Apr 6, 2009 by Quick HippoYeah I do see the need for standardization around the formatters. Actually the syntax I chose in example was bad, because the %filename syntax conflicts with %.3f Python formatter syntax I had written earlier. So those could be expressed: {var|template(filename)} and {floating-point|printf(%.3f)}. If people like brevity they can always define their own syntax, but there should be a standard one.
I would make this another module next to jsontemplate.py, called formatters.py. And then we can add all the common use cases there, so that everybody doesn't invent their own.
To get real reuse, I think there might need to be some higher order function chaining, like:
Template("...", more_formatters=Chain([formatters.FileLoader('root-directory'), formatters.PythonPrintfFormat()])
or something like that. Now you can include template() and printf() as formatters. Are you interested in providing a patch for this?
As for the dependencies, did you look at the example linked in the Design Minimalism article about how it's generated? That already has repeated sections for js and css. There's no need for another section type there.
Is the issue that you want to package the .css and .js paths (which are part of the data dictionary) in the same file as the template?
Comment #7
Posted on Apr 6, 2009 by Happy PandaDependencies is more along the lines of, an inner template specified what dependencies it has (it knows how the outer template accepts data, but that's it) and the outer template will render the inner's dependencies.
An example is the html skeleton which defines where .js and .css files go, but user-summary.tpl needs a js and css file, so it gives those two to the outer template to be placed in the header. Sort of like a static JSON object declaration. This is NOT part of the JSON data given to the template, it is purely a construct inside the templates.
As for template... I just want a parametrized formatters pattern. This way I (working in a javascript server) can implement how to retrieve other files. Actually I never had a need to do python programming (a good time to start is now :) but I might be really slow making these python implementations :(, or I can make the javascript side and you can port to py). However once you have the parametrized stuff that detail is removed from things like printf(%0.3f)
I like the printf idea as well, definitely helps since it handles most necessary cases.
My idea of the template formatter is to have it ask for a file finder function which takes a path and finds it. We can have a default one for django or w/e, its just that each web server has their own methodology of how to find files, so it might be problematic to actually implement a real finder.
Comment #8
Posted on Apr 6, 2009 by Happy PandaSorry to add to the above... Once we have parametrized formatters, we can just give a recipes page of all sorts of cool recipes people come up with when designing JSON template. These recipes will be things you (or the community) decides are necessary but don't need to be in the language.
Comment #9
Posted on Apr 6, 2009 by Helpful RhinoOK, well if you want to hack something up for the JavaScript version, I'll look at it and implement the Python version. I think that in both cases it should be a separate module. Particularly in the JavaScript case, people care about download size.
Do you see what I'm saying about the chaining? The compiler has resolve a formatter string to an actual formatter, so first it will try "template()", and then "printf()", etc. So we would have to compose functions to create a single more_formatters= function.
I agree about having "recipes"; there should be a standard set. The thing is that all implementations won't always be in sync, so it's important to have a standard to follow.
Django already has a large list of formatters. Where possible we should borrow them (but they're not all named greatly):
http://docs.djangoproject.com/en/dev/ref/templates/builtins/#add
Comment #10
Posted on Apr 6, 2009 by Happy PandaSince currently the only way to make custom formatters is to have one, we need to chain... Right.
Right we can give the users the ability to make their own formatter lookup and whatever funky syntax they want, or use the default to add multiple formatters and use them by a key lookup. Definitely a necessity as well.
May I recommend we take this discussion off the bug post and post a strategy as the next comment? This is turning into a back-and-forth conversation. Email me at gmail.
Comment #11
Posted on Apr 6, 2009 by Helpful RhinoYeah let's take this to the discussion list. There are enough people on it that they might provide some feedback.
Comment #12
Posted on Apr 7, 2009 by Quick Hippo(No comment was entered for this change.)
Comment #13
Posted on Apr 10, 2009 by Quick HippoWe've agreed on a way to do this -- it still needs to be implemented in JavaScript and documented everywhere.
Comment #14
Posted on May 14, 2009 by Swift KangarooI recommend implementing a simple template recursion feature such as in StringTemplate. On the other hand, I strongly recommend against the idea of tracking dependencies between templates as described here. Please allow me to explain...
My desired usage scenario is that I want a simple API for creating an empty instance of a template, assembling and inserting my data, then rendering the template with that data to obtain a String. The template engine should be aware of and properly handle character encoding, probably by forcing me to declare the encoding of the template(s) prior to loading.
So, I should be able to do something like the following:
instance = template.create("name")
data = ...(whatever I want, independent of the template API)...
output = instance.render(data)
A crucial feature of this approach is that I should be able to refactor the template "name" as much as I want without having to edit the code to use it. In particular, I should be able to refactor gracefully from a template in a single file (known by "name") to splitting the template up into as many named pieces (separate files) as I want. Typically, template "name" represents a single web page, report, or whatever other output that I desire.
This feature necessitates a means of invoking the template engine with a configuration for finding all the template pieces. This might mean a constructor that takes a directory (with named templates as files within the subdirectory tree). This might mean a single file with templates as named sections within it. This might mean a constructor for the template engine that creates an empty template holder that allows the user to add named templates at will, via whatever mechanism that the user chooses. In JavaScript, the engine could make AJAX calls to request empty templates by name from the server (where relevant).
As a consequence, each template instance must have a parent object that knows how to resolve and provide any references to other templates. StringTemplate does this via a StringTemplateGroup.
However, one of StringTemplate's problems is that the API has gotten way too complex, in large part because of this addition of the StringTemplateGroup, plus some special syntax to support it, etc. I STRONGLY advocate for keeping your template language and the API simple and clean. In particular, if you add such a feature then I would make it a separate deliverable/artifact that is optional and separately testable (which StringTemplate did not do).
As for the whole dependency thing, I consider it to be a nonissue. If I am templating a web page, then the browser will trigger the rendering of the HTML template by the initial web request. When the browser finds a reference to the "external" CSS file, then that web request will trigger the rendering of the CSS template. Likewise, the reference to the "external" JavaScript file in the HTML template will trigger a web request for the JavaScript template. If I edit the HTML template to no longer reference the "external" CSS or JavaScript, then the browser won't find them and it won't issue web requests for them. However, I want to be able to make that CSS and JavaScript internal by replacing the "external" references with "internal" references to the same (sub)templates. I should be able to switch back and forth between those implementations without changing my code, and I can with StringTemplate.
However, StringTemplate has gotten too complex and they seem to have lost sight of the real usage patterns, so their test suite is incomplete and does not adequately cover these features. Therefore, in recent versions, this behavior has become buggy and the code base has become bloated.
I think that we can avoid a repetition with json-template, and I am committed to helping do so.
Best wishes...
Comment #15
Posted on May 15, 2009 by Helpful RhinoYou know I think you'll be pleased with the reuse mechanism(s). It satisfies the properties you request, and the API for JSON Template is still dead simple.
The key is that the include mechanisms are implemented as a special case of "formatters". It's completely on top of the engine, and user configurable. I wrote the file system include mechanism in formatters.py, but you can also write one that does AJAX calls, etc. like you said. All without modification of the API.
Definitely read this if you haven't:
http://json-template.googlecode.com/svn/trunk/doc/On-Design-Minimalism.html
The implementation now basically a demo, and not really "standardized". But the idea is all there. I think it's too early to standardize; we need some more feedback based on actual usage.
I hadn't seen StringTemplate until now. It sounds like it has some of the same problems in mind. But I took one look at this page: http://www.antlr.org/wiki/display/ST/StringTemplate+Documentation
And my initial thought is that it's way too complicated.
It's interesting that there's a paper about how it's a functional language: http://www.cs.usfca.edu/~parrt/papers/ST.pdf
I'll have to read this sometime. JSON Template is also a functional language as I wrote in that article... in particular all language constructs can be evaluated in any order whatsoever.
Comment #16
Posted on Nov 7, 2009 by Quick HippoDone in JS and Python
This is the FunctionRegistry set of APIs
Status: Started
Labels:
Type-Defect
Priority-Medium
Todo-Java
Todo-PHP