Next:
tailindex
Previous:
Text::Wigwam::Plugins::DirectiveSet
 [Table of Contents][Text::Wigwam Index]

Text::Wigwam::Tutorials::Basics



NAME

Text::Wigwam::Tutorials::Basics - A Tutorial on the basics of Wigwam templating.

Description

This tutorial explains the fundamentals of the Wigwam framework from a template writer's perspective.

Introduction

Wigwam is a utility that provides the basic tools and features to build custom template scripting environments. Because environments will vary, this tutorial will focus on the the basic constructs and elements that make up Wigwam templates.

Templates

Wigwam templates consist of simple plain-text documents which are interspersed with special tags that act as place holders where data is to be inserted. These tags contain tokens which can either represent data or manipulate it in some way. When the template is parsed, each tag is systematically processed from top to bottom and replaced by the resulting text that they produce.

Code tags

Code tags are denoted by a pair of delimiters, typically [!! and !!], and usually encompass one or more tokens which are separated by white-space. These tags designate where data is to be inserted into the document. Everything outside the boundary of a tag is simply left unaltered by the parser.

Tokens

Tokens are the basic elements which make up the Wigwam scripting environment. There are three basic types of tokens: literals; variables; and directives.

Literals

Literals are used to represent a value that does not change. There are two types of literals: quoted; and unquoted numeric.

Quoted literals are identified by their surrounding quotation marks:

  [!! "This is a quoted literal" !!]
  [!! 'Single quotes can also be used' !!]

Unquoted numeric literals are any series of characters that equates to a valid numeric value.

  [!! -42 !!]   [!! 98.6 !!]   [!! +186E3 !!]

By default, Wigwam treats anything that appears to be a valid floating point number as a literal numeric value. This behavior can be modified via the numbers parsing option.

Variables

Variables are used to access values within Wigwam's variable space. Wigwam variables are identified by their lack of identifier characters.

  [!! foo !!] [!! bar !!] [!! bazz !!]

Directives

Directives add functionality to the environment by allowing operations to be performed within templates. They are identified by the hash mark preceding them.

  [!! #directive !!]

Directives are stored in modules and plug-ins which can be loaded on demand from within templates, thereby the directives available in any given template environment depends upon which modules and plug-ins have been loaded. The documentation for any given directive should be distributed with the plug-in or module that provides it. Always consult this documentation to obtain the specifics of its function and usage.

Arguments

Directives often require arguments to be used as parameters for performing an operation. Arguments may consist of any of the three basic token types and are always placed immediately after the directive (this is the basis of prefix syntax).

The #define directive demonstrated below expects two arguments: a variable name; and a value. It assigns a value to a variable and does not produce any output.

  1: [!! #define foo "bar" !!]
  2: [!! foo !!]
  output:
  1: 
  2: bar

Note: The numbers followed by colons in many examples herein serve no purpose other than to demonstrate what is happening line by line as the template is parsed.

The most important thing to remember about directives is that each requires a fixed number of arguments.

  1: [!! #define foo "bar" "bazz" !!]
  2: foo=[!! foo !!]
  output:
  1: bazz
  2: foo=bar

What's happening on line 1 is that #define foo "bar" represents a single expression which assigns the variable foo the value bar and produces no output, thus we are left with the trailing literal "bazz". This literal is then interpolated in place of the tag on line 1. Line 2 demonstrates that the foo variable was assigned the value of the first literal, bar.

Blocks

Blocks are used to group a number of tokens together so that their combined values may be joined and used as a single argument. There are two types of blocks: code blocks; and text blocks. Both block types may also contain an unlimited number of nested blocks and will always produce a string value (text).

Code blocks

Code blocks are represented by the brace characters { and }.

  1: [!! #define foo { "bar" "bazz" } !!]
  2: foo=[!! foo !!]
  output:
  1: 
  2: foo=barbazz

Text blocks

Text blocks are denoted by the special tag delimiters !!> and <!! and are functionally equivalent to code blocks. As the name implies, text blocks are expressed in text form and may contain embedded tags.

  1: [!! #define foo !!>bar bazz<!! !!]
  2: foo=[!! foo !!]
  output:
  1: 
  2: foo=bar bazz

Text blocks are typically used when it makes more sense to express a value as a large block of text as opposed to a long string of tokens. As an example, let's say you have a simple template code snippet that you've now decided you want stored in a variable:

  The [!!thing!!] is guaranteed to [!!function!!] or your [!!cost!!] will be refunded!

An unappealing approach would be to convert it into a string of tokens, like so:

  [!!
    #define variable {
      "The "
      thing
      " is guaranteed to "
      function
      " or your "
      cost
      " will be refunded!"
    }
  !!]

A much better alternative is to place the unaltered code snippet between text block delimiters, as it doesn't require us to make any alterations to the code snippet.

  [!! #define variable !!>
   The [!!thing!!] is guaranteed to [!!function!!] or your [!!cost!!] will be refunded!
  <!! !!]

Comments

Comments exist within tag delimiters and are used to document code. Anything existing between the comment delimiters /* and */ are ignored by the parser.

  1: [!! #define foo 'bar' /* This assigns a value to a variable */ !!]
  2: [!! foo /* output the value of the variable */ !!]
  output:
  1: 
  2: bar

White-space trimming

White-space outside of any individual tag delimiter can be eliminated at compile time by using the white-space trimming tag delimiters. These alternate tag delimiters will remove all tabs and spaces directly outside the delimiter up to and including the first new-line (if encountered before a non-tab or non-space). Anything beyond that will be left untouched.

By default, Wigwam defines the following white-space trimming tag delimiters which, outside of their white-space trimming function, are equivalent to their non-trimming counterparts.

 [!~ /* White space trimming code tag delimiters */ ~!]
 [!!  ~!> White space trimming text block delimiters <!~  !!]

  The [!! 'quick ' ~!>
  brown <!! 'fox ' ~!]
  jump [!~ 'ed ' !!]
  [!~ 'over' !!> the
  <!~ ' lazy' !!] dogs.

produces

 The quick brown fox jumped over the lazy dogs.

Configuration tag

Each template may contain its own configuration options tag which is processed prior to template execution. It can be used to specify parsing options, debugging features, template characteristics (such as redefining tag delimiters), or to load plug-ins & modules.

These options are defined via a uniquely identified and specially formatted configuration tag. They take the following form:

 << Wigwam
     Options: 
     /* Tag delimiters */
      code_open = [!!;
      code_term = !!];
      text_open = !!>;
      text_term = <!!;
     /* White space trimming tag delimiters */
      code_open_trim = [!~;
      code_term_trim = ~!];
      text_open_trim = ~!>;
      text_term_trim = <!~;
     /* Other common options */
      numbers = float;
      plugins = DirectiveSet;
      modules = Core/Cgi, Core/Html;
    /* These comments are ignored */
 >>

Only the first encountered configuration tag is processed for any given template. Any other configuration tags within the template will be treated as plain text. This feature is useful when dealing with templates that generate other templates.

The configuration tag may also be used to define default settings for, or impose restrictions upon, subsequently invoked templates, though that aspect will not be covered in this tutorial.

Data management

This section focuses on the basic conventions involved in managing Perl's various data types from within templates.

Strings

String values are nothing more than text, so handling them is straightforward.

  1: [!! #define foo "bar" /* Store a string value into the variable foo */ !!]
  2: [!! foo /* echo the value */ !!] 
  output:
  1: 
  2: bar

Arrays

An array (sometimes referred to as a list) is simply an ordered list of values which may consist of strings, arrays, hashes or nested data structures made up of some combination of any or all of these data types.

Arrays can be defined within templates using the parenthesis characters ( and ). In the following example, we assign a list of values to the stuff variable, then proceed to access the individual values by suffixing the variable which contains the array with a colon metacharacter followed by a numeric representation of the element to be accessed.

  1: [!! #define stuff ( "one" "two" "three" ) !!]
  2: [!! stuff:0 !!]
  3: [!! stuff:1 !!]
  4: [!! stuff:2 !!]
  output:
  1:
  2: one
  3: two
  4: three

Another means for defining arrays is to use the angle brackets < and >. They function like the parenthesis except that raw variable names are interpreted as literals which enables you to define a long string of literals without the need to painstakingly quote each one.

  1: [!! #define stuff < one two three > !!]
  2: [!! stuff:0 !!]
  3: [!! stuff:1 !!]
  4: [!! stuff:2 !!]
 output:
  1:
  2: one
  3: two
  4: three

Laziness is not the only motivation for the angle brackets - they also make template code more readable in many situations.

Hashes

A hash is a list of values which are accessible by way of an associated key, as opposed to an element number as with arrays. Like arrays, hash values may consist of strings or nested data structures.

Hashes can be defined within templates by using the percent % character to cast an array into a hash, during which the array values are converted to key/value pairs. The hash values can then be retrieved explicitly by suffixing the variable containing the hash with a dot metacharacter followed by the key which references the desired value.

  1: [!! #define hashlist %< one uno  two dos  three tres > !!]
  2: [!! hashlist.one !!]
  3: [!! hashlist.two !!]
  4: [!! hashlist.three !!]
  output:
  1: 
  2: uno
  3: dos
  4: tres

Backtick metacharacter

The backtick metacharacter can be used in place of either the dot or colon metacharacters to detect the type of data being accessed and use the appropriate lookup syntax to access the data stored there. It can also be used to perform operations on the data itself.

The following example defines an array of data, displays the data, then performs the same operation on a hash of data.

 0: [!! #macro showdata { #parameters <data> #foreach item data`values`sort  item } !!]
 1: [!! #define data < a b c d > /* Array */ !!]
 2: [!! &showdata(data) !!]
 3: [!! #define data %< Aye a Bee b Cee c Dee d > /* Hash */ !!]
 4: [!! &showdata(data) !!]
 output:
 1: 
 2: abcd
 3: 
 4: abcd

Variable Interpolation

Variable interpolation is an indispensable tool for accessing data indirectly. Wigwam allows variable interpolation through the use of square brackets within the variable names.

 [!! #define foobazz "FOOBAR" !!]
 [!! #define quux "bazz" !!]
 [!! foo[quux] !!]

produces:

 FOOBAR

Interpolation is typically used to access hash or array elements when the key or element number is stored in a variable.

  [!!
   #define rules %<
     paper %<
       rock "You win - paper wraps rock"
       scissors "You lose - scissors cuts paper"
     >
     rock %<
       paper "You lose - paper wraps rock"
       scissors "You win - rock crushes scissors"
     >
     scissors %<
       rock "You lose - rock crushes scissors"
       paper "You win - scissors cuts paper"
     >
   >
  #define choice rules`keys`rand /* Random choice */
  #define challenge rules`keys`rand /* ditto */
  !!]
  I've chosen [!! choice !!], you challenge with [!! challenge !!].
  Outcome: [!! #or rules.[challenge].[choice] "We tie" !!].

There is no limit on the number of nested square brackets that can be used on any given variable.

Author

DJOHNSTON, <djohnston@cpan.org> WINGNUT, <wingnut@cpan.org>

The latest Wigwam version and documentation are available at http://www.wigwamhq.org

Copyright and License

Copyright 2004-2007 by Scot Woodward and Daniel Johnston

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.