# HG changeset patch
# User wizard@linux-odin.local
# Date 1267170561 -10800
# Node ID 16ada169ca7561efaa3e0fdfef19a15831339c66
# Parent 1c3c3e63a3142fe3a89178fc67f7bd10c1cb7dbc
migrating to the Eclipse IDE
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/BNFCompiler.pm
--- a/Lib/BNFCompiler.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/BNFCompiler.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,666 +1,666 @@
-package BNFCompiler;
-package BNFCompiler::DOM;
-package BNFCompiler::DOM::Builder;
-package BNFCompiler::DOM::Node;
-use strict;
-
-package BNFCompiler::EventParser;
-use strict;
-use lib '.';
-use Common;
-our @ISA = qw(Object);
-
-our $EventMapSchema = {
- Description => 'Parser events',
- Type => 'HASH',
- Values => 'SCALAR'
-};
-
-BEGIN {
- DeclareProperty(EventMap => ACCESS_READ);
- DeclareProperty(CompiledEvents => ACCESS_NONE);
- DeclareProperty(Handler => ACCESS_ALL);
-}
-
-sub CTOR {
- my ($this,%args) = @_;
- $this->SUPER::CTOR(%args);
-}
-
-sub Compile {
- my ($this) = @_;
-
- delete $this->{$CompiledEvents};
- while (my ($key,$val) = each %{$this->{$EventMap}}) {
- $this->{$CompiledEvents}{$key} = qr/\G$val/;
- }
- 1;
-}
-
-sub Parse {
- my ($this,$data) = @_;
-
- my $StateData;
- OUTER: while(pos($data) < length($data)) {
- keys %{$this->{$CompiledEvents}};
- while (my ($event,$match) = each %{$this->{$CompiledEvents}}) {
- if ($data =~ m/($match)/gc) {
- $StateData .= $1;
- eval {
- undef $StateData if $this->{$Handler}->($event,$StateData);
- };
- if ($@) {
- die ["Invalid syntax","unexpected $event: $1",pos($data)];
- }
- next OUTER;
- }
- }
- die ["Invalid syntax",substr($data,pos($data),10),pos($data)];
- }
-
- return 1;
-}
-
-# небольшая уловка, поскольку ref от регулярного выражения есть Regexp, можно поставить хуки
-package Regexp;
-use Data::Dumper;
-
-sub STORABLE_freeze {
- my ($obj,$cloning) = @_;
-
- return $obj;
-}
-
-sub STORABLE_attach {
- my($class, $cloning, $serialized) = @_;
- return qr/$serialized/;
-}
-
-package BNFCompiler;
-use Common;
-use Storable;
-use Data::Dumper;
-our @ISA = qw(Object);
-
-our $BNFSchema;
-my $ParseAgainstSchema;
-my $TransformDOMToBNF;
-
-BEGIN {
- DeclareProperty(Schema => ACCESS_NONE);
- DeclareProperty(SchemaCache => ACCESS_NONE);
- DeclareProperty(Transform => ACCESS_NONE);
-}
-
-sub CTOR {
- my $this = shift;
- $this->SUPER::CTOR(@_);
-
- $this->{$SchemaCache} .= '/' if ($this->{$SchemaCache} and not $this->{$SchemaCache} =~ /\/$/);
-}
-{
- my $compiledBNFSchema;
- sub LoadBNFSchema {
- my ($this,%args) = @_;
-
- my $CompileBNFText = sub {
- my ($this,$text) = @_;
-
- my %SchemaDOM;
- foreach my $item (split /\n{2,}/, $text) {
- next if not $item;
- $compiledBNFSchema = CompileBNFSchema($BNFSchema) if not $compiledBNFSchema;
- my $context = new BNFCompiler::DOM::Builder();
- eval {
- my $expr = &$ParseAgainstSchema($compiledBNFSchema,$item,$context);
- die ["Unexpected expression", $expr] if $expr;
- };
- if ($@) {
- if (ref $@ eq 'ARRAY') {
- die new Exception(@{$@});
- } else {
- die $@;
- }
- }
-
- $SchemaDOM{$context->Document->selectNodes('name')->text()} = &$TransformDOMToBNF($context->Document->selectNodes('def'));
-
- }
-
- $SchemaDOM{'separator'} = ['re:\\s+'];
- $this->{$Schema} = CompileBNFSchema(\%SchemaDOM);
- };
-
- my $text;
- if ($args{'file'}) {
-
- my $fnameCached;
- if ($this->{$SchemaCache}) {
- my $fname = $args{'file'};
- $fname =~ tr/\//_/;
- $fnameCached = $this->{$SchemaCache}.$fname.'.cbs';
- if ( -e $fnameCached && -f $fnameCached && ( -M $args{'file'} >= -M $fnameCached )) {
- my $compiledSchema = retrieve($fnameCached);
- if ($compiledSchema) {
- $this->{$Schema} = $compiledSchema;
- return 1;
- } else {
- unlink $fnameCached;
- }
- }
- }
- open my $hFile, '<', $args{'file'} or die new Exception("Failed to open file",$args{'file'},$!);
- local $/ = undef;
- my $text = <$hFile>;
-
- $this->$CompileBNFText($text);
-
- if ($fnameCached) {
- store($this->{$Schema},$fnameCached);
- }
- } elsif ($args{'Schema'}) {
- $this->{$Schema} = CompileBNFSchema($args{'Schema'});
- return 1;
- } elsif ($args{'text'}) {
- $this->$CompileBNFText( $args{'text'} );
- } else {
- die new Exception("'file', 'text' or 'Schema' parameter required");
- }
-
- }
-}
-
-sub Parse {
- my ($this, $string, %flags) = @_;
-
- my $context = new BNFCompiler::DOM::Builder;
-
- eval {
- my $err;
- $err = &$ParseAgainstSchema($this->{$Schema},$string,$context,\%flags) and die new Exception('Failed to parse',substr($err,0,80).' ...');
- };
- if ($@) {
- if (ref $@ eq 'ARRAY') {
- die new Exception(@{$@});
- } else {
- die $@;
- }
- }
- if (not $this->{$Transform}) {
- return $context->Document;
- } else {
- return $this->{$Transform}->($context->Document);
- }
-}
-
-sub Dispose {
- my ($this) = shift;
- CleanSchema($this->{$Schema});
- delete @$this{$Schema, $Transform};
- $this->SUPER::Dispose;
-}
-
-sub CleanSchema {
- my ($schema,$table) = @_;
-
- UNIVERSAL::isa($schema,'ARRAY') or return;
- $table or $table = { $schema, 1};
-
- for(my $i=0; $i<@$schema;$i++) {
- my $item = $schema->[$i];
- if (ref $item) {
- next if $table->{$item};
- $table->{$item} = 1;
- if (UNIVERSAL::isa($item,'ARRAY')) {
- CleanSchema($item,$table);
- } elsif( UNIVERSAL::isa($item,'HASH')) {
- CleanSchema($item->{'syntax'},$table);
- }
- undef $schema->[$i];
- }
- }
-}
-
-
-sub OPT {
- return bless [@_], 'OPT';
-}
-
-sub SWITCH {
- return bless [@_], 'SWITCH';
-}
-
-sub REPEAT {
- return bless [@_], 'REPEAT';
-}
-
-$TransformDOMToBNF = sub {
- my ($nodeRoot) = @_;
-
- return [grep $_, map {
- my $nodeName = $_->nodeName;
- if (not $nodeName ){
- my $obj = $_;
- $obj->text() if (not( grep { $obj->text() eq $_} ('{', '}', '[', ']') ) );
- }elsif($nodeName eq 'name') {
- $_->text();
- } elsif ($nodeName eq 'separator') {
- OPT('separator');
- } elsif ($nodeName eq 'or_sep') {
- # nothing
- } elsif ($nodeName eq 'switch_part') {
- &$TransformDOMToBNF($_);
- } elsif ($nodeName eq 'class') {
- my $class = $_->childNodes->[0]->text();
-
- $class =~ s{(^<|>$|\\.|[\]\[])}{
- my $char = { '>' => '', '<' => '', '[' => '\\[', ']' => '\\]', '\\\\' => '\\\\'}->{$1};
- defined $char ? $char : ($1 =~ tr/\\// && $1);
- }ge;
- $class = '['.$class.']';
- $class .= $_->childNodes->[1]->text() if $_->childNodes->[1];
- 're:'.$class;
- } elsif ($nodeName eq 'symbol') {
- $_->text();
- } elsif ($nodeName eq 'simple') {
- @{&$TransformDOMToBNF($_)};
- } elsif ($nodeName eq 'multi_def') {
- @{&$TransformDOMToBNF($_)};
- } elsif ($nodeName eq 'optional') {
- my $multi_def = &$TransformDOMToBNF($_);
- if ($multi_def->[scalar(@{$multi_def})-1] eq '...') {
- pop @{$multi_def};
- OPT(REPEAT(@{$multi_def}));
- } else {
- OPT(@{$multi_def});
- }
- } elsif ($nodeName eq 'switch') {
- SWITCH(@{&$TransformDOMToBNF($_)});
- } elsif ($nodeName eq 'def') {
- @{&$TransformDOMToBNF($_)};
- } else{
- die "unknown nodeName: $nodeName";
- }
- } @{$nodeRoot->childNodes}];
-};
-
-$BNFSchema = {
- syntax => ['name',OPT('separator'),'::=',OPT('separator'),'def'],
- name => ['re:\\w+'],
- class => ['re:<([^<>\\\\]|\\\\.)+>',OPT('re:\\*|\\+|\\?|\\{\\d+\\}')],
- symbol => ['re:[^\\w\\d\\s\\[\\]{}<>\\\\|]+'],
- separator => ['re:\\s+'],
- simple => [
- SWITCH(
- 'name',
- 'class',
- 'symbol'
- )
- ],
- multi_def => [
- OPT('separator'), SWITCH('...',[SWITCH('simple','optional','switch'),OPT('multi_def')])
- ],
- optional => [
- '[','multi_def', OPT('separator') ,']'
-
- ],
- keyword => [],
- or_sep => ['|'],
- switch_part => [OPT('separator'),SWITCH('simple','optional','switch'),OPT(REPEAT(OPT('separator'),SWITCH('simple','optional','switch'))),OPT('separator')],
- switch => [
- '{','switch_part',OPT(REPEAT('or_sep','switch_part')),'}'
- ],
- def => [REPEAT(OPT('separator'),SWITCH('simple','optional','switch'))]
-};
-
-my $CompileTerm;
-$CompileTerm = sub {
- my ($term,$Schema,$cache,$ref) = @_;
-
- my $compiled = ref $term eq 'ARRAY' ? ($ref or []) : bless (($ref or []), ref $term);
-
- die new Exception("Invalid term type $term", $term, ref $term) if not grep ref $term eq $_, qw(ARRAY REPEAT SWITCH OPT);
-
- foreach my $element (@{$term}) {
- if (ref $element) {
- push @{$compiled}, &$CompileTerm($element,$Schema,$cache);
- } else {
- if($element =~/^\w+$/) {
- if (exists $Schema->{$element}) {
- # reference
- my $compiledUnit;
- if (exists $cache->{$element}) {
- $compiledUnit = $cache->{$element};
- } else {
- $compiledUnit = [];
- $cache->{$element} = $compiledUnit;
- &$CompileTerm($Schema->{$element},$Schema,$cache,$compiledUnit);
- }
-
- push @{$compiled},{ name => $element, syntax => $compiledUnit};
- } else {
- # simple word
- push @{$compiled}, $element;
- }
- } elsif ($element =~ /^re:(.*)/){
- # regexp
- push @{$compiled},qr/\G(?:$1)/;
- } else {
- # char sequence
- push @{$compiled},$element;
- }
- }
- }
-
- return $compiled;
-};
-
-sub CompileBNFSchema {
- my($Schema) = @_;
-
- my %Cache;
- return &$CompileTerm($Schema->{'syntax'},$Schema,\%Cache);
-}
-
-my $CompiledSchema = CompileBNFSchema($BNFSchema);
-
-$ParseAgainstSchema = sub {
- my ($Schema,$expression,$context,$flags,$level) = @_;
-
- $level = 0 if not defined $level;
- my $dbgPrint = $flags->{debug} ? sub {
- print "\t" x $level, @_,"\n";
- } : sub {};
-
- foreach my $elem (@{$Schema}) {
- my $type = ref $elem;
- $expression = substr $expression,pos($expression) if $type ne 'Regexp' and pos($expression);
-
- if ($type eq 'HASH') {
- $context->NewContext($elem->{'name'});
- &$dbgPrint("$elem->{name} ", join(',',map { ref $_ eq 'HASH' ? $_->{name} : $_ }@{$elem->{'syntax'}}));
- eval {
- $expression = &$ParseAgainstSchema($elem->{'syntax'},$expression,$context,$flags,$level+1);
- };
- if ($@) {
- $context->EndContext(0);
- &$dbgPrint("/$elem->{name} ", "0");
- die $@;
- } else {
- &$dbgPrint("/$elem->{name} ", "1");
- $context->EndContext(1);
- }
- } elsif ($type eq 'ARRAY') {
- &$dbgPrint("entering ", join(',',map { ref $_ eq 'HASH' ? $_->{name} : $_ }@{$elem}));
- $expression = &$ParseAgainstSchema($elem,$expression,$context,$flags,$level+1);
- &$dbgPrint("success");
- } elsif ($type eq 'OPT') {
- if (defined $expression) {
- &$dbgPrint("optional ",join(',',map { ref $_ eq 'HASH' ? $_->{name} : $_ }@{$elem}));
- eval {
- $expression = &$ParseAgainstSchema($elem,$expression,$context,$flags,$level+1);
- };
- if ($@) {
- &$dbgPrint("failed");
- undef $@;
- } else {
- &$dbgPrint("success");
- }
- }
- } elsif ($type eq 'SWITCH') {
- my $success = 0;
- &$dbgPrint("switch");
- LOOP_SWITCH: foreach my $subelem (@{$elem}) {
- eval {
- &$dbgPrint("\ttry ",join(',',map { ref $_ eq 'HASH' ? $_->{name} : $_ } @{(grep ref $subelem eq $_, qw(ARRAY SWITCH OPT REPEAT)) ? $subelem : [$subelem]}));
- $expression = &$ParseAgainstSchema((grep ref $subelem eq $_, qw(ARRAY SWITCH OPT REPEAT)) ? $subelem : [$subelem],$expression,$context,$flags,$level+1);
- $success = 1;
- };
- if ($@) {
- undef $@;
- } else {
- last LOOP_SWITCH;
- }
- }
- if ($success) {
- &$dbgPrint("success");
- } else {
- &$dbgPrint("failed");
- die ["syntax error",$expression,$elem];
- }
- } elsif ($type eq 'REPEAT') {
- my $copy = [@{$elem}];
- my $i = 0;
- &$dbgPrint("repeat ",join(',',map { ref $_ eq 'HASH' ? $_->{name} : $_ }@{$elem}));
- while (1) {
- eval {
- $expression = &$ParseAgainstSchema($copy,$expression,$context,$flags,$level+1);
- $i++;
- };
- if ($@) {
- if (not $i) {
- &$dbgPrint("failed");
- die $@;
- }
- &$dbgPrint("found $i matches");
- undef $@;
- last;
- }
- }
- } elsif ($type eq 'Regexp') {
- my $posPrev = pos($expression) || 0;
- if ( $expression =~ m/($elem)/ ) {
- $context->Data($1);
- pos($expression) = $posPrev+length($1);
- &$dbgPrint("Regexp: $1 $elem ", pos($expression));
- } else {
- &$dbgPrint("Regexp: $elem failed");
- die ["syntax error",$expression,$elem,$posPrev];
- pos($expression) = $posPrev;
- }
- } else {
- if ((my $val = substr($expression, 0, length($elem),'')) eq $elem) {
- &$dbgPrint("Scalar: $val");
- $context->Data($elem);
- } else {
- &$dbgPrint("Scalar: failed $val expected $elem");
- die ["syntax error",$val.$expression,$elem];
- }
- }
-
- }
-
- if (pos $expression) {
- return substr $expression,(pos($expression) || 0);
- } else {
- return $expression;
- }
-
-};
-
-package BNFCompiler::DOM::Node;
-use Common;
-our @ISA = qw(Object);
-
-sub NODE_TEXT { 1 }
-sub NODE_ELEM { 2 }
-
-BEGIN {
- DeclareProperty(nodeName => ACCESS_READ);
- DeclareProperty(nodeType => ACCESS_READ);
- DeclareProperty(nodeValue => ACCESS_READ);
- DeclareProperty(childNodes => ACCESS_READ);
- DeclareProperty(isComplex => ACCESS_READ);
-}
-
-sub CTOR {
- my ($this,%args) = @_;
- $args{'nodeType'} = NODE_ELEM if not $args{'nodeType'};
- die new Exception("Invalid args. nodeName reqired.") if $args{'nodeType'} == NODE_ELEM and not $args{nodeName};
-
- #for speed reason
- #$this->SUPER::CTOR(%args);
-
- $this->{$nodeName} = $args{'nodeName'} if $args{'nodeName'};
- $this->{$nodeType} = $args{'nodeType'};
- $this->{$nodeValue} = $args{'nodeValue'} if exists $args{'nodeValue'};
-
- $this->{$isComplex} = 0;
-}
-
-sub insertNode {
- my ($this,$node,$pos) = @_;
-
- die new Exception("Invalid operation on text node.") if $this->{$nodeType} != NODE_ELEM;
- die new Exception("Invalid node type",ref $node) if ref $node ne __PACKAGE__;
-
- $this->{$childNodes} = [] if not $this->{$childNodes};
-
- $pos = scalar(@{$this->{$childNodes}}) if not defined $pos;
- die new Exception("Index out of range",$pos) if $pos > scalar(@{$this->{$childNodes}}) or $pos < 0;
-
- splice @{$this->{$childNodes}},$pos,0,$node;
- $this->{$isComplex} = 1 if not $this->{$isComplex} and $node->{$nodeType} == NODE_ELEM;
-
- return $node;
-}
-
-sub removeNode {
- my ($this,$node) = @_;
-
- die new Exception("Invalid operation on text node.") if $this->{$nodeType} != NODE_ELEM;
- @{$this->{$childNodes}} = grep { $_ != $node } @{$this->{$childNodes}};
-
- return $node;
-}
-
-sub removeAt {
- my ($this,$pos) = @_;
-
- die new Exception("Invalid operation on text node.") if $this->{$nodeType} != NODE_ELEM;
- die new Exception("Index out of range",$pos) if $pos >= scalar(@{$this->{$childNodes}}) or $pos < 0;
-
- return splice @{$this->{$childNodes}},$pos,1;
-}
-
-sub selectNodes {
- my ($this,$name) = @_;
-
- die new Exception("Invalid operation on text node.") if $this->{$nodeType} != NODE_ELEM;
-
- my @nodes = grep { $_->{$nodeType} == NODE_ELEM and $_->{$nodeName} eq $name } @{$this->{$childNodes}};
-
- if (wantarray) {
- return @nodes;
- } else {
- return shift @nodes;
- }
-}
-
-sub text {
- my $this = shift;
-
- if ($this->{$nodeType} == NODE_TEXT) {
- return $this->{$nodeValue};
- } else {
- my @texts;
-
- foreach my $node (@{$this->{$childNodes}}) {
- push @texts, $node->{$nodeValue} if ($node->{$nodeType}==NODE_TEXT);
- }
-
- if (wantarray) {
- return @texts;
- } else {
- return join '',@texts;
- }
- }
-}
-
-package BNFCompiler::DOM::Builder;
-use Common;
-our @ISA=qw(Object);
-
-BEGIN {
- DeclareProperty(Document => ACCESS_READ);
- DeclareProperty(currentNode => ACCESS_NONE);
- DeclareProperty(stackNodes => ACCESS_NONE);
-}
-
-sub CTOR {
- my $this = shift;
-
- $this->{$Document} = new BNFCompiler::DOM::Node(nodeName => 'Document', nodeType => BNFCompiler::DOM::Node::NODE_ELEM);
- $this->{$currentNode} = $this->{$Document};
-}
-
-sub NewContext {
- my ($this,$contextName) = @_;
-
- push @{$this->{$stackNodes}},$this->{$currentNode};
- $this->{$currentNode} = new BNFCompiler::DOM::Node(nodeName => $contextName, nodeType=> BNFCompiler::DOM::Node::NODE_ELEM);
-
- return 1;
-}
-sub EndContext{
- my ($this,$isNotEmpty) = @_;
-
- if ($isNotEmpty) {
- my $child = $this->{$currentNode};
- $this->{$currentNode} = pop @{$this->{$stackNodes}};
- $this->{$currentNode}->insertNode($child);
- } else {
- $this->{$currentNode} = pop @{$this->{$stackNodes}};
- }
-}
-sub Data {
- my ($this,$data) = @_;
- $this->{$currentNode}->insertNode(new BNFCompiler::DOM::Node(nodeType=> BNFCompiler::DOM::Node::NODE_TEXT, nodeValue => $data));
-}
-
-package BNFCompiler::DOM;
-
-sub TransformDOMToHash {
- my ($root,$options) = @_;
-
- my %content;
-
- if (not $root->childNodes) {
- die;
- }
-
- foreach my $child (@{$root->childNodes}) {
- if ($child->nodeType == BNFCompiler::DOM::Node::NODE_ELEM) {
- my @newValue;
- my $nodeName = $child->nodeName;
- next if $nodeName eq 'separator' and $options->{'skip_spaces'};
- if ($child->isComplex) {
- $newValue[0] = TransformDOMToHash($child,$options);
- } else {
- @newValue = $child->text()
- }
-
- if ($options->{'use_arrays'}) {
- push @{$content{$nodeName}},@newValue;
- }
-
- if (exists $content{$nodeName}) {
- if (ref $content{$nodeName} eq 'ARRAY') {
- push @{$content{$nodeName}}, @newValue;
- } else {
- $content{$nodeName} = [$content{$nodeName},@newValue];
- }
- } else {
- $content{$nodeName} = $newValue[0] if scalar(@newValue) == 1;
- $content{$nodeName} = \@newValue if scalar(@newValue) > 1;
- }
- } else {
- next if $options->{'skip_text'};
- push @{$content{'_text'}},$child->nodeValue();
- }
- }
-
- return \%content;
-}
-
-1;
+package BNFCompiler;
+package BNFCompiler::DOM;
+package BNFCompiler::DOM::Builder;
+package BNFCompiler::DOM::Node;
+use strict;
+
+package BNFCompiler::EventParser;
+use strict;
+use lib '.';
+use Common;
+our @ISA = qw(Object);
+
+our $EventMapSchema = {
+ Description => 'Parser events',
+ Type => 'HASH',
+ Values => 'SCALAR'
+};
+
+BEGIN {
+ DeclareProperty(EventMap => ACCESS_READ);
+ DeclareProperty(CompiledEvents => ACCESS_NONE);
+ DeclareProperty(Handler => ACCESS_ALL);
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+ $this->SUPER::CTOR(%args);
+}
+
+sub Compile {
+ my ($this) = @_;
+
+ delete $this->{$CompiledEvents};
+ while (my ($key,$val) = each %{$this->{$EventMap}}) {
+ $this->{$CompiledEvents}{$key} = qr/\G$val/;
+ }
+ 1;
+}
+
+sub Parse {
+ my ($this,$data) = @_;
+
+ my $StateData;
+ OUTER: while(pos($data) < length($data)) {
+ keys %{$this->{$CompiledEvents}};
+ while (my ($event,$match) = each %{$this->{$CompiledEvents}}) {
+ if ($data =~ m/($match)/gc) {
+ $StateData .= $1;
+ eval {
+ undef $StateData if $this->{$Handler}->($event,$StateData);
+ };
+ if ($@) {
+ die ["Invalid syntax","unexpected $event: $1",pos($data)];
+ }
+ next OUTER;
+ }
+ }
+ die ["Invalid syntax",substr($data,pos($data),10),pos($data)];
+ }
+
+ return 1;
+}
+
+# небольшая уловка, поскольку ref от регулярного выражения есть Regexp, можно поставить хуки
+package Regexp;
+use Data::Dumper;
+
+sub STORABLE_freeze {
+ my ($obj,$cloning) = @_;
+
+ return $obj;
+}
+
+sub STORABLE_attach {
+ my($class, $cloning, $serialized) = @_;
+ return qr/$serialized/;
+}
+
+package BNFCompiler;
+use Common;
+use Storable;
+use Data::Dumper;
+our @ISA = qw(Object);
+
+our $BNFSchema;
+my $ParseAgainstSchema;
+my $TransformDOMToBNF;
+
+BEGIN {
+ DeclareProperty(Schema => ACCESS_NONE);
+ DeclareProperty(SchemaCache => ACCESS_NONE);
+ DeclareProperty(Transform => ACCESS_NONE);
+}
+
+sub CTOR {
+ my $this = shift;
+ $this->SUPER::CTOR(@_);
+
+ $this->{$SchemaCache} .= '/' if ($this->{$SchemaCache} and not $this->{$SchemaCache} =~ /\/$/);
+}
+{
+ my $compiledBNFSchema;
+ sub LoadBNFSchema {
+ my ($this,%args) = @_;
+
+ my $CompileBNFText = sub {
+ my ($this,$text) = @_;
+
+ my %SchemaDOM;
+ foreach my $item (split /\n{2,}/, $text) {
+ next if not $item;
+ $compiledBNFSchema = CompileBNFSchema($BNFSchema) if not $compiledBNFSchema;
+ my $context = new BNFCompiler::DOM::Builder();
+ eval {
+ my $expr = &$ParseAgainstSchema($compiledBNFSchema,$item,$context);
+ die ["Unexpected expression", $expr] if $expr;
+ };
+ if ($@) {
+ if (ref $@ eq 'ARRAY') {
+ die new Exception(@{$@});
+ } else {
+ die $@;
+ }
+ }
+
+ $SchemaDOM{$context->Document->selectNodes('name')->text()} = &$TransformDOMToBNF($context->Document->selectNodes('def'));
+
+ }
+
+ $SchemaDOM{'separator'} = ['re:\\s+'];
+ $this->{$Schema} = CompileBNFSchema(\%SchemaDOM);
+ };
+
+ my $text;
+ if ($args{'file'}) {
+
+ my $fnameCached;
+ if ($this->{$SchemaCache}) {
+ my $fname = $args{'file'};
+ $fname =~ tr/\//_/;
+ $fnameCached = $this->{$SchemaCache}.$fname.'.cbs';
+ if ( -e $fnameCached && -f $fnameCached && ( -M $args{'file'} >= -M $fnameCached )) {
+ my $compiledSchema = retrieve($fnameCached);
+ if ($compiledSchema) {
+ $this->{$Schema} = $compiledSchema;
+ return 1;
+ } else {
+ unlink $fnameCached;
+ }
+ }
+ }
+ open my $hFile, '<', $args{'file'} or die new Exception("Failed to open file",$args{'file'},$!);
+ local $/ = undef;
+ my $text = <$hFile>;
+
+ $this->$CompileBNFText($text);
+
+ if ($fnameCached) {
+ store($this->{$Schema},$fnameCached);
+ }
+ } elsif ($args{'Schema'}) {
+ $this->{$Schema} = CompileBNFSchema($args{'Schema'});
+ return 1;
+ } elsif ($args{'text'}) {
+ $this->$CompileBNFText( $args{'text'} );
+ } else {
+ die new Exception("'file', 'text' or 'Schema' parameter required");
+ }
+
+ }
+}
+
+sub Parse {
+ my ($this, $string, %flags) = @_;
+
+ my $context = new BNFCompiler::DOM::Builder;
+
+ eval {
+ my $err;
+ $err = &$ParseAgainstSchema($this->{$Schema},$string,$context,\%flags) and die new Exception('Failed to parse',substr($err,0,80).' ...');
+ };
+ if ($@) {
+ if (ref $@ eq 'ARRAY') {
+ die new Exception(@{$@});
+ } else {
+ die $@;
+ }
+ }
+ if (not $this->{$Transform}) {
+ return $context->Document;
+ } else {
+ return $this->{$Transform}->($context->Document);
+ }
+}
+
+sub Dispose {
+ my ($this) = shift;
+ CleanSchema($this->{$Schema});
+ delete @$this{$Schema, $Transform};
+ $this->SUPER::Dispose;
+}
+
+sub CleanSchema {
+ my ($schema,$table) = @_;
+
+ UNIVERSAL::isa($schema,'ARRAY') or return;
+ $table or $table = { $schema, 1};
+
+ for(my $i=0; $i<@$schema;$i++) {
+ my $item = $schema->[$i];
+ if (ref $item) {
+ next if $table->{$item};
+ $table->{$item} = 1;
+ if (UNIVERSAL::isa($item,'ARRAY')) {
+ CleanSchema($item,$table);
+ } elsif( UNIVERSAL::isa($item,'HASH')) {
+ CleanSchema($item->{'syntax'},$table);
+ }
+ undef $schema->[$i];
+ }
+ }
+}
+
+
+sub OPT {
+ return bless [@_], 'OPT';
+}
+
+sub SWITCH {
+ return bless [@_], 'SWITCH';
+}
+
+sub REPEAT {
+ return bless [@_], 'REPEAT';
+}
+
+$TransformDOMToBNF = sub {
+ my ($nodeRoot) = @_;
+
+ return [grep $_, map {
+ my $nodeName = $_->nodeName;
+ if (not $nodeName ){
+ my $obj = $_;
+ $obj->text() if (not( grep { $obj->text() eq $_} ('{', '}', '[', ']') ) );
+ }elsif($nodeName eq 'name') {
+ $_->text();
+ } elsif ($nodeName eq 'separator') {
+ OPT('separator');
+ } elsif ($nodeName eq 'or_sep') {
+ # nothing
+ } elsif ($nodeName eq 'switch_part') {
+ &$TransformDOMToBNF($_);
+ } elsif ($nodeName eq 'class') {
+ my $class = $_->childNodes->[0]->text();
+
+ $class =~ s{(^<|>$|\\.|[\]\[])}{
+ my $char = { '>' => '', '<' => '', '[' => '\\[', ']' => '\\]', '\\\\' => '\\\\'}->{$1};
+ defined $char ? $char : ($1 =~ tr/\\// && $1);
+ }ge;
+ $class = '['.$class.']';
+ $class .= $_->childNodes->[1]->text() if $_->childNodes->[1];
+ 're:'.$class;
+ } elsif ($nodeName eq 'symbol') {
+ $_->text();
+ } elsif ($nodeName eq 'simple') {
+ @{&$TransformDOMToBNF($_)};
+ } elsif ($nodeName eq 'multi_def') {
+ @{&$TransformDOMToBNF($_)};
+ } elsif ($nodeName eq 'optional') {
+ my $multi_def = &$TransformDOMToBNF($_);
+ if ($multi_def->[scalar(@{$multi_def})-1] eq '...') {
+ pop @{$multi_def};
+ OPT(REPEAT(@{$multi_def}));
+ } else {
+ OPT(@{$multi_def});
+ }
+ } elsif ($nodeName eq 'switch') {
+ SWITCH(@{&$TransformDOMToBNF($_)});
+ } elsif ($nodeName eq 'def') {
+ @{&$TransformDOMToBNF($_)};
+ } else{
+ die "unknown nodeName: $nodeName";
+ }
+ } @{$nodeRoot->childNodes}];
+};
+
+$BNFSchema = {
+ syntax => ['name',OPT('separator'),'::=',OPT('separator'),'def'],
+ name => ['re:\\w+'],
+ class => ['re:<([^<>\\\\]|\\\\.)+>',OPT('re:\\*|\\+|\\?|\\{\\d+\\}')],
+ symbol => ['re:[^\\w\\d\\s\\[\\]{}<>\\\\|]+'],
+ separator => ['re:\\s+'],
+ simple => [
+ SWITCH(
+ 'name',
+ 'class',
+ 'symbol'
+ )
+ ],
+ multi_def => [
+ OPT('separator'), SWITCH('...',[SWITCH('simple','optional','switch'),OPT('multi_def')])
+ ],
+ optional => [
+ '[','multi_def', OPT('separator') ,']'
+
+ ],
+ keyword => [],
+ or_sep => ['|'],
+ switch_part => [OPT('separator'),SWITCH('simple','optional','switch'),OPT(REPEAT(OPT('separator'),SWITCH('simple','optional','switch'))),OPT('separator')],
+ switch => [
+ '{','switch_part',OPT(REPEAT('or_sep','switch_part')),'}'
+ ],
+ def => [REPEAT(OPT('separator'),SWITCH('simple','optional','switch'))]
+};
+
+my $CompileTerm;
+$CompileTerm = sub {
+ my ($term,$Schema,$cache,$ref) = @_;
+
+ my $compiled = ref $term eq 'ARRAY' ? ($ref or []) : bless (($ref or []), ref $term);
+
+ die new Exception("Invalid term type $term", $term, ref $term) if not grep ref $term eq $_, qw(ARRAY REPEAT SWITCH OPT);
+
+ foreach my $element (@{$term}) {
+ if (ref $element) {
+ push @{$compiled}, &$CompileTerm($element,$Schema,$cache);
+ } else {
+ if($element =~/^\w+$/) {
+ if (exists $Schema->{$element}) {
+ # reference
+ my $compiledUnit;
+ if (exists $cache->{$element}) {
+ $compiledUnit = $cache->{$element};
+ } else {
+ $compiledUnit = [];
+ $cache->{$element} = $compiledUnit;
+ &$CompileTerm($Schema->{$element},$Schema,$cache,$compiledUnit);
+ }
+
+ push @{$compiled},{ name => $element, syntax => $compiledUnit};
+ } else {
+ # simple word
+ push @{$compiled}, $element;
+ }
+ } elsif ($element =~ /^re:(.*)/){
+ # regexp
+ push @{$compiled},qr/\G(?:$1)/;
+ } else {
+ # char sequence
+ push @{$compiled},$element;
+ }
+ }
+ }
+
+ return $compiled;
+};
+
+sub CompileBNFSchema {
+ my($Schema) = @_;
+
+ my %Cache;
+ return &$CompileTerm($Schema->{'syntax'},$Schema,\%Cache);
+}
+
+my $CompiledSchema = CompileBNFSchema($BNFSchema);
+
+$ParseAgainstSchema = sub {
+ my ($Schema,$expression,$context,$flags,$level) = @_;
+
+ $level = 0 if not defined $level;
+ my $dbgPrint = $flags->{debug} ? sub {
+ print "\t" x $level, @_,"\n";
+ } : sub {};
+
+ foreach my $elem (@{$Schema}) {
+ my $type = ref $elem;
+ $expression = substr $expression,pos($expression) if $type ne 'Regexp' and pos($expression);
+
+ if ($type eq 'HASH') {
+ $context->NewContext($elem->{'name'});
+ &$dbgPrint("$elem->{name} ", join(',',map { ref $_ eq 'HASH' ? $_->{name} : $_ }@{$elem->{'syntax'}}));
+ eval {
+ $expression = &$ParseAgainstSchema($elem->{'syntax'},$expression,$context,$flags,$level+1);
+ };
+ if ($@) {
+ $context->EndContext(0);
+ &$dbgPrint("/$elem->{name} ", "0");
+ die $@;
+ } else {
+ &$dbgPrint("/$elem->{name} ", "1");
+ $context->EndContext(1);
+ }
+ } elsif ($type eq 'ARRAY') {
+ &$dbgPrint("entering ", join(',',map { ref $_ eq 'HASH' ? $_->{name} : $_ }@{$elem}));
+ $expression = &$ParseAgainstSchema($elem,$expression,$context,$flags,$level+1);
+ &$dbgPrint("success");
+ } elsif ($type eq 'OPT') {
+ if (defined $expression) {
+ &$dbgPrint("optional ",join(',',map { ref $_ eq 'HASH' ? $_->{name} : $_ }@{$elem}));
+ eval {
+ $expression = &$ParseAgainstSchema($elem,$expression,$context,$flags,$level+1);
+ };
+ if ($@) {
+ &$dbgPrint("failed");
+ undef $@;
+ } else {
+ &$dbgPrint("success");
+ }
+ }
+ } elsif ($type eq 'SWITCH') {
+ my $success = 0;
+ &$dbgPrint("switch");
+ LOOP_SWITCH: foreach my $subelem (@{$elem}) {
+ eval {
+ &$dbgPrint("\ttry ",join(',',map { ref $_ eq 'HASH' ? $_->{name} : $_ } @{(grep ref $subelem eq $_, qw(ARRAY SWITCH OPT REPEAT)) ? $subelem : [$subelem]}));
+ $expression = &$ParseAgainstSchema((grep ref $subelem eq $_, qw(ARRAY SWITCH OPT REPEAT)) ? $subelem : [$subelem],$expression,$context,$flags,$level+1);
+ $success = 1;
+ };
+ if ($@) {
+ undef $@;
+ } else {
+ last LOOP_SWITCH;
+ }
+ }
+ if ($success) {
+ &$dbgPrint("success");
+ } else {
+ &$dbgPrint("failed");
+ die ["syntax error",$expression,$elem];
+ }
+ } elsif ($type eq 'REPEAT') {
+ my $copy = [@{$elem}];
+ my $i = 0;
+ &$dbgPrint("repeat ",join(',',map { ref $_ eq 'HASH' ? $_->{name} : $_ }@{$elem}));
+ while (1) {
+ eval {
+ $expression = &$ParseAgainstSchema($copy,$expression,$context,$flags,$level+1);
+ $i++;
+ };
+ if ($@) {
+ if (not $i) {
+ &$dbgPrint("failed");
+ die $@;
+ }
+ &$dbgPrint("found $i matches");
+ undef $@;
+ last;
+ }
+ }
+ } elsif ($type eq 'Regexp') {
+ my $posPrev = pos($expression) || 0;
+ if ( $expression =~ m/($elem)/ ) {
+ $context->Data($1);
+ pos($expression) = $posPrev+length($1);
+ &$dbgPrint("Regexp: $1 $elem ", pos($expression));
+ } else {
+ &$dbgPrint("Regexp: $elem failed");
+ die ["syntax error",$expression,$elem,$posPrev];
+ pos($expression) = $posPrev;
+ }
+ } else {
+ if ((my $val = substr($expression, 0, length($elem),'')) eq $elem) {
+ &$dbgPrint("Scalar: $val");
+ $context->Data($elem);
+ } else {
+ &$dbgPrint("Scalar: failed $val expected $elem");
+ die ["syntax error",$val.$expression,$elem];
+ }
+ }
+
+ }
+
+ if (pos $expression) {
+ return substr $expression,(pos($expression) || 0);
+ } else {
+ return $expression;
+ }
+
+};
+
+package BNFCompiler::DOM::Node;
+use Common;
+our @ISA = qw(Object);
+
+sub NODE_TEXT { 1 }
+sub NODE_ELEM { 2 }
+
+BEGIN {
+ DeclareProperty(nodeName => ACCESS_READ);
+ DeclareProperty(nodeType => ACCESS_READ);
+ DeclareProperty(nodeValue => ACCESS_READ);
+ DeclareProperty(childNodes => ACCESS_READ);
+ DeclareProperty(isComplex => ACCESS_READ);
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+ $args{'nodeType'} = NODE_ELEM if not $args{'nodeType'};
+ die new Exception("Invalid args. nodeName reqired.") if $args{'nodeType'} == NODE_ELEM and not $args{nodeName};
+
+ #for speed reason
+ #$this->SUPER::CTOR(%args);
+
+ $this->{$nodeName} = $args{'nodeName'} if $args{'nodeName'};
+ $this->{$nodeType} = $args{'nodeType'};
+ $this->{$nodeValue} = $args{'nodeValue'} if exists $args{'nodeValue'};
+
+ $this->{$isComplex} = 0;
+}
+
+sub insertNode {
+ my ($this,$node,$pos) = @_;
+
+ die new Exception("Invalid operation on text node.") if $this->{$nodeType} != NODE_ELEM;
+ die new Exception("Invalid node type",ref $node) if ref $node ne __PACKAGE__;
+
+ $this->{$childNodes} = [] if not $this->{$childNodes};
+
+ $pos = scalar(@{$this->{$childNodes}}) if not defined $pos;
+ die new Exception("Index out of range",$pos) if $pos > scalar(@{$this->{$childNodes}}) or $pos < 0;
+
+ splice @{$this->{$childNodes}},$pos,0,$node;
+ $this->{$isComplex} = 1 if not $this->{$isComplex} and $node->{$nodeType} == NODE_ELEM;
+
+ return $node;
+}
+
+sub removeNode {
+ my ($this,$node) = @_;
+
+ die new Exception("Invalid operation on text node.") if $this->{$nodeType} != NODE_ELEM;
+ @{$this->{$childNodes}} = grep { $_ != $node } @{$this->{$childNodes}};
+
+ return $node;
+}
+
+sub removeAt {
+ my ($this,$pos) = @_;
+
+ die new Exception("Invalid operation on text node.") if $this->{$nodeType} != NODE_ELEM;
+ die new Exception("Index out of range",$pos) if $pos >= scalar(@{$this->{$childNodes}}) or $pos < 0;
+
+ return splice @{$this->{$childNodes}},$pos,1;
+}
+
+sub selectNodes {
+ my ($this,$name) = @_;
+
+ die new Exception("Invalid operation on text node.") if $this->{$nodeType} != NODE_ELEM;
+
+ my @nodes = grep { $_->{$nodeType} == NODE_ELEM and $_->{$nodeName} eq $name } @{$this->{$childNodes}};
+
+ if (wantarray) {
+ return @nodes;
+ } else {
+ return shift @nodes;
+ }
+}
+
+sub text {
+ my $this = shift;
+
+ if ($this->{$nodeType} == NODE_TEXT) {
+ return $this->{$nodeValue};
+ } else {
+ my @texts;
+
+ foreach my $node (@{$this->{$childNodes}}) {
+ push @texts, $node->{$nodeValue} if ($node->{$nodeType}==NODE_TEXT);
+ }
+
+ if (wantarray) {
+ return @texts;
+ } else {
+ return join '',@texts;
+ }
+ }
+}
+
+package BNFCompiler::DOM::Builder;
+use Common;
+our @ISA=qw(Object);
+
+BEGIN {
+ DeclareProperty(Document => ACCESS_READ);
+ DeclareProperty(currentNode => ACCESS_NONE);
+ DeclareProperty(stackNodes => ACCESS_NONE);
+}
+
+sub CTOR {
+ my $this = shift;
+
+ $this->{$Document} = new BNFCompiler::DOM::Node(nodeName => 'Document', nodeType => BNFCompiler::DOM::Node::NODE_ELEM);
+ $this->{$currentNode} = $this->{$Document};
+}
+
+sub NewContext {
+ my ($this,$contextName) = @_;
+
+ push @{$this->{$stackNodes}},$this->{$currentNode};
+ $this->{$currentNode} = new BNFCompiler::DOM::Node(nodeName => $contextName, nodeType=> BNFCompiler::DOM::Node::NODE_ELEM);
+
+ return 1;
+}
+sub EndContext{
+ my ($this,$isNotEmpty) = @_;
+
+ if ($isNotEmpty) {
+ my $child = $this->{$currentNode};
+ $this->{$currentNode} = pop @{$this->{$stackNodes}};
+ $this->{$currentNode}->insertNode($child);
+ } else {
+ $this->{$currentNode} = pop @{$this->{$stackNodes}};
+ }
+}
+sub Data {
+ my ($this,$data) = @_;
+ $this->{$currentNode}->insertNode(new BNFCompiler::DOM::Node(nodeType=> BNFCompiler::DOM::Node::NODE_TEXT, nodeValue => $data));
+}
+
+package BNFCompiler::DOM;
+
+sub TransformDOMToHash {
+ my ($root,$options) = @_;
+
+ my %content;
+
+ if (not $root->childNodes) {
+ die;
+ }
+
+ foreach my $child (@{$root->childNodes}) {
+ if ($child->nodeType == BNFCompiler::DOM::Node::NODE_ELEM) {
+ my @newValue;
+ my $nodeName = $child->nodeName;
+ next if $nodeName eq 'separator' and $options->{'skip_spaces'};
+ if ($child->isComplex) {
+ $newValue[0] = TransformDOMToHash($child,$options);
+ } else {
+ @newValue = $child->text()
+ }
+
+ if ($options->{'use_arrays'}) {
+ push @{$content{$nodeName}},@newValue;
+ }
+
+ if (exists $content{$nodeName}) {
+ if (ref $content{$nodeName} eq 'ARRAY') {
+ push @{$content{$nodeName}}, @newValue;
+ } else {
+ $content{$nodeName} = [$content{$nodeName},@newValue];
+ }
+ } else {
+ $content{$nodeName} = $newValue[0] if scalar(@newValue) == 1;
+ $content{$nodeName} = \@newValue if scalar(@newValue) > 1;
+ }
+ } else {
+ next if $options->{'skip_text'};
+ push @{$content{'_text'}},$child->nodeValue();
+ }
+ }
+
+ return \%content;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/CDBI/Map.pm
--- a/Lib/CDBI/Map.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/CDBI/Map.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,110 +1,110 @@
-package CDBI::Map;
-use strict;
-use Common;
-
-BEGIN {
- DeclareProperty _Cache => ACCESS_NONE;
- DeclareProperty _HoldingType => ACCESS_NONE;
-}
-
-sub _KeyValuePairClass {
- my $this = shift;
- ($this->{$_HoldingType} = ref $this ) =~ s/^((?:\w+::)*)Map(\w+)$/${1}MapItem${2}/ unless $this->{$_HoldingType};
- return $this->{$_HoldingType};
-}
-
-# при загрузке кеша нельзя грузить KeyValuePair поскольку получатся циклические ссылки:(
-sub GetCache {
- my $this = shift;
-
- if (not $this->{$_Cache}) {
- $this->{$_Cache} = { map { $_->ItemKey, { id => $_->id, value => $_->Value} } $this->_KeyValuePairClass->search(Parent => $this) };
- }
-
- return $this->{$_Cache};
-}
-
-sub Keys {
- my $this = shift;
- return wantarray ? keys %{$this->GetCache} : [keys %{$this->GetCache}];
-}
-
-sub Item {
- my ($this,$key,$value,%options) = @_;
-
- die new Exception('A key must be specified') unless defined $key;
-
- if (@_ > 2) {
- # set
- if (my $pairInfo = $this->GetCache->{$key}) {
- # update
- my $pair = $this->_KeyValuePairClass->retrieve($pairInfo->{id});
- if (defined $value or $options{'keepnull'}) {
- $pair->Value($value);
- $pair->update;
- $pairInfo->{value} = $value;
- } else {
- #delete
- $pair->delete;
- delete $this->GetCache->{$key};
- }
- } else {
- if ( defined $value or $options{'keepnull'}) {
- my $pair = $this->_KeyValuePairClass->insert( {Parent => $this, ItemKey => $key, Value => $value } );
- $this->GetCache->{$key} = {id => $pair->id, value => $value };
- }
- }
- return $value;
- } else {
- # get
- if (my $pairInfo = $this->GetCache->{$key}) {
- return $pairInfo->{value};
- } else {
- return undef;
- }
- }
-}
-
-sub Delete {
- my ($this,$key) = @_;
-
- if (my $pair = $this->GetCache->{$key} ) {
- $pair->delete;
- delete $this->GetCache->{$key};
- return 1;
- }
- return 0;
-}
-
-sub Has {
- my ($this,$key) = @_;
-
- return exists $this->GetCache->{$key};
-}
-
-1;
-__END__
-=pod
-=head1 SYNOPSIS
-package App::CDBI;
-use base 'Class::DBI';
-
-#....
-
-package App::MapString;
-use base 'Class::DBI','CDBI::Map';
-
-#....
-
-
-my $Map = App::MapString->retrieve($id);
-print $Map->Item('key');
-$Map->Item('key','value');
-$Map->Delete('key');
-print "the $key is found" if $Map->Has($key);
-
-=head1 DESCRIPTION
-
-Provides a set of methods to manipulate with Maps;
-
-=cut
\ No newline at end of file
+package CDBI::Map;
+use strict;
+use Common;
+
+BEGIN {
+ DeclareProperty _Cache => ACCESS_NONE;
+ DeclareProperty _HoldingType => ACCESS_NONE;
+}
+
+sub _KeyValuePairClass {
+ my $this = shift;
+ ($this->{$_HoldingType} = ref $this ) =~ s/^((?:\w+::)*)Map(\w+)$/${1}MapItem${2}/ unless $this->{$_HoldingType};
+ return $this->{$_HoldingType};
+}
+
+# при загрузке кеша нельзя грузить KeyValuePair поскольку получатся циклические ссылки:(
+sub GetCache {
+ my $this = shift;
+
+ if (not $this->{$_Cache}) {
+ $this->{$_Cache} = { map { $_->ItemKey, { id => $_->id, value => $_->Value} } $this->_KeyValuePairClass->search(Parent => $this) };
+ }
+
+ return $this->{$_Cache};
+}
+
+sub Keys {
+ my $this = shift;
+ return wantarray ? keys %{$this->GetCache} : [keys %{$this->GetCache}];
+}
+
+sub Item {
+ my ($this,$key,$value,%options) = @_;
+
+ die new Exception('A key must be specified') unless defined $key;
+
+ if (@_ > 2) {
+ # set
+ if (my $pairInfo = $this->GetCache->{$key}) {
+ # update
+ my $pair = $this->_KeyValuePairClass->retrieve($pairInfo->{id});
+ if (defined $value or $options{'keepnull'}) {
+ $pair->Value($value);
+ $pair->update;
+ $pairInfo->{value} = $value;
+ } else {
+ #delete
+ $pair->delete;
+ delete $this->GetCache->{$key};
+ }
+ } else {
+ if ( defined $value or $options{'keepnull'}) {
+ my $pair = $this->_KeyValuePairClass->insert( {Parent => $this, ItemKey => $key, Value => $value } );
+ $this->GetCache->{$key} = {id => $pair->id, value => $value };
+ }
+ }
+ return $value;
+ } else {
+ # get
+ if (my $pairInfo = $this->GetCache->{$key}) {
+ return $pairInfo->{value};
+ } else {
+ return undef;
+ }
+ }
+}
+
+sub Delete {
+ my ($this,$key) = @_;
+
+ if (my $pair = $this->GetCache->{$key} ) {
+ $pair->delete;
+ delete $this->GetCache->{$key};
+ return 1;
+ }
+ return 0;
+}
+
+sub Has {
+ my ($this,$key) = @_;
+
+ return exists $this->GetCache->{$key};
+}
+
+1;
+__END__
+=pod
+=head1 SYNOPSIS
+package App::CDBI;
+use base 'Class::DBI';
+
+#....
+
+package App::MapString;
+use base 'Class::DBI','CDBI::Map';
+
+#....
+
+
+my $Map = App::MapString->retrieve($id);
+print $Map->Item('key');
+$Map->Item('key','value');
+$Map->Delete('key');
+print "the $key is found" if $Map->Has($key);
+
+=head1 DESCRIPTION
+
+Provides a set of methods to manipulate with Maps;
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/CDBI/Meta.pm
--- a/Lib/CDBI/Meta.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/CDBI/Meta.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,20 +1,20 @@
-package CDBI::Meta::BindingAttribute;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-
-BEGIN {
- public _direct property Binding => prop_get;
- public _direct property Name => prop_get;
-}
-
-sub CTOR {
- my ($this,$name,$binding) = @_;
- $this->{$Binding} = $binding;
- $this->{$Name} = $name;
-}
-
-1;
+package CDBI::Meta::BindingAttribute;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+
+BEGIN {
+ public _direct property Binding => prop_get;
+ public _direct property Name => prop_get;
+}
+
+sub CTOR {
+ my ($this,$name,$binding) = @_;
+ $this->{$Binding} = $binding;
+ $this->{$Name} = $name;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/CDBI/Transform.pm
--- a/Lib/CDBI/Transform.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/CDBI/Transform.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,105 +1,105 @@
-package CDBI::Transform::FormToObject;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object::Autofill Form::Transform );
-use IMPL::Class::Property;
-require IMPL::Exception;
-
-BEGIN {
- public property Class => prop_all;
- public property Namespace => prop_all;
-}
-
-sub CTOR {
- my $this = shift;
- $this->superCTOR(@_);
-
- die new IMPL::InvalidArgumentException('Class is required') unless $this->Class;
-}
-
-sub TransformContainer {
- my ($this,$container) = @_;
-
- my $class;
- if ($container->Name eq 'Form') {
- $class = $this->Class;
- } else {
- $class = $this->_mk_class($container->Attributes->{'cdbi.class'}) or die new IMPL::Exception('cdbi.class isn\'t specified',$container->Id->Canonical);
- }
-
- my %data;
-
- #my %columns = map {$_,1} $class->columns();
-
- no strict 'refs';
- my @accessors = map $_->accessor, $class->columns();# grep $columns{lc $_}, keys %{"${class}::"};
-
- # формируем из контейнера формы данные для объекта
- foreach my $column ( @accessors, 'id' ) {
- my ($val) = $container->GetChild($column);
- $data{$column} = $this->Transform($val) if $val;
- }
-
- my $obj;
- if ($data{id}) {
- # edit value
-
-
- $obj = $class->validateId($data{id});
- my %filter = map { $_, $obj->$_()} @accessors;
- $filter{$_} = $data{$_} foreach keys %data;
- my ($newObj) = $class->lookup(\%data);
- die new IMPL::DuplicateException('The object already exists', $class) if ($newObj and $newObj->id != $data{id});
-
- $obj->$_($data{$_}) foreach keys %data;
- $obj->update();
- } else {
- # new instance
- die new IMPL::DuplicateException('The object already exists', $class) if $class->lookup(\%data);
- $obj = $class->insert(\%data);
- }
- return $obj;
-}
-
-sub _mk_class {
- my ($this,$name) = @_;
-
- return unless $name;
- return $name if $name =~ /::/;
- return $this->Namespace ? $this->Namespace."::$name" : $name;
-}
-
-package CDBI::Transform::ObjectToForm;
-use base qw(IMPL::Transform);
-
-use IMPL::Class::Property;
-
-sub CTOR {
- my $this = shift;
-
- $this->superCTOR(
- Default => \&TransformObject,
- Plain => sub { my ($this,$val) = @_; return $val; }
- );
-}
-
-sub TransformObject {
- my ($this,$object) = @_;
-
- return $object if not ref $object;
-
- my %data;
- foreach my $column ( (map $_->accessor,$object->columns()),'id') {
- my $value = $object->$column();
-
- if (ref $value eq 'HASH') {
- $data{"$column/$_"} = $value->{$_} foreach keys %$value;
- } else {
- $data{$column} = $value;
- }
- }
-
- return \%data;
-}
-1;
+package CDBI::Transform::FormToObject;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object::Autofill Form::Transform );
+use IMPL::Class::Property;
+require IMPL::Exception;
+
+BEGIN {
+ public property Class => prop_all;
+ public property Namespace => prop_all;
+}
+
+sub CTOR {
+ my $this = shift;
+ $this->superCTOR(@_);
+
+ die new IMPL::InvalidArgumentException('Class is required') unless $this->Class;
+}
+
+sub TransformContainer {
+ my ($this,$container) = @_;
+
+ my $class;
+ if ($container->Name eq 'Form') {
+ $class = $this->Class;
+ } else {
+ $class = $this->_mk_class($container->Attributes->{'cdbi.class'}) or die new IMPL::Exception('cdbi.class isn\'t specified',$container->Id->Canonical);
+ }
+
+ my %data;
+
+ #my %columns = map {$_,1} $class->columns();
+
+ no strict 'refs';
+ my @accessors = map $_->accessor, $class->columns();# grep $columns{lc $_}, keys %{"${class}::"};
+
+ # формируем из контейнера формы данные для объекта
+ foreach my $column ( @accessors, 'id' ) {
+ my ($val) = $container->GetChild($column);
+ $data{$column} = $this->Transform($val) if $val;
+ }
+
+ my $obj;
+ if ($data{id}) {
+ # edit value
+
+
+ $obj = $class->validateId($data{id});
+ my %filter = map { $_, $obj->$_()} @accessors;
+ $filter{$_} = $data{$_} foreach keys %data;
+ my ($newObj) = $class->lookup(\%data);
+ die new IMPL::DuplicateException('The object already exists', $class) if ($newObj and $newObj->id != $data{id});
+
+ $obj->$_($data{$_}) foreach keys %data;
+ $obj->update();
+ } else {
+ # new instance
+ die new IMPL::DuplicateException('The object already exists', $class) if $class->lookup(\%data);
+ $obj = $class->insert(\%data);
+ }
+ return $obj;
+}
+
+sub _mk_class {
+ my ($this,$name) = @_;
+
+ return unless $name;
+ return $name if $name =~ /::/;
+ return $this->Namespace ? $this->Namespace."::$name" : $name;
+}
+
+package CDBI::Transform::ObjectToForm;
+use base qw(IMPL::Transform);
+
+use IMPL::Class::Property;
+
+sub CTOR {
+ my $this = shift;
+
+ $this->superCTOR(
+ Default => \&TransformObject,
+ Plain => sub { my ($this,$val) = @_; return $val; }
+ );
+}
+
+sub TransformObject {
+ my ($this,$object) = @_;
+
+ return $object if not ref $object;
+
+ my %data;
+ foreach my $column ( (map $_->accessor,$object->columns()),'id') {
+ my $value = $object->$column();
+
+ if (ref $value eq 'HASH') {
+ $data{"$column/$_"} = $value->{$_} foreach keys %$value;
+ } else {
+ $data{$column} = $value;
+ }
+ }
+
+ return \%data;
+}
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Common.pm
--- a/Lib/Common.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Common.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,282 +1,282 @@
-package Common;
-use strict;
-no strict 'refs';
-
-require Exporter;
-
-our @ISA = qw(Exporter);
-our @EXPORT = qw(&ACCESS_NONE &ACCESS_READ &ACCESS_WRITE &ACCESS_ALL &DeclareProperty &DumpCaller &PropertyList &CloneObject);
-
-our $Debug;
-
-$Debug = 1 if not defined $Debug;
-
-my %ListProperties;
-my %GlobalContext;
-
-1;
-
-sub ACCESS_NONE () { 0 }
-sub ACCESS_READ () { 1 }
-sub ACCESS_WRITE () { 2 }
-sub ACCESS_ALL () {ACCESS_READ | ACCESS_WRITE}
-
-sub PropertyList {
- return $ListProperties{ref($_[0]) || $_[0] || caller} || {};
-}
-
-sub DeclareProperty {
- my ($attrName,$accessRights,%Mutators) = @_;
-
- my $Package = caller;
- my $Method = $Package.'::'.$attrName;
- my $fldName;
-
- my $getMutator = $Mutators{'get'};
- my $setMutator = $Mutators{'set'};
-
- ($fldName = $Method) =~ s/:+/_/g;
-
- $ListProperties{$Package} = {} if not exists $ListProperties{$Package};
- $ListProperties{$Package}->{$attrName} = $fldName;
-
- if ($Debug) {
- *$Method = sub {
- my $this = shift;
-
- die new Exception( 'too many args ['.scalar(@_).'\]' , "'$Method' called from: ".DumpCaller() ) if (@_ > 1);
-
- my $Rights = $accessRights;
- $Rights = ACCESS_ALL if $Package eq caller;
-
- if (@_){
- die new Exception("access denied 'write $Method'", "'$Method' called from: ".DumpCaller()) if not $Rights & ACCESS_WRITE;
- if (defined $setMutator) {
- &$setMutator($this,$fldName,shift);
- } else {
- $this->{$fldName} = $_[0];
- }
-
- } elsif (defined wantarray) {
- die new Exception("access denied 'read $Method'", "'$Method' called from: ".DumpCaller()) if not $Rights & ACCESS_READ;
- if (defined $getMutator) {
- &$getMutator($this,$fldName);
- } else {
- if (wantarray){
- if(ref $this->{$fldName} eq 'ARRAY' ) {
- return @{$this->{$fldName}};
- } elsif (not exists $this->{$fldName}) {
- return;
- } else {
- return $this->{$fldName};
- }
- } else {
- return $this->{$fldName};
- }
- }
- } else {
- undef;
- }
- };
- *$Method = \$fldName;
- } else {
- *$Method = sub {
- my $this = shift;
- #return undef if @_ > 1;
- #my $Rights = $accessRights;
- #$Rights = ACCESS_ALL if $Package eq caller;
-
- if (@_){
- # return undef if not $Rights & ACCESS_WRITE;
- if (defined $setMutator) {
- &$setMutator($this,$fldName,shift);
- } else {
- $this->{$fldName} = shift;
- }
- } elsif (defined wantarray) {
- # return undef if not $Rights & ACCESS_READ;
- if (defined $getMutator) {
- &$getMutator($this,$fldName);
- } else {
- if (wantarray){
- if(ref $this->{$fldName} eq 'ARRAY' ) {
- return @{$this->{$fldName}};
- } elsif (not defined $this->{$fldName}) {
- return;
- } else {
- return $this->{$fldName};
- }
- } else {
- return $this->{$fldName};
- }
- }
- } else {
- undef;
- }
- };
- *$Method = \$fldName;
- }
-}
-
-sub DumpCaller {
- return join(" ",(caller($_[0]))[1,2],(caller($_[0]+1))[3]);
-}
-
-sub Owner {
- return undef if not tied $_[0];
- return undef if not tied($_[0])->UNIVERSAL::can('owner');
- return tied($_[0])->owner();
-};
-
-sub CloneObject {
- my $object = shift;
- if (ref $object == undef) {
- return $object;
- } elsif (ref $object eq 'SCALAR') {
- return \CloneObject(${$object});
- } elsif (ref $object eq 'ARRAY') {
- return [map{CloneObject($_)}@{$object}];
- } elsif (ref $object eq 'HASH') {
- my %clone;
- while (my ($key,$value) = each %{$object}) {
- $clone{$key} = CloneObject($value);
- }
- return \%clone;
- } elsif (ref $object eq 'REF') {
- return \CloneObject(${$object});
- } else {
- if ($object->can('Clone')) {
- return $object->Clone();
- } else {
- die new Exception('Object doesn\'t supports cloning');
- }
- }
-}
-
-package Exception;
-use base qw(IMPL::Exception);
-
-package Persistent;
-import Common;
-
-sub newSurogate {
- my $class = ref($_[0]) || $_[0];
- return bless {}, $class;
-}
-sub load {
- my ($this,$context) = @_;
- die new Exception("invalid deserialization context") if ref($context) ne 'ARRAY';
- die new Exception("This is not an object") if not ref $this;
-
- my %Props = (@{$context});
- foreach my $BaseClass(@{ref($this).'::ISA'}) {
- while (my ($key,$value) = each %{PropertyList($BaseClass)}) {
- $this->{$value} = $Props{$value} if exists $Props{$value};
- }
- }
-
- while (my ($key,$value) = each %{PropertyList(ref($this))}) {
- $this->{$value} = $Props{$key} if exists $Props{$key};
- }
- return 1;
-}
-sub save {
- my ($this,$context) = @_;
-
- foreach my $BaseClass(@{ref($this).'::ISA'}) {
- while (my ($key,$value) = each %{PropertyList($BaseClass)}) {
- $context->AddVar($value,$this->{$value});
- }
- }
-
- while (my ($key,$value) = each %{PropertyList(ref($this))}) {
- $context->AddVar($key,$this->{$value});
- }
- return 1;
-}
-
-sub restore {
- my ($class,$context,$surogate) = @_;
- my $this = $surogate || $class->newNewSurogate;
- $this->load($context);
- return $this;
-}
-
-package Object;
-import Common;
-
-sub new {
- my $class = shift;
- my $self = bless {}, ref($class) || $class;
- $self->CTOR(@_);
- return $self;
-}
-
-sub cast {
- return bless {}, ref $_[0] || $_[0];
-}
-
-our %objects_count;
-our %leaked_objects;
-
-sub CTOR {
- my $this= shift;
- $objects_count{ref $this} ++ if $Debug;
- my %args = @_ if scalar (@_) > 0;
- return if scalar(@_) == 0;
-
- warn "invalid args in CTOR. type: ".(ref $this) if scalar(@_) % 2 != 0;
- my @packages = (ref($this));
- my $countArgs = int(scalar(@_) / 2);
- #print "Set ", join(', ',keys %args), "\n";
- LOOP_PACKS: while(@packages) {
- my $package = shift @packages;
- #print "\t$package\n";
- my $refProps = PropertyList($package);
- foreach my $name (keys %{$refProps}) {
- my $fld = $refProps->{$name};
- if (exists $args{$name}) {
- $this->{$fld} = $args{$name};
- #print "\t$countArgs, $name\n";
- delete $args{$name};
- $countArgs --;
- last LOOP_PACKS if $countArgs < 1;
- } else {
- #print "\t-$name ($fld)\n";
- }
- }
- push @packages, @{$package.'::ISA'};
- }
-}
-
-sub Dispose {
- my $this = shift;
-
- if ($Debug and UNIVERSAL::isa($this,'HASH')) {
- my @keys = grep { $this->{$_} and ref $this->{$_} } keys %{$this};
- warn "not all fields of the object were deleted\n".join("\n",@keys) if @keys;
- }
-
- bless $this,'Object::Disposed';
-}
-
-our $MemoryLeakProtection;
-
-sub DESTROY {
- if ($MemoryLeakProtection) {
- my $this = shift;
- warn sprintf("Object leaks: %s of type %s %s",$this,ref $this,UNIVERSAL::can($this,'_dump') ? $this->_dump : '');
- }
-}
-
-package Object::Disposed;
-our $AUTOLOAD;
-sub AUTOLOAD {
- return if $AUTOLOAD eq __PACKAGE__.'::DESTROY';
- die new Exception('Object have been disposed',$AUTOLOAD);
-}
-
-END {
- $MemoryLeakProtection = 0 if not $Debug;
-}
-1;
\ No newline at end of file
+package Common;
+use strict;
+no strict 'refs';
+
+require Exporter;
+
+our @ISA = qw(Exporter);
+our @EXPORT = qw(&ACCESS_NONE &ACCESS_READ &ACCESS_WRITE &ACCESS_ALL &DeclareProperty &DumpCaller &PropertyList &CloneObject);
+
+our $Debug;
+
+$Debug = 1 if not defined $Debug;
+
+my %ListProperties;
+my %GlobalContext;
+
+1;
+
+sub ACCESS_NONE () { 0 }
+sub ACCESS_READ () { 1 }
+sub ACCESS_WRITE () { 2 }
+sub ACCESS_ALL () {ACCESS_READ | ACCESS_WRITE}
+
+sub PropertyList {
+ return $ListProperties{ref($_[0]) || $_[0] || caller} || {};
+}
+
+sub DeclareProperty {
+ my ($attrName,$accessRights,%Mutators) = @_;
+
+ my $Package = caller;
+ my $Method = $Package.'::'.$attrName;
+ my $fldName;
+
+ my $getMutator = $Mutators{'get'};
+ my $setMutator = $Mutators{'set'};
+
+ ($fldName = $Method) =~ s/:+/_/g;
+
+ $ListProperties{$Package} = {} if not exists $ListProperties{$Package};
+ $ListProperties{$Package}->{$attrName} = $fldName;
+
+ if ($Debug) {
+ *$Method = sub {
+ my $this = shift;
+
+ die new Exception( 'too many args ['.scalar(@_).'\]' , "'$Method' called from: ".DumpCaller() ) if (@_ > 1);
+
+ my $Rights = $accessRights;
+ $Rights = ACCESS_ALL if $Package eq caller;
+
+ if (@_){
+ die new Exception("access denied 'write $Method'", "'$Method' called from: ".DumpCaller()) if not $Rights & ACCESS_WRITE;
+ if (defined $setMutator) {
+ &$setMutator($this,$fldName,shift);
+ } else {
+ $this->{$fldName} = $_[0];
+ }
+
+ } elsif (defined wantarray) {
+ die new Exception("access denied 'read $Method'", "'$Method' called from: ".DumpCaller()) if not $Rights & ACCESS_READ;
+ if (defined $getMutator) {
+ &$getMutator($this,$fldName);
+ } else {
+ if (wantarray){
+ if(ref $this->{$fldName} eq 'ARRAY' ) {
+ return @{$this->{$fldName}};
+ } elsif (not exists $this->{$fldName}) {
+ return;
+ } else {
+ return $this->{$fldName};
+ }
+ } else {
+ return $this->{$fldName};
+ }
+ }
+ } else {
+ undef;
+ }
+ };
+ *$Method = \$fldName;
+ } else {
+ *$Method = sub {
+ my $this = shift;
+ #return undef if @_ > 1;
+ #my $Rights = $accessRights;
+ #$Rights = ACCESS_ALL if $Package eq caller;
+
+ if (@_){
+ # return undef if not $Rights & ACCESS_WRITE;
+ if (defined $setMutator) {
+ &$setMutator($this,$fldName,shift);
+ } else {
+ $this->{$fldName} = shift;
+ }
+ } elsif (defined wantarray) {
+ # return undef if not $Rights & ACCESS_READ;
+ if (defined $getMutator) {
+ &$getMutator($this,$fldName);
+ } else {
+ if (wantarray){
+ if(ref $this->{$fldName} eq 'ARRAY' ) {
+ return @{$this->{$fldName}};
+ } elsif (not defined $this->{$fldName}) {
+ return;
+ } else {
+ return $this->{$fldName};
+ }
+ } else {
+ return $this->{$fldName};
+ }
+ }
+ } else {
+ undef;
+ }
+ };
+ *$Method = \$fldName;
+ }
+}
+
+sub DumpCaller {
+ return join(" ",(caller($_[0]))[1,2],(caller($_[0]+1))[3]);
+}
+
+sub Owner {
+ return undef if not tied $_[0];
+ return undef if not tied($_[0])->UNIVERSAL::can('owner');
+ return tied($_[0])->owner();
+};
+
+sub CloneObject {
+ my $object = shift;
+ if (ref $object == undef) {
+ return $object;
+ } elsif (ref $object eq 'SCALAR') {
+ return \CloneObject(${$object});
+ } elsif (ref $object eq 'ARRAY') {
+ return [map{CloneObject($_)}@{$object}];
+ } elsif (ref $object eq 'HASH') {
+ my %clone;
+ while (my ($key,$value) = each %{$object}) {
+ $clone{$key} = CloneObject($value);
+ }
+ return \%clone;
+ } elsif (ref $object eq 'REF') {
+ return \CloneObject(${$object});
+ } else {
+ if ($object->can('Clone')) {
+ return $object->Clone();
+ } else {
+ die new Exception('Object doesn\'t supports cloning');
+ }
+ }
+}
+
+package Exception;
+use base qw(IMPL::Exception);
+
+package Persistent;
+import Common;
+
+sub newSurogate {
+ my $class = ref($_[0]) || $_[0];
+ return bless {}, $class;
+}
+sub load {
+ my ($this,$context) = @_;
+ die new Exception("invalid deserialization context") if ref($context) ne 'ARRAY';
+ die new Exception("This is not an object") if not ref $this;
+
+ my %Props = (@{$context});
+ foreach my $BaseClass(@{ref($this).'::ISA'}) {
+ while (my ($key,$value) = each %{PropertyList($BaseClass)}) {
+ $this->{$value} = $Props{$value} if exists $Props{$value};
+ }
+ }
+
+ while (my ($key,$value) = each %{PropertyList(ref($this))}) {
+ $this->{$value} = $Props{$key} if exists $Props{$key};
+ }
+ return 1;
+}
+sub save {
+ my ($this,$context) = @_;
+
+ foreach my $BaseClass(@{ref($this).'::ISA'}) {
+ while (my ($key,$value) = each %{PropertyList($BaseClass)}) {
+ $context->AddVar($value,$this->{$value});
+ }
+ }
+
+ while (my ($key,$value) = each %{PropertyList(ref($this))}) {
+ $context->AddVar($key,$this->{$value});
+ }
+ return 1;
+}
+
+sub restore {
+ my ($class,$context,$surogate) = @_;
+ my $this = $surogate || $class->newNewSurogate;
+ $this->load($context);
+ return $this;
+}
+
+package Object;
+import Common;
+
+sub new {
+ my $class = shift;
+ my $self = bless {}, ref($class) || $class;
+ $self->CTOR(@_);
+ return $self;
+}
+
+sub cast {
+ return bless {}, ref $_[0] || $_[0];
+}
+
+our %objects_count;
+our %leaked_objects;
+
+sub CTOR {
+ my $this= shift;
+ $objects_count{ref $this} ++ if $Debug;
+ my %args = @_ if scalar (@_) > 0;
+ return if scalar(@_) == 0;
+
+ warn "invalid args in CTOR. type: ".(ref $this) if scalar(@_) % 2 != 0;
+ my @packages = (ref($this));
+ my $countArgs = int(scalar(@_) / 2);
+ #print "Set ", join(', ',keys %args), "\n";
+ LOOP_PACKS: while(@packages) {
+ my $package = shift @packages;
+ #print "\t$package\n";
+ my $refProps = PropertyList($package);
+ foreach my $name (keys %{$refProps}) {
+ my $fld = $refProps->{$name};
+ if (exists $args{$name}) {
+ $this->{$fld} = $args{$name};
+ #print "\t$countArgs, $name\n";
+ delete $args{$name};
+ $countArgs --;
+ last LOOP_PACKS if $countArgs < 1;
+ } else {
+ #print "\t-$name ($fld)\n";
+ }
+ }
+ push @packages, @{$package.'::ISA'};
+ }
+}
+
+sub Dispose {
+ my $this = shift;
+
+ if ($Debug and UNIVERSAL::isa($this,'HASH')) {
+ my @keys = grep { $this->{$_} and ref $this->{$_} } keys %{$this};
+ warn "not all fields of the object were deleted\n".join("\n",@keys) if @keys;
+ }
+
+ bless $this,'Object::Disposed';
+}
+
+our $MemoryLeakProtection;
+
+sub DESTROY {
+ if ($MemoryLeakProtection) {
+ my $this = shift;
+ warn sprintf("Object leaks: %s of type %s %s",$this,ref $this,UNIVERSAL::can($this,'_dump') ? $this->_dump : '');
+ }
+}
+
+package Object::Disposed;
+our $AUTOLOAD;
+sub AUTOLOAD {
+ return if $AUTOLOAD eq __PACKAGE__.'::DESTROY';
+ die new Exception('Object have been disposed',$AUTOLOAD);
+}
+
+END {
+ $MemoryLeakProtection = 0 if not $Debug;
+}
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Configuration.pm
--- a/Lib/Configuration.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Configuration.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,37 +1,37 @@
-package Configuration;
-use strict;
-
-my $Configured = 0;
-
-sub import {
- my ($class,$site) = @_;
-
- if ($site and $site ne $Configured) {
- Configure($site);
- $Configured = $site;
- } elsif (not $site and not $Configured) {
- $Configured = 1;
- require Configuration::Global;
- }
-}
-
-our %virtualSite;
-
-sub Configure {
- my $siteName = shift;
- require Configuration::Global;
-
- while ( my ($pattern,$configSite) = each %virtualSite) {
- next if not $siteName =~ $pattern;
- if (ref $configSite eq 'CODE') {
- $configSite->();
- } elsif (not ref $configSite and $configSite) {
- require $configSite;
- }
- last;
- }
-}
-
-
-
-1;
+package Configuration;
+use strict;
+
+my $Configured = 0;
+
+sub import {
+ my ($class,$site) = @_;
+
+ if ($site and $site ne $Configured) {
+ Configure($site);
+ $Configured = $site;
+ } elsif (not $site and not $Configured) {
+ $Configured = 1;
+ require Configuration::Global;
+ }
+}
+
+our %virtualSite;
+
+sub Configure {
+ my $siteName = shift;
+ require Configuration::Global;
+
+ while ( my ($pattern,$configSite) = each %virtualSite) {
+ next if not $siteName =~ $pattern;
+ if (ref $configSite eq 'CODE') {
+ $configSite->();
+ } elsif (not ref $configSite and $configSite) {
+ require $configSite;
+ }
+ last;
+ }
+}
+
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/DOM.pm
--- a/Lib/DOM.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/DOM.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,19 +1,19 @@
-package DOM;
-require DOM::Site;
-use Common;
-
-my $GlobalSite;
-
-sub Site {
- my $self = shift;
-
- $GlobalSite = construct DOM::Site if not $GlobalSite;
- return $GlobalSite;
-}
-
-sub Cleanup {
- $GlobalSite->Dispose if $GlobalSite;
- undef $GlobalSite;
-}
-
-1;
\ No newline at end of file
+package DOM;
+require DOM::Site;
+use Common;
+
+my $GlobalSite;
+
+sub Site {
+ my $self = shift;
+
+ $GlobalSite = construct DOM::Site if not $GlobalSite;
+ return $GlobalSite;
+}
+
+sub Cleanup {
+ $GlobalSite->Dispose if $GlobalSite;
+ undef $GlobalSite;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/DOM/Page.pm
--- a/Lib/DOM/Page.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/DOM/Page.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,241 +1,241 @@
-package DOM::Page;
-use Common;
-use Template::Context;
-use strict;
-
-our @ISA = qw(Object);
-our $AUTOLOAD;
-
-BEGIN {
- DeclareProperty(Title => ACCESS_ALL);
- DeclareProperty(NavChain => ACCESS_READ);
- DeclareProperty(Menus => ACCESS_READ);
- DeclareProperty(Properties => ACCESS_READ);
- DeclareProperty(Template => ACCESS_READ);
- DeclareProperty(TemplatesProvider => ACCESS_NONE);
- DeclareProperty(Site => ACCESS_READ);
-}
-
-sub CTOR {
- my ($this,%args) = @_;
- $this->{$Site} = $args{'Site'};
- $this->{$TemplatesProvider} = $args{'TemplatesProvider'};
- $this->{$Properties} = $args{'Properties'} || {};
- $this->{$Title} = $args{'Template'}->Title() || $args{'Properties'}->{'Title'};
- $this->{$Template} = $args{'Template'};
- $this->{$NavChain} = $args{'NavChain'};
- $this->{$Menus} = $args{'Menus'};
-}
-
-sub Render {
- my ($this,$hOut) = @_;
-
- my $context = new Template::Context({
- VARIABLES => $this->{$Site}->Objects(),
- LOAD_TEMPLATES => $this->{$TemplatesProvider}
- });
-
- print $hOut $this->{$Template}->process($context);
-}
-
-sub Dispose {
- my ($this) = @_;
-
- undef %$this;
-
- $this->SUPER::Dispose;
-}
-
-sub Container {
- my ($this) = @_;
- my $nav = $this->{$NavChain};
- return $nav->[@{$nav}-1];
-}
-
-sub AUTOLOAD {
- my $this = shift;
-
- my $name = $AUTOLOAD;
- $name =~ s/.*://;
-
- return $this->{$Properties}->{$name};
-}
-
-=pod
-Меню
- [
- Элемент меню
- {
- Key => Ключ пункта меню, для быстрого обращения к элементу и слиянии меню
- Name => Имя пункта меню, которое будет видель пользователь
- Expand => флаг того, что меню выбрано
- Value => {[ элемент меню ...] | что-то еще, обычно урл}
- }
- ]
-=cut
-
-package DOM::PageMenu;
-use Common;
-
-our @ISA = qw(Object);
-
-BEGIN {
- DeclareProperty('Items'); # массив
- DeclareProperty('Keys'); # ключи для пунктов меню, если таковые имеются
-}
-
-sub CTOR {
- my ($this,%args) = @_;
- if (ref $args{'DATA'} eq 'ARRAY') {
- foreach my $item (@{$args{'DATA'}}) {
- if (ref $item eq 'HASH') {
- $this->Append($item->{'Name'},_ProcessData($item->{'Value'}), Expand => $item->{'Expand'}, Key => $item->{'Key'}, Url => $item->{'Url'});
- } elsif (ref $item eq 'ARRAY') {
- $this->Append($item->[0],_ProcessData($item->[1]), Expand => $item->[2], Key => $item->[3], Url => $item->[4]);
- }
- }
- }
-}
-
-sub Item {
- my ($this,$index) = @_;
-
- return $this->{$Items}[$index];
-}
-
-sub ItemByKey {
- my ($this,$key) = @_;
-
- return $this->{$Keys}->{$key};
-}
-
-sub InsertBefore {
- my ($this,$index,$name,$data,%options) = @_;
-
- my $item = {Name => $name, Value => _ProcessData($data), %options};
- splice @{$this->{$Items}},$index,0,$item;
-
- if ($options{'Key'}) {
- $this->{$Keys}->{$options{'Key'}} = $item;
- }
-}
-
-sub Append {
- my ($this,$name,$data,%options) = @_;
-
- my $item = {Name => $name, Value => _ProcessData($data), %options};
-
- push @{$this->{$Items}},$item;
-
- if ($options{'Key'}) {
- $this->{$Keys}->{$options{'Key'}} = $item;
- }
-}
-
-sub SubMenu {
- my ($this,$path) = @_;
- my $item = $this;
- foreach my $key ( split /\/+/,$path ) {
- $item = $item->{$Keys}->{$key};
- if (not $item ) {
- die new Exception('Item does\'t exist', $path, $key);
- }
- $item = $item->{Value};
- if (not UNIVERSAL::isa($item,'DOM::PageMenu')) {
- $item = ($this->{$Keys}->{$key}->{Value} = new DOM::PageMenu());
- }
- }
-
- return $item;
-}
-
-sub Dump {
- use Data::Dumper;
-
- return Dumper(shift);
-}
-
-sub AppendItem {
- my ($this,$item) = @_;
-
- push @{$this->{$Items}},$item;
-
- if ($item->{'Key'}) {
- $this->{$Keys}->{$item->{'Key'}} = $item;
- }
-}
-
-sub RemoveAt {
- my ($this,$index) = @_;
-
- my $item = splice @{$this->{$Items}},$index,1;
-
- if ($item->{'Key'}) {
- delete $this->{$Keys}->{$item->{'Key'}};
- }
-
- return 1;
-}
-
-sub ItemsCount {
- my $this = shift;
- return scalar(@{$this->{$Items}});
-}
-
-sub Sort {
- my $this = shift;
-
- $this->{$Items} = \sort { $a->{'Name'} <=> $b->{'Name'} } @{$this->{$Items}};
-
- return 1;
-}
-
-sub as_list {
- my $this = shift;
- return $this->{$Items} || [];
-}
-
-sub Merge {
- my ($this,$that) = @_;
-
- foreach my $itemThat ($that->Items) {
- my $itemThis = $itemThat->{'Key'} ? $this->{$Keys}->{$itemThat->{'Key'}} : undef;
- if ($itemThis) {
- $this->MergeItems($itemThis,$itemThat);
- } else {
- $this->AppendItem($itemThat);
- }
- }
-}
-
-sub MergeItems {
- my ($this,$itemLeft,$itemRight) = @_;
-
- while (my ($prop,$value) = each %{$itemRight}) {
- if ($prop eq 'Value') {
- if (UNIVERSAL::isa($itemLeft->{$prop},__PACKAGE__) && UNIVERSAL::isa($value,__PACKAGE__)) {
- $itemLeft->{$prop}->Merge($value);
- } else {
- $itemLeft->{$prop} = $value if defined $value;
- }
- } else {
- $itemLeft->{$prop} = $value if defined $value;
- }
- }
-
- return 1;
-}
-
-sub _ProcessData {
- my $refData = shift;
-
- if (ref $refData eq 'ARRAY') {
- return new DOM::PageMenu(DATA => $refData);
- } else {
- return $refData;
- }
-}
-
-
-
-1;
+package DOM::Page;
+use Common;
+use Template::Context;
+use strict;
+
+our @ISA = qw(Object);
+our $AUTOLOAD;
+
+BEGIN {
+ DeclareProperty(Title => ACCESS_ALL);
+ DeclareProperty(NavChain => ACCESS_READ);
+ DeclareProperty(Menus => ACCESS_READ);
+ DeclareProperty(Properties => ACCESS_READ);
+ DeclareProperty(Template => ACCESS_READ);
+ DeclareProperty(TemplatesProvider => ACCESS_NONE);
+ DeclareProperty(Site => ACCESS_READ);
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+ $this->{$Site} = $args{'Site'};
+ $this->{$TemplatesProvider} = $args{'TemplatesProvider'};
+ $this->{$Properties} = $args{'Properties'} || {};
+ $this->{$Title} = $args{'Template'}->Title() || $args{'Properties'}->{'Title'};
+ $this->{$Template} = $args{'Template'};
+ $this->{$NavChain} = $args{'NavChain'};
+ $this->{$Menus} = $args{'Menus'};
+}
+
+sub Render {
+ my ($this,$hOut) = @_;
+
+ my $context = new Template::Context({
+ VARIABLES => $this->{$Site}->Objects(),
+ LOAD_TEMPLATES => $this->{$TemplatesProvider}
+ });
+
+ print $hOut $this->{$Template}->process($context);
+}
+
+sub Dispose {
+ my ($this) = @_;
+
+ undef %$this;
+
+ $this->SUPER::Dispose;
+}
+
+sub Container {
+ my ($this) = @_;
+ my $nav = $this->{$NavChain};
+ return $nav->[@{$nav}-1];
+}
+
+sub AUTOLOAD {
+ my $this = shift;
+
+ my $name = $AUTOLOAD;
+ $name =~ s/.*://;
+
+ return $this->{$Properties}->{$name};
+}
+
+=pod
+Меню
+ [
+ Элемент меню
+ {
+ Key => Ключ пункта меню, для быстрого обращения к элементу и слиянии меню
+ Name => Имя пункта меню, которое будет видель пользователь
+ Expand => флаг того, что меню выбрано
+ Value => {[ элемент меню ...] | что-то еще, обычно урл}
+ }
+ ]
+=cut
+
+package DOM::PageMenu;
+use Common;
+
+our @ISA = qw(Object);
+
+BEGIN {
+ DeclareProperty('Items'); # массив
+ DeclareProperty('Keys'); # ключи для пунктов меню, если таковые имеются
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+ if (ref $args{'DATA'} eq 'ARRAY') {
+ foreach my $item (@{$args{'DATA'}}) {
+ if (ref $item eq 'HASH') {
+ $this->Append($item->{'Name'},_ProcessData($item->{'Value'}), Expand => $item->{'Expand'}, Key => $item->{'Key'}, Url => $item->{'Url'});
+ } elsif (ref $item eq 'ARRAY') {
+ $this->Append($item->[0],_ProcessData($item->[1]), Expand => $item->[2], Key => $item->[3], Url => $item->[4]);
+ }
+ }
+ }
+}
+
+sub Item {
+ my ($this,$index) = @_;
+
+ return $this->{$Items}[$index];
+}
+
+sub ItemByKey {
+ my ($this,$key) = @_;
+
+ return $this->{$Keys}->{$key};
+}
+
+sub InsertBefore {
+ my ($this,$index,$name,$data,%options) = @_;
+
+ my $item = {Name => $name, Value => _ProcessData($data), %options};
+ splice @{$this->{$Items}},$index,0,$item;
+
+ if ($options{'Key'}) {
+ $this->{$Keys}->{$options{'Key'}} = $item;
+ }
+}
+
+sub Append {
+ my ($this,$name,$data,%options) = @_;
+
+ my $item = {Name => $name, Value => _ProcessData($data), %options};
+
+ push @{$this->{$Items}},$item;
+
+ if ($options{'Key'}) {
+ $this->{$Keys}->{$options{'Key'}} = $item;
+ }
+}
+
+sub SubMenu {
+ my ($this,$path) = @_;
+ my $item = $this;
+ foreach my $key ( split /\/+/,$path ) {
+ $item = $item->{$Keys}->{$key};
+ if (not $item ) {
+ die new Exception('Item does\'t exist', $path, $key);
+ }
+ $item = $item->{Value};
+ if (not UNIVERSAL::isa($item,'DOM::PageMenu')) {
+ $item = ($this->{$Keys}->{$key}->{Value} = new DOM::PageMenu());
+ }
+ }
+
+ return $item;
+}
+
+sub Dump {
+ use Data::Dumper;
+
+ return Dumper(shift);
+}
+
+sub AppendItem {
+ my ($this,$item) = @_;
+
+ push @{$this->{$Items}},$item;
+
+ if ($item->{'Key'}) {
+ $this->{$Keys}->{$item->{'Key'}} = $item;
+ }
+}
+
+sub RemoveAt {
+ my ($this,$index) = @_;
+
+ my $item = splice @{$this->{$Items}},$index,1;
+
+ if ($item->{'Key'}) {
+ delete $this->{$Keys}->{$item->{'Key'}};
+ }
+
+ return 1;
+}
+
+sub ItemsCount {
+ my $this = shift;
+ return scalar(@{$this->{$Items}});
+}
+
+sub Sort {
+ my $this = shift;
+
+ $this->{$Items} = \sort { $a->{'Name'} <=> $b->{'Name'} } @{$this->{$Items}};
+
+ return 1;
+}
+
+sub as_list {
+ my $this = shift;
+ return $this->{$Items} || [];
+}
+
+sub Merge {
+ my ($this,$that) = @_;
+
+ foreach my $itemThat ($that->Items) {
+ my $itemThis = $itemThat->{'Key'} ? $this->{$Keys}->{$itemThat->{'Key'}} : undef;
+ if ($itemThis) {
+ $this->MergeItems($itemThis,$itemThat);
+ } else {
+ $this->AppendItem($itemThat);
+ }
+ }
+}
+
+sub MergeItems {
+ my ($this,$itemLeft,$itemRight) = @_;
+
+ while (my ($prop,$value) = each %{$itemRight}) {
+ if ($prop eq 'Value') {
+ if (UNIVERSAL::isa($itemLeft->{$prop},__PACKAGE__) && UNIVERSAL::isa($value,__PACKAGE__)) {
+ $itemLeft->{$prop}->Merge($value);
+ } else {
+ $itemLeft->{$prop} = $value if defined $value;
+ }
+ } else {
+ $itemLeft->{$prop} = $value if defined $value;
+ }
+ }
+
+ return 1;
+}
+
+sub _ProcessData {
+ my $refData = shift;
+
+ if (ref $refData eq 'ARRAY') {
+ return new DOM::PageMenu(DATA => $refData);
+ } else {
+ return $refData;
+ }
+}
+
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/DOM/Providers/Form.pm
--- a/Lib/DOM/Providers/Form.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/DOM/Providers/Form.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,49 +1,49 @@
-package Configuration;
-our $DataDir;
-package DOM::Providers::Form;
-use strict;
-use Form;
-use Schema::Form;
-use Common;
-our @ISA = qw(Object);
-
-our $Encoding ;
-our $CacheDir ||= "${DataDir}Cache/";
-warn "The encoding for the DOM::Provider::Form isn't specified" if not $Encoding;
-$Encoding ||= 'utf-8';
-
-sub GetProviderInfo {
- return {
- Name => 'Form',
- Host => 'DOM::Site',
- Methods => {
- LoadForm => \&SiteLoadForm
- }
- }
-}
-
-BEGIN {
- DeclareProperty FormsEncoding => ACCESS_READ;
- DeclareProperty DataCacheDir => ACCESS_READ;
-}
-
-sub SiteLoadForm {
- my ($this,$site,$file,$form) = @_;
- return $site->RegisterObject('Form',$this->LoadForm($file,$form));
-}
-
-sub LoadForm {
- my ($this,$file, $formName) = @_;
-
- my $formSchema = Schema::Form->LoadForms($file,$this->{$DataCacheDir},$this->{$FormsEncoding})->{$formName} or die new Exception('The form isn\'t found',$formName,$file);
- return Form->new($formSchema);
-}
-
-sub construct {
- my ($class) = @_;
-
- return $class->new(FormsEncoding => $Encoding, DataCacheDir => $CacheDir);
-}
-
-
-1;
+package Configuration;
+our $DataDir;
+package DOM::Providers::Form;
+use strict;
+use Form;
+use Schema::Form;
+use Common;
+our @ISA = qw(Object);
+
+our $Encoding ;
+our $CacheDir ||= "${DataDir}Cache/";
+warn "The encoding for the DOM::Provider::Form isn't specified" if not $Encoding;
+$Encoding ||= 'utf-8';
+
+sub GetProviderInfo {
+ return {
+ Name => 'Form',
+ Host => 'DOM::Site',
+ Methods => {
+ LoadForm => \&SiteLoadForm
+ }
+ }
+}
+
+BEGIN {
+ DeclareProperty FormsEncoding => ACCESS_READ;
+ DeclareProperty DataCacheDir => ACCESS_READ;
+}
+
+sub SiteLoadForm {
+ my ($this,$site,$file,$form) = @_;
+ return $site->RegisterObject('Form',$this->LoadForm($file,$form));
+}
+
+sub LoadForm {
+ my ($this,$file, $formName) = @_;
+
+ my $formSchema = Schema::Form->LoadForms($file,$this->{$DataCacheDir},$this->{$FormsEncoding})->{$formName} or die new Exception('The form isn\'t found',$formName,$file);
+ return Form->new($formSchema);
+}
+
+sub construct {
+ my ($class) = @_;
+
+ return $class->new(FormsEncoding => $Encoding, DataCacheDir => $CacheDir);
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/DOM/Providers/Gallery.pm
--- a/Lib/DOM/Providers/Gallery.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/DOM/Providers/Gallery.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,200 +1,200 @@
-use strict;
-package DOM::Gallery;
-use Common;
-our @ISA = qw(Object);
-
-BEGIN {
- DeclareProperty(Id => ACCESS_READ);
- DeclareProperty(Name => ACCESS_READ);
- DeclareProperty(Description => ACCESS_READ);
- DeclareProperty(Images => ACCESS_READ);
- DeclareProperty(CurrentImage => ACCESS_READ);
- DeclareProperty(NextImage => ACCESS_READ);
- DeclareProperty(PrevImage => ACCESS_READ);
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$Id} = $args{'Id'};
- $this->{$Name} = $args{'Name'};
- $this->{$Description} = $args{'Description'};
-}
-
-sub GroupList {
- my ($this,$GroupCount, $option) = @_;
-
- my @images = map { $this->{$Images}->{$_} } sort keys %{$this->{$Images}};
-
- my @listGroups;
- my $group;
- for (my $i = 0; $i < $GroupCount; $i++ ) {
- #last unless scalar(@images) or $option =~ /align/i;
- push (@$group, shift(@images));
- if ($i == $GroupCount - 1) {
- push @listGroups, $group;
- undef $group;
- $i = -1;
- last if not scalar(@images);
- }
- }
-
- return \@listGroups;
-}
-
-sub SelectImage {
- my ($this,$imageId) = @_;
-
- my @images = sort keys %{$this->{$Images}};
-
- for (my $i=0; $i <= @images; $i++) {
- if ($images[$i] eq $imageId) {
- $this->{$CurrentImage} = $this->{$Images}->{$images[$i]};
- $this->{$PrevImage} = $i-1 >= 0 ? $this->{$Images}->{$images[$i-1]} : undef;
- $this->{$NextImage} = $i+1 < @images ? $this->{$Images}->{$images[$i+1]} : undef;
- return 1;
- }
- }
- die new Exception("An image '$imageId' not found in the gallery '$this->{$Id}'");
-}
-
-sub AddImage {
- my ($this,$image) = @_;
-
- $this->{$Images}->{$image->Id()} = $image;
-}
-
-package DOM::Gallery::Image;
-use Common;
-our @ISA = qw(Object);
-BEGIN {
- DeclareProperty(Id => ACCESS_READ);
- DeclareProperty(Name => ACCESS_READ);
- DeclareProperty(Gallery => ACCESS_READ);
- DeclareProperty(URL => ACCESS_READ);
- DeclareProperty(ThumbURL => ACCESS_READ);
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$Id} = $args{'Id'} or die new Exception ('An Id should be specified for an image');
- $this->{$Name} = $args{'Name'};
- $this->{$Gallery} = $args{'Gallery'} or die new Exception('An Gallery should be specified for an image');
- $this->{$URL} = $args{'URL'};
- $this->{$ThumbURL} = $args{'ThumbURL'};
-}
-
-package DOM::Providers::Gallery;
-use Common;
-our @ISA = qw(Object);
-
-our $RepoPath;
-our $ImagesURL;
-our $Encoding;
-
-BEGIN {
- DeclareProperty(GalleryCache => ACCESS_NONE);
- DeclareProperty(Repository => ACCESS_NONE);
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$Repository} = $args {'Repository'} or die new Exception('A path to an galleries repository should be specified');
-}
-
-sub GetProviderInfo() {
- return {
- Name => 'Gallery',
- Host => 'DOM::Site',
- Methods => {
- LoadGallery => \&SiteLoadGallery #($this,$site,$galleryId)
- }
- };
-}
-
-sub SiteLoadGallery {
- my ($this,$site,$galleryId) = @_;
-
- my $gallery = $this->LoadGallery($galleryId);
-
- $site->RegisterObject('Gallery',$gallery);
-
- return $gallery;
-}
-
-sub LoadGallery {
- my ($this,$galleryId) = @_;
-
- die new Exception("Invalid Gallery Id: $galleryId") if $galleryId =~ /\\|\//;
-
- my $galleryIdPath = $galleryId;
- $galleryIdPath =~ s/\./\//g;
-
- my $GalleryPath = $this->{$Repository} . $galleryIdPath .'/';
-
- die new Exception("A gallery '$galleryId' isn't found",$GalleryPath) if not -d $GalleryPath;
-
- open my $hDesc, "<:encoding($Encoding)", $GalleryPath.'index.htm' or die new Exception("Invalid gallery: $galleryId","Failed to open ${GalleryPath}index.htm: $!");
-
- my $GalleryName;
- while (<$hDesc>) {
- if (/
(.+?)<\/title>/i) {
- $GalleryName = $1;
- last;
- }
- }
- undef $hDesc;
-
- my $ImagesPath = $GalleryPath.'images/';
- my $ThumbsPath = $GalleryPath.'thumbnails/';
-
- opendir my $hImages, $ImagesPath or die new Exception("Invalid gallery: $galleryId","Can't open images repository: $!");
-
- my @imageIds = grep { -f $ImagesPath.$_ } readdir $hImages;
-
- my %imageNames;
-
- if (-f $GalleryPath.'description.txt') {
- local $/="\n";
- if (open my $hfile,"<:encoding($Encoding)",$GalleryPath.'description.txt') {
- while (<$hfile>) {
- chomp;
- my ($id,$name) = split /\s*=\s*/;
- $imageNames{$id} = $name;
- }
- }
- }
-
- undef $hImages;
-
- if ($Common::Debug) {
- foreach (@imageIds) {
- warn "A tumb isn't found for an image: $_" if not -f $ThumbsPath.$_;
- }
- }
-
- my $gallery = new DOM::Gallery(Id => $galleryId, Name => $GalleryName);
-
- foreach my $imageId (@imageIds) {
- $gallery->AddImage(new DOM::Gallery::Image(
- Id => $imageId,
- URL => $ImagesURL.$galleryIdPath.'/images/'.$imageId,
- ThumbURL => $ImagesURL.$galleryIdPath.'/thumbnails/'.$imageId,
- Gallery => $gallery,
- Name => $imageNames{$imageId}
- )
- );
- }
-
- return $gallery;
-}
-
-sub construct {
- my $self = shift;
-
- return new DOM::Providers::Gallery( Repository => $RepoPath);
-}
-
-1;
+use strict;
+package DOM::Gallery;
+use Common;
+our @ISA = qw(Object);
+
+BEGIN {
+ DeclareProperty(Id => ACCESS_READ);
+ DeclareProperty(Name => ACCESS_READ);
+ DeclareProperty(Description => ACCESS_READ);
+ DeclareProperty(Images => ACCESS_READ);
+ DeclareProperty(CurrentImage => ACCESS_READ);
+ DeclareProperty(NextImage => ACCESS_READ);
+ DeclareProperty(PrevImage => ACCESS_READ);
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$Id} = $args{'Id'};
+ $this->{$Name} = $args{'Name'};
+ $this->{$Description} = $args{'Description'};
+}
+
+sub GroupList {
+ my ($this,$GroupCount, $option) = @_;
+
+ my @images = map { $this->{$Images}->{$_} } sort keys %{$this->{$Images}};
+
+ my @listGroups;
+ my $group;
+ for (my $i = 0; $i < $GroupCount; $i++ ) {
+ #last unless scalar(@images) or $option =~ /align/i;
+ push (@$group, shift(@images));
+ if ($i == $GroupCount - 1) {
+ push @listGroups, $group;
+ undef $group;
+ $i = -1;
+ last if not scalar(@images);
+ }
+ }
+
+ return \@listGroups;
+}
+
+sub SelectImage {
+ my ($this,$imageId) = @_;
+
+ my @images = sort keys %{$this->{$Images}};
+
+ for (my $i=0; $i <= @images; $i++) {
+ if ($images[$i] eq $imageId) {
+ $this->{$CurrentImage} = $this->{$Images}->{$images[$i]};
+ $this->{$PrevImage} = $i-1 >= 0 ? $this->{$Images}->{$images[$i-1]} : undef;
+ $this->{$NextImage} = $i+1 < @images ? $this->{$Images}->{$images[$i+1]} : undef;
+ return 1;
+ }
+ }
+ die new Exception("An image '$imageId' not found in the gallery '$this->{$Id}'");
+}
+
+sub AddImage {
+ my ($this,$image) = @_;
+
+ $this->{$Images}->{$image->Id()} = $image;
+}
+
+package DOM::Gallery::Image;
+use Common;
+our @ISA = qw(Object);
+BEGIN {
+ DeclareProperty(Id => ACCESS_READ);
+ DeclareProperty(Name => ACCESS_READ);
+ DeclareProperty(Gallery => ACCESS_READ);
+ DeclareProperty(URL => ACCESS_READ);
+ DeclareProperty(ThumbURL => ACCESS_READ);
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$Id} = $args{'Id'} or die new Exception ('An Id should be specified for an image');
+ $this->{$Name} = $args{'Name'};
+ $this->{$Gallery} = $args{'Gallery'} or die new Exception('An Gallery should be specified for an image');
+ $this->{$URL} = $args{'URL'};
+ $this->{$ThumbURL} = $args{'ThumbURL'};
+}
+
+package DOM::Providers::Gallery;
+use Common;
+our @ISA = qw(Object);
+
+our $RepoPath;
+our $ImagesURL;
+our $Encoding;
+
+BEGIN {
+ DeclareProperty(GalleryCache => ACCESS_NONE);
+ DeclareProperty(Repository => ACCESS_NONE);
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$Repository} = $args {'Repository'} or die new Exception('A path to an galleries repository should be specified');
+}
+
+sub GetProviderInfo() {
+ return {
+ Name => 'Gallery',
+ Host => 'DOM::Site',
+ Methods => {
+ LoadGallery => \&SiteLoadGallery #($this,$site,$galleryId)
+ }
+ };
+}
+
+sub SiteLoadGallery {
+ my ($this,$site,$galleryId) = @_;
+
+ my $gallery = $this->LoadGallery($galleryId);
+
+ $site->RegisterObject('Gallery',$gallery);
+
+ return $gallery;
+}
+
+sub LoadGallery {
+ my ($this,$galleryId) = @_;
+
+ die new Exception("Invalid Gallery Id: $galleryId") if $galleryId =~ /\\|\//;
+
+ my $galleryIdPath = $galleryId;
+ $galleryIdPath =~ s/\./\//g;
+
+ my $GalleryPath = $this->{$Repository} . $galleryIdPath .'/';
+
+ die new Exception("A gallery '$galleryId' isn't found",$GalleryPath) if not -d $GalleryPath;
+
+ open my $hDesc, "<:encoding($Encoding)", $GalleryPath.'index.htm' or die new Exception("Invalid gallery: $galleryId","Failed to open ${GalleryPath}index.htm: $!");
+
+ my $GalleryName;
+ while (<$hDesc>) {
+ if (/(.+?)<\/title>/i) {
+ $GalleryName = $1;
+ last;
+ }
+ }
+ undef $hDesc;
+
+ my $ImagesPath = $GalleryPath.'images/';
+ my $ThumbsPath = $GalleryPath.'thumbnails/';
+
+ opendir my $hImages, $ImagesPath or die new Exception("Invalid gallery: $galleryId","Can't open images repository: $!");
+
+ my @imageIds = grep { -f $ImagesPath.$_ } readdir $hImages;
+
+ my %imageNames;
+
+ if (-f $GalleryPath.'description.txt') {
+ local $/="\n";
+ if (open my $hfile,"<:encoding($Encoding)",$GalleryPath.'description.txt') {
+ while (<$hfile>) {
+ chomp;
+ my ($id,$name) = split /\s*=\s*/;
+ $imageNames{$id} = $name;
+ }
+ }
+ }
+
+ undef $hImages;
+
+ if ($Common::Debug) {
+ foreach (@imageIds) {
+ warn "A tumb isn't found for an image: $_" if not -f $ThumbsPath.$_;
+ }
+ }
+
+ my $gallery = new DOM::Gallery(Id => $galleryId, Name => $GalleryName);
+
+ foreach my $imageId (@imageIds) {
+ $gallery->AddImage(new DOM::Gallery::Image(
+ Id => $imageId,
+ URL => $ImagesURL.$galleryIdPath.'/images/'.$imageId,
+ ThumbURL => $ImagesURL.$galleryIdPath.'/thumbnails/'.$imageId,
+ Gallery => $gallery,
+ Name => $imageNames{$imageId}
+ )
+ );
+ }
+
+ return $gallery;
+}
+
+sub construct {
+ my $self = shift;
+
+ return new DOM::Providers::Gallery( Repository => $RepoPath);
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/DOM/Providers/Headlines.pm
--- a/Lib/DOM/Providers/Headlines.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/DOM/Providers/Headlines.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,128 +1,128 @@
-package DOM::Providers::Headlines::Headline;
-use Common;
-use Time::Local;
-our @ISA = qw(Object);
-
-BEGIN {
- DeclareProperty(Id => ACCESS_READ);
- DeclareProperty(DateModify => ACCESS_READ);
- DeclareProperty(DateExpire => ACCESS_READ);
- DeclareProperty(URL => ACCESS_READ);
- DeclareProperty(Text => ACCESS_READ);
- DeclareProperty(Channel => ACCESS_READ);
-}
-
-sub str2time {
- my $str = shift;
-
- if ($str =~ /^(\d{4})-(\d{2})-(\d{2})(?:\s(\d{2}):(\d{2}):(\d{2}))?$/) {
- my ($year,$month,$day,$hh,$mm,$ss) = ($1,$2-1,$3,(defined $4 ? $4 : 0),(defined $5 ? $5 : 0),(defined $6 ? $6 : 0));
- return timelocal($ss,$mm,$hh,$day,$month,$year);
- } else {
- die new Exception("A string '$str' isn't an ISO standard time");
- }
-}
-
-sub IsActive {
- my ($this) = @_;
- my $timeExpire = str2time($this->{$DateExpire});
-
- return ($timeExpire > time());
-}
-
-package DOM::Providers::Headlines::Collection;
-use Common;
-our @ISA = qw (Object);
-
-BEGIN {
- DeclareProperty(Items => ACCESS_READ);
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- foreach my $headline (@{$args{'Items'}}) {
- $this->{$Items}->{$headline->Id()} = $headline if ($headline->IsActive)
- }
-}
-
-sub as_list {
- my $this = shift;
-
- return [ map { $this->{$Items}->{$_} } sort keys %{$this->{$Items}} ];
-}
-
-sub GenerateRandomSequence {
- my ($count,$max) = @_;
-
- my %hash;
- $hash{rand()} = $_ foreach (0 .. $max - 1);
- my @sequence = map { $hash{$_} } sort keys %hash;
- return splice @sequence,0,$count;
-}
-
-sub Random {
- my ($this,$count) = @_;
-
- my $list = $this->as_list();
-
- return [map { $list->[$_] } GenerateRandomSequence($count,scalar(@$list))];
-}
-
-sub Recent {
- my ($this,$count) = @_;
-
- my @result = sort { $b->DateModify() cmp $a->DateModify() } values %{$this->{$Items}};
- splice @result,$count;
-
- return \@result;
-}
-
-sub AddItem {
- my ($this,$newItem) = @_;
-
- $this->{$Items}->{$newItem->Id()} = $newItem;
-}
-
-package DOM::Providers::Headlines;
-use Common;
-use ObjectStore::Headlines;
-
-our $DBPath;
-our $Encoding;
-
-my %Channels;
-
-eval {
- LoadHeadlines();
-};
-
-if ($@) {
- my $err = $@;
- if (ref $err eq 'Exception') {
- die $err->ToString();
- } else {
- die $err;
- }
-}
-
-
-sub GetProviderInfo {
- return {
- Name => 'Headlines',
- Host => 'DOM::Site',
- Objects => \%Channels
- }
-}
-
-sub LoadHeadlines {
- my $dsHeadlines = new ObjectStore::Headlines(DBPath => $DBPath, HeadlineClass => 'DOM::Providers::Headlines::Headline', Encoding => $Encoding);
-
- foreach my $headline (@{$dsHeadlines->Search(Filter => sub { return $_[0]->IsActive(); } )}) {
- my $channel = $headline->Channel() || 'main';
- $Channels{$channel} = new DOM::Providers::Headlines::Collection() if not exists $Channels{$channel};
- $Channels{$channel}->AddItem($headline);
- }
-}
-
-1;
\ No newline at end of file
+package DOM::Providers::Headlines::Headline;
+use Common;
+use Time::Local;
+our @ISA = qw(Object);
+
+BEGIN {
+ DeclareProperty(Id => ACCESS_READ);
+ DeclareProperty(DateModify => ACCESS_READ);
+ DeclareProperty(DateExpire => ACCESS_READ);
+ DeclareProperty(URL => ACCESS_READ);
+ DeclareProperty(Text => ACCESS_READ);
+ DeclareProperty(Channel => ACCESS_READ);
+}
+
+sub str2time {
+ my $str = shift;
+
+ if ($str =~ /^(\d{4})-(\d{2})-(\d{2})(?:\s(\d{2}):(\d{2}):(\d{2}))?$/) {
+ my ($year,$month,$day,$hh,$mm,$ss) = ($1,$2-1,$3,(defined $4 ? $4 : 0),(defined $5 ? $5 : 0),(defined $6 ? $6 : 0));
+ return timelocal($ss,$mm,$hh,$day,$month,$year);
+ } else {
+ die new Exception("A string '$str' isn't an ISO standard time");
+ }
+}
+
+sub IsActive {
+ my ($this) = @_;
+ my $timeExpire = str2time($this->{$DateExpire});
+
+ return ($timeExpire > time());
+}
+
+package DOM::Providers::Headlines::Collection;
+use Common;
+our @ISA = qw (Object);
+
+BEGIN {
+ DeclareProperty(Items => ACCESS_READ);
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ foreach my $headline (@{$args{'Items'}}) {
+ $this->{$Items}->{$headline->Id()} = $headline if ($headline->IsActive)
+ }
+}
+
+sub as_list {
+ my $this = shift;
+
+ return [ map { $this->{$Items}->{$_} } sort keys %{$this->{$Items}} ];
+}
+
+sub GenerateRandomSequence {
+ my ($count,$max) = @_;
+
+ my %hash;
+ $hash{rand()} = $_ foreach (0 .. $max - 1);
+ my @sequence = map { $hash{$_} } sort keys %hash;
+ return splice @sequence,0,$count;
+}
+
+sub Random {
+ my ($this,$count) = @_;
+
+ my $list = $this->as_list();
+
+ return [map { $list->[$_] } GenerateRandomSequence($count,scalar(@$list))];
+}
+
+sub Recent {
+ my ($this,$count) = @_;
+
+ my @result = sort { $b->DateModify() cmp $a->DateModify() } values %{$this->{$Items}};
+ splice @result,$count;
+
+ return \@result;
+}
+
+sub AddItem {
+ my ($this,$newItem) = @_;
+
+ $this->{$Items}->{$newItem->Id()} = $newItem;
+}
+
+package DOM::Providers::Headlines;
+use Common;
+use ObjectStore::Headlines;
+
+our $DBPath;
+our $Encoding;
+
+my %Channels;
+
+eval {
+ LoadHeadlines();
+};
+
+if ($@) {
+ my $err = $@;
+ if (ref $err eq 'Exception') {
+ die $err->ToString();
+ } else {
+ die $err;
+ }
+}
+
+
+sub GetProviderInfo {
+ return {
+ Name => 'Headlines',
+ Host => 'DOM::Site',
+ Objects => \%Channels
+ }
+}
+
+sub LoadHeadlines {
+ my $dsHeadlines = new ObjectStore::Headlines(DBPath => $DBPath, HeadlineClass => 'DOM::Providers::Headlines::Headline', Encoding => $Encoding);
+
+ foreach my $headline (@{$dsHeadlines->Search(Filter => sub { return $_[0]->IsActive(); } )}) {
+ my $channel = $headline->Channel() || 'main';
+ $Channels{$channel} = new DOM::Providers::Headlines::Collection() if not exists $Channels{$channel};
+ $Channels{$channel}->AddItem($headline);
+ }
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/DOM/Providers/Page.pm
--- a/Lib/DOM/Providers/Page.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/DOM/Providers/Page.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,258 +1,258 @@
-use strict;
-
-package DOM::Providers::Page;
-use Template::Provider;
-#use PerfCounter;
-use DOM::Page;
-use Common;
-use Encode;
-
-our @ISA= qw(Object Exporter);
-
-our $UseIndexPage; #optional
-our $PagesPath; #required
-our $IncludesPath; #optional
-our $CacheSize; #optional
-our $CachePath; #optional
-our $Encoding; #optional
-our $AllowExtPath; #optional
-our $PageResolver; #optional
-
-
-BEGIN {
- DeclareProperty('PageResolver');
- DeclareProperty('PagesBase');
- DeclareProperty('IndexPage');
- DeclareProperty('TemplatesProvider');
- DeclareProperty('PageEnc');
-}
-
-sub as_list {
- return( map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : defined $_ ? $_ : () } @_ );
-}
-
-sub GetProviderInfo {
- return {
- Name => 'Page',
- Host => 'DOM::Site',
- Methods => {
- LoadPage => \&SiteLoadPage,
- ReleasePage => \&SiteReleasePage,
- }
- }
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$PageResolver} = $args{'PageResolver'};
- $this->{$PagesBase} = $args{'TemplatesPath'};
- $this->{$IndexPage} = $args{'IndexPage'} || 'index.html';
- $this->{$PageEnc} = $args{'Encoding'};
- $this->{$TemplatesProvider} = new Template::Provider( INCLUDE_PATH => [$this->{$PagesBase}, as_list($args{'IncludePath'}) ], COMPILE_DIR => $args{'CachePath'}, CACHE_SIZE => $args{'CacheSize'}, ENCODING => $args{'Encoding'}, ABSOLUTE => $AllowExtPath, RELATIVE => $AllowExtPath, INTERPOLATE => 1, PRE_CHOMP => 3);
-}
-
-sub ResolveId {
- my ($this,$pageId) = @_;
-
- if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'ResolveId')) {
- return $this->{$PageResolver}->ResolveId($pageId);
- } else {
- return grep { $_ } split /\//,$pageId;
- }
-}
-
-sub MakePageId {
- my ($this,$raPath) = @_;
-
- if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'MakeId')) {
- return $this->{$PageResolver}->MakeId($raPath);
- } else {
- return join '/',@$raPath;
- }
-}
-
-sub PageIdToURL {
- my ($this,$pageId) = @_;
-
- if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'PageIdToURL')) {
- return $this->{$PageResolver}->PageIdToURL($pageId);
- } else {
- return '/'.$pageId;
- }
-}
-
-sub SiteLoadPage {
- my ($this,$site,$pageId) = @_;
-
- return $site->RegisterObject('Page', $this->LoadPage($pageId, Site => $site));
-}
-sub LoadPage {
- my ($this,$pageId,%args) = @_;
-
- #StartTimeCounter('LoadPageTime');
-
- my @pathPage = $this->ResolveId($pageId);
-
- my $pageNode = $this->LoadNode(\@pathPage);
-
- pop @pathPage;
-
- my @pathNode;
-
- # поскольку путь указан относительно корневого контейнера, то нужно его добавить в начало
- my @NavChain = map { push @pathNode, $_; $this->LoadNode(\@pathNode); } ('.',@pathPage);
-
- if ($pageNode->{'Type'} eq 'Section') {
- push @NavChain,$pageNode;
- $pageNode = $this->LoadNode($pageNode->{'pathIndexPage'});
- }
-
- # формируем меню страницы
- my %PageMenus;
- foreach my $MenuSet (map { $_->{'Menus'}} @NavChain, $pageNode->{'Menus'} ) {
- foreach my $menuName (keys %$MenuSet) {
- if ($PageMenus{$menuName}) {
- $PageMenus{$menuName}->Merge($MenuSet->{$menuName});
- } else {
- $PageMenus{$menuName} = $MenuSet->{$menuName};
- }
- }
- }
-
- # формируем ключевые слова и свойства
- my @keywords;
- my %Props;
- foreach my $PropSet ( (map { $_->{'Props'}} @NavChain), $pageNode->{'Props'} ) {
- if(ref $PropSet->{'Keywords'} eq 'ARRAY') {
- push @keywords, @{$PropSet->{'Keywords'}};
- } elsif (not ref $PropSet->{'Keywords'} and exists $PropSet->{'Keywords'}) {
- push @keywords, $PropSet->{'Keywords'};
- }
-
- while (my ($prop,$value) = each %$PropSet) {
- next if $prop eq 'Keywords';
- $Props{$prop} = $value;
- }
- }
-
- #StopTimeCounter('LoadPageTime');
- # загружаем шаблон
-
- #StartTimeCounter('FetchTime');
- my ($Template,$error) = $this->{$TemplatesProvider}->fetch($pageNode->{'TemplateFileName'});
- die new Exception("Failed to load page $pageId",$Template ? $Template->as_string : 'Failed to parse') if $error;
- #StopTimeCounter('FetchTime');
-
- my $page = new DOM::Page(TemplatesProvider => $this->{$TemplatesProvider}, Properties => \%Props, Menus => \%PageMenus, NavChain => \@NavChain, Template => $Template, %args);
- $page->Properties->{url} = $this->PageIdToURL($pageId);
- return $page;
-}
-
-sub LoadNode {
- my ($this,$refNodePath) = @_;
-
- my $fileNameNode = $this->{$PagesBase} . join('/',grep $_, @$refNodePath);
- my $fileNameMenus;
- my $fileNameProps;
-
- my %Node;
-
- if ( -d $fileNameNode ) {
- $Node{'Type'} = 'Section';
- $fileNameMenus = $fileNameNode . '/.menu.pl';
- $fileNameProps = $fileNameNode . '/.prop.pl';
- } elsif ( -e $fileNameNode ) {
- $Node{'Type'} = 'Page';
- $Node{'TemplateFileName'} = join('/',@$refNodePath);;
- $fileNameMenus = $fileNameNode . '.menu.pl';
- $fileNameProps = $fileNameNode . '.prop.pl';
- } else {
- die new Exception("Page not found: $fileNameNode");
- }
-
- if ( -f $fileNameProps ) {
- local ${^ENCODING};
- my $dummy = '';
- open my $hnull,'>>',\$dummy;
- local (*STDOUT,*STDIN) = ($hnull,$hnull);
- $Node{'Props'} = do $fileNameProps or warn "can't parse $fileNameProps: $@";
- }
-
- if ( -f $fileNameMenus ) {
- local ${^ENCODING};
- my $dummy = '';
- open my $hnull,'>>',\$dummy;
- local (*STDOUT,*STDIN) = ($hnull,$hnull);
- $Node{'Menus'} = do $fileNameMenus or warn "can't parse $fileNameMenus: $@";
- }
-
- if ($Node{'Menus'}) {
- my %Menus;
- foreach my $menu (keys %{$Node{'Menus'}}) {
- $Menus{$menu} = new DOM::PageMenu( DATA => $Node{'Menus'}->{$menu} );
- }
- $Node{'Menus'} = \%Menus;
- }
-
- $Node{'pathIndexPage'} = [@$refNodePath, $Node{'Props'}->{'IndexPage'} || $this->{$IndexPage}] if $Node{'Type'} eq 'Section';
-
- return \%Node;
-}
-
-sub SiteReleasePage {
- my ($this,$site) = @_;
-
- my $page = $site->Objects()->{'Page'};
- $page->Release() if $page;
-
- return 1;
-}
-
-sub construct {
- my $self = shift;
-
- return new DOM::Providers::Page(TemplatesPath => $PagesPath, IncludePath => $IncludesPath, IndexPage => $UseIndexPage, CachePath => $CachePath, CacheSize => $CacheSize, Encoding => $Encoding);
-}
-
-sub DecodeData {
- my ($Encoding, $data) = @_;
-
- if (ref $data) {
- if (ref $data eq 'SCALAR') {
- my $decoded = Encode::decode($Encoding,$$data,Encode::LEAVE_SRC);
- return \$decoded;
- } elsif (UNIVERSAL::isa($data, 'HASH')) {
- return {map {Encode::decode($Encoding,$_,Encode::LEAVE_SRC),DecodeData($Encoding,$data->{$_})} keys %$data };
- } elsif (UNIVERSAL::isa($data, 'ARRAY')) {
- return [map {DecodeData($Encoding,$_)} @$data];
- } elsif (ref $data eq 'REF') {
- my $decoded = DecodeData($Encoding,$$data);
- return \$decoded;
- } else {
- die new Exception('Cant decode data type', ref $data);
- }
- } else {
- return Encode::decode($Encoding,$data,Encode::LEAVE_SRC);
- }
-}
-
-1;
-
-=pod
-Хранилище шаблонов на основе файловой системы.
-
-Хранилище состоит из разделов, каждый раздел имеет набор свойств и меню
-Специальны свойства разделов
- Keywords Ключевые слова
- Name Название
- IndexPage страница по умолчанию
-
-В разделах находятся страницы, каждая страница имеет набор свойств и меню
-
-При загрузке страницы полностью загружаются все родительские контейнеры,
-При этом одноименные меню сливаются,
-Свойства keywords объеъединяются,
-Если имя страницы не задано, то используется имя раздела
-
-=cut
\ No newline at end of file
+use strict;
+
+package DOM::Providers::Page;
+use Template::Provider;
+#use PerfCounter;
+use DOM::Page;
+use Common;
+use Encode;
+
+our @ISA= qw(Object Exporter);
+
+our $UseIndexPage; #optional
+our $PagesPath; #required
+our $IncludesPath; #optional
+our $CacheSize; #optional
+our $CachePath; #optional
+our $Encoding; #optional
+our $AllowExtPath; #optional
+our $PageResolver; #optional
+
+
+BEGIN {
+ DeclareProperty('PageResolver');
+ DeclareProperty('PagesBase');
+ DeclareProperty('IndexPage');
+ DeclareProperty('TemplatesProvider');
+ DeclareProperty('PageEnc');
+}
+
+sub as_list {
+ return( map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : defined $_ ? $_ : () } @_ );
+}
+
+sub GetProviderInfo {
+ return {
+ Name => 'Page',
+ Host => 'DOM::Site',
+ Methods => {
+ LoadPage => \&SiteLoadPage,
+ ReleasePage => \&SiteReleasePage,
+ }
+ }
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$PageResolver} = $args{'PageResolver'};
+ $this->{$PagesBase} = $args{'TemplatesPath'};
+ $this->{$IndexPage} = $args{'IndexPage'} || 'index.html';
+ $this->{$PageEnc} = $args{'Encoding'};
+ $this->{$TemplatesProvider} = new Template::Provider( INCLUDE_PATH => [$this->{$PagesBase}, as_list($args{'IncludePath'}) ], COMPILE_DIR => $args{'CachePath'}, CACHE_SIZE => $args{'CacheSize'}, ENCODING => $args{'Encoding'}, ABSOLUTE => $AllowExtPath, RELATIVE => $AllowExtPath, INTERPOLATE => 1, PRE_CHOMP => 3);
+}
+
+sub ResolveId {
+ my ($this,$pageId) = @_;
+
+ if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'ResolveId')) {
+ return $this->{$PageResolver}->ResolveId($pageId);
+ } else {
+ return grep { $_ } split /\//,$pageId;
+ }
+}
+
+sub MakePageId {
+ my ($this,$raPath) = @_;
+
+ if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'MakeId')) {
+ return $this->{$PageResolver}->MakeId($raPath);
+ } else {
+ return join '/',@$raPath;
+ }
+}
+
+sub PageIdToURL {
+ my ($this,$pageId) = @_;
+
+ if ($this->{$PageResolver} && UNIVERSAL::can($this->{$PageResolver},'PageIdToURL')) {
+ return $this->{$PageResolver}->PageIdToURL($pageId);
+ } else {
+ return '/'.$pageId;
+ }
+}
+
+sub SiteLoadPage {
+ my ($this,$site,$pageId) = @_;
+
+ return $site->RegisterObject('Page', $this->LoadPage($pageId, Site => $site));
+}
+sub LoadPage {
+ my ($this,$pageId,%args) = @_;
+
+ #StartTimeCounter('LoadPageTime');
+
+ my @pathPage = $this->ResolveId($pageId);
+
+ my $pageNode = $this->LoadNode(\@pathPage);
+
+ pop @pathPage;
+
+ my @pathNode;
+
+ # поскольку путь указан относительно корневого контейнера, то нужно его добавить в начало
+ my @NavChain = map { push @pathNode, $_; $this->LoadNode(\@pathNode); } ('.',@pathPage);
+
+ if ($pageNode->{'Type'} eq 'Section') {
+ push @NavChain,$pageNode;
+ $pageNode = $this->LoadNode($pageNode->{'pathIndexPage'});
+ }
+
+ # формируем меню страницы
+ my %PageMenus;
+ foreach my $MenuSet (map { $_->{'Menus'}} @NavChain, $pageNode->{'Menus'} ) {
+ foreach my $menuName (keys %$MenuSet) {
+ if ($PageMenus{$menuName}) {
+ $PageMenus{$menuName}->Merge($MenuSet->{$menuName});
+ } else {
+ $PageMenus{$menuName} = $MenuSet->{$menuName};
+ }
+ }
+ }
+
+ # формируем ключевые слова и свойства
+ my @keywords;
+ my %Props;
+ foreach my $PropSet ( (map { $_->{'Props'}} @NavChain), $pageNode->{'Props'} ) {
+ if(ref $PropSet->{'Keywords'} eq 'ARRAY') {
+ push @keywords, @{$PropSet->{'Keywords'}};
+ } elsif (not ref $PropSet->{'Keywords'} and exists $PropSet->{'Keywords'}) {
+ push @keywords, $PropSet->{'Keywords'};
+ }
+
+ while (my ($prop,$value) = each %$PropSet) {
+ next if $prop eq 'Keywords';
+ $Props{$prop} = $value;
+ }
+ }
+
+ #StopTimeCounter('LoadPageTime');
+ # загружаем шаблон
+
+ #StartTimeCounter('FetchTime');
+ my ($Template,$error) = $this->{$TemplatesProvider}->fetch($pageNode->{'TemplateFileName'});
+ die new Exception("Failed to load page $pageId",$Template ? $Template->as_string : 'Failed to parse') if $error;
+ #StopTimeCounter('FetchTime');
+
+ my $page = new DOM::Page(TemplatesProvider => $this->{$TemplatesProvider}, Properties => \%Props, Menus => \%PageMenus, NavChain => \@NavChain, Template => $Template, %args);
+ $page->Properties->{url} = $this->PageIdToURL($pageId);
+ return $page;
+}
+
+sub LoadNode {
+ my ($this,$refNodePath) = @_;
+
+ my $fileNameNode = $this->{$PagesBase} . join('/',grep $_, @$refNodePath);
+ my $fileNameMenus;
+ my $fileNameProps;
+
+ my %Node;
+
+ if ( -d $fileNameNode ) {
+ $Node{'Type'} = 'Section';
+ $fileNameMenus = $fileNameNode . '/.menu.pl';
+ $fileNameProps = $fileNameNode . '/.prop.pl';
+ } elsif ( -e $fileNameNode ) {
+ $Node{'Type'} = 'Page';
+ $Node{'TemplateFileName'} = join('/',@$refNodePath);;
+ $fileNameMenus = $fileNameNode . '.menu.pl';
+ $fileNameProps = $fileNameNode . '.prop.pl';
+ } else {
+ die new Exception("Page not found: $fileNameNode");
+ }
+
+ if ( -f $fileNameProps ) {
+ local ${^ENCODING};
+ my $dummy = '';
+ open my $hnull,'>>',\$dummy;
+ local (*STDOUT,*STDIN) = ($hnull,$hnull);
+ $Node{'Props'} = do $fileNameProps or warn "can't parse $fileNameProps: $@";
+ }
+
+ if ( -f $fileNameMenus ) {
+ local ${^ENCODING};
+ my $dummy = '';
+ open my $hnull,'>>',\$dummy;
+ local (*STDOUT,*STDIN) = ($hnull,$hnull);
+ $Node{'Menus'} = do $fileNameMenus or warn "can't parse $fileNameMenus: $@";
+ }
+
+ if ($Node{'Menus'}) {
+ my %Menus;
+ foreach my $menu (keys %{$Node{'Menus'}}) {
+ $Menus{$menu} = new DOM::PageMenu( DATA => $Node{'Menus'}->{$menu} );
+ }
+ $Node{'Menus'} = \%Menus;
+ }
+
+ $Node{'pathIndexPage'} = [@$refNodePath, $Node{'Props'}->{'IndexPage'} || $this->{$IndexPage}] if $Node{'Type'} eq 'Section';
+
+ return \%Node;
+}
+
+sub SiteReleasePage {
+ my ($this,$site) = @_;
+
+ my $page = $site->Objects()->{'Page'};
+ $page->Release() if $page;
+
+ return 1;
+}
+
+sub construct {
+ my $self = shift;
+
+ return new DOM::Providers::Page(TemplatesPath => $PagesPath, IncludePath => $IncludesPath, IndexPage => $UseIndexPage, CachePath => $CachePath, CacheSize => $CacheSize, Encoding => $Encoding);
+}
+
+sub DecodeData {
+ my ($Encoding, $data) = @_;
+
+ if (ref $data) {
+ if (ref $data eq 'SCALAR') {
+ my $decoded = Encode::decode($Encoding,$$data,Encode::LEAVE_SRC);
+ return \$decoded;
+ } elsif (UNIVERSAL::isa($data, 'HASH')) {
+ return {map {Encode::decode($Encoding,$_,Encode::LEAVE_SRC),DecodeData($Encoding,$data->{$_})} keys %$data };
+ } elsif (UNIVERSAL::isa($data, 'ARRAY')) {
+ return [map {DecodeData($Encoding,$_)} @$data];
+ } elsif (ref $data eq 'REF') {
+ my $decoded = DecodeData($Encoding,$$data);
+ return \$decoded;
+ } else {
+ die new Exception('Cant decode data type', ref $data);
+ }
+ } else {
+ return Encode::decode($Encoding,$data,Encode::LEAVE_SRC);
+ }
+}
+
+1;
+
+=pod
+Хранилище шаблонов на основе файловой системы.
+
+Хранилище состоит из разделов, каждый раздел имеет набор свойств и меню
+Специальны свойства разделов
+ Keywords Ключевые слова
+ Name Название
+ IndexPage страница по умолчанию
+
+В разделах находятся страницы, каждая страница имеет набор свойств и меню
+
+При загрузке страницы полностью загружаются все родительские контейнеры,
+При этом одноименные меню сливаются,
+Свойства keywords объеъединяются,
+Если имя страницы не задано, то используется имя раздела
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/DOM/Providers/Perfomance.pm
--- a/Lib/DOM/Providers/Perfomance.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/DOM/Providers/Perfomance.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,15 +1,15 @@
-use strict;
-
-package DOM::Providers::Perfomance;
-use PerfCounter;
-
-sub GetProviderInfo {
- return {
- Name => 'Perfomance',
- Host => 'DOM::Site',
- Objects => {
- Counters => \%PerfCounter::Counters
- }
- }
-}
-1;
+use strict;
+
+package DOM::Providers::Perfomance;
+use PerfCounter;
+
+sub GetProviderInfo {
+ return {
+ Name => 'Perfomance',
+ Host => 'DOM::Site',
+ Objects => {
+ Counters => \%PerfCounter::Counters
+ }
+ }
+}
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/DOM/Providers/Security.pm
--- a/Lib/DOM/Providers/Security.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/DOM/Providers/Security.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,19 +1,19 @@
-use strict;
-
-package DOM::Providers::Security;
-use Security;
-
-sub GetProviderInfo {
- return {
- Name => 'Security',
- Host => 'DOM::Site',
- Objects => {
- Session => \&GetSession
- }
- }
-}
-
-sub GetSession {
- return Security->CurrentSession;
-}
-1;
\ No newline at end of file
+use strict;
+
+package DOM::Providers::Security;
+use Security;
+
+sub GetProviderInfo {
+ return {
+ Name => 'Security',
+ Host => 'DOM::Site',
+ Objects => {
+ Session => \&GetSession
+ }
+ }
+}
+
+sub GetSession {
+ return Security->CurrentSession;
+}
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/DOM/Site.pm
--- a/Lib/DOM/Site.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/DOM/Site.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,80 +1,80 @@
-package DOM::Site;
-use strict;
-use Common;
-our @ISA = qw(Object);
-
-our $Name;
-our @Providers;
-our $AUTOLOAD;
-
-BEGIN {
- DeclareProperty(Objects => ACCESS_READ);
- DeclareProperty(Providers => ACCESS_NONE);
-}
-
-sub RegisterObject {
- my ($this,$name,$object) = @_;
-
- $this->{$Objects}->{$name} = $object;
-}
-
-sub RegisterProvider {
- my ($this,$provider) = @_;
-
- my $refInfo = $provider->GetProviderInfo();
-
- if ($refInfo->{'Host'} eq __PACKAGE__) {
- die new Exception("Provider $refInfo->{'Name'} already registered") if exists $this->{$Providers}->{$refInfo->{'Name'}};
- while (my ($name,$method) = each %{$refInfo->{'Methods'}}) {
- no strict 'refs';
- no warnings 'redefine';
- *{__PACKAGE__ . '::' . $name} = sub {
- shift;
- $method->($provider,$this,@_);
- };
- }
-
- while (my ($name,$object) = each %{$refInfo->{'Objects'}}) {
- $this->{$Objects}->{$refInfo->{'Name'}}->{$name} = $object;
- }
-
- $this->{$Providers}->{$refInfo->{'Name'}} = 1;
- }
-}
-
-sub construct {
- my $self = shift;
-
- my $site = $self->new();
- $site->RegisterObject(Site => { Name => $Name});
- foreach my $provider (@Providers) {
- my $providerFile = $provider;
- $providerFile =~ s/::/\//g;
- $providerFile .= '.pm';
- eval {
- require $providerFile;
- };
- if ($@) {
- my $InnerErr = $@;
- die new Exception("Failed to load provider $provider", $InnerErr);
- }
- if ($provider->can('construct')) {
- $site->RegisterProvider($provider->construct());
- } else {
- $site->RegisterProvider($provider);
- }
- }
- return $site;
-}
-
-sub Dispose {
- my ($this) = @_;
-
- UNIVERSAL::can($_,'Dispose') and $_->Dispose foreach values %{$this->{$Objects} || {}};
-
- undef %$this;
-
- $this->SUPER::Dispose;
-}
-
-1;
+package DOM::Site;
+use strict;
+use Common;
+our @ISA = qw(Object);
+
+our $Name;
+our @Providers;
+our $AUTOLOAD;
+
+BEGIN {
+ DeclareProperty(Objects => ACCESS_READ);
+ DeclareProperty(Providers => ACCESS_NONE);
+}
+
+sub RegisterObject {
+ my ($this,$name,$object) = @_;
+
+ $this->{$Objects}->{$name} = $object;
+}
+
+sub RegisterProvider {
+ my ($this,$provider) = @_;
+
+ my $refInfo = $provider->GetProviderInfo();
+
+ if ($refInfo->{'Host'} eq __PACKAGE__) {
+ die new Exception("Provider $refInfo->{'Name'} already registered") if exists $this->{$Providers}->{$refInfo->{'Name'}};
+ while (my ($name,$method) = each %{$refInfo->{'Methods'}}) {
+ no strict 'refs';
+ no warnings 'redefine';
+ *{__PACKAGE__ . '::' . $name} = sub {
+ shift;
+ $method->($provider,$this,@_);
+ };
+ }
+
+ while (my ($name,$object) = each %{$refInfo->{'Objects'}}) {
+ $this->{$Objects}->{$refInfo->{'Name'}}->{$name} = $object;
+ }
+
+ $this->{$Providers}->{$refInfo->{'Name'}} = 1;
+ }
+}
+
+sub construct {
+ my $self = shift;
+
+ my $site = $self->new();
+ $site->RegisterObject(Site => { Name => $Name});
+ foreach my $provider (@Providers) {
+ my $providerFile = $provider;
+ $providerFile =~ s/::/\//g;
+ $providerFile .= '.pm';
+ eval {
+ require $providerFile;
+ };
+ if ($@) {
+ my $InnerErr = $@;
+ die new Exception("Failed to load provider $provider", $InnerErr);
+ }
+ if ($provider->can('construct')) {
+ $site->RegisterProvider($provider->construct());
+ } else {
+ $site->RegisterProvider($provider);
+ }
+ }
+ return $site;
+}
+
+sub Dispose {
+ my ($this) = @_;
+
+ UNIVERSAL::can($_,'Dispose') and $_->Dispose foreach values %{$this->{$Objects} || {}};
+
+ undef %$this;
+
+ $this->SUPER::Dispose;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/DateTime.pm
--- a/Lib/DateTime.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/DateTime.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,312 +1,312 @@
-use strict;
-package DateTime::Span;
-package DateTime;
-use Common;
-use Time::Local;
-use Time::Zone;
-use Date::Format;
-our @ISA = qw(Object);
-
-use overload
- '+' => \&opAdd,
- '-' => \&opSubtract,
- '<=>' => \&opCompare,
- 'bool' => \&opAsBool,
- 'fallback' => 1,
- '""' => \&opAsString;
-
-BEGIN {
- DeclareProperty UnixTime => ACCESS_READ;
-}
-
-sub CTOR {
- my $this = shift;
-
- if (@_ >= 2) {
- my(%args) = @_;
-
- $this->{$UnixTime} = $args{UnixTime} or die new Exception("A correct unix time value is required");
- } else {
- $this->{$UnixTime} = $this->ParseISOTime(shift,'+000');
- }
-}
-
-sub ParseISOTime {
- my ($class,$time,$timezone) = @_;
-
- if ($time =~ /^(\d{4})-(\d{2})-(\d{2})(?:.(\d{2}):(\d{2}):(\d{2})(?:\.\d{3})?)?/ ) {
- my ($yyyy,$mm,$dd,$hh,$MM,$SS) = ($1-1900,$2-1,$3,$4 || 0,$5 || 0,$6 || 0);
- if ($timezone) {
- return tz_offset($timezone) + timegm($SS,$MM,$hh,$dd,$mm,$yyyy);
- } else {
- return timelocal($SS,$MM,$hh,$dd,$mm,$yyyy);
- }
- } else {
- die new Exception("The specified string isn\'t a correct ISO date",$time);
- }
-}
-
-sub new_ISO {
- my ($class,$ISOTime,$zone) = @_;
- return $class->new(UnixTime => $class->ParseISOTime($ISOTime,$zone));
-}
-
-sub now {
- my ($class) = @_;
- return $class->new(UnixTime => time);
-}
-
-sub AsISOString {
- my ($this,$zone) = @_;
- return time2str("%Y-%m-%dT%H:%M:%S",$this->{$UnixTime},$zone);
-}
-
-sub AsFormatString {
- my ($this,$format,$zone) = @_;
- return time2str($format,$this->{$UnixTime},$zone);
-}
-
-sub opAdd {
- my ($a,$b,$flag) = @_;
-
- if (UNIVERSAL::isa($b,'DateTime::Span')) {
- return new DateTime(UnixTime => $a->{$UnixTime} + $b->SecondsSpan);
- } elsif (not ref $b){
- return new DateTime(UnixTime => $a->UnixTime + $b);
- } else {
- die new Exception("Only a time span can be added to the DateTime object",$b);
- }
-}
-
-sub GetDate {
- my ($this) = @_;
-
- return DateTime->new_ISO($this->AsFormatString('%Y-%m-%d'));
-}
-
-sub opSubtract {
- my ($a,$b,$flag) = @_;
-
- if (UNIVERSAL::isa($b,'DateTime')) {
- return new DateTime::Span(Seconds => $a->{$UnixTime}-$b->{$UnixTime});
- } elsif (UNIVERSAL::isa($b,'DateTime::Span')) {
- return new DateTime(UnixTime => $flag ? $b->SecondsSpan - $a->UnixTime: $a->UnixTime - $b->SecondsSpan);
- } elsif (not ref $b){
- return new DateTime(UnixTime => $flag ? $b - $a->UnixTime : $a->UnixTime - $b);
- } else {
- die new Exception("Only an another DateTime object or a time span can be subtracted from the DateTime",$b);
- }
-}
-
-sub opCompare {
- my ($a,$b,$flag) = @_;
-
- if (UNIVERSAL::isa($b,'DateTime')) {
- return $flag ? $b->{$UnixTime} <=> $a->{$UnixTime} : $a->{$UnixTime} <=> $b->{$UnixTime};
- } else {
- die new Exception("Only a DateTime object can be compared to the DateTime object", $b);
- }
-}
-
-sub opAsString {
- my $this = shift;
- $this->AsISOString('+000');
-}
-
-sub opAsBool {
- 1;
-}
-
-package DateTime::Span;
-use Common;
-our @ISA = qw(Object);
-
-use overload
- '-' => \&opSub,
- '+' => \&opAdd,
- '<=>' => \&opCmp,
- 'fallback' => 1;
-
-BEGIN {
- DeclareProperty SecondsSpan=>ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$SecondsSpan} = ($args{'Seconds'} || 0) + ($args{'Minutes'} || 0)*60 + ($args{'Hours'} || 0)*3600 + ($args{'Days'} || 0)*86400;
-}
-
-sub Days {
- my ($this) = @_;
-
- return int($this->{$SecondsSpan}/86400);
-}
-
-sub Hours {
- my ($this) = @_;
-
- return int($this->{$SecondsSpan}/3600);
-}
-sub Minutes {
- my ($this) = @_;
-
- return int($this->{$SecondsSpan}/60);
-}
-
-sub opAdd {
- my ($a,$b,$flag) = @_;
-
- if (UNIVERSAL::isa($b,'DateTime::Span')) {
- return new DateTime::Span(Seconds => $a->{$SecondsSpan} + $b->{$SecondsSpan});
- } elsif (not ref $b) {
- return new DateTime::Span(Seconds => $a->{$SecondsSpan} + $b);
- } else {
- die new Exception("Only a time span can be added to the time span");
- }
-}
-
-sub opSub {
- my ($a,$b,$flag) = @_;
-
- if (UNIVERSAL::isa($b,'DateTime::Span')) {
- return new DateTime::Span(Seconds => $flag ? $b->{$SecondsSpan} - $a->{$SecondsSpan} : $a->{$SecondsSpan} - $b->{$SecondsSpan});
- } elsif (not ref $b) {
- return new DateTime::Span(Seconds => $flag ? $b - $a->{$SecondsSpan} : $a->{$SecondsSpan} - $b);
- } else {
- die new Exception("Only a time span can be subtracted from the time span");
- }
-}
-
-sub opCmp {
- my ($a,$b,$flag) = @_;
-
- if (UNIVERSAL::isa($b,'DateTime::Span')) {
- return $flag ? $b->{$SecondsSpan} <=> $a->{$SecondsSpan} : $a->{$SecondsSpan} <=> $b->{$SecondsSpan};
- } elsif (not ref $b) {
- return $flag ? $b <=> $a->{$SecondsSpan} : $a->{$SecondsSpan} <=> $b;
- } else {
- die new Exception("Only a time span can be compared to the time span");
- }
-}
-
-package DateTime::TimeLine;
-use Common;
-our @ISA = qw(Object);
-
-BEGIN {
- DeclareProperty Timeline => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this) = @_;
-
- $this->{$Timeline} = [ {Date => undef} ];
-}
-
-# рекурсивно копирует простые структуры
-sub SimpleCopy {
- my ($refObject,$cache) = @_;
-
- return undef if not defined $refObject;
-
- $cache ||= {};
-
- if ($cache->{$refObject}) {
- return $cache->{$refObject};
- }
-
- local $_;
-
- if (ref $refObject eq 'HASH' ) {
- return ($cache->{$refObject} = { map { $_, SimpleCopy($refObject->{$_},$cache) } keys %$refObject });
- } elsif (ref $refObject eq 'ARRAY' ) {
- return ($cache->{$refObject} = [ map { SimpleCopy($_,$cache) } @$refObject]);
- } else {
- return ($cache->{$refObject} = $refObject);
- }
-}
-
-sub Split {
- my ($this,$date) = @_;
-
- die new Exception('Can\'t split the timeline with an undefined date') unless $date;
-
- for (my $i = 0; $i < @{$this->{$Timeline}}; $i++) {
- my $Elem = $this->{$Timeline}[$i];
- if ($Elem->{Date} and $Elem->{Date} >= $date ) {
- if ($Elem->{Date} == $date) {
- return $Elem;
- } else {
- my $newElem = SimpleCopy($this->{$Timeline}[$i-1]);
- $newElem->{Date} = $date;
- use Data::Dumper;
-
- splice @{$this->{$Timeline}},$i,0,$newElem;
- return $newElem;
- }
- }
- }
- my $Elem = { Date => $date };
- push @{$this->{$Timeline}},$Elem;
- return $Elem;
-}
-
-sub Select {
- my ($this,$start,$end) = @_;
-
- my @result;
-
- for (my $i=0; $i< @{$this->{$Timeline}}; $i++) {
- my $Elem = $this->{$Timeline}[$i];
- my $Next = $this->{$Timeline}[$i+1];
- if (
- (not $Elem->{Date} or not $start or $Elem->{Date} < $start)
- and
- (not $Next->{Date} or not $start or $Next->{Date} > $start)
- ) {
- # ------*++++(++++*----...--)---
- push @result,$Elem;
- } elsif (
- $Elem->{Date}
- and
- (not $start or $Elem->{Date} >= $start)
- and
- (not $end or $Elem->{Date} < $end )
- ) {
- # ------*---(----*++...++*++)+++*----
- push @result,$Elem;
- } elsif ( $Elem->{Date} and $end and $Elem->{Date} >= $end) {
- last;
- }
- }
-
- return @result;
-}
-
-sub SelectStrict {
- my ($this,$start,$end) = @_;
- $this->Split($start);
- $this->Split($end);
- return grep {
- $_->{Date}
- and
- $start ? $_->{Date} >= $start : 1
- and
- $end ? $_->{Date} < $end : 1
- } @{$this->{$Timeline}};
-}
-
-sub SelectAsPeriod {
- my ($this,$start,$end) = @_;
-
- my @Dates = $this->Select($start,$end);
- for (my $i = 0; $i< @Dates; $i++) {
- $Dates[$i]->{Start} = $Dates[$i]->{Date};
- $Dates[$i]->{End} = $Dates[$i+1] ? $Dates[$i+1]->{Date} : undef
- }
-
- return @Dates;
-}
-
-1;
+use strict;
+package DateTime::Span;
+package DateTime;
+use Common;
+use Time::Local;
+use Time::Zone;
+use Date::Format;
+our @ISA = qw(Object);
+
+use overload
+ '+' => \&opAdd,
+ '-' => \&opSubtract,
+ '<=>' => \&opCompare,
+ 'bool' => \&opAsBool,
+ 'fallback' => 1,
+ '""' => \&opAsString;
+
+BEGIN {
+ DeclareProperty UnixTime => ACCESS_READ;
+}
+
+sub CTOR {
+ my $this = shift;
+
+ if (@_ >= 2) {
+ my(%args) = @_;
+
+ $this->{$UnixTime} = $args{UnixTime} or die new Exception("A correct unix time value is required");
+ } else {
+ $this->{$UnixTime} = $this->ParseISOTime(shift,'+000');
+ }
+}
+
+sub ParseISOTime {
+ my ($class,$time,$timezone) = @_;
+
+ if ($time =~ /^(\d{4})-(\d{2})-(\d{2})(?:.(\d{2}):(\d{2}):(\d{2})(?:\.\d{3})?)?/ ) {
+ my ($yyyy,$mm,$dd,$hh,$MM,$SS) = ($1-1900,$2-1,$3,$4 || 0,$5 || 0,$6 || 0);
+ if ($timezone) {
+ return tz_offset($timezone) + timegm($SS,$MM,$hh,$dd,$mm,$yyyy);
+ } else {
+ return timelocal($SS,$MM,$hh,$dd,$mm,$yyyy);
+ }
+ } else {
+ die new Exception("The specified string isn\'t a correct ISO date",$time);
+ }
+}
+
+sub new_ISO {
+ my ($class,$ISOTime,$zone) = @_;
+ return $class->new(UnixTime => $class->ParseISOTime($ISOTime,$zone));
+}
+
+sub now {
+ my ($class) = @_;
+ return $class->new(UnixTime => time);
+}
+
+sub AsISOString {
+ my ($this,$zone) = @_;
+ return time2str("%Y-%m-%dT%H:%M:%S",$this->{$UnixTime},$zone);
+}
+
+sub AsFormatString {
+ my ($this,$format,$zone) = @_;
+ return time2str($format,$this->{$UnixTime},$zone);
+}
+
+sub opAdd {
+ my ($a,$b,$flag) = @_;
+
+ if (UNIVERSAL::isa($b,'DateTime::Span')) {
+ return new DateTime(UnixTime => $a->{$UnixTime} + $b->SecondsSpan);
+ } elsif (not ref $b){
+ return new DateTime(UnixTime => $a->UnixTime + $b);
+ } else {
+ die new Exception("Only a time span can be added to the DateTime object",$b);
+ }
+}
+
+sub GetDate {
+ my ($this) = @_;
+
+ return DateTime->new_ISO($this->AsFormatString('%Y-%m-%d'));
+}
+
+sub opSubtract {
+ my ($a,$b,$flag) = @_;
+
+ if (UNIVERSAL::isa($b,'DateTime')) {
+ return new DateTime::Span(Seconds => $a->{$UnixTime}-$b->{$UnixTime});
+ } elsif (UNIVERSAL::isa($b,'DateTime::Span')) {
+ return new DateTime(UnixTime => $flag ? $b->SecondsSpan - $a->UnixTime: $a->UnixTime - $b->SecondsSpan);
+ } elsif (not ref $b){
+ return new DateTime(UnixTime => $flag ? $b - $a->UnixTime : $a->UnixTime - $b);
+ } else {
+ die new Exception("Only an another DateTime object or a time span can be subtracted from the DateTime",$b);
+ }
+}
+
+sub opCompare {
+ my ($a,$b,$flag) = @_;
+
+ if (UNIVERSAL::isa($b,'DateTime')) {
+ return $flag ? $b->{$UnixTime} <=> $a->{$UnixTime} : $a->{$UnixTime} <=> $b->{$UnixTime};
+ } else {
+ die new Exception("Only a DateTime object can be compared to the DateTime object", $b);
+ }
+}
+
+sub opAsString {
+ my $this = shift;
+ $this->AsISOString('+000');
+}
+
+sub opAsBool {
+ 1;
+}
+
+package DateTime::Span;
+use Common;
+our @ISA = qw(Object);
+
+use overload
+ '-' => \&opSub,
+ '+' => \&opAdd,
+ '<=>' => \&opCmp,
+ 'fallback' => 1;
+
+BEGIN {
+ DeclareProperty SecondsSpan=>ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$SecondsSpan} = ($args{'Seconds'} || 0) + ($args{'Minutes'} || 0)*60 + ($args{'Hours'} || 0)*3600 + ($args{'Days'} || 0)*86400;
+}
+
+sub Days {
+ my ($this) = @_;
+
+ return int($this->{$SecondsSpan}/86400);
+}
+
+sub Hours {
+ my ($this) = @_;
+
+ return int($this->{$SecondsSpan}/3600);
+}
+sub Minutes {
+ my ($this) = @_;
+
+ return int($this->{$SecondsSpan}/60);
+}
+
+sub opAdd {
+ my ($a,$b,$flag) = @_;
+
+ if (UNIVERSAL::isa($b,'DateTime::Span')) {
+ return new DateTime::Span(Seconds => $a->{$SecondsSpan} + $b->{$SecondsSpan});
+ } elsif (not ref $b) {
+ return new DateTime::Span(Seconds => $a->{$SecondsSpan} + $b);
+ } else {
+ die new Exception("Only a time span can be added to the time span");
+ }
+}
+
+sub opSub {
+ my ($a,$b,$flag) = @_;
+
+ if (UNIVERSAL::isa($b,'DateTime::Span')) {
+ return new DateTime::Span(Seconds => $flag ? $b->{$SecondsSpan} - $a->{$SecondsSpan} : $a->{$SecondsSpan} - $b->{$SecondsSpan});
+ } elsif (not ref $b) {
+ return new DateTime::Span(Seconds => $flag ? $b - $a->{$SecondsSpan} : $a->{$SecondsSpan} - $b);
+ } else {
+ die new Exception("Only a time span can be subtracted from the time span");
+ }
+}
+
+sub opCmp {
+ my ($a,$b,$flag) = @_;
+
+ if (UNIVERSAL::isa($b,'DateTime::Span')) {
+ return $flag ? $b->{$SecondsSpan} <=> $a->{$SecondsSpan} : $a->{$SecondsSpan} <=> $b->{$SecondsSpan};
+ } elsif (not ref $b) {
+ return $flag ? $b <=> $a->{$SecondsSpan} : $a->{$SecondsSpan} <=> $b;
+ } else {
+ die new Exception("Only a time span can be compared to the time span");
+ }
+}
+
+package DateTime::TimeLine;
+use Common;
+our @ISA = qw(Object);
+
+BEGIN {
+ DeclareProperty Timeline => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this) = @_;
+
+ $this->{$Timeline} = [ {Date => undef} ];
+}
+
+# рекурсивно копирует простые структуры
+sub SimpleCopy {
+ my ($refObject,$cache) = @_;
+
+ return undef if not defined $refObject;
+
+ $cache ||= {};
+
+ if ($cache->{$refObject}) {
+ return $cache->{$refObject};
+ }
+
+ local $_;
+
+ if (ref $refObject eq 'HASH' ) {
+ return ($cache->{$refObject} = { map { $_, SimpleCopy($refObject->{$_},$cache) } keys %$refObject });
+ } elsif (ref $refObject eq 'ARRAY' ) {
+ return ($cache->{$refObject} = [ map { SimpleCopy($_,$cache) } @$refObject]);
+ } else {
+ return ($cache->{$refObject} = $refObject);
+ }
+}
+
+sub Split {
+ my ($this,$date) = @_;
+
+ die new Exception('Can\'t split the timeline with an undefined date') unless $date;
+
+ for (my $i = 0; $i < @{$this->{$Timeline}}; $i++) {
+ my $Elem = $this->{$Timeline}[$i];
+ if ($Elem->{Date} and $Elem->{Date} >= $date ) {
+ if ($Elem->{Date} == $date) {
+ return $Elem;
+ } else {
+ my $newElem = SimpleCopy($this->{$Timeline}[$i-1]);
+ $newElem->{Date} = $date;
+ use Data::Dumper;
+
+ splice @{$this->{$Timeline}},$i,0,$newElem;
+ return $newElem;
+ }
+ }
+ }
+ my $Elem = { Date => $date };
+ push @{$this->{$Timeline}},$Elem;
+ return $Elem;
+}
+
+sub Select {
+ my ($this,$start,$end) = @_;
+
+ my @result;
+
+ for (my $i=0; $i< @{$this->{$Timeline}}; $i++) {
+ my $Elem = $this->{$Timeline}[$i];
+ my $Next = $this->{$Timeline}[$i+1];
+ if (
+ (not $Elem->{Date} or not $start or $Elem->{Date} < $start)
+ and
+ (not $Next->{Date} or not $start or $Next->{Date} > $start)
+ ) {
+ # ------*++++(++++*----...--)---
+ push @result,$Elem;
+ } elsif (
+ $Elem->{Date}
+ and
+ (not $start or $Elem->{Date} >= $start)
+ and
+ (not $end or $Elem->{Date} < $end )
+ ) {
+ # ------*---(----*++...++*++)+++*----
+ push @result,$Elem;
+ } elsif ( $Elem->{Date} and $end and $Elem->{Date} >= $end) {
+ last;
+ }
+ }
+
+ return @result;
+}
+
+sub SelectStrict {
+ my ($this,$start,$end) = @_;
+ $this->Split($start);
+ $this->Split($end);
+ return grep {
+ $_->{Date}
+ and
+ $start ? $_->{Date} >= $start : 1
+ and
+ $end ? $_->{Date} < $end : 1
+ } @{$this->{$Timeline}};
+}
+
+sub SelectAsPeriod {
+ my ($this,$start,$end) = @_;
+
+ my @Dates = $this->Select($start,$end);
+ for (my $i = 0; $i< @Dates; $i++) {
+ $Dates[$i]->{Start} = $Dates[$i]->{Date};
+ $Dates[$i]->{End} = $Dates[$i+1] ? $Dates[$i+1]->{Date} : undef
+ }
+
+ return @Dates;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Deployment.pm
--- a/Lib/Deployment.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Deployment.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,15 +1,15 @@
-package Deployment;
-use strict;
-
-our %DeploymentScheme;
-our %DeployMethod;
-
-sub isUpdateNeeded {
-
-}
-
-sub Update {
-
-}
-
-1;
+package Deployment;
+use strict;
+
+our %DeploymentScheme;
+our %DeployMethod;
+
+sub isUpdateNeeded {
+
+}
+
+sub Update {
+
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Deployment/Batch.pm
--- a/Lib/Deployment/Batch.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Deployment/Batch.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,129 +1,129 @@
-use strict;
-
-package Deployment::Batch;
-
-require URI::file;
-
-my %Provider;
-our $AUTOLOAD;
-
-our %Dirs;
-our %Context;
-
-$Context{DieOnError} = 1; # dies by default if the action fails to run
-
-our @history;
-
-# make all inc absolute;
-@INC = map { URI::file->new_abs($_)->dir } @INC;
-
-sub AUTOLOAD {
- my $method = $AUTOLOAD;
-
- shift if $_[0] eq __PACKAGE__;
-
- my $class = "$method";
-
- if (not $Provider{$method}) {
- (my $file = "$class.pm") =~ s/::/\//g;
- require $file;
- $Provider{$method} = 1;
- }
-
- my $action = $class->new(@_);
-
- push @history,$action;
- if ($Context{Immediate}) {
- $action->_Run or ($Context{DieOnError} ? die $_->LastError : return 0);
- }
-
- return 1;
-}
-
-sub SetDir {
- shift if $_[0] eq __PACKAGE__;
- my ($name,$dir) = @_;
-
- $Dirs{$name} = URI::file->new_abs($dir);
-}
-
-sub Rollback {
- return 1 if not @history;
-
- $_->_Rollback or $_->Log('Rollback: ',$_->LastError) foreach reverse grep { $_->isProcessed } @history;
- undef @history;
- return 1;
-}
-
-sub Commit {
- return 1 if not @history;
-
- # during commit we are in the immediate mode
- local $Context{Immediate} = 1;
-
- $_->_Run or $_->Log('Run: ',$_->LastError) and Rollback() and last foreach grep { not $_->isProcessed } @history;
- return 0 if not @history;
- undef @history;
- return 1;
-}
-
-sub DoPackage {
- shift if $_[0] eq __PACKAGE__;
- my ($package,$inline) = @_;
-
- Log( "The package is required" ) and return 0 if not $package;
- Log( "Processing $package" );
- my $t0 = [Time::HiRes::gettimeofday];
-
- if ($inline and $inline eq 'inline') {
- $inline = 1;
- } else {
- $inline = 0;
- }
-
- if (not $inline) {
- my %copy = %Context;
- local %Context = %copy;
- local @history = ();
- $Context{Package} = $Context{PackageDir} ? URI::file->new($package)->abs($Context{PackageDir}) : URI::file->new_abs($package);
- $Context{PackageDir} = URI::file->new('./')->abs($Context{Package});
-
- undef $@;
- do $package or Log("$package: ". ($@ || $!)) and Rollback() and Log("Rollback completed in ",Time::HiRes::tv_interval($t0)," s") and return 0;
-
- Log("Commiting");
- Commit or Log("Commit failed in ",Time::HiRes::tv_interval($t0)) and return 0;
- Log("Commit successful in ",Time::HiRes::tv_interval($t0),' s');
- return 1;
- } else {
- local $Context{Package} = $Context{PackageDir} ? URI::file->new($package)->abs($Context{PackageDir}) : URI::file->new_abs($package);
- local $Context{PackageDir} = URI::file->new('./')->abs($Context{Package});
-
- do $package or Log("$package: ". ($@ || $!)) and Rollback() and Log("Rollback completed in ",Time::HiRes::tv_interval($t0),' s') and return 0;
-
- return 1;
- }
-}
-
-sub Dir {
- shift if $_[0] eq __PACKAGE__;
- my $uriDir = $Dirs{$_[0]} or die "No such directory entry $_[0]";
- shift;
- return $uriDir->dir.join('/',@_);
-}
-
-sub PackageDir {
- shift if $_[0] eq __PACKAGE__;
- return $Context{PackageDir}->dir.join('/',@_);
-}
-
-sub Log {
- shift if $_[0] eq __PACKAGE__;
-
- if (my $hout = $Context{LogOutput}) {
- print $hout 'DoPackage: ',@_,"\n";
- }
- 1;
-}
-
-1;
\ No newline at end of file
+use strict;
+
+package Deployment::Batch;
+
+require URI::file;
+
+my %Provider;
+our $AUTOLOAD;
+
+our %Dirs;
+our %Context;
+
+$Context{DieOnError} = 1; # dies by default if the action fails to run
+
+our @history;
+
+# make all inc absolute;
+@INC = map { URI::file->new_abs($_)->dir } @INC;
+
+sub AUTOLOAD {
+ my $method = $AUTOLOAD;
+
+ shift if $_[0] eq __PACKAGE__;
+
+ my $class = "$method";
+
+ if (not $Provider{$method}) {
+ (my $file = "$class.pm") =~ s/::/\//g;
+ require $file;
+ $Provider{$method} = 1;
+ }
+
+ my $action = $class->new(@_);
+
+ push @history,$action;
+ if ($Context{Immediate}) {
+ $action->_Run or ($Context{DieOnError} ? die $_->LastError : return 0);
+ }
+
+ return 1;
+}
+
+sub SetDir {
+ shift if $_[0] eq __PACKAGE__;
+ my ($name,$dir) = @_;
+
+ $Dirs{$name} = URI::file->new_abs($dir);
+}
+
+sub Rollback {
+ return 1 if not @history;
+
+ $_->_Rollback or $_->Log('Rollback: ',$_->LastError) foreach reverse grep { $_->isProcessed } @history;
+ undef @history;
+ return 1;
+}
+
+sub Commit {
+ return 1 if not @history;
+
+ # during commit we are in the immediate mode
+ local $Context{Immediate} = 1;
+
+ $_->_Run or $_->Log('Run: ',$_->LastError) and Rollback() and last foreach grep { not $_->isProcessed } @history;
+ return 0 if not @history;
+ undef @history;
+ return 1;
+}
+
+sub DoPackage {
+ shift if $_[0] eq __PACKAGE__;
+ my ($package,$inline) = @_;
+
+ Log( "The package is required" ) and return 0 if not $package;
+ Log( "Processing $package" );
+ my $t0 = [Time::HiRes::gettimeofday()];
+
+ if ($inline and $inline eq 'inline') {
+ $inline = 1;
+ } else {
+ $inline = 0;
+ }
+
+ if (not $inline) {
+ my %copy = %Context;
+ local %Context = %copy;
+ local @history = ();
+ $Context{Package} = $Context{PackageDir} ? URI::file->new($package)->abs($Context{PackageDir}) : URI::file->new_abs($package);
+ $Context{PackageDir} = URI::file->new('./')->abs($Context{Package});
+
+ undef $@;
+ do $package or Log("$package: ". ($@ || $!)) and Rollback() and Log("Rollback completed in ",Time::HiRes::tv_interval($t0)," s") and return 0;
+
+ Log("Commiting");
+ Commit or Log("Commit failed in ",Time::HiRes::tv_interval($t0)) and return 0;
+ Log("Commit successful in ",Time::HiRes::tv_interval($t0),' s');
+ return 1;
+ } else {
+ local $Context{Package} = $Context{PackageDir} ? URI::file->new($package)->abs($Context{PackageDir}) : URI::file->new_abs($package);
+ local $Context{PackageDir} = URI::file->new('./')->abs($Context{Package});
+
+ do $package or Log("$package: ". ($@ || $!)) and Rollback() and Log("Rollback completed in ",Time::HiRes::tv_interval($t0),' s') and return 0;
+
+ return 1;
+ }
+}
+
+sub Dir {
+ shift if $_[0] eq __PACKAGE__;
+ my $uriDir = $Dirs{$_[0]} or die "No such directory entry $_[0]";
+ shift;
+ return $uriDir->dir.join('/',@_);
+}
+
+sub PackageDir {
+ shift if $_[0] eq __PACKAGE__;
+ return $Context{PackageDir}->dir.join('/',@_);
+}
+
+sub Log {
+ shift if $_[0] eq __PACKAGE__;
+
+ if (my $hout = $Context{LogOutput}) {
+ print $hout 'DoPackage: ',@_,"\n";
+ }
+ 1;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Deployment/Batch/Backup.pm
--- a/Lib/Deployment/Batch/Backup.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Deployment/Batch/Backup.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,48 +1,48 @@
-package Deployment::Batch::Backup;
-use base qw(Deployment::Batch::Generic);
-use Common;
-use File::Copy;
-
-BEGIN {
- DeclareProperty Action => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,$actionName,$actionArg) = @_;
-
- $this->{$Action} = { Name => $actionName, Arg => $actionArg };
-}
-
-sub Run {
- my ($this) = @_;
-
- my $tmpObj;
-
- # we are in the immediate mode
- if ($this->{$Action}{Name} eq 'File') {
- $this->Log("Backup file: $this->{$Action}{Arg}");
- if (-e $this->{$Action}{Arg}) {
-
- Deployment::Batch->Temp( File => \$tmpObj ) or die "Failed to create temp file" ;
-
- copy ($this->{$Action}{Arg}, $tmpObj->filename) or die "Failed to backup";
- $this->{$Action}{Result} = $tmpObj->filename;
- }
- } else {
- die "Don't know how to backup the $this->{$Action}{Name}";
- }
-}
-
-sub Rollback {
- my ($this) = @_;
- if ($this->{$Action}{Name} eq 'File') {
- $this->Log("Revert file: $this->{$Action}{Arg}");
- if ($this->{$Action}{Result}) {
- copy ($this->{$Action}{Result}, $this->{$Action}{Arg}) or die "Failed to backup";
- } else {
- unlink $this->{$Action}{Arg} if -f $this->{$Action}{Arg};
- }
- }
-}
-
-1;
\ No newline at end of file
+package Deployment::Batch::Backup;
+use base qw(Deployment::Batch::Generic);
+use Common;
+use File::Copy;
+
+BEGIN {
+ DeclareProperty Action => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,$actionName,$actionArg) = @_;
+
+ $this->{$Action} = { Name => $actionName, Arg => $actionArg };
+}
+
+sub Run {
+ my ($this) = @_;
+
+ my $tmpObj;
+
+ # we are in the immediate mode
+ if ($this->{$Action}{Name} eq 'File') {
+ $this->Log("Backup file: $this->{$Action}{Arg}");
+ if (-e $this->{$Action}{Arg}) {
+
+ Deployment::Batch->Temp( File => \$tmpObj ) or die "Failed to create temp file" ;
+
+ copy ($this->{$Action}{Arg}, $tmpObj->filename) or die "Failed to backup";
+ $this->{$Action}{Result} = $tmpObj->filename;
+ }
+ } else {
+ die "Don't know how to backup the $this->{$Action}{Name}";
+ }
+}
+
+sub Rollback {
+ my ($this) = @_;
+ if ($this->{$Action}{Name} eq 'File') {
+ $this->Log("Revert file: $this->{$Action}{Arg}");
+ if ($this->{$Action}{Result}) {
+ copy ($this->{$Action}{Result}, $this->{$Action}{Arg}) or die "Failed to backup";
+ } else {
+ unlink $this->{$Action}{Arg} if -f $this->{$Action}{Arg};
+ }
+ }
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Deployment/Batch/CDBIUpdate.pm
--- a/Lib/Deployment/Batch/CDBIUpdate.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Deployment/Batch/CDBIUpdate.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,139 +1,139 @@
-use strict;
-package Deployment::Batch::CDBIUpdate;
-use Common;
-use base qw(Deployment::Batch::Generic);
-
-use DBI;
-use Schema::DataSource;
-use Schema::DataSource::CDBIBuilder;
-
-
-BEGIN {
- DeclareProperty DataSchemaFile => ACCESS_READ;
- DeclareProperty DataSourceDir => ACCESS_READ;
- DeclareProperty DSNamespace => ACCESS_READ;
- DeclareProperty DBConnection => ACCESS_READ;
- DeclareProperty DBTraitsClass => ACCESS_READ;
- DeclareProperty SchemaPrev => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$DataSchemaFile} = $args{'Source'} or die new Exception('A data shema file is required');
- $this->{$DataSourceDir} = $args{'Output'} or die new Exception('A directory for a data source is required');
- $this->{$DSNamespace} = $args{'Namespace'} || 'DataSource';
- $this->{$DBTraitsClass} = $args{'DBTraits'} or die new Exception('A DBTraitsClass is required');
-
- (my $modname = $args{'DBTraits'}.'.pm') =~ s/::/\//g;
- $this->Log("Loading DBTraits '$modname'");
- require $modname;
-}
-
-sub Run {
- my ($this) = @_;
-
- $this->{$DBConnection} = $this->Context->{Connection};
-
- my $prefix = $this->{$DSNamespace}.'::';
-
- my $schemaDS = new Schema::DataSource(DataSourceBuilder => new Schema::DataSource::CDBIBuilder);
- $schemaDS->BuildSchema($this->{$DataSchemaFile});
-
- my $schemaDB = $schemaDS->DataSourceBuilder->BuildDBSchema();
- (my $fname = $this->{$DataSourceDir}.$this->{$DSNamespace}.'.pm') =~ s/::/\//g;
-
- # we are in the immediate mode, so the file will be backupped immediatelly;
- $this->Log("Backup $fname");
- Deployment::Batch->Backup( File => $fname );
-
- $this->Log("Write the datasource '$this->{$DSNamespace}' to '$this->{$DataSourceDir}'");
- $schemaDS->DataSourceBuilder->WriteModules($fname,$prefix);
-
- if ($this->{$DBConnection}) {
- $this->Log("Update the database '$this->{$DBConnection}[0]'");
-
- $this->{$SchemaPrev} = $this->UpdateDBToSchema($schemaDB);
-
- }
- $schemaDB->Dispose;
-}
-
-sub Rollback {
- my ($this) = @_;
-
- if ($this->{$SchemaPrev}) {
- $this->Log("Rallback the DB schema");
- $this->UpdateDBToSchema($this->{$SchemaPrev})->Dispose;
- $this->{$SchemaPrev}->Dispose;
- delete $this->{$SchemaPrev};
- }
-
-}
-
-sub UpdateDBToSchema {
- my ($this,$schemaDB) = @_;
- my $dbh = DBI->connect(@{$this->{$DBConnection}}) or die new Exception('Failed to connect to the database',@{$this->{$DBConnection}});
- my $SchemaSource;
-
- if (UNIVERSAL::can($this->{$DBTraitsClass},'GetMetaTable')) {
- $SchemaSource = new Deployment::CDBI::SQLSchemeSource (MetaTable => $this->{$DBTraitsClass}->GetMetaTable($dbh));
- } else {
- die new Exception("Can't get a meta table",$this->{$DBTraitsClass});
- }
-
- my $schemaDBOld = $SchemaSource->ReadSchema($schemaDB->Name);
-
- my $updater = $this->{$DBTraitsClass}->new(SrcSchema => $schemaDBOld, DstSchema => $schemaDB);
- $updater->UpdateSchema();
-
- $dbh->do($_) or die new Exception('Failed to execute the sql statement', $_) foreach $updater->Handler->Sql;
-
- $SchemaSource->SaveSchema($schemaDB);
- return $schemaDBOld;
-}
-
-sub DESTROY {
- my $this = shift;
-
- $this->{$SchemaPrev}->Dispose if $this->{$SchemaPrev};
-}
-
-package Deployment::CDBI::SQLSchemeSource;
-use Common;
-use Data::Dumper;
-use MIME::Base64;
-use Storable qw(nstore_fd fd_retrieve);
-our @ISA = qw(Object);
-
-BEGIN {
- DeclareProperty MetaTable => ACCESS_NONE;
-}
-
-sub ReadSchema {
- my ($this,$name) = @_;
-
- my $schema = decode_base64($this->{$MetaTable}->ReadProperty("db_schema_$name"));
- if ($schema) {
- open my $hvar,"<",\$schema or die new Exception("Failed to create a handle to the variable");
- return fd_retrieve($hvar);
- } else {
- return new Schema::DB(Name => $name, Version => 0);
- }
-}
-
-sub SaveSchema {
- my ($this,$schema) = @_;
-
- my $name = $schema->Name;
-
- my $data = "";
- {
- open my $hvar,">",\$data or die new Exception("Failed to create a handle to the variable");
- nstore_fd($schema,$hvar);
- }
-
- $this->{$MetaTable}->SetProperty("db_schema_$name",encode_base64($data));
-}
-
-1;
\ No newline at end of file
+use strict;
+package Deployment::Batch::CDBIUpdate;
+use Common;
+use base qw(Deployment::Batch::Generic);
+
+use DBI;
+use Schema::DataSource;
+use Schema::DataSource::CDBIBuilder;
+
+
+BEGIN {
+ DeclareProperty DataSchemaFile => ACCESS_READ;
+ DeclareProperty DataSourceDir => ACCESS_READ;
+ DeclareProperty DSNamespace => ACCESS_READ;
+ DeclareProperty DBConnection => ACCESS_READ;
+ DeclareProperty DBTraitsClass => ACCESS_READ;
+ DeclareProperty SchemaPrev => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$DataSchemaFile} = $args{'Source'} or die new Exception('A data shema file is required');
+ $this->{$DataSourceDir} = $args{'Output'} or die new Exception('A directory for a data source is required');
+ $this->{$DSNamespace} = $args{'Namespace'} || 'DataSource';
+ $this->{$DBTraitsClass} = $args{'DBTraits'} or die new Exception('A DBTraitsClass is required');
+
+ (my $modname = $args{'DBTraits'}.'.pm') =~ s/::/\//g;
+ $this->Log("Loading DBTraits '$modname'");
+ require $modname;
+}
+
+sub Run {
+ my ($this) = @_;
+
+ $this->{$DBConnection} = $this->Context->{Connection};
+
+ my $prefix = $this->{$DSNamespace}.'::';
+
+ my $schemaDS = new Schema::DataSource(DataSourceBuilder => new Schema::DataSource::CDBIBuilder);
+ $schemaDS->BuildSchema($this->{$DataSchemaFile});
+
+ my $schemaDB = $schemaDS->DataSourceBuilder->BuildDBSchema();
+ (my $fname = $this->{$DataSourceDir}.$this->{$DSNamespace}.'.pm') =~ s/::/\//g;
+
+ # we are in the immediate mode, so the file will be backupped immediatelly;
+ $this->Log("Backup $fname");
+ Deployment::Batch->Backup( File => $fname );
+
+ $this->Log("Write the datasource '$this->{$DSNamespace}' to '$this->{$DataSourceDir}'");
+ $schemaDS->DataSourceBuilder->WriteModules($fname,$prefix);
+
+ if ($this->{$DBConnection}) {
+ $this->Log("Update the database '$this->{$DBConnection}[0]'");
+
+ $this->{$SchemaPrev} = $this->UpdateDBToSchema($schemaDB);
+
+ }
+ $schemaDB->Dispose;
+}
+
+sub Rollback {
+ my ($this) = @_;
+
+ if ($this->{$SchemaPrev}) {
+ $this->Log("Rallback the DB schema");
+ $this->UpdateDBToSchema($this->{$SchemaPrev})->Dispose;
+ $this->{$SchemaPrev}->Dispose;
+ delete $this->{$SchemaPrev};
+ }
+
+}
+
+sub UpdateDBToSchema {
+ my ($this,$schemaDB) = @_;
+ my $dbh = DBI->connect(@{$this->{$DBConnection}}) or die new Exception('Failed to connect to the database',@{$this->{$DBConnection}});
+ my $SchemaSource;
+
+ if (UNIVERSAL::can($this->{$DBTraitsClass},'GetMetaTable')) {
+ $SchemaSource = new Deployment::CDBI::SQLSchemeSource (MetaTable => $this->{$DBTraitsClass}->GetMetaTable($dbh));
+ } else {
+ die new Exception("Can't get a meta table",$this->{$DBTraitsClass});
+ }
+
+ my $schemaDBOld = $SchemaSource->ReadSchema($schemaDB->Name);
+
+ my $updater = $this->{$DBTraitsClass}->new(SrcSchema => $schemaDBOld, DstSchema => $schemaDB);
+ $updater->UpdateSchema();
+
+ $dbh->do($_) or die new Exception('Failed to execute the sql statement', $_) foreach $updater->Handler->Sql;
+
+ $SchemaSource->SaveSchema($schemaDB);
+ return $schemaDBOld;
+}
+
+sub DESTROY {
+ my $this = shift;
+
+ $this->{$SchemaPrev}->Dispose if $this->{$SchemaPrev};
+}
+
+package Deployment::CDBI::SQLSchemeSource;
+use Common;
+use Data::Dumper;
+use MIME::Base64;
+use Storable qw(nstore_fd fd_retrieve);
+our @ISA = qw(Object);
+
+BEGIN {
+ DeclareProperty MetaTable => ACCESS_NONE;
+}
+
+sub ReadSchema {
+ my ($this,$name) = @_;
+
+ my $schema = decode_base64($this->{$MetaTable}->ReadProperty("db_schema_$name"));
+ if ($schema) {
+ open my $hvar,"<",\$schema or die new Exception("Failed to create a handle to the variable");
+ return fd_retrieve($hvar);
+ } else {
+ return new Schema::DB(Name => $name, Version => 0);
+ }
+}
+
+sub SaveSchema {
+ my ($this,$schema) = @_;
+
+ my $name = $schema->Name;
+
+ my $data = "";
+ {
+ open my $hvar,">",\$data or die new Exception("Failed to create a handle to the variable");
+ nstore_fd($schema,$hvar);
+ }
+
+ $this->{$MetaTable}->SetProperty("db_schema_$name",encode_base64($data));
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Deployment/Batch/CopyFile.pm
--- a/Lib/Deployment/Batch/CopyFile.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Deployment/Batch/CopyFile.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,45 +1,45 @@
-use strict;
-package Deployment::Batch;
-our %Dirs;
-package Deployment::Batch::CopyFile;
-use base qw(Deployment::Batch::Generic);
-use File::Copy;
-require URI::file;
-use Common;
-
-BEGIN {
- DeclareProperty Src => ACCESS_READ;
- DeclareProperty Dst => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,$src,$dest,$Dir) = @_;
-
- $src or die "Source file name is required";
- $dest or die "Destination file name is reqiured";
-
- my $uriSrc = URI::file->new($src)->abs($this->Context->{PackageDir});
-
- my $uriDest = URI::file->new($dest);
-
- $uriDest = $uriDest->abs(
- ($Dir and $Dirs{$Dir}) ?
- $Dirs{$Dir} :
- $this->Context->{PackageDir}
- );
-
- $this->{$Src} = $uriSrc->file;
- $this->{$Dst} = $uriDest->file;
-}
-
-sub Run {
- my ($this) = @_;
-
- $this->Log("Copy '$this->{$Src}' to '$this->{$Dst}'");
-
- Deployment::Batch->Backup( File => $this->{$Dst} );
-
- copy($this->{$Src},$this->{$Dst}) or die "copy failed: $!";
-}
-
-1;
+use strict;
+package Deployment::Batch;
+our %Dirs;
+package Deployment::Batch::CopyFile;
+use base qw(Deployment::Batch::Generic);
+use File::Copy;
+require URI::file;
+use Common;
+
+BEGIN {
+ DeclareProperty Src => ACCESS_READ;
+ DeclareProperty Dst => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,$src,$dest,$Dir) = @_;
+
+ $src or die "Source file name is required";
+ $dest or die "Destination file name is reqiured";
+
+ my $uriSrc = URI::file->new($src)->abs($this->Context->{PackageDir});
+
+ my $uriDest = URI::file->new($dest);
+
+ $uriDest = $uriDest->abs(
+ ($Dir and $Dirs{$Dir}) ?
+ $Dirs{$Dir} :
+ $this->Context->{PackageDir}
+ );
+
+ $this->{$Src} = $uriSrc->file;
+ $this->{$Dst} = $uriDest->file;
+}
+
+sub Run {
+ my ($this) = @_;
+
+ $this->Log("Copy '$this->{$Src}' to '$this->{$Dst}'");
+
+ Deployment::Batch->Backup( File => $this->{$Dst} );
+
+ copy($this->{$Src},$this->{$Dst}) or die "copy failed: $!";
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Deployment/Batch/CopyTree.pm
--- a/Lib/Deployment/Batch/CopyTree.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Deployment/Batch/CopyTree.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,5 +1,5 @@
-package Deployment::Batch::CopyTree;
-use base 'Deployment::Batch::Generic';
-use Common;
-
-1;
+package Deployment::Batch::CopyTree;
+use base 'Deployment::Batch::Generic';
+use Common;
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Deployment/Batch/CustomAction.pm
--- a/Lib/Deployment/Batch/CustomAction.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Deployment/Batch/CustomAction.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,32 +1,32 @@
-use strict;
-package Deployment::Batch::CustomAction;
-use base qw(Deployment::Batch::Generic);
-use Common;
-
-BEGIN {
- DeclareProperty handlerRun => ACCESS_READ;
- DeclareProperty handlerRollback => ACCESS_READ;
- DeclareProperty Name => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$handlerRun} = $args{Run} || sub {};
- $this->{$handlerRollback} = $args{Rollback} || sub {};
- $this->{$Name} = $args{Name} || $this->SUPER::Name();
-}
-
-sub Run {
- my ($this) = @_;
-
- $this->{$handlerRun}->($this);
-}
-
-sub Rollback {
- my ($this) = @_;
-
- $this->{$handlerRollback}->($this);
-}
-
-1;
\ No newline at end of file
+use strict;
+package Deployment::Batch::CustomAction;
+use base qw(Deployment::Batch::Generic);
+use Common;
+
+BEGIN {
+ DeclareProperty handlerRun => ACCESS_READ;
+ DeclareProperty handlerRollback => ACCESS_READ;
+ DeclareProperty Name => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$handlerRun} = $args{Run} || sub {};
+ $this->{$handlerRollback} = $args{Rollback} || sub {};
+ $this->{$Name} = $args{Name} || $this->SUPER::Name();
+}
+
+sub Run {
+ my ($this) = @_;
+
+ $this->{$handlerRun}->($this);
+}
+
+sub Rollback {
+ my ($this) = @_;
+
+ $this->{$handlerRollback}->($this);
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Deployment/Batch/Generic.pm
--- a/Lib/Deployment/Batch/Generic.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Deployment/Batch/Generic.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,87 +1,87 @@
-use strict;
-package Deployment::Batch;
-our @history;
-
-package Deployment::Batch::Generic;
-use Common;
-use Time::HiRes;
-our @ISA = qw(Object);
-
-BEGIN {
- DeclareProperty isProcessed => ACCESS_READ;
- DeclareProperty LastError => ACCESS_READ;
- DeclareProperty LocalHistory => ACCESS_NONE;
-}
-
-sub _Run {
- my ($this) = @_;
-
- undef $@;
- local @history = ();
- my $t0 = [Time::HiRes::gettimeofday];
- eval {
- $this->Run;
- };
- $this->Log("completed in ",Time::HiRes::tv_interval($t0)," s");
-
- if ($@) {
- $this->{$LastError} = $@;
- Deployment::Batch::Rollback; # rallback nested actions
- return 0;
- }
-
- $this->{$LocalHistory} = \@history;
- $this->{$isProcessed} = 1;
-
- return 1;
-}
-
-sub Name {
- my $this = shift;
- (my $mod = ref $this) =~ s/^(?:\w+\:\:)*(\w+)$/$1/;
- return $mod;
-}
-
-sub _Rollback {
- my ($this) = @_;
-
- undef $@;
- eval {
- $this->Rollback;
- };
-
- if ($@) {
- $this->{$LastError} = $@;
- }
-
- $this->{$isProcessed} = 0;
-
- if ($this->{$LocalHistory}) {
- local @history = @{$this->{$LocalHistory}};
- Deployment::Batch::Rollback;
- }
-
- return 1;
-}
-
-sub Context {
- my $this = shift;
-
- return \%Deployment::Batch::Context;
-}
-
-sub Log {
- my $this = shift @_;
- if ($this->Context->{LogOutput}) {
- my $out = $this->Context->{LogOutput};
- print $out $this->Name,": ",@_,"\n";
- }
-}
-
-sub Run {
-}
-
-sub Rollback {
-}
-
-1;
\ No newline at end of file
+use strict;
+package Deployment::Batch;
+our @history;
+
+package Deployment::Batch::Generic;
+use Common;
+use Time::HiRes;
+our @ISA = qw(Object);
+
+BEGIN {
+ DeclareProperty isProcessed => ACCESS_READ;
+ DeclareProperty LastError => ACCESS_READ;
+ DeclareProperty LocalHistory => ACCESS_NONE;
+}
+
+sub _Run {
+ my ($this) = @_;
+
+ undef $@;
+ local @history = ();
+ my $t0 = [Time::HiRes::gettimeofday];
+ eval {
+ $this->Run;
+ };
+ $this->Log("completed in ",Time::HiRes::tv_interval($t0)," s");
+
+ if ($@) {
+ $this->{$LastError} = $@;
+ Deployment::Batch::Rollback(); # rallback nested actions
+ return 0;
+ }
+
+ $this->{$LocalHistory} = \@history;
+ $this->{$isProcessed} = 1;
+
+ return 1;
+}
+
+sub Name {
+ my $this = shift;
+ (my $mod = ref $this) =~ s/^(?:\w+\:\:)*(\w+)$/$1/;
+ return $mod;
+}
+
+sub _Rollback {
+ my ($this) = @_;
+
+ undef $@;
+ eval {
+ $this->Rollback;
+ };
+
+ if ($@) {
+ $this->{$LastError} = $@;
+ }
+
+ $this->{$isProcessed} = 0;
+
+ if ($this->{$LocalHistory}) {
+ local @history = @{$this->{$LocalHistory}};
+ Deployment::Batch::Rollback();
+ }
+
+ return 1;
+}
+
+sub Context {
+ my $this = shift;
+
+ return \%Deployment::Batch::Context;
+}
+
+sub Log {
+ my $this = shift @_;
+ if ($this->Context->{LogOutput}) {
+ my $out = $this->Context->{LogOutput};
+ print $out $this->Name,": ",@_,"\n";
+ }
+}
+
+sub Run {
+}
+
+sub Rollback {
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Deployment/Batch/Temp.pm
--- a/Lib/Deployment/Batch/Temp.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Deployment/Batch/Temp.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,52 +1,52 @@
-use strict;
-package Deployment::Batch::Temp;
-use base qw(Deployment::Batch::Generic);
-use Common;
-use File::Temp;
-
-
-BEGIN {
- DeclareProperty TmpObj => ACCESS_READ;
- DeclareProperty Ref => ACCESS_NONE;
- DeclareProperty TmpObjType => ACCESS_NONE;
-}
-
-sub CTOR {
- my ($this,$type,$ref) = @_;
-
- die "A reference to the temp object can be obtained only in the immediate mode" if $ref and not $this->Context->{Immediate};
-
- $this->{$TmpObjType} = $type or die "The type of a temporary object should be specified";
- $this->{$Ref} = $ref;
-}
-
-sub Run {
- my ($this) = @_;
-
- if ($this->{$TmpObjType} eq 'File') {
- $this->{$TmpObj} = File::Temp->new;
- if ($this->{$Ref}) {
- ${$this->{$Ref}} = $this->{$TmpObj};
- } else {
- $this->Context('tmpfile') = $this->{$TmpObj}->filename;
- }
- } elsif ($this->{$TmpObjType} eq 'Dir') {
- $this->{$TmpObj} = File::Temp->newdir;
- if ($this->{$Ref}) {
- ${$this->{$Ref}} = $this->{$TmpObj};
- } else {
- $this->Context('tmpdir') = $this->{$TmpObj}->dirname;
- }
- } else {
- die "Don't know how to create a temporary $this->{$TmpObjType}";
- }
-}
-
-sub DESTORY {
- my ($this) = @_;
-
- undef $this->{$TmpObj};
-}
-
-
-1;
\ No newline at end of file
+use strict;
+package Deployment::Batch::Temp;
+use base qw(Deployment::Batch::Generic);
+use Common;
+use File::Temp;
+
+
+BEGIN {
+ DeclareProperty TmpObj => ACCESS_READ;
+ DeclareProperty Ref => ACCESS_NONE;
+ DeclareProperty TmpObjType => ACCESS_NONE;
+}
+
+sub CTOR {
+ my ($this,$type,$ref) = @_;
+
+ die "A reference to the temp object can be obtained only in the immediate mode" if $ref and not $this->Context->{Immediate};
+
+ $this->{$TmpObjType} = $type or die "The type of a temporary object should be specified";
+ $this->{$Ref} = $ref;
+}
+
+sub Run {
+ my ($this) = @_;
+
+ if ($this->{$TmpObjType} eq 'File') {
+ $this->{$TmpObj} = File::Temp->new;
+ if ($this->{$Ref}) {
+ ${$this->{$Ref}} = $this->{$TmpObj};
+ } else {
+ $this->Context('tmpfile') = $this->{$TmpObj}->filename;
+ }
+ } elsif ($this->{$TmpObjType} eq 'Dir') {
+ $this->{$TmpObj} = File::Temp->newdir;
+ if ($this->{$Ref}) {
+ ${$this->{$Ref}} = $this->{$TmpObj};
+ } else {
+ $this->Context('tmpdir') = $this->{$TmpObj}->dirname;
+ }
+ } else {
+ die "Don't know how to create a temporary $this->{$TmpObjType}";
+ }
+}
+
+sub DESTORY {
+ my ($this) = @_;
+
+ undef $this->{$TmpObj};
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Deployment/CDBI.pm
--- a/Lib/Deployment/CDBI.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Deployment/CDBI.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,101 +1,101 @@
-use strict;
-package Deployment::CDBI;
-use Common;
-use DBI;
-use Schema::DataSource;
-use Schema::DataSource::CDBIBuilder;
-
-our @ISA = qw(Object);
-
-BEGIN {
- DeclareProperty DataSchemaFile => ACCESS_READ;
- DeclareProperty DataSourceDir => ACCESS_READ;
- DeclareProperty DSNamespace => ACCESS_READ;
- DeclareProperty DBConnection => ACCESS_READ;
- DeclareProperty DBTraitsClass => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$DataSchemaFile} = $args{'DataSchemaFile'} or die new Exception('A data shema file is required');
- $this->{$DataSourceDir} = $args{'DataSourceDir'} or die new Exception('A directory for a data source is required');
- $this->{$DSNamespace} = $args{'DSNamespace'} || 'DataSource';
- $this->{$DBTraitsClass} = $args{'DBTraitsClass'} or die new Exception('A DBTraitsClass is required');
- $this->{$DBConnection} = $args{'DBConnection'};
-}
-
-sub Update {
- my ($this) = @_;
-
- my $prefix = $this->{$DSNamespace}.'::';
-
- my $schemaDS = new Schema::DataSource(DataSourceBuilder => new Schema::DataSource::CDBIBuilder);
- $schemaDS->BuildSchema($this->{$DataSchemaFile});
-
- my $schemaDB = $schemaDS->DataSourceBuilder->BuildDBSchema();
- (my $fname = $this->{$DSNamespace} ) =~ s/::/\//g;
- $schemaDS->DataSourceBuilder->WriteModules($this->{$DataSourceDir}.$fname.'.pm',$prefix);
-
- if ($this->{$DBConnection}) {
-
- my $dbh = DBI->connect(@{$this->{$DBConnection}}) or die new Exception('Failed to connect to the database',@{$this->{$DBConnection}});
- my $SchemaSource;
- if (UNIVERSAL::can($this->{$DBTraitsClass},'GetMetaTable')) {
- $SchemaSource = new Deployment::CDBI::SQLSchemeSource (MetaTable => $this->{$DBTraitsClass}->GetMetaTable($dbh));
- } else {
- die new Exception("Can't get meta table");
- }
-
- my $schemaDBOld = $SchemaSource->ReadSchema($schemaDB->Name);
-
- my $updater = $this->{$DBTraitsClass}->new(SrcSchema => $schemaDBOld, DstSchema => $schemaDB);
- $updater->UpdateSchema();
-
- $dbh->do($_) or die new Exception('Failed to execute the sql statement', $_) foreach $updater->Handler->Sql;
-
- $SchemaSource->SaveSchema($schemaDB);
-
- $schemaDBOld->Dispose;
- }
- $schemaDB->Dispose;
-}
-
-package Deployment::CDBI::SQLSchemeSource;
-use Common;
-use Data::Dumper;
-use MIME::Base64;
-use Storable qw(nstore_fd fd_retrieve);
-our @ISA = qw(Object);
-
-BEGIN {
- DeclareProperty MetaTable => ACCESS_NONE;
-}
-
-sub ReadSchema {
- my ($this,$name) = @_;
-
- my $schema = decode_base64($this->{$MetaTable}->ReadProperty("db_schema_$name"));
- if ($schema) {
- open my $hvar,"<",\$schema or die new Exception("Failed to create a handle to the variable");
- return fd_retrieve($hvar);
- } else {
- return new Schema::DB(Name => $name, Version => 0);
- }
-}
-
-sub SaveSchema {
- my ($this,$schema) = @_;
-
- my $name = $schema->Name;
-
- my $data;
- {
- open my $hvar,">",\$data or die new Exception("Failed to create a handle to the variable");
- nstore_fd($schema,$hvar);
- }
-
- $this->{$MetaTable}->SetProperty("db_schema_$name",encode_base64($data));
-}
-
-1;
+use strict;
+package Deployment::CDBI;
+use Common;
+use DBI;
+use Schema::DataSource;
+use Schema::DataSource::CDBIBuilder;
+
+our @ISA = qw(Object);
+
+BEGIN {
+ DeclareProperty DataSchemaFile => ACCESS_READ;
+ DeclareProperty DataSourceDir => ACCESS_READ;
+ DeclareProperty DSNamespace => ACCESS_READ;
+ DeclareProperty DBConnection => ACCESS_READ;
+ DeclareProperty DBTraitsClass => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$DataSchemaFile} = $args{'DataSchemaFile'} or die new Exception('A data shema file is required');
+ $this->{$DataSourceDir} = $args{'DataSourceDir'} or die new Exception('A directory for a data source is required');
+ $this->{$DSNamespace} = $args{'DSNamespace'} || 'DataSource';
+ $this->{$DBTraitsClass} = $args{'DBTraitsClass'} or die new Exception('A DBTraitsClass is required');
+ $this->{$DBConnection} = $args{'DBConnection'};
+}
+
+sub Update {
+ my ($this) = @_;
+
+ my $prefix = $this->{$DSNamespace}.'::';
+
+ my $schemaDS = new Schema::DataSource(DataSourceBuilder => new Schema::DataSource::CDBIBuilder);
+ $schemaDS->BuildSchema($this->{$DataSchemaFile});
+
+ my $schemaDB = $schemaDS->DataSourceBuilder->BuildDBSchema();
+ (my $fname = $this->{$DSNamespace} ) =~ s/::/\//g;
+ $schemaDS->DataSourceBuilder->WriteModules($this->{$DataSourceDir}.$fname.'.pm',$prefix);
+
+ if ($this->{$DBConnection}) {
+
+ my $dbh = DBI->connect(@{$this->{$DBConnection}}) or die new Exception('Failed to connect to the database',@{$this->{$DBConnection}});
+ my $SchemaSource;
+ if (UNIVERSAL::can($this->{$DBTraitsClass},'GetMetaTable')) {
+ $SchemaSource = new Deployment::CDBI::SQLSchemeSource (MetaTable => $this->{$DBTraitsClass}->GetMetaTable($dbh));
+ } else {
+ die new Exception("Can't get meta table");
+ }
+
+ my $schemaDBOld = $SchemaSource->ReadSchema($schemaDB->Name);
+
+ my $updater = $this->{$DBTraitsClass}->new(SrcSchema => $schemaDBOld, DstSchema => $schemaDB);
+ $updater->UpdateSchema();
+
+ $dbh->do($_) or die new Exception('Failed to execute the sql statement', $_) foreach $updater->Handler->Sql;
+
+ $SchemaSource->SaveSchema($schemaDB);
+
+ $schemaDBOld->Dispose;
+ }
+ $schemaDB->Dispose;
+}
+
+package Deployment::CDBI::SQLSchemeSource;
+use Common;
+use Data::Dumper;
+use MIME::Base64;
+use Storable qw(nstore_fd fd_retrieve);
+our @ISA = qw(Object);
+
+BEGIN {
+ DeclareProperty MetaTable => ACCESS_NONE;
+}
+
+sub ReadSchema {
+ my ($this,$name) = @_;
+
+ my $schema = decode_base64($this->{$MetaTable}->ReadProperty("db_schema_$name"));
+ if ($schema) {
+ open my $hvar,"<",\$schema or die new Exception("Failed to create a handle to the variable");
+ return fd_retrieve($hvar);
+ } else {
+ return new Schema::DB(Name => $name, Version => 0);
+ }
+}
+
+sub SaveSchema {
+ my ($this,$schema) = @_;
+
+ my $name = $schema->Name;
+
+ my $data;
+ {
+ open my $hvar,">",\$data or die new Exception("Failed to create a handle to the variable");
+ nstore_fd($schema,$hvar);
+ }
+
+ $this->{$MetaTable}->SetProperty("db_schema_$name",encode_base64($data));
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Engine/Action.pm
--- a/Lib/Engine/Action.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Engine/Action.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,65 +1,65 @@
-use strict;
-
-package Engine::Action;
-use Engine::CGI;
-use Common;
-use URI;
-use base qw(IMPL::Object IMPL::Object::Disposable IMPL::Object::Autofill IMPL::Object::EventSource);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-
-our %Fallout;
-
-BEGIN {
- public _direct property Package => prop_all;
- public _direct property Method => prop_all;
- public _direct property Output => prop_all;
- public _direct property RequestURI => prop_all;
- public _direct property Result => prop_all;
- __PACKAGE__->CreateEvent('OnPreInvoke');
- __PACKAGE__->CreateEvent('OnPastInvoke');
-}
-
-sub Invoke {
- my ($this,$query) = @_;
-
- eval {
- die new Exception('A package isn\'t specified for the action',$this->RequestURI->as_string) if not $this->{$Package};
-
- no strict 'refs';
- eval "require ".$this->{$Package}.";" or die $@;
-
- $this->OnPreInvoke();
-
- $this->{$Package}->can($this->{$Method}) or
- die new Exception("The method doesn't exists", $this->{$Method}, $this->{$Package})
- if not ref $this->{$Method} eq 'CODE';
-
- my $instance = $this->{$Package}->can('revive') ? $this->{$Package}->revive : $this->{$Package};
- my $method = $this->{$Method};
-
- $this->{$Result} = $instance->$method($query,$this);
- $this->OnPastInvoke();
- };
-
- if($@) {
- my $err = $@;
- my $module = ref $this->{$Output} || $this->{$Output};
- if(my $uri = $module ? ($Fallout{$module}->{ref $err} || $Fallout{$module}->{Default}) : undef) {
- $this->{$RequestURI} = URI->new($uri,'http');
- $this->{$Result} = $Common::Debug ? $err : undef;
- } else {
- die $err;
- }
- }
-}
-
-sub Dispose {
- my ($this) = @_;
-
- undef %$this;
-
- $this->SUPER::Dispose;
-}
-
-1;
\ No newline at end of file
+use strict;
+
+package Engine::Action;
+use Engine::CGI;
+use Common;
+use URI;
+use base qw(IMPL::Object IMPL::Object::Disposable IMPL::Object::Autofill IMPL::Object::EventSource);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+
+our %Fallout;
+
+BEGIN {
+ public _direct property Package => prop_all;
+ public _direct property Method => prop_all;
+ public _direct property Output => prop_all;
+ public _direct property RequestURI => prop_all;
+ public _direct property Result => prop_all;
+ __PACKAGE__->CreateEvent('OnPreInvoke');
+ __PACKAGE__->CreateEvent('OnPastInvoke');
+}
+
+sub Invoke {
+ my ($this,$query) = @_;
+
+ eval {
+ die new Exception('A package isn\'t specified for the action',$this->RequestURI->as_string) if not $this->{$Package};
+
+ no strict 'refs';
+ eval "require ".$this->{$Package}.";" or die $@;
+
+ $this->OnPreInvoke();
+
+ $this->{$Package}->can($this->{$Method}) or
+ die new Exception("The method doesn't exists", $this->{$Method}, $this->{$Package})
+ if not ref $this->{$Method} eq 'CODE';
+
+ my $instance = $this->{$Package}->can('revive') ? $this->{$Package}->revive : $this->{$Package};
+ my $method = $this->{$Method};
+
+ $this->{$Result} = $instance->$method($query,$this);
+ $this->OnPastInvoke();
+ };
+
+ if($@) {
+ my $err = $@;
+ my $module = ref $this->{$Output} || $this->{$Output};
+ if(my $uri = $module ? ($Fallout{$module}->{ref $err} || $Fallout{$module}->{Default}) : undef) {
+ $this->{$RequestURI} = URI->new($uri,'http');
+ $this->{$Result} = $Common::Debug ? $err : undef;
+ } else {
+ die $err;
+ }
+ }
+}
+
+sub Dispose {
+ my ($this) = @_;
+
+ undef %$this;
+
+ $this->SUPER::Dispose;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Engine/Action/URICall.pm
--- a/Lib/Engine/Action/URICall.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Engine/Action/URICall.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,42 +1,42 @@
-package Engine::Action::URICall;
-use strict;
-use Common;
-use Engine::Action;
-
-our $Namespace;
-
-our %MapOutput;
-our $DefaultMethod;
-
-%MapOutput = ( page => 'Engine::Output::Page' , xml => 'Engine::Output::Xml' ) if not %MapOutput;
-
-=pod
- /module/submodule/method.format
-=cut
-
-sub ConstructAction {
- my ($class,$uriRequest) = @_;
-
- my @module = $uriRequest->path_segments;
-
- my ($function,$format) = (((pop @module) or $DefaultMethod) =~ m/^(.*?)(?:\.(\w+))?$/);
- @module = grep $_, @module;
- my $module = @module ? ($Namespace ? $Namespace . '::' : '').join('::',@module) : $Namespace;
-
- return new Engine::Action( Package => $module, Method => $function, Output => $class->MapOutput($format), RequestURI => $uriRequest);
-}
-
-sub MapOutput {
- my ($class,$format) = @_;
- my $module = $MapOutput{$format} or return undef;
-
- eval "require $module;" or die new Exception('Failed to load output module',$module,$@);
-
- if ($module->can('construct')) {
- return $module->construct($format);
- } else {
- return $module;
- }
-}
-
-1;
+package Engine::Action::URICall;
+use strict;
+use Common;
+use Engine::Action;
+
+our $Namespace;
+
+our %MapOutput;
+our $DefaultMethod;
+
+%MapOutput = ( page => 'Engine::Output::Page' , xml => 'Engine::Output::Xml' ) if not %MapOutput;
+
+=pod
+ /module/submodule/method.format
+=cut
+
+sub ConstructAction {
+ my ($class,$uriRequest) = @_;
+
+ my @module = $uriRequest->path_segments;
+
+ my ($function,$format) = (((pop @module) or $DefaultMethod) =~ m/^(.*?)(?:\.(\w+))?$/);
+ @module = grep $_, @module;
+ my $module = @module ? ($Namespace ? $Namespace . '::' : '').join('::',@module) : $Namespace;
+
+ return new Engine::Action( Package => $module, Method => $function, Output => $class->MapOutput($format), RequestURI => $uriRequest);
+}
+
+sub MapOutput {
+ my ($class,$format) = @_;
+ my $module = $MapOutput{$format} or return undef;
+
+ eval "require $module;" or die new Exception('Failed to load output module',$module,$@);
+
+ if ($module->can('construct')) {
+ return $module->construct($format);
+ } else {
+ return $module;
+ }
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Engine/CGI.pm
--- a/Lib/Engine/CGI.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Engine/CGI.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,67 +1,67 @@
-use strict;
-package Engine::CGI;
-use base 'CGI';
-use Encode;
-use Common;
-
-BEGIN {
- DeclareProperty Expires => ACCESS_ALL;
-}
-
-my $query;
-
-sub Query {
- $query = new Engine::CGI unless $query;
- return $query;
-}
-
-
-my $fcgi_loaded = 0;
-sub Accept {
- my ($self) = shift;
- require CGI::Fast unless $fcgi_loaded;
- $fcgi_loaded = 1;
-
- my $fquery = CGI::Fast->new();
- $query = $fquery ? $self->new($fquery) : undef;
- return $query;
-}
-
-sub as_list {
- return( map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : defined $_ ? $_ : () } @_ );
-}
-
-sub header {
- my ($this,%args) = @_;
-
- $args{'-cookies'} = [as_list($args{'-cookies'}), values %{$this->{'cookies_list'}}] if $this->{'cookies_list'};
- $args{'-expires'} = $this->{$Expires} || 'now';
-
- $this->SUPER::header(%args);
-}
-
-sub SetCookies {
- my ($this,@cookies) = @_;
-
- foreach (@cookies) {
- $this->{'cookies_list'}{$_->name} = $_;
- }
-}
-
-sub param {
- my ($this) = shift;
- my $charset = $this->charset or die new Exception("Encoding is not defined");
- if (wantarray) {
- return map { Encode::is_utf8($_) ? $_ : Encode::decode($charset,$_,Encode::LEAVE_SRC) } $this->SUPER::param( map Encode::encode($charset,$_,Encode::LEAVE_SRC ), @_ );
- } else {
- my $val = $this->SUPER::param( map Encode::encode($charset,$_,Encode::LEAVE_SRC ), @_ );
- return (Encode::is_utf8($val) ? $val : Encode::decode($charset,$val,Encode::LEAVE_SRC));
- }
-}
-
-sub param_raw {
- my $this = shift;
- return $this->SUPER::param(@_);
-}
-
-1;
\ No newline at end of file
+use strict;
+package Engine::CGI;
+use base 'CGI';
+use Encode;
+use Common;
+
+BEGIN {
+ DeclareProperty Expires => ACCESS_ALL;
+}
+
+my $query;
+
+sub Query {
+ $query = new Engine::CGI unless $query;
+ return $query;
+}
+
+
+my $fcgi_loaded = 0;
+sub Accept {
+ my ($self) = shift;
+ require CGI::Fast unless $fcgi_loaded;
+ $fcgi_loaded = 1;
+
+ my $fquery = CGI::Fast->new();
+ $query = $fquery ? $self->new($fquery) : undef;
+ return $query;
+}
+
+sub as_list {
+ return( map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : defined $_ ? $_ : () } @_ );
+}
+
+sub header {
+ my ($this,%args) = @_;
+
+ $args{'-cookies'} = [as_list($args{'-cookies'}), values %{$this->{'cookies_list'}}] if $this->{'cookies_list'};
+ $args{'-expires'} = $this->{$Expires} || 'now';
+
+ $this->SUPER::header(%args);
+}
+
+sub SetCookies {
+ my ($this,@cookies) = @_;
+
+ foreach (@cookies) {
+ $this->{'cookies_list'}{$_->name} = $_;
+ }
+}
+
+sub param {
+ my ($this) = shift;
+ my $charset = $this->charset or die new Exception("Encoding is not defined");
+ if (wantarray) {
+ return map { Encode::is_utf8($_) ? $_ : Encode::decode($charset,$_,Encode::LEAVE_SRC) } $this->SUPER::param( map Encode::encode($charset,$_,Encode::LEAVE_SRC ), @_ );
+ } else {
+ my $val = $this->SUPER::param( map Encode::encode($charset,$_,Encode::LEAVE_SRC ), @_ );
+ return (Encode::is_utf8($val) ? $val : Encode::decode($charset,$val,Encode::LEAVE_SRC));
+ }
+}
+
+sub param_raw {
+ my $this = shift;
+ return $this->SUPER::param(@_);
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Engine/Output/JSON.pm
--- a/Lib/Engine/Output/JSON.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Engine/Output/JSON.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,56 +1,56 @@
-package Configuration;
-our $HtDocsDir;
-
-package Engine;
-our $Encoding;
-
-package Engine::Output::JSON;
-use strict;
-use warnings;
-
-use Encode;
-use PerlIO;
-use IMPL::Exception;
-use JSON;
-
-sub CTX_TEMPLATE() { 1 }
-sub CTX_DATA() { 2 }
-
-my $context = CTX_DATA;
-our $Data;
-
-sub template() { $context = CTX_TEMPLATE }
-sub data() { $context = CTX_DATA }
-
-sub Print {
- my ($class,$query,$action) = @_;
-
- my @path = $action->RequestURI->path_segments;
- shift @path;
-
- my $result;
-
- undef $@;
- $Data = $action->Result;
- eval {
- my $fname = $HtDocsDir . join '/', @path;
- if ($context == CTX_DATA) {
- my $dummy = '';
- open my $hstd, ">>", \$dummy or die new IMPL::Exception('Failed to create inmemory stream');
- local (*STDIN,*STDOUT) = ($hstd,$hstd);
- local ${^ENCODING};
- $result = do $fname or die new IMPL::Exception('Failed to evalute the file', $@, $!,$fname);
- } else {
- die new IMPL::Exception('JSON templates not implemented');
- }
- };
- if ($@) {
- $result = { errorCode => 1, errorMessage => "$@"};
- }
-
- print $query->header(-status => 200, -type => 'text/javascript');
- print to_json({ errorCode => 0, result => $result });
-}
-
-
-1;
+package Configuration;
+our $HtDocsDir;
+
+package Engine;
+our $Encoding;
+
+package Engine::Output::JSON;
+use strict;
+use warnings;
+
+use Encode;
+use PerlIO;
+use IMPL::Exception;
+use JSON;
+
+sub CTX_TEMPLATE() { 1 }
+sub CTX_DATA() { 2 }
+
+my $context = CTX_DATA;
+our $Data;
+
+sub template() { $context = CTX_TEMPLATE }
+sub data() { $context = CTX_DATA }
+
+sub Print {
+ my ($class,$query,$action) = @_;
+
+ my @path = $action->RequestURI->path_segments;
+ shift @path;
+
+ my $result;
+
+ undef $@;
+ $Data = $action->Result;
+ eval {
+ my $fname = $HtDocsDir . join '/', @path;
+ if ($context == CTX_DATA) {
+ my $dummy = '';
+ open my $hstd, ">>", \$dummy or die new IMPL::Exception('Failed to create inmemory stream');
+ local (*STDIN,*STDOUT) = ($hstd,$hstd);
+ local ${^ENCODING};
+ $result = do $fname or die new IMPL::Exception('Failed to evalute the file', $@, $!,$fname);
+ } else {
+ die new IMPL::Exception('JSON templates not implemented');
+ }
+ };
+ if ($@) {
+ $result = { errorCode => 1, errorMessage => "$@"};
+ }
+
+ print $query->header(-status => 200, -type => 'text/javascript');
+ print to_json({ errorCode => 0, result => $result });
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Engine/Output/Page.pm
--- a/Lib/Engine/Output/Page.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Engine/Output/Page.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,34 +1,34 @@
-package Engine;
-our $Encoding;
-
-package Engine::Output::Page;
-use strict;
-
-use Common;
-use DOM;
-
-sub Print {
- my ($class,$Query,$Action) = @_;
-
- if (DOM::Site->can('LoadPage')) {
- my $pageId = $Action->RequestURI->path;
- DOM::Site->RegisterObject("Request",$Action);
- my $Page = DOM::Site->LoadPage($pageId);
- print $Query->header(-status => 200);
- undef $@;
- eval {
- $Page->Properties->{Encoding} = $Engine::Encoding;
- $Page->Render(*STDOUT);
- };
- if ($@) {
- print $Query->start_html('Error processing template');
- print $Query->p("Page: $pageId");
- print $Query->p("Error: $@");
- print $Query->end_html;
- }
- } else {
- die new Exception('The site doesn\'t support page output');
- }
-}
-
-1;
+package Engine;
+our $Encoding;
+
+package Engine::Output::Page;
+use strict;
+
+use Common;
+use DOM;
+
+sub Print {
+ my ($class,$Query,$Action) = @_;
+
+ if (DOM::Site->can('LoadPage')) {
+ my $pageId = $Action->RequestURI->path;
+ DOM::Site->RegisterObject("Request",$Action);
+ my $Page = DOM::Site->LoadPage($pageId);
+ print $Query->header(-status => 200);
+ undef $@;
+ eval {
+ $Page->Properties->{Encoding} = $Engine::Encoding;
+ $Page->Render(*STDOUT);
+ };
+ if ($@) {
+ print $Query->start_html('Error processing template');
+ print $Query->p("Page: $pageId");
+ print $Query->p("Error: $@");
+ print $Query->end_html;
+ }
+ } else {
+ die new Exception('The site doesn\'t support page output');
+ }
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Engine/Output/Template.pm
--- a/Lib/Engine/Output/Template.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Engine/Output/Template.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,55 +1,55 @@
-package Engine;
-our $Encoding;
-
-package Engine::Output::Template;
-use strict;
-use Common;
-use Template;
-our @ISA = qw(Object);
-our %Formats;
-
-BEGIN {
- DeclareProperty Include => ACCESS_READ;
- DeclareProperty ContentType => ACCESS_READ;
- DeclareProperty Encoding => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$Include} = $args{Include} or die new Exception('An include diretory is required',$args{Format});
- $this->{$ContentType} = $args{ContentType} or die new Exception('A content type must be specied',$args{Format});
- $this->{$Encoding} = $args{Encoding};
-}
-
-sub Print {
- my ($this,$Query,$Action) = @_;
-
- my $template = new Template(
- {
- INCLUDE_PATH => $this->{$Include},
- INTERPOLATE => 1,
- RECURSION => 1,
- ENCODING => $this->{$Encoding}
- }
- );
-
- my @path = $Action->RequestURI->path_segments;
- shift @path;
- my $Template;
- eval {
- $Template = $template->context->template(join('/',@path));
- };
- print $Query->header(-type => 'text/html') and die new Exception('Failed to process a template', $@) if $@;
- $Query->Expires($Template->Expires);
- print $Query->header(-type => $this->{$ContentType});
- print $template->context->process($Template,{Encoding => $Engine::Encoding, Data => $Action->Result, Query => $Query });
-}
-
-sub construct {
- my ($class,$format) = @_;
-
- $class->new(%{$Formats{$format}},Format => $format);
-}
-
-1;
\ No newline at end of file
+package Engine;
+our $Encoding;
+
+package Engine::Output::Template;
+use strict;
+use Common;
+use Template;
+our @ISA = qw(Object);
+our %Formats;
+
+BEGIN {
+ DeclareProperty Include => ACCESS_READ;
+ DeclareProperty ContentType => ACCESS_READ;
+ DeclareProperty Encoding => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$Include} = $args{Include} or die new Exception('An include diretory is required',$args{Format});
+ $this->{$ContentType} = $args{ContentType} or die new Exception('A content type must be specied',$args{Format});
+ $this->{$Encoding} = $args{Encoding};
+}
+
+sub Print {
+ my ($this,$Query,$Action) = @_;
+
+ my $template = new Template(
+ {
+ INCLUDE_PATH => $this->{$Include},
+ INTERPOLATE => 1,
+ RECURSION => 1,
+ ENCODING => $this->{$Encoding}
+ }
+ );
+
+ my @path = $Action->RequestURI->path_segments;
+ shift @path;
+ my $Template;
+ eval {
+ $Template = $template->context->template(join('/',@path));
+ };
+ print $Query->header(-type => 'text/html') and die new Exception('Failed to process a template', $@) if $@;
+ $Query->Expires($Template->Expires);
+ print $Query->header(-type => $this->{$ContentType});
+ print $template->context->process($Template,{Encoding => $Engine::Encoding, Data => $Action->Result, Query => $Query });
+}
+
+sub construct {
+ my ($class,$format) = @_;
+
+ $class->new(%{$Formats{$format}},Format => $format);
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Engine/Security.pm
--- a/Lib/Engine/Security.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Engine/Security.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,36 +1,36 @@
-use strict;
-package Engine::Security;
-use Security::Auth;
-use Security;
-use Engine::Security::Auth;
-
-our @AuthMethods;
-my $AuthResult;
-my $AuthMod;
-my $AuthMethod;
-
-# use last auth method as default
-$AuthMethod = Engine::Security::Auth->new(%{$AuthMethods[$#AuthMethods]}) if @AuthMethods;
-
-sub AuthenticateContext {
- Security->CurrentSession(undef); #prevent previous session from closing
- foreach my $method (@AuthMethods) {
- my $AuthObj = Engine::Security::Auth->new(%$method);
- $AuthResult = $AuthObj->DoAuth();
- # обновить текущий контекст безопасности, только если это необходимо
- $AuthObj->SetAuthResult($AuthResult) if $AuthResult->State == Security::AUTH_FAILED or $AuthResult->State == Security::AUTH_SUCCESS;
- $AuthMethod = $AuthObj and last if $AuthResult->State != Security::AUTH_FAILED and $AuthResult->State != Security::AUTH_NOAUTH;
- }
- $AuthMod = $AuthMethod->AuthMod if $AuthMethod;
-}
-
-sub SetAuthResult {
- shift;
- $AuthMethod->SetAuthResult(@_) if $AuthMethod;
-}
-
-sub AuthMod {
- return $AuthMethod ? $AuthMethod->AuthMod : undef;
-}
-
-1;
\ No newline at end of file
+use strict;
+package Engine::Security;
+use Security::Auth;
+use Security;
+use Engine::Security::Auth;
+
+our @AuthMethods;
+my $AuthResult;
+my $AuthMod;
+my $AuthMethod;
+
+# use last auth method as default
+$AuthMethod = Engine::Security::Auth->new(%{$AuthMethods[$#AuthMethods]}) if @AuthMethods;
+
+sub AuthenticateContext {
+ Security->CurrentSession(undef); #prevent previous session from closing
+ foreach my $method (@AuthMethods) {
+ my $AuthObj = Engine::Security::Auth->new(%$method);
+ $AuthResult = $AuthObj->DoAuth();
+ # обновить текущий контекст безопасности, только если это необходимо
+ $AuthObj->SetAuthResult($AuthResult) if $AuthResult->State == Security::AUTH_FAILED or $AuthResult->State == Security::AUTH_SUCCESS;
+ $AuthMethod = $AuthObj and last if $AuthResult->State != Security::AUTH_FAILED and $AuthResult->State != Security::AUTH_NOAUTH;
+ }
+ $AuthMod = $AuthMethod->AuthMod if $AuthMethod;
+}
+
+sub SetAuthResult {
+ shift;
+ $AuthMethod->SetAuthResult(@_) if $AuthMethod;
+}
+
+sub AuthMod {
+ return $AuthMethod ? $AuthMethod->AuthMod : undef;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Engine/Security/AccessDeniedException.pm
--- a/Lib/Engine/Security/AccessDeniedException.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Engine/Security/AccessDeniedException.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,13 +1,13 @@
-package Engine::Security::AccessDeniedException;
-use strict;
-use Common;
-our @ISA = qw(Exception);
-
-sub CTOR {
- my ($this,$message,@args) = @_;
-
- $this->SUPER::CTOR($message ? $message : 'Access denied',@args);
-}
-
-
-1;
+package Engine::Security::AccessDeniedException;
+use strict;
+use Common;
+our @ISA = qw(Exception);
+
+sub CTOR {
+ my ($this,$message,@args) = @_;
+
+ $this->SUPER::CTOR($message ? $message : 'Access denied',@args);
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Engine/Security/Auth.pm
--- a/Lib/Engine/Security/Auth.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Engine/Security/Auth.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,94 +1,94 @@
-package Engine::Security::Auth;
-use strict;
-use Common;
-our @ISA = qw(Object);
-use Security;
-use Security::Auth;
-use Engine::Security::AccessDeniedException;
-
-BEGIN {
- DeclareProperty ClientSecData => ACCESS_READ;
- DeclareProperty SecPackage => ACCESS_READ;
- DeclareProperty DataSource => ACCESS_READ;
- DeclareProperty DefaultUser => ACCESS_READ;
- DeclareProperty _AuthMod => ACCESS_NONE; # construct on demand
-}
-
-sub CTOR {
- my $this = shift;
- $this->SUPER::CTOR(@_);
- eval "require $this->{$ClientSecData};" or warn $@;
-}
-
-sub DoAuth {
- my ($this) = @_;
-
- my $data = $this->{$ClientSecData}->ReadSecData($this);
- my $SSID = $this->{$ClientSecData}->ReadSSID($this);
-
- my $AuthResult;
-
- if ($SSID) {
- $AuthResult = $this->AuthMod->AuthenticateSession($SSID,$data);
- } else {
- $AuthResult = new Security::AuthResult(State => Security::AUTH_NOAUTH);
- }
-
- if ($AuthResult->State == Security::AUTH_SUCCESS) {
- #warn "Session authenticated: ".$AuthResult->Session->User->Name;
- } else {
- #warn "Session is not authenticated: ".$AuthResult->State;
- if ($this->{$DefaultUser}) {
- $AuthResult = $this->AuthMod->AuthenticateUser($this->{$DefaultUser},undef);
- }
- }
-
- return $AuthResult;
-}
-
-sub SetAuthResult {
- my ($this,$AuthResult) = @_;
-
- if ($AuthResult and $AuthResult->State == Security::AUTH_SUCCESS) {
- $this->_CurrentSession($AuthResult->Session);
- $this->{$ClientSecData}->WriteSecData($AuthResult->ClientSecData,$this);
- } else {
- $this->_CurrentSession(undef);
- $this->{$ClientSecData}->WriteSecData(undef,$this);
- }
-}
-
-sub _CurrentSession {
- my ($this,$Session) = @_;
-
- if (@_ >= 2) {
- $this->AuthMod->DS->CloseSession(Security->CurrentSession) if Security->CurrentSession;
-
- $this->{$ClientSecData}->WriteSSID($Session ? $Session->SSID : undef);
- Security->CurrentSession($Session);
- } else {
- return Security->CurrentSession;
- }
-}
-
-sub AuthMod {
- my ($this) = @_;
- if (not $this->{$_AuthMod}) {
- if ($this->{$DataSource} and $this->{$SecPackage}) {
- eval qq {
- require $this->{$DataSource};
- require $this->{$SecPackage};
- } or warn $@;
- $this->{$_AuthMod} = Security::Auth->new(
- DS => $this->{$DataSource},
- SecPackage => $this->{$SecPackage}
- );
- } else {
- #construct default
- $this->{$_AuthMod} = Security::Auth->construct;
- }
- }
- return $this->{$_AuthMod};
-}
-
-1;
+package Engine::Security::Auth;
+use strict;
+use Common;
+our @ISA = qw(Object);
+use Security;
+use Security::Auth;
+use Engine::Security::AccessDeniedException;
+
+BEGIN {
+ DeclareProperty ClientSecData => ACCESS_READ;
+ DeclareProperty SecPackage => ACCESS_READ;
+ DeclareProperty DataSource => ACCESS_READ;
+ DeclareProperty DefaultUser => ACCESS_READ;
+ DeclareProperty _AuthMod => ACCESS_NONE; # construct on demand
+}
+
+sub CTOR {
+ my $this = shift;
+ $this->SUPER::CTOR(@_);
+ eval "require $this->{$ClientSecData};" or warn $@;
+}
+
+sub DoAuth {
+ my ($this) = @_;
+
+ my $data = $this->{$ClientSecData}->ReadSecData($this);
+ my $SSID = $this->{$ClientSecData}->ReadSSID($this);
+
+ my $AuthResult;
+
+ if ($SSID) {
+ $AuthResult = $this->AuthMod->AuthenticateSession($SSID,$data);
+ } else {
+ $AuthResult = new Security::AuthResult(State => Security::AUTH_NOAUTH);
+ }
+
+ if ($AuthResult->State == Security::AUTH_SUCCESS) {
+ #warn "Session authenticated: ".$AuthResult->Session->User->Name;
+ } else {
+ #warn "Session is not authenticated: ".$AuthResult->State;
+ if ($this->{$DefaultUser}) {
+ $AuthResult = $this->AuthMod->AuthenticateUser($this->{$DefaultUser},undef);
+ }
+ }
+
+ return $AuthResult;
+}
+
+sub SetAuthResult {
+ my ($this,$AuthResult) = @_;
+
+ if ($AuthResult and $AuthResult->State == Security::AUTH_SUCCESS) {
+ $this->_CurrentSession($AuthResult->Session);
+ $this->{$ClientSecData}->WriteSecData($AuthResult->ClientSecData,$this);
+ } else {
+ $this->_CurrentSession(undef);
+ $this->{$ClientSecData}->WriteSecData(undef,$this);
+ }
+}
+
+sub _CurrentSession {
+ my ($this,$Session) = @_;
+
+ if (@_ >= 2) {
+ $this->AuthMod->DS->CloseSession(Security->CurrentSession) if Security->CurrentSession;
+
+ $this->{$ClientSecData}->WriteSSID($Session ? $Session->SSID : undef);
+ Security->CurrentSession($Session);
+ } else {
+ return Security->CurrentSession;
+ }
+}
+
+sub AuthMod {
+ my ($this) = @_;
+ if (not $this->{$_AuthMod}) {
+ if ($this->{$DataSource} and $this->{$SecPackage}) {
+ eval qq {
+ require $this->{$DataSource};
+ require $this->{$SecPackage};
+ } or warn $@;
+ $this->{$_AuthMod} = Security::Auth->new(
+ DS => $this->{$DataSource},
+ SecPackage => $this->{$SecPackage}
+ );
+ } else {
+ #construct default
+ $this->{$_AuthMod} = Security::Auth->construct;
+ }
+ }
+ return $this->{$_AuthMod};
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Engine/Security/Cookies.pm
--- a/Lib/Engine/Security/Cookies.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Engine/Security/Cookies.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,27 +1,27 @@
-use strict;
-package Engine::Security::Cookies;
-use Engine::CGI;
-use CGI::Cookie;
-
-sub ReadSecData {
-
- return Engine::CGI::Query->cookie('SecData');
-}
-
-sub WriteSecData {
- my ($class,$data) = @_;
-
- Engine::CGI::Query->SetCookies(new CGI::Cookie(-name => 'SecData', -value => $data, -expires => '+1d'));
-}
-
-sub ReadSSID {
- return Engine::CGI::Query->cookie('SSID');
-}
-
-sub WriteSSID {
- my ($class,$data) = @_;
-
- Engine::CGI::Query->SetCookies(new CGI::Cookie(-name => 'SSID', -value => $data, -expires => '+1d'));
-}
-
-1;
\ No newline at end of file
+use strict;
+package Engine::Security::Cookies;
+use Engine::CGI;
+use CGI::Cookie;
+
+sub ReadSecData {
+
+ return Engine::CGI::Query->cookie('SecData');
+}
+
+sub WriteSecData {
+ my ($class,$data) = @_;
+
+ Engine::CGI::Query->SetCookies(new CGI::Cookie(-name => 'SecData', -value => $data, -expires => '+1d'));
+}
+
+sub ReadSSID {
+ return Engine::CGI::Query->cookie('SSID');
+}
+
+sub WriteSSID {
+ my ($class,$data) = @_;
+
+ Engine::CGI::Query->SetCookies(new CGI::Cookie(-name => 'SSID', -value => $data, -expires => '+1d'));
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Engine/Security/IPSession.pm
--- a/Lib/Engine/Security/IPSession.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Engine/Security/IPSession.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,48 +1,48 @@
-package Engine::Security::IPSession;
-use strict;
-use Digest::MD5 qw(md5_hex);
-
-our %IPMap; # { IP_ADDR => {user => 'name', ClientSecData => 'ClientData', InitSecData => 'ServerData'} }
-
-sub ReadSecData {
-
- return $IPMap{$ENV{REMOTE_ADDR} || ''} ? $IPMap{$ENV{REMOTE_ADDR} || ''}->{ClientSecData} : undef; # avoid from create hash item
-}
-
-sub WriteSecData {
- my ($class,$data) = @_;
- # does nothing
-}
-
-sub ReadSSID {
- my ($class,$authEngineObj) = @_;
-
- my $ip = $ENV{REMOTE_ADDR};
- return undef if not $IPMap{$ip || ''};
- my $SSID = md5_hex($ip);
-
- if (not my $session = $authEngineObj->AuthMod->DS->LoadSession($SSID)) {
- my $User = $authEngineObj->AuthMod->DS->FindUser($IPMap{$ip}->{user}) or warn "can't authenticate the $ip: user not found" and return undef;
- $authEngineObj->AuthMod->DS->CreateSession($SSID,$User,$authEngineObj->AuthMod->SecPackage->NewAuthData($IPMap{$ip}->{InitSecData}));
- } elsif ($session->User->Name ne $IPMap{$ip}->{user}) {
- # update user
- my $User = $authEngineObj->AuthMod->DS->FindUser($IPMap{$ip}->{user});
- if ($User) {
- $session->User($User);
- } else {
- warn "can't authenticate the $ip: user not found";
- $authEngineObj->AuthMod->DS->CloseSession($session);
- }
- }
-
- return $SSID;
-}
-
-sub WriteSSID {
- my ($class,$data) = @_;
-
- #do nothing
-}
-
-
-1;
+package Engine::Security::IPSession;
+use strict;
+use Digest::MD5 qw(md5_hex);
+
+our %IPMap; # { IP_ADDR => {user => 'name', ClientSecData => 'ClientData', InitSecData => 'ServerData'} }
+
+sub ReadSecData {
+
+ return $IPMap{$ENV{REMOTE_ADDR} || ''} ? $IPMap{$ENV{REMOTE_ADDR} || ''}->{ClientSecData} : undef; # avoid from create hash item
+}
+
+sub WriteSecData {
+ my ($class,$data) = @_;
+ # does nothing
+}
+
+sub ReadSSID {
+ my ($class,$authEngineObj) = @_;
+
+ my $ip = $ENV{REMOTE_ADDR};
+ return undef if not $IPMap{$ip || ''};
+ my $SSID = md5_hex($ip);
+
+ if (not my $session = $authEngineObj->AuthMod->DS->LoadSession($SSID)) {
+ my $User = $authEngineObj->AuthMod->DS->FindUser($IPMap{$ip}->{user}) or warn "can't authenticate the $ip: user not found" and return undef;
+ $authEngineObj->AuthMod->DS->CreateSession($SSID,$User,$authEngineObj->AuthMod->SecPackage->NewAuthData($IPMap{$ip}->{InitSecData}));
+ } elsif ($session->User->Name ne $IPMap{$ip}->{user}) {
+ # update user
+ my $User = $authEngineObj->AuthMod->DS->FindUser($IPMap{$ip}->{user});
+ if ($User) {
+ $session->User($User);
+ } else {
+ warn "can't authenticate the $ip: user not found";
+ $authEngineObj->AuthMod->DS->CloseSession($session);
+ }
+ }
+
+ return $SSID;
+}
+
+sub WriteSSID {
+ my ($class,$data) = @_;
+
+ #do nothing
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Form.pm
--- a/Lib/Form.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Form.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,147 +1,147 @@
-package Form;
-use strict;
-use Common;
-use base qw(Form::Container);
-use Form::ItemId;
-use Form::ValueItem;
-
-BEGIN {
- DeclareProperty AutoCreate => ACCESS_ALL;
- DeclareProperty isValidated => ACCESS_READ;
- DeclareProperty isValid => ACCESS_READ;
- DeclareProperty ValidationErrors => ACCESS_READ;
- DeclareProperty MapFieldClasses => ACCESS_READ;
- DeclareProperty LoadedFiledClasses => ACCESS_NONE;
- DeclareProperty Bindings => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,$schema,$bind) = @_;
-
- $this->SUPER::CTOR(
- Schema => $schema->Body,
- Id => Form::ItemId->new('Form',undef,Form::ItemId::Root->new()),
- Form => $this
- );
- $this->{$MapFieldClasses} = {
- SelectBox => 'Form::ValueItem::List',
- RadioSelect => 'Form::ValueItem::List',
- MultiCheckBox => 'Form::ValueItem::List'
- };
- $this->{$LoadedFiledClasses} = { 'Form::ValueItem' => 1 };
- $this->{$Bindings} = $bind || {};
- $this->{$isValid} = 0;
- $this->{$isValidated} = 0;
-}
-
-sub NavigatePath {
- my ($this,$path) = @_;
-
- shift @$path if $path->[0]->Name eq 'Form'; # eat root node in Form/Item
-
- return $this->SUPER::NavigatePath($path);
-}
-
-sub Item {
- my ($this,$strId) = @_;
-
- return $this->Navigate($this->MakeItemId($strId,undef));
-}
-
-sub MakeItemId {
- my ($this,$Name,$BaseObject) = @_;
-
- my $ItemId;
- if ($BaseObject and $BaseObject->isa('Form::Item')) {
- $ItemId = $BaseObject->Id;
- } else {
- $ItemId = new Form::ItemId::Root;
- }
-
- foreach my $item (split /\//,$Name) {
- if ($item =~ /^(\w+?)(\d+)?$/) {
- $ItemId = Form::ItemId->new($1,$2,$ItemId);
- } else {
- die new Exception('The invalid identifier',$Name);
- }
- }
- return $ItemId;
-}
-
-sub CreateInstance {
- my ($this,$schema,$ItemId,$parent) = @_;
-
- my $obj;
- if ($schema->isa('Schema::Form::Container')) {
- $obj = new Form::Container(
- Id => Form::ItemId->new($ItemId->Name,$ItemId->InstanceID,($parent ? $parent->Id : undef)),
- Form => $this,
- Parent => $parent,
- Schema => $schema,
- Attributes => {%{$schema->Attributes}}
- );
- } elsif ($schema->isa('Schema::Form::Field')) {
- my $class = $this->{$MapFieldClasses}{$schema->Format->Name} || 'Form::ValueItem';
- if (not $this->{$LoadedFiledClasses}{$class}) {
- eval "require $class;" or die new Exception('Failed to load a module',$class,$@);
- $this->{$LoadedFiledClasses}{$class} = 1;
- }
- $obj = $class->new(
- Id => Form::ItemId->new($ItemId->Name,$ItemId->InstanceID,($parent ? $parent->Id : undef)),
- Form => $this,
- Parent => $parent,
- Type => $schema->Format->Name,
- Schema => $schema,
- Attributes => {%{$schema->Attributes}}
- );
- } else {
- die new Exception('Unexpected schema type', ref $schema);
- }
-
- return $obj;
-}
-
-sub Validate {
- my ($this) = @_;
-
- my @errors = $this->SUPER::Validate;
- $this->{$isValidated} = 1;
- if (@errors) {
- $this->{$isValid} = 0;
- $this->{$ValidationErrors} = \@errors;
- } else {
- $this->{$isValid} = 1;
- delete $this->{$ValidationErrors};
- }
-
- return @errors;
-}
-
-sub SelectErrors {
- my ($this,$parentId) = @_;
-
- return [grep $_->Item->Parent->Id->Canonical eq $parentId, $this->ValidationErrors];
-}
-
-sub LoadValues {
- my ($this,$rhValues) = @_;
-
- $this->{$isValidated} = 0;
- $this->{$isValid} = 0;
-
- foreach my $key (keys %$rhValues) {
- eval { $this->Item($key)->Value($rhValues->{$key}) };
- undef $@;
- }
-}
-
-
-sub Dispose {
- my ($this) = @_;
-
- delete @$this{$ValidationErrors,$MapFieldClasses,$LoadedFiledClasses,$Bindings};
-
- $this->SUPER::Dispose;
-}
-
-1;
\ No newline at end of file
+package Form;
+use strict;
+use Common;
+use base qw(Form::Container);
+use Form::ItemId;
+use Form::ValueItem;
+
+BEGIN {
+ DeclareProperty AutoCreate => ACCESS_ALL;
+ DeclareProperty isValidated => ACCESS_READ;
+ DeclareProperty isValid => ACCESS_READ;
+ DeclareProperty ValidationErrors => ACCESS_READ;
+ DeclareProperty MapFieldClasses => ACCESS_READ;
+ DeclareProperty LoadedFiledClasses => ACCESS_NONE;
+ DeclareProperty Bindings => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,$schema,$bind) = @_;
+
+ $this->SUPER::CTOR(
+ Schema => $schema->Body,
+ Id => Form::ItemId->new('Form',undef,Form::ItemId::Root->new()),
+ Form => $this
+ );
+ $this->{$MapFieldClasses} = {
+ SelectBox => 'Form::ValueItem::List',
+ RadioSelect => 'Form::ValueItem::List',
+ MultiCheckBox => 'Form::ValueItem::List'
+ };
+ $this->{$LoadedFiledClasses} = { 'Form::ValueItem' => 1 };
+ $this->{$Bindings} = $bind || {};
+ $this->{$isValid} = 0;
+ $this->{$isValidated} = 0;
+}
+
+sub NavigatePath {
+ my ($this,$path) = @_;
+
+ shift @$path if $path->[0]->Name eq 'Form'; # eat root node in Form/Item
+
+ return $this->SUPER::NavigatePath($path);
+}
+
+sub Item {
+ my ($this,$strId) = @_;
+
+ return $this->Navigate($this->MakeItemId($strId,undef));
+}
+
+sub MakeItemId {
+ my ($this,$Name,$BaseObject) = @_;
+
+ my $ItemId;
+ if ($BaseObject and $BaseObject->isa('Form::Item')) {
+ $ItemId = $BaseObject->Id;
+ } else {
+ $ItemId = new Form::ItemId::Root;
+ }
+
+ foreach my $item (split /\//,$Name) {
+ if ($item =~ /^(\w+?)(\d+)?$/) {
+ $ItemId = Form::ItemId->new($1,$2,$ItemId);
+ } else {
+ die new Exception('The invalid identifier',$Name);
+ }
+ }
+ return $ItemId;
+}
+
+sub CreateInstance {
+ my ($this,$schema,$ItemId,$parent) = @_;
+
+ my $obj;
+ if ($schema->isa('Schema::Form::Container')) {
+ $obj = new Form::Container(
+ Id => Form::ItemId->new($ItemId->Name,$ItemId->InstanceID,($parent ? $parent->Id : undef)),
+ Form => $this,
+ Parent => $parent,
+ Schema => $schema,
+ Attributes => {%{$schema->Attributes}}
+ );
+ } elsif ($schema->isa('Schema::Form::Field')) {
+ my $class = $this->{$MapFieldClasses}{$schema->Format->Name} || 'Form::ValueItem';
+ if (not $this->{$LoadedFiledClasses}{$class}) {
+ eval "require $class;" or die new Exception('Failed to load a module',$class,$@);
+ $this->{$LoadedFiledClasses}{$class} = 1;
+ }
+ $obj = $class->new(
+ Id => Form::ItemId->new($ItemId->Name,$ItemId->InstanceID,($parent ? $parent->Id : undef)),
+ Form => $this,
+ Parent => $parent,
+ Type => $schema->Format->Name,
+ Schema => $schema,
+ Attributes => {%{$schema->Attributes}}
+ );
+ } else {
+ die new Exception('Unexpected schema type', ref $schema);
+ }
+
+ return $obj;
+}
+
+sub Validate {
+ my ($this) = @_;
+
+ my @errors = $this->SUPER::Validate;
+ $this->{$isValidated} = 1;
+ if (@errors) {
+ $this->{$isValid} = 0;
+ $this->{$ValidationErrors} = \@errors;
+ } else {
+ $this->{$isValid} = 1;
+ delete $this->{$ValidationErrors};
+ }
+
+ return @errors;
+}
+
+sub SelectErrors {
+ my ($this,$parentId) = @_;
+
+ return [grep $_->Item->Parent->Id->Canonical eq $parentId, $this->ValidationErrors];
+}
+
+sub LoadValues {
+ my ($this,$rhValues) = @_;
+
+ $this->{$isValidated} = 0;
+ $this->{$isValid} = 0;
+
+ foreach my $key (keys %$rhValues) {
+ eval { $this->Item($key)->Value($rhValues->{$key}) };
+ undef $@;
+ }
+}
+
+
+sub Dispose {
+ my ($this) = @_;
+
+ delete @$this{$ValidationErrors,$MapFieldClasses,$LoadedFiledClasses,$Bindings};
+
+ $this->SUPER::Dispose;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Form/Container.pm
--- a/Lib/Form/Container.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Form/Container.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,170 +1,170 @@
-package Form::Container;
-use strict;
-use Common;
-use Form::Filter;
-use base qw(Form::Item);
-
-BEGIN {
- DeclareProperty Schema => ACCESS_READ;
- DeclareProperty Children => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,%args) = @_;
- $args{Schema} or die new Exception('A schema is required');
-
- $this->SUPER::CTOR(@args{qw(Id Form Parent Attributes)});
- $this->{$Schema} = $args{Schema};
-}
-
-sub ResolveItem {
- my ($this,$ItemId) = @_;
-
- if (my $schemaChild = $this->{$Schema}->FindChild($ItemId->Name)) {
- if ($schemaChild->isMulti) {
- defined $ItemId->InstanceID or die new Exception('Instance id is required for a muti element');
- if (my $child = $this->{$Children}{$ItemId->Name}[$ItemId->InstanceID]){
- return $child;
- } else {
- return undef if not $this->Form->AutoCreate;
- return $this->{$Children}{$ItemId->Name}[$ItemId->InstanceID] = $this->Form->CreateInstance($schemaChild,$ItemId,$this);
- }
-
- } else {
- defined $ItemId->InstanceID and die new Exception('The child is a single element',$this->Id->Canonical,$ItemId->Name);
- if(my $child = $this->{$Children}{$ItemId->Name}) {
- return $child;
- } else {
- return undef if not $this->Form->AutoCreate;
- return $this->{$Children}{$ItemId->Name} = $this->Form->CreateInstance($schemaChild,$ItemId,$this);
- }
- }
- } else {
- die new Exception('The requested item isn\'t exists in the schema', $this->Id->Canonical,$ItemId->Name);
- }
-}
-
-sub isEmpty {
- my ($this) = @_;
-
- foreach my $child (values %{$this->{$Children} || {} }) {
- if (ref $child eq 'ARRAY') {
- foreach my $inst (@$child) {
- return 0 if not $child->isEmpty;
- }
- } else {
- return 0 if not $child->isEmpty;
- }
- }
-
- return 1;
-}
-
-=pod
-Получает дочерние контенеры в виде списка, при том только не пустые контейнеры.
-Если дочернний контейнер не множественный, то список будет состоять из одного элемента.
-=cut
-sub GetChild {
- my ($this,$name) = @_;
- return unless exists $this->{$Children}{$name};
- return( grep $_, map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : $_ } $this->{$Children}{$name} );
-}
-
-=pod
-Выполняет фильтры по схеме для себя и всех детей.
-Фильтры определяются по схеме и вызываются в различнх контекстах
-
-* сначала для группы,
-* потом для детишек, причем если
- * детишки множественные, то
- * снсчала для набора детишек, а потом
- * для каждого в отдельности
-=cut
-sub Validate {
- my ($this,$rhDisableFilters) = @_;
-
- $rhDisableFilters ||= {};
-
- my @errors;
-
- foreach my $filter (grep {$_->SUPPORTED_CONTEXT & (Form::Filter::CTX_SINGLE) and not exists $rhDisableFilters->{$_}} map {$_->Instance} $this->{$Schema}->Filters) {
- my $result = $filter->Invoke($this,Form::Filter::CTX_SINGLE | Form::Filter::CTX_EXISTENT,$this->{$Schema});
- if ($result->State == Form::FilterResult::STATE_SUCCESS_STOP) {
- return ();
- } elsif ($result->State == Form::FilterResult::STATE_ERROR) {
- push @errors,$result;
- }
- }
-
- CHILD_LOOP: foreach my $schemaChild ($this->{$Schema}->Children) {
-
- if ($schemaChild->isMulti) {
- my %DisableFilters;
- foreach my $filter (grep {$_->SUPPORTED_CONTEXT & Form::Filter::CTX_SET} map {$_->Instance} $schemaChild->Filters) {
-
- my $result = $filter->Invoke($this->{$Children}{$schemaChild->Name},Form::Filter::CTX_SET,$schemaChild,$this);
- if ($result->State == Form::FilterResult::STATE_ERROR) {
- push @errors,$result;
- # не проверять другие фильтры вообще
- next CHILD_LOOP;
- } elsif ($result->State == Form::FilterResult::STATE_SUCCESS_STOP) {
- # не проверять другие фильтры вообще
- next CHILD_LOOP;
- } elsif ($result->State == Form::FilterResult::STATE_SUCCESS_STAY) {
- # не проверять данный фильтр на каждом экземпляре
- $DisableFilters{$filter} = 1;
- } else {
- # STATE_SUCCESS - все ок
- }
- }
-
- $_ and push @errors,$_->Validate(\%DisableFilters) foreach grep !$_->isEmpty, $this->GetChild($schemaChild->Name);
-
- } else {
- my %DisableFilters;
-
- # проверяем фильтры, которые могут применяться на несуществующем значении
- foreach my $filter (grep { $_->SUPPORTED_CONTEXT & Form::Filter::CTX_SINGLE and not $_->SUPPORTED_CONTEXT & Form::Filter::CTX_EXISTENT} map {$_->Instance} $schemaChild->Filters) {
- my $result = $filter->Invoke($this->{$Children}{$schemaChild->Name},Form::Filter::CTX_SINGLE,$schemaChild,$this);
-
- if ($result->State == Form::FilterResult::STATE_ERROR) {
- push @errors,$result;
- # не проверять другие фильтры вообще
- next CHILD_LOOP;
- } elsif ($result->State == Form::FilterResult::STATE_SUCCESS_STOP) {
- # не проверять другие фильтры вообще
- next CHILD_LOOP;
- } else {
- # STATE_SUCCESS(_STAY) - все ок
- $DisableFilters{$filter} = 1;
- }
- }
-
- # если значение существует, то применяем оставшиеся фильтры
- push @errors,$this->{$Children}{$schemaChild->Name}->Validate(\%DisableFilters) if $this->{$Children}{$schemaChild->Name};
- }
-
- }
-
- return @errors;
-}
-
-sub Dispose {
- my ($this) = @_;
-
- foreach my $child (values %{ $this->{$Children} || {} }) {
- if (ref $child eq 'ARRAY') {
- foreach my $inst (@$child) {
- $inst->Dispose;
- }
- } else {
- die new IMPL::Exception("Child is null",%{ $this->{$Children} }) if not $child;
- $child->Dispose;
- }
- }
-
- delete @$this{$Schema,$Children};
-
- $this->SUPER::Dispose;
-}
-1;
\ No newline at end of file
+package Form::Container;
+use strict;
+use Common;
+use Form::Filter;
+use base qw(Form::Item);
+
+BEGIN {
+ DeclareProperty Schema => ACCESS_READ;
+ DeclareProperty Children => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+ $args{Schema} or die new Exception('A schema is required');
+
+ $this->SUPER::CTOR(@args{qw(Id Form Parent Attributes)});
+ $this->{$Schema} = $args{Schema};
+}
+
+sub ResolveItem {
+ my ($this,$ItemId) = @_;
+
+ if (my $schemaChild = $this->{$Schema}->FindChild($ItemId->Name)) {
+ if ($schemaChild->isMulti) {
+ defined $ItemId->InstanceID or die new Exception('Instance id is required for a muti element');
+ if (my $child = $this->{$Children}{$ItemId->Name}[$ItemId->InstanceID]){
+ return $child;
+ } else {
+ return undef if not $this->Form->AutoCreate;
+ return $this->{$Children}{$ItemId->Name}[$ItemId->InstanceID] = $this->Form->CreateInstance($schemaChild,$ItemId,$this);
+ }
+
+ } else {
+ defined $ItemId->InstanceID and die new Exception('The child is a single element',$this->Id->Canonical,$ItemId->Name);
+ if(my $child = $this->{$Children}{$ItemId->Name}) {
+ return $child;
+ } else {
+ return undef if not $this->Form->AutoCreate;
+ return $this->{$Children}{$ItemId->Name} = $this->Form->CreateInstance($schemaChild,$ItemId,$this);
+ }
+ }
+ } else {
+ die new Exception('The requested item isn\'t exists in the schema', $this->Id->Canonical,$ItemId->Name);
+ }
+}
+
+sub isEmpty {
+ my ($this) = @_;
+
+ foreach my $child (values %{$this->{$Children} || {} }) {
+ if (ref $child eq 'ARRAY') {
+ foreach my $inst (@$child) {
+ return 0 if not $child->isEmpty;
+ }
+ } else {
+ return 0 if not $child->isEmpty;
+ }
+ }
+
+ return 1;
+}
+
+=pod
+Получает дочерние контенеры в виде списка, при том только не пустые контейнеры.
+Если дочернний контейнер не множественный, то список будет состоять из одного элемента.
+=cut
+sub GetChild {
+ my ($this,$name) = @_;
+ return unless exists $this->{$Children}{$name};
+ return( grep $_, map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : $_ } $this->{$Children}{$name} );
+}
+
+=pod
+Выполняет фильтры по схеме для себя и всех детей.
+Фильтры определяются по схеме и вызываются в различнх контекстах
+
+* сначала для группы,
+* потом для детишек, причем если
+ * детишки множественные, то
+ * снсчала для набора детишек, а потом
+ * для каждого в отдельности
+=cut
+sub Validate {
+ my ($this,$rhDisableFilters) = @_;
+
+ $rhDisableFilters ||= {};
+
+ my @errors;
+
+ foreach my $filter (grep {$_->SUPPORTED_CONTEXT & (Form::Filter::CTX_SINGLE) and not exists $rhDisableFilters->{$_}} map {$_->Instance} $this->{$Schema}->Filters) {
+ my $result = $filter->Invoke($this,Form::Filter::CTX_SINGLE | Form::Filter::CTX_EXISTENT,$this->{$Schema});
+ if ($result->State == Form::FilterResult::STATE_SUCCESS_STOP) {
+ return ();
+ } elsif ($result->State == Form::FilterResult::STATE_ERROR) {
+ push @errors,$result;
+ }
+ }
+
+ CHILD_LOOP: foreach my $schemaChild ($this->{$Schema}->Children) {
+
+ if ($schemaChild->isMulti) {
+ my %DisableFilters;
+ foreach my $filter (grep {$_->SUPPORTED_CONTEXT & Form::Filter::CTX_SET} map {$_->Instance} $schemaChild->Filters) {
+
+ my $result = $filter->Invoke($this->{$Children}{$schemaChild->Name},Form::Filter::CTX_SET,$schemaChild,$this);
+ if ($result->State == Form::FilterResult::STATE_ERROR) {
+ push @errors,$result;
+ # не проверять другие фильтры вообще
+ next CHILD_LOOP;
+ } elsif ($result->State == Form::FilterResult::STATE_SUCCESS_STOP) {
+ # не проверять другие фильтры вообще
+ next CHILD_LOOP;
+ } elsif ($result->State == Form::FilterResult::STATE_SUCCESS_STAY) {
+ # не проверять данный фильтр на каждом экземпляре
+ $DisableFilters{$filter} = 1;
+ } else {
+ # STATE_SUCCESS - все ок
+ }
+ }
+
+ $_ and push @errors,$_->Validate(\%DisableFilters) foreach grep !$_->isEmpty, $this->GetChild($schemaChild->Name);
+
+ } else {
+ my %DisableFilters;
+
+ # проверяем фильтры, которые могут применяться на несуществующем значении
+ foreach my $filter (grep { $_->SUPPORTED_CONTEXT & Form::Filter::CTX_SINGLE and not $_->SUPPORTED_CONTEXT & Form::Filter::CTX_EXISTENT} map {$_->Instance} $schemaChild->Filters) {
+ my $result = $filter->Invoke($this->{$Children}{$schemaChild->Name},Form::Filter::CTX_SINGLE,$schemaChild,$this);
+
+ if ($result->State == Form::FilterResult::STATE_ERROR) {
+ push @errors,$result;
+ # не проверять другие фильтры вообще
+ next CHILD_LOOP;
+ } elsif ($result->State == Form::FilterResult::STATE_SUCCESS_STOP) {
+ # не проверять другие фильтры вообще
+ next CHILD_LOOP;
+ } else {
+ # STATE_SUCCESS(_STAY) - все ок
+ $DisableFilters{$filter} = 1;
+ }
+ }
+
+ # если значение существует, то применяем оставшиеся фильтры
+ push @errors,$this->{$Children}{$schemaChild->Name}->Validate(\%DisableFilters) if $this->{$Children}{$schemaChild->Name};
+ }
+
+ }
+
+ return @errors;
+}
+
+sub Dispose {
+ my ($this) = @_;
+
+ foreach my $child (values %{ $this->{$Children} || {} }) {
+ if (ref $child eq 'ARRAY') {
+ foreach my $inst (@$child) {
+ $inst->Dispose;
+ }
+ } else {
+ die new IMPL::Exception("Child is null",%{ $this->{$Children} }) if not $child;
+ $child->Dispose;
+ }
+ }
+
+ delete @$this{$Schema,$Children};
+
+ $this->SUPER::Dispose;
+}
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Form/Filter.pm
--- a/Lib/Form/Filter.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Form/Filter.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,67 +1,67 @@
-package Form::Filter;
-use strict;
-use Common;
-our @ISA = qw(Object);
-
-use constant {
- CTX_SINGLE => 1, # значение поля
- CTX_SET => 2, # множество значений
- CTX_EXISTENT => 4 # только существующие значения
-};
-
-BEGIN {
- DeclareProperty Name => ACCESS_READ;
- DeclareProperty Message => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,$name,$message) = @_;
- $this->{$Name} = $name or die new Exception('A filter name is required');
- $this->{$Message} = $message;
-}
-
-sub FormatMessage {
- my ($this,$object) = @_;
-
- (my $message = $object->Attributes->{$this->{$Name}} || $this->{$Message} || ($Common::Debug ? "$this->{$Name}: %name%" : '')) =~ s{%(\w+(?:\.\w+)*)%}{
- my $value = $object->Attributes->{$1} || ($Common::Debug ? $object->Name.'.'.$1 : '');
- }ge;
-
- return $message;
-}
-
-package Form::FilterResult;
-use Common;
-our @ISA = qw(Object);
-
-use constant {
- STATE_ERROR => 0, # ошибочное значение
- STATE_SUCCESS => 1, # значение корректное, можно продолжать выполнение
- STATE_SUCCESS_STOP => 2, # значение корректное, выполнение остальных фильтров не требуется
- STATE_SUCCESS_STAY => 3 # значение корректное, выполнение данного фильтра более не требуется
-};
-
-BEGIN {
- DeclareProperty State => ACCESS_READ;
- DeclareProperty Message => ACCESS_READ;
- DeclareProperty Target => ACCESS_READ;
- DeclareProperty Container => ACCESS_READ;
-}
-
-sub CTOR {
- my $this = shift;
- $this->SUPER::CTOR(@_);
-
- UNIVERSAL::isa($this->{$Target},'Form::Item') or UNIVERSAL::isa($this->{$Container},'Form::Container') or die new Exception("Invalid Target or Container property") if $this->{$State} == STATE_ERROR;
-}
-
-sub Item {
- my $this = shift;
-
- return ref $this->{$Target} ?
- ($this->{$Target}->isa('Form::Item') ? $this->{$Target} : $this->{$Container}->Item( $this->{$Target}->isMulti ? $this->{$Target}->Name . '0' : $this->{$Target}->Name ) )
- :
- ($this->{$Target});
-}
-
-1;
+package Form::Filter;
+use strict;
+use Common;
+our @ISA = qw(Object);
+
+use constant {
+ CTX_SINGLE => 1, # значение поля
+ CTX_SET => 2, # множество значений
+ CTX_EXISTENT => 4 # только существующие значения
+};
+
+BEGIN {
+ DeclareProperty Name => ACCESS_READ;
+ DeclareProperty Message => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,$name,$message) = @_;
+ $this->{$Name} = $name or die new Exception('A filter name is required');
+ $this->{$Message} = $message;
+}
+
+sub FormatMessage {
+ my ($this,$object) = @_;
+
+ (my $message = $object->Attributes->{$this->{$Name}} || $this->{$Message} || ($Common::Debug ? "$this->{$Name}: %name%" : '')) =~ s{%(\w+(?:\.\w+)*)%}{
+ my $value = $object->Attributes->{$1} || ($Common::Debug ? $object->Name.'.'.$1 : '');
+ }ge;
+
+ return $message;
+}
+
+package Form::FilterResult;
+use Common;
+our @ISA = qw(Object);
+
+use constant {
+ STATE_ERROR => 0, # ошибочное значение
+ STATE_SUCCESS => 1, # значение корректное, можно продолжать выполнение
+ STATE_SUCCESS_STOP => 2, # значение корректное, выполнение остальных фильтров не требуется
+ STATE_SUCCESS_STAY => 3 # значение корректное, выполнение данного фильтра более не требуется
+};
+
+BEGIN {
+ DeclareProperty State => ACCESS_READ;
+ DeclareProperty Message => ACCESS_READ;
+ DeclareProperty Target => ACCESS_READ;
+ DeclareProperty Container => ACCESS_READ;
+}
+
+sub CTOR {
+ my $this = shift;
+ $this->SUPER::CTOR(@_);
+
+ UNIVERSAL::isa($this->{$Target},'Form::Item') or UNIVERSAL::isa($this->{$Container},'Form::Container') or die new Exception("Invalid Target or Container property") if $this->{$State} == STATE_ERROR;
+}
+
+sub Item {
+ my $this = shift;
+
+ return ref $this->{$Target} ?
+ ($this->{$Target}->isa('Form::Item') ? $this->{$Target} : $this->{$Container}->Item( $this->{$Target}->isMulti ? $this->{$Target}->Name . '0' : $this->{$Target}->Name ) )
+ :
+ ($this->{$Target});
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Form/Filter/Depends.pm
--- a/Lib/Form/Filter/Depends.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Form/Filter/Depends.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,34 +1,34 @@
-package Form::Filter::Depends;
-use base qw(Form::Filter);
-
-use Common;
-
-BEGIN {
- DeclareProperty Fields => ACCESS_READ;
-}
-
-sub SUPPORTED_CONTEXT { Form::Filter::CTX_SINGLE | Form::Filter::CTX_SET }
-
-sub CTOR {
- my ($this,$name,$message,@fields) = @_;
-
- $this->SUPER::CTOR($name,$message);
- $this->{$Fields} = \@fields;
-}
-
-sub Invoke {
- my ($this,$object,$context,$schemaTarget) = @_;
-
- foreach my $field (@{$this->{$Fields}}) {
- my $objProv = $object->Navigate($object->Form->MakeItemId($field,$object->Parent));
-
- if ( not $objProv or $objProv->isEmpty ) {
- return new Form::FilterResult(State => Form::FilterResult::STATE_STOP);
- }
-
- }
-
- return new Form::FilterResult(State => Form::FilterResult::STATE_SUCCESS_STAY);
-}
-
-1;
\ No newline at end of file
+package Form::Filter::Depends;
+use base qw(Form::Filter);
+
+use Common;
+
+BEGIN {
+ DeclareProperty Fields => ACCESS_READ;
+}
+
+sub SUPPORTED_CONTEXT { Form::Filter::CTX_SINGLE | Form::Filter::CTX_SET }
+
+sub CTOR {
+ my ($this,$name,$message,@fields) = @_;
+
+ $this->SUPER::CTOR($name,$message);
+ $this->{$Fields} = \@fields;
+}
+
+sub Invoke {
+ my ($this,$object,$context,$schemaTarget) = @_;
+
+ foreach my $field (@{$this->{$Fields}}) {
+ my $objProv = $object->Navigate($object->Form->MakeItemId($field,$object->Parent));
+
+ if ( not $objProv or $objProv->isEmpty ) {
+ return new Form::FilterResult(State => Form::FilterResult::STATE_STOP);
+ }
+
+ }
+
+ return new Form::FilterResult(State => Form::FilterResult::STATE_SUCCESS_STAY);
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Form/Filter/Mandatory.pm
--- a/Lib/Form/Filter/Mandatory.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Form/Filter/Mandatory.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,34 +1,34 @@
-package Form::Filter::Mandatory;
-use strict;
-use Common;
-use base qw(Form::Filter);
-
-sub SUPPORTED_CONTEXT { Form::Filter::CTX_SINGLE | Form::Filter::CTX_SET }
-
-sub Invoke {
- my ($this,$target,$context,$schemaTarget,$parent) = @_;
-
- my @list;
- if ($context & Form::Filter::CTX_SET) {
- @list = @{$target || []};
- } elsif ($context & (Form::Filter::CTX_SINGLE | Form::Filter::CTX_EXISTENT)) {
- @list = ($target);
- }
-
- foreach my $object (@list) {
- if (defined $object and not $object->isEmpty) {
- return Form::FilterResult->new(
- State => Form::FilterResult::STATE_SUCCESS_STAY
- );
- }
- }
-
- return Form::FilterResult->new(
- State => Form::FilterResult::STATE_ERROR,
- Message => $this->FormatMessage($schemaTarget),
- Target => $schemaTarget,
- Container => $parent
- );
-}
-
-1;
\ No newline at end of file
+package Form::Filter::Mandatory;
+use strict;
+use Common;
+use base qw(Form::Filter);
+
+sub SUPPORTED_CONTEXT { Form::Filter::CTX_SINGLE | Form::Filter::CTX_SET }
+
+sub Invoke {
+ my ($this,$target,$context,$schemaTarget,$parent) = @_;
+
+ my @list;
+ if ($context & Form::Filter::CTX_SET) {
+ @list = @{$target || []};
+ } elsif ($context & (Form::Filter::CTX_SINGLE | Form::Filter::CTX_EXISTENT)) {
+ @list = ($target);
+ }
+
+ foreach my $object (@list) {
+ if (defined $object and not $object->isEmpty) {
+ return Form::FilterResult->new(
+ State => Form::FilterResult::STATE_SUCCESS_STAY
+ );
+ }
+ }
+
+ return Form::FilterResult->new(
+ State => Form::FilterResult::STATE_ERROR,
+ Message => $this->FormatMessage($schemaTarget),
+ Target => $schemaTarget,
+ Container => $parent
+ );
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Form/Filter/Regexp.pm
--- a/Lib/Form/Filter/Regexp.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Form/Filter/Regexp.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,38 +1,38 @@
-package Form::Filter::Regexp;
-use strict;
-use Common;
-use Form::Filter;
-use base qw(Form::Filter);
-
-BEGIN {
- DeclareProperty Regexp => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,@args) = @_;
-
- $this->SUPER::CTOR(@args[0,1]);
-
- my $re = $args[2] or die new Exception('A regular expression is required');
-
- $this->{$Regexp} = qr/$re/;
-}
-
-sub SUPPORTED_CONTEXT { Form::Filter::CTX_SINGLE | Form::Filter::CTX_EXISTENT }
-
-sub Invoke {
- my ($this,$object) = @_;
-
- if ($object->isa('Form::ValueItem')) {
- my $re = $this->{$Regexp};
- if ($object->isEmpty or $object->Value =~ m/$re/) {
- return new Form::FilterResult(State => Form::FilterResult::STATE_SUCCESS);
- } else {
- return new Form::FilterResult(Sate => Form::FilterResult::STATE_ERROR, Message => $this->FormatMessage($object), Target => $object );
- }
- } else {
- die new Exception('Only a value items can be verified against a regular expression');
- }
-}
-
-1;
\ No newline at end of file
+package Form::Filter::Regexp;
+use strict;
+use Common;
+use Form::Filter;
+use base qw(Form::Filter);
+
+BEGIN {
+ DeclareProperty Regexp => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,@args) = @_;
+
+ $this->SUPER::CTOR(@args[0,1]);
+
+ my $re = $args[2] or die new Exception('A regular expression is required');
+
+ $this->{$Regexp} = qr/$re/;
+}
+
+sub SUPPORTED_CONTEXT { Form::Filter::CTX_SINGLE | Form::Filter::CTX_EXISTENT }
+
+sub Invoke {
+ my ($this,$object) = @_;
+
+ if ($object->isa('Form::ValueItem')) {
+ my $re = $this->{$Regexp};
+ if ($object->isEmpty or $object->Value =~ m/$re/) {
+ return new Form::FilterResult(State => Form::FilterResult::STATE_SUCCESS);
+ } else {
+ return new Form::FilterResult(Sate => Form::FilterResult::STATE_ERROR, Message => $this->FormatMessage($object), Target => $object );
+ }
+ } else {
+ die new Exception('Only a value items can be verified against a regular expression');
+ }
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Form/Item.pm
--- a/Lib/Form/Item.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Form/Item.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,79 +1,79 @@
-package Form::Item;
-use strict;
-use Common;
-our @ISA = qw(Object);
-
-BEGIN {
- DeclareProperty Parent => ACCESS_READ;
- DeclareProperty Form => ACCESS_READ;
- DeclareProperty Id => ACCESS_READ;
- DeclareProperty Attributes => ACCESS_ALL;
-}
-
-sub CTOR {
- my ($this,$id,$form,$parent,$attrib) = @_;
-
- $this->{$Id} = $id or die new Exception('An Id i required for the form item');
- $this->{$Form} = $form or die new Exception('A form is required for the form item');
- $this->{$Parent} = $parent;
- $this->{$Attributes} = $attrib || {};
-}
-
-sub Name {
- my ($this) = @_;
- return $this->{$Id}->Name;
-}
-
-sub Navigate {
- my ($this,$ItemId) = @_;
-
- $ItemId or die new Exception("An item id is undefined");
-
- return $this->NavigatePath([$ItemId->ToNAVPath]);
-}
-
-sub Item {
- my ($this,$strId) = @_;
-
- return $this->Navigate($this->Form->MakeItemId($strId,$this));
-}
-
-sub NavigatePath {
- my ($this,$refPath) = @_;
-
- my $ItemId = shift @$refPath or die new Exception("An item id is undefined");
- my $current;
-
- if ($ItemId->isa('Form::ItemId::Prev')) {
- $this->{$Parent} or die new Exception('Can\'t navigate to upper level');
- $current = $this->{$Parent};
- } elsif ($ItemId->isa('Form::ItemId::Root')) {
- $current = $this->{$Form};
- } else {
- $current = $this->ResolveItem($ItemId);
- }
-
- if (@$refPath > 0) {
- die new Exception('The item not found', $ItemId->Canonical) if not $current;
- return $current->NavigatePath($refPath);
- } else {
- return $current;
- }
-}
-
-sub ResolveItem {
- my ($this,$ItemId) = @_;
-
- die new Exception('Item not found',$ItemId->Name);
-}
-
-sub Dispose {
- my ($this) = @_;
-
- undef %$this;
-
- $this->SUPER::Dispose;
-}
-
-
-1;
+package Form::Item;
+use strict;
+use Common;
+our @ISA = qw(Object);
+
+BEGIN {
+ DeclareProperty Parent => ACCESS_READ;
+ DeclareProperty Form => ACCESS_READ;
+ DeclareProperty Id => ACCESS_READ;
+ DeclareProperty Attributes => ACCESS_ALL;
+}
+
+sub CTOR {
+ my ($this,$id,$form,$parent,$attrib) = @_;
+
+ $this->{$Id} = $id or die new Exception('An Id i required for the form item');
+ $this->{$Form} = $form or die new Exception('A form is required for the form item');
+ $this->{$Parent} = $parent;
+ $this->{$Attributes} = $attrib || {};
+}
+
+sub Name {
+ my ($this) = @_;
+ return $this->{$Id}->Name;
+}
+
+sub Navigate {
+ my ($this,$ItemId) = @_;
+
+ $ItemId or die new Exception("An item id is undefined");
+
+ return $this->NavigatePath([$ItemId->ToNAVPath]);
+}
+
+sub Item {
+ my ($this,$strId) = @_;
+
+ return $this->Navigate($this->Form->MakeItemId($strId,$this));
+}
+
+sub NavigatePath {
+ my ($this,$refPath) = @_;
+
+ my $ItemId = shift @$refPath or die new Exception("An item id is undefined");
+ my $current;
+
+ if ($ItemId->isa('Form::ItemId::Prev')) {
+ $this->{$Parent} or die new Exception('Can\'t navigate to upper level');
+ $current = $this->{$Parent};
+ } elsif ($ItemId->isa('Form::ItemId::Root')) {
+ $current = $this->{$Form};
+ } else {
+ $current = $this->ResolveItem($ItemId);
+ }
+
+ if (@$refPath > 0) {
+ die new Exception('The item not found', $ItemId->Canonical) if not $current;
+ return $current->NavigatePath($refPath);
+ } else {
+ return $current;
+ }
+}
+
+sub ResolveItem {
+ my ($this,$ItemId) = @_;
+
+ die new Exception('Item not found',$ItemId->Name);
+}
+
+sub Dispose {
+ my ($this) = @_;
+
+ undef %$this;
+
+ $this->SUPER::Dispose;
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Form/ItemId.pm
--- a/Lib/Form/ItemId.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Form/ItemId.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,46 +1,46 @@
-package Form::ItemId;
-use strict;
-use Common;
-our @ISA = qw(Object);
-
-BEGIN {
- DeclareProperty Name => ACCESS_READ;
- DeclareProperty Canonical => ACCESS_READ;
- DeclareProperty InstanceID => ACCESS_READ;
- DeclareProperty Parent => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,$name,$instance_id,$parent) = @_;
-
- $this->{$Name} = $name or die new Exception('A name is required for the item id');
- $this->{$InstanceID} = $instance_id;
- $this->{$Parent} = $parent;
-
- $this->{$Canonical} = ($parent && !$parent->isa('Form::ItemId::Root') ? $parent->Canonical.'/':'').$name.(defined $instance_id ? $instance_id : '');
-}
-
-sub ToNAVPath {
- my ($this) = @_;
-
- return ($this->{$Parent} ? ($this->{$Parent}->ToNAVPath,$this) : $this);
-}
-
-package Form::ItemId::Prev;
-our @ISA = qw(Form::ItemId);
-
-sub CTOR {
- my ($this,$parent) = @_;
- $this->SUPER::CTOR('(prev)',undef,$parent);
-}
-
-package Form::ItemId::Root;
-our @ISA = qw(Form::ItemId);
-
-sub CTOR {
- my ($this,$parent) = @_;
- $this->SUPER::CTOR('(root)',undef,$parent);
-}
-
-
-1;
+package Form::ItemId;
+use strict;
+use Common;
+our @ISA = qw(Object);
+
+BEGIN {
+ DeclareProperty Name => ACCESS_READ;
+ DeclareProperty Canonical => ACCESS_READ;
+ DeclareProperty InstanceID => ACCESS_READ;
+ DeclareProperty Parent => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,$name,$instance_id,$parent) = @_;
+
+ $this->{$Name} = $name or die new Exception('A name is required for the item id');
+ $this->{$InstanceID} = $instance_id;
+ $this->{$Parent} = $parent;
+
+ $this->{$Canonical} = ($parent && !$parent->isa('Form::ItemId::Root') ? $parent->Canonical.'/':'').$name.(defined $instance_id ? $instance_id : '');
+}
+
+sub ToNAVPath {
+ my ($this) = @_;
+
+ return ($this->{$Parent} ? ($this->{$Parent}->ToNAVPath,$this) : $this);
+}
+
+package Form::ItemId::Prev;
+our @ISA = qw(Form::ItemId);
+
+sub CTOR {
+ my ($this,$parent) = @_;
+ $this->SUPER::CTOR('(prev)',undef,$parent);
+}
+
+package Form::ItemId::Root;
+our @ISA = qw(Form::ItemId);
+
+sub CTOR {
+ my ($this,$parent) = @_;
+ $this->SUPER::CTOR('(root)',undef,$parent);
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Form/Transform.pm
--- a/Lib/Form/Transform.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Form/Transform.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,29 +1,29 @@
-package Form::Transform;
-use strict;
-use warnings;
-use base qw(IMPL::Transform);
-
-sub CTOR {
- my ($this) = @_;
-
- $this->superCTOR(
- Templates => {
- 'Form::Container' => sub { my $this = shift; $this->TransformContainer(@_); },
- 'Form' => sub { my $this = shift; $this->TransformContainer(@_); }
- },
- Default => \&TransformItem
- );
-}
-
-sub TransformContainer {
- my ($this,$container) = @_;
-}
-
-sub TransformItem {
- my ($this,$item) = @_;
- return $item->isEmpty ? undef : $item->Value;
-}
-
-
-
-1;
+package Form::Transform;
+use strict;
+use warnings;
+use base qw(IMPL::Transform);
+
+sub CTOR {
+ my ($this) = @_;
+
+ $this->superCTOR(
+ Templates => {
+ 'Form::Container' => sub { my $this = shift; $this->TransformContainer(@_); },
+ 'Form' => sub { my $this = shift; $this->TransformContainer(@_); }
+ },
+ Default => \&TransformItem
+ );
+}
+
+sub TransformContainer {
+ my ($this,$container) = @_;
+}
+
+sub TransformItem {
+ my ($this,$item) = @_;
+ return $item->isEmpty ? undef : $item->Value;
+}
+
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Form/ValueItem.pm
--- a/Lib/Form/ValueItem.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Form/ValueItem.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,47 +1,47 @@
-package Form::ValueItem;
-use strict;
-use base qw(Form::Item);
-use Common;
-use Form::Filter;
-
-BEGIN {
- DeclareProperty Value => ACCESS_ALL;
- DeclareProperty Type => ACCESS_READ;
- DeclareProperty Schema => ACCESS_READ;
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->SUPER::CTOR(@args{qw(Id Form Parent Attributes)});
- $this->{$Type} = $args{'Type'};
- $this->{$Schema} = $args{'Schema'} or die new Exception('A field schema is required');
-}
-
-sub isEmpty {
- my ($this) = @_;
-
- return length $this->{$Value} ? 0 : 1;
-}
-
-sub Validate {
- my ($this,$rhDisableFilters) = @_;
-
- $rhDisableFilters ||= {};
-
- my @errors;
-
- foreach my $filter (grep {$_->SUPPORTED_CONTEXT & (Form::Filter::CTX_SINGLE) and not exists $rhDisableFilters->{$_}} map {$_->Instance} $this->{$Schema}->Filters) {
- my $result = $filter->Invoke($this,Form::Filter::CTX_SINGLE | Form::Filter::CTX_EXISTENT,$this->{$Schema},$this->Parent);
- if ($result->State == Form::FilterResult::STATE_SUCCESS_STOP) {
- return ();
- } elsif ($result->State == Form::FilterResult::STATE_ERROR) {
- push @errors,$result;
- }
- }
-
- return @errors;
-}
-
-
-1;
+package Form::ValueItem;
+use strict;
+use base qw(Form::Item);
+use Common;
+use Form::Filter;
+
+BEGIN {
+ DeclareProperty Value => ACCESS_ALL;
+ DeclareProperty Type => ACCESS_READ;
+ DeclareProperty Schema => ACCESS_READ;
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->SUPER::CTOR(@args{qw(Id Form Parent Attributes)});
+ $this->{$Type} = $args{'Type'};
+ $this->{$Schema} = $args{'Schema'} or die new Exception('A field schema is required');
+}
+
+sub isEmpty {
+ my ($this) = @_;
+
+ return length $this->{$Value} ? 0 : 1;
+}
+
+sub Validate {
+ my ($this,$rhDisableFilters) = @_;
+
+ $rhDisableFilters ||= {};
+
+ my @errors;
+
+ foreach my $filter (grep {$_->SUPPORTED_CONTEXT & (Form::Filter::CTX_SINGLE) and not exists $rhDisableFilters->{$_}} map {$_->Instance} $this->{$Schema}->Filters) {
+ my $result = $filter->Invoke($this,Form::Filter::CTX_SINGLE | Form::Filter::CTX_EXISTENT,$this->{$Schema},$this->Parent);
+ if ($result->State == Form::FilterResult::STATE_SUCCESS_STOP) {
+ return ();
+ } elsif ($result->State == Form::FilterResult::STATE_ERROR) {
+ push @errors,$result;
+ }
+ }
+
+ return @errors;
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/Form/ValueItem/List.pm
--- a/Lib/Form/ValueItem/List.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/Form/ValueItem/List.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,107 +1,107 @@
-package Form::ValueItem::List;
-use Common;
-use base qw(Form::ValueItem);
-
-BEGIN {
- DeclareProperty ListValues => ACCESS_READ;
- DeclareProperty CurrentItem => ACCESS_READ;
-}
-
-sub CTOR {
- my $this = shift;
- $this->SUPER::CTOR(@_);
-
- $this->{$ListValues} = [];
-
- my $source = $this->Form->Bindings->{$this->Attributes->{source}};
-
- if (ref $source eq 'CODE') {
- $this->LoadList($source->());
- } elsif (ref $source and (UNIVERSAL::isa($source,'HASH') or UNIVERSAL::isa($source,'ARRAY'))){
- $this->LoadList($source);
- } else {
- if (not $source) {
- warn "a source isn't specified for the listvalue ".$this->Id->Canonical;
- } else {
- warn "an unsupported source type ".(ref $source)." for the listvalue".$this->Id->Canonical;
- }
- }
-}
-
-sub Value {
- my $this = shift;
-
- if (@_) {
- my $newValue = shift;
-
- $this->{$CurrentItem}->{active} = 0 if $this->{$CurrentItem};
-
- my ($item) = (defined $newValue ? grep {defined $_->{id} and $_->{id} eq $newValue} @{$this->{$ListValues}} : undef);
-
- if ($item) {
- $this->{$CurrentItem} = $item;
- $item->{active} = 1;
- return $this->SUPER::Value($newValue);
- } else {
- undef $this->{$CurrentItem};
- return $this->SUPER::Value(undef);
- }
- } else {
- return $this->SUPER::Value;
- }
-}
-
-sub LoadList {
- my ($this,$refList) = @_;
-
- if (ref $refList and UNIVERSAL::isa($refList,'HASH')) {
- $this->{$CurrentItem} = undef;
- $this->{$ListValues} = [ sort { $a->{name} cmp $b->{name} } map { Form::ValueItem::List::Item->new($_,ref $refList->{$_} eq 'ARRAY' ? @{$refList->{$_}} : $refList->{$_})} keys %{$refList}];
- $this->SUPER::Value(undef);
- } elsif (ref $refList and UNIVERSAL::isa($refList,'ARRAY')) {
- $this->{$CurrentItem} = undef;
- $this->{$ListValues} = [map { Form::ValueItem::List::Item->new(ref $_ eq 'ARRAY' ? @$_ : $_ )} @$refList];
- $this->SUPER::Value(undef);
- } else {
- die new Exception('An unexpected list type');
- }
-}
-
-package Form::ValueItem::List::Item;
-use fields qw(
- id
- description
- name
- active
-);
-
-sub new {
- my ($class,$id,$name,$desc) = @_;
-
- my $this=fields::new($class);
- $this->{id} = $id;
- $this->{name} = $name;
- $this->{description} = $desc;
-
- return $this;
-}
-
-#compatibility with TToolkit
-
-sub Id {
- $_[0]->{id};
-}
-
-sub Description {
- $_[0]->{description};
-}
-
-sub Active {
- $_[0]->{active};
-}
-
-sub Name {
- $_[0]->{name};
-}
-
-1;
+package Form::ValueItem::List;
+use Common;
+use base qw(Form::ValueItem);
+
+BEGIN {
+ DeclareProperty ListValues => ACCESS_READ;
+ DeclareProperty CurrentItem => ACCESS_READ;
+}
+
+sub CTOR {
+ my $this = shift;
+ $this->SUPER::CTOR(@_);
+
+ $this->{$ListValues} = [];
+
+ my $source = $this->Form->Bindings->{$this->Attributes->{source}};
+
+ if (ref $source eq 'CODE') {
+ $this->LoadList($source->());
+ } elsif (ref $source and (UNIVERSAL::isa($source,'HASH') or UNIVERSAL::isa($source,'ARRAY'))){
+ $this->LoadList($source);
+ } else {
+ if (not $source) {
+ warn "a source isn't specified for the listvalue ".$this->Id->Canonical;
+ } else {
+ warn "an unsupported source type ".(ref $source)." for the listvalue".$this->Id->Canonical;
+ }
+ }
+}
+
+sub Value {
+ my $this = shift;
+
+ if (@_) {
+ my $newValue = shift;
+
+ $this->{$CurrentItem}->{active} = 0 if $this->{$CurrentItem};
+
+ my ($item) = (defined $newValue ? grep {defined $_->{id} and $_->{id} eq $newValue} @{$this->{$ListValues}} : undef);
+
+ if ($item) {
+ $this->{$CurrentItem} = $item;
+ $item->{active} = 1;
+ return $this->SUPER::Value($newValue);
+ } else {
+ undef $this->{$CurrentItem};
+ return $this->SUPER::Value(undef);
+ }
+ } else {
+ return $this->SUPER::Value;
+ }
+}
+
+sub LoadList {
+ my ($this,$refList) = @_;
+
+ if (ref $refList and UNIVERSAL::isa($refList,'HASH')) {
+ $this->{$CurrentItem} = undef;
+ $this->{$ListValues} = [ sort { $a->{name} cmp $b->{name} } map { Form::ValueItem::List::Item->new($_,ref $refList->{$_} eq 'ARRAY' ? @{$refList->{$_}} : $refList->{$_})} keys %{$refList}];
+ $this->SUPER::Value(undef);
+ } elsif (ref $refList and UNIVERSAL::isa($refList,'ARRAY')) {
+ $this->{$CurrentItem} = undef;
+ $this->{$ListValues} = [map { Form::ValueItem::List::Item->new(ref $_ eq 'ARRAY' ? @$_ : $_ )} @$refList];
+ $this->SUPER::Value(undef);
+ } else {
+ die new Exception('An unexpected list type');
+ }
+}
+
+package Form::ValueItem::List::Item;
+use fields qw(
+ id
+ description
+ name
+ active
+);
+
+sub new {
+ my ($class,$id,$name,$desc) = @_;
+
+ my $this=fields::new($class);
+ $this->{id} = $id;
+ $this->{name} = $name;
+ $this->{description} = $desc;
+
+ return $this;
+}
+
+#compatibility with TToolkit
+
+sub Id {
+ $_[0]->{id};
+}
+
+sub Description {
+ $_[0]->{description};
+}
+
+sub Active {
+ $_[0]->{active};
+}
+
+sub Name {
+ $_[0]->{name};
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/Class/Member.pm
--- a/Lib/IMPL/Class/Member.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/Class/Member.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,37 +1,37 @@
-package IMPL::Class::Member;
-use strict;
-use base qw(Exporter);
-our @EXPORT = qw(virtual public private protected);
-
-use IMPL::Class::Meta;
-require IMPL::Class::MemberInfo;
-
-use constant {
- MOD_PUBLIC => 1,
- MOD_PROTECTED => 2,
- MOD_PRIVATE => 3
-};
-
-sub virtual($) {
- $_[0]->Virtual(1);
- $_[0];
-}
-
-sub public($) {
- $_[0]->Access(MOD_PUBLIC);
- $_[0]->Implement;
- $_[0];
-}
-
-sub private($) {
- $_[0]->Access(MOD_PRIVATE);
- $_[0]->Implement;
- $_[0];
-}
-
-sub protected($) {
- $_[0]->Access(MOD_PROTECTED);
- $_[0]->Implement;
- $_[0];
-}
-1;
\ No newline at end of file
+package IMPL::Class::Member;
+use strict;
+use base qw(Exporter);
+our @EXPORT = qw(virtual public private protected);
+
+use IMPL::Class::Meta;
+require IMPL::Class::MemberInfo;
+
+use constant {
+ MOD_PUBLIC => 1,
+ MOD_PROTECTED => 2,
+ MOD_PRIVATE => 3
+};
+
+sub virtual($) {
+ $_[0]->Virtual(1);
+ $_[0];
+}
+
+sub public($) {
+ $_[0]->Access(MOD_PUBLIC);
+ $_[0]->Implement;
+ $_[0];
+}
+
+sub private($) {
+ $_[0]->Access(MOD_PRIVATE);
+ $_[0]->Implement;
+ $_[0];
+}
+
+sub protected($) {
+ $_[0]->Access(MOD_PROTECTED);
+ $_[0]->Implement;
+ $_[0];
+}
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/Class/MemberInfo.pm
--- a/Lib/IMPL/Class/MemberInfo.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/Class/MemberInfo.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,48 +1,48 @@
-package IMPL::Class::MemberInfo;
-use strict;
-use base qw(IMPL::Object::Accessor);
-
-require IMPL::Exception;
-require IMPL::Class::Member;
-
-__PACKAGE__->mk_accessors(
- qw(
- Name
- Access
- Virtual
- Class
- Frozen
- Implementor
- Attributes
- )
-);
-__PACKAGE__->PassThroughArgs;
-
-sub CTOR {
- my $this = shift;
-
- die new IMPL::Exception('The name is required for the member') unless $this->Name;
- die new IMPL::Exception('The class is required for the member') unless $this->Class;
-
- $this->Frozen(0);
- $this->Virtual(0) unless defined $this->Virtual;
- $this->Access(3) unless $this->Access;
-}
-
-sub Implement {
- my ($this) = @_;
- $this->Implementor->Make($this);
- $this->Frozen(1);
- $this->Class->set_meta($this);
- return;
-}
-
-sub set {
- my $this = shift;
- if ($this->Frozen) {
- die new IMPL::Exception('The member information can\'t be modified', $this->Name);
- }
- $this->SUPER::set(@_);
-}
-
-1;
+package IMPL::Class::MemberInfo;
+use strict;
+use base qw(IMPL::Object::Accessor);
+
+require IMPL::Exception;
+require IMPL::Class::Member;
+
+__PACKAGE__->mk_accessors(
+ qw(
+ Name
+ Access
+ Virtual
+ Class
+ Frozen
+ Implementor
+ Attributes
+ )
+);
+__PACKAGE__->PassThroughArgs;
+
+sub CTOR {
+ my $this = shift;
+
+ die new IMPL::Exception('The name is required for the member') unless $this->Name;
+ die new IMPL::Exception('The class is required for the member') unless $this->Class;
+
+ $this->Frozen(0);
+ $this->Virtual(0) unless defined $this->Virtual;
+ $this->Access(3) unless $this->Access;
+}
+
+sub Implement {
+ my ($this) = @_;
+ $this->Implementor->Make($this);
+ $this->Frozen(1);
+ $this->Class->set_meta($this);
+ return;
+}
+
+sub set {
+ my $this = shift;
+ if ($this->Frozen) {
+ die new IMPL::Exception('The member information can\'t be modified', $this->Name);
+ }
+ $this->SUPER::set(@_);
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/Class/Meta.pm
--- a/Lib/IMPL/Class/Meta.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/Class/Meta.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,43 +1,43 @@
-package IMPL::Class::Meta;
-use strict;
-
-my %class_meta;
-
-sub set_meta {
- my ($class,$meta_data) = @_;
- $class = ref $class if ref $class;
-
- # тут нельзя использовать стандартное исключение, поскольку для него используется
- # класс IMPL::Object::Accessor, который наследуется от текущего класса
- die "The meta_data parameter should be an object" if not ref $meta_data;
-
- push @{$class_meta{$class}{ref $meta_data}},$meta_data;
-}
-
-sub get_meta {
- my ($class,$meta_class,$predicate,$deep) = @_;
- $class = ref $class if ref $class;
- no strict 'refs';
- my @result;
-
- if ($deep) {
- @result = map { $_->can('get_meta') ? $_->get_meta($meta_class,$predicate,$deep) : () } @{$class.'::ISA'};
- }
-
- if ($predicate) {
- push @result,grep( &$predicate($_), map( @{$class_meta{$class}{$_}}, grep( $_->isa($meta_class), keys %{$class_meta{$class} || {}} ) ) );
- } else {
- push @result, map( @{$class_meta{$class}{$_} || []}, grep( $_->isa($meta_class), keys %{$class_meta{$class} || {}} ) );
- }
- wantarray ? @result : \@result;
-}
-
-=pod
-__PACKAGE_->set_meta($metaObject);
-__PACKAGE_->get_meta('MyMetaClass',sub {
- my ($item) = @_;
- $item->Name eq 'Something' ? 1 : 0
-} );
-=cut
-
-1;
\ No newline at end of file
+package IMPL::Class::Meta;
+use strict;
+
+my %class_meta;
+
+sub set_meta {
+ my ($class,$meta_data) = @_;
+ $class = ref $class if ref $class;
+
+ # тут нельзя использовать стандартное исключение, поскольку для него используется
+ # класс IMPL::Object::Accessor, который наследуется от текущего класса
+ die "The meta_data parameter should be an object" if not ref $meta_data;
+
+ push @{$class_meta{$class}{ref $meta_data}},$meta_data;
+}
+
+sub get_meta {
+ my ($class,$meta_class,$predicate,$deep) = @_;
+ $class = ref $class if ref $class;
+ no strict 'refs';
+ my @result;
+
+ if ($deep) {
+ @result = map { $_->can('get_meta') ? $_->get_meta($meta_class,$predicate,$deep) : () } @{$class.'::ISA'};
+ }
+
+ if ($predicate) {
+ push @result,grep( &$predicate($_), map( @{$class_meta{$class}{$_}}, grep( $_->isa($meta_class), keys %{$class_meta{$class} || {}} ) ) );
+ } else {
+ push @result, map( @{$class_meta{$class}{$_} || []}, grep( $_->isa($meta_class), keys %{$class_meta{$class} || {}} ) );
+ }
+ wantarray ? @result : \@result;
+}
+
+=pod
+__PACKAGE_->set_meta($metaObject);
+__PACKAGE_->get_meta('MyMetaClass',sub {
+ my ($item) = @_;
+ $item->Name eq 'Something' ? 1 : 0
+} );
+=cut
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/Class/Property.pm
--- a/Lib/IMPL/Class/Property.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/Class/Property.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,35 +1,35 @@
-package IMPL::Class::Property;
-use strict;
-use base qw(Exporter);
-BEGIN {
- our @EXPORT = qw(property prop_get prop_set owner_set prop_none prop_all prop_list CreateProperty);
-}
-
-require IMPL::Class::Member;
-require IMPL::Class::PropertyInfo;
-
-sub import {
- __PACKAGE__->export_to_level(1,@_);
- IMPL::Class::Member->export_to_level(1,@_);
-}
-
-sub prop_get { 1 };
-sub prop_set { 2 };
-sub owner_set { 2 };
-sub prop_none { 0 };
-sub prop_all { 3 };
-sub prop_list { 4 };
-
-sub property($$;$) {
- my ($propName,$mutators,$attributes) = @_;
- my $Info = new IMPL::Class::PropertyInfo( {Name => $propName, Mutators => $mutators, Class => scalar(caller), Attributes => $attributes } );
- return $Info;
-}
-
-sub CreateProperty {
- my ($class,$propName,$mutators,$attributes) = @_;
- my $Info = new IMPL::Class::PropertyInfo( {Name => $propName, Mutators => $mutators, Class => $class, Attributes => $attributes} );
- return $Info;
-};
-
-1;
\ No newline at end of file
+package IMPL::Class::Property;
+use strict;
+use base qw(Exporter);
+BEGIN {
+ our @EXPORT = qw(property prop_get prop_set owner_set prop_none prop_all prop_list CreateProperty);
+}
+
+require IMPL::Class::Member;
+require IMPL::Class::PropertyInfo;
+
+sub import {
+ __PACKAGE__->export_to_level(1,@_);
+ IMPL::Class::Member->export_to_level(1,@_);
+}
+
+sub prop_get { 1 };
+sub prop_set { 2 };
+sub owner_set { 2 };
+sub prop_none { 0 };
+sub prop_all { 3 };
+sub prop_list { 4 };
+
+sub property($$;$) {
+ my ($propName,$mutators,$attributes) = @_;
+ my $Info = new IMPL::Class::PropertyInfo( {Name => $propName, Mutators => $mutators, Class => scalar(caller), Attributes => $attributes } );
+ return $Info;
+}
+
+sub CreateProperty {
+ my ($class,$propName,$mutators,$attributes) = @_;
+ my $Info = new IMPL::Class::PropertyInfo( {Name => $propName, Mutators => $mutators, Class => $class, Attributes => $attributes} );
+ return $Info;
+};
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/Class/Property/Direct.pm
--- a/Lib/IMPL/Class/Property/Direct.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/Class/Property/Direct.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,111 +1,111 @@
-package IMPL::Class::Property::Direct;
-use strict;
-
-use base qw(IMPL::Object::Accessor Exporter);
-our @EXPORT = qw(_direct);
-
-use IMPL::Class::Property;
-require IMPL::Exception;
-
-__PACKAGE__->mk_accessors qw(ExportField);
-
-sub _direct($) {
- my ($prop_info) = @_;
- $prop_info->Implementor( IMPL::Class::Property::Direct->new({ExportField => 1}) );
- return $prop_info;
-}
-
-my $access_private = "die new IMPL::Exception('Can\\'t access the private member',\$name,\$class,scalar caller) unless caller eq \$class;";
-my $access_protected = "die new IMPL::Exception('Can\\'t access the protected member',\$name,\$class,scalar caller) unless caller eq \$class;";
-
-my $accessor_get_no = 'die new IMPL::Exception(\'The property is write only\',$name,$class) unless $get;';
-my $accessor_set_no = 'die new IMPL::Exception(\'The property is read only\',$name,$class) unless $set;';
-my $accessor_set = 'return( $this->{$field} = @_ == 1 ? $_[0] : [@_] );';
-my $accessor_get = 'return( $this->{$field} );';
-my $list_accessor_set = 'return( @{ ($this->{$field} = ( (@_ == 1 and ref $_[0] eq \'ARRAY\') ? $_[0] : [@_] ) || [] ) } );';
-my $list_accessor_get = 'return( @{ $this->{$field} || [] } );';
-my $custom_accessor_get = 'unshift @_, $this and goto &$get;';
-my $custom_accessor_set = 'unshift @_, $this and goto &$set;';
-
-my %accessor_cache;
-sub mk_acessor {
- my ($virtual,$access,$class,$name,$mutators,$field) = @_;
-
- my ($get,$set) = ref $mutators ? ( $mutators->{get}, $mutators->{set}) : ($mutators & prop_get, $mutators & prop_set);
- my $key = join '',$virtual,$access,$get ? 1 : 0,$set ? 1 : 0, (ref $mutators ? 'c' : ($mutators & prop_list() ? 'l' : 's'));
- my $factory = $accessor_cache{$key};
- if (not $factory) {
- my $code =
-<can(\$name);
- return \$this->\$method(\@_) unless \$method == \$accessor or caller->isa(\$class);
-VCALL
- $code .= "$access_private\n" if $access == IMPL::Class::Member::MOD_PRIVATE;
- $code .= "$access_protected\n" if $access == IMPL::Class::Member::MOD_PROTECTED;
- my ($codeGet,$codeSet);
- if (ref $mutators) {
- $codeGet = $get ? $custom_accessor_get : $accessor_get_no;
- $codeSet = $set ? $custom_accessor_set : $accessor_set_no;
- } else {
- if ($mutators & prop_list) {
- $codeGet = $get ? $list_accessor_get : $accessor_get_no;
- $codeSet = $set ? $list_accessor_set : $accessor_set_no;
- } else {
- $codeGet = $get ? $accessor_get : $accessor_get_no;
- $codeSet = $set ? $accessor_set : $accessor_set_no;
- }
- }
- $code .=
-<($class,$name,$set,$get, $field);
-}
-
-sub Make {
- my ($self,$propInfo) = @_;
-
- my $isExportField = ref $self ? ($self->ExportField || 0) : 0;
- my ($class,$name,$virt,$access,$mutators) = $propInfo->get qw(Class Name Virtual Access Mutators);
- (my $field = "${class}_$name") =~ s/::/_/g;
-
- my $propGlob = $class.'::'.$name;
-
- no strict 'refs';
- *$propGlob = mk_acessor($virt,$access,$class,$name,$mutators,$field);
- *$propGlob = \$field if $isExportField;
-
- if (ref $mutators) {
- $propInfo->canGet( $mutators->{get} ? 1 : 0);
- $propInfo->canSet( $mutators->{set} ? 1 : 0);
- } else {
- $propInfo->canGet( ($mutators & prop_get) ? 1 : 0);
- $propInfo->canSet( ($mutators & prop_set) ? 1 : 0);
- }
-}
-
-sub FieldName {
- my ($self,$propInfo) = @_;
-
- my ($class,$name) = $propInfo->get qw(Class Name);
- (my $field = "${class}_$name") =~ s/::/_/g;
- return $field;
-}
-
-1;
\ No newline at end of file
+package IMPL::Class::Property::Direct;
+use strict;
+
+use base qw(IMPL::Object::Accessor Exporter);
+our @EXPORT = qw(_direct);
+
+use IMPL::Class::Property;
+require IMPL::Exception;
+
+__PACKAGE__->mk_accessors qw(ExportField);
+
+sub _direct($) {
+ my ($prop_info) = @_;
+ $prop_info->Implementor( IMPL::Class::Property::Direct->new({ExportField => 1}) );
+ return $prop_info;
+}
+
+my $access_private = "die new IMPL::Exception('Can\\'t access the private member',\$name,\$class,scalar caller) unless caller eq \$class;";
+my $access_protected = "die new IMPL::Exception('Can\\'t access the protected member',\$name,\$class,scalar caller) unless caller eq \$class;";
+
+my $accessor_get_no = 'die new IMPL::Exception(\'The property is write only\',$name,$class) unless $get;';
+my $accessor_set_no = 'die new IMPL::Exception(\'The property is read only\',$name,$class) unless $set;';
+my $accessor_set = 'return( $this->{$field} = @_ == 1 ? $_[0] : [@_] );';
+my $accessor_get = 'return( $this->{$field} );';
+my $list_accessor_set = 'return( @{ ($this->{$field} = ( (@_ == 1 and ref $_[0] eq \'ARRAY\') ? $_[0] : [@_] ) || [] ) } );';
+my $list_accessor_get = 'return( @{ $this->{$field} || [] } );';
+my $custom_accessor_get = 'unshift @_, $this and goto &$get;';
+my $custom_accessor_set = 'unshift @_, $this and goto &$set;';
+
+my %accessor_cache;
+sub mk_acessor {
+ my ($virtual,$access,$class,$name,$mutators,$field) = @_;
+
+ my ($get,$set) = ref $mutators ? ( $mutators->{get}, $mutators->{set}) : ($mutators & prop_get, $mutators & prop_set);
+ my $key = join '',$virtual,$access,$get ? 1 : 0,$set ? 1 : 0, (ref $mutators ? 'c' : ($mutators & prop_list() ? 'l' : 's'));
+ my $factory = $accessor_cache{$key};
+ if (not $factory) {
+ my $code =
+<can(\$name);
+ return \$this->\$method(\@_) unless \$method == \$accessor or caller->isa(\$class);
+VCALL
+ $code .= "$access_private\n" if $access == IMPL::Class::Member::MOD_PRIVATE;
+ $code .= "$access_protected\n" if $access == IMPL::Class::Member::MOD_PROTECTED;
+ my ($codeGet,$codeSet);
+ if (ref $mutators) {
+ $codeGet = $get ? $custom_accessor_get : $accessor_get_no;
+ $codeSet = $set ? $custom_accessor_set : $accessor_set_no;
+ } else {
+ if ($mutators & prop_list) {
+ $codeGet = $get ? $list_accessor_get : $accessor_get_no;
+ $codeSet = $set ? $list_accessor_set : $accessor_set_no;
+ } else {
+ $codeGet = $get ? $accessor_get : $accessor_get_no;
+ $codeSet = $set ? $accessor_set : $accessor_set_no;
+ }
+ }
+ $code .=
+<($class,$name,$set,$get, $field);
+}
+
+sub Make {
+ my ($self,$propInfo) = @_;
+
+ my $isExportField = ref $self ? ($self->ExportField || 0) : 0;
+ my ($class,$name,$virt,$access,$mutators) = $propInfo->get qw(Class Name Virtual Access Mutators);
+ (my $field = "${class}_$name") =~ s/::/_/g;
+
+ my $propGlob = $class.'::'.$name;
+
+ no strict 'refs';
+ *$propGlob = mk_acessor($virt,$access,$class,$name,$mutators,$field);
+ *$propGlob = \$field if $isExportField;
+
+ if (ref $mutators) {
+ $propInfo->canGet( $mutators->{get} ? 1 : 0);
+ $propInfo->canSet( $mutators->{set} ? 1 : 0);
+ } else {
+ $propInfo->canGet( ($mutators & prop_get) ? 1 : 0);
+ $propInfo->canSet( ($mutators & prop_set) ? 1 : 0);
+ }
+}
+
+sub FieldName {
+ my ($self,$propInfo) = @_;
+
+ my ($class,$name) = $propInfo->get qw(Class Name);
+ (my $field = "${class}_$name") =~ s/::/_/g;
+ return $field;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/Class/PropertyInfo.pm
--- a/Lib/IMPL/Class/PropertyInfo.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/Class/PropertyInfo.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,57 +1,57 @@
-package IMPL::Class::PropertyInfo;
-use strict;
-
-use base qw(IMPL::Class::MemberInfo);
-
-__PACKAGE__->mk_accessors(qw(Type Mutators canGet canSet));
-__PACKAGE__->PassThroughArgs;
-
-my %LoadedModules;
-
-sub CTOR {
- my $this = shift;
-
- if ( my $type = $this->Attributes ? delete $this->Attributes->{type} : undef ) {
- $this->Type($type);
- }
-
- $this->Mutators(0) unless defined $this->Mutators;
-}
-
-sub Implementor {
- my $this = shift;
-
- my $implementor;
-
- if (@_) {
- $this->SUPER::Implementor(@_);
- } else {
- my $implementor = $this->SUPER::Implementor;
- return $implementor if $implementor;
-
- $implementor = $this->SelectImplementor();
-
- if (my $class = ref $implementor ? undef : $implementor) {
- if (not $LoadedModules{$class}) {
- (my $package = $class.'.pm') =~ s/::/\//g;
- require $package;
- $LoadedModules{$class} = 1;
- }
- }
-
- $this->Implementor($implementor);
- return $implementor;
- }
-
-}
-
-sub SelectImplementor {
- my ($this) = @_;
-
- if ($this->Class->can('_PropertyImplementor')) {
- return $this->Class->_PropertyImplementor;
- }
- die new IMPL::Exception('Can\'t find a property implementor for the specified class',$this->Class);
-}
-
-1;
\ No newline at end of file
+package IMPL::Class::PropertyInfo;
+use strict;
+
+use base qw(IMPL::Class::MemberInfo);
+
+__PACKAGE__->mk_accessors(qw(Type Mutators canGet canSet));
+__PACKAGE__->PassThroughArgs;
+
+my %LoadedModules;
+
+sub CTOR {
+ my $this = shift;
+
+ if ( my $type = $this->Attributes ? delete $this->Attributes->{type} : undef ) {
+ $this->Type($type);
+ }
+
+ $this->Mutators(0) unless defined $this->Mutators;
+}
+
+sub Implementor {
+ my $this = shift;
+
+ my $implementor;
+
+ if (@_) {
+ $this->SUPER::Implementor(@_);
+ } else {
+ my $implementor = $this->SUPER::Implementor;
+ return $implementor if $implementor;
+
+ $implementor = $this->SelectImplementor();
+
+ if (my $class = ref $implementor ? undef : $implementor) {
+ if (not $LoadedModules{$class}) {
+ (my $package = $class.'.pm') =~ s/::/\//g;
+ require $package;
+ $LoadedModules{$class} = 1;
+ }
+ }
+
+ $this->Implementor($implementor);
+ return $implementor;
+ }
+
+}
+
+sub SelectImplementor {
+ my ($this) = @_;
+
+ if ($this->Class->can('_PropertyImplementor')) {
+ return $this->Class->_PropertyImplementor;
+ }
+ die new IMPL::Exception('Can\'t find a property implementor for the specified class',$this->Class);
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/Config.pm
--- a/Lib/IMPL/Config.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/Config.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,132 +1,132 @@
-package IMPL::Config;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object IMPL::Object::Serializable IMPL::Object::Autofill);
-
-__PACKAGE__->PassThroughArgs;
-
-use IMPL::Class::Member;
-use IMPL::Class::PropertyInfo;
-use IMPL::Exception;
-
-use IMPL::Serialization;
-use IMPL::Serialization::XmlFormatter;
-
-sub LoadXMLFile {
- my ($self,$file) = @_;
-
- my $class = ref $self || $self;
-
- my $serializer = new IMPL::Serializer(
- Formatter => new IMPL::Serialization::XmlFormatter(
- IdentOutput => 1,
- SkipWhitespace => 1
- )
- );
-
- open my $hFile,'<',$file or die new IMPL::Exception("Failed to open file",$file,$!);
-
- my $obj;
- eval {
- $obj = $serializer->Deserialize($hFile);
- };
-
- if ($@) {
- my $e=$@;
- die new IMPL::Exception("Can't load the configuration file",$file,$e);
- }
- return $obj;
-}
-
-sub SaveXMLFile {
- my ($this,$file) = @_;
-
- my $serializer = new IMPL::Serializer(
- Formatter => new IMPL::Serialization::XmlFormatter(
- IdentOutput => 1,
- SkipWhitespace => 1
- )
- );
-
- open my $hFile,'>',$file or die new IMPL::Exception("Failed to open file",$file,$!);
-
- $serializer->Serialize($hFile, $this);
-}
-
-sub xml {
- my $this = shift;
- my $serializer = new IMPL::Serializer(
- Formatter => new IMPL::Serialization::XmlFormatter(
- IdentOutput => 1,
- SkipWhitespace => 1
- )
- );
- my $str = '';
- open my $hFile,'>',\$str or die new IMPL::Exception("Failed to open stream",$!);
-
- $serializer->Serialize($hFile, $this);
-
- undef $hFile;
-
- return $str;
-}
-
-sub save {
- my ($this,$ctx) = @_;
-
- foreach my $info ($this->get_meta('IMPL::Class::PropertyInfo')) {
- next if $info->Access != IMPL::Class::Member::MOD_PUBLIC; # save only public properties
-
- my $name = $info->Name;
- $ctx->AddVar($name => $this->$name()) if $this->$name();
- }
-}
-
-1;
-__END__
-
-=pod
-
-=h1 SYNOPSIS
-
-package App::Config
-use base qw(IMPL::Config)
-
-use IMPL::Class::Property;
-use IMPL::Config::Class;
-
-BEGIN {
- public property SimpleString => prop_all;
- public property MyClass => prop_all;
-}
-
-sub CTOR {
- my $this = shift;
- $this->superCTOR(@_);
-
- $this->MyClass(new IMPL::Config::Class(Type => MyClass)) unless $this->MyClass;
-}
-
-=head1 DESCRIPTION
-
-Позволяет сохранить/загрузить конфигурацию. Также все классы конфигурации
-должны наследоваться от данного класса, и все Public свойства будут
-автоматически сохраняться и восстанавливаться.
-
-=head1 MEMBERS
-
-=over
-
-=item static LoadXMLFile($fileName)
-Создает из XML файла экземпляр приложения
-
-=item SaveXMLFile($fileName)
-Сохраняет приложение в файл
-
-=item xml
-Сохраняет конфигурацию приложения в XML строку
-
-=back
-
-=cut
\ No newline at end of file
+package IMPL::Config;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object IMPL::Object::Serializable IMPL::Object::Autofill);
+
+__PACKAGE__->PassThroughArgs;
+
+use IMPL::Class::Member;
+use IMPL::Class::PropertyInfo;
+use IMPL::Exception;
+
+use IMPL::Serialization;
+use IMPL::Serialization::XmlFormatter;
+
+sub LoadXMLFile {
+ my ($self,$file) = @_;
+
+ my $class = ref $self || $self;
+
+ my $serializer = new IMPL::Serializer(
+ Formatter => new IMPL::Serialization::XmlFormatter(
+ IdentOutput => 1,
+ SkipWhitespace => 1
+ )
+ );
+
+ open my $hFile,'<',$file or die new IMPL::Exception("Failed to open file",$file,$!);
+
+ my $obj;
+ eval {
+ $obj = $serializer->Deserialize($hFile);
+ };
+
+ if ($@) {
+ my $e=$@;
+ die new IMPL::Exception("Can't load the configuration file",$file,$e);
+ }
+ return $obj;
+}
+
+sub SaveXMLFile {
+ my ($this,$file) = @_;
+
+ my $serializer = new IMPL::Serializer(
+ Formatter => new IMPL::Serialization::XmlFormatter(
+ IdentOutput => 1,
+ SkipWhitespace => 1
+ )
+ );
+
+ open my $hFile,'>',$file or die new IMPL::Exception("Failed to open file",$file,$!);
+
+ $serializer->Serialize($hFile, $this);
+}
+
+sub xml {
+ my $this = shift;
+ my $serializer = new IMPL::Serializer(
+ Formatter => new IMPL::Serialization::XmlFormatter(
+ IdentOutput => 1,
+ SkipWhitespace => 1
+ )
+ );
+ my $str = '';
+ open my $hFile,'>',\$str or die new IMPL::Exception("Failed to open stream",$!);
+
+ $serializer->Serialize($hFile, $this);
+
+ undef $hFile;
+
+ return $str;
+}
+
+sub save {
+ my ($this,$ctx) = @_;
+
+ foreach my $info ($this->get_meta('IMPL::Class::PropertyInfo')) {
+ next if $info->Access != IMPL::Class::Member::MOD_PUBLIC; # save only public properties
+
+ my $name = $info->Name;
+ $ctx->AddVar($name => $this->$name()) if $this->$name();
+ }
+}
+
+1;
+__END__
+
+=pod
+
+=h1 SYNOPSIS
+
+package App::Config
+use base qw(IMPL::Config)
+
+use IMPL::Class::Property;
+use IMPL::Config::Class;
+
+BEGIN {
+ public property SimpleString => prop_all;
+ public property MyClass => prop_all;
+}
+
+sub CTOR {
+ my $this = shift;
+ $this->superCTOR(@_);
+
+ $this->MyClass(new IMPL::Config::Class(Type => MyClass)) unless $this->MyClass;
+}
+
+=head1 DESCRIPTION
+
+Позволяет сохранить/загрузить конфигурацию. Также все классы конфигурации
+должны наследоваться от данного класса, и все Public свойства будут
+автоматически сохраняться и восстанавливаться.
+
+=head1 MEMBERS
+
+=over
+
+=item static LoadXMLFile($fileName)
+Создает из XML файла экземпляр приложения
+
+=item SaveXMLFile($fileName)
+Сохраняет приложение в файл
+
+=item xml
+Сохраняет конфигурацию приложения в XML строку
+
+=back
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/Config/Class.pm
--- a/Lib/IMPL/Config/Class.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/Config/Class.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,52 +1,52 @@
-package IMPL::Config::Class;
-use strict;
-use warnings;
-
-use base qw(IMPL::Config);
-use IMPL::Exception;
-use IMPL::Class::Property;
-
-BEGIN {
- public property Type => prop_all;
- public property Parameters => prop_all;
- public property IsSingleton => prop_all;
- private property _Instance => prop_all;
-}
-
-__PACKAGE__->PassThroughArgs;
-
-sub CTOR {
- my $this = shift;
-
- die new IMPL::Exception("A Type parameter is required") unless $this->Type;
-
-}
-
-sub _is_class {
- no strict 'refs';
- scalar keys %{"$_[0]::"} ? 1 : 0;
-}
-
-sub instance {
- my $this = shift;
-
- my $type = $this->Type;
-
- if ($this->IsSingleton) {
- if ($this->_Instance) {
- return $this->_Instance;
- } else {
- my %args = (%{$this->Parameters || {}},@_);
- eval "require $type" unless _is_class($type);
- my $inst = $type->new(%args);
- $this->_Instance($inst);
- return $inst;
- }
- } else {
- my %args = (%{$this->Parameters || {}},@_);
- eval "require $type" unless _is_class($type);
- return $type->new(%args);
- }
-}
-
-1;
+package IMPL::Config::Class;
+use strict;
+use warnings;
+
+use base qw(IMPL::Config);
+use IMPL::Exception;
+use IMPL::Class::Property;
+
+BEGIN {
+ public property Type => prop_all;
+ public property Parameters => prop_all;
+ public property IsSingleton => prop_all;
+ private property _Instance => prop_all;
+}
+
+__PACKAGE__->PassThroughArgs;
+
+sub CTOR {
+ my $this = shift;
+
+ die new IMPL::Exception("A Type parameter is required") unless $this->Type;
+
+}
+
+sub _is_class {
+ no strict 'refs';
+ scalar keys %{"$_[0]::"} ? 1 : 0;
+}
+
+sub instance {
+ my $this = shift;
+
+ my $type = $this->Type;
+
+ if ($this->IsSingleton) {
+ if ($this->_Instance) {
+ return $this->_Instance;
+ } else {
+ my %args = (%{$this->Parameters || {}},@_);
+ eval "require $type" unless _is_class($type);
+ my $inst = $type->new(%args);
+ $this->_Instance($inst);
+ return $inst;
+ }
+ } else {
+ my %args = (%{$this->Parameters || {}},@_);
+ eval "require $type" unless _is_class($type);
+ return $type->new(%args);
+ }
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/Config/Container.pm
--- a/Lib/IMPL/Config/Container.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/Config/Container.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,40 +1,40 @@
-package IMPL::Config::Container;
-use strict;
-use warnings;
-
-use base qw(IMPL::Config);
-use IMPL::Class::Property;
-
-BEGIN {
- public property Chidren => prop_all;
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->Chidren(\%args);
-}
-
-sub save {
- my ($this,$ctx) = @_;
-
- while (my ($key,$value) = each %{$this->Chidren}) {
- $ctx->AddVar($key,$value);
- }
-}
-
-our $AUTOLOAD;
-sub AUTOLOAD {
- my $this = shift;
-
- (my $prop = $AUTOLOAD) =~ s/.*?(\w+)$/$1/;
-
- my $child = $this->Chidren->{$prop};
- if (ref $child and $child->isa('IMPL::Config::Class')) {
- return $child->instance(@_);
- } else {
- return $child;
- }
-}
-
-1;
+package IMPL::Config::Container;
+use strict;
+use warnings;
+
+use base qw(IMPL::Config);
+use IMPL::Class::Property;
+
+BEGIN {
+ public property Chidren => prop_all;
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->Chidren(\%args);
+}
+
+sub save {
+ my ($this,$ctx) = @_;
+
+ while (my ($key,$value) = each %{$this->Chidren}) {
+ $ctx->AddVar($key,$value);
+ }
+}
+
+our $AUTOLOAD;
+sub AUTOLOAD {
+ my $this = shift;
+
+ (my $prop = $AUTOLOAD) =~ s/.*?(\w+)$/$1/;
+
+ my $child = $this->Chidren->{$prop};
+ if (ref $child and $child->isa('IMPL::Config::Class')) {
+ return $child->instance(@_);
+ } else {
+ return $child;
+ }
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Document.pm
--- a/Lib/IMPL/DOM/Document.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Document.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,51 +1,51 @@
-package IMPL::DOM::Document;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Node);
-
-__PACKAGE__->PassThroughArgs;
-
-sub document {
- return $_[0];
-}
-
-sub Create {
- my ($this,$nodeName,$class,$refProps) = @_;
-
- $refProps ||= {};
-
- delete $refProps->{nodeName};
-
- return $class->new(
- nodeName => $nodeName,
- document => $this,
- %$refProps
- );
-}
-
-{
- my $empty;
- sub Empty() {
- return $empty ? $empty : $empty = __PACKAGE__->new(nodeName => 'Empty');
- }
-}
-
-1;
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-=head1 METHODS
-
-=over
-
-=item C<<$doc->Create>>
-
-Создает узел определеннго типа с определенным именем и свойствами.
-
-=back
-
-=cut
\ No newline at end of file
+package IMPL::DOM::Document;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Node);
+
+__PACKAGE__->PassThroughArgs;
+
+sub document {
+ return $_[0];
+}
+
+sub Create {
+ my ($this,$nodeName,$class,$refProps) = @_;
+
+ $refProps ||= {};
+
+ delete $refProps->{nodeName};
+
+ return $class->new(
+ nodeName => $nodeName,
+ document => $this,
+ %$refProps
+ );
+}
+
+{
+ my $empty;
+ sub Empty() {
+ return $empty ? $empty : $empty = __PACKAGE__->new(nodeName => 'Empty');
+ }
+}
+
+1;
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+=head1 METHODS
+
+=over
+
+=item C<<$doc->Create>>
+
+Создает узел определеннго типа с определенным именем и свойствами.
+
+=back
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Navigator.pm
--- a/Lib/IMPL/DOM/Navigator.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Navigator.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,274 +1,274 @@
-package IMPL::DOM::Navigator;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-BEGIN {
- private _direct property _path => prop_all;
- private _direct property _state => prop_all;
- private _direct property _savedstates => prop_all;
- public property Current => {get => \&_getCurrent};
-}
-
-sub CTOR {
- my ($this,$CurrentNode) = @_;
-
- die IMPL::InvalidArgumentException("A starting node is a required paramater") unless $CurrentNode;
-
- $this->{$_state} = { alternatives => [ $CurrentNode ], current => 0 };
-}
-
-sub _initNavigator {
- my ($this,$CurrentNode) = @_;
-
- die IMPL::InvalidArgumentException("A starting node is a required paramater") unless $CurrentNode;
-
- $this->{$_state} = { alternatives => [ $CurrentNode ], current => 0 };
- delete $this->{$_path};
- delete $this->{$_savedstates};
-}
-
-sub _getCurrent {
- $_[0]->{$_state}{alternatives}[$_[0]->{$_state}{current}]
-}
-
-sub Navigate {
- my ($this,@path) = @_;
-
- return unless @path;
-
- my $node;
-
- foreach my $query (@path) {
- if (my $current = $this->Current) {
-
- my @alternatives = $current->selectNodes($query);
-
- unless (@alternatives) {
- $current = $this->advanceNavigator or return undef;
- @alternatives = $current->selectNodes($query);
- }
-
- push @{$this->{$_path}},$this->{$_state};
- $this->{$_state} = {
- alternatives => \@alternatives,
- current => 0,
- query => $query
- };
-
- $node = $alternatives[0];
- } else {
- return undef;
- }
- }
-
- $node;
-}
-
-sub selectNodes {
- my ($this,@path) = @_;
-
- return internalSelectNodes($this->Current,@path);
-}
-
-sub internalSelectNodes {
- my $node = shift;
- my $query = shift;
-
- if (@_) {
- return map internalSelectNodes($_,@_), $node->selectNodes($query);
- } else {
- return $node->selectNodes($query);
- }
-}
-
-sub internalNavigateNodeSet {
- my ($this,@nodeSet) = @_;
-
- push @{$this->{$_path}}, $this->{$_state};
-
- $this->{$_state} = {
- alternatives => \@nodeSet,
- current => 0
- };
-
- $nodeSet[0];
-}
-
-sub fetch {
- my ($this) = @_;
-
- my $result = $this->Current;
- $this->advanceNavigator;
- return $result;
-}
-
-sub advanceNavigator {
- my ($this) = @_;
-
- $this->{$_state}{current}++;
-
- if (@{$this->{$_state}{alternatives}} <= $this->{$_state}{current}) {
- if ( exists $this->{$_state}{query} ) {
- my $query = $this->{$_state}{query};
-
- $this->Back or return undef; # that meams the end of the history
-
- undef while ( $this->advanceNavigator and not $this->Navigate($query));
-
- return $this->Current;
- }
- return undef;
- }
-
- return $this->Current;
-}
-
-sub doeach {
- my ($this,$code) = @_;
- local $_;
-
- do {
- for (my $i = $this->{$_state}{current}; $i < @{$this->{$_state}{alternatives}}; $i++) {
- $_ = $this->{$_state}{alternatives}[$i];
- $code->();
- }
- $this->{$_state}{current} = @{$this->{$_state}{alternatives}};
- } while ($this->advanceNavigator);
-}
-
-sub Back {
- my ($this,$steps) = @_;
- if ($this->{$_path} and @{$this->{$_path}}) {
- if ( (not $steps) || $steps == 1) {
- $this->{$_state} = pop @{$this->{$_path}};
- } else {
- $steps ||= 1;
-
- $steps = @{$this->{$_path}} - 1 if $steps >= @{$this->{$_path}};
-
- $this->{$_state} = (splice @{$this->{$_path}},-$steps)[0];
- }
- $this->Current if defined wantarray;
- } else {
- return undef;
- }
-}
-
-sub PathToString {
- my ($this,$delim) = @_;
-
- $delim ||= '/';
-
- join($delim,map $_->{alternatives}[$_->{current}]->nodeName, $this->{$_path} ? (@{$this->{$_path}}, $this->{$_state}) : $this->{$_state});
-}
-
-sub clone {
- my ($this) = @_;
-
- my $newNavi = __PACKAGE__->surrogate;
-
- $newNavi->{$_path} = [ map { { %{ $_ } } } @{$this->{$_path}} ] if $this->{$_path};
- $newNavi->{$_state} = { %{$this->{$_state}} };
-
- return $newNavi;
-
-}
-
-sub saveState {
- my ($this) = @_;
-
- my %state;
-
- $state{path} = [ map { { %{ $_ } } } @{$this->{$_path}} ] if $this->{$_path};
- $state{state} = { %{$this->{$_state}} };
-
- push @{$this->{$_savedstates}}, \%state;
-}
-
-sub restoreState {
- my ($this) = @_;
-
- if ( my $state = pop @{$this->{$_savedstates}||[]} ) {
- $this->{$_path} = $state->{path};
- $this->{$_state} = $state->{state};
- }
-}
-
-sub applyState {
- my ($this) = @_;
-
- pop @{$this->{$_savedstates}||[]};
-}
-
-sub dosafe {
- my ($this,$transaction) = @_;
-
- $this->saveState();
-
- my $result;
-
- eval {
- $result = $transaction->();
- };
-
- if ($@) {
- $this->restoreState();
- return undef;
- } else {
- $this->applyState();
- return $result;
- }
-}
-
-1;
-
-__END__
-=pod
-
-=head1 DESCRIPTION
-
-Объект для хождения по дереву DOM объектов.
-
-Результатом навигации является множество узлов (альтернатив).
-
-Состоянием навигатора является текущий набор узлов, позиция в данном наборе,
-а также запрос по которому были получены данные результаты.
-
-Если при навигации указан путь сосящий из нескольких фильтров, то он разбивается
-этапы простой навигации по кадой из частей пути. На каждом элементарном этапе
-навигации образуется ряд альтернатив, и при каждом следующем этапе навигации
-альтернативы предыдущих этапов могут перебираться, до получения положительного
-результата навигации, в противном случае навигация считается невозможной.
-
-=head1 METHODS
-
-=over
-
-=item C<<$obj->new($nodeStart)>>
-
-Создает объект навигатора с указанной начальной позицией.
-
-=item C<<$obj->Navigate([$query,...])>>
-
-Перейти в новый узел используя запрос C<$query>. На данный момент запросом может
-быть только имя узла и будет взят только первый узел. Если по запросу ничего не
-найдено, переход не будет осуществлен.
-
-Возвращает либо новый узел в который перешли, либо C.
-
-=item C<<$obj->Back()>>
-
-Возвращается в предыдущий узел, если таковой есть.
-
-Возвращает либо узел в который перешли, либо C.
-
-=item C<<$obj->advanceNavigator()>>
-
-Переходит в следующую альтернативу, соответствующую текущему запросу.
-
-=back
-
-=cut
\ No newline at end of file
+package IMPL::DOM::Navigator;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+BEGIN {
+ private _direct property _path => prop_all;
+ private _direct property _state => prop_all;
+ private _direct property _savedstates => prop_all;
+ public property Current => {get => \&_getCurrent};
+}
+
+sub CTOR {
+ my ($this,$CurrentNode) = @_;
+
+ die IMPL::InvalidArgumentException("A starting node is a required paramater") unless $CurrentNode;
+
+ $this->{$_state} = { alternatives => [ $CurrentNode ], current => 0 };
+}
+
+sub _initNavigator {
+ my ($this,$CurrentNode) = @_;
+
+ die IMPL::InvalidArgumentException("A starting node is a required paramater") unless $CurrentNode;
+
+ $this->{$_state} = { alternatives => [ $CurrentNode ], current => 0 };
+ delete $this->{$_path};
+ delete $this->{$_savedstates};
+}
+
+sub _getCurrent {
+ $_[0]->{$_state}{alternatives}[$_[0]->{$_state}{current}]
+}
+
+sub Navigate {
+ my ($this,@path) = @_;
+
+ return unless @path;
+
+ my $node;
+
+ foreach my $query (@path) {
+ if (my $current = $this->Current) {
+
+ my @alternatives = $current->selectNodes($query);
+
+ unless (@alternatives) {
+ $current = $this->advanceNavigator or return undef;
+ @alternatives = $current->selectNodes($query);
+ }
+
+ push @{$this->{$_path}},$this->{$_state};
+ $this->{$_state} = {
+ alternatives => \@alternatives,
+ current => 0,
+ query => $query
+ };
+
+ $node = $alternatives[0];
+ } else {
+ return undef;
+ }
+ }
+
+ $node;
+}
+
+sub selectNodes {
+ my ($this,@path) = @_;
+
+ return internalSelectNodes($this->Current,@path);
+}
+
+sub internalSelectNodes {
+ my $node = shift;
+ my $query = shift;
+
+ if (@_) {
+ return map internalSelectNodes($_,@_), $node->selectNodes($query);
+ } else {
+ return $node->selectNodes($query);
+ }
+}
+
+sub internalNavigateNodeSet {
+ my ($this,@nodeSet) = @_;
+
+ push @{$this->{$_path}}, $this->{$_state};
+
+ $this->{$_state} = {
+ alternatives => \@nodeSet,
+ current => 0
+ };
+
+ $nodeSet[0];
+}
+
+sub fetch {
+ my ($this) = @_;
+
+ my $result = $this->Current;
+ $this->advanceNavigator;
+ return $result;
+}
+
+sub advanceNavigator {
+ my ($this) = @_;
+
+ $this->{$_state}{current}++;
+
+ if (@{$this->{$_state}{alternatives}} <= $this->{$_state}{current}) {
+ if ( exists $this->{$_state}{query} ) {
+ my $query = $this->{$_state}{query};
+
+ $this->Back or return undef; # that meams the end of the history
+
+ undef while ( $this->advanceNavigator and not $this->Navigate($query));
+
+ return $this->Current;
+ }
+ return undef;
+ }
+
+ return $this->Current;
+}
+
+sub doeach {
+ my ($this,$code) = @_;
+ local $_;
+
+ do {
+ for (my $i = $this->{$_state}{current}; $i < @{$this->{$_state}{alternatives}}; $i++) {
+ $_ = $this->{$_state}{alternatives}[$i];
+ $code->();
+ }
+ $this->{$_state}{current} = @{$this->{$_state}{alternatives}};
+ } while ($this->advanceNavigator);
+}
+
+sub Back {
+ my ($this,$steps) = @_;
+ if ($this->{$_path} and @{$this->{$_path}}) {
+ if ( (not $steps) || $steps == 1) {
+ $this->{$_state} = pop @{$this->{$_path}};
+ } else {
+ $steps ||= 1;
+
+ $steps = @{$this->{$_path}} - 1 if $steps >= @{$this->{$_path}};
+
+ $this->{$_state} = (splice @{$this->{$_path}},-$steps)[0];
+ }
+ $this->Current if defined wantarray;
+ } else {
+ return undef;
+ }
+}
+
+sub PathToString {
+ my ($this,$delim) = @_;
+
+ $delim ||= '/';
+
+ join($delim,map $_->{alternatives}[$_->{current}]->nodeName, $this->{$_path} ? (@{$this->{$_path}}, $this->{$_state}) : $this->{$_state});
+}
+
+sub clone {
+ my ($this) = @_;
+
+ my $newNavi = __PACKAGE__->surrogate;
+
+ $newNavi->{$_path} = [ map { { %{ $_ } } } @{$this->{$_path}} ] if $this->{$_path};
+ $newNavi->{$_state} = { %{$this->{$_state}} };
+
+ return $newNavi;
+
+}
+
+sub saveState {
+ my ($this) = @_;
+
+ my %state;
+
+ $state{path} = [ map { { %{ $_ } } } @{$this->{$_path}} ] if $this->{$_path};
+ $state{state} = { %{$this->{$_state}} };
+
+ push @{$this->{$_savedstates}}, \%state;
+}
+
+sub restoreState {
+ my ($this) = @_;
+
+ if ( my $state = pop @{$this->{$_savedstates}||[]} ) {
+ $this->{$_path} = $state->{path};
+ $this->{$_state} = $state->{state};
+ }
+}
+
+sub applyState {
+ my ($this) = @_;
+
+ pop @{$this->{$_savedstates}||[]};
+}
+
+sub dosafe {
+ my ($this,$transaction) = @_;
+
+ $this->saveState();
+
+ my $result;
+
+ eval {
+ $result = $transaction->();
+ };
+
+ if ($@) {
+ $this->restoreState();
+ return undef;
+ } else {
+ $this->applyState();
+ return $result;
+ }
+}
+
+1;
+
+__END__
+=pod
+
+=head1 DESCRIPTION
+
+Объект для хождения по дереву DOM объектов.
+
+Результатом навигации является множество узлов (альтернатив).
+
+Состоянием навигатора является текущий набор узлов, позиция в данном наборе,
+а также запрос по которому были получены данные результаты.
+
+Если при навигации указан путь сосящий из нескольких фильтров, то он разбивается
+этапы простой навигации по кадой из частей пути. На каждом элементарном этапе
+навигации образуется ряд альтернатив, и при каждом следующем этапе навигации
+альтернативы предыдущих этапов могут перебираться, до получения положительного
+результата навигации, в противном случае навигация считается невозможной.
+
+=head1 METHODS
+
+=over
+
+=item C<<$obj->new($nodeStart)>>
+
+Создает объект навигатора с указанной начальной позицией.
+
+=item C<<$obj->Navigate([$query,...])>>
+
+Перейти в новый узел используя запрос C<$query>. На данный момент запросом может
+быть только имя узла и будет взят только первый узел. Если по запросу ничего не
+найдено, переход не будет осуществлен.
+
+Возвращает либо новый узел в который перешли, либо C.
+
+=item C<<$obj->Back()>>
+
+Возвращается в предыдущий узел, если таковой есть.
+
+Возвращает либо узел в который перешли, либо C.
+
+=item C<<$obj->advanceNavigator()>>
+
+Переходит в следующую альтернативу, соответствующую текущему запросу.
+
+=back
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Navigator/Builder.pm
--- a/Lib/IMPL/DOM/Navigator/Builder.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Navigator/Builder.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,97 +1,97 @@
-package IMPL::DOM::Navigator::Builder;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-require IMPL::DOM::Navigator::SchemaNavigator;
-
-BEGIN {
- private _direct property _schemaNavi => prop_all;
- private _direct property _nodesPath => prop_all;
- private _direct property _nodeCurrent => prop_all;
- private _direct property _docClass => prop_all
- public _direct property Document => prop_get | owner_set;
-}
-
-sub CTOR {
- my ($this,$docClass,$schema) = @_;
-
- $this->{$_docClass} = $docClass;
- $this->{$_schemaNavi} = $schema ? IMPL::DOM::Navigator::SchemaNavigator->new($schema) : undef;
-}
-
-sub NavigateCreate {
- my ($this,$nodeName,%props) = @_;
-
- if (my $schemaNode = $this->{$_schemaNavi}->NavigateName($nodeName)) {
- my $class = $schemaNode->can('nativeType') ? $schemaNode->nativeType : 'IMPL::DOM::Node';
-
- my $node;
- if (! $this->{$Document}) {
- $node = $this->{$Document} = $this->{$_docClass}->new(nodeName => $nodeName,%props);
- } else {
- die new IMPL::InvalidOperationException('Can\t create a second top level element') unless $this->{$_nodeCurrent};
- $node = $this->{$Document}->Create($nodeName,$class,\%props);
- push @{$this->{$_nodesPath}}, $this->{$_nodeCurrent};
- $this->{$_nodeCurrent}->appendChild($node);
- }
-
- $this->{$_nodeCurrent} = $node;
-
- return $node;
- } else {
- die new IMPL::InvalidOperationException("The specified node is undefined", $nodeName);
- }
-}
-
-sub Back {
- my ($this) = @_;
-
- $this->{$_schemaNavi}->SchemaBack();
- $this->{$_nodeCurrent} = pop @{$this->{$_nodesPath}};
-}
-
-1;
-
-__END__
-=pod
-
-=head1 SYNOPSIS
-
-my $builder = new IMPL::DOM::Navigator::Builder(new MyApp::Document,$schema);
-my $reader = new IMPL::DOM::XMLReader(Navigator => $builder);
-
-$reader->ParseFile("document.xml");
-
-my @errors = $schema->Validate($builder->Document);
-
-=head1 DESCRIPTION
-
-Построитель DOM документов по указанной схеме. Обычно используется в связке
-с объектами для чтения такими как C.
-
-=head1 METHODS
-
-=over
-
-=item C
-
-Создает новый объект, принимает на вход пустой (но не обязательно) документ и
-схему.
-
-=item C<< $obj->NavigateCreate($nodeName) >>
-
-Создает новый узел с указанным именем и переходит в него. В случае если в схеме
-подходящий узел не найден, то вызывается исключение.
-
-При этом по имени узла ищется его схема, после чего определяется класс для
-создания экземпляра и созданный узел доавляется в документ.
-
-Также имя создаваемого узла НЕ может быть переопределено свойством nodeName, оно
-будет проигнорировано.
-
-=back
-
-=cut
\ No newline at end of file
+package IMPL::DOM::Navigator::Builder;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+require IMPL::DOM::Navigator::SchemaNavigator;
+
+BEGIN {
+ private _direct property _schemaNavi => prop_all;
+ private _direct property _nodesPath => prop_all;
+ private _direct property _nodeCurrent => prop_all;
+ private _direct property _docClass => prop_all
+ public _direct property Document => prop_get | owner_set;
+}
+
+sub CTOR {
+ my ($this,$docClass,$schema) = @_;
+
+ $this->{$_docClass} = $docClass;
+ $this->{$_schemaNavi} = $schema ? IMPL::DOM::Navigator::SchemaNavigator->new($schema) : undef;
+}
+
+sub NavigateCreate {
+ my ($this,$nodeName,%props) = @_;
+
+ if (my $schemaNode = $this->{$_schemaNavi}->NavigateName($nodeName)) {
+ my $class = $schemaNode->can('nativeType') ? $schemaNode->nativeType : 'IMPL::DOM::Node';
+
+ my $node;
+ if (! $this->{$Document}) {
+ $node = $this->{$Document} = $this->{$_docClass}->new(nodeName => $nodeName,%props);
+ } else {
+ die new IMPL::InvalidOperationException('Can\t create a second top level element') unless $this->{$_nodeCurrent};
+ $node = $this->{$Document}->Create($nodeName,$class,\%props);
+ push @{$this->{$_nodesPath}}, $this->{$_nodeCurrent};
+ $this->{$_nodeCurrent}->appendChild($node);
+ }
+
+ $this->{$_nodeCurrent} = $node;
+
+ return $node;
+ } else {
+ die new IMPL::InvalidOperationException("The specified node is undefined", $nodeName);
+ }
+}
+
+sub Back {
+ my ($this) = @_;
+
+ $this->{$_schemaNavi}->SchemaBack();
+ $this->{$_nodeCurrent} = pop @{$this->{$_nodesPath}};
+}
+
+1;
+
+__END__
+=pod
+
+=head1 SYNOPSIS
+
+my $builder = new IMPL::DOM::Navigator::Builder(new MyApp::Document,$schema);
+my $reader = new IMPL::DOM::XMLReader(Navigator => $builder);
+
+$reader->ParseFile("document.xml");
+
+my @errors = $schema->Validate($builder->Document);
+
+=head1 DESCRIPTION
+
+Построитель DOM документов по указанной схеме. Обычно используется в связке
+с объектами для чтения такими как C.
+
+=head1 METHODS
+
+=over
+
+=item C
+
+Создает новый объект, принимает на вход пустой (но не обязательно) документ и
+схему.
+
+=item C<< $obj->NavigateCreate($nodeName) >>
+
+Создает новый узел с указанным именем и переходит в него. В случае если в схеме
+подходящий узел не найден, то вызывается исключение.
+
+При этом по имени узла ищется его схема, после чего определяется класс для
+создания экземпляра и созданный узел доавляется в документ.
+
+Также имя создаваемого узла НЕ может быть переопределено свойством nodeName, оно
+будет проигнорировано.
+
+=back
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Navigator/SchemaNavigator.pm
--- a/Lib/IMPL/DOM/Navigator/SchemaNavigator.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Navigator/SchemaNavigator.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,124 +1,124 @@
-package IMPL::DOM::Navigator::SchemaNavigator;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Navigator);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-
-require IMPL::DOM::Schema::ComplexType;
-require IMPL::DOM::Schema::NodeSet;
-require IMPL::DOM::Schema::AnyNode;
-
-__PACKAGE__->PassThroughArgs;
-
-BEGIN {
- public _direct property Schema => prop_get;
- private _direct property _historySteps => prop_all;
-}
-
-sub CTOR {
- my ($this,$schema) = @_;
-
- $this->{$Schema} = $schema;
-
- die new IMPL::InvalidArgumentException("A schema object is required") unless $schema->isa('IMPL::DOM::Schema');
-}
-
-my $schemaAnyNode = IMPL::DOM::Schema::ComplexType->new(type => '::AnyNodeType', nativeType => 'IMPL::DOM::ComplexNode')->appendRange(
- IMPL::DOM::Schema::NodeSet->new()->appendRange(
- IMPL::DOM::Schema::AnyNode->new()
- )
-);
-
-sub NavigateName {
- my ($this,$name) = @_;
-
- die new IMPL::InvalidArgumentException('name is required') unless defined $name;
-
- # perform a safe navigation
- #return dosafe $this sub {
- my $steps = 1;
- # navigate to node
- if (
- my $node = $this->Navigate( sub {
- $_->isa('IMPL::DOM::Schema::Node') and (
- $_->name eq $name
- or
- $_->nodeName eq 'AnyNode'
- or
- ( $_->nodeName eq 'SwitchNode' and $_->selectNodes( sub { $_->name eq $name } ) )
- )
- })
- ) {
- if ($node->nodeName eq 'AnyNode') {
- # if we navigate to the anynode
- # assume it to be ComplexType by default
- $node = $node->type ? $this->{$Schema}->resolveType($node->type) : $schemaAnyNode;
- } elsif ($node->nodeName eq 'SwitchNode') {
- # if we are in the switchnode
- # navigate to the target node
- $node = $this->Navigate(sub { $_->name eq $name });
- $steps ++;
- }
-
- if ($node->nodeName eq 'Node') {
- # if we navigate to a reference
- # resolve it
- $node = $this->{$Schema}->resolveType($node->type);
- $this->internalNavigateNodeSet($node);
- $steps++;
- }
-
- # if target node is a complex node
- if ($node->isa('IMPL::DOM::Schema::ComplexNode')) {
- # navigate to it's content
- $this->internalNavigateNodeSet($node->content);
- $steps ++;
- }
-
- push @{$this->{$_historySteps}},$steps;
-
- # return found node schema
- return $node;
- } else {
- return undef; # abort navigation
- }
- #}
-}
-
-sub SchemaBack {
- my ($this) = @_;
-
- $this->Back(pop @{$this->{$_historySteps}}) if $this->{$_historySteps};
-}
-
-1;
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-Помимо стандартных методов навигации позволяет переходить по элементам документа,
-который данной схемой описывается.
-
-=head1 METHODS
-
-=over
-
-=item C<< $navi->NavigateName($name) >>
-
-Переходит на схему узла с указанным именем. Тоесть использует свойство C.
-В данном случае всегда происходит безопасная навигация, тоесть в случае неудачи,
-навигатор останется на прежней позиции.
-
-=item C<< $navi->SchemaBack >>
-
-Возвращается на позицию до последней операции C. Данный метод нужен
-посокольку операция навигации по элементам описываемым схемой может приводить к
-нескольким операциям навигации по самой схеме.
-
-=back
-
-=cut
\ No newline at end of file
+package IMPL::DOM::Navigator::SchemaNavigator;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Navigator);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+
+require IMPL::DOM::Schema::ComplexType;
+require IMPL::DOM::Schema::NodeSet;
+require IMPL::DOM::Schema::AnyNode;
+
+__PACKAGE__->PassThroughArgs;
+
+BEGIN {
+ public _direct property Schema => prop_get;
+ private _direct property _historySteps => prop_all;
+}
+
+sub CTOR {
+ my ($this,$schema) = @_;
+
+ $this->{$Schema} = $schema;
+
+ die new IMPL::InvalidArgumentException("A schema object is required") unless $schema->isa('IMPL::DOM::Schema');
+}
+
+my $schemaAnyNode = IMPL::DOM::Schema::ComplexType->new(type => '::AnyNodeType', nativeType => 'IMPL::DOM::ComplexNode')->appendRange(
+ IMPL::DOM::Schema::NodeSet->new()->appendRange(
+ IMPL::DOM::Schema::AnyNode->new()
+ )
+);
+
+sub NavigateName {
+ my ($this,$name) = @_;
+
+ die new IMPL::InvalidArgumentException('name is required') unless defined $name;
+
+ # perform a safe navigation
+ #return dosafe $this sub {
+ my $steps = 1;
+ # navigate to node
+ if (
+ my $node = $this->Navigate( sub {
+ $_->isa('IMPL::DOM::Schema::Node') and (
+ $_->name eq $name
+ or
+ $_->nodeName eq 'AnyNode'
+ or
+ ( $_->nodeName eq 'SwitchNode' and $_->selectNodes( sub { $_->name eq $name } ) )
+ )
+ })
+ ) {
+ if ($node->nodeName eq 'AnyNode') {
+ # if we navigate to the anynode
+ # assume it to be ComplexType by default
+ $node = $node->type ? $this->{$Schema}->resolveType($node->type) : $schemaAnyNode;
+ } elsif ($node->nodeName eq 'SwitchNode') {
+ # if we are in the switchnode
+ # navigate to the target node
+ $node = $this->Navigate(sub { $_->name eq $name });
+ $steps ++;
+ }
+
+ if ($node->nodeName eq 'Node') {
+ # if we navigate to a reference
+ # resolve it
+ $node = $this->{$Schema}->resolveType($node->type);
+ $this->internalNavigateNodeSet($node);
+ $steps++;
+ }
+
+ # if target node is a complex node
+ if ($node->isa('IMPL::DOM::Schema::ComplexNode')) {
+ # navigate to it's content
+ $this->internalNavigateNodeSet($node->content);
+ $steps ++;
+ }
+
+ push @{$this->{$_historySteps}},$steps;
+
+ # return found node schema
+ return $node;
+ } else {
+ return undef; # abort navigation
+ }
+ #}
+}
+
+sub SchemaBack {
+ my ($this) = @_;
+
+ $this->Back(pop @{$this->{$_historySteps}}) if $this->{$_historySteps};
+}
+
+1;
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Помимо стандартных методов навигации позволяет переходить по элементам документа,
+который данной схемой описывается.
+
+=head1 METHODS
+
+=over
+
+=item C<< $navi->NavigateName($name) >>
+
+Переходит на схему узла с указанным именем. Тоесть использует свойство C.
+В данном случае всегда происходит безопасная навигация, тоесть в случае неудачи,
+навигатор останется на прежней позиции.
+
+=item C<< $navi->SchemaBack >>
+
+Возвращается на позицию до последней операции C. Данный метод нужен
+посокольку операция навигации по элементам описываемым схемой может приводить к
+нескольким операциям навигации по самой схеме.
+
+=back
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Navigator/SimpleBuilder.pm
--- a/Lib/IMPL/DOM/Navigator/SimpleBuilder.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Navigator/SimpleBuilder.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,37 +1,37 @@
-package IMPL::DOM::Navigator::SimpleBuilder;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Navigator);
-
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-
-require IMPL::DOM::Navigator::SchemaNavigator;
-use IMPL::DOM::Document;
-
-BEGIN {
- public _direct property Document => prop_get | owner_set;
-}
-
-our %CTOR = (
- 'IMPL::DOM::Navigator' => sub { IMPL::DOM::Document::Empty; }
-);
-
-sub NavigateCreate {
- my ($this,$nodeName,%props) = @_;
-
- my $node;
- if (! $this->{$Document}) {
- $node = $this->{$Document} = IMPL::DOM::Document->new(nodeName => $nodeName,%props);
- $this->_initNavigator($node);
- } else {
- die new IMPL::InvalidOperationException('Can\t create a second top level element') unless $this->Current;
- $node = $this->{$Document}->Create($nodeName,'IMPL::DOM::Node',\%props);
- $this->Current->appendChild($node);
- $this->internalNavigateNodeSet($node);
- }
- return $node;
-}
-
-1;
+package IMPL::DOM::Navigator::SimpleBuilder;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Navigator);
+
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+
+require IMPL::DOM::Navigator::SchemaNavigator;
+use IMPL::DOM::Document;
+
+BEGIN {
+ public _direct property Document => prop_get | owner_set;
+}
+
+our %CTOR = (
+ 'IMPL::DOM::Navigator' => sub { IMPL::DOM::Document::Empty; }
+);
+
+sub NavigateCreate {
+ my ($this,$nodeName,%props) = @_;
+
+ my $node;
+ if (! $this->{$Document}) {
+ $node = $this->{$Document} = IMPL::DOM::Document->new(nodeName => $nodeName,%props);
+ $this->_initNavigator($node);
+ } else {
+ die new IMPL::InvalidOperationException('Can\t create a second top level element') unless $this->Current;
+ $node = $this->{$Document}->Create($nodeName,'IMPL::DOM::Node',\%props);
+ $this->Current->appendChild($node);
+ $this->internalNavigateNodeSet($node);
+ }
+ return $node;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Node.pm
--- a/Lib/IMPL/DOM/Node.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Node.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,275 +1,275 @@
-package IMPL::DOM::Node;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object);
-
-use IMPL::Object::List;
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-use Scalar::Util qw(weaken);
-
-use IMPL::Exception;
-
-BEGIN {
- public _direct property nodeName => prop_get;
- public _direct property document => prop_get;
- public _direct property isComplex => { get => \&_getIsComplex } ;
- public _direct property nodeValue => prop_all;
- public _direct property childNodes => { get => \&_getChildNodes };
- public _direct property parentNode => prop_get ;
- private _direct property _propertyMap => prop_all ;
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$nodeName} = delete $args{nodeName} or die new IMPL::InvalidArgumentException("A name is required");
- $this->{$nodeValue} = delete $args{nodeValue} if exists $args{nodeValue};
- if ( exists $args{document} ) {
- $this->{$document} = delete $args{document};
- weaken($this->{$document});
- }
-
- $this->{$_propertyMap} = \%args;
-}
-
-sub insertNode {
- my ($this,$node,$pos) = @_;
-
- die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node;
-
- $node->{$parentNode}->removeNode($node) if ($node->{$parentNode});
-
- $this->childNodes->InsertAt($pos,$node);
-
- $node->_setParent( $this );
-
- return $node;
-}
-
-sub appendChild {
- my ($this,$node) = @_;
-
- die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node;
-
- $node->{$parentNode}->removeNode($node) if ($node->{$parentNode});
-
- my $children = $this->childNodes;
- $children->Append($node);
-
- $node->_setParent( $this );
-
- return $node;
-}
-
-sub appendNode {
- goto &appendChild;
-}
-
-sub appendRange {
- my ($this,@range) = @_;
-
- die new IMPL::InvalidOperationException("You can't insert the node to itselft") if grep $_ == $this, @range;
-
- foreach my $node (@range) {
- $node->{$parentNode}->removeNode($node) if ($node->{$parentNode});
- $node->_setParent( $this );
- }
-
- $this->childNodes->Append(@range);
-
- return $this;
-}
-
-sub _getChildNodes {
- my ($this) = @_;
-
- $this->{$childNodes} = new IMPL::Object::List() unless $this->{$childNodes};
- return $this->{$childNodes};
-}
-
-sub removeNode {
- my ($this,$node) = @_;
-
- if ($this == $node->{$parentNode}) {
- $this->childNodes->RemoveItem($node);
- $node->_setParent(undef);
- return $node;
- } else {
- die new IMPL::InvalidOperationException("The specified node isn't belong to this node");
- }
-}
-
-sub replaceNodeAt {
- my ($this,$index,$node) = @_;
-
- my $nodeOld = $this->childNodes->[$index];
-
- die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node;
-
- # unlink node from previous parent
- $node->{$parentNode}->removeNode($node) if ($node->{$parentNode});
-
- # replace (or set) old node
- $this->childNodes->[$index] = $node;
-
- # set new parent
- $node->_setParent( $this );
-
- # unlink old node if we have one
- $nodeOld->_setParent(undef) if $nodeOld;
-
- # return old node
- return $nodeOld;
-}
-
-sub removeAt {
- my ($this,$pos) = @_;
-
- if ( my $node = $this->childNodes->RemoveAt($pos) ) {
- $node->_setParent(undef);
- return $node;
- } else {
- return undef;
- }
-}
-
-sub removeLast {
- my ($this) = @_;
-
- if ( my $node = $this->{$childNodes} ? $this->{$childNodes}->RemoveLast() : undef) {
- $node->_setParent(undef);
- return $node;
- } else {
- return undef;
- }
-}
-
-sub removeSelected {
- my ($this,$query) = @_;
-
- my @newSet;
- my @result;
-
- if (ref $query eq 'CODE') {
- &$query($_) ? push @result, $_ : push @newSet, $_ foreach @{$this->childNodes};
- } elsif (defined $query) {
- $_->nodeName eq $query ? push @result, $_ : push @newSet, $_ foreach @{$this->childNodes};
- } else {
- my $children = $this->childNodes;
- $_->_setParent(undef) foreach @$children;
- delete $this->{$childNodes};
- return wantarray ? @$children : $children;
- }
-
- $_->_setParent(undef) foreach @result;
-
- $this->{$childNodes} = @newSet ? bless \@newSet ,'IMPL::Object::List' : undef;
-
- return wantarray ? @result : \@result;
-}
-
-sub selectNodes {
- my ($this,$query) = @_;
-
- my @result;
-
- if (ref $query eq 'CODE') {
- @result = grep &$query($_), @{$this->childNodes};
- } elsif (ref $query eq 'ARRAY' ) {
- my %keys = map (($_,1),@$query);
- @result = grep $keys{$_->nodeName}, @{$this->childNodes};
- } elsif (defined $query) {
- @result = grep $_->nodeName eq $query, @{$this->childNodes};
- } else {
- if (wantarray) {
- return @{$this->childNodes};
- } else {
- @result = $this->childNodes;
- return \@result;
- }
- }
-
- return wantarray ? @result : \@result;
-}
-
-sub firstChild {
- @_ >=2 ? $_[0]->replaceNodeAt(0,$_[1]) : $_[0]->childNodes->[0];
-}
-
-sub _getIsComplex {
- $_[0]->childNodes->Count ? 1 : 0;
-}
-
-sub _updateDocRefs {
- my ($this) = @_;
-
- # this method is called by the parent node on his children, so we need no to check parent
- $this->{$document} = $this->{$parentNode}->document;
-
- # prevent cyclic
- weaken($this->{$document}) if $this->{$document};
-
- $_->_updateDocRefs foreach @{$this->{$childNodes}};
-}
-
-sub _setParent {
- my ($this,$node) = @_;
-
-
- if (($node || 0) != ($this->{$parentNode} || 0)) {
- my $newOwner;
- if ($node) {
- $this->{$parentNode} = $node;
- $newOwner = $node->document || 0;
-
- # prevent from creating cyclicreferences
- weaken($this->{$parentNode});
-
- } else {
- delete $this->{$parentNode};
- $newOwner = 0;
- }
-
- if (($this->{$document}||0) != $newOwner) {
- $this->{$document} = $newOwner;
- weaken($this->{$document}) if $newOwner;
- $_->_updateDocRefs foreach @{$this->childNodes};
- }
- }
-}
-
-sub text {
- my ($this) = @_;
-
- join ('', $this->nodeValue || '', map ($_->text || '', @{$this->childNodes}));
-}
-
-sub nodeProperty {
- my $this = shift;
- my $name = shift;
-
- if (@_) {
- # set
- return $this->{$_propertyMap}{$name} = shift;
- } else {
- return $this->{$_propertyMap}{$name};
- }
-}
-
-sub qname {
- $_[0]->{$nodeName};
-}
-
-sub path {
- my ($this) = @_;
-
- if ($this->parentNode) {
- return $this->parentNode->path.'.'.$this->qname;
- } else {
- return $this->qname;
- }
-}
-
-1;
+package IMPL::DOM::Node;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object);
+
+use IMPL::Object::List;
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+use Scalar::Util qw(weaken);
+
+use IMPL::Exception;
+
+BEGIN {
+ public _direct property nodeName => prop_get;
+ public _direct property document => prop_get;
+ public _direct property isComplex => { get => \&_getIsComplex } ;
+ public _direct property nodeValue => prop_all;
+ public _direct property childNodes => { get => \&_getChildNodes };
+ public _direct property parentNode => prop_get ;
+ private _direct property _propertyMap => prop_all ;
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$nodeName} = delete $args{nodeName} or die new IMPL::InvalidArgumentException("A name is required");
+ $this->{$nodeValue} = delete $args{nodeValue} if exists $args{nodeValue};
+ if ( exists $args{document} ) {
+ $this->{$document} = delete $args{document};
+ weaken($this->{$document});
+ }
+
+ $this->{$_propertyMap} = \%args;
+}
+
+sub insertNode {
+ my ($this,$node,$pos) = @_;
+
+ die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node;
+
+ $node->{$parentNode}->removeNode($node) if ($node->{$parentNode});
+
+ $this->childNodes->InsertAt($pos,$node);
+
+ $node->_setParent( $this );
+
+ return $node;
+}
+
+sub appendChild {
+ my ($this,$node) = @_;
+
+ die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node;
+
+ $node->{$parentNode}->removeNode($node) if ($node->{$parentNode});
+
+ my $children = $this->childNodes;
+ $children->Append($node);
+
+ $node->_setParent( $this );
+
+ return $node;
+}
+
+sub appendNode {
+ goto &appendChild;
+}
+
+sub appendRange {
+ my ($this,@range) = @_;
+
+ die new IMPL::InvalidOperationException("You can't insert the node to itselft") if grep $_ == $this, @range;
+
+ foreach my $node (@range) {
+ $node->{$parentNode}->removeNode($node) if ($node->{$parentNode});
+ $node->_setParent( $this );
+ }
+
+ $this->childNodes->Append(@range);
+
+ return $this;
+}
+
+sub _getChildNodes {
+ my ($this) = @_;
+
+ $this->{$childNodes} = new IMPL::Object::List() unless $this->{$childNodes};
+ return $this->{$childNodes};
+}
+
+sub removeNode {
+ my ($this,$node) = @_;
+
+ if ($this == $node->{$parentNode}) {
+ $this->childNodes->RemoveItem($node);
+ $node->_setParent(undef);
+ return $node;
+ } else {
+ die new IMPL::InvalidOperationException("The specified node isn't belong to this node");
+ }
+}
+
+sub replaceNodeAt {
+ my ($this,$index,$node) = @_;
+
+ my $nodeOld = $this->childNodes->[$index];
+
+ die new IMPL::InvalidOperationException("You can't insert the node to itselft") if $this == $node;
+
+ # unlink node from previous parent
+ $node->{$parentNode}->removeNode($node) if ($node->{$parentNode});
+
+ # replace (or set) old node
+ $this->childNodes->[$index] = $node;
+
+ # set new parent
+ $node->_setParent( $this );
+
+ # unlink old node if we have one
+ $nodeOld->_setParent(undef) if $nodeOld;
+
+ # return old node
+ return $nodeOld;
+}
+
+sub removeAt {
+ my ($this,$pos) = @_;
+
+ if ( my $node = $this->childNodes->RemoveAt($pos) ) {
+ $node->_setParent(undef);
+ return $node;
+ } else {
+ return undef;
+ }
+}
+
+sub removeLast {
+ my ($this) = @_;
+
+ if ( my $node = $this->{$childNodes} ? $this->{$childNodes}->RemoveLast() : undef) {
+ $node->_setParent(undef);
+ return $node;
+ } else {
+ return undef;
+ }
+}
+
+sub removeSelected {
+ my ($this,$query) = @_;
+
+ my @newSet;
+ my @result;
+
+ if (ref $query eq 'CODE') {
+ &$query($_) ? push @result, $_ : push @newSet, $_ foreach @{$this->childNodes};
+ } elsif (defined $query) {
+ $_->nodeName eq $query ? push @result, $_ : push @newSet, $_ foreach @{$this->childNodes};
+ } else {
+ my $children = $this->childNodes;
+ $_->_setParent(undef) foreach @$children;
+ delete $this->{$childNodes};
+ return wantarray ? @$children : $children;
+ }
+
+ $_->_setParent(undef) foreach @result;
+
+ $this->{$childNodes} = @newSet ? bless \@newSet ,'IMPL::Object::List' : undef;
+
+ return wantarray ? @result : \@result;
+}
+
+sub selectNodes {
+ my ($this,$query) = @_;
+
+ my @result;
+
+ if (ref $query eq 'CODE') {
+ @result = grep &$query($_), @{$this->childNodes};
+ } elsif (ref $query eq 'ARRAY' ) {
+ my %keys = map (($_,1),@$query);
+ @result = grep $keys{$_->nodeName}, @{$this->childNodes};
+ } elsif (defined $query) {
+ @result = grep $_->nodeName eq $query, @{$this->childNodes};
+ } else {
+ if (wantarray) {
+ return @{$this->childNodes};
+ } else {
+ @result = $this->childNodes;
+ return \@result;
+ }
+ }
+
+ return wantarray ? @result : \@result;
+}
+
+sub firstChild {
+ @_ >=2 ? $_[0]->replaceNodeAt(0,$_[1]) : $_[0]->childNodes->[0];
+}
+
+sub _getIsComplex {
+ $_[0]->childNodes->Count ? 1 : 0;
+}
+
+sub _updateDocRefs {
+ my ($this) = @_;
+
+ # this method is called by the parent node on his children, so we need no to check parent
+ $this->{$document} = $this->{$parentNode}->document;
+
+ # prevent cyclic
+ weaken($this->{$document}) if $this->{$document};
+
+ $_->_updateDocRefs foreach @{$this->{$childNodes}};
+}
+
+sub _setParent {
+ my ($this,$node) = @_;
+
+
+ if (($node || 0) != ($this->{$parentNode} || 0)) {
+ my $newOwner;
+ if ($node) {
+ $this->{$parentNode} = $node;
+ $newOwner = $node->document || 0;
+
+ # prevent from creating cyclicreferences
+ weaken($this->{$parentNode});
+
+ } else {
+ delete $this->{$parentNode};
+ $newOwner = 0;
+ }
+
+ if (($this->{$document}||0) != $newOwner) {
+ $this->{$document} = $newOwner;
+ weaken($this->{$document}) if $newOwner;
+ $_->_updateDocRefs foreach @{$this->childNodes};
+ }
+ }
+}
+
+sub text {
+ my ($this) = @_;
+
+ join ('', $this->nodeValue || '', map ($_->text || '', @{$this->childNodes}));
+}
+
+sub nodeProperty {
+ my $this = shift;
+ my $name = shift;
+
+ if (@_) {
+ # set
+ return $this->{$_propertyMap}{$name} = shift;
+ } else {
+ return $this->{$_propertyMap}{$name};
+ }
+}
+
+sub qname {
+ $_[0]->{$nodeName};
+}
+
+sub path {
+ my ($this) = @_;
+
+ if ($this->parentNode) {
+ return $this->parentNode->path.'.'.$this->qname;
+ } else {
+ return $this->qname;
+ }
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Property.pm
--- a/Lib/IMPL/DOM/Property.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Property.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,73 +1,73 @@
-package IMPL::DOM::Property;
-use strict;
-use warnings;
-
-use IMPL::Class::Property;
-require IMPL::Exception;
-
-use base qw(Exporter);
-our @EXPORT_OK = qw(_dom);
-
-sub _dom($) {
- my ($prop_info) = @_;
- $prop_info->Implementor( 'IMPL::DOM::Property' );
- return $prop_info;
-}
-
-sub Make {
- my ($self,$propInfo) = @_;
-
- my ($class,$name,$virt,$access,$mutators) = $propInfo->get qw(Class Name Virtual Access Mutators);
-
- die new IMPL::InvalidOperationException("DOM properties can be declared only for the DOM objects") unless $class->isa('IMPL::DOM::Node');
-
- no strict 'refs';
- die new IMPL::InvalidOperationException("Custom mutators are not allowed","${class}::$name") if ref $mutators;
- if (($mutators & prop_all) == prop_all) {
- *{"${class}::$name"} = sub {
- $_[0]->nodeProperty($name,@_[1..$#_]);
- };
- $propInfo->canGet(1);
- $propInfo->canSet(1);
- } elsif( $mutators & prop_get ) {
- *{"${class}::$name"} = sub {
- die new IMPL::InvalidOperationException("This is a readonly property", "${class}::$name") if @_>1;
- $_[0]->nodeProperty($name);
- };
- $propInfo->canGet(1);
- $propInfo->canSet(0);
- } elsif( $mutators & prop_set ) {
- *{"${class}::$name"} = sub {
- die new IMPL::InvalidOperationException("This is a writeonly property", "${class}::$name") if @_<2;
- $_[0]->nodeProperty($name,@_[1..$#_]);
- };
- $propInfo->canGet(0);
- $propInfo->canSet(1);
- } else {
- die new IMPL::InvalidOperationException("Invalid value for the property mutators","${class}::$name",$mutators);
- }
-}
-
-1;
-__END__
-=pod
-
-=head1 SYNOPSIS
-
-package TypedNode;
-
-use base qw(IMPL::DOM::Node);
-use IMPL::DOM::Property qw(_dom);
-
-BEGIN {
- public _dom property Age => prop_all;
- public _dom property Address => prop_all;
- public property ServiceData => prop_all;
-}
-
-=head1 DESCRIPTION
-
-Позволяет объявлять свойства, которые будут храниться в списке динамических
-свойств.
-
-=cut
\ No newline at end of file
+package IMPL::DOM::Property;
+use strict;
+use warnings;
+
+use IMPL::Class::Property;
+require IMPL::Exception;
+
+use base qw(Exporter);
+our @EXPORT_OK = qw(_dom);
+
+sub _dom($) {
+ my ($prop_info) = @_;
+ $prop_info->Implementor( 'IMPL::DOM::Property' );
+ return $prop_info;
+}
+
+sub Make {
+ my ($self,$propInfo) = @_;
+
+ my ($class,$name,$virt,$access,$mutators) = $propInfo->get qw(Class Name Virtual Access Mutators);
+
+ die new IMPL::InvalidOperationException("DOM properties can be declared only for the DOM objects") unless $class->isa('IMPL::DOM::Node');
+
+ no strict 'refs';
+ die new IMPL::InvalidOperationException("Custom mutators are not allowed","${class}::$name") if ref $mutators;
+ if (($mutators & prop_all) == prop_all) {
+ *{"${class}::$name"} = sub {
+ $_[0]->nodeProperty($name,@_[1..$#_]);
+ };
+ $propInfo->canGet(1);
+ $propInfo->canSet(1);
+ } elsif( $mutators & prop_get ) {
+ *{"${class}::$name"} = sub {
+ die new IMPL::InvalidOperationException("This is a readonly property", "${class}::$name") if @_>1;
+ $_[0]->nodeProperty($name);
+ };
+ $propInfo->canGet(1);
+ $propInfo->canSet(0);
+ } elsif( $mutators & prop_set ) {
+ *{"${class}::$name"} = sub {
+ die new IMPL::InvalidOperationException("This is a writeonly property", "${class}::$name") if @_<2;
+ $_[0]->nodeProperty($name,@_[1..$#_]);
+ };
+ $propInfo->canGet(0);
+ $propInfo->canSet(1);
+ } else {
+ die new IMPL::InvalidOperationException("Invalid value for the property mutators","${class}::$name",$mutators);
+ }
+}
+
+1;
+__END__
+=pod
+
+=head1 SYNOPSIS
+
+package TypedNode;
+
+use base qw(IMPL::DOM::Node);
+use IMPL::DOM::Property qw(_dom);
+
+BEGIN {
+ public _dom property Age => prop_all;
+ public _dom property Address => prop_all;
+ public property ServiceData => prop_all;
+}
+
+=head1 DESCRIPTION
+
+Позволяет объявлять свойства, которые будут храниться в списке динамических
+свойств.
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema.pm
--- a/Lib/IMPL/DOM/Schema.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,240 +1,240 @@
-package IMPL::DOM::Schema;
-use strict;
-use warnings;
-
-require IMPL::DOM::Schema::ComplexNode;
-require IMPL::DOM::Schema::ComplexType;
-require IMPL::DOM::Schema::SimpleNode;
-require IMPL::DOM::Schema::SimpleType;
-require IMPL::DOM::Schema::Node;
-require IMPL::DOM::Schema::AnyNode;
-require IMPL::DOM::Schema::NodeList;
-require IMPL::DOM::Schema::NodeSet;
-require IMPL::DOM::Schema::Property;
-require IMPL::DOM::Schema::SwitchNode;
-
-use base qw(IMPL::DOM::Document);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-
-our %CTOR = (
- 'IMPL::DOM::Document' => sub { nodeName => 'schema' }
-);
-
-BEGIN {
- private _direct property _TypesMap => prop_all;
- public _direct property BaseSchemas => prop_get | owner_set;
- private _direct property _Validators => prop_all;
-}
-
-sub resolveType {
- $_[0]->{$_TypesMap}->{$_[1]};
-}
-
-sub Create {
- my ($this,$nodeName,$class,$refArgs) = @_;
-
- die new IMPL::Exception('Invalid node class') unless $class->isa('IMPL::DOM::Schema::Node');
-
- goto &SUPER::Create;
-}
-
-sub Process {
- my ($this) = @_;
-
- $this->{$_TypesMap} = { map { $_->type, $_ } $this->selectNodes(sub { $_[0]->nodeName eq 'ComplexType' || $_[0]->nodeName eq 'SimpleType' } ) };
-}
-
-sub Validate {
- my ($this,$node) = @_;
-
- if ( my ($schemaNode) = $this->selectNodes(sub { $_[0]->name eq $node->nodeName })) {
- $schemaNode->Validate($node);
- } else {
- return new IMPL::DOM::Schema::ValidationError(Message=> "A specified document doesn't match the schema");
- }
-}
-
-my $schema;
-
-sub MetaSchema {
-
- return $schema if $schema;
-
- $schema = new IMPL::DOM::Schema;
-
- $schema->appendRange(
- IMPL::DOM::Schema::ComplexNode->new(name => 'schema')->appendRange(
- IMPL::DOM::Schema::NodeSet->new()->appendRange(
- IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type => 'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::Node->new(name => 'ComplexType', type => 'ComplexType', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type => 'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::Node->new(name => 'SimpleType', type => 'SimpleType', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::SimpleNode->new(name => 'Include', minOccur => 0, maxOccur=>'unbounded')->appendRange(
- IMPL::DOM::Schema::Property->new(name => 'source')
- )
- ),
- ),
- IMPL::DOM::Schema::ComplexType->new(type => 'NodeSet', nativeType => 'IMPL::DOM::Schema::NodeSet')->appendRange(
- IMPL::DOM::Schema::NodeSet->new()->appendRange(
- IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type => 'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type => 'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::SwitchNode->new(minOccur => 0, maxOccur => 1)->appendRange(
- IMPL::DOM::Schema::SimpleNode->new(name => 'AnyNode'),
- IMPL::DOM::Schema::Node->new(name => 'SwitchNode',type => 'SwitchNode')
- )
- )
- ),
- IMPL::DOM::Schema::ComplexType->new(type => 'SwitchNode', nativeType => 'IMPL::DOM::Schema::SwitchNode')->appendRange(
- IMPL::DOM::Schema::NodeSet->new()->appendRange(
- IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type=>'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type=>'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
- )
- ),
- IMPL::DOM::Schema::ComplexType->new(type => 'NodeList', nativeType => 'IMPL::DOM::Schema::NodeList')->appendRange(
- IMPL::DOM::Schema::NodeSet->new()->appendRange(
- IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type => 'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type => 'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::Node->new(name => 'SwitchNode',type => 'SwitchNode', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
- IMPL::DOM::Schema::SimpleNode->new(name => 'AnyNode', minOccur => 0, maxOccur=>'unbounded'),
- )
- ),
- IMPL::DOM::Schema::ComplexType->new(type => 'ComplexType', nativeType => 'IMPL::DOM::Schema::ComplexType')->appendRange(
- IMPL::DOM::Schema::NodeList->new()->appendRange(
- IMPL::DOM::Schema::SwitchNode->new()->appendRange(
- IMPL::DOM::Schema::Node->new(name => 'NodeSet', type => 'NodeSet'),
- IMPL::DOM::Schema::Node->new(name => 'NodeList',type => 'NodeList'),
- ),
- IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
- ),
- new IMPL::DOM::Schema::Property(name => 'type')
- ),
- IMPL::DOM::Schema::ComplexType->new(type => 'ComplexNode', nativeType => 'IMPL::DOM::Schema::ComplexNode')->appendRange(
- IMPL::DOM::Schema::NodeList->new()->appendRange(
- IMPL::DOM::Schema::SwitchNode->new()->appendRange(
- IMPL::DOM::Schema::Node->new(name => 'NodeSet', type => 'NodeSet'),
- IMPL::DOM::Schema::Node->new(name => 'NodeList',type => 'NodeList'),
- ),
- IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
- ),
- new IMPL::DOM::Schema::Property(name => 'name')
- ),
- IMPL::DOM::Schema::ComplexType->new(type => 'SimpleType', nativeType => 'IMPL::DOM::Schema::SimpleType')->appendRange(
- IMPL::DOM::Schema::NodeSet->new()->appendRange(
- IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
- ),
- new IMPL::DOM::Schema::Property(name => 'type')
- ),
- IMPL::DOM::Schema::ComplexType->new(type => 'SimpleNode', nativeType => 'IMPL::DOM::Schema::SimpleNode')->appendRange(
- IMPL::DOM::Schema::NodeSet->new()->appendRange(
- IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
- ),
- new IMPL::DOM::Schema::Property(name => 'name')
- ),
- IMPL::DOM::Schema::ComplexType->new(type => 'Validator', nativeType => 'IMPL::DOM::Schema::Validator')->appendRange(
- IMPL::DOM::Schema::NodeList->new()->appendRange(
- IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0)
- ),
- new IMPL::DOM::Schema::Property(name => 'name')
- )
- );
-
- $schema->Process;
-
- return $schema;
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-Схема документа. Наследует C
-
-=head1 METHODS
-
-=over
-
-=item C<< $obj->Process() >>
-
-Обновляет таблицу типов из содержимого.
-
-=item C<< $obj->ResolveType($typeName) >>
-
-Возвращает схему типа c именем C<$typeName>.
-
-=back
-
-=head1 DESCRIPTION
-
-DOM схема - это документ, состоящий из определенных узлов, описывающая структуру
-других документов.
-
-=head1 META SCHEMA
-
-Схема для описания схемы, эта схема используется для постороения других схем
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-=cut
+package IMPL::DOM::Schema;
+use strict;
+use warnings;
+
+require IMPL::DOM::Schema::ComplexNode;
+require IMPL::DOM::Schema::ComplexType;
+require IMPL::DOM::Schema::SimpleNode;
+require IMPL::DOM::Schema::SimpleType;
+require IMPL::DOM::Schema::Node;
+require IMPL::DOM::Schema::AnyNode;
+require IMPL::DOM::Schema::NodeList;
+require IMPL::DOM::Schema::NodeSet;
+require IMPL::DOM::Schema::Property;
+require IMPL::DOM::Schema::SwitchNode;
+
+use base qw(IMPL::DOM::Document);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+
+our %CTOR = (
+ 'IMPL::DOM::Document' => sub { nodeName => 'schema' }
+);
+
+BEGIN {
+ private _direct property _TypesMap => prop_all;
+ public _direct property BaseSchemas => prop_get | owner_set;
+ private _direct property _Validators => prop_all;
+}
+
+sub resolveType {
+ $_[0]->{$_TypesMap}->{$_[1]};
+}
+
+sub Create {
+ my ($this,$nodeName,$class,$refArgs) = @_;
+
+ die new IMPL::Exception('Invalid node class') unless $class->isa('IMPL::DOM::Schema::Node');
+
+ goto &SUPER::Create;
+}
+
+sub Process {
+ my ($this) = @_;
+
+ $this->{$_TypesMap} = { map { $_->type, $_ } $this->selectNodes(sub { $_[0]->nodeName eq 'ComplexType' || $_[0]->nodeName eq 'SimpleType' } ) };
+}
+
+sub Validate {
+ my ($this,$node) = @_;
+
+ if ( my ($schemaNode) = $this->selectNodes(sub { $_[0]->name eq $node->nodeName })) {
+ $schemaNode->Validate($node);
+ } else {
+ return new IMPL::DOM::Schema::ValidationError(Message=> "A specified document doesn't match the schema");
+ }
+}
+
+my $schema;
+
+sub MetaSchema {
+
+ return $schema if $schema;
+
+ $schema = new IMPL::DOM::Schema;
+
+ $schema->appendRange(
+ IMPL::DOM::Schema::ComplexNode->new(name => 'schema')->appendRange(
+ IMPL::DOM::Schema::NodeSet->new()->appendRange(
+ IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type => 'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::Node->new(name => 'ComplexType', type => 'ComplexType', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type => 'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::Node->new(name => 'SimpleType', type => 'SimpleType', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::SimpleNode->new(name => 'Include', minOccur => 0, maxOccur=>'unbounded')->appendRange(
+ IMPL::DOM::Schema::Property->new(name => 'source')
+ )
+ ),
+ ),
+ IMPL::DOM::Schema::ComplexType->new(type => 'NodeSet', nativeType => 'IMPL::DOM::Schema::NodeSet')->appendRange(
+ IMPL::DOM::Schema::NodeSet->new()->appendRange(
+ IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type => 'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type => 'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::SwitchNode->new(minOccur => 0, maxOccur => 1)->appendRange(
+ IMPL::DOM::Schema::SimpleNode->new(name => 'AnyNode'),
+ IMPL::DOM::Schema::Node->new(name => 'SwitchNode',type => 'SwitchNode')
+ )
+ )
+ ),
+ IMPL::DOM::Schema::ComplexType->new(type => 'SwitchNode', nativeType => 'IMPL::DOM::Schema::SwitchNode')->appendRange(
+ IMPL::DOM::Schema::NodeSet->new()->appendRange(
+ IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type=>'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type=>'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
+ )
+ ),
+ IMPL::DOM::Schema::ComplexType->new(type => 'NodeList', nativeType => 'IMPL::DOM::Schema::NodeList')->appendRange(
+ IMPL::DOM::Schema::NodeSet->new()->appendRange(
+ IMPL::DOM::Schema::Node->new(name => 'ComplexNode', type => 'ComplexNode', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::Node->new(name => 'SimpleNode', type => 'SimpleNode', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::Node->new(name => 'SwitchNode',type => 'SwitchNode', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::SimpleNode->new(name => 'Node', minOccur => 0, maxOccur=>'unbounded'),
+ IMPL::DOM::Schema::SimpleNode->new(name => 'AnyNode', minOccur => 0, maxOccur=>'unbounded'),
+ )
+ ),
+ IMPL::DOM::Schema::ComplexType->new(type => 'ComplexType', nativeType => 'IMPL::DOM::Schema::ComplexType')->appendRange(
+ IMPL::DOM::Schema::NodeList->new()->appendRange(
+ IMPL::DOM::Schema::SwitchNode->new()->appendRange(
+ IMPL::DOM::Schema::Node->new(name => 'NodeSet', type => 'NodeSet'),
+ IMPL::DOM::Schema::Node->new(name => 'NodeList',type => 'NodeList'),
+ ),
+ IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
+ ),
+ new IMPL::DOM::Schema::Property(name => 'type')
+ ),
+ IMPL::DOM::Schema::ComplexType->new(type => 'ComplexNode', nativeType => 'IMPL::DOM::Schema::ComplexNode')->appendRange(
+ IMPL::DOM::Schema::NodeList->new()->appendRange(
+ IMPL::DOM::Schema::SwitchNode->new()->appendRange(
+ IMPL::DOM::Schema::Node->new(name => 'NodeSet', type => 'NodeSet'),
+ IMPL::DOM::Schema::Node->new(name => 'NodeList',type => 'NodeList'),
+ ),
+ IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
+ ),
+ new IMPL::DOM::Schema::Property(name => 'name')
+ ),
+ IMPL::DOM::Schema::ComplexType->new(type => 'SimpleType', nativeType => 'IMPL::DOM::Schema::SimpleType')->appendRange(
+ IMPL::DOM::Schema::NodeSet->new()->appendRange(
+ IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
+ ),
+ new IMPL::DOM::Schema::Property(name => 'type')
+ ),
+ IMPL::DOM::Schema::ComplexType->new(type => 'SimpleNode', nativeType => 'IMPL::DOM::Schema::SimpleNode')->appendRange(
+ IMPL::DOM::Schema::NodeSet->new()->appendRange(
+ IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0, type=>'Validator')
+ ),
+ new IMPL::DOM::Schema::Property(name => 'name')
+ ),
+ IMPL::DOM::Schema::ComplexType->new(type => 'Validator', nativeType => 'IMPL::DOM::Schema::Validator')->appendRange(
+ IMPL::DOM::Schema::NodeList->new()->appendRange(
+ IMPL::DOM::Schema::AnyNode->new(maxOccur => 'unbounded', minOccur => 0)
+ ),
+ new IMPL::DOM::Schema::Property(name => 'name')
+ )
+ );
+
+ $schema->Process;
+
+ return $schema;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Схема документа. Наследует C
+
+=head1 METHODS
+
+=over
+
+=item C<< $obj->Process() >>
+
+Обновляет таблицу типов из содержимого.
+
+=item C<< $obj->ResolveType($typeName) >>
+
+Возвращает схему типа c именем C<$typeName>.
+
+=back
+
+=head1 DESCRIPTION
+
+DOM схема - это документ, состоящий из определенных узлов, описывающая структуру
+других документов.
+
+=head1 META SCHEMA
+
+Схема для описания схемы, эта схема используется для постороения других схем
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema/AnyNode.pm
--- a/Lib/IMPL/DOM/Schema/AnyNode.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema/AnyNode.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,42 +1,42 @@
-package IMPL::DOM::Schema::AnyNode;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Schema::Node);
-
-our %CTOR = (
- 'IMPL::DOM::Schema::Node' => sub {
- my %args = @_;
- $args{nodeName} ||= 'AnyNode';
- $args{name} = '::any';
-
- %args;
- }
-);
-
-1;
-
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-Узел с произвольным именем, для этого узла предусмотрена специальная проверка
-в контейнерах.
-
-В контейнерах типа C этот узел можно использовать только один раз
-причем его использование исключает использование узла C.
-
-В контейнерах типа С данный узел может применяться несколько раз
-для решения таких задачь как последовательности разноименных узлов с одним типом.
-
-
-
-
-
-
-
-
-
-=cut
\ No newline at end of file
+package IMPL::DOM::Schema::AnyNode;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Schema::Node);
+
+our %CTOR = (
+ 'IMPL::DOM::Schema::Node' => sub {
+ my %args = @_;
+ $args{nodeName} ||= 'AnyNode';
+ $args{name} = '::any';
+
+ %args;
+ }
+);
+
+1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Узел с произвольным именем, для этого узла предусмотрена специальная проверка
+в контейнерах.
+
+В контейнерах типа C этот узел можно использовать только один раз
+причем его использование исключает использование узла C.
+
+В контейнерах типа С данный узел может применяться несколько раз
+для решения таких задачь как последовательности разноименных узлов с одним типом.
+
+
+
+
+
+
+
+
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema/ComplexNode.pm
--- a/Lib/IMPL/DOM/Schema/ComplexNode.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema/ComplexNode.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,59 +1,59 @@
-package IMPL::DOM::Schema::ComplexNode;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Schema::Node);
-use IMPL::Class::Property;
-
-BEGIN {
- public property content => {
- get => \&_getContent,
- set => \&_setContent
- }
-}
-
-our %CTOR = (
- 'IMPL::DOM::Schema::Node' => sub {my %args = @_; $args{nodeName} ||= 'ComplexNode'; %args }
-);
-
-sub _getContent {
- $_[0]->firstChild;
-}
-
-sub _setContent {
- $_[0]->firstChild($_[1]);
-}
-
-sub Validate {
- my ($this,$node) = @_;
-
- map $_->Validate($node), @{$this->childNodes};
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-Описывает сложный узел. Требует либо соответствие структуры, либо соответствия
-типу.
-
-Дочерними элементами могут быть правила контроля свойств и т.п.
-Первым дочерним элементом может быть только содержимое узла, см. C
-
-=head2 PROPERTIES
-
-=over
-
-=item C
-
-Содержимое узла, может быть либо C либо
-C, в зависимости от того важен порядок или нет.
-Это свойство ссылается на первый дочерний элемент узла.
-
-=back
-
-=cut
+package IMPL::DOM::Schema::ComplexNode;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Schema::Node);
+use IMPL::Class::Property;
+
+BEGIN {
+ public property content => {
+ get => \&_getContent,
+ set => \&_setContent
+ }
+}
+
+our %CTOR = (
+ 'IMPL::DOM::Schema::Node' => sub {my %args = @_; $args{nodeName} ||= 'ComplexNode'; %args }
+);
+
+sub _getContent {
+ $_[0]->firstChild;
+}
+
+sub _setContent {
+ $_[0]->firstChild($_[1]);
+}
+
+sub Validate {
+ my ($this,$node) = @_;
+
+ map $_->Validate($node), @{$this->childNodes};
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Описывает сложный узел. Требует либо соответствие структуры, либо соответствия
+типу.
+
+Дочерними элементами могут быть правила контроля свойств и т.п.
+Первым дочерним элементом может быть только содержимое узла, см. C
+
+=head2 PROPERTIES
+
+=over
+
+=item C
+
+Содержимое узла, может быть либо C либо
+C, в зависимости от того важен порядок или нет.
+Это свойство ссылается на первый дочерний элемент узла.
+
+=back
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema/ComplexType.pm
--- a/Lib/IMPL/DOM/Schema/ComplexType.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema/ComplexType.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,31 +1,31 @@
-package IMPL::DOM::Schema::ComplexType;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Schema::ComplexNode);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-
-BEGIN {
- public _direct property nativeType => prop_get;
-}
-
-our %CTOR = (
- 'IMPL::DOM::Schema::ComplexNode' => sub {
- my %args = @_;
- $args{nodeName} ||= 'ComplexType';
- $args{minOccur} = 0;
- $args{maxOccur} = 'unbounded';
- $args{name} ||= 'ComplexType';
- %args
- }
-);
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$nativeType} = $args{nativeType};
-}
-
-
-1;
+package IMPL::DOM::Schema::ComplexType;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Schema::ComplexNode);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+
+BEGIN {
+ public _direct property nativeType => prop_get;
+}
+
+our %CTOR = (
+ 'IMPL::DOM::Schema::ComplexNode' => sub {
+ my %args = @_;
+ $args{nodeName} ||= 'ComplexType';
+ $args{minOccur} = 0;
+ $args{maxOccur} = 'unbounded';
+ $args{name} ||= 'ComplexType';
+ %args
+ }
+);
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$nativeType} = $args{nativeType};
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema/Node.pm
--- a/Lib/IMPL/DOM/Schema/Node.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema/Node.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,62 +1,62 @@
-package IMPL::DOM::Schema::Node;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Node);
-use IMPL::Class::Property;
-use IMPL::DOM::Property qw(_dom);
-use IMPL::Class::Property::Direct;
-
-BEGIN {
- public _direct property minOccur => prop_all;
- public _direct property maxOccur => prop_all;
- public _direct property type => prop_all;
- public _direct property name => prop_all;
-}
-
-our %CTOR = (
- 'IMPL::DOM::Node' => sub {my %args = @_; $args{nodeName} ||= 'Node'; %args}
-);
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$minOccur} = defined $args{minOccur} ? $args{minOccur} : 1;
- $this->{$maxOccur} = defined $args{maxOccur} ? $args{maxOccur} : 1;
- $this->{$type} = $args{type};
- $this->{$name} = $args{name} or die new IMPL::InvalidArgumentException('Argument is required','name');
-}
-
-sub Validate {
- my ($this,$node) = @_;
-
- if (my $schemaType = $this->{$type} ? $this->document->resolveType($this->{$type}) : undef ) {
- return $schemaType->Validate($node);
- } else {
- return ();
- }
-}
-
-sub qname {
- $_[0]->nodeName.'[name='.$_[0]->{$name}.']';
-}
-
-1;
-
-__END__
-=pod
-
-=head1 SYNOPSIS
-
-package Restriction;
-use base qw(IMPL::DOM::Schema::Item);
-
-sub Validate {
- my ($this,$node) = @_;
-}
-
-=head1 DESCRIPTION
-
-Базовый класс для элементов схемы.
-
-=cut
+package IMPL::DOM::Schema::Node;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Node);
+use IMPL::Class::Property;
+use IMPL::DOM::Property qw(_dom);
+use IMPL::Class::Property::Direct;
+
+BEGIN {
+ public _direct property minOccur => prop_all;
+ public _direct property maxOccur => prop_all;
+ public _direct property type => prop_all;
+ public _direct property name => prop_all;
+}
+
+our %CTOR = (
+ 'IMPL::DOM::Node' => sub {my %args = @_; $args{nodeName} ||= 'Node'; %args}
+);
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$minOccur} = defined $args{minOccur} ? $args{minOccur} : 1;
+ $this->{$maxOccur} = defined $args{maxOccur} ? $args{maxOccur} : 1;
+ $this->{$type} = $args{type};
+ $this->{$name} = $args{name} or die new IMPL::InvalidArgumentException('Argument is required','name');
+}
+
+sub Validate {
+ my ($this,$node) = @_;
+
+ if (my $schemaType = $this->{$type} ? $this->document->resolveType($this->{$type}) : undef ) {
+ return $schemaType->Validate($node);
+ } else {
+ return ();
+ }
+}
+
+sub qname {
+ $_[0]->nodeName.'[name='.$_[0]->{$name}.']';
+}
+
+1;
+
+__END__
+=pod
+
+=head1 SYNOPSIS
+
+package Restriction;
+use base qw(IMPL::DOM::Schema::Item);
+
+sub Validate {
+ my ($this,$node) = @_;
+}
+
+=head1 DESCRIPTION
+
+Базовый класс для элементов схемы.
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema/NodeList.pm
--- a/Lib/IMPL/DOM/Schema/NodeList.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema/NodeList.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,104 +1,104 @@
-package IMPL::DOM::Schema::NodeList;
-use strict;
-use warnings;
-use base qw(IMPL::DOM::Node);
-
-use IMPL::Class::Property;
-require IMPL::DOM::Schema::ValidationError;
-
-our %CTOR = (
- 'IMPL::DOM::Node' => sub { nodeName => 'NodeList' }
-);
-
-BEGIN {
- public property messageUnexpected => prop_all;
- public property messageNodesRequired => prop_all;
-}
-
-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 %Node.path%');
-}
-
-sub Validate {
- my ($this,$node) = @_;
-
- my @nodes = map {
- {nodeName => $_->name, anyNode => $_->isa('IMPL::DOM::Schema::AnyNode') , Schema => $_, Max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur, Min => $_->minOccur, Seen => 0 }
- } @{$this->childNodes};
-
- my $info = shift @nodes;
-
- foreach my $child ( @{$node->childNodes} ) {
- #skip schema elements
- while ($info and not $info->{anyNode} and $info->{nodeName} ne $child->nodeName) {
- # if possible of course :)
- return new IMPL::DOM::Schema::ValidationError (
- Message => $this->messageUnexpected,
- Node => $child,
- Schema => $info->{Schema},
- Source => $this
- ) if $info->{Min} > $info->{Seen};
-
- $info = shift @nodes;
- }
-
- # return error if no more children allowed
- return new IMPL::DOM::Schema::ValidationError (
- Message => $this->messageUnexpected,
- Node => $child,
- Source => $this
- ) unless $info;
-
- # it's ok, we found schema element for child
- # but it may be any node or switching node wich would not satisfy current child
-
- # validate
- while (my @errors = $info->{Schema}->Validate($child)) {
- if( $info->{anyNode} and $info->{Seen} >= $info->{Min} ) {
- # in case of any or switch node, skip it if possible
- next if $info = shift @nodes;
- }
- return @errors;
- }
-
- $info->{Seen}++;
-
- # check count limits
- return new IMPL::DOM::Schema::ValidationError (
- Error => 1,
- Message => $this->messageUnexpected,
- Node => $child,
- Source => $this,
- ) if $info->{Max} and $info->{Seen} > $info->{Max};
- }
-
- # no more children left (but may be should :)
- while ($info) {
- return new IMPL::DOM::Schema::ValidationError (
- Error => 1,
- Message => $this->messageNodesRequired,
- Node => $node,
- Source => $this,
- Schema => $info->{Schema}
- ) if $info->{Seen} < $info->{Min};
-
- $info = shift @nodes;
- }
- return;
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-Содержимое для сложного узла. Порядок важен. Дочерними элементами могут быть
-только C и C.
-
-=cut
\ No newline at end of file
+package IMPL::DOM::Schema::NodeList;
+use strict;
+use warnings;
+use base qw(IMPL::DOM::Node);
+
+use IMPL::Class::Property;
+require IMPL::DOM::Schema::ValidationError;
+
+our %CTOR = (
+ 'IMPL::DOM::Node' => sub { nodeName => 'NodeList' }
+);
+
+BEGIN {
+ public property messageUnexpected => prop_all;
+ public property messageNodesRequired => prop_all;
+}
+
+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 %Node.path%');
+}
+
+sub Validate {
+ my ($this,$node) = @_;
+
+ my @nodes = map {
+ {nodeName => $_->name, anyNode => $_->isa('IMPL::DOM::Schema::AnyNode') , Schema => $_, Max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur, Min => $_->minOccur, Seen => 0 }
+ } @{$this->childNodes};
+
+ my $info = shift @nodes;
+
+ foreach my $child ( @{$node->childNodes} ) {
+ #skip schema elements
+ while ($info and not $info->{anyNode} and $info->{nodeName} ne $child->nodeName) {
+ # if possible of course :)
+ return new IMPL::DOM::Schema::ValidationError (
+ Message => $this->messageUnexpected,
+ Node => $child,
+ Schema => $info->{Schema},
+ Source => $this
+ ) if $info->{Min} > $info->{Seen};
+
+ $info = shift @nodes;
+ }
+
+ # return error if no more children allowed
+ return new IMPL::DOM::Schema::ValidationError (
+ Message => $this->messageUnexpected,
+ Node => $child,
+ Source => $this
+ ) unless $info;
+
+ # it's ok, we found schema element for child
+ # but it may be any node or switching node wich would not satisfy current child
+
+ # validate
+ while (my @errors = $info->{Schema}->Validate($child)) {
+ if( $info->{anyNode} and $info->{Seen} >= $info->{Min} ) {
+ # in case of any or switch node, skip it if possible
+ next if $info = shift @nodes;
+ }
+ return @errors;
+ }
+
+ $info->{Seen}++;
+
+ # check count limits
+ return new IMPL::DOM::Schema::ValidationError (
+ Error => 1,
+ Message => $this->messageUnexpected,
+ Node => $child,
+ Source => $this,
+ ) if $info->{Max} and $info->{Seen} > $info->{Max};
+ }
+
+ # no more children left (but may be should :)
+ while ($info) {
+ return new IMPL::DOM::Schema::ValidationError (
+ Error => 1,
+ Message => $this->messageNodesRequired,
+ Node => $node,
+ Source => $this,
+ Schema => $info->{Schema}
+ ) if $info->{Seen} < $info->{Min};
+
+ $info = shift @nodes;
+ }
+ return;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Содержимое для сложного узла. Порядок важен. Дочерними элементами могут быть
+только C и C.
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema/NodeSet.pm
--- a/Lib/IMPL/DOM/Schema/NodeSet.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema/NodeSet.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,91 +1,91 @@
-package IMPL::DOM::Schema::NodeSet;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Node);
-use IMPL::Class::Property;
-
-our %CTOR = (
- 'IMPL::DOM::Node' => sub { nodeName => 'NodeSet' }
-);
-
-BEGIN {
- public property messageUnexpected => prop_all;
- public property messageMax => prop_all;
- public property messageMin => prop_all;
-}
-
-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%');
-}
-
-sub Validate {
- my ($this,$node) = @_;
-
- my @errors;
-
- my %nodes;
- my $anyNode;
- foreach (@{$this->childNodes}) {
- if ($_->isa('IMPL::DOM::Schema::AnyNode')) {
- $anyNode = {Schema => $_, Min => $_->minOccur, Max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur , Seen => 0 };
- } else {
- $nodes{$_->name} = {Schema => $_, Min => $_->minOccur, Max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur , Seen => 0 };
- }
- }
-
- foreach my $child ( @{$node->childNodes} ) {
- if (my $info = $nodes{$child->nodeName} || $anyNode) {
- $info->{Seen}++;
- push @errors,new IMPL::DOM::Schema::ValidationError (
- Source => $this,
- Node => $child,
- Schema => $info->{Schema},
- Message => $this->messageMax
- ) if ($info->{Max} and $info->{Seen} > $info->{Max});
-
- if (my @localErrors = $info->{Schema}->Validate($child)) {
- push @errors,@localErrors;
- }
- } else {
- push @errors, new IMPL::DOM::Schema::ValidationError (
- Source => $this,
- Node => $child,
- Schema => $info->{Schema},
- Message => $this->messageUnexpected
- )
- }
- }
-
- foreach my $info (values %nodes) {
- push @errors, new IMPL::DOM::Schema::ValidationError (
- Source => $this,
- Schema => $info->{Schema},
- Node => $node,
- Message => $this->messageMin
- ) if $info->{Min} > $info->{Seen};
- }
-
- return @errors;
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-Содержимое для сложного узла. Порядок не важен. Дочерними элементами могут быть
-только C и C.
-
-При проверке данного правила, проверяются имеющиеся элементы на соответсие схемы
-и количества встречаемости, после чего проверяются количественные ограничения
-для несуществующих элементов.
-
-=cut
+package IMPL::DOM::Schema::NodeSet;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Node);
+use IMPL::Class::Property;
+
+our %CTOR = (
+ 'IMPL::DOM::Node' => sub { nodeName => 'NodeSet' }
+);
+
+BEGIN {
+ public property messageUnexpected => prop_all;
+ public property messageMax => prop_all;
+ public property messageMin => prop_all;
+}
+
+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%');
+}
+
+sub Validate {
+ my ($this,$node) = @_;
+
+ my @errors;
+
+ my %nodes;
+ my $anyNode;
+ foreach (@{$this->childNodes}) {
+ if ($_->isa('IMPL::DOM::Schema::AnyNode')) {
+ $anyNode = {Schema => $_, Min => $_->minOccur, Max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur , Seen => 0 };
+ } else {
+ $nodes{$_->name} = {Schema => $_, Min => $_->minOccur, Max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur , Seen => 0 };
+ }
+ }
+
+ foreach my $child ( @{$node->childNodes} ) {
+ if (my $info = $nodes{$child->nodeName} || $anyNode) {
+ $info->{Seen}++;
+ push @errors,new IMPL::DOM::Schema::ValidationError (
+ Source => $this,
+ Node => $child,
+ Schema => $info->{Schema},
+ Message => $this->messageMax
+ ) if ($info->{Max} and $info->{Seen} > $info->{Max});
+
+ if (my @localErrors = $info->{Schema}->Validate($child)) {
+ push @errors,@localErrors;
+ }
+ } else {
+ push @errors, new IMPL::DOM::Schema::ValidationError (
+ Source => $this,
+ Node => $child,
+ Schema => $info->{Schema},
+ Message => $this->messageUnexpected
+ )
+ }
+ }
+
+ foreach my $info (values %nodes) {
+ push @errors, new IMPL::DOM::Schema::ValidationError (
+ Source => $this,
+ Schema => $info->{Schema},
+ Node => $node,
+ Message => $this->messageMin
+ ) if $info->{Min} > $info->{Seen};
+ }
+
+ return @errors;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Содержимое для сложного узла. Порядок не важен. Дочерними элементами могут быть
+только C и C.
+
+При проверке данного правила, проверяются имеющиеся элементы на соответсие схемы
+и количества встречаемости, после чего проверяются количественные ограничения
+для несуществующих элементов.
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema/Property.pm
--- a/Lib/IMPL/DOM/Schema/Property.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema/Property.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,54 +1,54 @@
-package IMPL::DOM::Schema::Property;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Schema::SimpleNode);
-require IMPL::DOM::Schema;
-require IMPL::DOM::Node;
-use IMPL::Class::Property;
-
-__PACKAGE__->PassThroughArgs;
-
-BEGIN {
- public property RequiredMessage => prop_all;
-}
-
-our %CTOR = (
- 'IMPL::DOM::Schema::SimpleNode' => sub {
- my %args = @_;
-
- $args{maxOccur} = 1;
- $args{minOccur} = delete $args{optional} ? 0 : 1;
- $args{nodeName} ||= 'Property';
-
- return %args;
- }
-);
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->RequiredMessage($args{RequiredMessage} || 'A property %Schema.name% is required in the %Node.qname%');
-}
-
-sub Validate {
- my ($this,$node) = @_;
-
- if ($this->minOccur) {
- my $prop = $this->name;
- my $nodeProp = new IMPL::DOM::Node(nodeName => '::property', nodeValue => $node->$prop() || $node->nodePropety($prop));
-
- if (! $nodeProp->nodeValue) {
- return new IMPL::DOM::Schema::ValidationError(
- Message => $this->RequiredMessage,
- Node => $node,
- Schema => $this
- );
- }
- return $this->SUPER::Validate($nodeProp);
- } else {
- return ();
- }
-}
-
-1;
+package IMPL::DOM::Schema::Property;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Schema::SimpleNode);
+require IMPL::DOM::Schema;
+require IMPL::DOM::Node;
+use IMPL::Class::Property;
+
+__PACKAGE__->PassThroughArgs;
+
+BEGIN {
+ public property RequiredMessage => prop_all;
+}
+
+our %CTOR = (
+ 'IMPL::DOM::Schema::SimpleNode' => sub {
+ my %args = @_;
+
+ $args{maxOccur} = 1;
+ $args{minOccur} = delete $args{optional} ? 0 : 1;
+ $args{nodeName} ||= 'Property';
+
+ return %args;
+ }
+);
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->RequiredMessage($args{RequiredMessage} || 'A property %Schema.name% is required in the %Node.qname%');
+}
+
+sub Validate {
+ my ($this,$node) = @_;
+
+ if ($this->minOccur) {
+ my $prop = $this->name;
+ my $nodeProp = new IMPL::DOM::Node(nodeName => '::property', nodeValue => $node->$prop() || $node->nodePropety($prop));
+
+ if (! $nodeProp->nodeValue) {
+ return new IMPL::DOM::Schema::ValidationError(
+ Message => $this->RequiredMessage,
+ Node => $node,
+ Schema => $this
+ );
+ }
+ return $this->SUPER::Validate($nodeProp);
+ } else {
+ return ();
+ }
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema/SimpleNode.pm
--- a/Lib/IMPL/DOM/Schema/SimpleNode.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema/SimpleNode.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,29 +1,29 @@
-package IMPL::DOM::Schema::SimpleNode;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Schema::Node);
-
-our %CTOR = (
- 'IMPL::DOM::Schema::Node' => sub {my %args = @_; $args{nodeName} ||= 'SimpleNode'; %args}
-);
-
-sub Validate {
- my ($this,$node) = @_;
-
- map $_->Validate($node), @{$this->childNodes};
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-Узел имеющий простое значение. Данный узел может содержать ограничения
-на простое значение.
-
-
-=cut
\ No newline at end of file
+package IMPL::DOM::Schema::SimpleNode;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Schema::Node);
+
+our %CTOR = (
+ 'IMPL::DOM::Schema::Node' => sub {my %args = @_; $args{nodeName} ||= 'SimpleNode'; %args}
+);
+
+sub Validate {
+ my ($this,$node) = @_;
+
+ map $_->Validate($node), @{$this->childNodes};
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Узел имеющий простое значение. Данный узел может содержать ограничения
+на простое значение.
+
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema/SimpleType.pm
--- a/Lib/IMPL/DOM/Schema/SimpleType.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema/SimpleType.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,31 +1,31 @@
-package IMPL::DOM::Schema::SimpleType;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Schema::SimpleNode);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-
-BEGIN {
- public _direct property nativeType => prop_get;
-}
-
-our %CTOR = (
- 'IMPL::DOM::Schema::SimpleNode' => sub {
- my %args = @_;
- $args{nodeName} = 'SimpleType';
- $args{minOccur} = 0;
- $args{maxOccur} = 'unbounded';
- $args{name} ||= 'SimpleType';
- %args
- }
-);
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$nativeType} = $args{nativeType};
-}
-
-
-1;
+package IMPL::DOM::Schema::SimpleType;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Schema::SimpleNode);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+
+BEGIN {
+ public _direct property nativeType => prop_get;
+}
+
+our %CTOR = (
+ 'IMPL::DOM::Schema::SimpleNode' => sub {
+ my %args = @_;
+ $args{nodeName} = 'SimpleType';
+ $args{minOccur} = 0;
+ $args{maxOccur} = 'unbounded';
+ $args{name} ||= 'SimpleType';
+ %args
+ }
+);
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$nativeType} = $args{nativeType};
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema/SwitchNode.pm
--- a/Lib/IMPL/DOM/Schema/SwitchNode.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema/SwitchNode.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,54 +1,54 @@
-package IMPL::DOM::Schema::SwitchNode;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Schema::AnyNode);
-use IMPL::Class::Property;
-require IMPL::DOM::Schema::ValidationError;
-
-our %CTOR = (
- 'IMPL::DOM::Schema::AnyNode' => sub {
- my %args = @_;
-
- $args{nodeName} ||= 'SwitchNode';
-
- %args;
- }
-);
-
-BEGIN {
- public property messageNoMatch => prop_all;
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->messageNoMatch($args{messageNoMatch} || 'A node %Node.nodeName% isn\'t expected in the %Node.parentNode.path%');
-}
-
-sub Validate {
- my ($this,$node) = @_;
-
- if ( my ($schema) = $this->selectNodes(sub {$_[0]->name eq $node->nodeName} ) ) {
- return $schema->Validate($node);
- } else {
- return new IMPL::DOM::Schema::ValidationError(
- Node => $node,
- Source => $this,
- Message => $this->messageNoMatch
- );
- }
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-Представляет узел, который может быть одним из узлов, которые лежат внутри него.
-Это более строгий вариант C.
-
-=cut
+package IMPL::DOM::Schema::SwitchNode;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Schema::AnyNode);
+use IMPL::Class::Property;
+require IMPL::DOM::Schema::ValidationError;
+
+our %CTOR = (
+ 'IMPL::DOM::Schema::AnyNode' => sub {
+ my %args = @_;
+
+ $args{nodeName} ||= 'SwitchNode';
+
+ %args;
+ }
+);
+
+BEGIN {
+ public property messageNoMatch => prop_all;
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->messageNoMatch($args{messageNoMatch} || 'A node %Node.nodeName% isn\'t expected in the %Node.parentNode.path%');
+}
+
+sub Validate {
+ my ($this,$node) = @_;
+
+ if ( my ($schema) = $this->selectNodes(sub {$_[0]->name eq $node->nodeName} ) ) {
+ return $schema->Validate($node);
+ } else {
+ return new IMPL::DOM::Schema::ValidationError(
+ Node => $node,
+ Source => $this,
+ Message => $this->messageNoMatch
+ );
+ }
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Представляет узел, который может быть одним из узлов, которые лежат внутри него.
+Это более строгий вариант C.
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Schema/ValidationError.pm
--- a/Lib/IMPL/DOM/Schema/ValidationError.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Schema/ValidationError.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,26 +1,26 @@
-package IMPL::DOM::Schema::ValidationError;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-use IMPL::Resources::Format qw(FormatMessage);
-
-BEGIN {
- public _direct property Node => prop_get;
- public _direct property Schema => prop_get;
- public _direct property Source => prop_get;
- public _direct property Message => prop_get;
-}
-
-sub CTOR {
- my ($this,%args) = @_;
-
- $this->{$Node} = $args{Node} or die new IMPL::InvalidArgumentException("Node is a required parameter");
- $this->{$Schema} = $args{Schema} if $args{Schema};
- $this->{$Source} = $args{Source} if $args{Source};
- $this->{$Message} = FormatMessage(delete $args{Message}, \%args) if $args{Message};
-}
-
-1;
+package IMPL::DOM::Schema::ValidationError;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+use IMPL::Resources::Format qw(FormatMessage);
+
+BEGIN {
+ public _direct property Node => prop_get;
+ public _direct property Schema => prop_get;
+ public _direct property Source => prop_get;
+ public _direct property Message => prop_get;
+}
+
+sub CTOR {
+ my ($this,%args) = @_;
+
+ $this->{$Node} = $args{Node} or die new IMPL::InvalidArgumentException("Node is a required parameter");
+ $this->{$Schema} = $args{Schema} if $args{Schema};
+ $this->{$Source} = $args{Source} if $args{Source};
+ $this->{$Message} = FormatMessage(delete $args{Message}, \%args) if $args{Message};
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Transform.pm
--- a/Lib/IMPL/DOM/Transform.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Transform.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,33 +1,33 @@
-package IMPL::DOM::Transform;
-use strict;
-use warnings;
-
-use base qw(IMPL::Transform);
-
-__PACKAGE__->PassThroughArgs;
-
-sub GetClassForObject {
- my ($this,$object) = @_;
-
- if (my $class = ref $object) {
- if (UNIVERSAL::isa($object,'IMPL::DOM::Node')) {
- return $object->nodeName;
- } else {
- return $class;
- }
- } else {
- return undef;
- }
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-Преобразование для DOM документа
-
-=cut
\ No newline at end of file
+package IMPL::DOM::Transform;
+use strict;
+use warnings;
+
+use base qw(IMPL::Transform);
+
+__PACKAGE__->PassThroughArgs;
+
+sub GetClassForObject {
+ my ($this,$object) = @_;
+
+ if (my $class = ref $object) {
+ if (UNIVERSAL::isa($object,'IMPL::DOM::Node')) {
+ return $object->nodeName;
+ } else {
+ return $class;
+ }
+ } else {
+ return undef;
+ }
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Преобразование для DOM документа
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/Transform/PostToDOM.pm
--- a/Lib/IMPL/DOM/Transform/PostToDOM.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/Transform/PostToDOM.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,36 +1,36 @@
-package IMPL::DOM::Post2DOM;
-use strict;
-use warnings;
-
-use IMPL::DOM::Navigator;
-use IMPL::Class::Property;
-
-use base qw(IMPL::Transform);
-
-BEGIN {
- public property Navigator => prop_get | owner_set;
-}
-
-our %CTOR = (
- 'IMPL::Transform' => sub {
- return (
- HASH => \&TransfromPostData
- );
- }
-);
-
-sub TransformPostData {
- my ($this,$data) = @_;
-
- my $navi = $this->Navigator;
-
- while (my ($key,$value) = each %$data) {
- my $node = $navi->Navigate($key);
- $node->nodeValue($value);
- }
-
- return $navi->Document;
-}
-
-
-1;
+package IMPL::DOM::Post2DOM;
+use strict;
+use warnings;
+
+use IMPL::DOM::Navigator;
+use IMPL::Class::Property;
+
+use base qw(IMPL::Transform);
+
+BEGIN {
+ public property Navigator => prop_get | owner_set;
+}
+
+our %CTOR = (
+ 'IMPL::Transform' => sub {
+ return (
+ HASH => \&TransfromPostData
+ );
+ }
+);
+
+sub TransformPostData {
+ my ($this,$data) = @_;
+
+ my $navi = $this->Navigator;
+
+ while (my ($key,$value) = each %$data) {
+ my $node = $navi->Navigate($key);
+ $node->nodeValue($value);
+ }
+
+ return $navi->Document;
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/DOM/XMLReader.pm
--- a/Lib/IMPL/DOM/XMLReader.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/DOM/XMLReader.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,105 +1,105 @@
-package IMPL::DOM::XMLReader;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object IMPL::Object::Autofill);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-use XML::Parser;
-
-__PACKAGE__->PassThroughArgs;
-
-BEGIN {
- public _direct property Navigator => prop_get | owner_set;
- private _direct property _current => prop_all;
- private _direct property _text => prop_all;
- private _direct property _textHistory => prop_all;
-}
-
-sub Parse {
- my ($this,$in) = @_;
-
- my $parser = new XML::Parser(
- Handlers => {
- Start => sub {shift; goto &OnStart($this,@_)},
- End => sub {shift; goto &OnEnd($this,@_)},
- Char => sub {shift; goto &OnChar($this,@_)}
- }
- );
-
- $parser->parse($in);
-}
-
-sub ParseFile {
- my ($this,$in) = @_;
-
- my $parser = new XML::Parser(
- Handlers => {
- Start => sub {shift; unshift @_, $this; goto &_OnBegin;},
- End => sub {shift; unshift @_, $this; goto &_OnEnd;},
- Char => sub {shift; unshift @_, $this; goto &_OnChar;}
- }
- );
-
- $parser->parsefile($in);
-}
-
-
-sub _OnBegin {
- my ($this,$element,%attrs) = @_;
-
- push @{$this->{$_textHistory}},$this->{$_text};
- $this->{$_text} = "";
- $this->{$_current} = $this->Navigator->NavigateCreate($element,%attrs);
-}
-
-sub _OnEnd {
- my ($this,$element) = @_;
-
- $this->{$_current}->nodeValue($this->{$_text}) if length $this->{$_text};
- $this->{$_text} = pop @{$this->{$_textHistory}};
- $this->{$_current} = $this->Navigator->Back;
-}
-
-sub _OnChar {
- my ($this,$val) = @_;
- $this->{$_text} .= $val;
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 SYNOPSIS
-
-my $reader = new IMPL::DOM::XMLReader(Navigator => $DomBuilder);
-my $obj = $reader->parsefile("data.xml");
-
-=head1 DESCRIPTION
-
-Простой класс, использующий навигатор для постороения документа. В зависимости от
-используемого навигатора может быть получен различный результат.
-
-Навигатор должен поодерживать методы C и C
-
-=head1 METHODS
-
-=over
-
-=item C $builder)>
-
-Создает новый экземпляр парсера, с указанным навигатором для построения документа
-
-=item C<$obj->Parse($in)>
-
-Строит документ. На вход получает либо xml строку, либо HANDLE.
-
-=item C<$obj->ParseFile($fileName)>
-
-Строит документ из файла с именем C<$fileName>.
-
-=back
-
-=cut
+package IMPL::DOM::XMLReader;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object IMPL::Object::Autofill);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+use XML::Parser;
+
+__PACKAGE__->PassThroughArgs;
+
+BEGIN {
+ public _direct property Navigator => prop_get | owner_set;
+ private _direct property _current => prop_all;
+ private _direct property _text => prop_all;
+ private _direct property _textHistory => prop_all;
+}
+
+sub Parse {
+ my ($this,$in) = @_;
+
+ my $parser = new XML::Parser(
+ Handlers => {
+ Start => sub {shift; goto &OnStart($this,@_)},
+ End => sub {shift; goto &OnEnd($this,@_)},
+ Char => sub {shift; goto &OnChar($this,@_)}
+ }
+ );
+
+ $parser->parse($in);
+}
+
+sub ParseFile {
+ my ($this,$in) = @_;
+
+ my $parser = new XML::Parser(
+ Handlers => {
+ Start => sub {shift; unshift @_, $this; goto &_OnBegin;},
+ End => sub {shift; unshift @_, $this; goto &_OnEnd;},
+ Char => sub {shift; unshift @_, $this; goto &_OnChar;}
+ }
+ );
+
+ $parser->parsefile($in);
+}
+
+
+sub _OnBegin {
+ my ($this,$element,%attrs) = @_;
+
+ push @{$this->{$_textHistory}},$this->{$_text};
+ $this->{$_text} = "";
+ $this->{$_current} = $this->Navigator->NavigateCreate($element,%attrs);
+}
+
+sub _OnEnd {
+ my ($this,$element) = @_;
+
+ $this->{$_current}->nodeValue($this->{$_text}) if length $this->{$_text};
+ $this->{$_text} = pop @{$this->{$_textHistory}};
+ $this->{$_current} = $this->Navigator->Back;
+}
+
+sub _OnChar {
+ my ($this,$val) = @_;
+ $this->{$_text} .= $val;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 SYNOPSIS
+
+my $reader = new IMPL::DOM::XMLReader(Navigator => $DomBuilder);
+my $obj = $reader->parsefile("data.xml");
+
+=head1 DESCRIPTION
+
+Простой класс, использующий навигатор для постороения документа. В зависимости от
+используемого навигатора может быть получен различный результат.
+
+Навигатор должен поодерживать методы C и C
+
+=head1 METHODS
+
+=over
+
+=item C $builder)>
+
+Создает новый экземпляр парсера, с указанным навигатором для построения документа
+
+=item C<$obj->Parse($in)>
+
+Строит документ. На вход получает либо xml строку, либо HANDLE.
+
+=item C<$obj->ParseFile($fileName)>
+
+Строит документ из файла с именем C<$fileName>.
+
+=back
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/Exception.pm
--- a/Lib/IMPL/Exception.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/Exception.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,113 +1,113 @@
-package IMPL::Exception;
-use strict;
-use overload
- '""' => \&ToString,
- 'fallback' => 1;
-use Carp qw(longmess shortmess);
-use Scalar::Util qw(refaddr);
-
-BEGIN {
- require Error;
-}
-
-use base qw(IMPL::Object::Accessor Error);
-
-BEGIN {
- __PACKAGE__->mk_accessors( qw(Message Args CallStack Source) );
-}
-
-sub indent {
- my ($str,$level) = @_;
- $level ||= 0;
- $str = '' unless defined $str;
- join ("\n", map( "\t"x$level.$_ , split(/\n/,$str) ) );
-}
-
-sub new {
- my $class = shift;
- $class = ref $class || $class;
-
- my $this = $class->Error::new() or die "Failed to create an exception";
-
- $this->callCTOR(@_);
- $this->{-text} = $this->Message;
-
- local $Carp::CarpLevel = 0;
-
- $this->CallStack(longmess);
- $this->Source(shortmess);
-
- return $this;
-}
-
-sub CTOR {
- my ($this,$message,@args) = @_;
- $this->Message($message || '');
- die new IMPL::Exception("Fatal erorr: cyclic structure in the exceptions were detected, do not use \$\@ while throwing the exception!") if grep ref $_ ? refaddr($this) == refaddr($_) : 0 , @args;
- $this->Args([map defined $_ ? $_ : 'undef', @args]);
-}
-
-sub save {
- my ($this,$ctx) = @_;
-
- $ctx->AddVar(Message => $this->Message) if $this->Message;
- $ctx->AddVar(Args => $this->Args) if @{$this->Args};
- $ctx->AddVar(Source => $this->Source);
- $ctx->AddVar(CallStack => $this->CallStack);
-}
-
-sub restore {
- my ($class,$data,$instance) = @_;
-
- my %args = @$data;
-
- if ($instance) {
- $instance->callCTOR($args{Message},@{$args{Args}});
- } else {
- $instance = $class->new($args{Message},@{$args{Args}});
- }
-
- $instance->Source($args{Source});
- $instance->CallStack($args{CallStack});
-
- return $instance;
-}
-
-sub ToString {
- my $this = shift;
-
- $this->toString();
-}
-
-sub toString {
- my ($this,$notrace) = @_;
- $this->Message . join("\n",'',map { my $s = $_; local $_; indent("$s",1) } @{$this->Args} ) . ( $notrace ? '' : "\n" . $this->CallStack);
-}
-
-package IMPL::InvalidOperationException;
-our @ISA = qw(IMPL::Exception);
-__PACKAGE__->PassThroughArgs;
-
-package IMPL::InvalidArgumentException;
-our @ISA = qw(IMPL::Exception);
-__PACKAGE__->PassThroughArgs;
-
-package IMPL::DuplicateException;
-our @ISA = qw(IMPL::Exception);
-__PACKAGE__->PassThroughArgs;
-
-package IMPL::NotImplementedException;
-our @ISA = qw(IMPL::Exception);
-__PACKAGE__->PassThroughArgs;
-
-package Exception;
-our @ISA = qw(IMPL::Exception);
-__PACKAGE__->PassThroughArgs;
-
-package IMPL::DeprecatedException;
-our @ISA = qw(IMPL::Exception);
-our %CTOR = (
- 'IMPL::Exception' => sub { @_ ? @_ : "The method is deprecated" }
-);
-
-1;
+package IMPL::Exception;
+use strict;
+use overload
+ '""' => \&ToString,
+ 'fallback' => 1;
+use Carp qw(longmess shortmess);
+use Scalar::Util qw(refaddr);
+
+BEGIN {
+ require Error;
+}
+
+use base qw(IMPL::Object::Accessor Error);
+
+BEGIN {
+ __PACKAGE__->mk_accessors( qw(Message Args CallStack Source) );
+}
+
+sub indent {
+ my ($str,$level) = @_;
+ $level ||= 0;
+ $str = '' unless defined $str;
+ join ("\n", map( "\t"x$level.$_ , split(/\n/,$str) ) );
+}
+
+sub new {
+ my $class = shift;
+ $class = ref $class || $class;
+
+ my $this = $class->Error::new() or die "Failed to create an exception";
+
+ $this->callCTOR(@_);
+ $this->{-text} = $this->Message;
+
+ local $Carp::CarpLevel = 0;
+
+ $this->CallStack(longmess);
+ $this->Source(shortmess);
+
+ return $this;
+}
+
+sub CTOR {
+ my ($this,$message,@args) = @_;
+ $this->Message($message || '');
+ die new IMPL::Exception("Fatal erorr: cyclic structure in the exceptions were detected, do not use \$\@ while throwing the exception!") if grep ref $_ ? refaddr($this) == refaddr($_) : 0 , @args;
+ $this->Args([map defined $_ ? $_ : 'undef', @args]);
+}
+
+sub save {
+ my ($this,$ctx) = @_;
+
+ $ctx->AddVar(Message => $this->Message) if $this->Message;
+ $ctx->AddVar(Args => $this->Args) if @{$this->Args};
+ $ctx->AddVar(Source => $this->Source);
+ $ctx->AddVar(CallStack => $this->CallStack);
+}
+
+sub restore {
+ my ($class,$data,$instance) = @_;
+
+ my %args = @$data;
+
+ if ($instance) {
+ $instance->callCTOR($args{Message},@{$args{Args}});
+ } else {
+ $instance = $class->new($args{Message},@{$args{Args}});
+ }
+
+ $instance->Source($args{Source});
+ $instance->CallStack($args{CallStack});
+
+ return $instance;
+}
+
+sub ToString {
+ my $this = shift;
+
+ $this->toString();
+}
+
+sub toString {
+ my ($this,$notrace) = @_;
+ $this->Message . join("\n",'',map { my $s = $_; local $_; indent("$s",1) } @{$this->Args} ) . ( $notrace ? '' : "\n" . $this->CallStack);
+}
+
+package IMPL::InvalidOperationException;
+our @ISA = qw(IMPL::Exception);
+__PACKAGE__->PassThroughArgs;
+
+package IMPL::InvalidArgumentException;
+our @ISA = qw(IMPL::Exception);
+__PACKAGE__->PassThroughArgs;
+
+package IMPL::DuplicateException;
+our @ISA = qw(IMPL::Exception);
+__PACKAGE__->PassThroughArgs;
+
+package IMPL::NotImplementedException;
+our @ISA = qw(IMPL::Exception);
+__PACKAGE__->PassThroughArgs;
+
+package Exception;
+our @ISA = qw(IMPL::Exception);
+__PACKAGE__->PassThroughArgs;
+
+package IMPL::DeprecatedException;
+our @ISA = qw(IMPL::Exception);
+our %CTOR = (
+ 'IMPL::Exception' => sub { @_ ? @_ : "The method is deprecated" }
+);
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM.pm
--- a/Lib/IMPL/ORM.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,123 +1,123 @@
-package IMPL::ORM;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object);
-use IMPL::Class::Property;
-use Scalar::Util qw(weaken refaddr);
-
-use IMPL::Exception;
-
-our $Depth = 1; # загружать объект + 1 уровень детей
-our $UseProxy = 1;
-
-BEGIN {
- private property _ObjectCache => prop_all;
- private property _MapInstances => prop_all;
- private property _WorkUnit => prop_all;
- public property Schema => prop_all;
-}
-
-sub ObjectInfoById {
- my ($this,$oid) = @_;
-
- return $this->_ObjectCache->{$oid};
-}
-
-sub ObjectInfo {
- my ($this,$inst) = @_;
-
- die new IMPL::InvalidOperationException("This method can be used only for a reference") unless ref $inst;
-
- return $this->_MapInstances->{refaddr $inst};
-}
-
-
-1;
-__END__
-=pod
-=head1 SYNOPSIS
-
-use IMPL::ORM::Sql;
-
-my $DB = new IMPL::ORM::Sql("connection string");
-
-local $IMPL::ORM::Depth = 1; # load childs only, no more
-
-my $artist = $DB->Lookup( Artist => { name => 'Beatles' } );
-
-my $order = new Order();
-$order->AddItem($_) foreach $artist->Albums->List;
-
-$DB->Save($order);
-
-my $label = $artist->Albums->Index(0)->Label;
-
-$DB->Populate($label); #load $label
-
-=head1 DESCRIPTION
-=head2 MEMBERS
-=level 4
-=back
-=head2 Variables
-=head2 INTERNALS
-=head3 Object Representation
-
-Каждый класс отображаемый в источник данных представляется в виде набора
-сущностей, каждая из которых представляет состояние базового класса.
-
-Foo entityFoo
- Bar entityBar
- Baz entityBaz
-
-При сохранении виртуальных свойств классов в соответствующих сущностях заводится
-два поля - одно под сохранение собственного значения свойства, другое - для
-хренеия виртуального значения.
-
-Foo
- public virtual property Name => prop_all, {Type => String};
-
-entityFoo
- string m_Name - собственное значение
- string v_Name - вртуальное значение
-
-Каждый сохраненный объект в базе имеет собственный идентификатор.
-Новые объекты идентификатора не имеют, до тех пор пока они не будут сохранены.
-
-=head3 Object Cache
-
-Для учета объектов, которые присутствуют в источнике данных используется кеш
-объектов. Сюда попадают полученные из базы объекты, а также вновь добавленные
-объекты.
-
-ObjectInfo => {
- instance => weak ref
- _id => data source dependent id
- state => {persistent|null|new|deleted}
- work_unit => ref to the work unit where object is acting
-}
-
-данная структура доступна через две функции ObjectInfoById и ObjectInfo
-
-=head3 Type mapping
-
-Источник данных имеет в себе схему данных, которая определяет набор типов,
-хранимых в данном источнике. Есть несколько видов отображения типов:
-
-=level 4
-
-=item 1
-
-Отображение классов, когда класс рассмаривается в иде набора свойств
-
-=item
-
-Отображение классов в одно значение (напрмер строку, данные и т.п.)
-
-=item
-
-Классы, которые на прямую работают с источником данных, такие как коллекции.
-
-=back
-
-=cut
\ No newline at end of file
+package IMPL::ORM;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object);
+use IMPL::Class::Property;
+use Scalar::Util qw(weaken refaddr);
+
+use IMPL::Exception;
+
+our $Depth = 1; # загружать объект + 1 уровень детей
+our $UseProxy = 1;
+
+BEGIN {
+ private property _ObjectCache => prop_all;
+ private property _MapInstances => prop_all;
+ private property _WorkUnit => prop_all;
+ public property Schema => prop_all;
+}
+
+sub ObjectInfoById {
+ my ($this,$oid) = @_;
+
+ return $this->_ObjectCache->{$oid};
+}
+
+sub ObjectInfo {
+ my ($this,$inst) = @_;
+
+ die new IMPL::InvalidOperationException("This method can be used only for a reference") unless ref $inst;
+
+ return $this->_MapInstances->{refaddr $inst};
+}
+
+
+1;
+__END__
+=pod
+=head1 SYNOPSIS
+
+use IMPL::ORM::Sql;
+
+my $DB = new IMPL::ORM::Sql("connection string");
+
+local $IMPL::ORM::Depth = 1; # load childs only, no more
+
+my $artist = $DB->Lookup( Artist => { name => 'Beatles' } );
+
+my $order = new Order();
+$order->AddItem($_) foreach $artist->Albums->List;
+
+$DB->Save($order);
+
+my $label = $artist->Albums->Index(0)->Label;
+
+$DB->Populate($label); #load $label
+
+=head1 DESCRIPTION
+=head2 MEMBERS
+=level 4
+=back
+=head2 Variables
+=head2 INTERNALS
+=head3 Object Representation
+
+Каждый класс отображаемый в источник данных представляется в виде набора
+сущностей, каждая из которых представляет состояние базового класса.
+
+Foo entityFoo
+ Bar entityBar
+ Baz entityBaz
+
+При сохранении виртуальных свойств классов в соответствующих сущностях заводится
+два поля - одно под сохранение собственного значения свойства, другое - для
+хренеия виртуального значения.
+
+Foo
+ public virtual property Name => prop_all, {Type => String};
+
+entityFoo
+ string m_Name - собственное значение
+ string v_Name - вртуальное значение
+
+Каждый сохраненный объект в базе имеет собственный идентификатор.
+Новые объекты идентификатора не имеют, до тех пор пока они не будут сохранены.
+
+=head3 Object Cache
+
+Для учета объектов, которые присутствуют в источнике данных используется кеш
+объектов. Сюда попадают полученные из базы объекты, а также вновь добавленные
+объекты.
+
+ObjectInfo => {
+ instance => weak ref
+ _id => data source dependent id
+ state => {persistent|null|new|deleted}
+ work_unit => ref to the work unit where object is acting
+}
+
+данная структура доступна через две функции ObjectInfoById и ObjectInfo
+
+=head3 Type mapping
+
+Источник данных имеет в себе схему данных, которая определяет набор типов,
+хранимых в данном источнике. Есть несколько видов отображения типов:
+
+=level 4
+
+=item 1
+
+Отображение классов, когда класс рассмаривается в иде набора свойств
+
+=item
+
+Отображение классов в одно значение (напрмер строку, данные и т.п.)
+
+=item
+
+Классы, которые на прямую работают с источником данных, такие как коллекции.
+
+=back
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Entity.pm
--- a/Lib/IMPL/ORM/Entity.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Entity.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,48 +1,48 @@
-package IMPL::ORM::Entity;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-
-BEGIN {
- public _direct property Name => prop_get;
- public _direct property Class => prop_get;
- public _direct property Values => prop_get;
- public _direct property Schema => prop_get;
-}
-
-sub CTOR {
- my ($this,$class,$schema) = @_;
-
- $this->{$Class} = $class;
- (my $name = $class) =~ s/::/_/g;
- $this->{$Name} = $name;
- $this->Schema = $schema;
- $this->{$Values} = {
- map {$_->{name},{type => $_->{type}, virtual => $_->{virtual}}} @$schema
- };
-}
-
-sub Store;
-*Store = \&dbgStore;
-
-sub dbgStore {
- my ($this,$prop,$value) = @_;
-
- if ( my $container = $this->{$Values}{$prop} ) {
- $container->{oldValue} = $container->{value};
- $container->{value} = $value;
- } else {
- die new IMPL::InvalidOperationException("Property not found",$this->Name,$prop);
- }
-}
-
-sub Get {
- my ($this,$prop) = @_;
-
- return $this->{$Values}{$prop}{value};
-}
-
-1;
+package IMPL::ORM::Entity;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+
+BEGIN {
+ public _direct property Name => prop_get;
+ public _direct property Class => prop_get;
+ public _direct property Values => prop_get;
+ public _direct property Schema => prop_get;
+}
+
+sub CTOR {
+ my ($this,$class,$schema) = @_;
+
+ $this->{$Class} = $class;
+ (my $name = $class) =~ s/::/_/g;
+ $this->{$Name} = $name;
+ $this->Schema = $schema;
+ $this->{$Values} = {
+ map {$_->{name},{type => $_->{type}, virtual => $_->{virtual}}} @$schema
+ };
+}
+
+sub Store;
+*Store = \&dbgStore;
+
+sub dbgStore {
+ my ($this,$prop,$value) = @_;
+
+ if ( my $container = $this->{$Values}{$prop} ) {
+ $container->{oldValue} = $container->{value};
+ $container->{value} = $value;
+ } else {
+ die new IMPL::InvalidOperationException("Property not found",$this->Name,$prop);
+ }
+}
+
+sub Get {
+ my ($this,$prop) = @_;
+
+ return $this->{$Values}{$prop}{value};
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Helpers.pm
--- a/Lib/IMPL/ORM/Helpers.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Helpers.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,24 +1,24 @@
-package IMPL::ORM::Helpers;
-use strict;
-use warnings;
-
-require Exporter;
-our @ISA = qw(Exporter);
-our @EXPORT_OK = qw(&Map &Box);
-
-sub Map($$) {
- my ($TKey,$TValue) = @_;
-
- $TKey =~ s/:://g;
- $TValue =~ s/:://g;
-
- return "IMPL::ORM::Map::${TKey}${TValue}";
-}
-
-sub Box($) {
- my ($TValue) = @_;
- $TValue =~ s/:://g;
- return "IMPL::ORM::Box::$TValue";
-}
-
-1;
+package IMPL::ORM::Helpers;
+use strict;
+use warnings;
+
+require Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT_OK = qw(&Map &Box);
+
+sub Map($$) {
+ my ($TKey,$TValue) = @_;
+
+ $TKey =~ s/:://g;
+ $TValue =~ s/:://g;
+
+ return "IMPL::ORM::Map::${TKey}${TValue}";
+}
+
+sub Box($) {
+ my ($TValue) = @_;
+ $TValue =~ s/:://g;
+ return "IMPL::ORM::Box::$TValue";
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Object.pm
--- a/Lib/IMPL/ORM/Object.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Object.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,116 +1,116 @@
-package IMPL::ORM::Object;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-
-require IMPL::ORM::Entity;
-require IMPL::ORM::Schema::Entity;
-require IMPL::ORM::Schema::Field;
-require IMPL::ORM::Schema::Relation::HasMany;
-require IMPL::ORM::Schema::Relation::HasOne;
-require IMPL::ORM::Schema::Relation::Subclass;
-
-BEGIN {
- private _direct property _entities => prop_all;
- public property objectType => prop_all, {type => 'String'};
-
- sub _PropertyImplementor {
- 'IMPL::ORM::PropertyImplementor'
- }
-}
-
-my %schemaCache;
-
-sub CTOR {
- my ($this) = @_;
-
- while ( my ($class,$schema) = $this->ormGetSchema ) {
- $this->{$_entities}{$class} = new IMPL::ORM::Entity($class,$schema);
- }
-}
-
-sub ormStore {
- my ($this,$class,$prop,$value) = @_;
-
- die IMPL::InvalidOperationException("Cannot find entity for the specified class",$class) unless $this->{$_entities}{$class};
-
- $this->{$_entities}{$class}->Store($prop,$value);
-}
-
-sub ormGet {
- my ($this,$class,$prop,$value) = @_;
-
- return $this->{$_entities}{$class} ? $this->{$_entities}{$class}->Get($prop,$value) : undef;
-}
-
-sub entityName {
- (my $self = ref $_[0] || $_[0]) =~ s/^.*?(\w+)$/$1/;
- return $self;
-}
-
-sub ormGetSchema {
- my ($self,$dataSchema,$surrogate) = @_;
-
- my $schema = $surrogate || IMPL::ORM::Schema::Entity->new($self->entityName);
-
- # для текущего класса, проходим по всем свойствам
- foreach my $ormProp (
- $self->get_meta(
- 'IMPL::Class::PropertyInfo',
- sub {
- UNIVERSAL::isa($_->Implementor, 'IMPL::ORM::PropertyImplementor' )
- },
- 0
- )
- ){
- if ($ormProp->Mutators & prop_list) {
- # отношение 1 ко многим
- my $type = $dataSchema->resolveType($ormProp->Type) or die new IMPL::InvalidOperationException("Failed to resolve a reference type due building schema for a class", $ormProp->Class, $ormProp->Name);
- $schema->appendChild( new IMPL::ORM::Schema::Relation::HasMany($ormProp->Name, $type->entityName) );
- } elsif (my $type = $dataSchema->isValueType($ormProp->Type)) {
- # поле
- $schema->appendChild( new IMPL::ORM::Schema::Field($ormProp->Name,$ormProp->Type) );
- } elsif (my $entity = $dataSchema->resolveType($ormProp->Type)) {
- # отношение ссылка
- $schema->appendChild( new IMPL::ORM::Schema::Relation::HasOne($ormProp->Name,$entity->entityName));
- } else {
- # хз что. Скорее всего не удалось квалифицировать тип свойства не как ссылочный и как поле.
- die new IMPL::Exception('Uexpected error due building schema for a class', $ormProp->Class, $ormProp->Name,$ormProp->Type);
- }
- }
-
- # Формируем отношения наследования
- {
- # локализуем прагму
- no strict 'refs';
-
- my $class = ref $self || $self;
-
- # по всем классам
- foreach my $super (grep $_->isa(__PACKAGE__), @{"${class}::ISA"}) {
- my $type = $dataSchema->resolveType($super) or die new IMPL::InvalidOperationException("Failed to resolve a super class due building schema for a class", $class, $super);
- $schema->appendChild(new IMPL::ORM::Schema::Relation::Subclass($type));
- }
- }
-
- return $schema;
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-Базовый объект для реляционного отображения,
-содержит в себе реляционные записи представляющие данный объект.
-
-Каждый класс отображается в определенную сущность. Сущности хранят
-состояние объектов в том виде в котором удобно записывать в реляционную базу.
-
-=cut
\ No newline at end of file
+package IMPL::ORM::Object;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object);
+use IMPL::Class::Property;
+use IMPL::Class::Property::Direct;
+
+require IMPL::ORM::Entity;
+require IMPL::ORM::Schema::Entity;
+require IMPL::ORM::Schema::Field;
+require IMPL::ORM::Schema::Relation::HasMany;
+require IMPL::ORM::Schema::Relation::HasOne;
+require IMPL::ORM::Schema::Relation::Subclass;
+
+BEGIN {
+ private _direct property _entities => prop_all;
+ public property objectType => prop_all, {type => 'String'};
+
+ sub _PropertyImplementor {
+ 'IMPL::ORM::PropertyImplementor'
+ }
+}
+
+my %schemaCache;
+
+sub CTOR {
+ my ($this) = @_;
+
+ while ( my ($class,$schema) = $this->ormGetSchema ) {
+ $this->{$_entities}{$class} = new IMPL::ORM::Entity($class,$schema);
+ }
+}
+
+sub ormStore {
+ my ($this,$class,$prop,$value) = @_;
+
+ die IMPL::InvalidOperationException("Cannot find entity for the specified class",$class) unless $this->{$_entities}{$class};
+
+ $this->{$_entities}{$class}->Store($prop,$value);
+}
+
+sub ormGet {
+ my ($this,$class,$prop,$value) = @_;
+
+ return $this->{$_entities}{$class} ? $this->{$_entities}{$class}->Get($prop,$value) : undef;
+}
+
+sub entityName {
+ (my $self = ref $_[0] || $_[0]) =~ s/^.*?(\w+)$/$1/;
+ return $self;
+}
+
+sub ormGetSchema {
+ my ($self,$dataSchema,$surrogate) = @_;
+
+ my $schema = $surrogate || IMPL::ORM::Schema::Entity->new($self->entityName);
+
+ # для текущего класса, проходим по всем свойствам
+ foreach my $ormProp (
+ $self->get_meta(
+ 'IMPL::Class::PropertyInfo',
+ sub {
+ UNIVERSAL::isa($_->Implementor, 'IMPL::ORM::PropertyImplementor' )
+ },
+ 0
+ )
+ ){
+ if ($ormProp->Mutators & prop_list) {
+ # отношение 1 ко многим
+ my $type = $dataSchema->resolveType($ormProp->Type) or die new IMPL::InvalidOperationException("Failed to resolve a reference type due building schema for a class", $ormProp->Class, $ormProp->Name);
+ $schema->appendChild( new IMPL::ORM::Schema::Relation::HasMany($ormProp->Name, $type->entityName) );
+ } elsif (my $type = $dataSchema->isValueType($ormProp->Type)) {
+ # поле
+ $schema->appendChild( new IMPL::ORM::Schema::Field($ormProp->Name,$ormProp->Type) );
+ } elsif (my $entity = $dataSchema->resolveType($ormProp->Type)) {
+ # отношение ссылка
+ $schema->appendChild( new IMPL::ORM::Schema::Relation::HasOne($ormProp->Name,$entity->entityName));
+ } else {
+ # хз что. Скорее всего не удалось квалифицировать тип свойства не как ссылочный и как поле.
+ die new IMPL::Exception('Uexpected error due building schema for a class', $ormProp->Class, $ormProp->Name,$ormProp->Type);
+ }
+ }
+
+ # Формируем отношения наследования
+ {
+ # локализуем прагму
+ no strict 'refs';
+
+ my $class = ref $self || $self;
+
+ # по всем классам
+ foreach my $super (grep $_->isa(__PACKAGE__), @{"${class}::ISA"}) {
+ my $type = $dataSchema->resolveType($super) or die new IMPL::InvalidOperationException("Failed to resolve a super class due building schema for a class", $class, $super);
+ $schema->appendChild(new IMPL::ORM::Schema::Relation::Subclass($type));
+ }
+ }
+
+ return $schema;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Базовый объект для реляционного отображения,
+содержит в себе реляционные записи представляющие данный объект.
+
+Каждый класс отображается в определенную сущность. Сущности хранят
+состояние объектов в том виде в котором удобно записывать в реляционную базу.
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/PropertyImplementor.pm
--- a/Lib/IMPL/ORM/PropertyImplementor.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/PropertyImplementor.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,8 +1,8 @@
-package IMPL::ORM::PropertyImplementor;
-use strict;
-use warnings;
-
-use base qw(IMPL::Class::Property::Direct);
-
-
-1;
+package IMPL::ORM::PropertyImplementor;
+use strict;
+use warnings;
+
+use base qw(IMPL::Class::Property::Direct);
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Schema.pm
--- a/Lib/IMPL/ORM/Schema.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Schema.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,145 +1,145 @@
-package IMPL::ORM::Schema;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Document);
-use IMPL::Class::Property;
-require IMPL::ORM::Schema::Entity;
-require IMPL::ORM::Schema::ValueType;
-
-our %CTOR = (
- 'IMPL::DOM::Document' => sub { nodeName => 'ORMSchema' }
-);
-
-BEGIN {
- public property mapValueTypes => prop_get | owner_set;
- public property mapReferenceTypes => prop_get | owner_set;
- public property mapPending => prop_get | owner_set;
- public property prefix => prop_get | owner_set;
-}
-
-sub CTOR {
- my ($this ) = @_;
- $this->mapValueTypes({});
- $this->mapReferenceTypes({});
- $this->mapPending({});
-}
-
-# return an entity for the specified typename
-# makes forward declaration if nesessary
-sub resolveType {
- my ($this,$typeName) = @_;
-
- $this = ref $this ? $this : $this->instance;
-
- if (my $entity = $this->mapReferenceTypes->{$typeName}) {
- return $entity;
- } elsif (UNIVERSAL::isa($typeName,'IMPL::ORM::Object')) {
- return $this->declareReferenceType($typeName);
- } else {
- return undef;
- }
-}
-
-sub declareReferenceType {
- my ($this,$typeName) = @_;
-
- my $entity = new IMPL::ORM::Schema::Entity($typeName->entityName);
-
- $this->mapPending->{$typeName} = $entity;
-
- $this->appendChild($entity);
-
- return $this->mapReferenceTypes->{$typeName} = $entity;
-}
-
-sub _addReferenceType {
- my ($this,$className) = @_;
-
- if ( my $entity = delete $this->mapPending->{$className} ) {
- $className->ormGetSchema($this,$entity);
- } else {
- return $this->appendChild( $this->mapReferenceTypes->{$className} = $className->ormGetSchema($this) );
- }
-
-}
-
-# returns valuetype name
-sub isValueType {
- my ($this,$typeName) = @_;
-
- $this = ref $this ? $this : $this->instance;
-
- return $this->mapValueTypes->{$typeName};
-}
-
-my %instances;
-sub instance {
- my ($class) = @_;
-
- return ($instances{$class} || ($instances{$class} = $class->new));
-}
-
-sub ValueTypes {
- my ($this,%classes) = @_;
-
- $this = ref $this ? $this : $this->instance;
-
- while ( my ($typeName,$typeReflected) = each %classes ) {
- $this->mapValueTypes->{$typeName} = $typeReflected;
- $this->appendChild(IMPL::ORM::Schema::ValueType->new($typeName,$typeReflected));
- }
-}
-
-sub Classes {
- my ($this,@classNames) = @_;
-
- $this = ref $this ? $this : $this->instance;
-
- $this->_addReferenceType($this->prefix . $_) foreach @classNames;
-}
-
-sub usePrefix {
- my ($this,$prefix) = @_;
-
- $prefix .= '::' if $prefix and $prefix !~ /::$/;
-
- (ref $this ? $this : $this->instance)->prefix($prefix);
-}
-
-sub CompleteSchema {
- my ($this) = @_;
-
- $this = ref $this ? $this : $this->instance;
-
- $_->ormGetSchema($this,delete $this->mapPending->{$_}) foreach (keys %{$this->mapPending});
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-
-Схема данных, представляет собой DOM документ, элементами которой
-являются сущности.
-
-Каждый узел - это описание сущности.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-=cut
\ No newline at end of file
+package IMPL::ORM::Schema;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Document);
+use IMPL::Class::Property;
+require IMPL::ORM::Schema::Entity;
+require IMPL::ORM::Schema::ValueType;
+
+our %CTOR = (
+ 'IMPL::DOM::Document' => sub { nodeName => 'ORMSchema' }
+);
+
+BEGIN {
+ public property mapValueTypes => prop_get | owner_set;
+ public property mapReferenceTypes => prop_get | owner_set;
+ public property mapPending => prop_get | owner_set;
+ public property prefix => prop_get | owner_set;
+}
+
+sub CTOR {
+ my ($this ) = @_;
+ $this->mapValueTypes({});
+ $this->mapReferenceTypes({});
+ $this->mapPending({});
+}
+
+# return an entity for the specified typename
+# makes forward declaration if nesessary
+sub resolveType {
+ my ($this,$typeName) = @_;
+
+ $this = ref $this ? $this : $this->instance;
+
+ if (my $entity = $this->mapReferenceTypes->{$typeName}) {
+ return $entity;
+ } elsif (UNIVERSAL::isa($typeName,'IMPL::ORM::Object')) {
+ return $this->declareReferenceType($typeName);
+ } else {
+ return undef;
+ }
+}
+
+sub declareReferenceType {
+ my ($this,$typeName) = @_;
+
+ my $entity = new IMPL::ORM::Schema::Entity($typeName->entityName);
+
+ $this->mapPending->{$typeName} = $entity;
+
+ $this->appendChild($entity);
+
+ return $this->mapReferenceTypes->{$typeName} = $entity;
+}
+
+sub _addReferenceType {
+ my ($this,$className) = @_;
+
+ if ( my $entity = delete $this->mapPending->{$className} ) {
+ $className->ormGetSchema($this,$entity);
+ } else {
+ return $this->appendChild( $this->mapReferenceTypes->{$className} = $className->ormGetSchema($this) );
+ }
+
+}
+
+# returns valuetype name
+sub isValueType {
+ my ($this,$typeName) = @_;
+
+ $this = ref $this ? $this : $this->instance;
+
+ return $this->mapValueTypes->{$typeName};
+}
+
+my %instances;
+sub instance {
+ my ($class) = @_;
+
+ return ($instances{$class} || ($instances{$class} = $class->new));
+}
+
+sub ValueTypes {
+ my ($this,%classes) = @_;
+
+ $this = ref $this ? $this : $this->instance;
+
+ while ( my ($typeName,$typeReflected) = each %classes ) {
+ $this->mapValueTypes->{$typeName} = $typeReflected;
+ $this->appendChild(IMPL::ORM::Schema::ValueType->new($typeName,$typeReflected));
+ }
+}
+
+sub Classes {
+ my ($this,@classNames) = @_;
+
+ $this = ref $this ? $this : $this->instance;
+
+ $this->_addReferenceType($this->prefix . $_) foreach @classNames;
+}
+
+sub usePrefix {
+ my ($this,$prefix) = @_;
+
+ $prefix .= '::' if $prefix and $prefix !~ /::$/;
+
+ (ref $this ? $this : $this->instance)->prefix($prefix);
+}
+
+sub CompleteSchema {
+ my ($this) = @_;
+
+ $this = ref $this ? $this : $this->instance;
+
+ $_->ormGetSchema($this,delete $this->mapPending->{$_}) foreach (keys %{$this->mapPending});
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Схема данных, представляет собой DOM документ, элементами которой
+являются сущности.
+
+Каждый узел - это описание сущности.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Schema/Entity.pm
--- a/Lib/IMPL/ORM/Schema/Entity.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Schema/Entity.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,24 +1,24 @@
-package IMPL::ORM::Schema::Entity;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Node);
-use IMPL::Class::Property;
-
-BEGIN {
- public property entityName => prop_get | owner_set;
-}
-
-our %CTOR = (
- 'IMPL::DOM::Node' => sub {
- nodeName => 'Entity'
- }
-);
-
-sub CTOR {
- my ($this,$name) = @_;
-
- $this->entityName($name);
-}
-
-1;
+package IMPL::ORM::Schema::Entity;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Node);
+use IMPL::Class::Property;
+
+BEGIN {
+ public property entityName => prop_get | owner_set;
+}
+
+our %CTOR = (
+ 'IMPL::DOM::Node' => sub {
+ nodeName => 'Entity'
+ }
+);
+
+sub CTOR {
+ my ($this,$name) = @_;
+
+ $this->entityName($name);
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Schema/Field.pm
--- a/Lib/IMPL/ORM/Schema/Field.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Schema/Field.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,30 +1,30 @@
-package IMPL::ORM::Schema::Field;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Node);
-use IMPL::Class::Property;
-
-BEGIN {
- public property fieldName => prop_get | owner_set;
- public property fieldType => prop_get | owner_set;
- public property fieldNullbale => prop_get | owner_set;
-}
-
-our %CTOR = (
- 'IMPL::DOM::Node' => sub { nodeName => 'Field' }
-);
-
-sub CTOR {
- my ($this,$name,$type,$nullable) = @_;
-
- $this->fieldName($name) or die new IMPL::InvalidArgumentException('A name is required for the field');
- $this->fieldType($type) or die new IMPL::InvalidArgumentException('A type is required for the field');
- $this->fieldNullbale(1) if $nullable;
-}
-
-sub canHaveChildren {
- 0;
-}
-
-1;
+package IMPL::ORM::Schema::Field;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Node);
+use IMPL::Class::Property;
+
+BEGIN {
+ public property fieldName => prop_get | owner_set;
+ public property fieldType => prop_get | owner_set;
+ public property fieldNullbale => prop_get | owner_set;
+}
+
+our %CTOR = (
+ 'IMPL::DOM::Node' => sub { nodeName => 'Field' }
+);
+
+sub CTOR {
+ my ($this,$name,$type,$nullable) = @_;
+
+ $this->fieldName($name) or die new IMPL::InvalidArgumentException('A name is required for the field');
+ $this->fieldType($type) or die new IMPL::InvalidArgumentException('A type is required for the field');
+ $this->fieldNullbale(1) if $nullable;
+}
+
+sub canHaveChildren {
+ 0;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Schema/Relation.pm
--- a/Lib/IMPL/ORM/Schema/Relation.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Schema/Relation.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,12 +1,12 @@
-package IMPL::ORM::Schema::Relation;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Node);
-
-our %CTOR =(
- 'IMPL::DOM::Node' => sub { nodeName => $_[0] }
-);
-
-
-1;
+package IMPL::ORM::Schema::Relation;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Node);
+
+our %CTOR =(
+ 'IMPL::DOM::Node' => sub { nodeName => $_[0] }
+);
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Schema/Relation/HasMany.pm
--- a/Lib/IMPL/ORM/Schema/Relation/HasMany.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Schema/Relation/HasMany.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,27 +1,27 @@
-package IMPL::ORM::Schema::Relation::HasMany;
-use strict;
-use warnings;
-
-use base qw(IMPL::ORM::Schema::Relation);
-use IMPL::Class::Property;
-
-BEGIN {
- public property target => prop_get | owner_set;
- public property name => prop_get | owner_set;
-}
-
-our %CTOR = (
- 'IMPL::ORM::Schema::Relation' => sub { 'HasMany' }
-);
-
-sub CTOR {
- my ($this,$name,$target) = @_;
- $this->name($name) or die new IMPL::InvalidArgumentException('A name is required for this relation');
- $this->target($target) or die new IMPL::InvalidArgumentException('A target is required for this relation',$name);
-}
-
-sub canHaveChildren {
- 0;
-}
-
-1;
+package IMPL::ORM::Schema::Relation::HasMany;
+use strict;
+use warnings;
+
+use base qw(IMPL::ORM::Schema::Relation);
+use IMPL::Class::Property;
+
+BEGIN {
+ public property target => prop_get | owner_set;
+ public property name => prop_get | owner_set;
+}
+
+our %CTOR = (
+ 'IMPL::ORM::Schema::Relation' => sub { 'HasMany' }
+);
+
+sub CTOR {
+ my ($this,$name,$target) = @_;
+ $this->name($name) or die new IMPL::InvalidArgumentException('A name is required for this relation');
+ $this->target($target) or die new IMPL::InvalidArgumentException('A target is required for this relation',$name);
+}
+
+sub canHaveChildren {
+ 0;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Schema/Relation/HasOne.pm
--- a/Lib/IMPL/ORM/Schema/Relation/HasOne.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Schema/Relation/HasOne.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,28 +1,28 @@
-package IMPL::ORM::Schema::Relation::HasOne;
-use strict;
-use warnings;
-
-use base qw(IMPL::ORM::Schema::Relation);
-use IMPL::Class::Property;
-
-BEGIN {
- public property target => prop_get | owner_set;
- public property name => prop_get | owner_set;
-}
-
-our %CTOR = (
- 'IMPL::ORM::Schema::Relation' => sub { 'HasOne' }
-);
-
-sub CTOR {
- my ($this,$name,$target) = @_;
- $this->name($name) or die new IMPL::InvalidArgumentException('A name is required for this relation');
- $this->target($target) or die new IMPL::InvalidArgumentException('A target is required for this relation',$name);
-}
-
-sub canHaveChildren {
- 0;
-}
-
-
-1;
+package IMPL::ORM::Schema::Relation::HasOne;
+use strict;
+use warnings;
+
+use base qw(IMPL::ORM::Schema::Relation);
+use IMPL::Class::Property;
+
+BEGIN {
+ public property target => prop_get | owner_set;
+ public property name => prop_get | owner_set;
+}
+
+our %CTOR = (
+ 'IMPL::ORM::Schema::Relation' => sub { 'HasOne' }
+);
+
+sub CTOR {
+ my ($this,$name,$target) = @_;
+ $this->name($name) or die new IMPL::InvalidArgumentException('A name is required for this relation');
+ $this->target($target) or die new IMPL::InvalidArgumentException('A target is required for this relation',$name);
+}
+
+sub canHaveChildren {
+ 0;
+}
+
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Schema/Relation/Subclass.pm
--- a/Lib/IMPL/ORM/Schema/Relation/Subclass.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Schema/Relation/Subclass.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,26 +1,26 @@
-package IMPL::ORM::Schema::Relation::Subclass;
-use strict;
-use warnings;
-
-use base qw(IMPL::ORM::Schema::Relation);
-use IMPL::Class::Property;
-
-BEGIN {
- public property base => prop_get | owner_set;
-}
-
-our %CTOR = (
- 'IMPL::ORM::Schema::Relation' => sub { 'Subclass' }
-);
-
-sub CTOR {
- my ($this,$base) = @_;
-
- $this->base($base) or die new IMPL::InvalidArgumentException('A base is required for this relation');
-}
-
-sub canHaveChildren {
- 0;
-}
-
-1;
+package IMPL::ORM::Schema::Relation::Subclass;
+use strict;
+use warnings;
+
+use base qw(IMPL::ORM::Schema::Relation);
+use IMPL::Class::Property;
+
+BEGIN {
+ public property base => prop_get | owner_set;
+}
+
+our %CTOR = (
+ 'IMPL::ORM::Schema::Relation' => sub { 'Subclass' }
+);
+
+sub CTOR {
+ my ($this,$base) = @_;
+
+ $this->base($base) or die new IMPL::InvalidArgumentException('A base is required for this relation');
+}
+
+sub canHaveChildren {
+ 0;
+}
+
+1;
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Schema/TransformToSQL.pm
--- a/Lib/IMPL/ORM/Schema/TransformToSQL.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Schema/TransformToSQL.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,177 +1,177 @@
-package IMPL::ORM::Schema::TransformToSQL;
-use strict;
-use warnings;
-
-use base qw(IMPL::DOM::Transform);
-use IMPL::Class::Property;
-use IMPL::SQL::Types qw(DateTime Varchar Integer Float Text Binary);
-
-require IMPL::SQL::Schema;
-
-BEGIN {
- public property Types => prop_get | owner_set;
-}
-
-our %CTOR = (
- 'IMPL::DOM::Transform' => sub {
- ORMSchema => \&ORMSchemaTransform,
- Entity => \&EntityTransform,
- Field => \&FieldTransform,
- HasOne => \&HasOneTransform,
- HasMany => \&HasManyTransform,
- Subclass => \&SubclassTransform,
- ValueType => sub {}
- }
-);
-
-sub CTOR {
- my ($this,$refTypeMap) = @_;
-
- $this->Types($refTypeMap) or die new IMPL::InvalidArgumentException("A reference to the type map hash is required");
-}
-
-sub ORMSchemaTransform {
- my ($this,$node) = @_;
-
- my $schema = IMPL::SQL::Schema->new(Name => ref $node);
-
- my @constraints;
-
- my %ctx = (Schema => $schema);
-
- # all tables
- foreach my $entity ($node->selectNodes('Entity')) {
- $schema->AddTable($this->Transform($entity,\%ctx));
- push @constraints, $entity->selectNodes(sub {$_->isa('IMPL::ORM::Schema::Relation')});
- }
-
- # establish relations
- $this->Transform($_,\%ctx) foreach @constraints;
-
- return $schema;
-}
-
-sub EntityTransform {
- my ($this,$node,$ctx) = @_;
-
- my $table = IMPL::SQL::Schema::Table->new(Name => $node->entityName, Schema => $ctx->{Schema});
-
- $this->MakePrimaryKey($table);
-
- $table->InsertColumn( $this->Transform($_,$ctx)) foreach$node->selectNodes('Field');
-
- return $table;
-}
-
-sub FieldTransform {
- my ($this,$field,$ctx) = @_;
-
- return {
- Name => $field->fieldName,
- Type => $this->MapType($field->fieldType) || die new IMPL::Exception("Can't get map a rom schema type to the SQL type",$field->fieldType),
- CanBeNull => $field->fieldNullable
- };
-}
-
-sub HasOneTransform {
- my ($this,$relation,$ctx) = @_;
-
- my $sqlSchema = $ctx->{Schema};
- my $table = $sqlSchema->Tables->{$relation->parentNode->entityName};
- my $tableForeign = $sqlSchema->Tables->{$relation->target};
- my $prefix = $relation->name;
-
- my @fkColumns = @{$tableForeign->PrimaryKey->Columns};
-
- if (@fkColumns > 1) {
- @fkColumns = map
- $table->InsertColumn({
- Name => $prefix . $_->Name,
- Type => $_->Type,
- CanBeNull => 1
- }), @fkColumns;
- } else {
- @fkColumns = $table->InsertColumn({
- Name => $prefix,
- Type => $fkColumns[0]->Type,
- CanBeNull => 1
- });
- }
-
- $table->LinkTo($tableForeign,@fkColumns);
-}
-
-sub HasManyTransform {
- my ($this,$relation,$ctx) = @_;
-
- #similar to HasOne
-
- my $sqlSchema = $ctx->{Schema};
- my $table = $sqlSchema->Tables->{$relation->parentNode->entityName};
- my $tableForeign = $sqlSchema->Tables->{$relation->target};
- my $prefix = $relation->name;
-
- my @fkColumns = @{$table->PrimaryKey->Columns};
-
- if (@fkColumns > 1 ) {
- @fkColumns = map $tableForeign->InsertColumn({
- Name => $prefix . $_->Name,
- Type => $_->Type,
- CanBeNull => 1
- }), @fkColumns;
- } else {
- @fkColumns = $tableForeign->InsertColumn({
- Name => $prefix,
- Type => $fkColumns[0]->Type,
- CanBeNull => 1
- });
- }
-
- $tableForeign->LinkTo($table,@fkColumns);
-}
-
-sub SubclassTransform {
- # actually this rlations has only logical implementation
-}
-
-sub MapType {
- my ($this,$typeName) = @_;
-
- $this->Types->{$typeName} || die new IMPL::Exception("Can't map a type",$typeName);
-}
-
-sub MakePrimaryKey {
- my ($this,$table) = @_;
-
- $table->InsertColumn( {Name => '_Id', Type => Integer } );
- $table->SetPrimaryKey('_Id');
-}
-
-{
- my $std;
- sub Std {
- $std ||= __PACKAGE__->new({
- String => Varchar(255),
- DateTime => DateTime,
- Integer => Integer,
- Float => Float(24),
- Decimal => Float(53),
- Real => Float(24),
- Binary => Binary,
- Text => Text
- });
- }
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 SYNOPSIS
-
-my $sqlSchema = IMPL::ORM::Schema::TransformToSQL->Default->Transform(Data::Schema->instance);
-
-=cut
-
+package IMPL::ORM::Schema::TransformToSQL;
+use strict;
+use warnings;
+
+use base qw(IMPL::DOM::Transform);
+use IMPL::Class::Property;
+use IMPL::SQL::Types qw(DateTime Varchar Integer Float Text Binary);
+
+require IMPL::SQL::Schema;
+
+BEGIN {
+ public property Types => prop_get | owner_set;
+}
+
+our %CTOR = (
+ 'IMPL::DOM::Transform' => sub {
+ ORMSchema => \&ORMSchemaTransform,
+ Entity => \&EntityTransform,
+ Field => \&FieldTransform,
+ HasOne => \&HasOneTransform,
+ HasMany => \&HasManyTransform,
+ Subclass => \&SubclassTransform,
+ ValueType => sub {}
+ }
+);
+
+sub CTOR {
+ my ($this,$refTypeMap) = @_;
+
+ $this->Types($refTypeMap) or die new IMPL::InvalidArgumentException("A reference to the type map hash is required");
+}
+
+sub ORMSchemaTransform {
+ my ($this,$node) = @_;
+
+ my $schema = IMPL::SQL::Schema->new(Name => ref $node);
+
+ my @constraints;
+
+ my %ctx = (Schema => $schema);
+
+ # all tables
+ foreach my $entity ($node->selectNodes('Entity')) {
+ $schema->AddTable($this->Transform($entity,\%ctx));
+ push @constraints, $entity->selectNodes(sub {$_->isa('IMPL::ORM::Schema::Relation')});
+ }
+
+ # establish relations
+ $this->Transform($_,\%ctx) foreach @constraints;
+
+ return $schema;
+}
+
+sub EntityTransform {
+ my ($this,$node,$ctx) = @_;
+
+ my $table = IMPL::SQL::Schema::Table->new(Name => $node->entityName, Schema => $ctx->{Schema});
+
+ $this->MakePrimaryKey($table);
+
+ $table->InsertColumn( $this->Transform($_,$ctx)) foreach$node->selectNodes('Field');
+
+ return $table;
+}
+
+sub FieldTransform {
+ my ($this,$field,$ctx) = @_;
+
+ return {
+ Name => $field->fieldName,
+ Type => $this->MapType($field->fieldType) || die new IMPL::Exception("Can't get map a rom schema type to the SQL type",$field->fieldType),
+ CanBeNull => $field->fieldNullable
+ };
+}
+
+sub HasOneTransform {
+ my ($this,$relation,$ctx) = @_;
+
+ my $sqlSchema = $ctx->{Schema};
+ my $table = $sqlSchema->Tables->{$relation->parentNode->entityName};
+ my $tableForeign = $sqlSchema->Tables->{$relation->target};
+ my $prefix = $relation->name;
+
+ my @fkColumns = @{$tableForeign->PrimaryKey->Columns};
+
+ if (@fkColumns > 1) {
+ @fkColumns = map
+ $table->InsertColumn({
+ Name => $prefix . $_->Name,
+ Type => $_->Type,
+ CanBeNull => 1
+ }), @fkColumns;
+ } else {
+ @fkColumns = $table->InsertColumn({
+ Name => $prefix,
+ Type => $fkColumns[0]->Type,
+ CanBeNull => 1
+ });
+ }
+
+ $table->LinkTo($tableForeign,@fkColumns);
+}
+
+sub HasManyTransform {
+ my ($this,$relation,$ctx) = @_;
+
+ #similar to HasOne
+
+ my $sqlSchema = $ctx->{Schema};
+ my $table = $sqlSchema->Tables->{$relation->parentNode->entityName};
+ my $tableForeign = $sqlSchema->Tables->{$relation->target};
+ my $prefix = $relation->name;
+
+ my @fkColumns = @{$table->PrimaryKey->Columns};
+
+ if (@fkColumns > 1 ) {
+ @fkColumns = map $tableForeign->InsertColumn({
+ Name => $prefix . $_->Name,
+ Type => $_->Type,
+ CanBeNull => 1
+ }), @fkColumns;
+ } else {
+ @fkColumns = $tableForeign->InsertColumn({
+ Name => $prefix,
+ Type => $fkColumns[0]->Type,
+ CanBeNull => 1
+ });
+ }
+
+ $tableForeign->LinkTo($table,@fkColumns);
+}
+
+sub SubclassTransform {
+ # actually this rlations has only logical implementation
+}
+
+sub MapType {
+ my ($this,$typeName) = @_;
+
+ $this->Types->{$typeName} || die new IMPL::Exception("Can't map a type",$typeName);
+}
+
+sub MakePrimaryKey {
+ my ($this,$table) = @_;
+
+ $table->InsertColumn( {Name => '_Id', Type => Integer } );
+ $table->SetPrimaryKey('_Id');
+}
+
+{
+ my $std;
+ sub Std {
+ $std ||= __PACKAGE__->new({
+ String => Varchar(255),
+ DateTime => DateTime,
+ Integer => Integer,
+ Float => Float(24),
+ Decimal => Float(53),
+ Real => Float(24),
+ Binary => Binary,
+ Text => Text
+ });
+ }
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 SYNOPSIS
+
+my $sqlSchema = IMPL::ORM::Schema::TransformToSQL->Default->Transform(Data::Schema->instance);
+
+=cut
+
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Schema/ValueType.pm
--- a/Lib/IMPL/ORM/Schema/ValueType.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Schema/ValueType.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,31 +1,31 @@
-package IMPL::ORM::Schema::ValueType;
-
-use strict;
-
-use base qw(IMPL::DOM::Node);
-
-our %CTOR = (
- 'IMPL::DOM::Node' => sub { nodeName => 'ValueType' }
-);
-
-use IMPL::Class::Property;
-
-BEGIN {
- public property typeName => prop_all;
- public property typeReflected => prop_all;
-}
-
-sub CTOR {
- my ($this,$typeName,$typeReflected) = @_;
-
- $this->typeName($typeName);
- $this->typeReflected($typeReflected);
-}
-
-1;
-
-__END__
-
-=pod
-
-=cut
\ No newline at end of file
+package IMPL::ORM::Schema::ValueType;
+
+use strict;
+
+use base qw(IMPL::DOM::Node);
+
+our %CTOR = (
+ 'IMPL::DOM::Node' => sub { nodeName => 'ValueType' }
+);
+
+use IMPL::Class::Property;
+
+BEGIN {
+ public property typeName => prop_all;
+ public property typeReflected => prop_all;
+}
+
+sub CTOR {
+ my ($this,$typeName,$typeReflected) = @_;
+
+ $this->typeName($typeName);
+ $this->typeReflected($typeReflected);
+}
+
+1;
+
+__END__
+
+=pod
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/ORM/Store/SQL.pm
--- a/Lib/IMPL/ORM/Store/SQL.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/ORM/Store/SQL.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,30 +1,30 @@
-package IMPL::ORM::Store::SQL;
-use strict;
-use warnings;
-
-use base qw(IMPL::Object);
-
-use IMPL::Class::Property;
-
-BEGIN {
- public property Connection => prop_all;
-}
-
-sub loadObjects {
- my ($this,$rObjects) = @_;
-}
-
-sub search {
- my ($this,$query) = @_;
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 DESCRIPTION
-Драйвер для SQL баз данных.
-
-=cut
\ No newline at end of file
+package IMPL::ORM::Store::SQL;
+use strict;
+use warnings;
+
+use base qw(IMPL::Object);
+
+use IMPL::Class::Property;
+
+BEGIN {
+ public property Connection => prop_all;
+}
+
+sub loadObjects {
+ my ($this,$rObjects) = @_;
+}
+
+sub search {
+ my ($this,$query) = @_;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+Драйвер для SQL баз данных.
+
+=cut
diff -r 1c3c3e63a314 -r 16ada169ca75 Lib/IMPL/Object.pm
--- a/Lib/IMPL/Object.pm Fri Feb 26 01:43:42 2010 +0300
+++ b/Lib/IMPL/Object.pm Fri Feb 26 10:49:21 2010 +0300
@@ -1,103 +1,103 @@
-package IMPL::Object;
-use strict;
-
-use base qw(IMPL::Object::Abstract);
-
-sub surrogate {
- bless {}, ref $_[0] || $_[0];
-}
-
-sub new {
- my $class = shift;
- my $self = bless {}, ref($class) || $class;
- $self->callCTOR(@_);
-
- $self;
-}
-
-sub _PropertyImplementor {
- 'IMPL::Class::Property::Direct'
-}
-
-=pod
-=h1 SYNOPSIS
-
-package Foo;
-use base qw(IMPL::Object);
-
-sub CTOR {
- my ($this,$arg) = @_;
- print "Foo: $arg\n";
-}
-
-package Bar;
-use base qw(IMPL::Object);
-
-sub CTOR {
- my ($this,$arg) = @_;
- print "Bar: $arg\n";
-}
-
-package Baz;
-use base qw(Foo Bar);
-
-our %CTOR = (
- Foo => sub { my %args = @_; $args{Mazzi}; },
- Bar => sub { my %args = @_; $args{Fugi}; }
-);
-
-package Composite;
-use base qw(Baz Foo Bar);
-
-our %CTOR = (
- Foo => undef,
- Bar => undef
-);
-
-sub CTOR {
- my ($this,%args) = @_;
-
- print "Composite: $args{Text}\n";
-}
-
-package main;
-
-my $obj = new Composite(
- Text => 'Hello World!',
- Mazzi => 'Mazzi',
- Fugi => 'Fugi'
-);
-
-# will print
-#
-# Foo: Mazzi
-# Bar: Fugi
-# Bar:
-# Composite: Hello World!
-
-=h1 Description
-Базовый класс для объектов, основанных на хеше.
-
-=h1 Members
-
-=level 4
-
-=item operator C(@args)
-
-Создает экземпляр объекта и вызывает конструктор с параметрами @args.
-
-=item operator C()
-
-Создает неинициализированный экземпляр объекта.
-
-=back
-
-=р1 Cavearts
-
-Нужно заметить, что директива C