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; |