WigwamHQ


Wigwam Community Libraries Modules Plugins Download Development
Wigwam: Introduction | Basics | Details

View source (Text/Wigwam.pm)


Name

Text::Wigwam - A user-extensible template parser.


Synopsis

Simple

 # Parse a file
 use Text::Wigwam; 
 my $wwobj = Text::Wigwam->new( file => 'path/to/filename.txt' )
  or die $Text::Wigwam::ERROR;
 print $wwobj->parse; 
 #
 # Parse a string
 use Text::Wigwam; 
 my $wwobj = Text::Wigwam->new( text =>  'foo=[!!foo!!] bar=[!!bar!!]' )
  or die $Text::Wigwam::ERROR;
 print $wwobj->parse;

Verbose

 use Text::Wigwam; 
 my $Restrict = {
        options_ltag_id => '<<',
        options_rtag_id => '>>',
        default_engine => 'Fusion, FusionX',
 };
 my $Defaults = {
        engine => 'Fusion, FusionX',
        set_strict_tags => 1,
        set_ltag_entity => '[!!',
        set_rtag_entity => '!!]',
        set_lblk_entity => '<!!',
        set_rblk_entity => '!!>',
        set_kill_wspace => '~',
        set_numeric_off => 0,
        set_spew_stacks => 0,
        set_priv_vspace => 0,
        set_save_vspace => undef,
        set_pckg_root => undef,
        set_pckg_path => undef,
 };
 my $Settings = {
        plugins => 'DirectiveSet',
        modules => 'CgiTools, HtmlTools',
        set_spew_option => 0,
        set_spew_stacks => 0,
        set_no_drip_cache => 0,
 };
 my $varspace = { greet => "Hello", entity => "World" };
 my $string = '[!!greet!!], [!!entity!!]';
 my $wwobj = Text::Wigwam->new(
        text => $string,
        $Restrict,
        $Defaults,
        $Settings,
 ) or die $Text::Wigwam::ERROR; 
 $wwobj->set_path( template => '~/wigwam/templates/', '/wigwam/templates/' );
 my( $error, $text ) = $wwobj->parse( $varspace );
 die $error if $error;
 print $text; # outputs "Hello, World"


About

The purpose of this documentation is to provide a categorized and detailed reference into the specifics of the Wigwam templating system. Even though we have arranged these categories in a manner which we hope provides the smoothest flow when read from beginning to end, there are still situations where it is necessary to make references to things not yet covered up to a particular point in the documentation in order to cover all aspects of a specific category. We have made an attempt to point this out whenever it occurs, but the bottom line is that despite our best efforts to the contrary, this document is not a substitute for a tutorial.

We hope to provide some on-line tutorials in the future, which will no doubt be posted on the web site at http://www.wigwamhq.org. Until then, we suggest you skim through this document to pick up the basics, then try things out for a while and refer back later to grasp more of the details.

Many of the examples found throughout this documentation make use of directives which are included in the DirectiveSet plug-in which is loaded by default unless it's explicitly overridden. The directives used in most of the examples herein will be self-explanatory for some, but for the rest, refer to the documentation for Text::Wigwam::Plugins::DirectiveSet.


Description

Wigwam is a user-extensible/customizable template processor which provides a well-defined framework for intermingling text with dynamic content in a manner which is flexible, extensible, reusable, and efficient.

Overview

What differentiates Wigwam from most other template parsers we've come across is its extensibility, versatile data handling features, dynamic parsing options, and full-featured scripting environment. Another differentiating factor is that Wigwam is not largely regex driven, but is more of a token-based parser.

Mechanics

Wigwam can be divided into three fundamental components:

  • Interface
    This is the mechanism through which a user invokes Wigwam to construct a template object, define parameters, and parse the template.
  • Engine
    The engine provides the basic template processing framework. It understands only the rudimentary layout of Wigwam templates, and the three basic token types: literals, variables, and directives.
  • Directive Tree
    The directive tree is a name space based hierarchy into which groups of directives (in the form of plug-ins and modules) are loaded by the interface, when instructed. These directives collectively contribute to the overall templating environment. Templates can be restricted to specific branches of the directive tree hierarchy as a method of limiting their capability.

Features

Wigwam offers a templating framework which provides:

  • Dynamic parsing options
    Redefine tag entities, enable debugging features, load plug-ins and modules, and more, from within the template itself.
  • Versatile data handling
    Accessing hashes of hashes of arrays (or any combination) from within a template is child's play.
  • Extensibility
    Write your own custom directives targeted to specific tasks, and organize them into plug-ins or modules for easy reuse.
  • Dynamic scope management
    Wigwam reduces the complexities involved in coding directives intended for recursive or nested use in templates.
  • Template debugging features
    Wigwam templates' well-defined structure allows for some fancy debugging features.

Wigwam's default DirectiveSet plug-in extends this templating environment to include a powerful scripting language which offers:

Philosophy

Insert yours here.

Flexibility

Rather than impose our own templating philosophies on anyone, we chose to design Wigwam to be flexible. Although Wigwam provides for some fairly complex code in templates by default, it can quite easily be reduced to nothing more than a variable interpolator, which may be all you are looking for in a template parser. Or, perhaps somewhere in between. Wigwam allows you this flexibility.

Extensibility

The primary goal throughout the development of Wigwam was to make it as easily user-extensible as possible, to facilitate custom directives with all the robustness of any of the directives found in the DirectiveSet plug-in via a relatively simple API and with a minimal amount of code & effort.

Efficiency

For template coding and parsing efficiency, we've adopted a straight-forward Polish notation style syntax, as it requires the simplest of algorithms to process and is easy to learn. Under this scheme, template code is well-defined, parsed efficiently, and requires a minimal amount of pre-process time during tokenization, so templates execute with minimum initial overhead.

Wigwam's automatic casting mechanism and prototype scheme were designed with developmental efficiency in mind. They're designed to keep the amount of code necessary to add custom directives to a minimum, and at the same time to reduce the likelihood of runtime errors during template execution.


Interface

Wigwam employs an object oriented interface which is the mechanism through which a user invokes Wigwam to construct a template object, set up parameters, and execute (parse) the template.

Constructor

The new constructor returns a Wigwam template object, or undef upon error. It requires at least two arguments, the first of which indicates whether to parse a given string or a file. The second parameter is the string or filename which contains the root template to be processed.

 use Text::Wigwam;
 my $wwobj = Text::Wigwam->new( text => $string )
  or die $Text::Wigwam::ERROR;
 #      ...or...
 my $wwobj = Text::Wigwam->new( file => $filename )
  or die $Text::Wigwam::ERROR;

Optionally, three more parameters can be passed to the constructor, each of which are hash references. The key value pairs within these hash references are typically referred to as ``options'', or simply ``Wigwam options'' and are used to control some of the behavioral characteristics of the parsing engine, among other things. Most of these options can be set using any of the three hash reference parameters described below, however, each hash reference holds its own unique scope and/or priority level.

 use Text::Wigwam;
  my $wwobj = Text::Wigwam->new(
        file => 'path/to/root_template.txt',
        \%Restrict,
        \%Defaults,
        \%Settings,
  ) or die $Text::Wigwam::ERROR;
  print $wwobj->parse( \%varspace );

Restrict

Options defined within this parameter are global in scope and cannot be overridden throughout the life of the template object. It is used to fix options to a specific value not just for the root template, but any given child template as well. This is a handy mechanism for locking out features, such as specifying a fixed set of modules for use by templates, or limiting templates to specific branches of the directive tree, and so on..

Defaults

Options defined within this parameter represent the initial settings for the root template as well as all child templates, if any. These settings hold the lowest priority and are easily overridden, even from within a template.

Settings

Options defined within this parameter only apply to the root template, and are not passed to child templates. These settings will override conflicting settings in the Defaults parameter, but they can be overridden by conflicting options within the Restrict parameter, or a Wigwam configuration tag within the root template.

Standard Wigwam Options

(The available options will vary depending upon which parsing engine is in use)

The following options can only be defined via the Restrict parameter.

options_ltag_id
(Default: <<) Wigwam configuration tag left tag entity.
options_rtag_id
(Default: >>) Wigwam configuration tag right tag entity.
default_engine
(Default: Fusion) A comma delimited list of fall-back engines which are to be used in the event that the engine(s) specified by the engine parameter fail to initialize.

The following can be defined via any parameter.

engine
(Default: Fusion) - A comma delimited list of preferred parsing engines to be used to parse a given template. Should the first one fail to initialize, an attempt to initialize the next entry will be made. This goes on until an engine is successfully initialized or until all entries are exhausted, after which the default_engine parameters are invoked.
plugins
(Default: DirectiveSet) - Loads a comma delimited list of plug-ins.
modules
(Default: null) - Loads a comma delimited list of modules.
set_strict_tags
(Default: 1) - When true, helps to detect template coding issues such as missing arguments and/or unexpected #end tokens. It does this by generating an exception when a problem is detected. It is typically okay to set this value to false, but it is recommended to leave it enabled while coding templates.
set_spew_option
(Default: 0) - A debugging feature that outputs the list of current option keys and their values.
set_spew_stacks
(Default: 0) - A debugging feature that outputs the state of the Global stacks after template execution has terminated.
set_kill_wspace
(Default: ~) - Defines the character to be used to flag white-space removal outside of tag boundaries.
set_ltag_entity
(Default: [!!) - Defines the left tag entity.
set_rtag_entity
(Default: !!]) - Defines the right tag entity.
set_lblk_entity
(Default: <!!) - Defines the left block entity (block terminator).
set_rblk_entity
(Default: !!>) - Defines the right block entity (opens a new block).
set_priv_vspace
(Default: 0) - Generates an empty (private) variable space prior to template execution, when true. The parent template will not be able to access the current template's variable space.
set_save_vspace
(Default: null) - Indicates that child templates should be executed using the hash complex stored within the specified current variable space location as their root varspace. When left null, child templates will share a common variable space with the parent.
set_numeric_off
(Default: 0) - Forces the tokenizer to disable numeric literals when true, thereby requiring that all literals be surrounded by quotation marks. This is useful when a template must use variable names that may be confused as variable names by the tokenizer, such as 3.14E0.

Methods

The following methods can be invoked on a template object returned by the aforementioned constructor.

General

parse( hashref )
The parse method executes the template object and returns a list consisting of an error message (if any), and the resulting text of the parsed template. If the optional hashref parameter is provided, it will be used as the initial variable space for the template and will override any existing variable space data, including anything which was defined using the varspace related methods described below (set_value, set_alias, etc..).
 use Text::Wigwam;
 my $varspace = {};
 my $wwobj = Text::Wigwam->new( file => 'path/to/filename.txt' )
  or die $Text::Wigwam::ERROR;
 my( $error, $text ) = $wwobj->parse( $varspace );
 die $error if $error;
 print $text;

Directory Paths

Wigwam maintains several independent lists of directory paths which are used to locate various types of files. Whenever a file is required, Wigwam will attempt to locate it by searching the relevant path list in left-to-right order. Each list can be manipulated by invoking one of the following methods with the list class to be modified, followed by a list of directory paths.

set_path( class, path1, path2, ... )
The set_path method is used to provide Wigwam with an ordered list of directory paths in which to search for files of the specified class type. Any pre-existing list within the current template object is lost and replaced with the path items. The new list is then returned in list form.
add_path( class, path1, path2, ... )
This is similar to set_path except that add_path is non-destructive to any pre-existing list. The add_path method appends path items to any pre-existing list items in the specified class, thereby yielding priority to any existing directory paths. The updated list is returned in list form.

Where class (the first argument) is one of the following non-case-sensitive list types:

template
Specifies where Wigwam will look for child templates. Empty by default - no child templates can be processed unless you define at least one directory path in this list.
module
Specifies where Wigwam will look for modules. Defaults to a single entry which is the equivalent of Text::Wigwam::Modules on any given system. (e.g. /usr/lib/perl5/site_perl/5.8.4/Text/Wigwam/Modules)
plugin
Specifies where Wigwam will look for plug-ins. Defaults to a single entry equivalent to Text::Wigwam::Plugins.
engine
Specifies where Wigwam will look for engines. Defaults to a single entry which translates to the equivalent of Text::Wigwam::Engines.

Unrecognized class types will be silently ignored, and an empty list will always be returned as a result.

 use Text::Wigwam;
 $wwobj=Text::Wigwam->new( text => '[!!#template "blah" !!]' );
 $wwobj->add_path( template => '/var/www/templates' );
 print $wwobj->parse;

A copy of any given list can be retrieved by calling the non-destructive add_path list manipulation method with an empty list.

 print "Template paths: " . join( ', ', $wwobj->add_path( template => () ) );
 print "Module paths: ". join( ', ', $wwobj->add_path( module => () ) );

Directory paths can be given priority by placing them first in the list. This can be accomplished by first retrieving any existing list items (which is done by passing an empty list to the add_path method) and inserting the new items where appropriate.

 $wwobj->set_path( module => '/give/this/path/priority', $wwobj->add_path( 'module' ) );

Varspace related

The following methods can be used to pre-populate, or otherwise condition the template's variable space prior to template execution, or to retrieve data from the template's variable space after the template has executed. The function of each of the following methods are explained in more detail in the API section. It's also helpful to understand variables, which are explained in detail in the Variables section.

get_value( var )
set_value( var, val )
set_alias( var, val )
undefine( var )
is_defined( var )
generalized_get_value( ref, arr, var )
generalized_set_alias( ref, arr, var, val )
generalized_is_defined( ref, arr, var )
generalized_undefine( ref, arr, var )

Globals related

The following methods can be used to pre-populate, or otherwise condition the template's Globals prior to template execution, or to retrieve data from the Globals facility after template execution. The function of each of the following methods are explained in more detail in the API section. It's also helpful to understand Globals, which are explained in the Globals section.

set_global( name, val )
get_global( name )
add_global( name1, name2,... )
del_global( name1, name2,... )
push_global( name, val )
new_global( scope, name, default, eflag )
global_exists( name )
kill_global( name1, name2,... )


Templates

Wigwam templates are simply bodies of plain text enhanced with a customizable scripting language which is embedded within the text inside of predefined boundary identifiers (tag entities).

Tags

Wigwam tags are the elements of templates which invoke Wigwam code. They are denoted by the default delimiters [!! and !!], which typically encompass one or more Wigwam tokens. The Wigwam engine replaces these tags along with their contents with the resulting string of text that is produced after all of the encompassed tokens have been executed.

 Here is the gratuitous "[!!"Hello"!!], [!!"World"!!]" example.

After the above example is parsed by the engine, it becomes:

 Here is the gratuitous "Hello, World" example.

Tags are not limited to a single expression. The Wigwam engine will concatenate the results of each expression in a given tag, as demonstrated below.

 [!!  "Hello"   ", "   "World"  !!]

produces:

 Hello, World

Here is a somewhat more complex example which introduces a couple of arbitrary variables, as well as the #if directive (included in the DirectiveSet plug-in).

 [!!
        #if foo { "
                This is some text
                which will only be
                output if 'foo' has
                a true value.
                That value is " foo "."
                #if bar { "
                        bar is also true.
                        Its value is "
                        bar "."
                }
        }
 !!]

Blocks

Blocks are simply a means of representing an argument for any given directive in the form of a block of text (which may consist of embedded Wigwam tags and nested blocks) rather than a long string of tokens.

A new block is opened whenever a block tag delimiter (!!> by default) is encountered, and is terminated by its counterpart, the block terminator tag (<!! by default).

The block of text between these block tag delimiters is typically used as an argument for a directive inside the tag which opened the block.

 [!!
        #if foo !!>
                This is some text
                which will only be
                output if 'foo' has
                a true value.
                That value is [!! foo !!].
                [!! #if bar !!>
                        bar is also true.
                        Its value is [!! bar !!].
                <!! !!]
        <!!
 !!]

Notice that the preceding two examples use the same #if directive. This demonstrates that blocks are not tied to any particular directive or set of directives. Because blocks are not directive specific, they may be used to represent an argument for any given directive. This contributes to Wigwam's flexibility.

Terminators

A block terminator is simply a block terminator entity (<!! by default).

 [!! #if zig !!> Take off <!! #else !!> Great justice <!! !!]

Blocks aren't limited to representing the final argument for a given directive, although this is the typical coding method. Consider the following example where we use a block as the first argument for the #if directive.

 [!! #if !!>1<!! "True" !!]

Side effects

Blocks also provide some interesting and useful side effects, the first of which is that the Wigwam engine (in passive mode) can look past, skip over, or otherwise ignore a template element defined within a Block much quicker than it could if the same code were expressed as a long string of tokens within conventional tag entities.

Blocks are also handy in situations where it is desirable to define unexecuted code blocks (EXPR types, explained later) which contain directives whose corresponding module or plug-in may not yet have been loaded. The mechanics of this may be difficult to understand without intimate knowledge of how the Wigwam engine works, and it is unlikely that most people who will be using Wigwam will have this knowledge, so suffice it to say that the following template code will produce an exception unless the plug-in or module that handles the encompassed directives was loaded prior to execution.

 [!! #proc foo { #bzork #bazz #biff } !!]

The same declaration can be done using Block tag entities, in which case it does not matter whether or not the encompassed directives' plug-ins and/or modules were loaded. Obviously, it does matter when the attempt is eventually made to execute the code.

 [!! #proc foo !!>[!!#bzork #bazz #biff!!]<!! !!]

This can be useful for pre-defining pseudo-procedures (subroutines, macros) without requiring the corresponding plug-ins/modules to be loaded until they are necessary.

This may not make much sense to you if this is your first read through this documentation, and you may never require the need to exploit such a quirk. However, this behavior is by design and thus it has been documented.

White-space modifier

White-space surrounding any given tag can be eliminated at parse time by adding a white-space modifier character ('~' by default) to the inside of the tag entity. The white-space modifier character can be redefined using the set_kill_wspace option.

This example removes the leading white-space to the left of the tag.

 Howdy,         [!!~ " Stranger" !!]

produces

 Howdy, Stranger

This character can also be used at the closing tag to remove white-space up to and including the first encountered new-line character to the right of the tag.

 [!! "Hi, " ~!!]
 There!

produces:

 Hi, There!

White-space outside of the first encountered new-line character is left untouched, however. The purpose of this feature is to remove white-space used in formatting tag code - indenting nested tags & such.

 Welcome 
 [!!~ #if 1 !!>
        [!!~ "foobar" !!]
 <!! !!]

Assuming there is a single space after ``Welcome'', produces

 Welcome foobar

White-space produced by preceding tags is unaffected, however..

 [!! "Welcome, " !!]        [!!~ "Mister" !!]

produces

 Welcome, Mister

Comments

Any text existing between the character sequences /* and */ within a Wigwam tag will be ignored by the engine. This is useful for commenting your template code.

 [!! /* Greeting */ "Welcome!" !!]

produces

 Welcome!

Syntax

Wigwam code is written using Polish notation in which operators precede their operands. This not only allows for well-defined expressions without the need for parentheses or other grouping delimiters, but also offers a consistent syntax and contributes to Wigwam's parsing efficiency.

Ordinary Expression:

 1 + 2

Polish Notation:

 + 1 2

Wigwam Code:

 #add 1 2

Example

 $text = 'one plus two equals [!!#add 1 2!!]';
 use Text::Wigwam;
 my $wwobj = Text::Wigwam->new( text => $text );
 print $wwobj->parse();

produces:

 one plus two equals 3

Tokens

Wigwam tokens exist within Wigwam tags, and are separated by white-space. These tokens come in only three varieties: literals; variables; and directives. Together, they provide the power and flexibility needed to generate useful Wigwam templates.

Literals

There are two forms of literals...

Quoted

Quoted literals are identified by their surrounding quotation marks:

 [!! "My Dog Has Fleas" !!]
 [!! "37" !!]
 [!! "Quote marks can be \"escaped\" with the backslash character" !!]

Quoted literals can also be defined using the single quotation marks:

 [!! 'My Dog Has Ticks' !!]
 [!! 'The "double quote" marks don\'t need to be escaped here' !!]
 [!! 'However, the \'single quotes\' do' !!]

Both methods are identical in terms of function, the only difference being the character which requires the escape character when used within the string itself.

The special character sequences \n, \r, and \t in any quoted literal will produce a new-line, carriage return, and tab, respectively.

Numeric

Unquoted numeric literals are any string of characters that equates to a valid numeric value:

 [!! 42 !!]
 [!! 98.6 !!]
 [!! 186E3 !!]

Variables

Wigwam variables are identified by their lack of surrounding decorations (e.g. var1). They represent values which can be examined, defined and undefined. They're used to access values within Wigwam's variable space, which is simply a hash reference as the following example demonstrates.

 Wigwam Variables      Perl Equivalents
      foobar        $varspace->{foobar}
       var1         $varspace->{var1}
       quux         $varspace->{quux}

Path names

Path names are simply Wigwam variables with the introduction of dot and colon characters. These characters are part of a simplified syntax which is useful for directly accessing data within complex structures.

Each individual component of a path name represents either a hash key, or an array element. The first component of any path name is always a hash key, each subsequent component is identified by the dot or colon character which precedes it.

Components preceded by a dot character represent hash keys, and are restricted to valid Perl hash key characters.

 Wigwam Variables      Perl Equivalents
     foo.var1       $varspace->{foo}->{var1}
     foo.bar        $varspace->{foo}->{bar}
   foo.bar.baz      $varspace->{foo}->{bar}->{baz}

Components preceded by a colon character represent array elements, and should always equate to a numeric value.

 Wigwam Variables      Perl Equivalents
     foo:23         $varspace->{foo}->[23]
     bar:1          $varspace->{bar}->[1]
   baz:2:4.quux     $varspace->{baz}->[2]->[4]->{quux}

Path names make a trivial task of traversing even the most complex data structures. They're also a hell of a lot more readable than their Perl equivalents, especially when you throw self-interpolation into the mix...

Self-interpolation

Wigwam variables can, themselves, be interpolated using the square-brackets, '[' and ']', allowing values to be accessed indirectly.

 Wigwam Variables    Perl Equivalents
    foo.[quux]    $varspace->{foo}->{$varspace->{quux}}
    foo[quux]     $varspace->{"foo$varspace->{quux}"}
  fum:[baz.quux]  $varspace->{fum}->[$varspace->{baz}->{quux}]
  [fi:[fi.[fo]]]  $varspace->{$varspace->{fi}->[$varspace->{fi}->{$varspace->{fo}}]}

Escaped Characters

Any of these identifying characters can be escaped using the back-slash character '\'.

 Wigwam Variables    Perl Equivalents
   foo\.bar.baz      $varspace->{'foo.bar'}->{baz}
   baz\:2:4.quux     $varspace->{'baz:2'}->[4]->{quux}
  fum\:[baz.quux]    $varspace->{'fum:'.$varspace->{baz}->{quux}}
 \[fi\]:[fi.[fo]]    $varspace->{'[fi]'}->{$varspace->{fi}->{$varspace->{fo}}}

Directives

Directive tokens are identified by the hash mark '#' preceding them. They take the following form:

 #directive arg1 arg2 ...

All operations including defining variables, weighing values against each other, comparing strings, and connecting to a database, are performed by directives.

Directives are, in reality, just Perl subroutines which are typically organized in modules or plug-ins and are invoked by the parsing engine whenever a directive token is encountered in a template. Once executed, the directive and all of its associated arguments are interpolated by the parsing engine with the directive's return value.

Arguments

Each directive requires its own fixed number of arguments. For example, the #define directive in the DirectiveSet plug-in requires two arguments, a variable name and a value. It is important to understand that the number of arguments for each directive is fixed. It is crucial to provide the exact number of arguments required by a particular directive when writing Wigwam templates, otherwise you are bound to encounter unpredictable results.

 #define var "value"

It is perfectly acceptable to use directives as arguments. In the following example, the #define directive's arguments consist of the variable name 'var', and the #add directive. The #add directive requires two arguments (1 and 2, in the example below), and since its function is to return the sum of its arguments, it returns '3', which then replaces the expression #add 1 2. Ultimately, the value used as the second argument for the #define directive is '3', where it is assigned to the variable 'var'.

 #define var #add 1 2

...becomes...

 #define var 3

Directive tree

The directive tree is a hierarchy designed around Perl's package structure to organize directives into categories. The internal base of the directive tree is fixed in the Text::Wigwam::Directives name space. By default, any simple directive such as #foo is expected to be located in the Text::Wigwam::Directives name space. Subsequent nested packages represent branches of the directive tree and can be accessed explicitly using the following directive syntax:

 #name::space::here::directive_name_here

In the following example, the Wigwam engine would expect to find the connect directive within the Text::Wigwam::Directives::mysql name space.

 #mysql::connect ...

Certain features are available which can be used to temporarily overload directives, or restrict templates from accessing certain directives within the directive tree. These features are controlled by the set_pckg_root and set_pckg_path options.

The set_pckg_root option key is used to restrict templates to a specified name space within the directive tree. This option is null by default, but when set, it restricts templates (or template coders) to a specific branch within the directive tree.

The following table lists some examples of how the engine will attempt to locate a given directive.

 set_pckg_root    directive     name space in which the directive is presumed to exist
    (null)          #foo        Text::Wigwam::Directives
     quux           #foo        Text::Wigwam::Directives::quux
     blah      #fee::fye::foo   Text::Wigwam::Directives::blah::fee::fye
  roe::sham       #boe::foo     Text::Wigwam::Directives::roe::sham::boe

The set_pckg_path option key can be used to define a comma delimited list of name spaces in which to search for directives. The following table lists some examples of how the engine searches through the directive tree for directives given various set_pckg_path settings.

 set_pckg_root  set_pckg_path    directive     name space search order
    (null)     bazz,bazz::quux     #foo        Text::Wigwam::Directives::bazz
                                               Text::Wigwam::Directives::bazz::quux
                                               Text::Wigwam::Directives
 set_pckg_root  set_pckg_path    directive     name space search order
    (null)        bazz,quux    #fe::fi::foo    Text::Wigwam::Directives::bazz::fe::fi
                                               Text::Wigwam::Directives::quux::fe::fi
                                               Text::Wigwam::Directives::fe::fi

As the previous examples demonstrate, the root name space will assume the last value in the path. The root name space can be specified elsewhere in the path with an empty entry, as the following table attempts to demonstrate.

 set_pckg_root  set_pckg_path     directive     name space search order
    (null)     ,bazz,bazz::quux     #foo        Text::Wigwam::Directives
                                                Text::Wigwam::Directives::bazz
                                                Text::Wigwam::Directives::bazz::quux
 set_pckg_root  set_pckg_path     directive     name space search order
    (null)        bazz,,quux    #fe::fi::foo    Text::Wigwam::Directives::bazz::fe::fi
                                                Text::Wigwam::Directives::fe::fi
                                                Text::Wigwam::Directives::quux::fe::fi

The following tables list some examples of how the engine searches for directives given various set_pckg_path and set_pckg_root settings.

 set_pckg_root  set_pckg_path     directive     name space search order
   foobar         bazz,quux         #foo        Text::Wigwam::Directives::foobar::bazz
                                                Text::Wigwam::Directives::foobar::quux
                                                Text::Wigwam::Directives::foobar
 set_pckg_root  set_pckg_path     directive     name space search order
     bar          bazz,quux     #fe::fi::foo    Text::Wigwam::Directives::bar::bazz::fe::fi
                                                Text::Wigwam::Directives::bar::quux::fe::fi
                                                Text::Wigwam::Directives::bar::fe::fi
 set_pckg_root  set_pckg_path     directive     name space search order
   foobar         bazz,,quux        #foo        Text::Wigwam::Directives::foobar::bazz
                                                Text::Wigwam::Directives::foobar
                                                Text::Wigwam::Directives::foobar::quux

A clever administrator could, in theory, use this hierarchy to implement a set of strategically designed plug-ins and modules which, when used with these restrictive option settings, limit a template coder to a specific set of directives. It can also be used to enable any given child template to temporarily overload directives.

Interpolation

Wigwam variable interpolation is supported in directive names, much like it is done with Wigwam variables. The motivation for this feature was to add a layer of abstraction in calling directives which exist within a sub-level of the current branch of the directive tree.

 [!!
        #define db "pgsql"
        #[db]::connect
 !!]

translates to

 [!!
        #pgsql::connect
 !!]

This feature is not limited to the name space portion of the directive handle, as demonstrated in the following example.

 [!!
        #define action "add"
        #[action] 2 3
 !!]

translates to

 [!!
        #add 2 3
 !!]

which produces

 5

Dynamic parsing options

Wigwam's dynamic parsing options are typically used to define the behavioral characteristics of the parsing engine. They are manipulated via a uniquely identified and specially formatted configuration tag. This mechanism can be used to override pre-specified default values for the current template, or to restrict (lock) or alter the default settings for child templates. They take the following form:

  << Wigwam class: key1=value1; key2=value2; >>

Where class is one of Options, Restrict, Defaults, or Settings (case insensitive). The key=value pairs that follow the class declaration are made members of that class.

Configuration tags are very passive. Any unsupported class definitions and all key=value pairs defined therein will be silently ignored. Furthermore, no checks are made to determine whether any given option key serves a purpose, nor whether its value is of the required type or format.

The Options class is the only one that will affect the current template. The remainder of the classes are used to define defaults or restrictions for subsequently invoked child templates, and they directly correlate to their counterparts described in the Interface section. Note also that any predeclared Restrict settings still have precedence over all.

Only a single configuration tag may exist in any given template file, as only the first encountered configuration tag will be parsed. Any other configuration tags within the template will be ignored and treated as plain text. However, the various classes may be cascaded within this single configuration tag:

 << Wigwam Options: set_ltag_entity=[!!; set_rtag_entity=!!]; Restrict: engine=Foomatic; >>

Duplicate keys within a common class will be ignored.

 << Wigwam
        Options:
         set_ltag_entity=[!!;
         set_rtag_entity=!!];
        Restrict:
         engine=Foomatic;
        Options:
         set_ltag_entity=[%; /* ignored */
         set_strict_tags=0;
         set_rtag_entity=%]; /* ignored */
 >>

The colon, semicolon, and equals characters must be escaped using the back-slash character '\' when used as part of a key or value in a configuration tag.

 << Wigwam
        Options:
         set_pckg_root=bazz\:\:quux;
         set_pckg_path=foo\:\:bar;
         some\=crazy\:key=some\;wacky\=value;
 >>

Here's an example that demonstrates some available option keys and their respective standard values:

 << Wigwam
        Options: 
         set_engine=Fusion;
         set_strict_tags=1;
         set_strict_code=1;
         set_ltag_entity=[!!;
         set_rtag_entity=!!];
         set_lblk_entity=<!!;
         set_rblk_entity=!!>;
         set_kill_wspace=~;
         set_priv_vspace=0;
         set_numeric_off=0;
         set_spew_option=0;
         set_spew_stacks=0;
         plugins=DirectiveSet;
         modules=CgiTools, HtmlTools;
 >>

The default Wigwam configuration tag entities, << and >>, can be changed to whatever characters you see fit by using the options_ltag_id and options_rtag_id options exclusively within the Restrict hash reference parameter during the object construction phase. This is a global alteration and applies not only to the root template, but to all child templates as well. They cannot be changed throughout the life of the template object.

As an example, a CGI wrapper may alter the Wigwam configuration tag identifiers so that they take on a form similar to SSI in order to better blend in with html documents:

 <!--Wigwam Options: set_engine=Fusion; set_priv_vspace=0; -->


Development environment

Modules

Modules are simply Perl external library files which are used to organize the subroutines that make up custom directives. The directives contained within these modules become available to templates by loading them via the modules option. Where Wigwam finds these files is determined by the module directory path (see Directory Paths).

 << Wigwam Options: modules=CgiTools, HtmlTools; >>

As with all Perl external library files, the last executable statement in a Wigwam module should result in a true value. Simply putting ``1;'' or ``return 1;'' as this last executable value in the file will suffice. However, sometimes it is necessary for a module or plug-in to declare some Globals upon initialization. This can be accomplished by returning a reference to a subroutine instead of simply ``1;'' as the last executable statement in the file. This code will be executed and passed an API object as its only argument each time the module is initialized by a new template object.

Package declarations within Wigwam plug-ins and modules must begin with the base name space Text::Wigwam::Directives (the base of the directive tree). Subsequent nested name spaces must consist of all lower case characters, however (i.e. Text::Wigwam::Directives::blah::blah). Modules which do not explicitly declare a package will be loaded into the base name space, Text::Wigwam::Directives by default, as this is the default name space in which the Wigwam engine will look for directives.

Plug-ins

Plug-ins are functionally equivalent to modules, but differ in that they may associate directives with single-character symbols (i.e. '{' => #do, '(' => #list, etc.) and are given priority over modules in terms of loading and initialization. Plug-ins are stored separately from modules in the 'Text/Wigwam/Plugins' folder and are loaded via the plugins option.

 << Wigwam Options: plugins=DirectiveSet, CustomLingo; >>

Writing directives

Writing your own directive is extremely simple, as has been the intention throughout the development of Wigwam. All that is required for any single directive are two specifically named subroutines consisting of a prototype, and a handler.

Handlers use the following naming convention:

 sub _directive{ }

Prototypes are named like their handler counterpart but have ``_proto'' prepended:

 sub _proto_directive{ }

These two Perl subroutines make up a directive named #directive. The existence of these subroutines is detected at run-time when a directive is encountered by the engine while parsing a template. If either of these subroutines is absent, the engine will throw an exception.

Note that both subroutine names must use all lower case, as the engine will associate #directive, #Directive, #DIRective, #DIRECTIVE, etc. to the same all-lower-case handler/prototype pair.

Prototypes

The Wigwam engine uses the information gleaned from prototypes to ensure that directive handlers receive the type of data that they expect for each of their arguments. The engine will perform the necessary type-casting when required to ensure this. This technique puts much of the burden of housekeeping on the Wigwam engine, which contributes to simplifying the task of directive coding.

Prototypes should do nothing more than return a simple array reference. Each argument required by the directive handler is represented by its corresponding element in this array. Each argument's requested data type is represented by the value stored in their corresponding array element. Consequently, the number of arguments required by any given directive is determined by the number of elements in this array.

The values stored within this array consist of numeric constants which represent the various data types. These constants are accessible via methods provided by an object which is passed as an argument to the prototype upon its invocation, or they can be imported from the Text::Wigwam::Const class. The various constants are described in detail below.

As you might expect, prototypes are called by the Wigwam engine before the handler is called. However, prototypes are typically only called once per parsing session upon first encountering any given directive. The information is typically pulled from a cache upon subsequent encounters. This cache can be de-activated via the set_no_drip_cache option, thereby forcing the engine to call the prototype at each encounter of a directive . This will undoubtedly degrade performance and is typically used only for debugging and engine test purposes.

Besides providing useful information to the Wigwam engine, prototypes also provide an overview into the design of any given directive. This is useful for making sense of Wigwam modules written by someone other than yourself.

Handlers

Handlers perform the function of the directive. The Wigwam engine replaces the directive and its associated arguments in the template with the directive handler's return value.

Directive handlers are required to pull exactly all of the arguments declared in their corresponding prototype. Pulling too few arguments, or attempting to pull too many, will cause the Wigwam engine to throw an exception.

Arguments are processed by calling methods of the Wigwam API object which is provided as an argument by the engine upon invocation of the directive handler. These methods are explained in more detail later, but for typical module coding, you'll rarely need to use anything besides the methods: get_arg which retrieves the next argument; and kill_arg(n) which destroys the next n arguments.

Examples

Here's a simple directive called #fnord, which concatenates two given scalars and inserts ``(fnord)'' between them:

#fnord's prototype:

 sub _proto_fnord{ [ $_[0]->SCALAR, $_[0]->SCALAR ] }

This directive's prototype indicates to the Wigwam engine that it requires two arguments of type SCALAR. It does this by returning an array reference containing two elements whose values both indicate SCALAR type.

#fnord's handler:

 sub _fnord{ return( $_[0]->get_arg." (fnord) ".$_[0]->get_arg ); }

The handler in the preceding example makes two calls to the get_arg method in order to retrieve each of its two arguments. This handler simply returns these arguments with ``(fnord)'' inserted between them.

The following example demonstrates an alternative method of coding the same thing.

 use Text::Wigwam::Const qw(:all); # Imports Wigwam constants
 sub _proto_fnord{ [ SCALAR, SCALAR ] } 
 sub _fnord{ my $API=shift; return( $API->get_arg." (fnord) ".$API->get_arg ); }

Let's see our #fnord directive in action in a template - we'll assume that the module containing our #fnord directive routines was already saved as ``Fnord.pm'' into the appropriate modules folder...

 << Wigwam Options: modules=Fnord; >>
 [!!#fnord "Wigwam modules" "are fun!"!!]

produces:

 Wigwam modules (fnord) are fun!

Caveat

It is important that you use the kill_arg(n) method to pull arguments that are being ignored by your directive, as opposed to simply calling get_arg and throwing away its return value. This becomes an issue when, for example, an argument is made up of a directive which performs a physical operation on data. Consider the following example:

 sub _proto_unless{ my $WWC=shift; return [ $WWC->SCALAR, $WWC->ANY ]; } 
 sub _unless { 
        my $API=shift;
        if( $API->get_arg ){
                $API->get_arg; # retrieve the next argument,
                return;        # and return null.
        }
        return $API->get_arg;
 }

This works fine in situations like this:

 [!!#unless foo bar!!]

But consider situations like this:

 [!!#unless foo #undefine bar!!]

In the latter example, #undefine bar will be executed regardless of the value of foo, which is probably not the behavior you want.

The directive handler ought to be rewritten to use kill_arg(n), instead...

 sub _unless { 
        my $API=shift; 
        if( $API->get_arg ){
                $API->kill_arg(1); # destroy the next argument,
                return;            # and return null. 
        }
        return $API->get_arg; 
 }

Constants

The Text::Wigwam::Const class provides several constants which are to be used within directive prototypes to specify argument attributes required by their corresponding directive handlers.

 Data type
 Constant   Instructs the Wigwam engine to execute the next argument, and return...
   HASH       a hash reference.
   ARRAY      an array reference.
   SCALAR_REF a scalar reference.
 * BLESSED    a blessed reference (or else throw an exception).
 * NUM        a numeric scalar value (or else throw an exception).
 * ANY        any value - no casting or type-checking is performed.
   SCALAR     a scalar value.
   VAR        a scalar value.. unless the given argument is a variable name, in which case,
              return the raw variable name rather than its value. When used in conjunction
              with ARRAY or HASH, the Wigwam engine will vivify this variable's value with
              an empty array or hash, respectively, if it was previously undefined.
 * To be used exclusively. Do not combine with any other data type constant.

In most cases, the following argument modifiers should be used in conjunction with at least one of the above data type constants. Multiple modifiers can be specified per argument, so long as it makes sense.

 Modifier
 Constant   Signals the Wigwam engine that we wish to...
  BLOCK     Execute this argument in a new block scope.
            (see the Globals section).
  EXPR      Retrieve the next argument in the form of an expression so that it may be
            executed at a later time, multiple times, or perhaps not at all.
            Note: An EXPR object is executed by invoking its 'execute' method.
  STRICT    Disallow casting (accepting only the specified data type(s)). Generates
            an exception if the value encountered is of a different type than what is
            specified for this argument.
  TERM      Keep pulling arguments until an #end terminator token is encountered.
            (see C<list_ends> in the API section).
            (rarely needed)

Access to the constants can be achieved in several ways. They can all be imported into the current name space, thusly.

 use Text::Wigwam::Const qw(:all);

Or, more selectively...

 use Text::Wigwam::Const qw( ARRAY HASH SCALAR );

Importing is probably the prettiest way, as prototypes look more readable.

 use Text::Wigwam::Const qw( ARRAY HASH SCALAR );
 sub _proto_blah { [ SCALAR, HASH, ARRAY ] }

Or, as methods of the constants object which is passed in to each prototype upon invocation, for convenience.

 sub _proto_blah { [ $_[0]->SCALAR, $_[0]->HASH, $_[0]->ARRAY ] }

These attributes can also be strung together using Perl's bitwise-or operator '|' to indicate a number of acceptable data types for your directive handler. To demonstrate, here is the code for the #reverse directive straight out of the DirectiveSet plug-in...

 sub _proto_reverse{ [ $_[0]->ARRAY | $_[0]->HASH ] }
 sub _reverse{
        my $arg = $_[0]->get_arg;
        return { reverse( %{$arg} ) } if $_[0]->is_hash( $arg ); # Hash ref?
        return [ reverse( @{$arg} ) ];                          # Assume it's an array ref
 }

The prototype in the above example guarantees that we will receive either an array reference or a hash reference upon calling the get_arg method. Therefore, the handler needs only to check the reference type once. This not only simplifies things & saves us some code, but we avoid Perl runtime errors, as the argument's type is assured to be one of two possible types.

The EXPR data type

EXPR data types are ideally suited for macro and iterator directives, as they can be executed once, many times, or not at all. An EXPR object is executed by calling its execute method, after which it will return the appropriate data type as defined in the prototype where it was declared - if no data type was specified, ANY is assumed.

 sub _proto_badong { [ EXPR ] }
 # is identical to:
 sub _proto_badong { [ EXPR | ANY ] }
 # Or we can force the EXPR type to return a specific data type when executed:
 sub _proto_badong { [ EXPR | ARRAY ] }
 sub _badong {
   my $expr = $_[0]->get_arg;
   my $array = $expr->execute; # We're guaranteed an array reference here.
 }

EXPRs execute within the same environment as the template from which they originate. This means that if an expression object is executed from within a template other than the one where it was defined, the EXPR may not have access to the same varspace, directives, etc. as the template that invoked it. Conversely, the EXPR may have access to directives and resources that the calling template doesn't. This feature can be used as a means for providing some advanced functions to templates which are restricted to a very limited branch of the directive tree.

Some other standard methods available in EXPRs:

num
Returns a numeric representation of the size of the expression (usually the number of tokens).
doc
Returns the filename of the template in which it originated.
beautify
Returns a beautified representation of the expression.
engine
Returns the name of the engine that generated the expression.

API

The Wigwam API is an object that is passed by the engine as the first (and only) argument to any given directive handler upon invocation. It provides methods which can be called by directive handlers to perform basic functions, such as handling arguments, manipulating variables, managing Globals, and other useful functions. They are invoked using one of the following techniques:

 my $arg = $_[0]->get_arg; 
 # do something with $arg... 
 #   ..or.. 
 my $API=shift;
 my $arg = $API->get_arg;
 # do something with $arg...

Argument functions

get_arg
Returns the next argument in the form of the data type indicated in the prototype.
kill_arg( n )
Skips the next n arguments without executing them. When called on an #end terminated list (TERM type) argument, kill_arg(1) will destroy the entire list.
list_ends
Returns true if the #end token was encountered on the most recent get_arg call. This function should be called after each call to get_arg when pulling an #end terminated list (TERM type).

Basic variable functions

These functions perform operations on variables stored within Wigwam's variable space.

get_value( path_name )
Returns the value stored in path_name.
set_value( path_name, value )
Stores the specified value into path_name and returns value. If value happens to be a reference to an array or hash, set_value creates a new reference from value and uses that as the value to be stored into path_name & returned.
set_alias( path_name, value )
Stores value into path_name and returns value. Unlike set_value, set_alias blindly stores value into path_name. No copies of references are made.
is_defined( path_name )
Returns true if path_name is defined.
undefine( path_name )
Deletes the specified path_name key, or element.
escape_var( path_name )
Returns an escaped version of a variable name - backslashes are added in front of meta characters, such as the dot, colon, and square-bracket characters.

Data type detection functions

is_num( value )
Returns true if value is a valid numeric value.
is_scalar( thing )
Returns true if thing is a scalar value.
is_list( thing )
Returns true if thing is an array reference.
is_hash( thing )
Returns true if thing is a hash reference.
is_expr( thing )
Returns true if thing is a valid Wigwam expression object.
is_scalar_ref( thing )
Returns true if thing is a scalar reference.
is_blessed( thing )
Returns thing's underlying referent type if thing is a blessed reference, otherwise returns false.
ref_type( thing )
Returns the thing's underlying referent data type.

Note: The preceding methods will detect the underlying referent types of blessed references, with the exception of inherent Wigwam data types, such as EXPR. Of the data type detection methods described here, the is_expr method is the only one that will return true when passed an EXPR object, regardless of its true underlying referent type.

Miscellaneous functions

doc
Returns the current template filename, or null if it was provided as a text string.
exception( string )
Prepends some brief text to string indicating which template caused the exception and stores it in the die Global.
 $API->exception( 'An error occurred!' );
debug ( string )
Adds string as a comment that will appear at the current location in the template when reconstructed by Wigwam's template debugger facility.
load_modules( string )
Attempts to load all modules specified in the comma-delimited string. Returns undef upon success, or an error message if there was an error.
 my $err = $_[0]->load_modules( 'HtmlTools, CgiTools' );
 $_[0]->exception( $err ) if $err;
 return;
template( filename )
Attempts to locate and execute the child template specified by filename, and returns a list consisting of an error message (or null string) followed by the resulting text produced by the template.
 my( $error, $result ) = $API->template( 'ChildTemplate' );
 if( $error ){ $API->exception( $error ); return undef }
 return $result;
get_options( list )
Returns the values of configuration options specified in list for the currently executing template.

Returns a array of configuration values when called in list context.

 my ( $engine, $default_engine ) = $API->get_options qw( engine default_engine );
 return if $engine ne $default_engine;

When called in scalar context, only the value of the first parameter in list is returned.

 return if $API->get_options qw( engine ) ne $API->get_options qw( default_engine );

When no parameters are given in list, the entire configuration hash is returned in the form of a key/value list. This is handy for making a copy of the entire configuration hash.

 my %config_hash = $API->get_options();
 return if $config_hash{engine} ne $config_hash{default_engine};
set_path( class, list )
See Directory Paths
add_path( class, list )
See Directory Paths

Globals functions

For a more detailed description of what Globals are and how to use them, read the Globals section.

eflag( )
Returns true of the engine was forced into passive mode by an eflag enabled global.
set_global( name, value )
Sets the value of the name Global variable to value, and returns value.
get_global( name )
Returns the value of the name Global variable.
add_global( name1, name2, ... )
Adds one scope level to each specified Global and sets their default value.
del_global( name, name2, ... )
Deletes one scope level to each specified Global and restores their previous value.
inc_scope( name )
Push the default values into all stacks within the name scope, thereby incrementing the scope of all of those Globals.
dec_scope( name )
Pop all stacks within the name scope, thus restoring all of those Globals to their previous values.
push_global( name, value )
Performs an add_global function on name, followed by a set_value function on name using value, and returns value.
new_global( scope, name, default, eflag )
Creates a new Global variable called name within the specified scope, defines its default value and whether or not to enable eflag mode.
global_exists( name )
Returns the scope of the name Global, or undef if it is not defined.
kill_global( name1, name2,... )
Removes a Global, or a list of Globals. (rarely needed)

Advanced variable functions

The following variable functions are made available to directive handlers for rare situations where it's required to traverse arbitrary data complexes which are not necessarily stored within the normal varspace. They are primarily used by the Wigwam engine and are not typically used in directive handlers, since the basic variable functions will suffice 99% of the time.

generalized_get_value( ref, arr, var )
generalized_set_alias( ref, arr, var, val )
generalized_is_defined( ref, arr, var )
generalized_undefine( ref, arr, var )

Where...

ref
is the array or hash reference which will serve as the root level of the data structure to be traversed.
arr
indicates whether the root reference, ref, is to be accessed as an array (true), or as a hash (false). i.e.: $ref->[ ] vs. $ref->{ }
var
is the path name to be traversed.
val
is the value to be assigned to the final data element (generalized_set_alias only).

Caveat:

If a path name is embedded within a var inside of square brackets (i.e. foo.[bar]), that embedded element's value is retrieved based on the root varspace regardless of the ref value. As an example, the following routine probably will not return ``bazz'' as you might expect...

 my $ref = { foo => { quux => 'bazz' }, bar => 'quux' }; 
 return $API->generalized_get_value( $ref, 0, 'foo.[bar]' );

...instead, the call to generalized_get_value will behave similarly to the following semi-pseudo code to retrieve the value of the given path name, foo.[bar] ...

 return $ref->{foo}{$API->get_value('bar')};

Casting

Prototype information is used to determine the type of data required by the directive which is requesting the argument. Casting is performed by the Wigwam engine only if needed, so if a particular directive requests several acceptable types and the retrieved value matches any one of those types, no casting is performed and the value is returned as is.

All blessed references are treated according to their underlying referent data type unless the BLESSED attribute is set, in which case the raw blessed reference value is returned. Should the BLESSED attribute be set and a non-blessed reference is encountered, an exception is generated.

Should the cast facility encounter an EXPR type, it will be executed, and its resulting value is cast and returned accordingly.

   Type       Type       Casting 
 Requested  Retrieved  Method (Perl)     Which Returns
  SCALAR     SCALAR         N/A          The unaltered scalar value.
  SCALAR   SCALAR_REF     $$value        The dereferenced scalar value.
  SCALAR     ARRAY       scalar @$a      The number of array elements.
  SCALAR     HASH      scalar keys %$h   The number of hash keys.
  ARRAY      SCALAR      [ $scalar ]     An array reference with a single scalar element, or
          null string        []          an empty array reference if the scalar is a null string.
  ARRAY    SCALAR_REF  [ $$scal_ref ]    The value is dereferenced and cast as a SCALAR.
  ARRAY      ARRAY          N/A          The unaltered array reference.
  ARRAY      HASH        [ %$hash ]      An array reference whose elements take on the
                                          keys/values of the hash in some arbitrary order.
  HASH       SCALAR      { $scalar }     A hashref with the scalar value as its only key, or
          null string        {}          An empty hash reference if the scalar is a null string.
  HASH     SCALAR_REF  { $$scal_ref }    The value is dereferenced and cast as a SCALAR.
  HASH       ARRAY         { @$a }       A hash reference whose key/value pairs are populated by
                                         the array elements.
  HASH       HASH           N/A          The unaltered hash reference.
  ANY         any           N/A          The unaltered value - no casting.

Any time an exception is generated while an argument is being processed for any given directive, the cast routine will return a null version of the requested data type so that the parser can make a clean exit.

Globals

Wigwam Globals have nothing to do with Wigwam's variable space, rather, it's a stack management utility which can be used by directive handlers to pass data and state information to other directive handlers within a common scope, as well as providing a means to dynamically control the engine's parsing mode. Globals are manipulated by way of specific methods of the API (see the API section for a full list of available methods).

Globals make the following capabilities possible:

  • Nested blocks
    Manage nested blocks, like: #if 1 { #if 0 { 'Never!' } } #else{ 'Never!' }
  • Nested directives
    Manage states, as with: #given choice { #default { #template ``Menu'' } #when ``A'' { #template ``A'' } #when ``B'' { #template ``B'' } }
  • Process control
    Dynamic control over engine parsing modes for any given scope, as with #exit, #break, and #continue, etc.

Child templates inherit their parent template's Globals data upon invocation, and all directive handlers have access to the same Globals data regardless of the name space they inhabit. This is the reason they are referred to as Globals.

Globals are not generally needed in most directive handlers, but they are particularly useful when coding directives that affect process control (#break, #continue, #return, #exit, etc.), or those which interact with other directives within a common scope (#if, #elsif, #else, #given, #when, etc.).

Globals are declared by calling the new_global method of the API.

 $API->new_global( scope, name, default, eflag );
scope
The range in which any given value is retained ( 'TEMPLATE', 'BLOCK', 'GLOBAL', 'LOCAL' ).
name
The name by which the Global is to be referenced.
default
The default value given to this Global upon entering a new scope.
eflag
If set to true, this Global will will act as a process interrupt by enabling the engine's passive mode whenever its value within the current scope is true.

Global values within the current scope are manipulated by way of the set_global and get_global API methods, and are always referenced by name.

 $API->set_global( name, value ); 
 $foo = $API->get_global( name );

Block scope

BLOCK scope Globals must be declared by calling the new_global method, using the format:

 $API->new_global( 'BLOCK', name, default, eflag );

The directives #if, #elsif, and #else make use of a BLOCK scoped Global variable to maintain state. These directives take the following generalized form:

 #if expression block 
 #elsif expression block 
 #else block

The BLOCK scoped Global elseval is pre-declared in the module init routine to maintain state:

 return sub { my $API=shift; $API->new_global( 'BLOCK', 'elseval', undef, 0 ); }

BLOCK scope is declared on a per-argument basis in the directive's argument prototype:

 sub _proto_if{ my $WWC=shift; return [ $WWC->SCALAR, $WWC->ANY | $WWC->BLOCK ]; } 
 sub _proto_elsif{ my $WWC=shift; return [ $WWC->SCALAR, $WWC->ANY | $WWC->BLOCK ]; } 
 sub _proto_else{ my $WWC=shift; return [ $WWC->ANY | $WWC->BLOCK ]; }

When the Wigwam engine encounters a BLOCK argument, a new BLOCK scope is generated automatically, and thus a new instance of elseval vivified to its default value. Once that BLOCK argument has been processed, the previous BLOCK scope is restored immediately before the result is returned.

Local scope

LOCAL scope Globals can be pre-declared within a module init routine by calling the new_global method, using the format:

 $API->new_global( 'LOCAL', name, default, eflag );

LOCAL scope is invoked by the engine on specified variable names before the directive handler is called. These variable names are declared in an array reference existing as the second argument of the prototype:

 sub _proto_call{ return( [ $_[0]->VAR, $_[0]->ARRAY ], [ 'returnval', 'return' ] ); }

This signals the engine to push a new default value onto the returnval and return stacks before calling the directive handler. Once the directive handler has completed execution, the Wigwam engine restores the original values by popping the stacks.

LOCAL scoped Globals need not be pre-declared by calling the new_global method unless you want to specify a default value other than undef, or set the eflag to true. If a previously undeclared variable name appears in the locals prototype, a stack is automatically vivified using a default value of undef and eflag set to false.

 sub _proto_bazz{ return( [ ], [ 'bazzvar' ] ); }

Assuming bazzvar was never pre declared using new_global it would be vivified for you by the Wigwam engine, in essence like this:

 $API->new_global( 'LOCAL', 'bazzvar', undef, 0 );

Template scope

TEMPLATE scope variables must be pre-declared by invoking the new_global method, using the format:

 $API->new_global( 'TEMPLATE', name, default, eflag );

TEMPLATE scope is like BLOCK scope in that all variables declared as such are updated as a whole. TEMPLATE scoped variables are refreshed each time an external template is processed.

As an example, the #exit directive uses the 'bail' Global to halt further processing of a template. It is declared with 'TEMPLATE' scope and its eflag set to 1, which signals the engine to stop processing tokens within the current TEMPLATE scope as long as its value remains true.

 sub _proto_exit{ return [ ]; } 
 sub _exit{ $_[0]->set_global( bail => 1 ); return; } 
 return sub { $_[0]->new_global( 'TEMPLATE', 'bail', 0, 1 ); } # module init routine

Global scope

GLOBAL scope variables must be pre-declared by calling the new_global method, using the format:

 $API->new_global( 'GLOBAL', name, default, eflag );

GLOBAL scope is just that. The Wigwam engine never generates a new GLOBAL scope. Any Global declared with GLOBAL scope will retain its value until altered by set_global or until all tokens in all templates are exhausted.

The GLOBAL scoped die Global is the only Global inherently declared by the Wigwam engine. Its eflag is set to true so that all processing of the current template and parent templates (if any) will cease if its value becomes true.

 $API->new_global( 'GLOBAL', 'die', undef, 1 );

The API sets this GLOBAL's value upon invocation of the exception method.


Engine

The Wigwam engine is essentially Wigwam itself. It provides the basic framework for parsing templates by taking care of the low-level details involved. Although the engine directly handles literal-type and variable-type tokens, the directive tokens are passed off to plug-ins and modules. The engine monitors all data being passed between these directives filters it through its data type casting facility. This data type casting mechanism contributes to minimizing the amount of code needed within directive handlers.

Basic functions

Parsing modes

You really don't need to know much about the engine to make use of Wigwam. However, if you plan to write your own directives, it's helpful to understand the engine's parsing modes.

Active

Active mode is what we call it when the engine is happily executing tokens.

Passive

Passive mode is what we call it when the engine is pulling tokens without executing them. This mode is often automatically enabled by 'magical' eflag enabled Globals whenever any one of them accumulates a true value (see the Globals section).


Export

None by default.


See Also

HTML::TEMPLATE TEMPLATE::TOOLKIT


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

Validate: CSS, HTML, Spelling