Updated art6 ideas.
[artemus.git] / Artemus4.pm
blobc4d02b4ce09d03d296bd13b5a2f3e7ce926c2daa
1 #####################################################################
3 # Artemus - Template Toolkit version 4
5 # Copyright (C) 2000/2009 Angel Ortega <angel@triptico.com>
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License
9 # as published by the Free Software Foundation; either version 2
10 # of the License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 # http://triptico.com
23 #####################################################################
25 use locale;
27 package Artemus4;
29 use strict;
30 use warnings;
32 $Artemus4::VERSION = '4.1.3-dev';
34 sub armor {
35 my $self = shift;
36 my $str = shift;
38 if ($str) {
39 $str =~ s/{/\&#123;/g;
40 $str =~ s/\|/\&#124;/g;
41 $str =~ s/}/\&#125;/g;
42 $str =~ s/\$/\&#36;/g;
43 # $str =~ s/=/\&#61;/g;
46 return $str;
50 sub unarmor {
51 my $self = shift;
52 my $str = shift;
54 if ($str) {
55 $str =~ s/\&#123;/{/g;
56 $str =~ s/\&#124;/\|/g;
57 $str =~ s/\&#125;/}/g;
58 $str =~ s/\&#36;/\$/g;
59 # $str =~ s/\&#61;/=/g;
62 return $str;
66 sub strip {
67 my ($ah, $t) = @_;
69 $t =~ s/{-([-\\\w_ \.]+)[^{}]*}/$1/g;
71 return $t;
75 sub params {
76 my $self = shift;
77 my $str = shift;
79 my $n = 0;
80 foreach my $a (@_) {
81 $a ||= '';
82 $str =~ s/(^|[^\\])\$$n/$1$a/g;
83 $n++;
86 $str =~ s/(^|[^\\])\$\d+/$1/g;
88 return $str;
92 sub process {
93 my ($ah, $data) = @_;
95 # not aborted by now
96 ${$ah->{'abort-flag'}} = 0;
98 # no unresolved templates by now
99 @{$ah->{'unresolved'}} = ();
101 # reset calling stack
102 @{$ah->{call_stack}} = ();
104 # surround with \BEGIN and \END
105 $data = $ah->{'vars'}->{'\BEGIN'} . $data . $ah->{'vars'}->{'\END'};
107 # really do it, recursively
108 $data = $ah->_process_do($data, 0);
110 # finally, convert end of lines if necessary
111 if ($ah->{'use-cr-lf'}) {
112 $data =~ s/\n/\r\n/g;
115 # strip comments
116 $data =~ s/{%[^}]+}//g;
118 return $data;
122 sub _process_do {
123 my ($ah, $data, $level, $template_name) = @_;
124 my ($cache_time);
126 # test if the template includes cache info
127 if ($data =~ s/{-\\CACHE\W([^}]*)}//) {
128 if ($template_name and $ah->{'cache-path'}) {
129 $cache_time = $1;
131 # convert strange chars to :
132 $template_name =~ s/[^\w\d_]/:/g;
134 my ($f) = "$ah->{'cache-path'}/$template_name";
136 if (-r $f and -M $f < $cache_time) {
137 open F, $f;
138 flock F, 1;
139 $data = join('', <F>);
140 close F;
142 return $data;
147 # strip POD documentation, if any
148 if ($data =~ /=cut/ and not $ah->{'contains-pod'}) {
149 my (@d);
151 foreach (split("\n", $data)) {
152 unless (/^=/ .. /^=cut/) {
153 push(@d, $_);
157 $data = join("\n", @d);
160 # strips HTML comments
161 if ($ah->{'strip-html-comments'}) {
162 $data =~ s/<!--.*?-->//gs;
165 # if defined, substitute the paragraphs
166 # with the paragraph separator
167 if ($ah->{'paragraph-separator'}) {
168 $data =~ s/\n\n/\n$ah->{'paragraph-separator'}\n/g;
171 # inverse substitutions
172 # (disabled until it works)
173 # while (my ($i, $v) = each(%{$ah->{'inv-vars'}})) {
174 # $data =~ s/\b$i\b/$v/g;
177 # main function, variable and include substitutions
178 while ($data =~ /{-([^{}\\]*(\\.[^{}\\]*)*)}/s) {
179 my ($found) = $1;
181 # take key and params
182 my ($key, $params) = ($found =~ /^([-\\\w_]+)\|?(.*)$/s);
184 # replace escaped chars
185 $params =~ s/\\{/{/g;
186 $params =~ s/\\}/}/g;
187 $params =~ s/\\\$/\$/g;
189 # split parameters
190 my @params = ();
192 while (length($params) && $params =~ s/^([^\|\\]*(\\.[^\|\\]*)*)\|?//s) {
193 my $p = $1;
194 $p =~ s/\\\|/\|/g;
196 push(@params, $p);
199 my $text = '';
201 # is it a variable?
202 if (defined $ah->{'vars'}->{$key}) {
203 $text = $ah->{'vars'}->{$key};
204 $text = $ah->params($text, @params);
207 # is it a function?
208 elsif (defined $ah->{'funcs'}->{$key}) {
209 my ($func);
211 $func = $ah->{'funcs'}->{$key};
212 $text = $func->(@params);
214 # functions can abort further execution
216 if (${$ah->{'abort-flag'}}) {
217 last;
221 # can it be loaded externally?
222 elsif (defined $ah->{loader_func} &&
223 (ref($ah->{loader_func}) eq 'CODE') &&
224 defined($text = $ah->{loader_func}->($key))) {
226 $text = $ah->params($text, @params);
229 # is it an include?
230 elsif ($ah->{'include-path'}) {
231 foreach my $p (@{$ah->{'include-path'}}) {
232 if (open(INC, "$p/$key")) {
233 $text = join('', <INC>);
234 close INC;
236 # cache it as a variable
237 $ah->{vars}->{$key} = $text;
239 $text = $ah->params($text, @params);
241 last;
245 else {
246 $text = $found;
248 push(@{$ah->{'unresolved'}}, $found);
250 if (ref $ah->{'AUTOLOAD'}) {
251 $text = $ah->{'AUTOLOAD'}($found);
255 $text ||= '';
257 if ($ah->{debug}) {
258 push(@{$ah->{call_stack}},
259 [ $key, $level, $found, $text ]
263 # do the recursivity
264 $text = $ah->_process_do($text, $level + 1, $key) || '';
266 # make the substitution
267 $data =~ s/{-\Q$found\E}/$text/;
270 # if the template included cache info,
271 # store the result there
272 if ($cache_time) {
273 open F, '>' . $ah->{'cache-path'} . '/' . $template_name;
274 flock F, 2;
275 print F $data;
276 close F;
279 return $data;
283 sub init {
284 my $self = shift;
286 # special variables
287 $self->{vars}->{'\n'} = "\n";
288 $self->{vars}->{'\BEGIN'} ||= '';
289 $self->{vars}->{'\END'} ||= '';
290 $self->{vars}->{'\VERSION'} = $Artemus4::VERSION;
292 # special functions
293 $self->{funcs}->{localtime} = sub { scalar(localtime) };
295 $self->{funcs}->{if} = sub { $_[0] ? $_[1] : (scalar(@_) == 3 ? $_[2] : '') };
296 $self->{funcs}->{ifelse} = $self->{funcs}->{if};
298 $self->{funcs}->{ifeq} = sub { $_[0] eq $_[1] ? $_[2] : (scalar(@_) == 4 ? $_[3] : '') };
299 $self->{funcs}->{ifneq} = sub { $_[0] ne $_[1] ? $_[2] : (scalar(@_) == 4 ? $_[3] : '') };
300 $self->{funcs}->{ifeqelse} = $self->{funcs}->{ifeq};
302 $self->{funcs}->{add} = sub { ($_[0] || 0) + ($_[1] || 0); };
303 $self->{funcs}->{sub} = sub { ($_[0] || 0) - ($_[1] || 0); };
304 $self->{funcs}->{gt} = sub { ($_[0] || 0) > ($_[1] || 0); };
305 $self->{funcs}->{lt} = sub { ($_[0] || 0) < ($_[1] || 0); };
306 $self->{funcs}->{eq} = sub { $_[0] eq $_[1] ? 1 : 0; };
307 $self->{funcs}->{random} = sub { $_[rand(scalar(@_))]; };
309 $self->{funcs}->{and} = sub { ($_[0] && $_[1]) || ''; };
310 $self->{funcs}->{or} = sub { $_[0] || $_[1] || ''; };
311 $self->{funcs}->{not} = sub { $_[0] ? 0 : 1; };
313 $self->{funcs}->{foreach} = sub {
314 my $list = shift;
315 my $code = shift || '$0';
316 my $sep = shift || '';
317 my $hdr = shift || '';
319 my @ret = ();
320 my @l = split(/\s*:\s*/, $list);
321 my $ph = '';
323 foreach my $l (@l) {
324 my @e = split(/\s*,\s*/, $l);
326 my $o = '';
328 if ($hdr) {
329 # generate header: parse parameters
330 my $tc = $self->params($hdr, @e);
332 # and process (we want the output of
333 # the possible code, no the code itself)
334 $tc = $self->_process_do($tc);
336 # is it different from previous? add
337 if ($tc ne $ph) {
338 $o = $tc;
341 # store for later
342 $ph = $tc;
345 # add main body
346 $o .= $self->params($code, @e);
348 push(@ret, $o);
351 return join($sep, @ret);
354 $self->{funcs}->{set} = sub { $self->{vars}->{$_[0]} = $_[1]; return ''; };
356 $self->{funcs}->{case} = sub {
357 my $var = shift;
358 my $ret = '';
360 chomp($var);
361 $var =~ s/\r//g;
363 # if args are odd, the last one is
364 # the 'otherwise' case
365 if (scalar(@_) % 2) {
366 $ret = pop(@_);
369 while (@_) {
370 my $val = shift;
371 my $out = shift;
373 chomp($val);
374 $val =~ s/\r//g;
376 if ($var eq $val) {
377 $ret = $out;
378 last;
382 return $ret;
385 $self->{funcs}->{env} = sub { scalar(@_) ? ($ENV{$_[0]} || '') : join(':', keys(%ENV)); };
386 $self->{funcs}->{size} = sub { scalar(@_) ? split(/\s*:\s*/, $_[0]) : 0; };
387 $self->{funcs}->{seq} = sub { join(':', ($_[0] || 0) .. ($_[1] || 0)); };
388 $self->{funcs}->{item} = sub { (split(/\s*:\s*/, $_[0]))[$_[1]]; };
390 $self->{funcs}->{sort} = sub {
391 my $list = shift;
392 my $field = shift || 0;
394 join(':',
395 sort {
396 my @a = split(',', $a);
397 my @b = split(',', $b);
399 $a[$field] cmp $b[$field];
400 } split(':', $list)
404 $self->{funcs}->{reverse} = sub { join(':', reverse(split(':', $_[0]))); };
406 $self->{_abort} = 0;
407 $self->{_unresolved} = [];
409 # ensure 'abort-flag' and 'unresolved' point to
410 # appropriate holders
411 $self->{'abort-flag'} ||= \$self->{_abort};
412 $self->{unresolved} ||= \$self->{_unresolved};
414 # fix include-path
415 $self->{'include-path'} ||= [];
417 if (!ref($self->{'include-path'})) {
418 $self->{'include-path'} = [ split(/:/, $self->{'include-path'}) ];
421 return $self;
425 sub new {
426 my ($class, %params) = @_;
428 my $self = bless({ %params }, $class);
430 return $self->init();
435 __END__
436 =pod
438 =head1 NAME
440 Artemus4 - Template Toolkit
442 =head1 SYNOPSIS
444 use Artemus4;
446 # normal variables
447 %vars = (
448 "copyright" => 'Copyright 2002', # normal variable
449 "number" => 100, # another
450 "about" => '{-copyright} My Self', # can be nested
451 "link" => '<a href="$0">$1</a>' # can accept parameters
454 # functions as templates
455 %funcs = (
456 "rnd" => sub { int(rand(100)) }, # normal function
457 "sqrt" => sub { sqrt($_[0]) } # can accept parameters
460 # create a new Artemus4 instance
461 $ah = new Artemus4( "vars" => \%vars, "funcs" => \%funcs );
463 # do it
464 $out = $ah->process('Click on {-link|http://my.page|my page}, {-about}');
465 $out2 = $ah->process('The square root of {-number} is {-sqrt|{-number}}');
467 =head1 DESCRIPTION
469 Artemus4 is yet another template toolkit. Though it was designed
470 to preprocess HTML, it can be used for any task that involves
471 text substitution. These templates can be plain text, text with
472 parameters and hooks to real Perl code. This document describes
473 the Artemus4 markup as well as the API.
475 =for html <->
477 You can download the latest version of this package and get
478 more information from its home page at
480 http://triptico.com/software/artemus.html
482 =head1 THE ARTEMUS MARKUP
484 =head2 Simple templates
486 The simplest Artemus4 template is just a text substitution. If
487 you set the 'about' template to '(C) 2000/2002 My Self', you
488 can just write in your text
490 This software is {-about}.
492 and found it replaced by
494 This software is (C) 2000/2002 My Self.
496 Artemus4 templates can be nestable; so, if you set another
497 template, called 'copyright' and containing '(C) 2000/2002', you
498 can set 'about' to be '{-copyright} My Self', and obtain the
499 same result. Though they can be nested nearly ad-infinitum, making
500 circular references is unwise.
502 =head2 Templates with parameters
504 This wouldn't be any cool if templates where just text substitutions.
505 But you can create templates that accept parameters just by including
506 $0, $1, $2... marks inside its content. This marks will be replaced
507 by the parameters used when inserting the call.
509 So, if you create the 'link' template containing
511 <a href = "$0">$1</a>
513 you can insert the following call:
515 {-link|http://triptico.com|Angel Ortega's Home Page}
517 As you can see, you use the | character as a separator
518 among the parameters and the template name itself.
520 =head2 Perl functions as templates
522 Anything more complicated than this would require the definition
523 of special functions provided by you. To do it, you just add
524 templates to the 'funcs' hash reference when the Artemus4 object
525 is created which values are references to Perl functions. For
526 example, you can create a function returning a random value
527 by using:
529 $funcs{'rnd'} = sub { int(rand(100)) };
531 And each time the {-random} template is found, it is evaluated
532 and returns a random number between 0 and 99.
534 Functions also can accept parameters; so, if you define it as
536 $funcs{'rnd'} = sub { int(rand($_[0])) };
538 then calling the template as
540 {-rnd|500}
542 will return each time it's evaluated a random value between 0 and 499.
544 =head2 Aborting further execution from a function
546 If the I<abort-flag> argument is set to a scalar reference when creating
547 the Artemus4 object, template processing can be aborted by setting
548 this scalar to non-zero from inside a template function.
550 =head2 Caching templates
552 If a template is expensive or time consuming (probably because it
553 calls several template functions that take very much time), it can be
554 marked as cacheable. You must set the 'cache-path' argument for
555 this to work, and include the following special Artemus4 code
556 inside the template:
558 {-\CACHE|number}
560 where I<number> is a number of days (or fraction of day) the
561 cache will remain cached before being re-evaluated. Individual
562 template functions cannot be cached; you must wrap them in a
563 normal template if need it.
565 =head2 Documenting templates
567 Artemus4 templates can contain documentation in Perl's POD format.
568 This POD documentation is stripped each time the template is evaluated
569 unless you create the Artemus4 object with the I<contains-pod> argument
570 set.
572 See http://www.perldoc.com/perl5.8.0/pod/perlpod.html and
573 http://www.perldoc.com/perl5.8.0/pod/perlpodspec.html for information
574 about writing POD documentation.
576 =head2 Unresolved templates
578 If a template is not found, it will be replaced by its name (that is,
579 stripped out of the {- and } and left there). Also, the names of the
580 unresolved templates are appended to an array referenced by the
581 I<unresolved> argument, if one was defined when the Artemus4 object
582 was created.
584 =head2 Predefined templates
586 =over 4
588 =head3 if
590 {-if|condition|text}
591 {-if|condition|text_if_true|text_unless_true}
593 If I<condition> is true, this template returns I<text>, or nothing
594 otherwise; in the 3 argument version, returns I<text_if_true> or
595 I<text_unless_true>. A condition is true if is not zero or the empty
596 string (the same as in Perl).
598 =head3 ifelse
600 This is an alias for the I<if> template provided for backwards-compatibility.
601 Don't use it.
603 =head3 ifeq
605 {-ifeq|term1|term2|text}
606 {-ifeq|term1|term2|text_if_true|text_unless_true}
608 If I<term1> is equal to I<term2>, this template returns I<text>, or nothing
609 otherwise. in the 4 argument version, returns I<text_if_true> or
610 I<text_unless_true>.
612 =head3 ifneq
614 {-ifneq|term1|term2|text}
616 If I<term1> is not equal to I<term2>, this template returns I<text>, or
617 nothing otherwise.
619 =head3 ifeqelse
621 This is an alias for the I<ifeq> template provided for backwards-compatibility.
622 Don't use it.
624 =head3 add, sub
626 {-add|num1|num2}
627 {-sub|num1|num2}
629 This functions add or substract the values and returns the result.
631 =head3 gt, lt, eq
633 {-gt|value1|value2}
634 {-lt|value1|value2}
635 {-eq|value1|value2}
637 This functions compare if I<value1> is greater-than, lesser-than or equal to
638 I<value2>. Meant primarily to use with the I<if> template.
640 =head3 random
642 {-random|value1|value2|...}
644 This function returns randomly one of the values sent as arguments. There can
645 any number of arguments.
647 =head3 and
649 {-and|value_or_condition_1|value_or_condition_2}
651 If both values are true or defined, returns I<value_or_condition_2>; otherwise,
652 returns the empty string.
654 =head3 or
656 {-or|value_or_condition_1|value_or_condition_2}
658 If I<value_or_condition_1> is true or defined, returns it; otherwise, if
659 I<value_or_condition_2> is true or defined, returns it; otherwise, returns
660 the empty string.
662 =head3 not
664 {-not|condition}
666 Returns the negation of I<condition>.
668 =head3 set
670 {-set|template_name|value}
672 Assigns a value to a template. Same as setting a value from the 'vars'
673 argument to B<new>, but from Artemus4 code.
675 If you must change a variable from inside an I<if> directive, don't
676 forget to escape the I<set> directive, as in
678 {-ifeq|{-user}|admin|\{-set\|powers\|EVERYTHING\}}
680 IF you don't escape it, the I<powers> variable will be inevitably set
681 to EVERYTHING.
683 =head3 foreach
685 {-foreach|list:of:colon:separated:values|output_text|separator}
687 Iterates the list of colon separated values and returns I<output_text>
688 for each one of the values, separating each of them with I<separator>
689 (if one is defined). Each element itself can be a list of comma
690 separated values that will be split and assigned to the $0, $1... etc
691 parameters set to I<output_text>. For example, to create a I<select>
692 HTML tag:
694 <select name = 'work_days'>
695 {-foreach|Monday,1:Tuesday,2:Wednesday,3:Thursday,4:Friday,5|
696 <option value = '\$1'>\$0</option>
698 </select>
700 Remember to escape the dollar signs to avoid being expanded too early,
701 and if the I<output_text> include calls to other Artemus4 templates,
702 to escape them as well.
704 =head3 case
706 {-case|string|value_1|return_1|value_2|return_2|...}
707 {-case|string|value_1|return_1|value_2|return_2|...|default_value}
709 Compares I<string> against the list of I<value_1>, I<value_2>... and
710 returns the appropriate I<return_1>, I<return_2>... value. If I<default_value>
711 is set (that is, I<case> has an odd number of arguments) it's returned
712 if I<string> does not match any value.
714 =head3 env
716 {-env|environment_variable}
717 {-env}
719 If I<environment_variable> has a value set in the environment, it's returned,
720 or the empty string otherwise. If no environment variable is set, returns
721 a colon-separated list of environment variable names.
723 =head3 size
725 {-size|colon_separated_list}
727 Returns the number of elements in I<colon_separated_list>.
729 =head3 seq
731 {-seq|from_number|to_number}
733 Generates a colon-separated list of the numbers from I<from_number>
734 to I<to_number>. Useful in a I<foreach> loop.
736 =head3 sort
738 {-sort|list}
739 {-sort|list|field}
741 Sorts the colon-separated list. The optional I<field> is the field
742 to sort on (assuming the elements of the list are comma-separated
743 lists themselves).
745 =head3 reverse
747 {-reverse|list}
749 Reverses a colon-separated list.
751 =head3 \CACHE
753 {-\CACHE|time}
755 Marks a template as cacheable and sets its cache time. See above.
757 =head3 \VERSION
759 {-\VERSION}
761 Returns current Artemus4 version.
763 =head3 \BEGIN
765 =head3 \END
767 If you set these templates, they will be appended (\BEGIN) and
768 prepended (\END) to the text being processed.
770 =back
772 =head2 Escaping
774 Escaping has been briefly mentioned above; this is a way to avoid
775 prematurely expanding and executing Artemus4 templates, and a direct
776 derivative of the simple text substitution approach of the Artemus4
777 engine.
779 To escape an Artemus4 template call you must escape ALL characters
780 that has special meaning to the uber-simple Artemus4 parser (that is,
781 the opening and closing braces, the pipe argument separator and
782 the optional dollar prefixes for arguments). If you nest some
783 directives (for example, two I<foreach> calls), you must
784 double-escape everything. Yes, this can get really cumbersome.
786 =head1 FUNCTIONS AND METHODS
788 =cut
790 =head2 new
792 $ah = new Artemus4(
793 [ "vars" => \%variables, ]
794 [ "funcs" => \%functions, ]
795 [ "inv-vars" => \%inverse_variables, ]
796 [ "include-path" => \@dir_with_templates_in_files, ]
797 [ "loader_func" => \&template_loader_function, ]
798 [ "cache-path" => $dir_to_store_cached_templates, ]
799 [ "abort-flag" => \$abort_flag, ]
800 [ "unresolved" => \@unresolved_templates, ]
801 [ "use-cr-lf" => $boolean, ]
802 [ "contains-pod" => $boolean, ]
803 [ "paragraph-separator" => $separator, ]
804 [ "strip-html-comments" => $boolean, ]
805 [ "AUTOLOAD" => \&autoload_func ]
808 Creates a new Artemus4 object. The following arguments (passed to it
809 as a hash) can be used:
811 =over 4
813 =head3 vars
815 This argument must be a reference to a hash containing
816 I<template> - I<content> pairs.
818 =head3 funcs
820 This argument must be a reference to a hash containing
821 I<template name> - I<code reference> pairs. Each time one of these
822 templates is evaluated, the function will be called with
823 the template parameters passed as the function's arguments.
825 =head3 inv-vars
827 This argument must be a reference to a hash containing
828 I<text> - I<content> pairs. Any occurrence of I<text> will be
829 replaced by I<content>. They are called 'inverse variables'
830 because they use to store variables that expand to Artemus4
831 markup, but can contain anything. This is really a plain
832 text substitution, so use it with care (B<NOTE>: this
833 option is disabled by now until it works correctly).
835 =head3 include-path
837 This arrayref should contain directories where templates are
838 to be found.
840 =head3 loader_func
842 If this reference to code exists, it's called with the template
843 name as argument as a method to load templates from external
844 sources. The function should return the template content or
845 C<undef> if the template is not found. It's called after testing
846 for variables or functions and before trying to load from
847 the C<include-path>.
849 =head3 cache-path
851 If this string is set, it must contain the path to a readable
852 and writable directory where the cacheable templates are cached.
853 See L<Caching templates> for further information.
855 =head3 abort-flag
857 This argument must be a reference to a scalar. When the template
858 processing is started, this scalar is set to 0. Template functions
859 can set it to any other non-zero value to stop template processing.
861 =head3 unresolved
863 If this argument points to an array reference, it will be filled
864 with the name of any unresolved templates. Each time a template
865 processing is started, the array is emptied.
867 =head3 use-cr-lf
869 If this flag is set, all lines are separated using CR/LF instead
870 of just LF (useful to generate MSDOS/Windows compatible text files).
872 =head3 contains-pod
874 If this flag is set, the (possible) POD documentation inside the
875 templates are not stripped-out. Understand this flag as saying
876 'this template has pod as part of its content, so do not strip it'.
877 See L<Documenting templates>.
879 =head3 paragraph-separator
881 If this argument is set to some string, all empty lines will be
882 substituted by it (can be another Artemus4 template).
884 =head3 strip-html-comments
886 If this flag is set, HTML comments are stripped before any
887 processing.
889 =head3 AUTOLOAD
891 If this argument points to a sub reference, the subrutine will
892 be executed when a template is unresolved and its return value used
893 as the final substitution value. Similar to the AUTOLOAD function
894 in Perl standard modules. The unresolved template name will be
895 sent as the first argument.
897 =back
899 =head2 armor
901 $str = $ah->armor($str);
903 Translate Artemus4 markup to HTML entities, to avoid being
904 interpreted by the parser.
906 =head2 unarmor
908 $str = $ah->unarmor($str);
910 Translate back the Artemus4 markup from HTML entities. This
911 is the reverse operation of B<armor>.
913 =head2 strip
915 $str = $ah->strip($str);
917 Strips all Artemus4 markup from the string.
919 =head2 params
921 $str = $ah->params($str, @params);
923 Interpolates all $0, $1, $2... occurrences in the string into
924 the equivalent element from @params.
926 =head2 process
928 $str = $ah->process($str);
930 Processes the string, translating all Artemus4 markup. This
931 is the main template processing method. The I<abort-flag> flag and
932 I<unresolved> list are reset on each call to this method.
934 =head1 AUTHOR
936 Angel Ortega angel@triptico.com