changeset 345:72799d1211c5

sync
author cin
date Fri, 27 Sep 2013 16:28:27 +0400
parents f1d67615a5b1
children f05634287ac7
files Lib/IMPL/Web/View/TTContext.pm Lib/IMPL/Web/View/TTDocument.pm Lib/IMPL/Web/View/TTLoader.pm Lib/IMPL/Web/View/TTRegistry.pm
diffstat 4 files changed, 209 insertions(+), 131 deletions(-) [+]
line wrap: on
line diff
--- a/Lib/IMPL/Web/View/TTContext.pm	Mon Sep 23 00:09:26 2013 +0400
+++ b/Lib/IMPL/Web/View/TTContext.pm	Fri Sep 27 16:28:27 2013 +0400
@@ -2,7 +2,11 @@
 use strict;
 use Template::Base;
 
+use IMPL::lang qw(is);
 use IMPL::declare {
+	require => [
+	   Document => '-Template::Document'
+	],
 	base => {
 		'Template::Context' => '@_'
 	}
@@ -24,4 +28,138 @@
     return $class->new($args);
 }
 
-1;
\ No newline at end of file
+sub base {
+	my $this = shift;
+	
+	return @_ ? $this->stash->set('base', @_) : $this->stash->get('base'); 
+}
+
+sub tt_ext {
+	my $this = shift;
+	
+	return @_ ? $this->stash->set('tt_ext', @_) : $this->stash->get('tt_ext');
+}
+
+sub find_template {
+	my ($this,$name,@inc) = @_;
+	
+	push @inc, "";
+	my $ext = $this->tt_ext || "";
+    
+	foreach my $dir (@inc) {
+		my $file = "$dir/$name$ext";
+		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
+		} if $tt;
+	}
+	
+	$this->throw(Template::Constants::ERROR_FILE, "$name: not found");
+}
+
+sub require {
+	my ($this,$name) = @_;
+	
+	return $this->stash->get([ 'require', [$name] ]);
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+C<IMPL::Web::View::TTContext> - доработанная версия контекста
+
+=head1 DESCRIPTION
+
+Расширяет функции C<Template::Context>
+
+=begin plantuml
+
+@startuml
+
+object FooContext {
+	document
+	this
+	model
+}
+
+object BarContext {
+    document
+    this
+    model
+}
+
+object FooFactoryContext {
+	require = function(){}
+	include = function(){}
+	labels = {...}
+	base = "my/app/view"
+	extends = "my/app/view/bar"
+}
+
+object BarFactoryContext {
+	require = function(){}
+	include = function(){}
+	base = "my/app/view"
+	labels = {...}
+	extends = undefined
+}
+
+object RegistryContext {
+	registry
+}
+
+object DocumentFactoryContext {
+	require = function() {}
+    include = function() {}
+    labels = {...}
+    base = ""
+    extends = undefined
+}
+
+object DocumentContext {
+	this
+}
+
+FooFactoryContext --o BarFactoryContext
+BarFactoryContext --o RegistryContext
+
+FooContext -right-o FooFactoryContext
+BarContext -right-o BarFactoryContext
+
+DocumentFactoryContext -up-o RegistryContext
+DocumentContext -left-o DocumentFactoryContext
+
+Document --> DocumentContext
+
+@enduml
+
+=end plantuml
+
+=head1 MEMBERS
+
+=head2 C<[get,set]base>
+
+Префикс пути для поиска шаблонов
+
+=head2 C<template($name)>
+
+Сначала пытается загрузить шаблон используя префикс C<base>, затем без префикса.
+
+=head2 C<clone()>
+
+Создает копию контекста, при этом C<stash> локализуется, таким образом
+клонированный контекст имеет собственное пространство имен, вложенное в
+пространство родительского контекста.
+
+=cut
\ No newline at end of file
--- a/Lib/IMPL/Web/View/TTDocument.pm	Mon Sep 23 00:09:26 2013 +0400
+++ b/Lib/IMPL/Web/View/TTDocument.pm	Fri Sep 27 16:28:27 2013 +0400
@@ -21,12 +21,6 @@
             $ctx ||= Template::Context->new();
             return $template, $ctx, $vars;  # context
         }
-    ],
-    props => [
-        layout => PROP_RW,
-        layoutBase => PROP_RW,
-        registry => PROP_RW,
-        baseLocation => PROP_RW
     ]
 };
 
@@ -35,22 +29,26 @@
     
     $this->layout( $template->layout ) unless $this->layout;
     $this->title( $template->title ) unless $this->title;
-    my $doc = $this;
-    weaken($doc);
-    $this->registry->context->stash->update({
-        document => sub { $doc }
-    });
 }
 
 sub Render {
     my ($this,$args) = @_;
+    
+    my $ctx = $this->context;
 
     $args ||= {};
     $args->{document} = $this;
+    $args->{render} = sub {
+    	my ($model,$factory) = @_;
+    	
+    	$factory = $ctx->require($factory) unless is($factory,TTFactory);
+    	
+    	return $factory->new({document => $this, model => $model})->Render();
+    };
     
     
     if ($this->layout) {
-    	my $layout = $this->registry->Require(join('/',$this->layoutBase, $this->layout))->new();
+    	my $layout = $this->registry->Require($this->layout)->new();
     	
     	my $next = $this->next::can();
     	
@@ -124,19 +122,21 @@
 
 @startuml
 
-namespace IMPL::Web::View {
+object "doc: TTDocument"  as doc
+object "docCtx: TTContext" as docctx
+object "factory: TTFactory" as factory 
+object "registry: TTRegistry" as registry
+object "control: TTControl" as ctl
+object "ctlCtx: TTContext" as ctlctx
 
-    TTDocument "0 .. *" .. TTLoader
-    TTDocument --|> TTControl
-    
-    TTControl .. TTContext
-    
-    TTFactory -- TTControl
-    TTFactory .. TTContext
-    
-    class TTRegistry
-
-}
+doc -up-> docctx
+registry --> "0..*" factory
+factory .> doc: <<creates>>
+factory .up.> ctl: <<creates>>
+docctx -up-> registry
+ctl -> ctlctx 
+ctlctx --> registry 
+ctlctx --> doc
 
 @enduml
 
--- a/Lib/IMPL/Web/View/TTLoader.pm	Mon Sep 23 00:09:26 2013 +0400
+++ b/Lib/IMPL/Web/View/TTLoader.pm	Fri Sep 27 16:28:27 2013 +0400
@@ -5,6 +5,8 @@
 
 use File::Spec();
 use IMPL::Const qw(:prop);
+use Scalar::Util qw(weaken);
+
 use IMPL::declare {
     require => {
         Provider => 'Template::Provider',
@@ -21,13 +23,9 @@
         'IMPL::Object::Serializable' => undef
     ],
     props => [
-        options => PROP_RO,
         provider => PROP_RO,
         context => PROP_RO,
-        ext => PROP_RO,
-        layoutBase => PROP_RO,
-        isInitialized => PROP_RO,
-        initializer => PROP_RO,
+        registry => PROP_RO,
         _globals => PROP_RW
     ]
 };
@@ -58,17 +56,44 @@
     
     $refOpts ||= {};
     
-    $this->ext($args{ext}) if $args{ext};
-    $this->initializer($args{initializer}) if $args{initializer};
+    # to aviod cyclic references we need to do a copy of $refOpts
+    $refOpts->{LOAD_TEMPLATES} = Provider->new( { %$refOpts } );
+    
+    my $ctx = Context->new( { %$refOpts } );
+    $this->context($ctx);
+    
     $this->_globals(ref $args{globals} eq 'HASH' ? $args{globals} : {});
     
-    $this->options($refOpts);
-    $this->layoutBase($args{layoutBase}) if $args{layoutBase};
+    $ctx->tt_ext($args{ext} || '.tt');
+    
+    $this->registry(TTRegitry->new($ctx));
     
-    # to aviod cyclic references we need to do a copy of $refOpts
-    $refOpts->{LOAD_TEMPLATES} = $this->provider(Provider->new( { %$refOpts } ));
+    weaken($ctx); 
+    weaken($this);
+    $ctx->stash->update({
+    	require => sub {
+    		my ($modname) = @_;
+    		
+    		my @inc;
+            push @inc, $ctx->base if $ctx->base;
+
+            my $ti = $ctx->find_template($name,@inc);
+            
+    		require $this->registry->Require($ti);
+    	},
+    	inclue => sub {
+    		my ($name) = @_;
+    		
+    		my @inc;
+    		push @inc, $ctx->base if $ctx->base;
+
+            my $ti = $ctx->find_template($name,@inc);
+            
+            return $ctx->include($ti->{template}, {base => $ti->{base}} );
+    	}
+    });
     
-    $this->context(Context->new($refOpts));
+    
 }
 
 sub document {
@@ -76,83 +101,9 @@
     
     $vars ||= {};
     
-    my $tt = $this->template($name);
-        
-    $this->_init();
-    
-    my $opts = { %{ $this->options } };
-    
-    my $ctx = $this->context->clone();
-    
-    $ctx->stash->update($vars);
-    
-    my $registry = TTRegistry->new($this, $ctx);
-    
-    my $factory = TTFactory->new($tt->class || TTDocument, $tt, $ctx, $name, $registry);
-    
-    $vars->{registry} = $registry;
-    $vars->{layoutBase} = $this->layoutBase;
-    
-    return $factory->new( $vars );
-}
-
-
-sub template {
-    my ($this,$name) = @_;
-    
-    $name =~ s/^\s+|\s+$//g;
-    
-    die ArgumentException->new("A valid template name is required") unless length $name;
-    
-    $name = $this->_appendExt($name);
-    
-    my ($tt,$error) = $this->provider->fetch($name);
-    
-    if (defined $error and $error == STATUS_DECLINED) {
-        die KeyNotFoundException->new($name);
-    } elsif (defined $error and $error == STATUS_ERROR) {
-        die Exception->new("Failed to load a template", $name, $tt);
-    }
+    my $factory = $this->registry->Require($name);
     
-    return $tt;
-}
-
-sub ResolveFileName {
-    my ($this,$fname) = @_;
-    
-    $fname = $this->_appendExt($fname);
-    
-    my @files = grep -f , map File::Spec->catfile($_,$fname), @{$this->provider->paths()};
-    return shift @files;
-}
-
-sub _appendExt {
-    my ($this,$name) = @_;
-    
-    return $name unless $this->ext;
-    
-    if (length $this->ext and substr( $name, -length($this->ext) ) eq $this->ext) {
-        return $name;
-    } else {
-        return $name . $this->ext;
-    }
-}
-
-sub _init {
-    my ($this) = @_;
-    
-    if (!$this->isInitialized) {
-        my $initializer = $this->initializer || sub {};
-        
-        eval {
-            $this->context->process($initializer,$this->_globals);
-        };
-        if (my $e = $@) {
-            die Exception->new("Failed to process an initializer", $this->initializer, $e);
-        }
-        
-        $this->isInitialized(1);
-    }
+    return $factory->new(hashMerge($vars, $this->_globals));
 }
 
 1;
@@ -179,7 +130,9 @@
         ]
     },
     ext => '.tt',
-    initializer => 'shared/global'
+    globals => {
+    	images => '//cdn.mysite.net/static/images'
+    }
         
 );
 
--- a/Lib/IMPL/Web/View/TTRegistry.pm	Mon Sep 23 00:09:26 2013 +0400
+++ b/Lib/IMPL/Web/View/TTRegistry.pm	Fri Sep 27 16:28:27 2013 +0400
@@ -9,20 +9,17 @@
         TTControl => '-IMPL::Web::View::TTControl'
     },
     base => [
-        'IMPL::Object' => undef,
-        'IMPL::Object::Disposable' => undef
+        'IMPL::Object' => undef
     ],
     props => [
-        loader => PROP_RW,
         context => PROP_RW,
         _cache => PROP_RW,
     ]
 };
 
 sub CTOR {
-	my ($this,$loader,$context) = @_;
-	
-	$this->loader($loader);
+	my ($this,$context) = @_;
+
 	$this->context($context);
 	$this->_cache({});
 }
@@ -39,7 +36,7 @@
         $factory = TTFactory->new(
             $template->class || TTControl,
             $template,
-            $this->context,
+            $this->context->clone,
             $name,
             $this
         );
@@ -49,16 +46,6 @@
     }
 }
 
-sub Dispose {
-	my ($this) = @_;
-	
-	$this->_cache(undef);
-	$this->context(undef);
-	$this->loader(undef);
-	
-	$this->next::method();
-}
-
 1;
 
 __END__