Syntax
A syntax should be very simple and, fit to the people who deal with as well as the output generated. In addition, the output data may even consist of different formats. Therefore, Snippetory is designed independent of its syntax. So it's easy to switch the syntax, even dynamically within the file.
Intact templates
As Snippetory is a small project it can't generate perfect tool support for every supported output language. It goes another way: Make the syntax simple and create several of them. As every syntax is very simple and follows commons rules one can keep them in mind. For instance the tags of FLUYT_X work great within the html part of a file, while causing errors in the javaScript part. As javaScript requires me to think in a completely different way it is no additional problem to switch over to FLUYT_CC that allows me to coat my Snippetory expressions in comments, giving them a highlighting color, as well as avoiding syntactical errors created by them.
How to implement a syntax
Additional syntaxes can be created by implementing the interface
org.jproggy.snippetory.spi.Syntax. A good starting point
to do so is RegExSyntax. It just needs a bunch of
regular expressions to work and provides some snippets to create syntaxes consistent with
the core syntaxes. Once your syntax is ready the interface provides a registry to register
it. The harder part is to document the syntax.
Anatomy
As the syntax can be replaced easily, it's not that simple to describe. However there is a number of elements each concrete syntax may provide and some rules a syntax can't control. The main elements are
- Names
- Names should be valid java field names with one addition: '-'. The minus sign is allowed to support typical XML naming schemes. Like in java names are case-sensitive.
- Location mark
- A location mark is simply a point, where data can be bound to. It can be annotated, how this binding should happen, by metadata. The same data may be bound to different locations with different metadata each. I.e. there may be several locations with same name in one region. All locations are accessed with a single set or append method call. But the results may be different depending on the metadata.
- Region
-
Syntactically a region consists of a start and an end. The content between start and end
can be used as an independent template. As a region can be retrieved, its name has to be unique
for the regions within the parent region.
Each region serves as location mark, as well. Therefore, it can be configured by metadata. - Metadata
- Allows fine-grained control over the Snippetory abstraction layer by several attributes.
- Syntax selector
- The syntax selector allows to switch the syntax at any point of parsing. To be able to use templates like output files in order to validate them, it's mandatory to use a syntax the fits its environment.
- Template Data
- The portion of the template file, that is not considered to be mark up and therefore is copied verbatim to the output, if used. Of course, there might be some regions, that are not always used.
- Comment
- The comment is an optional element and not yet supported by all of the core syntaxes.
Syntactical Elements
Names
Snippetory supports the full Java naming scheme with, in addition, allowing the minus sign '-' at any position of the name, to support typical XML naming strategies. The characters sharp '#' and period '.' will work but are reserved for future use. While the standard syntaxes enforce this naming scheme, there's no check in Snippetory whether other syntaxes enforce this too, or allow other names. But this might change in the future.
Names are always case-sensitive.
Location mark
A location mark has a name and may be configured by metadata. However, there's a special
variant without a name and at least one attribute. This is useful with so-called void formats,
as such a location mark can't be accessed from java, so no data can be bound.
For more information on formatting see the formats documentation
and Formats in java doc
$value
$value(msg="cart_no_data")
$(msg="cart_no_data")
Region
Like a location mark it can be replaced entirely by actual data. Even though this string typically consists of one or more parameterized copies of itself, this might be any data appropriate. However, replaced isn't that correct, as of it's not replaced it's not rendered anyway. In fact an inner template is absolutely independent of its parent. It's just stored there for better understanding of the context and simpler access. But technically it could be taken from anywhere and used everywhere one likes.
A region is marked by a start and an end element. In some syntaxes the name of region can be repeated in the end element. If it repeated it will be checked. That's recommended for longer regions, because it makes it easier to get what ends there. The start element may be configured by metadata. (In fact the syntax defines where metadata can be placed...)
A region can contain any number of complete regions with distinct names. I.e. there mustn't be more than one region with the same name directly embedded into one region, but any of these child regions provides its own, distinct name space.
A region may contain any number of location marks, without any limitations to naming. I.e. a single write operation can target several location marks and one region. These location marks are all direct children of one region. Location marks within child regions are out of scope anyway.
The start and end elements are provided in two variants each.
- In the inline variant only the element itself is considered to be part of the markup and is therefore omitted from output. All white-space before and after is normal part of the template.
- If the element is found in its 'own' line with only white space and a single region start or end element the entire line including the line break is considered to be markup, and therefore not part of the template. Let's call this the block variant.
The gray part is to be removed.
$inline-region{ Containing
some
text }$$block-region{ Also with
text contained }block-region$
Conditional regions
Starting with Snippetory 0.9.5 there is an addition type of region: Conditional regions have no name, and so they can't be controlled by java logic. Instead, their contained locations control them. This makes it easy to implement cases where the absence of data removes some infrastructure as well.
Optional attribute:
${title="$title"}$
If there are no rows the entire table will be omitted.
<t:>
<table>
<tr>
<th>Heading1</th><th>Heading2</th>
</tr>
<t:row>
<tr>
<td>$data1</td><td>$data2</td>
</tr>
</t:row>
</table>
</t:>
Metadata
For the core syntaxes the syntax of attributes is similar to XML (Other definitions may overwrite this, of course):
<name>=<quoted_value>
Where name consists on alphanumeric chars plus '.-_'. The quoted_value may be quoted either in single or double quotes. Again similar to XML. However, in contrast to XML the escaping of special characters works, similar to Strings in many programming languages, with the backslash character:
- \\
- backslash
- \'
- single quote (In double-quoted values the backslash is optional)
- \"
- double quote (In single-quoted values the backslash is optional)
- \n
- new line
- \r
- carriage return
- \b
- bell
- \t
- tabulator
- \f
- form feed
A single backslash might cause the piece of markup being considered to be template code.
Metadata consists of a bunch of attributes. Some of these attributes are implemented directly:
- enc
- Valid values are the name of all registered encodings. The encodings shipped with Snippetory are documented in org.jproggy.snippetory.Encodings.
- delimiter
- Is rendered only in case the values gets appended data more than once between the final content created by two subsequent calls to the append method. I.e. it's prepended any but the first call to the append method. The value will be neither formatted nor escaped. Note: Calls to some render-methods will cause calls to the append method, too.
- prefix
-
is only prepended if the region or location mark got data by appending or setting.
However, the prefix attribute will prevent the rendering of markup if no value is bound on a location mark. Deprecated: Consider use of conditional regions instead - suffix
- same as prefix but behind. Deprecated: Consider use of conditional regions instead
- backward
- This is a very advanced technique that allows 'touch-less' value binding. In some case
it's very useful to keep the template syntactically intact. However, this makes it impossible
to bind data to some places, where the syntax of the output format is too strict. In those cases
it's possible to place the insert location behind the real target.
resultset.getInt(i); // $types(backward='Int')
But Snippetory will fail, if the regular expression matches not exactly once within the region until next markup. If a simple expression is not specific enough, you can have a single sub-expression, that will actually be replaced, and use the main expression to describe the surroundings:
var langdesc = $.datepicker.regional["de"]; // {v:lang backward='\"(de)\"'}
Formats
... are created by registration of a Format. There's an example how to do that. And some come predefined with Snippetory to convert, like those to convert data types or manipulate character data like crop or pad.
Links
... are created by registration of a Link. The process of registration is similar to formats, but instead of formatting content, they will fetch the content from somewhere else.
Annotations
... can be read while dealing with the template. They allow the template author to place some additional information that's handled by some generic program code. Similar to annotations in Java. Annotation attributes can be registered via the Metadata interface
Syntax selector
The syntax selector allows to change the syntax on the fly. It can be placed inside a region. This might lead to regions with start and end element defined in different syntaxes. The only data of a syntax selector is the selected syntax. I.e. no name, hence a syntax selector can't be accessed from java.
A syntax selector generally needs to be the only content of a line. This line is considered markup thus it's not part of the output.
It can be expressed as a comment containing Syntax:<Syntax_Name>
with no white space within the expression.
Surrounding white space is allowed. There are a number of commenting schemes implemented.
Region: /* .. */ <!-- .. -->
Full line: // or # or ' or rem or --
Start and end can be mixed or even omitted:
# Syntax:FLUYT
Syntax:MyCoolSyntax */
Syntax:YetAnotherSyntax
Syntax Variants
The syntaxes shipped with Snippetory are documented in org.jproggy.snippetory.Syntaxes.
FLUYT
FLUYT is the main syntax of Snippetory and the root of an entire syntax family. It's designed to be concise and unified. Following this concept locations and regions are integrated into one syntactical concept where about every part is optional. In fact this perfectly shows that regions are location with an additional template part. There are 3 segments. Each segment is optional, but there has to be at least one. The segments are:
- Name
- Attribute brackets (i.e. Metadata surrounded by round brackets)
- The template region (Surrounded by curly brackets and finalized by a dollar sign. Repeating the name is optional even if there is one). If there's no template region, the final $ is optional
$[<name>][(<attribute>='value'...)][{<content_area>}[<name>]$]|[$]
In addition, there is a 3-slash comment and the normal syntax selector.
Example:
$item(delimiter=","){
{
id: $id
/// You can terminate locations with a $ to explicitly mark the end of the name.
image: 'details_$id$_small.jpg'
name: '$name(enc="string")'
values: [$values(delimiter=","){$value}$]
}
}item$
Usage
The vanilla FLUYT syntax is most likely to be used in add hoc formatting, or when generating natural text, like a plain text e-mail, as there is no integration needed.
FLUYT_X
FLUYT_X adds an alternative region mark-up to the FLUYT syntax scheme, looking like XML tags in name space 't'. Those tags are very convenient for XML or HTML integration. Many editors support one by closing the tags consistently and by this it's easy to build valid output. Typical tools recognize them as part of the document structure and display them nicely.
Example:
<t:cart>
<table>
<tr><th colspan="2">Product</th><th>Quantity</th><th>Price</th></tr>
<t:entry>
<tr>
<td><img src="imgs/icon_$imgId$.jpg"${ title="$desc"}$ /></td>
<td>$prodName</td><td>$quantity</td><td>$price(number="currency")</td>
</tr>
<t:><tr><td colspan="4">$longDescription</td></tr></t:>
</t:entry>
</table>
</t:cart>
Usage
FLUYT_X is designed for integration with HTML and XML. But FLUYT_X is no XML. Empty tags with the slash at the end aren't supported and there is no entity support. The escaping within attribute values works like described above.
FLUYT_CC
FLUYT_CC allows the FLUYT syntax to be coated with comments. Those comments will be considered to be part of the respective expression and removed together with the expression itself. To achieve this each token can be prefixed with either '//' or '/*' and can be suffixed with '*/'. In addition, there is an optional mock part before the closing attribute bracket. This is a portion of free text prefixed with '*/' and suffixed with '/*'. If used within a comment region this will make the free text visible for a tool handling it:
/* $name(default="" */<mock>/*)*/
Example:
package /*$package(*/org.jproggy.examples/*)*/;
// $imports{
import /*$type(*/org.jproggy.snippetory.Template/*)*/;
// }$
public class /*$name(*/TemplateName/*)*//*${ implements $interfaces(delimiter=", ")}$*/ {
/*$body*/
}
Usage
FLUYT_CC integrates nicely with languages like java, javaScript, C, C++, or CSS.
XML_ALIKE
The regions of this syntax look almost like XML within the name space t. If the name-space identifier 't' is already used for some reason, it's easy to create a similar syntax better supporting your needs. However, there are some differences to XML. The empty tag variant with the slash at the end is not allowed. And there's no entity support. But the rules for attribute definition are similar. However, the values are defined the programming way with backslashes as described above.
Location marks are limited by curly braces. The content start with v: immediately followed by the name.
Example:
<t:region-one>inline variant</t:region-one>
{v:location default="xyz"}
<t:region-two>
produces only a single line of output, whenever rendered.
</t:region-two>
Usage
XML_ALIKE provides a rather robust syntax scheme, so it might be used where conflicts with the template code are likely.
HIDDEN_BLOCKS
This syntax is quite similar to xml_alike. Just the start and end sequences of the region elements are modified to let it look like comments in a number of environments.
start element
Start sequence may be either
/*t:
or
<!--t:
and the end sequence may be
*/
or
-->
(In the second case a whitespace is mandatory)
End element
The start sequences are
/*!t:
or
<!--!t:
and the end sequence are also
*/
or
-->
(In the second case a whitespace is mandatory)
In either case it is allowed to mix the variants as needed.
<!--Syntax:HIDDEN_BLOCKS -->
<script>
/*t:region-one -->code might be hidden from javaScript<!--!t:region-one*/
/*t:region-two*/or visible, just as needed /*!t:region-two*/
</script>
<!--t:region-three*/same works in HTML, too, of course/*!t:region-three -->
<!--t:region-four -->
The markup lines work here, too.
<!--!t:region-four -->