NAME Text::MetaText - Perl extension implementing meta-language for processing "template" text files. SYNOPSIS use Text::MetaText; my $mt = new Text::MetaText; print $mt->process($filename, \%vardefs); SUMMARY OF METATEXT DIRECTIVES %% DEFINE variable=value %% # define variable(s) %% SUBST variable %% # insert variable value %% variable %% # short form of above %% BLOCK blockname %% # define a block 'blockname' block text... %% ENDBLOCK %% %% INCLUDE blockname %% # include 'blockname' block text %% INCLUDE filename %% # include external file 'filename' %% INCLUDE file_or_block # a more complete example... variable=value # additional variable definition(s) if=condition # conditional inclusion format=format_string # printf-like format string with '%s' filter=fltname(params) # post-process filter %% %% TIME # current system time, as per time(2) format=format_string # display format, as per strftime(3C) %% DESCRIPTION MetaText is a text processing and markup meta-language which can be used for processing "template" files. This module is a Perl 5 extension implementing a MetaText object class which processes text files, interpreting and acting on the embedded MetaText directives within. Like a glorified pre-processor, MetaText can; include files, define and substitute variable values, execute conditional actions based on variables, call other perl functions or object methods and capture the resulting output back into the document, and more. It can format the resulting output of any of these operations in a number of ways. The objects, and inherently, the format and symantics of the MetaText langauge itself, are highly configurable. MetaText was originally designed to aid in the creation of html documents in a large web site. It remains well suited for this and similar tasks, being able to create web pages (dynamically or statically) that are consistent with each other, yet easily customisable: * standard headers, footers and other elements can be defined in separate files and then inserted into web documents: %% INCLUDE header %% * variables can be defined externally or from within a document, then can be substituted back into the text. This is useful for including your %% name %% or %% email %% address or any other variable, and for encoding URL's or file paths that can then be changed en masse. e.g. * conditional actions can be made based on variable definitions, allowing easily and instantly customisable web pages. e.g %% INCLUDE higraphics/header if="higfx && userid != abw" %% * blocks of text can be internally defined simplifying the creation of repetitive elements. e.g. %% BLOCK table_row %% %% userid %% %% name %% %% ENDBLOCK %% %% INCLUDE table_row userid=lwall name="Larry Wall" %% %% INCLUDE table_row userid=tomc name="Tom Christiansen" %% %% INCLUDE table_row userid=merlyn name="Randal L. Schwartz" %% * in addition, the metapage utility is a script which can automatically traverse document trees, processing updated files to assist in web document management and other similar tasks. PREREQUISITES MetaText requires Perl 5.004 or later. The Date::Format module should also be installed. This is available from CPAN (in the "TimeDate" distribution) as described in the following section. OBTAINING AND INSTALLING THE METATEXT MODULE The MetaText module is available from CPAN. As the 'perlmod' man page explains: CPAN stands for the Comprehensive Perl Archive Network. This is a globally replicated collection of all known Perl materials, including hundreds of unbunded modules. [...] For an up-to-date listing of CPAN sites, see http://www.perl.com/perl/ or ftp://ftp.perl.com/perl/ . Within the CPAN archive, MetaText is in the "Text::" group which forms part of the the category: *) String Processing, Language Text Processing, Parsing and Searching The module is available in the following directories: /modules/by-module/Text/Text-MetaText-.tar.gz /authors/id/ABW/Text-MetaText-.tar.gz For the latest information on MetaText or to download the latest pre-release/beta version of the module, consult the definitive reference, the MetaText Home Page: http://www.kfs.org/~abw/perl/metatext/ MetaText is distributed as a single gzipped tar archive file: Text-MetaText-.tar.gz Note that "" represents the current MetaText Revision number, of the form "0.14". See the REVISION manpage below to determine the current version number for Text::MetaText. Unpack the archive to create a MetaText installation directory: gunzip Text-MetaText-.tar.gz tar xvf Text-MetaText-.tar 'cd' into that directory, make, test and install the MetaText module: cd Text-MetaText- perl Makefile.PL make make test make install The 't' sub-directory contains a number of small sample files which are processed by the test script (called by 'make test'). See the README file in that directory for more information. A logfile (test.log) is generated to report any errors that occur during this process. Please note that the test suite is incomplete and very much in an 'alpha' state. Any further contributions here are welcome. The 'make install' will install the module on your system. You may need root access to perform this task. If you install the module in a local directory (for example, by executing "perl Makefile.PL LIB=~/lib" in the above - see `perldoc MakeMaker' for full details), you will need to ensure that the PERL5LIB environment variable is set to include the location, or add a line to your scripts explicitly naming the library location: use lib '/local/path/to/lib'; The metapage utility is a script designed to automate MetaText processing of files. It can traverse directory trees, identify modified files (by comparing the time stamp of the equivalent file in both "source" and "destination" directories), process them and direct the resulting output to the appropriate file location in the destination tree. One can think of metapage as the MetaText equivalent of the Unix make(1S) utility. The installation process detailed above should install metapage in your system's perl 'installbin' directory (try `perl '- V:installbin'' to check this location). See the metapage documentation (`perldoc metapage') for more information on configuring and using metapage. USING THE METATEXT MODULE To import and use the MetaText module the following line should appear in your Perl script: use Text::MetaText; MetaText is implemented using object-oriented methods. A new MetaText object is created and initialised using the Text::MetaText->new() method. This returns a reference to a new MetaText object. my $mt = Text::MetaText->new; A number of configuration options can be specified when creating a MetaText object. A reference to a hash array of options and their associated values should be passed as a parameter to the new() method. $my $mt = Text::MetaText->new( { 'opt1' => 'val1', 'opt2' => 'val2' } ); The configurations options available are described in full below. All keywords are treated case-insensitively (i.e. "LIB", "lib" and "Lib" are all considered equal). LIB The INCLUDE directive causes the external file specified ("INCLUDE ") to be imported into the current document. The LIB option specifies one or more directories in which the file can be found. Multiple directories should be separated by a colon or comma. The current directory is also searched by default. my $mt = Text::MetaText->new( { LIB => "/tmp:/usr/metatext/lib" } ); CASE The default behaviour for MetaText is to treat variable names and identifiers case insensitively. Thus, the following are treated identically: %% INCLUDE foo %% %% INCLUDE FOO %% Setting the CASE option to any non-zero value causes the document to be processed case sensitively. my $mt = Text::MetaText->new( { CASE => 1 } ); # case sensitive Note that the configuration options described in this section are always treated case insensitively regardless of the CASE setting. MAGIC MetaText directives are identifed in the document being processed as text blocks surrounded by special "magic" identifers. The default identifiers are a double percent string, "%%", for both opening and closing identifiers. Thus, a typical directive looks like: %% INCLUDE some/file %% and may be embedded within other text: normal text, blah, blah %% INCLUDE some/file %% more normal text The MAGIC option allows new identifiers to be defined. A single value assigned to MAGIC defines a token to be used for both opening and closing identifiers: my $mt = Text::MetaText->new( { MAGIC => '++' } ); ++ INCLUDE file ++ A reference to an array providing two values (elements 0 and 1) indicates separate tokens to be used for opening and closing identifiers: my $mt = Text::MetaText->new( { MAGIC => [ '' ] } ); CHOMP When MetaText processes a file it identifies directives and replaces them with the result of whatever magical process the directive represents (e.g. file contents for an INCLUDE, variable value for a SUBST, etc). Anything outside the directive, including newline characters, are left intact. Where a directive is defined that has no corresponding output (DEFINE, for example, which silently sets a variable value), the trailing newline characters can leave large tracts of blank lines in the output documents. For example: line 1 %% DEFINE f="foo" %% %% DEFINE b="bar" %% line 2 Produces the following output: line 1 line 2 This happens because the newline characters at the end of the second and third lines are left intact in the output text. Setting CHOMP to any true value will remove any newline characters that appear immediately after a MetaText directive. Any characters coming between the directive and the newline, including whitespace, will override this behaviour and cause the intervening characters and newline to be output intact. With CHOMP set, the following example demonstrates the behaviour: line 1 %% DEFINE f="foo" %% %% DEFINE b="bar" %% line 2 Produces the following output (Note that "" is intended to represent a single space character, not the string "" itself, although the effect would be identical): line 1 line 2 FILTER There may be times when you may want to INCLUDE a file or element in a document but want to filter the contents in some way. You may wish to escape (i.e. prefix with a backslash '\') certain characters such as quotes, search for certain text and replace with an alternative phrase, or perform some other post-processing task. The FILTER option allows you to define one or more code blocks that can be called as filter functions from an INCLUDE directive. Each code block is given a unique name to identify it and may have calling parameters (parenthesised and separated by commas) that can be specified as part of the directive. e.g. %% INCLUDE foo filter="slurp(prm1, prm2, ...)" %% Two default filters are pre-defined: escape() and sr(). escape() takes as a parameter a perl-like regular expression pattern that indicates characters that should be 'escaped' (i.e. prefixed by a backslash '\') in the text. For example, to escape any of the character class `["'\]' you would specify the filter as: %% INCLUDE foo filter="escape([\"'\\])" %% The second filter, sr(), takes two arguments, a search string and a replace string. A simple substitution is made on the included text. e.g. %% INCLUDE foo filter="sr(spam, \"processed meat\")" %% Note that quotes and other special metacharacters should be escaped within the filter string as shown in the two examples above. Additional filters can be specified by passing a reference to a hash array that contains the name of the filter and the code itself in each key/value pair. Your filter function should be designed to accept the name of the function as the first parameter, followed by a line of text to be processed. Any additional parameters specified in the INCLUDE directive follow. The filter function is called for each line of an INCLUDE block and should return the modified text. Example: my $mt = Text::MetaText->new( { FILTER => { 'xyzzy' => sub { my ($filtername, $text, @params) = @_; $text = # do something here... $text; # return modified text } } } ); %% INCLUDE file1 filter="xyzzy(...)" %% A new FILTER definition will replace any existing filter with the same name. EXECUTE The SUBST directive performs a simple substitution for the value of the named variable. In the example shown below, the entire directive, including the surrounding 'magic' tokens '%%', is replaced with the value of the variable 'foo': %% SUBST foo %% (or more succinctly, %% foo %%) If the named variable has not been defined, MetaText can interpret the variable as the name of an object method in the current class or as a function in the main package. If the EXECUTE flag is set to any true value, the MetaText processor will interpret the variable as an object method and attempt to apply it to its own object instance (i.e. $self->$method(...)). If the method is not defined, the processor fails quietly (but see ROGUE below to see what can happen next). This allows classes to be derived from MetaText that implement methods that can be called (when EXECUTE == 1) as follows: %% method1 ... %% # calls $self->method1(...); %% method2 ... %% # calls $self->method2(...); The text returned from the method is used as a replacement value for the directive. The following pseudo-code example demonstrates this: package MyMetaText; @ISA = qw( Text::MetaText ); sub foo { "This is method 'foo'" } # simple return string sub bar { "This is method 'bar'" } # " " " package main; my $mt = MyMetaText->new( { EXECUTE => 1 } ); print $mt->process("myfile"); which, for the file 'myfile': %% foo %% %% bar %% generates the following output: This is method 'foo' This is method 'bar' If the EXECUTE flag is set to a value > 1 and the variable name does not correspond to a class method, the processor tries to interpret the variable as a function in the main package. Like the example above, the processor fails silently if the function is not defined (but see ROGUE below). The following pseudo-code extract demonstrates this: my $mt = Text::MetaText->new( { EXECUTE => 2 } ); print $mt->processs("myfile"); sub foo { "This is function 'foo'" } # simple return string sub bar { "This is fucntion 'bar'" } # " " " which, for the file 'myfile': %% foo %% %% bar %% generates the following output: This is function 'foo' This is function 'bar' Any additional parameters specified in the directive are passed to the class method or function as a hash array reference. The original parameter string is also passed. Note that the first parameter passed to class methods is the MetaText (or derivative) object reference itself. Example: %% foo name="Seuss" title="Dr" %% causes the equivalent of (when EXECUTE is any true value): $self->foo( # implicit $self ref { 'name' => 'Seuss', 'title' => 'Dr' }, # hash ref of params 'name="Seuss" title="Dr"' ); # parameter string and/or (when EXECUTE > 1): &main::foo( { 'name' => 'Seuss', 'title' => 'Dr' }, # hash ref of params 'name="Seuss" title="Dr"' ); # parameter string ROGUE This configuration item determines how MetaText behaves when it encounters a directive it does not recognise. The ROGUE option may contain one or more of the ROGUE keywords separated by any non-word character. The keywords and their associated meanings are: warn Issue a warning (via the ERROR function, if specified) when the directive is encountered. delete Delete any unrecognised directives. The default behaviour is to silently leave any unrecognised directive in the processed text. Example: my $mt = Text::MetaText->new( { ROGUE => "delete,warn" } ); DELIMITER The DELIMITER item specifies the character or character sequence that is used to delimit lists of data. This is used, for example, by the "in" operator which can be used in evaluation conditions. e.g. %% INCLUDE hardenuf if="uid in abw,wrigley" %% In this case, the condition evaluates true if the uid variable contains the value "abw" or "wrigley". The default delimiter character is a comma. The example: my $mt = Text::MetaText->new( { DELIMITER => ":" } ); would thus correctly process: %% INCLUDE hardenuf if="uid in abw:wrigley" %% ERROR The ERROR configuration item allows an alternative error reporting function to be specified for error handling. The function should expect a printf() like calling convention. Example: my $mt = Text::MetaText->new( { ERROR => sub { my ($format, @params) = @_; printf(STDERR "ERROR: $format", @params); } } ); DEBUG The DEBUG item allows an alternative debug function to be provided. The function should expect a printf() like calling convention, as per the ERROR option described above. The default DEBUG function sends debug messages to STDERR, prefixed by a debug string: 'D> '. DEBUGLEVEL The DEBUGLEVEL item specifies which, if any, of the debug messages are displayed during the operation of the MetaText object. Like the ROGUE option described above, the DEBUGLEVEL value should be constructed from one or more of the following keywords: none no debugging information (default) info general processing information config MetaText object configuration items preproc pre-processing phase process processing phase postproc post-processing phase data additional data parameters in debug messages content content of pre-processed INCLUDE blocks function list functions calls as executed evaluate trace conditional evaluations test used for any temporary test code all all of the above (excluding "none", obviously) Example: my $mt = Text::MetaText->new( { DEBUGLEVEL => "preproc,process,data" } ); MAXDEPTH It is possible for MetaText to become stuck in an endless loop if a circular dependancy exists between one or more files. For example: foo: %% INCLUDE bar %% bar: %% INCLUDE foo %% To detect and avoid such conditions, MetaText allows files to be nested up to MAXDEPTH times. By default, this value is 32. If you are processing a file which has nested INCLUDE directives to a depth greater than 32 and MetaText returns with a "Maximum recursion exceeded" warning, set this confiuration item to a higher value. e.g. my $mt = Text::MetaText->new( { MAXDEPTH => 42 } ); PROCESSING TEXT The MetaText process() method is called to process a file, interpreting any MetaText directives embedded within it. The first parameter should be the name of the file which should reside in the current working directory or in one of the directories specified in the LIB configuration option. A filename starting with a slash '/' is considered to be an absolute path. The optional second parameter may be a reference to a hash array containing a number of variable/value definitions that should be pre-defined when processing the file. print $mt->process("somefile", { name => "Fred" }); If "somefile" contains: Hello %% name %% then the output generated would be: Hello Fred Pre-defining variables in this way is equivalent to using the DEFINE directive (described below) at the start of the INCLUDE file %% DEFINE name="Fred" %% Hello %% name %% The process() function will continue until it reaches the end of the file or a line containing the pattern "__END__" by itself ("END" enclosed by double underscores, no other characters or whitespace on the line). Note that the pre-processor (a private method which is called by process(), so feel free to forget all about it) *does* scan past any __END__ marker. In practice, that means you can define blocks *after*, but use them *before*, the __END__ marker. e.g. Martin, %% INCLUDE taunt %% __END__ << processor stops here and ignores everything following %% BLOCK taunt %% << but the pre-processor has correctly you Camper! continued and parsed this block so that %% ENDBLOCK %% it can be included in the main body produces the output: Martin, you Camper! The process() function returns a string containing the processed file or block output. my $output = $mt->process("myfile"); print $output; METATEXT DIRECTIVES A MetaText directive is a block of text in a file that is enclosed by the MAGIC identifiers (by default '%%'). A directive may span multiple lines and may include blank lines within in. Whitespace within a directive is generally ignored except where quoted as part of a specific value. %% DEFINE name = Yorick age = 30 comment = "A fellow of infinite jest" %% The first word of the directive indicates the directive type. Directives may be specified in upper, lower or mixed case, irrespective of the CASE sensitivity flag (which affects only variable names). The general convention is to specify the directive type in UPPER CASE to aid clarity. The MetaText directives are: DEFINE Define the values for one or more variables SUBST Substitute the value of a named variable INCLUDE Process and include the contents of the named file or block BLOCK Define a named block which can be subsequently INCLUDE'd ENDBLOCK Marks the end of a BLOCK definition To improve clarity and reduce excessive, unnecessary and altogether undesirable verbosity, a directive block that doesn't start with a recognised MetaText directive is assumed to be a 'SUBST' variable substitution. Thus, %% SUBST foo %% can be written more succinctly as %% foo %% When MetaText processes directives, it is effectively performing a "search and replace". The MetaText directive block is replaced with whatever text is appropriate for the directive specified. Generally speaking, MetaText does not alter any text content or formatting outside of directive blocks. The only exception to this rule is when CHOMP is turned on (see the section on "USING THE METATEXT MODULE") and newlines immediately following a directive are subsequently deleted. DEFINE The DEFINE directive allows simple variables to be assigned values. Multiple variables may be defined in a single DEFINE directive. %% DEFINE name = Caliban quote = "that, when I waked, I cried to dream again." %% Variables defined within a file or passed to the process() function as a hash array remain defined until the file or block is processed in entirety. Variable values will be inherited by any nested files or blocks INCLUDE'd into the file. Re- definitions of existing variables will persist within the file or block, masking any existing values, until the end of the file or block when the previous values will be restored. The following example illustrates this: foo: Hello %% name %% # name assumes any predefined value %% DEFINE name=tom %% Hello %% name %% # name = 'tom' %% INCLUDE bar name='dick' %% # name = 'dick' for "INCLUDE bar" Hello %% name %% # name = 'tom' bar: Hello %% name %% # name = 'dick' %% DEFINE name='harry' %% # name = 'harry' Hello %% name %% Processing the file 'foo' as follows: print $mt->process('foo', { 'name' => 'nobody' }); produces the following output (with explanatory comments added for clarity): Hello nobody # value from process() hash Hello tom # from foo Hello dick # from bar Hello harry # re-defined in bar Hello tom # restored to previous value in foo SUBST A SUBST directive performs a simple variable substitution. If the variable is defined, its value will be inserted in place of the directive. Example: %% DEFINE name=Jake %% Hello %% SUBST name %% generates the following output: Hello Jake The SUBST keyword can be omitted for brevity. Thus "%% name %%" is processed identically to "%% SUBST name %%". If the variable is undefined, the MetaText processor will, according to the value of the EXECUTE configuration value, try to execute a class method or a function in the main package with the same name as the SUBST variable. If EXECUTE is set to any true value, the processor will try to make a corresponding method call for the current object (that is, the current instantiation of the MetaText or derived class). If no such method exists and EXECUTE is set to any value greater than 1, the processor will then try to execute a function in the main package with the same name as the SUBST variable In either case, the text returned from the method or function is included into the current block in place of the SUBST directive (non-text values are automatically coerced to text strings). If neither a variable, method or function exists, the SUBST directive will either be deleted or left intact (and additionally, a warning may be issued), depending on the value of the ROGUE configuration item. See EXTENDING METATEXT below for more information on deriving MetaText classes and using EXECUTE to extend the meta-language. The "format" and "filter" options as described in the INCLUDE section below are applied to the processed SUBST result before being inserted back into the document. Some MetaText variables have a special meaning. Unless specifically defined otherwise, the variable(s) listed below generate the following output: TIME The current system time in seconds since the epoch, 00:00:00 Jan 1 1970. Use the "format" option to specify a time/date format. INCLUDE The INCLUDE directive instructs MetaText to load and process the contents of the file or block specified. If the target is a file, it should reside in the current directory or a directory specified in the LIB configuration variable. Alternatively, the target may be a text block specified with BLOCK..ENDBLOCK directives (see below). %% INCLUDE chapter1 %% The target may also be a variable name and should be prefixed with a '$' to identify it as such. On evaluation, the value of the named variable will be used as the target: Example: %% DEFINE chapter=ch1 %% %% INCLUDE $chapter %% is equivalent to: %% INCLUDE ch1 %% Additional variables may be defined for substitution within the file: %% INCLUDE chapter2 bgcolor=#ffffff title="Chapter 2" %% The contents of the file "chapter2": %%title%% ... would produce the output: Chapter 2 ... Defining variables in this way is equivalent to using the DEFINE directive. Variables remain in scope for the lifetime of the file being processed and then revert to any previously defined values (or undefined). Any additional files processed via further INCLUDE directives within the file will also inherit any defined variable values. Example: %% INCLUDE file1 name="World" %% for the files: file1: # name => "World" from INCLUDE directive %% INCLUDE file2 %% file2: # inherits "name" variable from file1 %% INCLUDE file3 %% file3: # inherits "name" variable from file2 Hello %% name %% produces the output: Hello World The output generated by INCLUDE and SUBST directives can be formatted using a printf-like template. The format string should be specified as a "format" option in the INCLUDE or SUBST directive. Each line of the included text is formatted and concatentated to create the final output. Within the format string, '%s' is used to represent the text. For example, the 'author' element below could be used to display details of the author of the current document. author: File: %% file %% Author: %% name %% Date: %% date %% For inclusion in an HTML document, the text can be encapsulated in HTML comment tags ("") using a format string: %% INCLUDE author file = index.html name = "Andy Wardley" date = 19-Mar-1987 format = "" %% Which produces the following output: Note that the print format is applied to each line of the included text. To encapsulate the element as a whole, simply apply the formatting outside of the INCLUDE directive: In these examples, the formatting is applied as if the replacement value/line is a character string. Any of the standard printf(3) format tokens can be used to coerce the value into a specific type. As mentioned in the SUBST section above, the TIME variable is used to represent the current system time in seconds since the epoch (see time(2)). The "format" option can also be employed to represent such values in a more user-friendly format. Any format string that does not contain a '%s' token is assumed to be a time-based value and is formatted using the time2str() function from the Date::Format module (distributed as part of the TimeDate package). Example: The date is %% TIME format="%d-%b-%y" %% Generates: The date is 19-Mar-98 See `perldoc Date::Format' for information on the formatting characters available. The pragmatic token '%P' can be added to a format to override this behaviour and force the use of printf(). The '%P' token is otherwise ignored. Example: %% DEFINE foo=123456789 %% %% foo format="%d-%b-%y" %% # "day-month-year" using time2str %% foo format="%d" %% # "day" using timestr %% foo format="%P%d" %% # decimal value using printf %% foo format="%s" %% # string value using printf Generates: 29-Nov-73 29 123456789 123456789 Text that is inserted with an INCLUDE or SUBST directive can also be filtered. There are two default filters provided, 'escape' which can be used to escape (prefix with a backslash '\') certain characters, and 'sr' which is used to perform simple search and replace actions. Other filters may be added with the FILTER option when creating the object (see the FILTER section in the section on "USING THE METATEXT MODULE", above). Like the 'format' option, output filters work on a line of text at a time. Any parameters required for the filter can be specified in parentheses after the filter name. The 'escape' filter expects a perl-style character class indicating the characters to escape. The 'sr' filter expects two parameters, a search pattern and a replacement string, separated by a comma. Note that parameters that include embedded spaces should be quoted. The quote characters themselves must also be escaped as they already form part of a quoted string (the filter text). (This way of representing parameters is admittedly far from ideal and may be improved in a future version.) Example: %% DEFINE text="Madam I'm Adam" %% %% SUBST text filter="escape(['])" %% %% SUBST text filter="sr(Adam, \"Frank Bough\")" %% Generates: Madam I\'m Adam Madam I'm Frank Bough Conditional tests can be applied to INCLUDE blocks to determine if the block should evaluated or ignored. Variables and absolute values can be used and can be evaluated in the following ways: a == b # a is equal to b a != b # a is not equal to b a > b # a is greater than b a < b # a is less than b a => b # a is greater than or equal to b a <= b # a is less than or equal to b a =~ b # a matches the perl regex pattern b a !~ b # a does not match the perl regex pattern b a in b,c,d # a appears in the list b, c, d (see DELIMITER) The items on the right of the evaluations can be absolute values or variable names which should be prefixed by a '$'. The items on the left of the evaluation are assumed to be variable names. There is no need to prefix these with a '$', but you can if you choose. The single equality, "a = b", is treated identically to a double equality "a == b" although the two traditionally represent different things (the first, an assignment, the second, a comparison). In this context, I consider the former usage confusing and would recommend use of the latter at all times. Variables without any comparison operator or operand are tested for a true/false value. Examples: %% INCLUDE foo if="name==fred" %% %% INCLUDE foo if="$name==fred" %% # equivalent to above %% INCLUDE foo if="name==$goodguy" %% %% INCLUDE foo if="hour > 10" %% %% INCLUDE foo if="tonk =~ [Ss]pl?at" %% %% INCLUDE foo if="camper" %% Multiple conditions can be joined using the following boolean operators a && b # condition 'a' and 'b' a || b # condition 'a' or 'b' a ^ b # condition 'a' xor 'b' a and b # same as "a && b" but with lower precedence a or b # same as "a || b" but with lower precedence a xor b # same as "a ^ b" but with lower precedence Conditional equations are evaluated left to right and may include parentheses to explicitly set precedence. Examples: %% INCLUDE tonk if="hardenuf && uid in abw,wrigley" %% %% INCLUDE tapestry if="(girly && studly < 1) || uid == neilb" %% %% INCLUDE tapestry if="($girly && $studly < 1) || $uid == neilb" %% Note that the third example above is identical in meaning to the second, but explicitly prefixes variable names with '$'. This is optional for elements on the left hand side of comparison operators, but mandatory for those on the right that might otherwise be interpreted as absolute values. BLOCK..ENDBLOCK In some cases it is desirable to have a block of text available to be inserted via INCLUDE without having to define it in an external file. The BLOCK..ENDBLOCK directives allow this. A BLOCK directive with a unique identifier marks the start of a block definition. The block continues, including any valid MetaText directives, until an ENDBLOCK directive is found. A BLOCK..ENDBLOCK definition may appear anywhere in the file. It is in fact possible to INCLUDE the block before it has been defined as long as the block definition resides in the same file. Processing of a file stops when it encounters the __END__ marker on a line by itself. Blocks can be defined after this marker even though the contents of the file after __END__ are ignored by the processor. # include a block defined later %% INCLUDE greeting name=Prospero %% __END__ %% BLOCK greeting %% Hello %% name %% %% ENDBLOCK %% This produces the following output: # include a block defined later Hello Prospero Additional variable definitions specified in an INCLUDE directive will be applied to blocks just as they would to external files. A BLOCK..ENDBLOCK definition that appears in the main part of a document (i.e. before, or in the absence of an __END__ line) will not appear in the processed output. A simple "print" flag added to the BLOCK directive overrides this behaviour, causing a copy of the BLOCK to appear in it's place: %% DEFINE name=Caliban %% %% BLOCK greeting print %% Hello %% name %% %% ENDBLOCK %% %% INCLUDE greeting name="Prospero" %% produces the following output: Hello Caliban Hello Prospero Conditions ("if" and "unless") can be applied to BLOCK directives, but they affect how and when the BLOCK itself is printed, rather than determining if the block gets defined or not. Conditionals have no effect on BLOCK directives that do not include a "print" flag. EXTENDING METATEXT MetaText may be used as a base class for deriving other text processing modules. Any member function of a derived class can be called directly as a MetaText directive. See the EXECUTE configuration option for more details. Pseudo-code example: package MyMetaText; @ISA = qw( Text::MetaText ); # define a new derived class method, get_name() sub get_name { my $self = shift; my $params = shift; # return name from an ID hash, for example $self->{ PEOPLE }->{ $params->{'id'} } || 'nobody'; } package main; # use the new derived class my $mmt = MyMetaText { EXECUTE => 1 }; # process 'myfile' print $mmt->process('myfile'); which, for a sample file, 'myfile': %% get_name id=foo %% %% get_name id=bar %% is equivalent to: print $mmt->get_name({ 'id' => 'foo' }), "\n"; print $mmt->get_name({ 'id' => 'bar' }), "\n"; Alternatively, a simple calling script can be written that defines functions that themselves can be called from within a document: my $mt = Text::MetaText->new( { EXECUTE => 2 } ); print $mt->process("myfile"); sub get_name { my $params = shift; $global_people->{ $params->{'id'} } || 'nobody'; } Please note that the functionality provided by the EXECUTE option, and inherently, the extensibility possible by deriving MetaText sub-classes, relies in part on the operation of the AUTOLOAD method. Authors of derived MetaText classes should be aware of, and account for this, if re-defining the AUTOLOAD method. WARNINGS AND ERRORS The following list indicates warning or error messages that MetaText can generate and their associated meanings. "Closing directive tag missing in %s" A MetaText directive was found that was not terminated before the end of the file. e.g. `%% INCLUDE something ...' The processor attempts to compensate, but check your source files and add any missing MAGIC tokens. "Invalid configuration parameter: %s" An invalid configuration parameter was identified in the hash array passed to Text::MetaText->new(). See the section on "USING THE METATEXT MODULE". "Invalid debug/error function" The debug or error handling routine specified for the ERROR or DEBUG configuration options was not a code reference. See the ERROR and/or DEBUG sections for more details. "Invalid debug option: %s" A token was specified for the DEBUGLEVEL configuration item which was invalid. See the DEBUGLEVEL section for a complete list of valid tokens. "Invalid roque option: %s" A token was specified for the ROGUE configuration item which was invalid. See the ROGUE section for a complete list of valid tokens. "Maximum recursion exceeded" The processed file had multiple INCLUDE directives that nested to a depth greater than MAXDEPTH (default: 32). Set MAXDEPTH higher to avoid this problem, or check your files for circular dependencies. "Missing directive keyword" A MetaText directive was identified that had no keyword or other content. e.g. `%% %%' "Text::MetaText->new expects a hash array reference" The new() method can accept a reference to a hash array as the first parameter which contains configuration variables and values. This error is generated if the parameter is not a hash array reference. "Unrecognise directive: %s" An internal error that should never happen. The pre- processor has identified a directive type that the processor then failed to recognise. "Unrecognised token: %s" A `%% SUBST %%' or `%% %%' directive was found for which there was no corresponding defined. This warning is only generated when the 'warn' token is set for the ROGUE option. "Unmatched parenthesis: %s" A conditional evaluation ("if" or "unless") for a directive is missing a closing parenthesis. e.g. `%% INCLUDE foobar if="(foo && bar || baz" %%' "%s: non-existant or invalid filter" An INCLUDE or SUBST directive included a "filter" option that refers to a non-existant filter. e.g. `%% INCLUDE foo filter=nosuchfilter() %%' AUTHOR Andy Wardley See also: http://www.kfs.org/~abw/ http://www.kfs.org/~abw/perl/metatext/ My thanks extend to the people who have used and tested MetaText. In particular, the members of the Peritas Online team; Simon Matthews, Simon Millns and Gareth Scott; who brutally tested the software over a period of many months and provided valuable feedback, ideas and of course, bug reports. I am also indebted to the members of the SAS Team at Canon Research Centre Europe Ltd; Tim O'Donoghue, Neil Bowers, Ave Wrigley, Martin Portman, Channing Walton and Gareth Rees; although I'm not yet sure why. :-) I welcome bug reports, enhancement suggestions, comments, criticisms (hopefully constructive) and patches related to MetaText. I would appreciate hearing from you if you find MetaText particularly useful or indeed if it *doesn't* do what you want, for whatever reason. Hopefully this will help me make MetaText help you more. It pains me to say that MetaText comes without guarantee or warranty of suitability for any purpose whatsoever. That doesn't mean it doesn't do anything good, but just that I don't want some scrupulous old git to sue me because they thought I implied it did something it doesn't. ** REVISION $Revision: 0.15 $ COPYRIGHT Copyright (c) 1996-1998 Andy Wardley. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. SEE ALSO The metapage utility, the Date::Format module.