gschlossnagle / json-template

Automatically exported from code.google.com/p/json-template
0 stars 0 forks source link

Provide a standard way for formatters to take arguments, e.g. for implementing include statement #4

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
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.

Original issue reported on code.google.com by dlikhten on 30 Mar 2009 at 5:35

GoogleCodeExporter commented 8 years ago
I 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/reusi
ng_the_outside.py

http://code.google.com/p/json-template/source/browse/trunk/python/examples/reusi
ng_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.

Original comment by gtempacc...@yahoo.com on 1 Apr 2009 at 6:52

GoogleCodeExporter commented 8 years ago
I 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.

Original comment by andyc...@gmail.com on 5 Apr 2009 at 7:53

GoogleCodeExporter commented 8 years ago
Sorry 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?

Original comment by dlikhten on 5 Apr 2009 at 4:46

GoogleCodeExporter commented 8 years ago
Ah 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(<filename>) -- 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.

Original comment by gtempacc...@yahoo.com on 5 Apr 2009 at 5:47

GoogleCodeExporter commented 8 years ago
You 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:

<html>
  <head>
    <% yield for='css' %> 
    ... 
    <% yield for='js' %>
  </head>
  <body>
    <% yield %>
  </body>
</html>

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.

<html>
  <head>
    <!-- some css that is statically included in the page -->
    <link ...>

    {.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}

  </head>
  <body>
    {mainData|template(foo.tpl)}
  </body>
</html>

Original comment by dlikhten on 5 Apr 2009 at 6:17

GoogleCodeExporter commented 8 years ago
Yeah 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?

Original comment by gtempacc...@yahoo.com on 6 Apr 2009 at 12:32

GoogleCodeExporter commented 8 years ago
Dependencies 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.

Original comment by dlikhten on 6 Apr 2009 at 1:53

GoogleCodeExporter commented 8 years ago
Sorry 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.

Original comment by dlikhten on 6 Apr 2009 at 1:57

GoogleCodeExporter commented 8 years ago
OK, 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

Original comment by andyc...@gmail.com on 6 Apr 2009 at 4:19

GoogleCodeExporter commented 8 years ago
Since 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.

Original comment by dlikhten on 6 Apr 2009 at 5:08

GoogleCodeExporter commented 8 years ago
Yeah let's take this to the discussion list.  There are enough people on it 
that they
might provide some feedback.

Original comment by andyc...@gmail.com on 6 Apr 2009 at 7:48

GoogleCodeExporter commented 8 years ago

Original comment by gtempacc...@yahoo.com on 7 Apr 2009 at 3:17

GoogleCodeExporter commented 8 years ago
We've agreed on a way to do this -- it still needs to be implemented in 
JavaScript
and documented everywhere.

Original comment by gtempacc...@yahoo.com on 10 Apr 2009 at 12:29

GoogleCodeExporter commented 8 years ago
I 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...

Original comment by Robert.David.Williams on 14 May 2009 at 7:38

GoogleCodeExporter commented 8 years ago
You 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.

Original comment by andyc...@gmail.com on 15 May 2009 at 5:39

GoogleCodeExporter commented 8 years ago
Done in JS and Python

This is the FunctionRegistry set of APIs

Original comment by gtempacc...@yahoo.com on 7 Nov 2009 at 9:26