view release on metacpan or search on metacpan
Revision history for Perl extension HTML::Macro
1.00 Wed Jun 7 10:58:49 2000
- original version; created by h2xs 1.18
1.01 Wed Jun 27 10:56 2000
- got rid of quoted methods; now use single underscores for no quoting
1.03 Mon Jul 24 2000
- added <include> ; # as delimiter
1.04 Mon Jul 24 2000
- changed RE to not use $` in effort to be more efficient
1.10 Mon Sep 4 17:11:40 EDT 2000
- major change to parsing methodology in order to introduce <quote> and
generally simplify REs and ease porting
1.13 Fri Jun 29 2001
renamed to HTML::Macro (was IF::Page) prior to upload to CPAN.
No longer support '_' as macro delimiter.
1.14 Jan 2002
Added support for <if def>. Now setting '@precompile' to true inhibits
processing of tags without trailing underscore (<if_>, <loop_>,
etc.)
1.15 Wed Jan 16 2002
Added support for <eval> and <define>.
get now calls match_token.
Collapse_whitespace is now called when loading (caching) files, for
further optimization. This means interpolated values are no longer
collapsed; also any files read in by the user are not subject to
collapsing.
ColdFusion style quotes (<!--- ... --->) are now processed (by removing them).
The processing is done when a file is read.
New in 1.19; Various performance enhancements, including file caching.
Included files, and templates read by HTML::Macro::new and process are
cached in memory if the 'cache_files' attribute is true. This can improve
performance significantly if you include a file in a loop that is repeated
often. No attempt is made to detect when a file changes, so this cache is
unsuitable for use with mod_perl. I plan to add cache freshening at some
point for just this reason.
collapse_whitespace is now only called on the "final" pass of evaluation,
saving considerable work. Also, we attempt to make lighter use of cwd,
which turns out to be expensive in many OS implementations since it calls
`pwd`. I am considering a rewrite of the entire mechanism for walking
directories, but at least it runs reasonably fast now when you have a lot
of includes.
<eval/>: embedded perl evaluation
New in 1.15, the <eval expr=""></eval> construct evaluates its expression
attribute as Perl, in the package in which the HTML::Macro was created.
This is designed to allow you to call out to a perl function, not to embed
large blocks of code in the middle of your HTML, which we do not advocate.
The expression attribute is treated as a Perl block (enclosed in curly
braces) and passed a single argument: an HTML::Macro object whose content
is the markup between the <eval> and </eval> tags, and whose attributes are
inherited from the enclosing HTML::Macro. The return value of the
expression is interpolated into the output. A typical use might be:
Your user profile:
<eval expr="&get_user_info">
#FIRST_NAME# #LAST_NAME# <br>
#ADDRESS## #CITY# #STATE# <br>
</eval>
where get_user_info is a function defined in the package that called
HTML::Macro::process (or process_buf, or print...). Presumably get_user_info will look something like:
sub get_user_info
{
my ($htm) = @_;
my $id = $htm->get ('user_id');
... get database record for user with id $id ...;
$htm->set ('first_name', ...);
...;
return $htm->process;
}
<eval expr="&get_user_info(@_)">...
<define />
You can use the <define/> tag, as in:
<define/ name="variable_name" value="variable_value">
to define HTML::Macro tags during the course of processing. These
definitions are processed in the same macro evaluation pass as all the
other tags. Hence the defined variable is only in scope after the
definition, and any redefinition will override, in the way that you would
expect.
This feature is useful for passing arguments to functions called by eval.
New in version 1.14:
- The quote tag is now deprecated. In its place, you should use tags with
Loop/Loop.pm view on Meta::CPAN
# HTML::Macro::Loop; Loop.pm
# Copyright (c) 2001,2002 Michael Sokolov and Interactive Factory. All rights
# reserved. This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
package HTML::Macro::Loop;
use strict;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
require Exporter;
require AutoLoader;
@ISA = qw(Exporter AutoLoader);
# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
Loop/Loop.pm view on Meta::CPAN
{
my ($self, @vars) = @_;
@ {$$self {'vars'}} = @vars;
}
sub push_array ($@)
# values must be pushed in the same order as they were declared, and all
# must be present
{
my ($self, @vals) = @_;
die "HTML::Macro::Loop::push_array: number of vals pushed(" . (@vals+0) . ") does not match number declared: " . (@ {$$self{'vars'}} + 0)
if (@vals + 0 != @ {$$self{'vars'}});
my $row = &new_row;
my $i = 0;
foreach my $var (@ {$$self{'vars'}})
{
$row->set ($var, $vals[$i++]);
}
push @ {$$self{'rows'}}, $row;
}
sub new_row
{
my ($self) = @_;
my $row = new HTML::Macro;
$row->set ('@parent', $self);
$row->{'@attr'} = $self->{'@parent'}->{'@attr'};
$row->{'@incpath'} = $self->{'@parent'}->{'@incpath'};
return $row;
}
sub pushall_arrays ($@)
# values must be pushed in the same order as they were declared, and all
# must be present. Arg is an array filled with refs to arrays for each row
{
Loop/Loop.pm view on Meta::CPAN
my ($self, $var) = @_;
my $rows = $$self{'rows'};
if ($rows) {
my $row = $$rows[$#$rows];
return $row->get($var);
}
return undef;
}
sub doloop ($$$$ )
# perform repeated processing a-la HTML::Macro on the loop body $body,
# concatenate the results and return that.
{
my ($self, $body, $separator, $separator_final, $collapse) = @_;
my $buf = '';
my $markup_seen;
my @row_output;
foreach my $row (@ {$$self{'rows'}})
{
$row->{'@cwd'} = $self->{'@parent'}->{'@cwd'};
$row->{'@dynamic'} = $self->{'@dynamic'};
Loop/Loop.pm view on Meta::CPAN
return $buf;
}
sub new_loop ()
{
my ($self, $name, @loop_vars) = @_;
my $rows = $$self{'rows'};
die "HTML::Loop::new_loop: no rows in loop - call a push method" if !@$rows;
my $new_loop = new HTML::Macro::Loop ($$rows [$#$rows]);
if ($name) {
$self->set ($name, $new_loop);
}
if (@loop_vars) {
$new_loop->declare (@loop_vars);
}
return $new_loop;
}
Loop/Loop.pm view on Meta::CPAN
}
# Autoload methods go after =cut, and are processed by the autosplit program.
1;
__END__
# Below is the stub of documentation for your module. You better edit it!
=head1 NAME
HTML::Macro::Loop - looping construct for repeated HTML blocks
=head1 SYNOPSIS
use HTML::Macro;
use HTML::Macro::Loop;
$htm = HTML::Macro->new();
$loop = $htm->new_loop('loop-body', 'id', 'name', 'phone');
$loop->push_array (1, 'mike', '222-2389');
$loop->push_hash ({ 'id' => 2, 'name' => 'lou', 'phone' => '111-2389'});
$htm->print ('test.html');
=head1 DESCRIPTION
HTML::Macro::Loop processes tags like
<loop id="loop-tag"> loop body </loop>
Each loop body is treated as a nested HTML::Macro within which variable
substitutions, conditions and nested loops are processed as described under
HTML::Macro. For complete documentation see HTML::Macro.
=head1 AUTHOR
Michael Sokolov, sokolov@ifactory.com
=head1 SEE ALSO HTML::Macro
perl(1).
=cut
Loop/Makefile.PL view on Meta::CPAN
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
'NAME' => 'HTML::Macro::Loop',
'VERSION_FROM' => 'Loop.pm', # finds $VERSION
);
Loop/Makefile.old view on Meta::CPAN
# This Makefile is for the HTML::Macro::Loop extension to perl.
#
# It was generated automatically by MakeMaker version
# 6.30 (Revision: Revision: 4535 ) from the contents of
# Makefile.PL. Don't edit this file, edit Makefile.PL instead.
#
# ANY CHANGES MADE HERE WILL BE LOST!
#
# MakeMaker ARGV: ()
#
# MakeMaker Parameters:
# NAME => q[HTML::Macro::Loop]
# VERSION_FROM => q[Loop.pm]
# --- MakeMaker post_initialize section:
# --- MakeMaker const_config section:
# These definitions are from config.sh (via /usr/lib/perl5/5.8.8/i386-linux-thread-multi/Config.pm)
# They may have been overridden via Makefile.PL or on the command line
Loop/Makefile.old view on Meta::CPAN
EXE_EXT =
FULL_AR = /usr/bin/ar
VENDORARCHEXP = /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi
VENDORLIBEXP = /usr/lib/perl5/vendor_perl/5.8.8
# --- MakeMaker constants section:
AR_STATIC_ARGS = cr
DIRFILESEP = /
DFSEP = $(DIRFILESEP)
NAME = HTML::Macro::Loop
NAME_SYM = HTML_Macro_Loop
VERSION = 1.06
VERSION_MACRO = VERSION
VERSION_SYM = 1_06
DEFINE_VERSION = -D$(VERSION_MACRO)=\"$(VERSION)\"
XS_VERSION = 1.06
XS_VERSION_MACRO = XS_VERSION
XS_DEFINE_VERSION = -D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\"
INST_ARCHLIB = ../blib/arch
INST_SCRIPT = ../blib/script
INST_BIN = ../blib/bin
Loop/Makefile.old view on Meta::CPAN
PERM_RWX = 755
MAKEMAKER = /usr/lib/perl5/5.8.8/ExtUtils/MakeMaker.pm
MM_VERSION = 6.30
MM_REVISION = Revision: 4535
# FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle).
# BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle)
# PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar)
# DLBASE = Basename part of dynamic library. May be just equal BASEEXT.
FULLEXT = HTML/Macro/Loop
BASEEXT = Loop
PARENT_NAME = HTML::Macro
DLBASE = $(BASEEXT)
VERSION_FROM = Loop.pm
OBJECT =
LDFROM = $(OBJECT)
LINKTYPE = dynamic
BOOTDEP =
# Handy lists of source code files:
XS_FILES =
C_FILES =
O_FILES =
H_FILES =
MAN1PODS =
MAN3PODS = Loop.pm
# Where is the Config information that we are using/depend on
CONFIGDEP = $(PERL_ARCHLIB)$(DFSEP)Config.pm $(PERL_INC)$(DFSEP)config.h
# Where to build things
INST_LIBDIR = $(INST_LIB)/HTML/Macro
INST_ARCHLIBDIR = $(INST_ARCHLIB)/HTML/Macro
INST_AUTODIR = $(INST_LIB)/auto/$(FULLEXT)
INST_ARCHAUTODIR = $(INST_ARCHLIB)/auto/$(FULLEXT)
INST_STATIC =
INST_DYNAMIC =
INST_BOOT =
# Extra linker info
EXPORT_LIST =
PERL_ARCHIVE =
PERL_ARCHIVE_AFTER =
TO_INST_PM = Loop.pm
PM_TO_BLIB = Loop.pm \
$(INST_LIB)/HTML/Macro/Loop.pm
# --- MakeMaker platform_constants section:
MM_Unix_VERSION = 1.50
PERL_MALLOC_DEF = -DPERL_EXTMALLOC_DEF -Dmalloc=Perl_malloc -Dfree=Perl_mfree -Drealloc=Perl_realloc -Dcalloc=Perl_calloc
# --- MakeMaker tool_autosplit section:
# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto
AUTOSPLITFILE = $(ABSPERLRUN) -e 'use AutoSplit; autosplit($$ARGV[0], $$ARGV[1], 0, 1, 1)'
Loop/Makefile.old view on Meta::CPAN
# --- MakeMaker manifypods section:
POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--"
POD2MAN = $(POD2MAN_EXE)
manifypods : pure_all \
Loop.pm \
Loop.pm
$(NOECHO) $(POD2MAN) --section=3 --perm_rw=$(PERM_RW) \
Loop.pm $(INST_MAN3DIR)/HTML::Macro::Loop.$(MAN3EXT)
# --- MakeMaker processPL section:
# --- MakeMaker installbin section:
Loop/Makefile.old view on Meta::CPAN
$(MAKEFILE_OLD) $(FIRST_MAKEFILE)
- $(RM_RF) \
$(DISTVNAME)
# --- MakeMaker metafile section:
metafile : create_distdir
$(NOECHO) $(ECHO) Generating META.yml
$(NOECHO) $(ECHO) '# http://module-build.sourceforge.net/META-spec.html' > META_new.yml
$(NOECHO) $(ECHO) '#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#' >> META_new.yml
$(NOECHO) $(ECHO) 'name: HTML-Macro-Loop' >> META_new.yml
$(NOECHO) $(ECHO) 'version: 1.06' >> META_new.yml
$(NOECHO) $(ECHO) 'version_from: Loop.pm' >> META_new.yml
$(NOECHO) $(ECHO) 'installdirs: site' >> META_new.yml
$(NOECHO) $(ECHO) 'requires:' >> META_new.yml
$(NOECHO) $(ECHO) '' >> META_new.yml
$(NOECHO) $(ECHO) 'distribution_type: module' >> META_new.yml
$(NOECHO) $(ECHO) 'generated_by: ExtUtils::MakeMaker version 6.30' >> META_new.yml
-$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml
Loop/Makefile.old view on Meta::CPAN
$(NOECHO) $(ECHO) ' <ARCHITECTURE NAME="i386-linux-thread-multi" />' >> $(DISTNAME).ppd
$(NOECHO) $(ECHO) ' <CODEBASE HREF="" />' >> $(DISTNAME).ppd
$(NOECHO) $(ECHO) ' </IMPLEMENTATION>' >> $(DISTNAME).ppd
$(NOECHO) $(ECHO) '</SOFTPKG>' >> $(DISTNAME).ppd
# --- MakeMaker pm_to_blib section:
pm_to_blib : $(TO_INST_PM)
$(NOECHO) $(ABSPERLRUN) -MExtUtils::Install -e 'pm_to_blib({@ARGV}, '\''$(INST_LIB)/auto'\'', '\''$(PM_FILTER)'\'')' \
Loop.pm $(INST_LIB)/HTML/Macro/Loop.pm
$(NOECHO) $(TOUCH) pm_to_blib
# --- MakeMaker selfdocument section:
# --- MakeMaker postamble section:
# End.
Loop/test.pl view on Meta::CPAN
# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl test.pl'
######################### We start with some black magic to print on failure.
# Change 1..1 below to 1..last_test_to_print .
# (It may become useful if the test is moved to ./t subdirectory.)
BEGIN { $| = 1; print "1..5\n"; }
END {print "not ok 1\n" unless $loaded;}
use HTML::Macro;
use HTML::Macro::Loop;
$loaded = 1;
print "ok 1\n";
######################### End of black magic.
# Insert your test code below (better if it prints "ok 13"
# (correspondingly "not ok 13") depending on the success of chunk 13
# of the test code):
$htm = HTML::Macro->new();
my $loop = $htm->new_loop ('loop', 'value');
$loop->push_array (1);
$loop->push_array (2);
$result = $htm->process ('test.html');
if ($result eq "1_name2_name\n1: <loop id=\"quoted\">#VALUE#</loop>\n2: <loop id=\"quoted\">#VALUE#</loop>\n")
{
print "ok 2\n";
} else
{
print "not ok 2: $result\n";
}
$htm = HTML::Macro->new();
my $outer = $htm->new_loop ('outer', 'i');
$outer->push_hash ({'i' => 1});
my $inner = $outer->new_loop ('inner', 'j');
$inner->push_array (1);
$inner->push_array (2);
$outer->push_hash ({'i' => 2});
$inner = $outer->new_loop ('inner', 'j');
$inner->push_array (1);
$inner->push_array (2);
$result = $htm->process ('test2.html');
if ($result eq '(1,1,9)(1,2,9)(2,1,9)(2,2,9)')
{
print "ok 3\n";
} else
{
print "not ok 3: $result\n";
}
$htm = HTML::Macro->new();
$htm->set ('outer', 1);
my $testloop = $htm->new_loop ('testloop', 'val');
$testloop->push_array ('x');
$result = $htm->process ('test3.html');
if ($result eq '0x1') {
print "ok 3a\n";
} else {
print "not ok 3a: $result\nshould be 0x1\n";
}
$htm = HTML::Macro->new();
$htm->set ('quoteme', 1);
$testloop = $htm->new_loop ('testloop', 'dummy');
$testloop->push_hash ({'dummy' => 1});
$result = $htm->process ('test4.html');
if ($result eq "\n <quote preserve=\"#QUOTEME#\">\n <quote><if expr=\"0\">0</if></quote>\n </quote>\n\n")
{
print "ok 4\n";
} else
{
print "not ok 4: $result\nshould be:";
print "\n <quote preserve=\"#QUOTEME#\">\n <quote><if expr=\"0\">0</if></quote>\n </quote>\n\n";
}
$htm = new HTML::Macro;
$htm->set ('@precompile', 1);
$testloop = $htm->new_loop ('testloop', 'dummy');
$testloop->push_hash ({'dummy' => 1});
$result = $htm->process ('test5.html');
if ($result eq '<if expr="0">don\'t evaluate me</if>')
{
print "ok 5\n";
} else
{
print "not ok 5: $result\nshould be:";
print '<if expr="0">don\'t evaluate me</if>';
print "\ngot: $result\n";
}
# test two orthogonal loops, one nested inside the other
$htm = HTML::Macro->new();
my $outer = $htm->new_loop ('outer', 'i');
$outer->push_hash ({'i' => 1});
$outer->push_hash ({'i' => 2});
my $inner = $htm->new_loop ('inner', 'j');
$inner->push_array (1);
$inner->push_array (2);
$result = $htm->process ('test2.html');
if ($result eq '(1,1,9)(1,2,9)(2,1,9)(2,2,9)')
{
print "ok 6\n";
} else
{
print "not ok 6: $result\n";
}
# test separators
$htm = HTML::Macro->new();
my $loop = $htm->new_loop ('loop', 'x');
$loop->push_array ('a');
$loop->push_array ('b');
$loop->push_array ('c');
$result = $htm->process ('test7.html');
if ($result eq 'a, b and c')
{
print "ok 7\n";
} else
{
README
Changes
MANIFEST
Makefile.PL
Macro.pm
test.pl
# HTML::Macro; Macro.pm
# Copyright (c) 2001,2002 Michael Sokolov and Interactive Factory. Some rights
# reserved. This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
package HTML::Macro;
use strict;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %file_cache %expr_cache);
require Exporter;
require AutoLoader;
@ISA = qw(Exporter AutoLoader);
# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.
@EXPORT = qw(
);
$VERSION = '1.29';
# Preloaded methods go here.
use HTML::Macro::Loop;
use Cwd;
# Autoload methods go after =cut, and are processed by the autosplit program.
# don't worry about hi-bit characters
my %char2htmlentity =
(
'&' => '&',
'>' => '>',
'<' => '<',
$$pbuf =~ s/<!---.*?--->//sg;
# These will be valid XML:
$$pbuf =~ s/<!--#.*?#-->//sg;
}
sub doloop ($$)
{
my ($self, $loop_id, $loop_body, $element) = @_;
if ($self->{'@attr'}->{'debug'}) {
print STDERR "HTML::Macro: processing loop $loop_id\n";
}
my $p = $self;
my $loop;
while ($p) {
$loop = $$p{$loop_id};
last if $loop;
# look for loops in outer scopes
$p = $p->{'@parent'};
last if !$p;
if ($p->isa('HTML::Macro::Loop'))
{
$p = $p->{'@parent'};
die if ! $p;
}
}
if (! $loop ) {
$self->warning ("no match for loop id=$loop_id");
return '';
}
if (!ref $loop || ! $loop->isa('HTML::Macro::Loop'))
{
$self->error ("doloop: $loop (substitution for loop id \"$loop_id\") is not a HTML::Macro::Loop!");
}
my $separator;
if ($element =~ /\bseparator="([^\"]*)"/ ||
$element =~ /\bseparator=(\S+)/)
{
$separator = $1;
}
my $separator_final;
if ($element =~ /\bseparator_final="([^\"]*)"/ ||
$element =~ /\bseparator_final=(\S+)/)
$loop->{'@dynamic'} = $self; # allow dynamic scoping of macros !
$loop_body = $loop->doloop ($loop_body, $separator, $separator_final, $collapse);
#$loop_body = $self->dosub ($loop_body);
return $loop_body;
}
sub doeval ($$)
{
my ($self, $attr, $attrval, $body) = @_;
if ($self->{'@attr'}->{'debug'}) {
print STDERR "HTML::Macro: processing eval: { $attr $attrval }\n";
}
my $htm;
if ($body) {
$htm = new HTML::Macro;
$htm->{'@parent'} = $self;
$htm->{'@body'} = $body;
my @incpath = @ {$self->{'@incpath'}};
$htm->{'@incpath'} = \@incpath; # make a copy of incpath
$htm->{'@attr'} = $self->{'@attr'};
$htm->{'@cwd'} = $self->{'@cwd'};
} else {
$htm = $self;
}
my $package = $self->{'@caller_package'};
: (exists $$hash{uc $key} ? (defined($$hash{uc $key}) ? $$hash{uc $key} : '')
: undef) );
return $val;
}
sub match_token ($$)
{
my ($self, $var) = @_;
if ($self->{'@attr'}->{'debug'}) {
print STDERR "HTML::Macro: matching token $var\n";
}
# these are the two styles we've used
my $val;
my $dynamic = $self->{'@dynamic'};
while ($self)
{
# ovalues is also used to store request variables so they override
# data fetched (later in the processing of a request) from the database
$val = &case_fold_match ($self->{'@ovalues'}, $var) if $self->{'@ovalues'};
$val = &case_fold_match ($self, $var) if ! defined ($val);
# we came from, and add the file's directory to incpath
{
my ($self, $path) = @_;
my @incpath = @ {$self->{'@incpath'}};
my $cwd = $self->{'@cwd'};
open (FILE, $path) || $self->error ("Cannot open '$path': $!");
if ($self->{'@attr'}->{'debug'}) {
print STDERR "HTML::Macro: opening $path, incpath=@incpath, cwd=$cwd";
}
$self->{'@file'} = $path;
# we will change directories so relative includes work
# remember where we are so we can get back here
push @ {$self->{'@cdpath'}}, $cwd;
my ($dir, $fname);
if ($path =~ m|(.*)/([^/])+$|) {
print "Cache-Control: no-cache\n";
print "Pragma: no-cache\n";
print "Content-Type: text/html\n\n";
print &process;
}
sub error
{
my ($self, $msg, $pos) = @_;
$self->get_caller_info if ! $self->{'@caller_package'};
$msg = "HTML::Macro: $msg\n";
$msg .= "parsing " . $self->{'@file'} if ($self->{'@file'});
#$msg .= " near char $pos" if $pos;
if ($pos) {
my $line = 1;
my $linepos = 0;
my $body = $$self{'@body'};
while ($body =~ /\n/sg && pos $body <= $pos) {
++$line;
$linepos = pos $body;
}
$msg .= " on line $line, char $charpos\n\n";
$msg .= substr($body, $linepos, ((pos $body) - $linepos));
}
die "$msg\ncalled from " . $self->{'@caller_file'} . ", line " . $self->{'@caller_line'} . "\n";
}
sub warning
{
my ($self, $msg, $pos) = @_;
$self->get_caller_info if ! $self->{'@caller_package'};
$msg = "HTML::Macro: $msg";
$msg .= " parsing " . $self->{'@file'} if ($self->{'@file'});
if ($pos) {
my $line = 1;
my $linepos = 0;
my $body = $$self{'@body'};
while ($body =~ /\n/sg && pos $body <= $pos) {
++$line;
$linepos = pos $body;
}
my $charpos = ($pos - $linepos);
shift;
}
warn "odd number of arguments to set" if @_;
}
sub parent ($$)
{
my $self = shift;
$self = $self->{'@parent'};
return undef if !$self;
# parent may be either an HTML::Macro or an HTML::Macro::Loop
if ($self->isa('HTML::Macro::Loop'))
{
$self = $self->{'@parent'};
if ( ! $self ) {
warn "found an orphaned HTML::Macro::Loop" ;
return undef;
}
}
return $self;
}
sub top ($$)
{
my $self = shift;
my $parent;
sub get_caller_info ($ )
{
my ($self) = @_;
my ($caller_file, $caller_line);
my $stack_count = 0;
my $pkg;
do {
($pkg, $caller_file, $caller_line) = caller ($stack_count++);
}
# ignore HTML::Macro and HTML::Macro::Loop
while ($pkg =~ /HTML::Macro/);
$self->{'@caller_package'} = $pkg;
$self->{'@caller_file'} = $caller_file;
$self->{'@caller_line'} = $caller_line;
}
sub new ($$$ )
{
my ($class, $fname, $attr) = @_;
my $self = { };
bless $self, $class;
$$self{'@body'} = &readfile($self, $fname) if ($fname);
return $self;
}
sub new_loop ()
{
my ($self, $name, @loop_vars) = @_;
my $new_loop = HTML::Macro::Loop->new($self);
if ($name) {
$self->set ($name, $new_loop);
if (@loop_vars) {
$new_loop->declare (@loop_vars);
}
}
return $new_loop;
}
sub keys ()
push @keys, keys % {$self->{'@ovalues'}} if $self->{'@ovalues'};
push @keys, $self->parent()->keys() if $self->parent();
return @keys;
}
1;
__END__
=head1 NAME
HTML::Macro - process HTML templates with loops, conditionals, macros and more!
=head1 SYNOPSIS
use HTML::Macro;
$htm = new HTML::Macro ('template.html');
$htm->print;
sub myfunc {
$htm->declare ('var', 'missing');
$htm->set ('var', 'value');
return $htm->process;
}
( in template.html ):
<if def="missing">
Message about missing stuff...
<else />
Var's value is #var#.
</if>
</eval>
</body></html>
=head1 DESCRIPTION
HTML::Macro is a module to be used behind a web server (in CGI scripts). It
provides a convenient mechanism for generating HTML pages by combining
"dynamic" data derived from a database or other computation with HTML
templates that represent fixed or "static" content of a page.
There are many different ways to accomplish what HTML::Macro does,
including ASP, embedded perl, CFML, etc, etc. The motivation behind
HTML::Macro is to keep everything that a graphic designer wants to play
with *in a single HTML template*, and to keep as much as possible of what a
perl programmer wants to play with *in a perl file*. Our thinking is that
there are two basically dissimilar tasks involved in producing a dynamic
web page: graphic design and programming. Even if one person is responsible
for both tasks, it is useful to separate them in order to aid clear
thinking and organized work. I guess you could say the main motivation for
this separation is to make it easier for emacs (and other text processors,
including humans) to parse your files: it's yucky to have a lot of HTML in
a string in your perl file, and it's yucky to have perl embedded in a
special tag in an HTML file.
HTML::Macro began with some simple programming constructs: macro
expansions, include files, conditionals, loops and block quotes. Since
then we've added very little: only a define tag to allow setting values and
an eval tag to allow perl function calls in a nested macro scope. Our
creed is "less is more, more or less."
HTML::Macro variables will look familiar to C preprocessor users or
especially to Cold Fusion people. They are always surrounded with single
or double hash marks: "#" or "##". Variables surrounded by double hash
marks are subject to html entity encoding; variables with single hash marks
are substituted "as is" (like single quotes in perl or UNIX shells).
Conditionals are denoted by the <if> and <else> tags, and loops by the
<loop> tag. Quoting used to be done using a <quote> tag, but we now
deprecate that in favor of the more familiar CFML quoting syntax: <!---
--->.
=head1 Basic Usage:
Create a new HTML::Macro:
$htm = new HTML::Macro ('templates/page_template.html', { 'collapse_whitespace' => 1 });
The first (filename) argument is optional. If you do not specify it now,
you can do it later, which might be useful if you want to use this
HTML::Macro to operate on more than one template. If you do specify the
template when the object is created, the file is read in to memory at that
time.
The second (attribute hash) argument is also optional, but you have to set
it now if you want to set attributes. See Attributes below for a list of
attributes you can set.
Optionally, declare the names of all the variables that will be substituted
on this page. This has the effect of defining the value '' for all these
variables.
$htm->declare ('var', 'missing');
Set the values of one or more variables using HTML::Macro::set.
$htm->set ('var', 'value', 'var2', 'value2');
Note: variable names beginning with an '@' are reserved for internal use.
Get previously-set values using get:
$htm->get ('var'); # returns 'value'
$htm->get ('blah'); # returns undefined
get also returns values from enclosing scopes (see Scope below).
$htm->keys() returns a list of all defined macro names.
Or use HTML::Macro::set_hash to set a whole bunch of values at once. Typically
used with the value returned from a DBI::fetchrow_hashref.
$htm->set_hash ( {'var' => 'value', 'var2' => 'value2' } );
Finally, process the template and print the result using HTML::Macro::print,
or save the value return by HTML::Macro::process.
open CACHED_PAGE, '>page.html';
print CACHED_PAGE, $htm->process;
# or: print CACHED_PAGE, $htm->process ('templates/page_template.html');
close CACHED_PAGE;
- or in some contexts simply:
$htm->print;
or
$htm->print ('test.html');
However note this would not be useful for printing a cached page since
as a convenience for use in web applications HTML::Macro::print prints
some HTTP headers prior to printing the page itself as returned by
HTML::Macro::process.
=head1 Macro Expansion
HTML::Macro::process attempts to perform a substitution on any word
beginning and ending with single or double hashmarks (#) , such as
##NAME##. A word is any sequence of alphanumerics and underscores. If the
HTML::Macro has a matching variable, its value is substituted for the word
in the template everywhere it appears. A matching variable is determined
based on a case-folding match with precedence as follows: exact match,
lower case match, upper case match. HTML::Macro macro names are case
sensitive in the sense that you may define distinct macros whose names
differ only by case. However, matching is case-insensitive and follows the
above precedence rules. So :
$htm->set ('Name', 'Mike', 'NAME', 'MIKE', 'name', 'mike');
results in the following substitutions:
Name => Mike
NAME => MIKE
If no value is found for a macro name, no substitution is performed, and
this is not treated as an error. This allows templates to be processed in
more than one pass. Possibly it would be useful to be able to request
notification if any variables are not matched, or to request unmatched
variables be mapped to an empty string. However the convenience seems to
be outweighed by the benefit of consistency since it easy to get confused
if things like undefined variables are handled differently at different
times.
A typical usage is to stuff all the values returned from
DBI::fetchrow_hashref into an HTML::Macro. Then SQL column names are to be
mapped to template variables. Databases have different case conventions
for column names; providing the case insensitivity and stripping the
underscores allows templates to be written in a portable fashion while
preserving an upper-case convention for template variables.
=head2 HTML entity quoting
Variables surrounded by double delimiters (##) are subject to HTML entity
encoding. That is, >, <, & and "" occuring in the variables value are
replaced by their corresponding HTML entities. Variables surrounded by
second block (or nothing if there is no else clause) if the expressin is
false.
Conditional expressions are subject to variable substitution, allowing for
constructs such as:
You have #NUM_ITEMS# item<if "#NUM_THINGS# > 1">s</if> in your basket.
=head2 ifdef
HTML::Macro also provides the <if def="variable-name"> conditional. This
construct evaluates to true if variable-name is defined and has a true
value. It might have been better to name this something different like <if
set="variable"> ? Sometimes there is a need for if (defined (variable)) in
the perl sense. Also we occasionally want <if ndef="var"> but just use <if
def="var"><else/> instead which seems adequate if a little clumsy.
=head1 File Interpolation
It is often helpful to structure HTML by separating commonly-used chunks
(headers, footers, etc) into separate files. HTML::Macro provides the
<include /> tag for this purpose. Markup such as <include file="file.html"
/> gets replaced by the contents of file.html, which is itself subject to
evaluation by HTML::Macro. If the "asis" attribute is present: <include/
file="quoteme.html" asis>, the file is included "as is"; without any
further evaluation.
HTML::Macro also supports an include path. This allows common "part" files
to be placed in a single central directory. HTML::Macro::push_incpath adds
to the path, as in $htm->push_incpath ("/path/to/include/files"). The
current directory (of the file being processed) is always checked first,
followed by each directory on the incpath. When paths are added to the
incpath they are always converted to absolute paths, relative to the
working directory of the invoking script. Thus, if your script is running
in "/cgi-bin" and calls push_incpath("include"), this adds
"/cgi-bin/include" to the incpath. (Note that HTML::Macro never calls chdir
as part of an effort to be thread-safe).
Also note that during the processing of an included file, the folder in
which the included file resides is pushed on to the incpath. This means
that relative includes work as you would expect in included files; a file
found in a directory relative to the included file takes precedence over
one found in a directory relative to the including file (or HTML::Macros
global incpath).
=head1 Loops
The <loop> tag and the corresponding HTML::Macro::Loop object provide
for repeated blocks of HTML, with subsequent iterations evaluated in
different contexts. Typically you will want to select rows from a database
(lines from a file, files from a directory, etc), and present each
iteration in succession using identical markup. You do this by creating a
<loop> tag in your template file containing the markup to be repeated, and
by creating a correspondingly named Loop object attached to the HTML::Macro
and containing all the data to be interpolated. Note: this requires all
data to be fetched and stored before it is applied to the template; there
is no facility for streaming data. For the intended use this is not a
problem. However it militates against using HTML::Macro for text
processing of very large datasets.
<loop id="people">
<tr><td>#first_name# #last_name#</td><td>#email#</td></tr>
</loop>
The loop tag allows the single attribute "id" which can be any
identifier. Loop tags may be nested. If during processing no matching
loop object is found, a warning is produced and the tag is simply
ignored.
$htm = new HTML::Macro;
$loop = $htm->new_loop('people', 'id', 'first_name', 'last_name', 'email');
$loop->push_array (1, 'frank', 'jones', 'frank@hotmail.com');
Create a loop object using HTML::Macro::new_loop (or
HTML::Macro::Loop::new_loop for a nested loop). The first argument is
the id of the loop and must match the id attribute of a tag in the
template (the match is case sensitive). The remaining arguments are the
names of loop variables.
Append loop iterations (rows) by calling push_array with an array of
values corresponding to the loop variables declared when the loop was
created.
An alternative is to use push_hash, which is analogous to
HTML::Macro::set_hash; it sets up multiple variable substitutions. If you
use push_hash you don't have to declare the names of the variables when you
create the loop object. This allows them to be taken out of a hash and
bound late, for example by names returned in a database query.
pushall_arrays is a shortcut that allows a number of loop iterations to
be pushed at once. It is typically used in conjunction with
DBI::selectall_arrayref.
is_empty returns a true value iff the loop has at least one row.
keys returns a list of variable names defined in the (last row of the)
loop.
=head1 Eval
<eval expr="perl expression"> ... </eval>
You can evaluate arbitrary perl expressions (as long as you can place
them in an XML attribute between double quotes!). The expression is
subject to macro substition, placed in a block and invoked as an
anonymous function whose single argument is an HTML::Macro object
representing the nested scope. Any values set in the perl expression
thus affect the markup inside the eval tag. The perl is evaluated after
setting the package to the HTML::Macro caller's package.
Note: typically we only use this to make a function call, and it would
probably be more efficient to optimize for that case - look for the
special case <eval function=""> to be implemented soon. Also we might
like to provide a singleton eval that would operate in the current scope:
<eval function="perl_function" />.
=head1 Scope
=head1 Quoting
For inserting block quotes in your markup that will be completely removed
during macro processing, use <!--- --->.
Also note that all macro and tag processing can be inhibited by the use of
the "<quote>" tag. Any markup enclosed by <quote> ... </quote> is passed
on as-is. However please don't rely on this as it is not all that useful
and may go away. The only real use for this was to support a
pre-processing phase that could generate templates. A new feature supports
this better: any of the HTML::Macro tags may be written with a trailing
underscore, as in <if_ expr="..."> ... </if_>. Tags such as this are
processed only if the preference variable '@precompile' is set, in which
case unadorned tags are ignored.
=head1 Attributes
These are user-controllable attributes that affect the operation of
HTML::Macro in one way or another.
=head3 debug
Set to a true value, produces various diagnostic information on STDERR. Default is false.
=head3 precompile
If set, (only) tags with trailing underscores will be processed. Default is false.
=head3 collapse_whitespace, collapse_blanklines
situations in which the same file is read repeatedly during the processing
of a single template. This definitely helped in a scenario involving an
include in side a loop, but it's not immediately clear why given that the
operating system is probably caching recently-read files in memory anyway.
The cache checks file modification times and reloads when a file changes.
There is currently no limit to file cache size, which should definitely get
changed.
=head1 Idiosyncracies
For hysterical reasons HTML::Macro allows a certain kind of non-XML; singleton tags are allowed to be written with the trailing slash immediately following the tag and separated from the closing > by white space. EG:
<include/ file="foo"> is OK
whereas XML calls for
<include file="foo" /> (which is also allowed here).
HTML::Macro is copyright (c) 2000-2004 by Michael Sokolov and Interactive
Factory (sm). Some rights may be reserved. This program is free software;
you can redistribute it and/or modify it under the same terms as Perl
itself.
=head1 AUTHOR
Michael Sokolov, sokolov@ifactory.com
=head1 SEE ALSO HTML::Macro::Loop
perl(1).
=cut
Makefile.PL view on Meta::CPAN
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
'NAME' => 'HTML::Macro',
'VERSION_FROM' => 'Macro.pm', # finds $VERSION
);
Makefile.old view on Meta::CPAN
# This Makefile is for the HTML::Macro extension to perl.
#
# It was generated automatically by MakeMaker version
# 6.30 (Revision: Revision: 4535 ) from the contents of
# Makefile.PL. Don't edit this file, edit Makefile.PL instead.
#
# ANY CHANGES MADE HERE WILL BE LOST!
#
# MakeMaker ARGV: ()
#
# MakeMaker Parameters:
# NAME => q[HTML::Macro]
# VERSION_FROM => q[Macro.pm]
# --- MakeMaker post_initialize section:
# --- MakeMaker const_config section:
# These definitions are from config.sh (via /usr/lib/perl5/5.8.8/i386-linux-thread-multi/Config.pm)
# They may have been overridden via Makefile.PL or on the command line
AR = ar
Makefile.old view on Meta::CPAN
EXE_EXT =
FULL_AR = /usr/bin/ar
VENDORARCHEXP = /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi
VENDORLIBEXP = /usr/lib/perl5/vendor_perl/5.8.8
# --- MakeMaker constants section:
AR_STATIC_ARGS = cr
DIRFILESEP = /
DFSEP = $(DIRFILESEP)
NAME = HTML::Macro
NAME_SYM = HTML_Macro
VERSION = 1.29
VERSION_MACRO = VERSION
VERSION_SYM = 1_29
DEFINE_VERSION = -D$(VERSION_MACRO)=\"$(VERSION)\"
XS_VERSION = 1.29
XS_VERSION_MACRO = XS_VERSION
XS_DEFINE_VERSION = -D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\"
INST_ARCHLIB = blib/arch
INST_SCRIPT = blib/script
INST_BIN = blib/bin
Makefile.old view on Meta::CPAN
PERM_RWX = 755
MAKEMAKER = /usr/lib/perl5/5.8.8/ExtUtils/MakeMaker.pm
MM_VERSION = 6.30
MM_REVISION = Revision: 4535
# FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle).
# BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle)
# PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar)
# DLBASE = Basename part of dynamic library. May be just equal BASEEXT.
FULLEXT = HTML/Macro
BASEEXT = Macro
PARENT_NAME = HTML
DLBASE = $(BASEEXT)
VERSION_FROM = Macro.pm
OBJECT =
LDFROM = $(OBJECT)
LINKTYPE = dynamic
BOOTDEP =
# Handy lists of source code files:
XS_FILES =
C_FILES =
O_FILES =
H_FILES =
MAN1PODS =
MAN3PODS = Macro.pm
# Where is the Config information that we are using/depend on
CONFIGDEP = $(PERL_ARCHLIB)$(DFSEP)Config.pm $(PERL_INC)$(DFSEP)config.h
# Where to build things
INST_LIBDIR = $(INST_LIB)/HTML
INST_ARCHLIBDIR = $(INST_ARCHLIB)/HTML
INST_AUTODIR = $(INST_LIB)/auto/$(FULLEXT)
INST_ARCHAUTODIR = $(INST_ARCHLIB)/auto/$(FULLEXT)
Makefile.old view on Meta::CPAN
INST_STATIC =
INST_DYNAMIC =
INST_BOOT =
# Extra linker info
EXPORT_LIST =
PERL_ARCHIVE =
PERL_ARCHIVE_AFTER =
TO_INST_PM = Macro.pm
PM_TO_BLIB = Macro.pm \
$(INST_LIB)/HTML/Macro.pm
# --- MakeMaker platform_constants section:
MM_Unix_VERSION = 1.50
PERL_MALLOC_DEF = -DPERL_EXTMALLOC_DEF -Dmalloc=Perl_malloc -Dfree=Perl_mfree -Drealloc=Perl_realloc -Dcalloc=Perl_calloc
# --- MakeMaker tool_autosplit section:
# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto
AUTOSPLITFILE = $(ABSPERLRUN) -e 'use AutoSplit; autosplit($$ARGV[0], $$ARGV[1], 0, 1, 1)'
Makefile.old view on Meta::CPAN
COMPRESS = gzip --best
SUFFIX = .gz
SHAR = shar
PREOP = $(NOECHO) $(NOOP)
POSTOP = $(NOECHO) $(NOOP)
TO_UNIX = $(NOECHO) $(NOOP)
CI = ci -u
RCS_LABEL = rcs -Nv$(VERSION_SYM): -q
DIST_CP = best
DIST_DEFAULT = tardist
DISTNAME = HTML-Macro
DISTVNAME = HTML-Macro-1.29
# --- MakeMaker macro section:
# --- MakeMaker depend section:
# --- MakeMaker cflags section:
Makefile.old view on Meta::CPAN
# --- MakeMaker static_lib section:
# --- MakeMaker manifypods section:
POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--"
POD2MAN = $(POD2MAN_EXE)
manifypods : pure_all \
Macro.pm \
Macro.pm
$(NOECHO) $(POD2MAN) --section=3 --perm_rw=$(PERM_RW) \
Macro.pm $(INST_MAN3DIR)/HTML::Macro.$(MAN3EXT)
# --- MakeMaker processPL section:
# --- MakeMaker installbin section:
Makefile.old view on Meta::CPAN
$(MAKEFILE_OLD) $(FIRST_MAKEFILE)
- $(RM_RF) \
$(DISTVNAME)
# --- MakeMaker metafile section:
metafile : create_distdir
$(NOECHO) $(ECHO) Generating META.yml
$(NOECHO) $(ECHO) '# http://module-build.sourceforge.net/META-spec.html' > META_new.yml
$(NOECHO) $(ECHO) '#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#' >> META_new.yml
$(NOECHO) $(ECHO) 'name: HTML-Macro' >> META_new.yml
$(NOECHO) $(ECHO) 'version: 1.29' >> META_new.yml
$(NOECHO) $(ECHO) 'version_from: Macro.pm' >> META_new.yml
$(NOECHO) $(ECHO) 'installdirs: site' >> META_new.yml
$(NOECHO) $(ECHO) 'requires:' >> META_new.yml
$(NOECHO) $(ECHO) '' >> META_new.yml
$(NOECHO) $(ECHO) 'distribution_type: module' >> META_new.yml
$(NOECHO) $(ECHO) 'generated_by: ExtUtils::MakeMaker version 6.30' >> META_new.yml
-$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml
# --- MakeMaker signature section:
signature :
Makefile.old view on Meta::CPAN
$(NOECHO) $(ECHO) ' <ARCHITECTURE NAME="i386-linux-thread-multi" />' >> $(DISTNAME).ppd
$(NOECHO) $(ECHO) ' <CODEBASE HREF="" />' >> $(DISTNAME).ppd
$(NOECHO) $(ECHO) ' </IMPLEMENTATION>' >> $(DISTNAME).ppd
$(NOECHO) $(ECHO) '</SOFTPKG>' >> $(DISTNAME).ppd
# --- MakeMaker pm_to_blib section:
pm_to_blib : $(TO_INST_PM)
$(NOECHO) $(ABSPERLRUN) -MExtUtils::Install -e 'pm_to_blib({@ARGV}, '\''$(INST_LIB)/auto'\'', '\''$(PM_FILTER)'\'')' \
Macro.pm $(INST_LIB)/HTML/Macro.pm
$(NOECHO) $(TOUCH) pm_to_blib
# --- MakeMaker selfdocument section:
# --- MakeMaker postamble section:
# End.
HTML::Macro is a macro preprocessor designed for generating web pages from
HTMLish templates augmented with a simple tagset (<if>,<else/>,<include/>,<loop>,<define>,<eval>).
HTML::Macro supports variable (macro) substitution, conditional evaluation
(using perl expressions), file interpolation (like SSI), looping for
repeated format blocks with varying data (like rows in a table), and
arbitrary evaluation of perl expressions while encouraging a natural
separation of form, code and content.
It is especially convenient for filling out data-driven web pages using
DBI. Its use is not restricted to HTML; we have also used it for
generating email and other text files, but the tagging syntax is derived
from HTML/XML.
Installation is totally vanilla; just unpack the distribution,
> tar xvfz HTML-Macro-1.xx.tgz
> cd HTML-Macro-1.xx
> perl Makefile.PL
> make install (prob. as root)
For more info, please see the written documentation:
> perldoc HTML::Macro
There is also a web page about HTML::Macro maintained at
http:://www.ifactory.com/htmlmacro.
Copyright (c) 2001-2004 Michael Sokolov and Interactive Factory.
Some rights reserved. This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl test.pl'
######################### We start with some black magic to print on failure.
# Change 1..1 below to 1..last_test_to_print .
# (It may become useful if the test is moved to ./t subdirectory.)
BEGIN { $| = 1; print "1..19\n"; }
END {print "not ok 1\n" unless $loaded;}
use HTML::Macro;
$loaded = 1;
print "ok 1\n";
######################### End of black magic.
# Insert your test code below (better if it prints "ok 13"
# (correspondingly "not ok 13") depending on the success of chunk 13
# of the test code):
$ifp = HTML::Macro->new();
$ifp->set ('@precompile', 1);
$result = $ifp->process ('test/test1.html');
if ($result eq '<if expr="0">ok</if>')
{
print "ok 1a\n";
} else
{
print "not ok 1a: $result\nshould be: <if expr=\"0\">ok</if>\n";
}
$ifp = HTML::Macro->new();
$ifp->declare ('var', 'missing', 'outer');
$ifp->set ('var', 'value');
$ifp->set ('qvar', '"<quote me>"');
$ifp->set ('var_var', 'value2');
$ifp->set ('var_UP', 'value3');
$result = $ifp->process ('test/test.html');
if ($result eq 'value "<quote me>" value2 value_x ##VAR_UP##')
{
print "ok 2\n";
} else
{
print "not ok 2: $result\n";
}
$ifp = HTML::Macro->new();
$ifp->set ('val', 1);
$result = $ifp->process ('test/test2.html');
if ($result eq "greater\ngreaterequal\ngreaterequal\ngreater\ngreater\ngreaterequal\ngreaterequal\ngreater\nok\n")
{
print "ok 3\n";
} else
{
print "not ok 3: $result\n";
}
$ifp = HTML::Macro->new();
$ifp->set ('val', 1);
$ifp->set ('yes', 1);
$result = $ifp->process ('test/test3.html');
if ($result eq "greater\nlessequal\n")
{
print "ok 4\n";
} else
{
print "not ok 4: $result\n";
}
$ifp = HTML::Macro->new();
$ifp->set ('pagenum', 2);
$ifp->set ('val', 2);
$result = $ifp->process ('test/test4.html');
if ($result eq "2greater\ngreaterequal\ngreaterequal\ngreater\ngreater\ngreaterequal\ngreaterequal\ngreater\nok\n\ngreater\ngreaterequal\ngreaterequal\ngreater\ngreater\ngreaterequal\ngreaterequal\ngreater\nok\n")
{
print "ok 5\n";
} else
{
print "not ok 5: $result\n";
}
$ifp = HTML::Macro->new();
$ifp->set ('pagenum', 2);
$ifp->set ('val', 2);
$result = $ifp->process ('test/test5.html');
if ($result eq '<include/ file="/etc/passwd"><if expr="##YES##">greater</if><quote preserve="1">output should have the quote tag in it</quote>#VAL#')
{
print "ok 6\n";
} else
{
print "not ok 6: $result\n";
}
$ifp = HTML::Macro->new();
$ifp->push_incpath ('test/include');
$result = $ifp->process ('test/test6.html');
if ($result eq 'included file stuff.htmlincluded file substuff.html 6a')
{
print "ok 7\n";
} else
{
print "not ok 7: $result\n";
}
if (grep /oval/, $ifp->keys()) {
print "ok 13\n";
} else {
print "not ok 13: keys does not contain oval\n";
}
eval {
$ifp->process ('test/test-error.txt');
};
if ($@ =~ qr{^HTML::Macro: error parsing 'if' attributes: blah
parsing .*test-error.txt on line 3, char 0
<if blah>; the error should be at char 0
called from test.pl, line }) {
print "ok 14\n";
} else {
print "not ok 14: error handler produced $@\n";
print "should be: ", q{HTML::Macro: error parsing 'if' attributes: blah
parsing .*/test-error.txt on line 3, char 0
<if blah>; the error should be at char 0
called from test.pl, line };
}
$ifp = new HTML::Macro;
$result = $ifp->process ('test/test-elsif.html');
if ($result ne "one\ntwo\nthree\nfour\n") {
print "not ok 15: test-elsif produced $result\n";
} else {
print "ok 15\n";
}
$ifp = new HTML::Macro;
$ifp->set ('yes', 1);
$result = $ifp->process ('test/test-def-global.html');
if ($result eq "greater\nlessequal\n")
{
print "ok 16\n";
} else
{
print "not ok 16: $result\n";
print "val=", $ifp->get ('val'), "\n";
}
$ifp = new HTML::Macro;
$result = $ifp->process ('test/test-include-body.html');
if ($result eq "included: BODY")
{
print "ok 17\n";
} else
{
print "not ok 17: $result\n";
}
$result = $ifp->process ('test/test-include-body2.html');