# HG changeset patch # User wizard # Date 1270225126 -14400 # Node ID 9d24db321029d0112b8a0a9d81ccb1178ad3a31c # Parent b1652a158b2b8273db3d48200ba82a0a7220a8f6 Refactoring Web::TT docs diff -r b1652a158b2b -r 9d24db321029 Lib/IMPL/DOM/Document.pm --- a/Lib/IMPL/DOM/Document.pm Wed Mar 31 16:17:13 2010 +0400 +++ b/Lib/IMPL/DOM/Document.pm Fri Apr 02 20:18:46 2010 +0400 @@ -36,15 +36,58 @@ =pod +=head1 NAME + +C DOM документ. + =head1 DESCRIPTION +Документ, позволяет создавать узлы определенных типов, что позволяет абстрагироваться +от механизмов реального создания объектов. Т.о. например C +может формировать произвольные документы. + +=head1 SYNOPSIS + +=begin code + +package MyDocument; +use base qw(IMPL::DOM::Document); + +sub Create { + my $this = shift; + my ($name,$class,$hashProps) = @_; + + if ($class eq 'Info') { + return MyInfo->new($name,$hashProps->{date},$hashProps->{description}); + } else { + # leave as it is + return $this->SUPER::Create(@_); + } +} + +=end code + =head1 METHODS =over -=item C<<$doc->Create>> +=item C< Create($nodeName,$class,$hashProps) > + +Реализация по умолчанию. Создает узел определеннго типа с определенным именем и свойствами. + +=begin code -Создает узел определеннго типа с определенным именем и свойствами. +sub Create { + my ($this,$nodeName,$class,$hashProps) = @_; + + return $class->new ( + nodeName => $nodeName, + document => $this, + %$hashProps + ); +} + +=end code =back diff -r b1652a158b2b -r 9d24db321029 Lib/IMPL/Web/QueryHandler.pm --- a/Lib/IMPL/Web/QueryHandler.pm Wed Mar 31 16:17:13 2010 +0400 +++ b/Lib/IMPL/Web/QueryHandler.pm Fri Apr 02 20:18:46 2010 +0400 @@ -18,7 +18,7 @@ } sub Process { - die new NotImplementedException("The method isn't implemented", __PACKAGE__, 'Process'); + die new IMPL::NotImplementedException("The method isn't implemented", __PACKAGE__, 'Process'); } 1; diff -r b1652a158b2b -r 9d24db321029 Lib/IMPL/Web/QueryHandler/PageFormat.pm --- a/Lib/IMPL/Web/QueryHandler/PageFormat.pm Wed Mar 31 16:17:13 2010 +0400 +++ b/Lib/IMPL/Web/QueryHandler/PageFormat.pm Fri Apr 02 20:18:46 2010 +0400 @@ -4,7 +4,7 @@ __PACKAGE__->PassThroughArgs; use IMPL::Class::Property; -use IMPL::Web::TDocument; +use IMPL::Web::TT::Document; use File::Spec; use Error qw(:try); @@ -23,12 +23,12 @@ sub Process { my ($this,$action,$nextHandler) = @_; - my $doc = new IMPL::Web::TDocument(); + my $doc = new IMPL::Web::TT::Document(); try { my @path = split /\//, $ENV{PATH_TRANSLATED}; - $doc->loadFile ( File::Spec->catfile($this->templatesBase,@path), $this->templatesCharset ); + $doc->LoadFile ( File::Spec->catfile($this->templatesBase,@path), $this->templatesCharset ); $action->response->contentType('text/html'); my $hOut = $action->response->streamBody; diff -r b1652a158b2b -r 9d24db321029 Lib/IMPL/Web/TDocument.pm --- a/Lib/IMPL/Web/TDocument.pm Wed Mar 31 16:17:13 2010 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,172 +0,0 @@ -package IMPL::Web::TDocument; -use strict; -use warnings; - -use base qw(IMPL::DOM::Document IMPL::Object::Disposable); -use Template::Context; -use Template::Provider; -use IMPL::Class::Property; -use File::Spec; - -BEGIN { - private property _Provider => prop_all; - private property _Context => prop_all; - public property Template => prop_get | owner_set; -} - -our %CTOR = ( - 'IMPL::DOM::Document' => sub { nodeName => 'document' } -); - -sub Provider { - my ($this,%args) = @_; - - if (my $provider = $this->_Provider) { - return $provider; - } else { - return $this->_Provider(new Template::Provider( - \%args - )); - } -} - -sub Context { - my ($this) = @_; - - if (my $ctx = $this->_Context) { - return $ctx; - } else { - return $this->_Context ( - new Template::Context( - VARIABLES => { - document => $this - }, - TRIM => 1, - RECURSION => 1, - LOAD_TEMPLATES => [$this->Provider] - ) - ) - } -} - -sub loadFile { - my ($this,$filePath,$encoding) = @_; - - die new IMPL::InvalidArgumentException("A filePath parameter is required") unless $filePath; - - $encoding ||= 'utf8'; - - $this->_Context(undef); - $this->_Provider(undef); - - my ($vol,$dir,$fileName) = File::Spec->splitpath($filePath); - - my $inc = File::Spec->catpath($vol,$dir,''); - - $this->Provider( - ENCODING => $encoding, - INTERPOLATE => 1, - PRE_CHOMP => 1, - POST_CHOMP => 1, - INCLUDE_PATH => $inc - ); - - $this->Template($this->Context->template($fileName)); -} - -sub Title { - $_[0]->Template->Title; -} - -sub Render { - my ($this) = @_; - - return $this->Template->process($this->Context); -} - -sub Dispose { - my ($this) = @_; - - $this->Template(undef); - $this->_Context(undef); - $this->_Provider(undef); - - $this->SUPER::Dispose(); -} - -1; -__END__ -=pod - -=head1 SYNOPSIS - -=begin code - -// create new document -my $doc = new IMPL::Web::TDocument; - -// load template -$doc->loadFile('Templates/index.tt'); - -// render file -print $doc->Render(); - -=end code - -=head1 DESCRIPTION - -Документ, основанный на шаблоне Template::Toolkit. Позволяет загрузить шаблон, -и сформировать окончательный документ. Является наследником C, -т.о. может быть использован для реализации DOM модели. - -Внутри шаблона переменная C ссылается на объект документа. По этой -причине образуется циклическая ссылка между объектами шаблона и документом, что -требует вызова метода C для освобождения документа. - -=head1 METHODS - -=level 4 - -=item C - -Создает новый экземпляр документа - -=item C<$doc->loadFile($fileName,$encoding)> - -Загружает шаблон из файла C<$fileName>, используя кодировку C<$encoding>. Если -кодировка не указана, использует utf-8. - -=item C<$doc->Render()> - -Возвращает данные построенные на основе загруженного шаблона. - -=item C<$doc->Dispose()> - -Освобождает ресурсы и помечает объект как освобожденный. - -=back - -=head1 DOM - -=begin text - -[% table = document.tables.Add('env') %] - -[% FOEACH item in document.result %] - [% table.rows.Add( item.get('name','value') ) %] -[% END %] - -[% form = document.forms.Add('login') %] - -[% form.loadValues( {user => 'guest', password => ''} ) %] - -[% form.template = BLOCK %] - [% %] - [% END %] -[% END %] - - -=end text - - -=cut diff -r b1652a158b2b -r 9d24db321029 Lib/IMPL/Web/TT/Document.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/IMPL/Web/TT/Document.pm Fri Apr 02 20:18:46 2010 +0400 @@ -0,0 +1,218 @@ +package IMPL::Web::TT::Document; +use strict; +use warnings; + +use base qw(IMPL::DOM::Document IMPL::Object::Disposable); +use Template::Context; +use Template::Provider; +use IMPL::Class::Property; +use File::Spec; +use Scalar::Util qw(blessed); + +BEGIN { + private property _provider => prop_all; + private property _context => prop_all; + public property template => prop_get | owner_set; + public property presenter => prop_all, { validate => \&_validatePresenter }; +} + +our %CTOR = ( + 'IMPL::DOM::Document' => sub { nodeName => 'document' } +); + +sub provider { + my ($this,%args) = @_; + + if (my $provider = $this->_provider) { + return $provider; + } else { + return $this->_provider(new Template::Provider( + \%args + )); + } +} + +sub context { + my ($this) = @_; + + if (my $ctx = $this->_context) { + return $ctx; + } else { + return $this->_context ( + new Template::Context( + VARIABLES => { + document => $this, + this => $this, + render => sub { + $this->_process(@_); + } + }, + TRIM => 1, + RECURSION => 1, + LOAD_TEMPLATES => [$this->provider] + ) + ) + } +} + +sub _validatePresenter { + my ($this,$value) = @_; + + die new IMPL::InvalidArgumentException("A view object is required") unless blessed($value) and $value->isa('Template::View'); +} + +sub LoadFile { + my ($this,$filePath,$encoding) = @_; + + die new IMPL::InvalidArgumentException("A filePath parameter is required") unless $filePath; + + $encoding ||= 'utf8'; + + $this->_context(undef); + $this->_provider(undef); + + my ($vol,$dir,$fileName) = File::Spec->splitpath($filePath); + + my $inc = File::Spec->catpath($vol,$dir,''); + + $this->provider( + ENCODING => $encoding, + INTERPOLATE => 1, + PRE_CHOMP => 1, + POST_CHOMP => 1, + INCLUDE_PATH => $inc + ); + + $this->template($this->context->template($fileName)); +} + +sub title { + $_[0]->template->title; +} + +sub Render { + my ($this) = @_; + + return $this->template->process($this->context); +} + +# Формирует представление для произвольных объектов +sub _process { + my ($this,@items) = @_; + + my @result; + + foreach my $item (@items) { + if (blessed($item) and $item->isa('IMPL::Web::TT::Control')) { + push @result, $item->Render(); + } elsif(blessed($item)) { + if ($this->presenter) { + push @result, $this->presenter->print($item); + } else { + push @result, $this->toString; + } + } else { + push @result, $item; + } + } + + return join '',@items; +} + +sub Dispose { + my ($this) = @_; + + $this->template(undef); + $this->_context(undef); + $this->_provider(undef); + + $this->SUPER::Dispose(); +} + +1; +__END__ +=pod + +=head1 NAME + +C - Документ, позволяющий строить представление по шаблону + +=head1 SYNOPSIS + +=begin code + +// create new document +my $doc = new IMPL::Web::TT::Document; + +// load template +$doc->loadFile('Templates/index.tt'); + +// render file +print $doc->Render(); + +=end code + +=head1 DESCRIPTION + +C + +Документ, основанный на шаблоне Template::Toolkit. Позволяет загрузить шаблон, +и сформировать окончательный документ. Является наследником C, +т.о. может быть использован для реализации DOM модели. + +Внутри шаблона переменная C ссылается на объект документа. По этой +причине образуется циклическая ссылка между объектами шаблона и документом, что +требует вызова метода C для освобождения документа. + +=head1 METHODS + +=over + +=item C + +Создает новый экземпляр документа, свойство C устанавливается в 'C' + +=item C<$doc->LoadFile($fileName,$encoding)> + +Загружает шаблон из файла C<$fileName>, используя кодировку C<$encoding>. Если +кодировка не указана, использует utf-8. + +=item C<$doc->Render()> + +Возвращает данные построенные на основе загруженного шаблона. + +=item C<$doc->Dispose()> + +Освобождает ресурсы и помечает объект как освобожденный. + +=back + +=head1 DOM + +=begin code html + +[% table = document.Create('env','table') %] + +[% FOEACH item in document.result %] + [% table.rows.Add( item.get('name','value') ) %] +[% END %] + +[% form = document.Create('login','form') %] + + +[% form.template = 'LOGIN_FORM'%] + +[% FOREACH item IN document.childNodes %] + [%render(item)%] +[% END %] + +[% BLOCK LOGIN_FORM %] +
+ user: [% render(this.item('name')) %] password: [% render(this.item('password')) %] +
+[% END %] + +=end code html + + +=cut diff -r b1652a158b2b -r 9d24db321029 _test/Resources/simple.tt --- a/_test/Resources/simple.tt Wed Mar 31 16:17:13 2010 +0400 +++ b/_test/Resources/simple.tt Fri Apr 02 20:18:46 2010 +0400 @@ -1,2 +1,2 @@ -[% META Title = "Документ 1" %] -Текст докуметна $document.Title \ No newline at end of file +[% META title = "Документ 1" %] +Текст докуметна $document.title \ No newline at end of file diff -r b1652a158b2b -r 9d24db321029 _test/Test/Web/TDocument.pm --- a/_test/Test/Web/TDocument.pm Wed Mar 31 16:17:13 2010 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -package Test::Web::TDocument; -use strict; -use warnings; -use encoding 'cp1251'; - -use base qw(IMPL::Test::Unit); -use IMPL::Test qw(test failed); -use IMPL::Web::TDocument; -__PACKAGE__->PassThroughArgs; - -test Creation => sub { - my $document = new IMPL::Web::TDocument(); - - failed "Failed to create document" unless $document; - - $document->Dispose(); -}; - -test SimpleTemplate => sub { - my $document = new IMPL::Web::TDocument(); - - failed "Failed to create document" unless $document; - - $document->loadFile('Resources/simple.tt','cp1251'); - - my $out = $document->Render; - - open my $hFile,'<:encoding(cp1251)',"Resources/simple.txt" or die "Failed to open etalon file: $!"; - local $/; - my $eta = <$hFile>; - - failed "Rendered data doesn't match the etalon data","Expected:\n$eta","Actual:\n$out" if $out ne $eta; - - $document->Dispose(); -}; - - -1; diff -r b1652a158b2b -r 9d24db321029 _test/Test/Web/TT.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/_test/Test/Web/TT.pm Fri Apr 02 20:18:46 2010 +0400 @@ -0,0 +1,38 @@ +package Test::Web::TT; +use strict; +use warnings; +use encoding 'cp1251'; + +use base qw(IMPL::Test::Unit); +use IMPL::Test qw(test failed); +use IMPL::Web::TT::Document; +__PACKAGE__->PassThroughArgs; + +test Creation => sub { + my $document = new IMPL::Web::TT::Document(); + + failed "Failed to create document" unless $document; + + $document->Dispose(); +}; + +test SimpleTemplate => sub { + my $document = new IMPL::Web::TT::Document(); + + failed "Failed to create document" unless $document; + + $document->LoadFile('Resources/simple.tt','cp1251'); + + my $out = $document->Render; + + open my $hFile,'<:encoding(cp1251)',"Resources/simple.txt" or die "Failed to open etalon file: $!"; + local $/; + my $eta = <$hFile>; + + failed "Rendered data doesn't match the etalon data","Expected:\n$eta","Actual:\n$out" if $out ne $eta; + + $document->Dispose(); +}; + + +1; diff -r b1652a158b2b -r 9d24db321029 _test/Web.t --- a/_test/Web.t Wed Mar 31 16:17:13 2010 +0400 +++ b/_test/Web.t Fri Apr 02 20:18:46 2010 +0400 @@ -7,7 +7,7 @@ use IMPL::Test::TAPListener; my $plan = new IMPL::Test::Plan qw( - Test::Web::TDocument + Test::Web::TT Test::Web::Application );