Hi Matt,

     Thanks for the detailed usage and bug reports and sharing your
thoughts with us. Let me try to briefly respond:

1)  {% endblock <block_name> %}: the current grammar does not accept
identifiers after endblock. Is this something required by Jinja?

2)  super()  function: unfortunately, the extends statement is implemented
by appending template statements together. ersatz currently has no notion
of classes, let alone parent and children classes.

3) {% if not loop.last %}: this should work.  Can you check whether "if
loop.last" works?

4)  Filters: sorry about the documentation, I will try to document filters
soon then.

5) Tvalues: I am an SML/Ocaml groupie and fanatical believer in types :-D
But if it will help, I will add a sexpr->tvalue and tvalue->sexpr
procedures that can convert between Scheme values and template values.

6)  Yes, you can build templates "in-memory". Take a look at the
template-statement data type. I will add this to the documentation as well.

7) Name: 'tori' is a bit too generic, I think. Presumably German is the
native language of Chicken, so I chose what I think expresses the nature of
templates, yet is somewhat self-deprecating, as ersatz usually means 'poor
substitute' in English and my native Bulgarian.


Thanks again for your very useful comments and thoughts, Matt. Best,

  -Ivan





On Wed, Mar 13, 2013 at 1:32 AM, Matt Gushee <[email protected]> wrote:

> Hello, Ivan and anyone else who is interested--
>
> Having just finished successfully converting a web site from Python (Flask
> framework) to Chicken Scheme, I'd like to summarize my observations on the
> Ersatz template library. And let me say, Ivan, that although I have a few
> criticisms, I very much appreciate the work you have done to make Ersatz
> available. Before I discovered it, I was thinking about developing a
> Jinja-like template library myself, but I doubt that I could have done it
> as well as you have. And overall I find that Ersatz works very well and is
> not too difficult to use.
>
>
> UNIMPLEMENTED JINJA2 FEATURES
>
> So, first of all, I started out with a set of Jinja2 templates. I was
> afraid I would have to make major changes to use them with Ersatz, but it
> turned out I didn't need to change very much. However, I did notice a few
> Jinja features that are not implemented in Ersatz:
>
> 1) {% endblock <block_name> %} causes a parser error. This is certainly
> the least important of the issues I found.
>
> 2) The super() function is not supported. I was able to work around that
> limitation but splitting up some blocks. Still, this would be a very
> convenient feature to have.
>
> 3) {% if not loop.last %} also raises a parser error. This was a fairly
> important feature for me, because I have a couple of templates that
> generate JSON from arbitrary-length lists of objects, and there needs to be
> a comma *between* the objects in JSON. So I was doing this:
>
>    {% for item in items %}
>        {
>           ....
>        }
>    {% endfor %}{% if not loop.last %}, {% endif %}
>
> My solution for Ersatz was to split the list in Scheme code into
> all-but-last and last components, then do the following in my template:
>
>    {% for item in items %}
>       {
>           "a": {{ item.a }}
>           "b": {{ item.b }}
>           "c": {{ item.c }}
>        },
>    {% endfor %}
>    {
>           "a": {{ last_item.a }}
>           "b": {{ last_item.b }}
>           "c": {{ last_item.c }}
>     }
>
> And actually, I have since realized a couple of things about this. One is
> that I could split the list into car & cdr, and put a 'first_item' before
> the 'for' block, with a comma in between. The other is that I need to
> ensure that 'items' is not an empty list, otherwise there will be an extra
> comma. Is this the way to do that?
>
>    Scheme:
>       models: `((items . ,(Tbool #f)) ...)
>
>    Template:
>       {% if items %}
>          {% for item in items %}
>             ,
>             {
>                ...
>              }
>           {% endfor %}
>        {% endif %}
>
>
> FILTERS
>
> My application uses several custom filters. I eventually figured out how
> to do this, but it was rather challenging. First of all, the documentation
> does not cover how to program a filter. For the record, I found that both
> the inputs and outputs of user-defined filters need to be tvalues. I also
> found that when I tried to use a filter that accepted one argument, Ersatz
> was passing 2 arguments to it. I have no idea what the second argument is
> supposed to be; I added some code to pretty-print the second argument to a
> log file, and found that it was an empty list.
>
> I'm wondering if you [Ivan] have any recommendations on the best way to
> write user-defined filters. I can't use the 'func1-arg', 'func2-arg', etc.
> procedures that you use for the built-in filters, since those procedures
> are not exported. And in any case, I haven't read the code thoroughly
> enough to really understand what they are doing.
>
> I also found an error in the documentation related to filters. The
> signature of the 'template-std-env' function says that the filters: keyword
> argument should be a string list. In fact, it is a tvalue-alist of the same
> form as the models: argument to 'from-file' and 'from-string'.
>
>
> TVALUES
>
> Now we come to a philosophical issue. To put it bluntly, I feel that the
> tvalue datatype makes using Ersatz more complicated than it needs to be
> without providing any huge benefit. By the way, I spent several years
> programming in OCaml, so I know where this comes from. And, though in
> general I liked the language and the community, and found the OCaml type
> system very useful for certain kinds of applications, I was never convinced
> that type safety was a panacea, and in particular I don't see it as very
> useful for general web programming. Because in my limited experience, most
> web applications don't do much complex data manipulation. Most of the
> complexity is in (a) rendering pages; (b) validating user input; and (c)
> database storage, search, and retrieval. The kinds of data structures that
> an OCaml-ish type system helps with tend to be very short-lived. To give
> one of many possible examples, let's say your application accepts
> registrations of new users. Okay, so the user enters a username and
> password and some other information in a form. If the form input is
> accepted, then probably your app just puts it straight into the database,
> reports to the user that their registration was successful, and moves on to
> the next task. Now there are certain validation tasks that need to be done
> before accepting the registration. For example, you need to ensure that the
> username is unique. Well, that's just a matter of matching a string input
> against existing strings in the database. Et cetera ... in any case, most
> or all of the data in this type of interaction consists of strings; and
> while they often need to be validated, that validation usually needs to be
> done according to semantic constraints that are difficult or impossible to
> describe in even a very sophisticated type system. I could go on, but
> hopefully my point is clear, whether you agree with it or not.
>
> As for what I think you should do, well, probably you should gather more
> feedback on the merits of the tvalue datatype before considering any
> changes. Maybe there are common use cases where this kind of type-safety is
> really helpful, and maybe it makes the library easier to maintain. And I
> plan to continue using Ersatz anyway, I just feel that the need to wrap
> everything in tvalues makes it harder than it needs to be.
>
>
> (NOT HAVING) IN-MEMORY TEMPLATE OBJECTS?
>
> I have worked with several template systems in the past, and it seems like
> most of them allow/require you to instantiate a template object in memory,
> to which you can then feed variables and other contextual parameters before
> rendering the output. Although this adds a bit of complexity to the user's
> code, it seems like a good idea to me, because you can then reuse a
> template by resetting it and passing it new variables. Though I have no
> idea how much this affects performance vs. reading and parsing the template
> from a string or file on each request, it surely makes some difference.
> Though I have noticed there are several procedures for working with
> template statements ... perhaps that addresses this usage in some way? I
> don't really understand how that works yet.
>
>
> THE NAME OF THE EGG
>
> Okay, this is not entirely serious, but ... since, as I said, I was
> thinking about creating a Jinja-like template library myself: the name
> Ersatz doesn't make sense to me. I would like to call the egg Torii
> (heh-heh). I've noticed that you [Ivan] are in Japan, so I am assuming you
> know at least a little Japanese ... so maybe you can understand my little
> pun there.
>
> Anyway, thanks for everything, and goodbye for now.
>
> --
> Matt Gushee
>
> _______________________________________________
> Chicken-users mailing list
> [email protected]
> https://lists.nongnu.org/mailman/listinfo/chicken-users
>
>
_______________________________________________
Chicken-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/chicken-users

Reply via email to