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.
23 #####################################################################
32 $Artemus4::VERSION
= '4.1.3-dev';
39 $str =~ s/{/\{/g;
40 $str =~ s/\|/\|/g;
41 $str =~ s/}/\}/g;
42 $str =~ s/\$/\$/g;
43 # $str =~ s/=/\=/g;
55 $str =~ s/\{/{/g;
56 $str =~ s/\|/\|/g;
57 $str =~ s/\}/}/g;
58 $str =~ s/\$/\$/g;
59 # $str =~ s/\=/=/g;
69 $t =~ s/{-([-\\\w_ \.]+)[^{}]*}/$1/g;
82 $str =~ s/(^|[^\\])\$$n/$1$a/g;
86 $str =~ s/(^|[^\\])\$\d+/$1/g;
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;
116 $data =~ s/{%[^}]+}//g;
123 my ($ah, $data, $level, $template_name) = @_;
126 # test if the template includes cache info
127 if ($data =~ s/{-\\CACHE\W([^}]*)}//) {
128 if ($template_name and $ah->{'cache-path'}) {
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) {
139 $data = join('', <F
>);
147 # strip POD documentation, if any
148 if ($data =~ /=cut/ and not $ah->{'contains-pod'}) {
151 foreach (split("\n", $data)) {
152 unless (/^=/ .. /^=cut/) {
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) {
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;
192 while (length($params) && $params =~ s/^([^\|\\]*(\\.[^\|\\]*)*)\|?//s) {
202 if (defined $ah->{'vars'}->{$key}) {
203 $text = $ah->{'vars'}->{$key};
204 $text = $ah->params($text, @params);
208 elsif (defined $ah->{'funcs'}->{$key}) {
211 $func = $ah->{'funcs'}->{$key};
212 $text = $func->(@params);
214 # functions can abort further execution
216 if (${$ah->{'abort-flag'}}) {
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);
230 elsif ($ah->{'include-path'}) {
231 foreach my $p (@
{$ah->{'include-path'}}) {
232 if (open(INC
, "$p/$key")) {
233 $text = join('', <INC
>);
236 # cache it as a variable
237 $ah->{vars
}->{$key} = $text;
239 $text = $ah->params($text, @params);
248 push(@
{$ah->{'unresolved'}}, $found);
250 if (ref $ah->{'AUTOLOAD'}) {
251 $text = $ah->{'AUTOLOAD'}($found);
258 push(@
{$ah->{call_stack
}},
259 [ $key, $level, $found, $text ]
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
273 open F
, '>' . $ah->{'cache-path'} . '/' . $template_name;
287 $self->{vars
}->{'\n'} = "\n";
288 $self->{vars
}->{'\BEGIN'} ||= '';
289 $self->{vars
}->{'\END'} ||= '';
290 $self->{vars
}->{'\VERSION'} = $Artemus4::VERSION
;
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 {
315 my $code = shift || '$0';
316 my $sep = shift || '';
317 my $hdr = shift || '';
320 my @l = split(/\s*:\s*/, $list);
324 my @e = split(/\s*,\s*/, $l);
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
346 $o .= $self->params($code, @e);
351 return join($sep, @ret);
354 $self->{funcs
}->{set
} = sub { $self->{vars
}->{$_[0]} = $_[1]; return ''; };
356 $self->{funcs
}->{case
} = sub {
363 # if args are odd, the last one is
364 # the 'otherwise' case
365 if (scalar(@_) % 2) {
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 {
392 my $field = shift || 0;
396 my @a = split(',', $a);
397 my @b = split(',', $b);
399 $a[$field] cmp $b[$field];
404 $self->{funcs
}->{reverse} = sub { join(':', reverse(split(':', $_[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
};
415 $self->{'include-path'} ||= [];
417 if (!ref($self->{'include-path'})) {
418 $self->{'include-path'} = [ split(/:/, $self->{'include-path'}) ];
426 my ($class, %params) = @_;
428 my $self = bless({ %params }, $class);
430 return $self->init();
440 Artemus4 - Template Toolkit
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
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 );
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}}');
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.
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
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
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
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
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
584 =head2 Predefined templates
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).
600 This is an alias for the I<if> template provided for backwards-compatibility.
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
614 {-ifneq|term1|term2|text}
616 If I<term1> is not equal to I<term2>, this template returns I<text>, or
621 This is an alias for the I<ifeq> template provided for backwards-compatibility.
629 This functions add or substract the values and returns the result.
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.
642 {-random|value1|value2|...}
644 This function returns randomly one of the values sent as arguments. There can
645 any number of arguments.
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.
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
666 Returns the negation of I<condition>.
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
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>
694 <select name = 'work_days'>
695 {-foreach|Monday,1:Tuesday,2:Wednesday,3:Thursday,4:Friday,5|
696 <option value = '\$1'>\$0</option>
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.
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.
716 {-env|environment_variable}
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.
725 {-size|colon_separated_list}
727 Returns the number of elements in I<colon_separated_list>.
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.
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
749 Reverses a colon-separated list.
755 Marks a template as cacheable and sets its cache time. See above.
761 Returns current Artemus4 version.
767 If you set these templates, they will be appended (\BEGIN) and
768 prepended (\END) to the text being processed.
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
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
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:
815 This argument must be a reference to a hash containing
816 I<template> - I<content> pairs.
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.
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).
837 This arrayref should contain directories where templates are
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
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.
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.
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.
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).
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
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.
901 $str = $ah->armor($str);
903 Translate Artemus4 markup to HTML entities, to avoid being
904 interpreted by the parser.
908 $str = $ah->unarmor($str);
910 Translate back the Artemus4 markup from HTML entities. This
911 is the reverse operation of B<armor>.
915 $str = $ah->strip($str);
917 Strips all Artemus4 markup from the string.
921 $str = $ah->params($str, @params);
923 Interpolates all $0, $1, $2... occurrences in the string into
924 the equivalent element from @params.
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.
936 Angel Ortega angel@triptico.com