# HG changeset patch # User cin # Date 1380815337 -14400 # Node ID f116cd9fe7d9d1fdf031a12bf36df9566f3411d7 # Parent 3eafa6fefa9f444f150946f7525617cc90264d62 working on TTView: pre-alpha version diff -r 3eafa6fefa9f -r f116cd9fe7d9 Lib/IMPL/DOM/Transform/ObjectToDOM.pm --- a/Lib/IMPL/DOM/Transform/ObjectToDOM.pm Mon Sep 30 17:36:17 2013 +0400 +++ b/Lib/IMPL/DOM/Transform/ObjectToDOM.pm Thu Oct 03 19:48:57 2013 +0400 @@ -80,7 +80,6 @@ my $value = $data->{$key}; if (ref $value eq 'ARRAY') { - #TODO: collapse empty values only if needed foreach my $subval (grep $_, @$value) { $this->_navi->saveState(); diff -r 3eafa6fefa9f -r f116cd9fe7d9 Lib/IMPL/Web/View/TTContext.pm --- a/Lib/IMPL/Web/View/TTContext.pm Mon Sep 30 17:36:17 2013 +0400 +++ b/Lib/IMPL/Web/View/TTContext.pm Thu Oct 03 19:48:57 2013 +0400 @@ -1,29 +1,36 @@ package IMPL::Web::View::TTContext; use strict; use Template::Base; +use Carp qw(carp); -use IMPL::lang qw(is); +use IMPL::Exception(); +use IMPL::lang qw(is typeof hashApply); use IMPL::declare { - require => [ - Document => '-Template::Document' - ], - base => { + require => { + Document => '-Template::Document', + TypeKeyedCollection => 'IMPL::TypeKeyedCollection', + ArgException => "-IMPL::InvalidArgumentException" + }, + base => [ 'Template::Context' => '@_' - } + ] }; BEGIN { - no strict 'ref'; + no strict 'refs'; foreach my $prop (qw( + root base tt_ext - shared + tt_cache parent prefix + cache + includes )) { my $t = $prop; - *{__PACKAGE__ . '::' . $name} = sub { + *{__PACKAGE__ . '::' . $prop} = sub { my $this = shift; return @_ ? $this->stash->set($t, @_) : $this->stash->get($t); } @@ -40,7 +47,7 @@ $this->delocalise(); - my $class = typeof($this); + my $class = ref($this); delete $args->{CONFIG}; @@ -52,38 +59,45 @@ } sub find_template { - my ($this,$name,@inc) = @_; + my ($this,$name) = @_; + + my $cache = $this->tt_cache; + $this->tt_cache($cache = {}) unless $cache; - push @inc, ""; + if(my $tpl = $cache->{$name}) { + return $tpl; + } + + my @inc = ($this->base, @{$this->includes || []}); + my $ext = $this->tt_ext || ""; + + my $file; foreach my $dir (@inc) { - my $file = "$dir/$name$ext"; + $file = $dir ? "$dir/$name" : $name; + + my $base = join('/',splice([split(/\/+/,$file)],0,-1)); + + $file = $ext ? "$file.$ext" : $file; + + warn "lookup: $file"; + my $tt = eval { $this->template($file) }; - return { - # if we load a block then we should use the current base directory - base => is($tt,Document) ? $dir : $this->base, - isDocument => is($tt,Document), - name => $name, - file => $file, - template => $tt + return $cache->{$name} = { + base => $base, + template => $tt, } if $tt; } $this->throw(Template::Constants::ERROR_FILE, "$name: not found"); } -sub require { - my ($this,$name) = @_; - - return $this->stash->get([ 'require', [$name] ]); -} - sub display { my $this = shift; my $model = shift; - my $template, $args; + my ($template, $args); if (ref $_[0] eq 'HASH') { $args = shift; @@ -92,16 +106,138 @@ $args = shift; } - my $prefix = $this->prefix + my $prefix = $this->prefix; + + if (not(($args and delete $args->{'-no-resolve'}) or ref $model)) { + $prefix = $prefix ? "${prefix}.${model}" : $model; + $model = $this->resolve_model($model); + } else { + $prefix = ""; + } + + $template = $template ? $this->find_template($template) : $this->find_template_for($model); + + return $this->render( + $template, + hashApply( + { + prefix => $prefix, + model => $model, + }, + $args + ) + ); +} + +sub invoke_environment { + my ($this,$code,$env) = @_; + + $env ||= {}; + + my $out = eval { + $this->localise( + hashApply( + { + root => $this->root || $this, + cache => TypeKeyedCollection->new(), + display => sub { + $this->display(@_); + }, + render => sub { + $this->render(@_); + } + }, + $env + ) + ); + + &$code($this); + }; + + my $e = $@; + $this->delocalise(); + + die $e if $e; + + return $out; +} + +sub render { + my ($this,$template,$args) = @_; + + $args ||= {}; + + #TODO handle classes + + my $base; - my $cloned = $this->clone({ - prefix => $prefix, - shared => $this->shared || $this, - parent => $this - }); + $template = $this->find_template($template) unless ref $template; + + if (ref $template eq 'HASH') { + $base = $template->{base}; + $template = $template->{template}; + } else { + carp "got an invalid template object: $template"; + $base = $this->base; + } + + return $this->invoke_environment( + sub { + return shift->include($template,$args); + }, + { + base => $base, + parent => $this + } + ) +} + +sub resolve_model { + my ($this,$prefix) = @_; + + die ArgException->new(prefix => "the prefix must be specified") + unless defined $prefix; + + #TODO handle DOM models + + my @comp = map { $_, 0 } grep length($_), split(/\.|\[(\d+)\]/, $prefix); + return $this->stash->get(['model',0,@comp]); +} + +sub find_template_for { + my ($this,$model) = @_; + my $type = typeof($model); + return $this->find_template('templates/plain') unless $type; + + if (my $template = $this->cache->Get($type)) { + return $template; + } else { + + no strict 'refs'; + + my @isa = $type; + + while (@isa) { + my $sclass = shift @isa; + + (my $name = $sclass) =~ s/:+/_/g; + + $template = $this->find_template("templates/$name"); + + if ($template) { + $this->cache->Set($sclass,$template); + return $template; + } + + push @isa, @{"${sclass}::ISA"}; + } + + } + + return; } 1; @@ -122,7 +258,7 @@ @startuml -object SharedContext { +object RootContext { document globals } @@ -137,13 +273,13 @@ extends } -SharedContext o-- DocumentContext -SharedContext o-- ControlContext +RootContext o-- DocumentContext +RootContext o-- ControlContext Document -- DocumentContext Control - ControlContext -Loader . SharedContext: <> +Loader . RootContext: <> Loader . Document: <> Loader -up- Registry diff -r 3eafa6fefa9f -r f116cd9fe7d9 _test/Resources/view/packages/templates/ARRAY.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/_test/Resources/view/packages/templates/ARRAY.tt Thu Oct 03 19:48:57 2013 +0400 @@ -0,0 +1,3 @@ +[% FOR item IN model %] + * ${loop.index}. [% display(loop.index) %] +[% END %] \ No newline at end of file diff -r 3eafa6fefa9f -r f116cd9fe7d9 _test/Resources/view/packages/templates/HASH.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/_test/Resources/view/packages/templates/HASH.tt Thu Oct 03 19:48:57 2013 +0400 @@ -0,0 +1,3 @@ +[% FOR item IN model %] +
$item.key : [% display(item.key) %]
+[% END %] \ No newline at end of file diff -r 3eafa6fefa9f -r f116cd9fe7d9 _test/Resources/view/packages/templates/plain.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/_test/Resources/view/packages/templates/plain.tt Thu Oct 03 19:48:57 2013 +0400 @@ -0,0 +1,1 @@ +$model \ No newline at end of file diff -r 3eafa6fefa9f -r f116cd9fe7d9 _test/Resources/view/site/index.tt --- a/_test/Resources/view/site/index.tt Mon Sep 30 17:36:17 2013 +0400 +++ b/_test/Resources/view/site/index.tt Thu Oct 03 19:48:57 2013 +0400 @@ -1,1 +1,2 @@ -

hello

\ No newline at end of file +

hello

+[% display({ name = 'a2r2', description = 'service droid' }, prefix = 'data') %] \ No newline at end of file diff -r 3eafa6fefa9f -r f116cd9fe7d9 _test/Resources/view/site/product/view.tt --- a/_test/Resources/view/site/product/view.tt Mon Sep 30 17:36:17 2013 +0400 +++ b/_test/Resources/view/site/product/view.tt Thu Oct 03 19:48:57 2013 +0400 @@ -1,10 +1,3 @@ -[% display('name') %] -[% display('description') %] -
-
- $AddressLabel -
-
- [% display('address', 'templates/My_App_Model_Address', { nolinks => 1 } ) %] -
-
\ No newline at end of file +

PageTitle

+
name: [% display('name') %]
+
description: [% display(model) %]
\ No newline at end of file diff -r 3eafa6fefa9f -r f116cd9fe7d9 _test/Resources/view/site/product/view.tt.labels --- a/_test/Resources/view/site/product/view.tt.labels Mon Sep 30 17:36:17 2013 +0400 +++ b/_test/Resources/view/site/product/view.tt.labels Thu Oct 03 19:48:57 2013 +0400 @@ -1,1 +1,1 @@ -AddressLabel = Address \ No newline at end of file +PageTitle = View page title \ No newline at end of file diff -r 3eafa6fefa9f -r f116cd9fe7d9 _test/temp.pl --- a/_test/temp.pl Mon Sep 30 17:36:17 2013 +0400 +++ b/_test/temp.pl Thu Oct 03 19:48:57 2013 +0400 @@ -1,42 +1,44 @@ #!/usr/bin/perl use strict; -{ - package Foo; - use IMPL::declare { - base => [ - 'IMPL::Object::Disposable' => undef - ] - }; -} - -use Time::HiRes qw(gettimeofday tv_interval); - - -use IMPL::lang; use IMPL::require { - AutoDispose => 'IMPL::Object::AutoDispose', - DBSchema => 'IMPL::SQL::Schema' + TTContext => 'IMPL::Web::View::TTContext' }; -my $real = DBSchema->new( name => 'simple', version => 1); -my $proxy = AutoDispose->new($real); - -print typeof($proxy),"\n"; +my $ctx = TTContext->new({ + INCLUDE_PATH => './Resources/view', + INTERPOLATE => 1, + RECURSION => 1000 +}); -my $t = [gettimeofday]; - -for (1..1000000) { - $proxy->name; -} +warn $ctx->load_templates->[0]->include_path->[0]; -print "proxy: ",tv_interval($t,[gettimeofday]),"\n"; - -$t = [gettimeofday]; - -for (1..1000000) { - $real->name; -} - -print "real: ",tv_interval($t,[gettimeofday]),"\n"; +print $ctx->invoke_environment(sub { + return shift->render( + 'product/view',{ + model => { + name => 'debugger', + manufature => { + name => 'DEBUGGERS INC', + address => [ + { + coutry => 'Russuia', + city => 'Moscow' + }, + { + country => 'GB', + city => 'Essex' + } + ] + } + } + } + ); +}, { + base => 'site', + includes => [ + 'packages' + ], + tt_ext => 'tt' +});