NAME
HTML::Merge::Ext - Extending Merge by writing your own tags
DESCRIPTION
This file contains instructions as to how to create your own Merge tags.
TYPES OF TAGS
Generally, there are four types of tags in Merge.
Output tags
Tags such as <$RVAR> or others, that are substituted by values that
appear in the output. For example: <$RVAR.x> is substituted by the value
of the vairable x.
Non block tags
Tags that perform an action, and have no corresponding closing tags. For
example: <$RSET.x='8'> sets the value 8 into the variable x.
Opening block tags
Tags that usually handle the flow of the template. These tags, together
with the closing tags, encapsulate a block of HTML and tags between
them. The data inside the block will be treated as regular output
statements. If you wish to capture it for a different use, a capturing
mechanism (for example, using the Perl select() statement) needs to be
used. For example, <$RITERATION.LIMIT=4> .. </$RITERATION> will print
everything inside the block 4 times.
Closing block tags
The tags that close blocks beginning in the opening tags. The tags
<$REND>, <$REND_IF> and <$REND_WHILE> are privilleged as closing tags.
Other closing tags use the SGML like notation of specifying a slash
before the name of the tag, for example: </$RCOUNT> is the closing tag
for <$RCOUNT>
COMPILATION PROCESS
Do not execute, create code!
When Merge scans the template, it does not interprete the program, but
creates Perl code to run it. The HTML code is converted to print()
statements. Non block tags are inserted as generated Perl code. Block
tags are added as generated code, that encapsulate a perl operation on
the code within. Output tags depend on connotation: when specified in
the middle of HTML code, the generated code will be used as a parameter
for print(). When specified as part of a parameter for another tag,
string concatenation is used to create one string. For example:
<$RVAR.x> is translated to : print ($vars{"x"});
<$RQ.'<$RVAR.x>'> is translated to: $engines{""}.Query("" . ($vars{"x"})
. "")
In both cases, the code generated by <$RVAR> is an expression, not a
list of statements.
Notice, that when using *any* parameter gotten for a tag, either assumed
to be string or not, it must be encapsulated in double quotes. Consider
we are writing a tag <$RSQR> and generating the code "sqr($x)". If the
user tried <$RSQR.<$RVAR.x>>, we will get sqr(" . $vars{"x"} . ") which
is not what we intended. Therefore we should create the code:
"sqr(\"$x\")" Which can be sqr("3") for <$RSQR.3> or sqr("" . $vars{"x"}
. "") for <$RSQR.<$RVAR.x>>.
Hint: sometimes you need to perform a few sentences for generating an
output tag. In this case it is better to create a function to run in
runtime in the extension module, for example:
sub Proper {
my $str = shift;
$str =~ s/(\w+)/ucfirst(lc($1))/ge;
$str;
}
and generate the code: "HTML::Merge::Ext::Proper(\"$x\")". Note that all
the functions in the extension files reside under the namespace
HTML::Merge::Ext.
You can access the variable $HTML::Merge::Ext::ENGINE, or simply
$ENGINE, to determine which engine was called for the tag. The engine
API is not documented yet and might change without a warning.
EXTENSION FILES
Extension files are created per site, as a file called merge.ext,
residing in the instance directory, or per server, in the file
/etc/merge.ext.
EXTENDED TAGS SYNTAX
Every tag is defined as a function returning the Perl code for the tag.
The function must have a prototype cotaining only scalars, to represent
the number of input parameters.
If we defined a tag called <$RUSER> with two parameters, it will be
called as <$RUSER.<first parameter>.<second parameter>>. If parameters
were encapsulated with quotes, it's the job of the user defined function
to strip them.
All special chars in the parameters will be quoted with a leading
backslash using the function quotemeta. Special chars that were not
quoted belong to the generated code the parameters might already
contain. We basically encourage that you don't alter the parameters,
except of stripping quotes if necessary.
Here is an example for a tag called PLUS, that accepts two parameters,
and is substituted by the result of their addition in the output. Notice
that the function prototype is crucial.
sub OUT_PLUS ($$) {
my ($a, $b) = @_;
"\"$a\" + \"$b\""; # Return perl code to perform the operation
}
Notes:
1 The prototype defines two parameters.
2 The parameters must be encapsulated with double quotes, even though
we expect numbers.
Here is how ***NOT*** to implement the tag:
sub OUT_PLUS ($$) {
my ($a, $b) = @_;
return $a + $b; # or equally WRONG:
return '"' . ($a + $b) . '"'';
}
You should not perform the operation in compilation time, but enable
it to perform in run time. The second version will work for
<$RPLUS.4.5> but NOT for <$RPLUS.5.<$RVAR.a>>, which will result in
a hard coded zero.
IMPLEMENTING VARIOUS TAGS
Functions should be in all uppercase, and consist of a prefix describing
the type of the tag, an underscore, and the tag name. Merge is case
insensitive, so don't try to define tags with lowercase names.
For a non block tag, use the prefix B<API>.
For a block opening tag, use the prefix B<OAPI>.
For a block ending tag, use the prefix B<CAPI>.
For an output tag, use the prefix B<OUT>.
You can use the perl functions setvar, getvar and incvar to manipulate
Merge variables.
Here are some examples:
sub OAPI_CSV ($) {
my $filename = shift;
$filename =~ s/^\\(["'])(.*)\\\1$/$2/; # Drop the quotes
# in compilation time!
<<EOM;
open(I, "$filename"); # Must use double quotes!
local (\$__headers) = scalar(<I>); # Do not use my() !
chop \$__headers;
local (\@__fields) = split(/,\\s*/, \$__headers);
# Notice that we must escape variable names with backslashes
while (<I>) {
chop;
my \@__data = split(/,\\s*/);
foreach my \$i (0 .. \$#__fields) {
setvar(\$__fields[\$i], \$__data[\$i]);
}
EOM
}
sub CAPI_CSV () {
"}";
}
Here is how we would use it:
<$RCSV.'/data/<$RVAR.name>'>
<$RVAR.worker> has salary <$RVAR.salary><BR>
</$RCSV>
name could be 'workers.dat', and the file /data/workers.dat could be:
worker, salary, office
Bill, 9999999999999, Redmond
George, 0, White House
MACRO TAGS
Macro tags define a tag by simply grouping merge code to be susbtituted
under it. Suppose we have two tags, <$RFIRST> that takes two parameters,
and <$RSECOND> that takes two as well, we could define the tag
<$RCOMBINED> this way:
sub MACRO_COMBINED ($$$) {
<<'EOM';
First $1 and $2: <$RFIRST.$1.$2><BR>
Second $2 and $3: <$RSECOND.$2.$3><BR>
EOM
}
This tag can now be called with three parameters. Note: You do not need
to parse the parameters yourself in a Macro tag. You need to return a
string containing Merge code and references to the parameters like in a
shell script. Writing a prototype is still mandatory.
DESCRIBED TAGS
Until now, extension tags could be called only with a list of parameters
separated by commas. But merge enables defining tags that take a syntax
similar to Merge native tags.
Suppose we define a tag:
sub OUT_MINUS ($$) {
my ($a, $b) = @_;
qq!("$a") - ("$b")!;
}
Now suppose we define a description function:
sub DESC_MINUS {
'U-U';
}
We can now call the new tag: <$RMINUS.7-6> or <$RMINUS.<$RVAR.x>-1> and
so on.
All the non alpha characters in the description string stand for
themselves. The following letters are assigned:
U - Unquoted parameters (e.g. 9, ball, <$RVAR.a> etc).
Q - Quote parameter, (e.g. 'building', "quoted string", 'a "parameter" with <$RVAR.a> inside')
E - Call can end here, rest of the parameters optional. For example, a tag with the description QE:Q-QE*Q can be called as either 'first', 'first':'second'-'third' or 'first':'second'-'third'*'fourth'.
D - Either a dot or equal sign.
MOD PERL COMPLIANCE NOTICE
Merge implements the extensions by compiling them as Perl code into
Merge itself. Therefore, on a mod_perl driven web server with several
instances, extensions will be shared among all instances.
COPYRIGHT
Copyright (c) 1999 - 2005 Raz Information Systems Ltd.
This package is distributed under the same terms as Perl itself, see the
Artistic License on Perl's home page.