The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>HTML::Merge::Ext -  Extending Merge by writing your own tags</title>
<link rev="made" href="mailto:root@localhost" />
</head>

<body style="background-color: white">

<p><a name="__index__"></a></p>
<!-- INDEX BEGIN -->

<ul>

	<li><a href="#name">NAME</a></li>
	<li><a href="#description">DESCRIPTION</a></li>
	<li><a href="#types_of_tags">TYPES OF TAGS</a></li>
	<ul>

		<li><a href="#output_tags">Output tags</a></li>
		<li><a href="#non_block_tags">Non block tags</a></li>
		<li><a href="#opening_block_tags">Opening block tags</a></li>
		<li><a href="#closing_block_tags">Closing block tags</a></li>
	</ul>

	<li><a href="#compilation_process">COMPILATION PROCESS</a></li>
	<li><a href="#extension_files">EXTENSION FILES</a></li>
	<li><a href="#extended_tags_syntax">EXTENDED TAGS SYNTAX</a></li>
	<li><a href="#implementing_various_tags">IMPLEMENTING VARIOUS TAGS</a></li>
	<li><a href="#macro_tags">MACRO TAGS</a></li>
	<li><a href="#described_tags">DESCRIBED TAGS</a></li>
	<li><a href="#mod_perl_compliance_notice">MOD PERL COMPLIANCE NOTICE</a></li>
	<li><a href="#copyright">COPYRIGHT</a></li>
</ul>
<!-- INDEX END -->

<hr />
<p>
</p>
<h1><a name="name">NAME</a></h1>
<p>HTML::Merge::Ext -  Extending Merge by writing your own tags</p>
<p>
</p>
<hr />
<h1><a name="description">DESCRIPTION</a></h1>
<p>This file contains instructions as to how to create your own Merge tags.</p>
<p>
</p>
<hr />
<h1><a name="types_of_tags">TYPES OF TAGS</a></h1>
<p>Generally, there are four types of tags in Merge.</p>
<p>
</p>
<h2><a name="output_tags">Output tags</a></h2>
<p>Tags such as &lt;$RVAR&gt; or others, that are substituted by values that appear
in the output. For example: &lt;$RVAR.x&gt; is substituted by the value of the
vairable x.</p>
<p>
</p>
<h2><a name="non_block_tags">Non block tags</a></h2>
<p>Tags that perform an action, and have no corresponding closing tags.
For example: &lt;$RSET.x='8'&gt; sets the value 8 into the variable x.</p>
<p>
</p>
<h2><a name="opening_block_tags">Opening block tags</a></h2>
<p>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 <code>select()</code> statement) needs to be used.
For example, &lt;$RITERATION.LIMIT=4&gt; .. &lt;/$RITERATION&gt; will print everything
inside the block 4 times.</p>
<p>
</p>
<h2><a name="closing_block_tags">Closing block tags</a></h2>
<p>The tags that close blocks beginning in the opening tags.
The tags &lt;$REND&gt;, &lt;$REND_IF&gt; and &lt;$REND_WHILE&gt; 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: &lt;/$RCOUNT&gt; is the closing tag for
&lt;$RCOUNT&gt;</p>
<p>
</p>
<hr />
<h1><a name="compilation_process">COMPILATION PROCESS</a></h1>
<p><strong>Do not execute, create code!</strong></p>
<p>When Merge scans the template, it does not interprete the program, but
creates Perl code to run it. The HTML code is converted to <code>print()</code> 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:</p>
<p>&lt;$RVAR.x&gt; is translated to : print ($vars{``x''});</p>
<p>&lt;$RQ.'&lt;$RVAR.x&gt;'&gt; is translated to: $engines{``''}.Query(``'' . ($vars{``x''}) . ``'')</p>
<p>In both cases, the code generated by &lt;$RVAR&gt; is an expression, not a list
of statements.</p>
<p>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 &lt;$RSQR&gt; and generating the code
``sqr($x)''. If the user tried &lt;$RSQR.&lt;$RVAR.x&gt;&gt;, we will get
sqr(`` . $vars{''x``} . '') which is not what we intended.
Therefore we should create the code:
``sqr(\''$x\``)''
Which can be <code>sqr(``3'')</code> for &lt;$RSQR.3&gt; or sqr(``'' . $vars{``x''} . ``'') for
&lt;$RSQR.&lt;$RVAR.x&gt;&gt;.</p>
<p>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:</p>
<pre>
        sub Proper {
                my $str = shift;
                $str =~ s/(\w+)/ucfirst(lc($1))/ge;
                $str;
        }</pre>
<p>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.</p>
<p>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.</p>
<p>
</p>
<hr />
<h1><a name="extension_files">EXTENSION FILES</a></h1>
<p>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.</p>
<p>
</p>
<hr />
<h1><a name="extended_tags_syntax">EXTENDED TAGS SYNTAX</a></h1>
<p>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.</p>
<p>If we defined a tag called &lt;$RUSER&gt; with two parameters, it will be called
as &lt;$RUSER.&lt;first parameter&gt;.&lt;second parameter&gt;&gt;. If parameters were
encapsulated with quotes, it's the job of the user defined function to
strip them.</p>
<p>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.</p>
<p>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.</p>
<pre>
        sub OUT_PLUS ($$) {
                my ($a, $b) = @_;
                &quot;\&quot;$a\&quot; + \&quot;$b\&quot;&quot;; # Return perl code to perform the operation
        }</pre>
<p>Notes:</p>
<ol>
<li></li>
The prototype defines two parameters.
<p></p>
<li></li>
The parameters must be encapsulated with <strong>double</strong> quotes, even though we
expect numbers.
<p>Here is how <strong>***NOT***</strong> to implement the tag:</p>
<pre>
        sub OUT_PLUS ($$) {
                my ($a, $b) = @_;
                return $a + $b; # or equally WRONG:
                return '&quot;' . ($a + $b) . '&quot;''; 
        }</pre>
<p>You should not perform the operation in compilation time, but enable it to
perform in run time. The second version will work for
&lt;$RPLUS.4.5&gt; but <strong>NOT</strong> for &lt;$RPLUS.5.&lt;$RVAR.a&gt;&gt;, which will result in a
hard coded zero.</p>
<p></p></ol>
<p>
</p>
<hr />
<h1><a name="implementing_various_tags">IMPLEMENTING VARIOUS TAGS</a></h1>
<p>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.</p>
<pre>
        For a non block tag, use the prefix B&lt;API&gt;.
        For a block opening tag, use the prefix B&lt;OAPI&gt;.
        For a block ending tag, use the prefix B&lt;CAPI&gt;.
        For an output tag, use the prefix B&lt;OUT&gt;.</pre>
<p>You can use the perl functions setvar, getvar and incvar to manipulate Merge
variables.</p>
<p>Here are some examples:</p>
<pre>
        sub OAPI_CSV ($) {
                my $filename = shift;
                $filename =~ s/^\\([&quot;'])(.*)\\\1$/$2/; # Drop the quotes
                                                # in compilation time!
                &lt;&lt;EOM;
                open(I, &quot;$filename&quot;); # Must use double quotes!
                local (\$__headers) = scalar(&lt;I&gt;); # Do not use my() ! 
                chop \$__headers;
                local (\@__fields) = split(/,\\s*/, \$__headers);
                # Notice that we must escape variable names with backslashes
                while (&lt;I&gt;) {
                        chop;
                        my \@__data = split(/,\\s*/);
                        foreach my \$i (0 .. \$#__fields) {
                                setvar(\$__fields[\$i], \$__data[\$i]);
                        }
        EOM
        }</pre>
<pre>
        sub CAPI_CSV () {
                &quot;}&quot;;
        }</pre>
<pre>
        Here is how we would use it:</pre>
<pre>
        &lt;$RCSV.'/data/&lt;$RVAR.name&gt;'&gt;
                &lt;$RVAR.worker&gt; has salary &lt;$RVAR.salary&gt;&lt;BR&gt;
        &lt;/$RCSV&gt;</pre>
<pre>
        name could be 'workers.dat', and the file /data/workers.dat could be:</pre>
<pre>
        worker, salary, office
        Bill, 9999999999999, Redmond
        George, 0, White House</pre>
<p>
</p>
<hr />
<h1><a name="macro_tags">MACRO TAGS</a></h1>
<p>Macro tags define a tag by simply grouping merge code to be susbtituted under 
it. Suppose we have two tags, &lt;$RFIRST&gt; that takes two parameters, and 
&lt;$RSECOND&gt; that takes two as well, we could define the tag &lt;$RCOMBINED&gt;
this way:</p>
<pre>
        sub MACRO_COMBINED ($$$) {
                &lt;&lt;'EOM';
        First $1 and $2: &lt;$RFIRST.$1.$2&gt;&lt;BR&gt;
        Second $2 and $3: &lt;$RSECOND.$2.$3&gt;&lt;BR&gt;
        EOM
        }</pre>
<p>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.</p>
<p>
</p>
<hr />
<h1><a name="described_tags">DESCRIBED TAGS</a></h1>
<p>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.</p>
<p>Suppose we define a tag:</p>
<pre>
        sub OUT_MINUS ($$) {
                my ($a, $b) = @_;
                qq!(&quot;$a&quot;) - (&quot;$b&quot;)!;
        }</pre>
<p>Now suppose we define a description function:</p>
<pre>
        sub DESC_MINUS {
                'U-U';
        }</pre>
<p>We can now call the new tag: &lt;$RMINUS.7-6&gt; or &lt;$RMINUS.&lt;$RVAR.x&gt;-1&gt;
and so on.</p>
<p>All the non alpha characters in the description string stand for themselves.
The following letters are assigned:</p>
<pre>
        U - Unquoted parameters (e.g. 9, ball, &lt;$RVAR.a&gt; etc).
        Q - Quote parameter, (e.g. 'building', &quot;quoted string&quot;, 'a &quot;parameter&quot; with &lt;$RVAR.a&gt; 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.</pre>
<p>
</p>
<hr />
<h1><a name="mod_perl_compliance_notice">MOD PERL COMPLIANCE NOTICE</a></h1>
<p>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.</p>
<p>
</p>
<hr />
<h1><a name="copyright">COPYRIGHT</a></h1>
<p>Copyright (c) 1999 - 2005 Raz Information Systems Ltd.
<a href="http://www.raz.co.il">http://www.raz.co.il</a></p>
<p>This package is distributed under the same terms as Perl itself, see the
Artistic License on Perl's home page.</p>

</body>

</html>