Mercurial > pub > Impl
comparison Lib/Common.pm @ 0:03e58a454b20
Создан репозитарий
| author | Sergey |
|---|---|
| date | Tue, 14 Jul 2009 12:54:37 +0400 |
| parents | |
| children | 16ada169ca75 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:03e58a454b20 |
|---|---|
| 1 package Common; | |
| 2 use strict; | |
| 3 no strict 'refs'; | |
| 4 | |
| 5 require Exporter; | |
| 6 | |
| 7 our @ISA = qw(Exporter); | |
| 8 our @EXPORT = qw(&ACCESS_NONE &ACCESS_READ &ACCESS_WRITE &ACCESS_ALL &DeclareProperty &DumpCaller &PropertyList &CloneObject); | |
| 9 | |
| 10 our $Debug; | |
| 11 | |
| 12 $Debug = 1 if not defined $Debug; | |
| 13 | |
| 14 my %ListProperties; | |
| 15 my %GlobalContext; | |
| 16 | |
| 17 1; | |
| 18 | |
| 19 sub ACCESS_NONE () { 0 } | |
| 20 sub ACCESS_READ () { 1 } | |
| 21 sub ACCESS_WRITE () { 2 } | |
| 22 sub ACCESS_ALL () {ACCESS_READ | ACCESS_WRITE} | |
| 23 | |
| 24 sub PropertyList { | |
| 25 return $ListProperties{ref($_[0]) || $_[0] || caller} || {}; | |
| 26 } | |
| 27 | |
| 28 sub DeclareProperty { | |
| 29 my ($attrName,$accessRights,%Mutators) = @_; | |
| 30 | |
| 31 my $Package = caller; | |
| 32 my $Method = $Package.'::'.$attrName; | |
| 33 my $fldName; | |
| 34 | |
| 35 my $getMutator = $Mutators{'get'}; | |
| 36 my $setMutator = $Mutators{'set'}; | |
| 37 | |
| 38 ($fldName = $Method) =~ s/:+/_/g; | |
| 39 | |
| 40 $ListProperties{$Package} = {} if not exists $ListProperties{$Package}; | |
| 41 $ListProperties{$Package}->{$attrName} = $fldName; | |
| 42 | |
| 43 if ($Debug) { | |
| 44 *$Method = sub { | |
| 45 my $this = shift; | |
| 46 | |
| 47 die new Exception( 'too many args ['.scalar(@_).'\]' , "'$Method' called from: ".DumpCaller() ) if (@_ > 1); | |
| 48 | |
| 49 my $Rights = $accessRights; | |
| 50 $Rights = ACCESS_ALL if $Package eq caller; | |
| 51 | |
| 52 if (@_){ | |
| 53 die new Exception("access denied 'write $Method'", "'$Method' called from: ".DumpCaller()) if not $Rights & ACCESS_WRITE; | |
| 54 if (defined $setMutator) { | |
| 55 &$setMutator($this,$fldName,shift); | |
| 56 } else { | |
| 57 $this->{$fldName} = $_[0]; | |
| 58 } | |
| 59 | |
| 60 } elsif (defined wantarray) { | |
| 61 die new Exception("access denied 'read $Method'", "'$Method' called from: ".DumpCaller()) if not $Rights & ACCESS_READ; | |
| 62 if (defined $getMutator) { | |
| 63 &$getMutator($this,$fldName); | |
| 64 } else { | |
| 65 if (wantarray){ | |
| 66 if(ref $this->{$fldName} eq 'ARRAY' ) { | |
| 67 return @{$this->{$fldName}}; | |
| 68 } elsif (not exists $this->{$fldName}) { | |
| 69 return; | |
| 70 } else { | |
| 71 return $this->{$fldName}; | |
| 72 } | |
| 73 } else { | |
| 74 return $this->{$fldName}; | |
| 75 } | |
| 76 } | |
| 77 } else { | |
| 78 undef; | |
| 79 } | |
| 80 }; | |
| 81 *$Method = \$fldName; | |
| 82 } else { | |
| 83 *$Method = sub { | |
| 84 my $this = shift; | |
| 85 #return undef if @_ > 1; | |
| 86 #my $Rights = $accessRights; | |
| 87 #$Rights = ACCESS_ALL if $Package eq caller; | |
| 88 | |
| 89 if (@_){ | |
| 90 # return undef if not $Rights & ACCESS_WRITE; | |
| 91 if (defined $setMutator) { | |
| 92 &$setMutator($this,$fldName,shift); | |
| 93 } else { | |
| 94 $this->{$fldName} = shift; | |
| 95 } | |
| 96 } elsif (defined wantarray) { | |
| 97 # return undef if not $Rights & ACCESS_READ; | |
| 98 if (defined $getMutator) { | |
| 99 &$getMutator($this,$fldName); | |
| 100 } else { | |
| 101 if (wantarray){ | |
| 102 if(ref $this->{$fldName} eq 'ARRAY' ) { | |
| 103 return @{$this->{$fldName}}; | |
| 104 } elsif (not defined $this->{$fldName}) { | |
| 105 return; | |
| 106 } else { | |
| 107 return $this->{$fldName}; | |
| 108 } | |
| 109 } else { | |
| 110 return $this->{$fldName}; | |
| 111 } | |
| 112 } | |
| 113 } else { | |
| 114 undef; | |
| 115 } | |
| 116 }; | |
| 117 *$Method = \$fldName; | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 sub DumpCaller { | |
| 122 return join(" ",(caller($_[0]))[1,2],(caller($_[0]+1))[3]); | |
| 123 } | |
| 124 | |
| 125 sub Owner { | |
| 126 return undef if not tied $_[0]; | |
| 127 return undef if not tied($_[0])->UNIVERSAL::can('owner'); | |
| 128 return tied($_[0])->owner(); | |
| 129 }; | |
| 130 | |
| 131 sub CloneObject { | |
| 132 my $object = shift; | |
| 133 if (ref $object == undef) { | |
| 134 return $object; | |
| 135 } elsif (ref $object eq 'SCALAR') { | |
| 136 return \CloneObject(${$object}); | |
| 137 } elsif (ref $object eq 'ARRAY') { | |
| 138 return [map{CloneObject($_)}@{$object}]; | |
| 139 } elsif (ref $object eq 'HASH') { | |
| 140 my %clone; | |
| 141 while (my ($key,$value) = each %{$object}) { | |
| 142 $clone{$key} = CloneObject($value); | |
| 143 } | |
| 144 return \%clone; | |
| 145 } elsif (ref $object eq 'REF') { | |
| 146 return \CloneObject(${$object}); | |
| 147 } else { | |
| 148 if ($object->can('Clone')) { | |
| 149 return $object->Clone(); | |
| 150 } else { | |
| 151 die new Exception('Object doesn\'t supports cloning'); | |
| 152 } | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 package Exception; | |
| 157 use base qw(IMPL::Exception); | |
| 158 | |
| 159 package Persistent; | |
| 160 import Common; | |
| 161 | |
| 162 sub newSurogate { | |
| 163 my $class = ref($_[0]) || $_[0]; | |
| 164 return bless {}, $class; | |
| 165 } | |
| 166 sub load { | |
| 167 my ($this,$context) = @_; | |
| 168 die new Exception("invalid deserialization context") if ref($context) ne 'ARRAY'; | |
| 169 die new Exception("This is not an object") if not ref $this; | |
| 170 | |
| 171 my %Props = (@{$context}); | |
| 172 foreach my $BaseClass(@{ref($this).'::ISA'}) { | |
| 173 while (my ($key,$value) = each %{PropertyList($BaseClass)}) { | |
| 174 $this->{$value} = $Props{$value} if exists $Props{$value}; | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 while (my ($key,$value) = each %{PropertyList(ref($this))}) { | |
| 179 $this->{$value} = $Props{$key} if exists $Props{$key}; | |
| 180 } | |
| 181 return 1; | |
| 182 } | |
| 183 sub save { | |
| 184 my ($this,$context) = @_; | |
| 185 | |
| 186 foreach my $BaseClass(@{ref($this).'::ISA'}) { | |
| 187 while (my ($key,$value) = each %{PropertyList($BaseClass)}) { | |
| 188 $context->AddVar($value,$this->{$value}); | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 while (my ($key,$value) = each %{PropertyList(ref($this))}) { | |
| 193 $context->AddVar($key,$this->{$value}); | |
| 194 } | |
| 195 return 1; | |
| 196 } | |
| 197 | |
| 198 sub restore { | |
| 199 my ($class,$context,$surogate) = @_; | |
| 200 my $this = $surogate || $class->newNewSurogate; | |
| 201 $this->load($context); | |
| 202 return $this; | |
| 203 } | |
| 204 | |
| 205 package Object; | |
| 206 import Common; | |
| 207 | |
| 208 sub new { | |
| 209 my $class = shift; | |
| 210 my $self = bless {}, ref($class) || $class; | |
| 211 $self->CTOR(@_); | |
| 212 return $self; | |
| 213 } | |
| 214 | |
| 215 sub cast { | |
| 216 return bless {}, ref $_[0] || $_[0]; | |
| 217 } | |
| 218 | |
| 219 our %objects_count; | |
| 220 our %leaked_objects; | |
| 221 | |
| 222 sub CTOR { | |
| 223 my $this= shift; | |
| 224 $objects_count{ref $this} ++ if $Debug; | |
| 225 my %args = @_ if scalar (@_) > 0; | |
| 226 return if scalar(@_) == 0; | |
| 227 | |
| 228 warn "invalid args in CTOR. type: ".(ref $this) if scalar(@_) % 2 != 0; | |
| 229 my @packages = (ref($this)); | |
| 230 my $countArgs = int(scalar(@_) / 2); | |
| 231 #print "Set ", join(', ',keys %args), "\n"; | |
| 232 LOOP_PACKS: while(@packages) { | |
| 233 my $package = shift @packages; | |
| 234 #print "\t$package\n"; | |
| 235 my $refProps = PropertyList($package); | |
| 236 foreach my $name (keys %{$refProps}) { | |
| 237 my $fld = $refProps->{$name}; | |
| 238 if (exists $args{$name}) { | |
| 239 $this->{$fld} = $args{$name}; | |
| 240 #print "\t$countArgs, $name\n"; | |
| 241 delete $args{$name}; | |
| 242 $countArgs --; | |
| 243 last LOOP_PACKS if $countArgs < 1; | |
| 244 } else { | |
| 245 #print "\t-$name ($fld)\n"; | |
| 246 } | |
| 247 } | |
| 248 push @packages, @{$package.'::ISA'}; | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 sub Dispose { | |
| 253 my $this = shift; | |
| 254 | |
| 255 if ($Debug and UNIVERSAL::isa($this,'HASH')) { | |
| 256 my @keys = grep { $this->{$_} and ref $this->{$_} } keys %{$this}; | |
| 257 warn "not all fields of the object were deleted\n".join("\n",@keys) if @keys; | |
| 258 } | |
| 259 | |
| 260 bless $this,'Object::Disposed'; | |
| 261 } | |
| 262 | |
| 263 our $MemoryLeakProtection; | |
| 264 | |
| 265 sub DESTROY { | |
| 266 if ($MemoryLeakProtection) { | |
| 267 my $this = shift; | |
| 268 warn sprintf("Object leaks: %s of type %s %s",$this,ref $this,UNIVERSAL::can($this,'_dump') ? $this->_dump : ''); | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 package Object::Disposed; | |
| 273 our $AUTOLOAD; | |
| 274 sub AUTOLOAD { | |
| 275 return if $AUTOLOAD eq __PACKAGE__.'::DESTROY'; | |
| 276 die new Exception('Object have been disposed',$AUTOLOAD); | |
| 277 } | |
| 278 | |
| 279 END { | |
| 280 $MemoryLeakProtection = 0 if not $Debug; | |
| 281 } | |
| 282 1; |
