| HTML-Chunks documentation | Contained in the HTML-Chunks distribution. |
HTML::Chunks::Super - Chunks with superpowers
1.0
The mutant spawn of HTML::Chunks, this module has all of the abilities of its parent plus additional emerging superpowers. The first enhancement to be added is conditional processing. For full chunk documentation, please see HTML:::Chunks. Only HTML::Chunks::Super enhancements will be discussed here.
While conditional processing does indeed blur the lines between layout/markup and actual programming logic, it can be very powerful when used sparingly and appropriately. We urge you to use this ability only for simple display logic, keeping the chunk side of life mostly pure and uncomplicated. With great power comes great responsibility. :-)
That warning aside, here is the extended chunk syntax:
<!-- IF condition --> normal chunk stuff <!-- ELSIF condition --> more chunks <!-- ELSE --> chunky chunk of chunks <!-- ENDIF -->
The condition can by most any valid perl expression and will usually
reference one or more chunk data elements. See the HTML::Chunks
documentation for a full descripton of data elements, but as a refresher,
they look like ##this## and refer to dynamic data that is merged into
a chunk at run-time. For use in conditionals, you can treat them as
read-only scalars.
True if data element ##foo## has a true value (in the perl sense of "true")
True if ##foo## begins with "bar"
True if ##foo## contains no non-word characters
True if ##num## is between 1 and 10 inclusive
You get the idea. Most comparisons and conditions that are possible in straight perl will be possible here as well.
Created, developed and maintained by Mark W Blythe and Dave Balmer, Jr. Contact dbalmer@cpan.org or mblythe@cpan.org for comments or questions.
(C)2001-2009 Mark W Blythe and Dave Balmer Jr, all rights reserved. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| HTML-Chunks documentation | Contained in the HTML-Chunks distribution. |
package HTML::Chunks::Super; use Safe; use IO::Scalar; use strict; use base qw(HTML::Chunks); our $VERSION = "1.01"; sub new { my $class = shift; my $self = $class->SUPER::new(@_); return $self; } # override basic chunk output to support conditionals sub outputBasicChunk { my $self = shift; my $chunk = shift; my $chunkRef = ref $chunk ? $chunk : \$chunk; my $tree = $self->buildTree($chunkRef); $self->outputNode($tree, @_); } # parse a chunk into a decision tree. it might be possible to gain some # efficiencies by doing this parsing when chunks are loaded, but it would # be tricky to avoid confusing our parent class. sub buildTree { my $self = shift; my ($chunk) = @_; my $chunkRef = ref $chunk ? $chunk : \$chunk; my $tree = []; my @stack; my $pos = 0; while ($$chunkRef =~ /\G(.*?)<!--\s*(IF|ELSIF|ELSE|ENDIF)\b\s*(.*?)\s*-->/gs) { my $beginDepth = @stack; my $node = $beginDepth ? $stack[-1]->{current} : $tree; if (defined $1 && length $1) { push @{$node}, $1; } my $cmd = uc($2); if ($cmd eq 'ELSE' || $cmd eq 'ELSIF') { my $branch = @stack ? $stack[-1] : undef; if ($branch && $branch->{current} == $branch->{true}) { $node = $branch->{current} = $branch->{false} = []; } } if ($cmd eq 'ENDIF' || $cmd eq 'ELSIF') { my $branch = pop @stack; delete $branch->{current} if $branch; } if ($cmd eq 'IF' || ($cmd eq 'ELSIF' && $beginDepth)) { my $branch = { test => $3, true => [] }; push @{$node}, $branch; push @stack, $branch; $branch->{current} = $branch->{true}; } $pos = pos $$chunkRef; } my $tail = substr $$chunkRef, $pos; push @{$tree}, $tail if (defined $tail && length $tail); return $tree; } sub outputNode { my $self = shift; my $node = shift; if (defined $node) { die "what is this? => ", $node, "\n" unless (ref $node eq 'ARRAY'); foreach my $thing (@{$node}) { if (ref $thing eq 'HASH') { if (exists $thing->{test} && $self->testsTrue($thing->{test}, @_)) { $self->outputNode($thing->{true}, @_) if (exists $thing->{true}); } else { $self->outputNode($thing->{false}, @_) if (exists $thing->{false}); } } else { # call the normal HTML::Chunk output routine when we're down to a # basic unadulterated chunk $self->SUPER::outputBasicChunk(\$thing, @_); } } } } sub testsTrue { my $self = shift; my $test = shift; our %values; local %values; # Translate any data tokens into scalars containing the actual data values $test =~ s/\#\#([\w\.]+)\#\#/ my $name = $1; my $f = new IO::Scalar \$values{$name}; my $oldfh = select $f; $self->outputData($name, @_); select $oldfh; close $f; "\$values{'$name'}"; /gex; # select STDERR, otherwise a 'print' in the test will blow up apache my $oldfh = select STDERR; # now safely evaluate the test my $safe = new Safe; $safe->share('%values'); my $status = $safe->reval($test); # put filehandle things back select $oldfh; warn $@ if $@; return $status; } 1; __END__