# HG changeset patch # User cin # Date 1333493385 -14400 # Node ID 08015e2803f1ee048c450b78f744a57ee8e4fef6 # Parent 029c9610528c9eacf0ec2dec350608edd56f9ab3 IMPL::Vew::Web - fixed memory leaks, more tests diff -r 029c9610528c -r 08015e2803f1 Lib/IMPL/Profiler/Memory.pm --- a/Lib/IMPL/Profiler/Memory.pm Tue Apr 03 20:08:42 2012 +0400 +++ b/Lib/IMPL/Profiler/Memory.pm Wed Apr 04 02:49:45 2012 +0400 @@ -78,7 +78,7 @@ sub Dump { my $this = shift; - return Data::Dumper->Dump($this->{objects}); + return Data::Dumper->Dump([$this->{objects}]); } sub isLeak { diff -r 029c9610528c -r 08015e2803f1 Lib/IMPL/Web/View/TTControl.pm --- a/Lib/IMPL/Web/View/TTControl.pm Tue Apr 03 20:08:42 2012 +0400 +++ b/Lib/IMPL/Web/View/TTControl.pm Wed Apr 04 02:49:45 2012 +0400 @@ -36,7 +36,7 @@ if ( my $ctor = $template->blocks->{CTOR} ) { $context->process($ctor, { this => $this } ); - $this->templateVars('this',undef); + $context->stash->set('this',undef); } $this->id($name . "-" . _GetNextId()) unless $this->id; @@ -50,17 +50,6 @@ } ); -sub templateVars { - my $this = shift; - my $name = shift; - - if (@_) { - return $this->context->stash->set($name, shift); - } else { - return $this->context->stash->get($name); - } -} - sub renderBlock { $_[0]->template->blocks->{RENDER}; } @@ -71,7 +60,7 @@ $args = {} unless ref $args eq 'HASH'; if(my $body = $this->renderBlock ) { - return $this->context->include( $body, { %$args, this => $this, template => $this->template } ); + return $this->context->include( $body, { %$args, this => $this, template => $this->template, document => $this->document } ); } else { return ""; } diff -r 029c9610528c -r 08015e2803f1 Lib/IMPL/Web/View/TTDocument.pm --- a/Lib/IMPL/Web/View/TTDocument.pm Tue Apr 03 20:08:42 2012 +0400 +++ b/Lib/IMPL/Web/View/TTDocument.pm Wed Apr 04 02:49:45 2012 +0400 @@ -17,6 +17,10 @@ public property opts => PROP_GET | PROP_OWNERSET; public property loader => PROP_GET | PROP_OWNERSET; public property controls => PROP_GET | PROP_OWNERSET; + + # store the stash separately to make require() method to work correctly + # even when a stash of the context is modified during the processing + public property stash => PROP_GET | PROP_OWNERSET; } sub CTOR { @@ -28,6 +32,7 @@ $this->layout( $template->layout ) unless $this->layout; $this->opts($refOpts); + $this->stash($this->context->stash); } our %CTOR = ( @@ -41,38 +46,48 @@ } ); +sub templateVars { + my $this = shift; + my $name = shift; + + if (@_) { + return $this->stash->set($name, shift); + } else { + return $this->stash->get($name); + } +} + sub require { my ($this, $control) = @_; if (my $factory = $this->controls->{$control}) { return $factory; } else { -=pod + my $path = $control; if ( my $template = $this->loader->template($path) ) { - #my $opts = { %{$this->opts} }; - #$opts->{STASH} = $this->context->stash->clone(); + + my $opts = { %{$this->opts} }; + $opts->{STASH} = $this->stash->clone(); - my $ctx = new Template::Context();#$opts); + my $ctx = new Template::Context($opts); $factory = new IMPL::Web::View::TTFactory( typeof IMPL::Web::View::TTControl, $template, $ctx, - {} #$opts + $opts ); my @parts = split(/\/+/,$control); $this->controls->{$control} = $factory; - $this->context->stash->set([map { $_, 0 } @parts], $factory); return $factory; } else { die new IMPL::KeyNotFoundException($control); } -=cut } } @@ -134,7 +149,7 @@ Скприт шаблона формирует структуру документа, затем сформированная структура форматируется в готовый документ. Процесс преобразования объектной модели в готовый документ может быть выполнена как вручную, так и при помощи -вспомогательного шаблона - обертки. Если у шаблона документа указан C в метаданных, то он будет +вспомогательного шаблона - обертки. Если у шаблона документа указан C в метаданных, то он будет использован как шаблон для форматирования объектной модели, вывод самого шаблона будет проигнорирован. Если обертка не задана, то результатом будет вывод самого скрипта шаблона. @@ -161,11 +176,9 @@ =item 1 Загружает шаблон C -=item 1 Создает фабрику элементов управления с собственным контекстом, вложенным в контекст документа. +=item 1 Создает фабрику элементов управления с собственным контекстом, унаследованным от контекст документа. -=item 1 Выполняет шаблон в пространстве имен фабрики - -=item 1 Регистритует фабрику в контексте документа по пути C +=item 1 Выполняет шаблон в пространстве имен фабрики =back diff -r 029c9610528c -r 08015e2803f1 _test/Resources/TTView.Output/Panel.txt --- a/_test/Resources/TTView.Output/Panel.txt Tue Apr 03 20:08:42 2012 +0400 +++ b/_test/Resources/TTView.Output/Panel.txt Wed Apr 04 02:49:45 2012 +0400 @@ -1,1 +1,8 @@ -
+
+
one
+
+
two
+
+
hello world
+
+
diff -r 029c9610528c -r 08015e2803f1 _test/Resources/TTView/My/Org/Panel.tt --- a/_test/Resources/TTView/My/Org/Panel.tt Tue Apr 03 20:08:42 2012 +0400 +++ b/_test/Resources/TTView/My/Org/Panel.tt Wed Apr 04 02:49:45 2012 +0400 @@ -10,5 +10,16 @@ END; %] [% BLOCK RENDER %] -
$this.nodeValue
+[% + TPreview = document.require('My/Org/TextPreview'); + FOREACH text IN data; + CALL this.appendChild(TPreview.new('preview', nodeValue = text )); + END; +%] +
+ [% FOREACH node IN this.selectNodes('preview') %] + [% node.Render() %] +
+ [% END %] +
[% END %] \ No newline at end of file diff -r 029c9610528c -r 08015e2803f1 _test/Resources/TTView/My/Org/TextPreview.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/_test/Resources/TTView/My/Org/TextPreview.tt Wed Apr 04 02:49:45 2012 +0400 @@ -0,0 +1,8 @@ +[% + BLOCK INIT; + dojo.require.push("dijit.layout.ContentPane"); + END; +%] +[% BLOCK RENDER %] +
$this.nodeValue
+[% END %] \ No newline at end of file diff -r 029c9610528c -r 08015e2803f1 _test/Resources/TTView/complex.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/_test/Resources/TTView/complex.tt Wed Apr 04 02:49:45 2012 +0400 @@ -0,0 +1,9 @@ +[% + META version = 1, title = "my document 2"; + + TPanel = document.require('My/Org/Panel'); + + this.appendChild(TPanel.new('information')); + + this.selectSingleNode('information').Render(); +%] \ No newline at end of file diff -r 029c9610528c -r 08015e2803f1 _test/Test/Web/View.pm --- a/_test/Test/Web/View.pm Tue Apr 03 20:08:42 2012 +0400 +++ b/_test/Test/Web/View.pm Wed Apr 04 02:49:45 2012 +0400 @@ -24,7 +24,11 @@ my $data = MProfiler->Monitor($code, sub { $_ =~ m/^IMPL::/} ); - assert( not($data->isLeak), "Memory leak detected", GetCallerSourceLine() , @{$data->{objects}}, $dump ? $data->Dump : () ); + if ($data->isLeak and $dump) { + write_file("dump.out", { binmode => ':utf8' }, $data->Dump() ); + } + + assert( not($data->isLeak), "Memory leak detected", GetCallerSourceLine() , @{$data->{objects}} ); } sub templatesDir { @@ -111,7 +115,6 @@ assert(defined $factory); - assert(not $loader->context->stash->get('My.Org.Panel')); assert($factory->context->stash != $doc->context->stash); @@ -127,9 +130,9 @@ assert($factory->instances == 1); - assert($doc->templateVars('My.Org.Panel') == $factory); + $doc->appendChild($ctl); - my $text = $ctl->Render(); + my $text = $ctl->Render({ data => ['one','two','hello world']}); my $expected = read_file($this->GetResourceFile('Resources', 'TTView.Output', 'Panel.txt'), binmode => ':utf8'); assert($text eq $expected, '$ctl->Render(): Bad output', "Got: $text", "Expected: $expected"); @@ -151,12 +154,20 @@ $doc->Render( { self => $doc } ); }); - AssertMemoryLeak(sub{ + $loader->template('My/Org/Panel'); + $loader->template('My/Org/TextPreview'); + AssertMemoryLeak(sub { my $doc = $loader->document('simple'); my $factory = $doc->require('My/Org/Panel'); - #my $ctl = $doc->AppendChild($factory->new('information', { visualClass => 'complex' }) ); + my $ctl = $doc->AppendChild($factory->new('information', { visualClass => 'complex' }) ); }); + $loader->template('complex'); + AssertMemoryLeak(sub { + my $doc = $loader->document('complex'); + $doc->Render(); + },'dump'); + }; 1; \ No newline at end of file