HTML-Macro

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

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.

History  view on Meta::CPAN

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;
}

History  view on Meta::CPAN


  <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
{

MANIFEST  view on Meta::CPAN

README
Changes
MANIFEST
Makefile.PL
Macro.pm
test.pl

Macro.pm  view on Meta::CPAN

# 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 = 
(
    '&' => '&amp;',
    '>' => '&gt;',
    '<' => '&lt;',

Macro.pm  view on Meta::CPAN

    $$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+)/) 

Macro.pm  view on Meta::CPAN

    $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'};

Macro.pm  view on Meta::CPAN

                : (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);

Macro.pm  view on Meta::CPAN

# 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|(.*)/([^/])+$|) {

Macro.pm  view on Meta::CPAN

    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;
        }

Macro.pm  view on Meta::CPAN

        $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);

Macro.pm  view on Meta::CPAN

        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;

Macro.pm  view on Meta::CPAN


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 = { };

Macro.pm  view on Meta::CPAN

    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 ()

Macro.pm  view on Meta::CPAN

    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 ):

Macro.pm  view on Meta::CPAN

      <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

Macro.pm  view on Meta::CPAN

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

Macro.pm  view on Meta::CPAN

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

Macro.pm  view on Meta::CPAN

=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

Macro.pm  view on Meta::CPAN

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.

README  view on Meta::CPAN

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.

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..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 &quot;&lt;quote me&gt;&quot; 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";
}

test.pl  view on Meta::CPAN

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');



( run in 0.751 second using v1.01-cache-2.11-cpan-49f99fa48dc )