From c89da43b5840b0b46b478aec8b18d9014d0e5e11 Mon Sep 17 00:00:00 2001 From: Paul Driver Date: Wed, 1 Sep 2010 14:39:03 -0500 Subject: [PATCH] variable downgrading --- docs/changelog/7.x.x.txt | 3 + lib/WebGUI/Asset/Template/HTMLTemplate.pm | 1 + lib/WebGUI/Asset/Template/HTMLTemplateExpr.pm | 1 + lib/WebGUI/Asset/Template/Parser.pm | 44 ++++++++ t/Template/downgrade.t | 102 ++++++++++++++++++ 5 files changed, 151 insertions(+) create mode 100644 t/Template/downgrade.t diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index b94885599..13bceee72 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -2,6 +2,9 @@ - fixed #11812: Checking www_ajaxSave's response in the cart js, urlencoding post parameters - added: Link in the Admin Console to the Addons section on webgui.org - added: Labels in the Shopping Cart addresses are optional. + - added: template variable downgrading so that using we can safely pass + template variables TT would understand to HTML::Template templates -- see + WebGUI::Asset::Template::Parser->downgrade for details. 7.9.13 - fixed #11783: Instances deleted during realtime run diff --git a/lib/WebGUI/Asset/Template/HTMLTemplate.pm b/lib/WebGUI/Asset/Template/HTMLTemplate.pm index ed95d8345..8bd4f293f 100644 --- a/lib/WebGUI/Asset/Template/HTMLTemplate.pm +++ b/lib/WebGUI/Asset/Template/HTMLTemplate.pm @@ -54,6 +54,7 @@ sub process { my $self = shift; my $template = shift; my $vars = $self->addSessionVars(shift); + $self->downgrade($vars); my $t; eval { $t = HTML::Template->new( diff --git a/lib/WebGUI/Asset/Template/HTMLTemplateExpr.pm b/lib/WebGUI/Asset/Template/HTMLTemplateExpr.pm index 3f6984244..0812b2a9a 100644 --- a/lib/WebGUI/Asset/Template/HTMLTemplateExpr.pm +++ b/lib/WebGUI/Asset/Template/HTMLTemplateExpr.pm @@ -81,6 +81,7 @@ sub process { my $class = shift; my $template = shift; my $vars = $class->addSessionVars(shift); + $class->downgrade($vars); my $t; eval { $t = HTML::Template::Expr->new(scalarref=>\$template, diff --git a/lib/WebGUI/Asset/Template/Parser.pm b/lib/WebGUI/Asset/Template/Parser.pm index 47bb94511..b37f606f5 100644 --- a/lib/WebGUI/Asset/Template/Parser.pm +++ b/lib/WebGUI/Asset/Template/Parser.pm @@ -16,6 +16,7 @@ package WebGUI::Asset::Template::Parser; use strict; use WebGUI::International; +use Scalar::Util qw(blessed); #------------------------------------------------------------------- @@ -63,6 +64,49 @@ sub addSessionVars { #------------------------------------------------------------------- +=head2 downgrade ( vars ) + +Removes or converts things HTML::Template-like engines can't handle. Coderefs +are removed, blessed objects are removed, and hashes are recursively flattened +by appending keys separated by dots (e.g. { foo => { bar => 'baz' } } becomes +{ 'foo.bar' => 'baz' }. Also, array elements that aren't hashes are converted +to hashes via { value => $bareValue }. + +=cut + +sub downgrade { + my ($self, $vars) = @_; + for my $k (keys %$vars) { + my $v = $vars->{$k}; + if (blessed($v) || ref $v eq 'CODE') { + delete $vars->{$k}; + } + elsif (ref $v eq 'ARRAY') { + for my $i (0..$#$v) { + if (ref $v->[$i] eq 'HASH') { + $self->downgrade($v->[$i]); + } + else { + my %hash = ( value => $v->[$i] ); + $self->downgrade(\%hash); + $v->[$i] = \%hash; + } + } + } + elsif (ref $v eq 'HASH') { + delete $vars->{$k}; + my %flatter; + for my $subkey (keys %$v) { + $flatter{"$k.$subkey"} = $v->{$subkey}; + } + $self->downgrade(\%flatter); + @{$vars}{keys %flatter} = values %flatter; + } + } +} + +#------------------------------------------------------------------- + =head2 new ( session ) Constructor. diff --git a/t/Template/downgrade.t b/t/Template/downgrade.t new file mode 100644 index 000000000..589d705db --- /dev/null +++ b/t/Template/downgrade.t @@ -0,0 +1,102 @@ +use FindBin; +use strict; +use warnings; +use lib "$FindBin::Bin/../../lib"; +use lib "$FindBin::Bin/../lib"; + +use Data::Dumper; +use Test::More; +use WebGUI::Test; + +use WebGUI::Asset; +use WebGUI::Asset::Template::Parser; + +my $funky_instance = bless {}, 'WebGUI::Asset::Template::Parser'; + +sub down_ok { + my ( $down, $expected, $msg ) = @_; + $funky_instance->downgrade($down); + is_deeply( $down, $expected, $msg ) + or diag Dumper($down); +} + +down_ok { foo => 'bar' }, { foo => 'bar' }, 'nonthreatening'; +down_ok { + code => sub { } + }, + {}, + 'code'; +down_ok { obj => $funky_instance }, {}, 'object'; + +down_ok { hash => { foo => 'foo', bar => 'bar' } }, + { 'hash.foo' => 'foo', 'hash.bar' => 'bar' }, + 'simple hash flattening'; + +down_ok { array => [ 1, 2, 3 ] }, + { array => [ { value => 1 }, { value => 2 }, { value => 3 }, ] }, 'simple array flattening'; + +down_ok { + regular => 'simple', + hash => { + quite => 'deeply', + with => { + another => 'hashref', + and_even => [ + 'an', sub { }, { obj => $funky_instance }, + 'array', + [ 'nested', 'further', { son => '!!!' } ], + [ { oh => { wow => 'man' } } ] + ], + blessme => $funky_instance, + } + } + }, { + regular => 'simple', + 'hash.quite' => 'deeply', + 'hash.with.another' => 'hashref', + 'hash.with.and_even' => [ + { value => 'an' }, + {}, {}, + { value => 'array' }, + { value => [ { value => 'nested' }, { value => 'further' }, { son => '!!!' }, ], }, + { value => [ { 'oh.wow' => 'man' } ] } + ], + }, + 'twisted deep complex strucuture'; + +my $session = WebGUI::Test->session; + +sub processed_ok { + my ( $parser, $template, $msg ) = @_; + my $temp = WebGUI::Asset->getTempspace($session); + my $tmpl = $temp->addChild( { + className => 'WebGUI::Asset::Template', + parser => $parser, + template => $template, + } + ); + addToCleanup($tmpl); + is( $tmpl->process( { + his => { yes => 'yes', stop => 'stop' }, + my => { yes => 'no', stop => 'go' } + } + ), + <<'END_EXPECTED', $msg ); +You say yes, I say no. +You say stop, and I say go. +END_EXPECTED +} ## end sub processed_ok + +processed_ok( 'WebGUI::Asset::Template::HTMLTemplate', <<'END_HT', 'HTML::Template' ); +You say , I say . +You say , and I say . +END_HT + +processed_ok( 'WebGUI::Asset::Template::HTMLTemplateExpr', <<'END_HTE', 'HTML::Template::Expr' ); +You say , I say . +You say , and I say . +END_HTE + +done_testing; + +#vim:ft=perl