Mercurial > pub > Impl
changeset 238:b8c724f6de36
DOM model refactoring
TT view refactoring, controls are no longer derived from DOM nodes
bugfixes
line wrap: on
line diff
--- a/Lib/IMPL/DOM/Navigator.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Navigator.pm Tue Oct 16 01:33:06 2012 +0400 @@ -15,7 +15,7 @@ sub CTOR { my ($this,$CurrentNode) = @_; - die IMPL::InvalidArgumentException("A starting node is a required paramater") unless $CurrentNode; + die IMPL::InvalidArgumentException->new("A starting node is a required paramater") unless $CurrentNode; $this->{$_state} = { alternatives => [ $CurrentNode ], current => 0 }; } @@ -23,7 +23,7 @@ sub _initNavigator { my ($this,$CurrentNode) = @_; - die IMPL::InvalidArgumentException("A starting node is a required paramater") unless $CurrentNode; + die IMPL::InvalidArgumentException->new("A starting node is a required paramater") unless $CurrentNode; $this->{$_state} = { alternatives => [ $CurrentNode ], current => 0 }; delete $this->{$_path};
--- a/Lib/IMPL/DOM/Navigator/Builder.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Navigator/Builder.pm Tue Oct 16 01:33:06 2012 +0400 @@ -72,7 +72,7 @@ return $node; } else { die new IMPL::InvalidOperationException("The specified node is undefined", $nodeName) - if !$this->ingnoreUndefiend; + if !$this->ignoreUndefined; return; } }
--- a/Lib/IMPL/DOM/Schema/ComplexType.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Schema/ComplexType.pm Tue Oct 16 01:33:06 2012 +0400 @@ -28,7 +28,7 @@ my ($this,%args) = @_; $this->{$nativeType} = $args{nativeType}; - $this->{$messageWrongType} = $args{messageWrongType} || "A complex node '%Node.path%' is expected to be %Schema.nativeType%"; + $this->{$messageWrongType} = $args{messageWrongType} || "A complex node '%node.path%' is expected to be %schema.nativeType%"; } sub Validate {
--- a/Lib/IMPL/DOM/Schema/NodeList.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Schema/NodeList.pm Tue Oct 16 01:33:06 2012 +0400 @@ -19,8 +19,8 @@ sub CTOR { my ($this,%args) = @_; - $this->messageUnexpected($args{messageUnexpected} || 'A %Node.nodeName% isn\'t allowed in %Node.parentNode.path%'); - $this->messageNodesRequired($args{messageNodesRequired} || 'A %Schema.name% is required in the node %Parent.path%'); + $this->messageUnexpected($args{messageUnexpected} || 'A %node.nodeName% isn\'t allowed in %node.parentNode.path%'); + $this->messageNodesRequired($args{messageNodesRequired} || 'A %schema.name% is required in the node %parent.path%'); } sub Validate {
--- a/Lib/IMPL/DOM/Schema/NodeSet.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Schema/NodeSet.pm Tue Oct 16 01:33:06 2012 +0400 @@ -19,9 +19,9 @@ sub CTOR { my ($this,%args) = @_; - $this->messageMax( $args{messageMax} || 'Too many %Node.nodeName% nodes'); - $this->messageMin( $args{messageMin} || '%Schema.name% nodes expected'); - $this->messageUnexpected( $args{messageUnexpected} || 'A %Node.nodeName% isn\'t allowed in %Node.parentNode.path%'); + $this->messageMax( $args{messageMax} || 'Too many %node.nodeName% nodes'); + $this->messageMin( $args{messageMin} || '%schema.name% nodes expected'); + $this->messageUnexpected( $args{messageUnexpected} || 'A %node.nodeName% isn\'t allowed in %node.parentNode.path%'); } sub Validate {
--- a/Lib/IMPL/DOM/Schema/Property.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Schema/Property.pm Tue Oct 16 01:33:06 2012 +0400 @@ -21,7 +21,7 @@ $args{maxOccur} = 1; $args{minOccur} = delete $args{optional} ? 0 : 1; $args{nodeName} ||= 'Property'; - $args{messageInflateError} ||= "Failed to inflate a property '%Schema.name%' of a node '%Node.path%': %Error.Message%"; + $args{messageInflateError} ||= "Failed to inflate a property '%schema.name%' of a node '%node.path%': %error.message%"; return %args; } @@ -30,7 +30,7 @@ sub CTOR { my ($this,%args) = @_; - $this->messageRequired($args{messageRequired} || 'A property %Schema.name% is required in the %Node.qname%'); + $this->messageRequired($args{messageRequired} || 'A property %schema.name% is required in the %node.qname%'); } sub Validate {
--- a/Lib/IMPL/DOM/Schema/SimpleNode.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Schema/SimpleNode.pm Tue Oct 16 01:33:06 2012 +0400 @@ -26,7 +26,7 @@ if ( $args{inflator} ) { $this->{$inflator} = $args{inflator} ; - $this->{$messageInflateError} = exists $args{messageInflateError} ? $args{messageInflateError} : 'Failed to inflate nodeValue %Node.path%: %Error%'; + $this->{$messageInflateError} = exists $args{messageInflateError} ? $args{messageInflateError} : 'Failed to inflate nodeValue %node.path%: %error%'; } }
--- a/Lib/IMPL/DOM/Schema/SimpleType.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Schema/SimpleType.pm Tue Oct 16 01:33:06 2012 +0400 @@ -28,7 +28,7 @@ my ($this,%args) = @_; $this->{$nativeType} = $args{nativeType} if $args{nativeType}; - $this->{$messageWrongType} = $args{messageWrongType} || "A simple node '%Node.path%' is expected to be %Schema.nativeType%"; + $this->{$messageWrongType} = $args{messageWrongType} || "A simple node '%node.path%' is expected to be %schema.nativeType%"; } sub Validate {
--- a/Lib/IMPL/DOM/Schema/SwitchNode.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Schema/SwitchNode.pm Tue Oct 16 01:33:06 2012 +0400 @@ -24,7 +24,7 @@ sub CTOR { my ($this,%args) = @_; - $this->messageNoMatch($args{messageNoMatch} || 'A node %Node.nodeName% isn\'t expected in the %Parent.path%'); + $this->messageNoMatch($args{messageNoMatch} || 'A node %node.nodeName% isn\'t expected in the %parent.path%'); } sub Validate {
--- a/Lib/IMPL/DOM/Schema/Validator/Compare.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Schema/Validator/Compare.pm Tue Oct 16 01:33:06 2012 +0400 @@ -46,7 +46,7 @@ $this->targetProperty($args{targetProperty} || 'nodeValue'); $this->op( $Ops{ $args{op} || '=' } ) or die new IMPL::InvalidArgumentException("Invalid parameter value",'op',$args{op},$this->path); $this->nodePath($args{nodePath}) or die new IMPL::InvalidArgumentException("The argument is required", 'nodePath', $this->path); - $this->message($args{message} || 'The value of %Node.path% %Source.op% %Value% (%Source.nodePath%)' ); + $this->message($args{message} || 'The value of %node.path% %source.op% %value% (%source.nodePath%)' ); $this->optional($args{optional}) if $args{optional}; }
--- a/Lib/IMPL/DOM/Schema/Validator/RegExp.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Schema/Validator/RegExp.pm Tue Oct 16 01:33:06 2012 +0400 @@ -21,7 +21,7 @@ sub CTOR { my ($this,%args) = @_; - $this->message($args{message} || "A %Node.nodeName% doesn't match to the format %Schema.display%"); + $this->message($args{message} || "A %node.nodeName% doesn't match to the format %schema.display%"); } sub Validate { @@ -30,10 +30,10 @@ my $rx = $this->_rx() || $this->_rx( map qr{$_}, $this->nodeValue ); return new IMPL::DOM::Schema::ValidationError( - Node => $node, - Source => $ctx && $ctx->{Source} || $this->parentNode, - Schema => $this->parentNode, - Message => $this->message + node => $node, + source => $ctx && $ctx->{Source} || $this->parentNode, + schema => $this->parentNode, + message => $this->message ) unless (not $node->isComplex) and $node->nodeValue =~ /($rx)/; $node->nodeValue($1) if $this->launder;
--- a/Lib/IMPL/DOM/Transform/QueryToDOM.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/DOM/Transform/QueryToDOM.pm Tue Oct 16 01:33:06 2012 +0400 @@ -8,7 +8,7 @@ ], props => [ prefix => PROP_RO, - delimier => PROP_RO + delimiter => PROP_RO ] }; @@ -18,7 +18,8 @@ $this->templates->{'CGI'} = \&TransformCGI; $this->templates->{'CGIWrapper'} = \&TransformCGI; - $this->delimier('.'); + $this->delimiter('[.]'); + $this->prefix(''); } sub TransformCGI { @@ -32,21 +33,29 @@ foreach my $param (grep index($_,$prefix) >= 0 , $query->param()) { length (my $value = $query->param($param)) or next; - my @parts = split /\//,$param; + my @parts = split /$delim/,$param; my $node = $data; while ( my $part = shift @parts ) { - if (@parts) { - $node = ($node->{$part} ||= {}); - } else { - $node->{$part} = $value; + if (my ($name,$index) = ($part =~ m/^(\w+)(?:\[(\d+)\])?$/) ) { + if (@parts) { + if(defined $index) { + $node = ($node->{$name}[$index] ||= {}); + } else { + $node = ($node->{$name} ||= {}); + } + } else { + if(defined $index) { + $node->{$name}[$index] = $value; + } else { + $node->{$name} = $value; + } + } } } } - if (keys %$data > 1) { - $data = { document => $data }; - } - return $this->Transform($data); -} \ No newline at end of file +} + +1; \ No newline at end of file
--- a/Lib/IMPL/Security/AbstractContext.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/Security/AbstractContext.pm Tue Oct 16 01:33:06 2012 +0400 @@ -19,7 +19,7 @@ my $current; # current session if any sub Impersonate { - my ($this,$code) = @_; + my ($this,$code,@args) = @_; my $old = $current; $current = $this; @@ -29,7 +29,7 @@ { local $@; eval { - $result = $code->(); + $result = $code->(@args); }; $e = $@; }
--- a/Lib/IMPL/Security/Context.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/Security/Context.pm Tue Oct 16 01:33:06 2012 +0400 @@ -3,18 +3,19 @@ use warnings; use IMPL::require { - Principal => 'IMPL::Security::Principal', - Role => 'IMPL::Security::Role', AbstractContext => 'IMPL::Security::AbstractContext', - Exception => 'IMPL::Exception', - ArgumentException => '-IMPL::InvalidArgumentException' - }; use IMPL::declare { + require => { + Principal => 'IMPL::Security::Principal', + Role => 'IMPL::Security::Role', + Exception => 'IMPL::Exception', + ArgumentException => '-IMPL::InvalidArgumentException' + }, base => [ 'IMPL::Object' => undef, - 'IMPL::Object::Autofill' => undef, + 'IMPL::Object::Autofill' => '@_', 'IMPL::Security::AbstractContext' => undef, ], props => [
--- a/Lib/IMPL/Web/Application/Action.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/Web/Application/Action.pm Tue Oct 16 01:33:06 2012 +0400 @@ -1,33 +1,25 @@ package IMPL::Web::Application::Action; use strict; -use parent qw(IMPL::Object IMPL::Object::Autofill); - -__PACKAGE__->PassThroughArgs; - -use IMPL::Class::Property; use Carp qw(carp); -BEGIN { - public property application => prop_get | owner_set; - public property query => prop_get | owner_set; - private property _entryPoint => prop_all; -} +use IMPL::Const qw(:prop); + +use IMPL::declare { + base => [ + 'IMPL::Object' => undef, + 'IMPL::Object::Autofill' => '@_' + ], + props => [ + application => PROP_RO, + query => PROP_RO + ] +}; sub CTOR { my ($this) = @_; } -sub Invoke { - my ($this) = @_; - - if ($this->_entryPoint) { - $this->_entryPoint->(); - } else { - die new IMPL::InvalidOperationException("At least one handler is required"); - } -} - sub cookie { my ($this,$name,$rx) = @_; @@ -50,6 +42,12 @@ return $this->query->path_info; } +sub baseUrl { + my ($this) = @_; + + return $this->query->url(-base => 1); +} + sub _launder { my ($this,$value,$rx) = @_;
--- a/Lib/IMPL/Web/Handler/SecureCookie.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/Web/Handler/SecureCookie.pm Tue Oct 16 01:33:06 2012 +0400 @@ -8,7 +8,7 @@ use IMPL::declare { require => { SecurityContext => 'IMPL::Security::Context', - User => 'IMPL::Security::User', + User => 'IMPL::Security::Principal', AuthSimple => 'IMPL::Security::Auth::Simple', Exception => 'IMPL::Exception', OperationException => '-IMPL::InvalidOperationException', @@ -21,7 +21,7 @@ }, props => [ salt => PROP_RO, - manager => PROP_RO, + _manager => PROP_RO, _cookies => PROP_RW ] }; @@ -38,6 +38,7 @@ return unless $nextHandler; my $context; + $this->_manager($action->application->security); my $sid = $action->cookie('sid',qr/(\w+)/); @@ -56,12 +57,12 @@ ) ) { # TODO: add a DefferedProxy to deffer a request to a data source - if ( $context = $this->manager->GetSession($sid) ) { + if ( $context = $this->_manager->GetSession($sid) ) { if ( eval { $context->auth->isa(AuthSimple) } ) { my ($result,$challenge) = $context->auth->DoAuth($cookie); - $action->manager->SaveSession($context); + $action->_manager->SaveSession($context); if ($result == AUTH_FAIL) { $context = undef; @@ -73,7 +74,7 @@ $context ||= SecurityContext->new(principal => User->nobody, authority => $this); - my $httpResponse = $context->Impersonate($nextHandler); + my $httpResponse = $context->Impersonate($nextHandler,$action); die OperationException->new("A HttpResponse instance is expected") unless ref $httpResponse && eval { $httpResponse->isa(HttpResponse) }; @@ -90,9 +91,9 @@ $this->_cookies({ sid => $sid, sdata => $cookie - }) + }); - my $context = $this->$manager->CreateSession( + my $context = $this->_manager->CreateSession( sessionId => $sid, principal => $user, auth => AuthSimple->Create(password => $cookie), @@ -108,7 +109,7 @@ sub WriteResponse { my ($this,$response) = @_; - if (my $data $this->_cookies) { + if (my $data = $this->_cookies) { my $sign = md5_hex( $this->salt, @@ -152,10 +153,6 @@ Скаляр, использующийся для подписи данных. -=head2 C<[get,set] manager> - -Реализация менеджера безопасности, отвечающая за реализацию взаимодействия с -моделью безопасности. =head2 C<InitSession($user,$auth,$roles)>
--- a/Lib/IMPL/Web/View/TTControl.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/Web/View/TTControl.pm Tue Oct 16 01:33:06 2012 +0400 @@ -1,23 +1,21 @@ package IMPL::Web::View::TTControl; use strict; -use Scalar::Util qw(weaken); - use IMPL::Const qw(:prop); use IMPL::declare { require => { TTContext => 'Template::Context', Exception => 'IMPL::Exception', - ArgumentException => '-IMPL::InvalidArgumentException' + ArgumentException => '-IMPL::InvalidArgumentException', + OperationException => '-IMPL::InvalidOperationException' }, base => [ - 'IMPL::DOM::Node' => sub { - nodeName => $_[0], - %{ $_[3] || {} } - } + 'IMPL::Object' => '@_' ], props => [ id => PROP_RO, + attributes => PROP_RW, + name => PROP_RO, context => PROP_RO, template => PROP_RO ] @@ -31,6 +29,8 @@ } } +our $AutoloadRegex = qr/^[a-z]/; + sub CTOR { my ($this,$name,$template,$context,$refProps) = @_; @@ -41,11 +41,14 @@ $this->id($name . "-" . _GetNextId()) unless $this->id; - #TODO: deprecated, cleanup - #weaken($this); # prevent cyclic references produced by the code below + $this->name($name); + $this->attributes({}); - #$context->stash->set('append', sub { $this->appendChild(@_); undef; } ); - #$context->stash->set('select', sub { $this->selectNodes(@_); } ); + if (ref $refProps eq 'HASH') { + while (my($key,$value) = each %$refProps) { + $this->SetAttribute($key,$value); + } + } } sub InitInstance { @@ -58,6 +61,29 @@ } } +sub GetAttribute { + my ($this,$name) = (shift,shift); + + if (my $method = $this->can($name)) { + unshift @_,$this; + goto &$method; + } else { + return $this->attributes->{$name}; + } +} + +sub SetAttribute { + my $this = shift; + my $name = shift; + + if (my $method = $this->can($name)) { + unshift @_, $this; + goto &$method; + } else { + return $this->attributes->{$name} = shift; + } +} + sub GetRenderBlock { $_[0]->template->blocks->{RENDER} || $_[0]->template; } @@ -81,9 +107,13 @@ return if $method eq 'DESTROY'; - my $this = shift; - - $this->nodeProperty($method,@_); + if ($method =~ /$AutoloadRegex/) { + my $this = shift; + + return @_ ? $this->SetAttribute($method,@_) : $this->GetAttribute($method); + } else { + die OperationException->new("The specified method '$method' doesn't exists"); + } } 1;
--- a/Lib/IMPL/Web/View/TTDocument.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/Web/View/TTDocument.pm Tue Oct 16 01:33:06 2012 +0400 @@ -14,11 +14,8 @@ 'IMPL::Web::View::TTControl' => sub { my ($template,$contextOpts) = @_; 'document', - $_[0], # template - new Template::Context($_[1]) # context - }, - 'IMPL::DOM::Document' => sub { - nodeName => 'document' + $template, # template + Template::Context->new($contextOpts) # context } ], props => [
--- a/Lib/IMPL/require.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/Lib/IMPL/require.pm Tue Oct 16 01:33:06 2012 +0400 @@ -15,7 +15,7 @@ no strict 'refs'; while( my ($alias, $class) = each %$aliases ) { - _require($class); + $class = _require($class); *{"${caller}::$alias"} = set_prototype(sub { $class
--- a/_test/Resources/TTView/My/Org/Panel.tt Mon Oct 15 17:39:12 2012 +0400 +++ b/_test/Resources/TTView/My/Org/Panel.tt Tue Oct 16 01:33:06 2012 +0400 @@ -8,13 +8,14 @@ BLOCK CTOR; this.dojoClass = this.dojoClass || dojoDefaultClass; this.visualClass = this.visualClass || 'classic'; + this.childNodes = []; FOREACH text IN this.data; - append(TPreview.new('preview', nodeValue = text )); + this.childNodes.push( TPreview.new('preview', nodeValue = text ) ); END; END; %] <div class="$this.visualClass" data-dojo-type="$this.dojoClass"> - [% FOREACH node IN select('preview') %] + [% FOREACH node IN this.childNodes %] [% node.Render() %] <hr /> [% END %]
--- a/_test/Resources/TTView/complex.tt Mon Oct 15 17:39:12 2012 +0400 +++ b/_test/Resources/TTView/complex.tt Tue Oct 16 01:33:06 2012 +0400 @@ -3,7 +3,7 @@ BLOCK CTOR; TPanel = require('My/Org/Panel'); - append( TPanel.new('information', data = data ) ); + this.childNodes = [ TPanel.new('information', data = data ) ]; END; %]
--- a/_test/Test/Web/View.pm Mon Oct 15 17:39:12 2012 +0400 +++ b/_test/Test/Web/View.pm Tue Oct 16 01:33:06 2012 +0400 @@ -100,7 +100,7 @@ assert(defined $doc); $doc->title('test document'); - assert($doc->nodeName eq 'document'); + assert($doc->name eq 'document'); assert($doc->title eq 'test document'); assert(not $doc->can('notexists')); # autoloaded property should be ignored @@ -127,26 +127,26 @@ assert(defined $doc); - my $factory = $doc->require('My/Org/Panel'); + my $factory = $doc->RequireControl('My/Org/Panel'); assert(defined $factory); assert($factory->context->stash != $doc->context->stash); - assert($factory == $doc->require('My/Org/Panel'), "Control should be loaded only once"); + assert($factory == $doc->RequireControl('My/Org/Panel'), "Control should be loaded only once"); my $ctl = $factory->new('information', { visualClass => 'simple', data => ['one','two','hello world'] } ); assert(defined $ctl); - assert($ctl->nodeName eq 'information', "Created control should have a name", "Got: ".$ctl->nodeName, "Expected: information"); + assert($ctl->name eq 'information', "Created control should have a name", "Got: ".$ctl->name, "Expected: information"); - assert($ctl->nodeProperty('visualClass') eq 'simple'); + assert($ctl->GetAttribute('visualClass') eq 'simple'); assert($factory->instances == 1); - $doc->appendChild($ctl); + $doc->childNodes([$ctl]); assert($doc->templateVars('dojo.require')); assert(ref $doc->templateVars('dojo.require') eq 'ARRAY'); @@ -205,8 +205,8 @@ $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 $factory = $doc->RequireControl('My/Org/Panel'); + my $ctl = $doc->childNodes($factory->new('information', { visualClass => 'complex' }) ); }); $loader->template('complex');