OK interesting. I see what you mean more clearly with the single
definition of expressions. Either a simple name or a
name|formatter|... chain is an expression, and you just keep the
existing rule which determines whether to show a section.
But there's a problem as you've defined it: sections can't contain
.name lookups now. Even if they could, the lookup is "direct", not
the type that walks the stack. The fundamental problem is that for a
section, you're looking for context to test for truth and push on the
stack, while in a substitution, you're looking for a value to put in
the output. These just can't be made the same.
> An expression has the form name ("|" name)*.
> To evaluate the expression, the leading name is looked up
> in the value stack (same as current JSON template) to produce
> an initial value. Then each .name is applied, replacing the value
> with the result of looking that name up in value, which must
> be a JSON map. Then each |name is applied, replacing
> the value with the result if applying the named filter to the value.
> The expression a|b|c|d would be written d(c(b(a))) in many
> programming languages. The special leading name "@" means
> the top element on the value stack.
As mentioned, we would need 2 types of expressions here. In my
formulation, there are separate but similar syntaxes for substitutions
and sections, and then the formatters apply to *values*. You haven't
defined the value of a section here -- only the value of an
expression, which may appear inside a section directive.
So it looks like you're punting on the formatters on (expanded value
of) sections. But I think this is just too useful to pass up.
> A section has the form
> "{.section" expr "}" true-body ("{.or}" false-body)? "{.end}"
> In the output, it is replaced by the result of the following procedure.
> First, expr is evaluated to produce a value v.
> If v is not false or empty, v is pushed on the value stack, true-body
> is executed, and v is popped off. Otherwise, false-body is executed
> if present.
The asymmetry here will lead to awkwardness in practice. Say you have
{"num": 3}, then the most compact thing to do is:
{.section num|plural?)
There are {...@} people here.
{.or}
There is {num} person here.
{.end}
Of course you can use {num} in the first clause because of the stack
walk, but this subtlety is confusing.
In my formulation, we retain the original rule that the "num" context
is pushed on the stack if it's non-empty. The predicate determines
which one to execute. These decisions would be orthogonal -- in yours
they're tied together because you discard the original value in favor
of the filtered one.
Also, the definition for plural? here is:
def Plural(num):
if num > 1:
return num
else:
return None
I'd rather write:
def Plural(num):
return num > 1
> A repeated section has the form
> "{.repeated section" expr "}" body ("{.or}" false-body)? "{.end}"
> [Yes there's also an alternates-with but it doesn't matter here.]
> In the output, it is replaced by the result of the following procedure.
> First, expr is evaluated to produce a value v, which must be an array.
> For each element of v, that element is pushed on the stack, body is
> executed, and the element is popped off. If v is empty, false-body
> is executed if present.
>
> As a result of this definition, one style of filters is as "predicates"
> which return either their input or false. Using them can enable or
> disable sections appropriately:
>
> {.section num|>1}
> There are {num|english} people in group {name}
> {.or}
> {.section num|==1}
> There is one person in group {name}
> {.or}
> There are no people on group {name}. How sad.
> {.end}
> {.end}
This brings up something I've been thinking about -- chaining of
conditions (e.g. elif, elsif). I would rather have a flat structure
than a nested one.
> It is also possible to use filters to transform the data before iterating
> over it, for example to select only the public fields from a data structure
> definition:
>
> {.repeated section fields|public?}
> Field {name} has type {type}.
> {.end}
Right. In either formulation, I would write that like this, to avoid
using a loop in the formatter:
{.repeated section fields}
{section @|public?} {# Repeated sections move the cursor each time}
Field {name} has type {type}.
{.end}
{.end}
public? operates on an element rather than a list of elements.
> Or to order an array in a certain way:
>
> {.repeated section people|sort-by-phone-number}
> {name} {phone-number}
> {.end}
Unrelated to this discussion -- in either formulation, you can have
{.repeated section people|sort phone-number}
{name} {phone-number}
{.end}
{.repeated section people|sort name}
{name} {phone-number}
{.end}
Where sort is a single formatter that takes a string argument. This
works like the template-file ("include" feature) if you haven't seen
it.
----
About overloading | operator -- note that I tried to use ? as an
operator instead of |. However, this just looks ugly:
{.section ? plural}
{.end}
{var?plural}
The ? reads better after the predicate name, and it also would look
too much like a ternary operator, but the position of the predicate
swapped.
I'm open to suggestions on syntax that distinguishes predicates from
formatters. Formatters can be chained, so | is appropriate, but
predicates so far can't, although it's conceivable to have multiple
predicates.
> Or perhaps to create a potentially large data structure on the fly:
>
> {.section x|primes-up-to-10000}
> {...@} is prime.
> {.end}
> Again, the primes are: {x|primes-up-to-10000}.
>
> In this implementation, evaluation of expressions has just
> one behavior: a|b|c|d means take a, pipe it through b, c, and d,
> and use the result as the value of the expression, no matter
> what the context.
>
> Neither sections nor substitutions have predicates or formatters.
> Data has filters. Instead of 4 cases, there is 1.
> Predicates are an idiom, not a built-in concept.
So, as mentioned, you do have 2 cases for expressions. And my
formulation has 2 as well -- this is because I've introduced the
concept of "values" of sections and formatters, and defined
predicates/formatters on values, not a 2x2 matrix.
In the end I think that the practical matter of formatting sections is
vital. This was asked for by users, and it will fix nastiness I have
in my doc/makedocs.py stuff. There will be a bunch of silly Python
code eliminated in favor of simple, declarative templates.
It's very interesting how there can be two consistent but different
interpretations of the same language. I'm glad that coherent models
can be made.
thanks,
Andy
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "JSON
Template" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/json-template?hl=en
-~----------~----~----~----~------~----~------~--~---