File Coverage

blib/lib/Class/EHierarchy.pm
Criterion Covered Total %
statement 621 656 94.6
branch 150 198 75.7
condition 29 45 64.4
subroutine 78 79 98.7
pod 23 23 100.0
total 901 1001 90.0


line stmt bran cond sub pod time code
1             # Class::EHierarchy -- Base class for hierarchally ordered objects
2             #
3             # (c) 2009, Arthur Corliss
4             #
5             # $Id: EHierarchy.pm,v 0.93 2013/07/07 00:17:27 acorliss Exp $
6             #
7             # This software is licensed under the same terms as Perl, itself.
8             # Please see http://dev.perl.org/licenses/ for more information.
9             #
10             #####################################################################
11              
12             #####################################################################
13             #
14             # Environment definitions
15             #
16             #####################################################################
17              
18             package Class::EHierarchy;
19              
20 9     9   2320089 use 5.008003;
  9         38  
  9         359  
21              
22 9     9   59 use strict;
  9         29  
  9         307  
23 9     9   57 use warnings;
  9         19  
  9         337  
24 9     9   45 use vars qw($VERSION @EXPORT @EXPORT_OK %EXPORT_TAGS);
  9         15  
  9         1022  
25 9     9   80 use base qw(Exporter);
  9         20  
  9         1059  
26 9     9   58 use Carp;
  9         22  
  9         912  
27 9     9   50 use Scalar::Util qw(weaken);
  9         15  
  9         1420  
28              
29             ($VERSION) = ( q$Revision: 0.93 $ =~ /(\d+(?:\.(\d+))+)/sm );
30              
31             # Ordinal indexes for the @objects element records
32 9     9   52 use constant CEH_OREF => 0;
  9         13  
  9         746  
33 9     9   45 use constant CEH_PREF => 1;
  9         25  
  9         437  
34 9     9   99 use constant CEH_PKG => 2;
  9         16  
  9         393  
35 9     9   102 use constant CEH_SUPER => 3;
  9         23  
  9         343  
36 9     9   49 use constant CEH_CREF => 4;
  9         10  
  9         419  
37 9     9   41 use constant CEH_CNAME => 5;
  9         14  
  9         345  
38 9     9   39 use constant CEH_ALIAS => 6;
  9         20  
  9         320  
39              
40             # Ordinal indexes for the @properties element records
41 9     9   38 use constant CEH_ATTR => 0;
  9         15  
  9         341  
42 9     9   43 use constant CEH_PPKG => 1;
  9         16  
  9         494  
43 9     9   41 use constant CEH_PVAL => 2;
  9         16  
  9         410  
44              
45             # Property attribute masks
46 9     9   47 use constant CEH_ATTR_SCOPE => 7;
  9         50  
  9         369  
47 9     9   57 use constant CEH_ATTR_TYPE => 504;
  9         20  
  9         351  
48              
49             # Property attribute scopes
50 9     9   48 use constant CEH_PUB => 1;
  9         13  
  9         333  
51 9     9   39 use constant CEH_RESTR => 2;
  9         17  
  9         330  
52 9     9   39 use constant CEH_PRIV => 4;
  9         13  
  9         375  
53              
54             # Property attribute types
55 9     9   39 use constant CEH_SCALAR => 8;
  9         14  
  9         299  
56 9     9   40 use constant CEH_ARRAY => 16;
  9         28  
  9         366  
57 9     9   40 use constant CEH_HASH => 32;
  9         12  
  9         354  
58 9     9   44 use constant CEH_CODE => 64;
  9         26  
  9         362  
59 9     9   40 use constant CEH_REF => 128;
  9         14  
  9         377  
60 9     9   44 use constant CEH_GLOB => 256;
  9         14  
  9         498  
61              
62             # Property flags
63 9     9   41 use constant CEH_NO_UNDEF => 512;
  9         14  
  9         738269  
64              
65             @EXPORT = qw();
66             @EXPORT_OK = qw(CEH_PUB CEH_RESTR CEH_PRIV CEH_SCALAR CEH_ARRAY
67             CEH_HASH CEH_CODE CEH_REF CEH_GLOB CEH_NO_UNDEF _declProp
68             _declMethod );
69             %EXPORT_TAGS = ( all => [@EXPORT_OK] );
70              
71             #####################################################################
72             #
73             # Module code follows
74             #
75             #####################################################################
76              
77             {
78              
79             # Object list
80             # @objects = ( [ ref:parent_obj, [ ref:child_obj, ... ] ] );
81             my @objects;
82              
83             # Available IDs
84             my @available;
85              
86             # Properties
87             # @properties = ( { propName => [ int:attr, value ] } );
88             my @properties;
89              
90             # Methods
91             # %methods = ( '__PACKAGE__::method' => 1 );
92             my %methods;
93              
94             # Object aliases
95             # %aliases = ( alias => ref:obj );
96              
97             sub _dumpDiags () {
98              
99             # Purpose: Dumps some diagnostic information from class structures
100             # Returns: Boolean
101             # Usage: _dumpDiags();
102              
103 3     3   6 my ( $obj, @rec, $i );
104              
105 3         5 warn "\nCEH Objects: @{[ scalar @objects ]}\n";
  3         37  
106              
107 3         8 $i = 0;
108 3         5 foreach $obj (@objects) {
109 14 100 66     79 if ( defined $obj and @rec = @$obj ) {
110 13         19 foreach (@rec) {
111 91 100       165 $_ = 'undef' unless defined $_;
112             }
113 13         109 warn "CEH Obj #$i: @rec\n";
114             } else {
115 1         7 warn "CEH Obj #$i: unused\n";
116             }
117 14         29 $i++;
118             }
119              
120 3         14 return 1;
121             }
122              
123             # INTERNAL FUNCTIONS
124              
125             sub _ident () {
126              
127             # Purpose: Returns next available ID
128             # Returns: Integer
129             # Usage: $id = _ident();
130              
131 40 100   40   5055 return scalar @available ? CORE::shift @available : $#objects + 1;
132             }
133              
134             sub _regObj (@) {
135              
136             # Purpose: Registers the object for tracking
137             # Returns: Boolean
138             # Usage: $rv = _regObj($oref);
139              
140 40     40   56 my $obj = CORE::shift;
141              
142             # Initialize internal tracking
143 40         85 $objects[$$obj] = [];
144 40         82 $objects[$$obj][CEH_PREF] = undef;
145 40         93 $objects[$$obj][CEH_PKG] = ref $obj;
146 40         87 $objects[$$obj][CEH_SUPER] = [];
147 40         85 $objects[$$obj][CEH_CREF] = [];
148 40         104 $objects[$$obj][CEH_CNAME] = __PACKAGE__ . '0';
149 40         95 $objects[$$obj][CEH_ALIAS] = {};
150 40         70 $properties[$$obj] = {};
151              
152 40         66 return 1;
153             }
154              
155             sub _deregObj (@) {
156              
157             # Purpose: Removes the object from tracking
158             # Returns: Boolean
159             # Usage: $rv = _deregObj($oref);
160              
161 40     40   55 my $obj = CORE::shift;
162              
163             # Remove structures and make ID available
164 40         68 $objects[$$obj] = $properties[$$obj] = undef;
165 40         218 CORE::push @available, $$obj;
166              
167 40         61 return 1;
168             }
169              
170             sub _mergeAliases ($$) {
171              
172             # Purpose: Merges child aliases into parent aliases
173             # Returns: Boolean
174             # Usage: _mergeAliases($parent, $child);
175              
176 12     12   14 my $parent = CORE::shift;
177 12         2473 my $child = CORE::shift;
178 12         14 my ( @aliases, $alias, $class, $i );
179              
180             # Preserve aliases if possible
181 12         16 @aliases = CORE::keys %{ $objects[$$child][CEH_ALIAS] };
  12         80  
182 12         20 foreach $alias (@aliases) {
183 14 100       48 if ( exists $objects[$$parent][CEH_ALIAS]{$alias} ) {
184              
185             # generate new alias
186 8         12 $i = 0;
187 8         14 $class = ref $child;
188 8         31 while ( exists $objects[$$parent][CEH_ALIAS]{"$class$i"} ) {
189 11         30 $i++;
190             }
191 8         29 $objects[$$parent][CEH_ALIAS]{"$class$i"} =
192             $objects[$$child][CEH_ALIAS]{$alias};
193 8         37 weaken $objects[$$parent][CEH_ALIAS]{"$class$i"};
194 8         24 $objects[$$child][CEH_CNAME] = "$class$i";
195              
196             } else {
197              
198             # transfer alias intact
199 6         21 $objects[$$parent][CEH_ALIAS]{$alias} =
200             $objects[$$child][CEH_ALIAS]{$alias};
201 6         31 weaken $objects[$$parent][CEH_ALIAS]{$alias};
202             }
203             }
204              
205             # Sync alias hashes
206 12         29 $objects[$$child][CEH_ALIAS] = $objects[$$parent][CEH_ALIAS];
207              
208 12         49 return 1;
209             }
210              
211             sub _spliceAliases ($$) {
212              
213             # Purpose: Splits the aliase tree
214             # Returns: Boolean
215             # Usage: _spliceAliases($parent, $child);
216              
217 12     12   20 my $parent = CORE::shift;
218 12         23 my $child = CORE::shift;
219 12         24 my @children = ( $child, $child->descendants );
220 12         16 my ( $pref, $cref, $cname );
221              
222 12         20 $pref = $objects[$$parent][CEH_ALIAS];
223 12         23 $cref = $objects[$$child][CEH_ALIAS] = {};
224              
225 12         22 foreach $child (@children) {
226 14         27 $cname = $objects[$$child][CEH_CNAME];
227 14         32 delete $$pref{$cname};
228 14         30 $$cref{$cname} = $child;
229 14         53 weaken $$cref{$cname};
230             }
231              
232 12         36 return 1;
233             }
234              
235             sub _assocObj ($@) {
236              
237             # Purpose: Associates objects as children of the parent
238             # Returns: Boolean
239             # Usage: $rv = _assocObj( $parent, $child1, $child2 );
240              
241 15     15   17 my $parent = CORE::shift;
242 15         20 my @orphans = @_;
243 15         18 my $rv = 1;
244 15         18 my ( $orphan, @descendants, $n, $i, $irv, $class );
245              
246 15         19 foreach $orphan (@orphans) {
247 16 50       128 if ( !defined $orphan ) {
    100          
    100          
    50          
248              
249             # Filter out undefined references
250 0         0 $@ = 'undefined value passed as an object reference';
251 0         0 $rv = 0;
252              
253             } elsif ( !$orphan->isa('Class::EHierarchy') ) {
254              
255             # You can only adopt objects derived from this class
256 1         6 $@ = 'child object isn\'t derived from '
257             . "Class::EHierarchy: $orphan";
258 1         4 $rv = 0;
259              
260             } elsif ( $$parent == $$orphan ) {
261              
262             # Really? You want to adopt yourself? I'm sensing a chicken
263             # and the egg problem...
264 1         4 $@ = "attempted to adopt one's self: $parent";
265 1         3 $rv = 0;
266              
267             } elsif ( defined $objects[$$orphan][CEH_PREF] ) {
268              
269             # We don't allow kidnapping...
270 0         0 $@ = "attempted kidnapping of a parented child: $orphan";
271 0         0 $rv = 0;
272              
273             } else {
274              
275             # Objects are currently orphans...
276             #
277             # Now, make sure no (grand)?children of the orphan will create
278             # a circular reference
279 14         39 @descendants = $orphan->descendants;
280 14         16 $irv = 1;
281              
282             # Stop if our proposed parent is in this list
283 14 100       34 if ( grep { $$_ == $$parent } @descendants ) {
  7         19  
284 2         10 $@ = "circular reference detected between $parent "
285             . "& $orphan";
286 2         5 $irv = $rv = 0;
287             }
288              
289 14 100       37 if ($irv) {
290              
291             # No circular references, so now let's update the records
292 12         19 $objects[$$orphan][CEH_PREF] = $parent;
293 12         40 weaken( $objects[$$orphan][CEH_PREF] );
294 12         17 CORE::push @{ $objects[$$parent][CEH_CREF] }, $orphan;
  12         25  
295              
296             # Merge aliasas
297 12         26 _mergeAliases( $parent, $orphan );
298             }
299             }
300             }
301              
302 15         38 return $rv;
303             }
304              
305             sub _disassocObj ($@) {
306              
307             # Purpose: Removes the child/parent relationship
308             # Returns: Boolean
309             # Usage: $rv = _disassocObj($parent, $child1, $child2):
310              
311 12     12   16 my $parent = CORE::shift;
312 12         18 my @children = CORE::shift;
313 12         14 my $child;
314              
315 12         19 foreach $child (@children) {
316              
317             # Make sure the child actually belongs to the parent
318 12 50       42 if ( $objects[$$child][CEH_PREF] == $parent ) {
319              
320             # Remove the child objref from the parent's list
321 12         28 @{ $objects[$$parent][CEH_CREF] } =
  18         45  
322 12         16 grep { $_ != $child } @{ $objects[$$parent][CEH_CREF] };
  12         29  
323              
324             # Update the child's record
325 12         20 $objects[$$child][CEH_PREF] = undef;
326              
327             # Split aliases
328 12         28 _spliceAliases( $parent, $child );
329             }
330             }
331              
332 12         30 return 1;
333             }
334              
335             sub _cscope ($$) {
336              
337             # Purpose: Determines the caller's scope in relation to the object
338             # being acted upon
339             # Returns: CEH_PRIV, CEH_RESTR, or CEH_PUB
340             # Usage: $cscope = _cscope($caller, $obj);
341             # Usage: $cscope = _cscope($caller, $pkg);
342              
343 214     214   315 my $caller = CORE::shift;
344 214         244 my $pkg = CORE::shift;
345              
346             # Set $pkg to either the resolved package name (if it's an object
347             # reference) or leave it as a plain string package name
348 214 50       478 $pkg = $objects[$$pkg][CEH_PKG] unless ref $pkg eq '';
349              
350             return
351 214 100       997 $caller eq $pkg ? CEH_PRIV
    100          
352             : "$caller"->isa($pkg) ? CEH_RESTR
353             : CEH_PUB;
354             }
355              
356             sub _chkAccess ($$$) {
357              
358             # Purpose: Checks to see if the caller is allowed access to the
359             # requested property. If the caller is granted access it
360             # will return the name of the property (which may be
361             # adjusted for privately scoped properties), otherwise it
362             # croaks.
363             # Returns: name of property
364             # Usage: $prop = _chkAccess($caller, $prop);
365              
366 230     230   268 my $self = CORE::shift;
367 230         343 my $caller = CORE::shift;
368 230         285 my $prop = CORE::shift;
369 230         270 my ( $opkg, $cscope, $pscope );
370              
371             # Modify the property name for to check for private properties
372 230         1054 $prop = "${caller}::$prop"
373 230 100 66     566 if defined $prop and !exists ${ $properties[$$self] }{$prop};
374              
375 230 100 66     534 if ( defined $prop and CORE::exists ${ $properties[$$self] }{$prop} )
  230         767  
376             {
377              
378             # Get the object package
379 208         328 $opkg = $objects[$$self][CEH_PKG];
380              
381             # Property CORE::exists, check the caller & property scopes
382 208         853 $cscope =
383             _cscope( $caller, $properties[$$self]{$prop}[CEH_PPKG] );
384 208         523 $pscope =
385 208         268 ${ $properties[$$self] }{$prop}[CEH_ATTR] & CEH_ATTR_SCOPE;
386              
387 208 100       454 unless ( $cscope >= $pscope ) {
388              
389             # Caller is not authorized
390 12 50       41 $pscope =
    50          
391             $pscope == CEH_PRIV ? 'private'
392             : $pscope == CEH_RESTR ? 'restricted'
393             : 'public';
394 12         1802 croak "Attempted access of $pscope property $prop by $caller";
395             }
396              
397             } else {
398              
399             # Undefined or nonexistent property
400 22 50       51 $prop = '\'undef\'' unless defined $prop;
401 22         3508 croak "Attempted access of nonexistent property $prop";
402             }
403              
404 196         462 return $prop;
405             }
406              
407             sub __declProp {
408              
409             # Purpose: Registers list of properties as known
410             # Returns: Boolean
411             # Usage: $rv = __declProp($caller, $obj, $attr, @propNames);
412              
413 114     114   140 my $caller = CORE::shift;
414 114         129 my $obj = CORE::shift;
415 114         114 my $attr = CORE::shift;
416 114         192 my @names = splice @_;
417 114         126 my $rv = 0;
418 114         116 my $prop;
419              
420 114 50       214 if ( defined $attr ) {
421 114         127 $rv = 1;
422 114         145 @names = grep {defined} @names;
  116         333  
423              
424             # Preprocess private properties to avoid naming conflicts
425 114 100       236 if ( $attr & CEH_PRIV ) {
426              
427             # Prepend the caller's package to the property names to avoid
428             # naming conflicts with subclasses
429 50         79 foreach (@names) { $_ = "${caller}::$_" }
  52         137  
430             }
431              
432 114         178 foreach $prop (@names) {
433 116         311 croak "property '$prop' already defined"
434 116 50       111 if CORE::exists ${ $properties[$$obj] }{$prop};
435              
436             # Apply default attributes
437 116 50       356 $attr |= CEH_SCALAR
438             unless ( $attr ^ CEH_ATTR_TYPE ) > 0;
439 116 50       200 $attr |= CEH_PUB
440             unless ( $attr ^ CEH_ATTR_SCOPE ) > 0;
441              
442             # Save the properties
443 116         160 ${ $properties[$$obj] }{$prop} = [];
  116         245  
444 116         141 ${ $properties[$$obj] }{$prop}[CEH_ATTR] = $attr;
  116         243  
445 116         127 ${ $properties[$$obj] }{$prop}[CEH_PPKG] = $caller;
  116         306  
446 116 100       298 ${ $properties[$$obj] }{$prop}[CEH_PVAL] =
  116 100       331  
447             $attr & CEH_ARRAY ? []
448             : $attr & CEH_HASH ? {}
449             : undef;
450             }
451             }
452              
453 114         337 return $rv;
454             }
455              
456             sub _declProp {
457              
458             # Purpose: Wrapper for __declProp, this is the public interface
459             # Returns: RV of __declProp
460             # Usage: $rv = __declProp($obj, $attr, @propNames);
461              
462 60     60   306 my $caller = caller;
463 60         145 my @args = splice @_;
464              
465 60         118 return __declProp( $caller, @args );
466             }
467              
468             sub _loadProps($$) {
469              
470             # Purpose: Loads properties from @_properties
471             # Returns: Boolean
472             # Usage: $rv = _loadProps();
473              
474 48     48   67 my $class = CORE::shift;
475 48         61 my $obj = CORE::shift;
476 48         59 my $rv = 1;
477 48         57 my ( @_properties, $prop, $pname, $pattr, $pscope );
478              
479             # Get the contents of the class array
480             {
481 9     9   93 no strict 'refs';
  9         16  
  9         8111  
  48         54  
482              
483 8         20 @_properties = @{ *{"${class}::_properties"}{ARRAY} }
  8         27  
  48         284  
484 48 100       57 if defined *{"${class}::_properties"};
485             }
486              
487             # Process the list
488 48         88 foreach $prop (@_properties) {
489 54 50       103 next unless defined $prop;
490              
491 54 50       181 unless (
492             __declProp( $class, $obj, @$prop[ CEH_ATTR, CEH_PPKG ] ) ) {
493 0         0 $rv = 0;
494 0         0 last;
495             }
496              
497             # Set the default values
498 54 100 66     229 if ( $rv and defined $$prop[CEH_PVAL] ) {
499              
500             # Get the attribute type, scope, and internal prop name
501 48         100 $pattr = $$prop[CEH_ATTR] & CEH_ATTR_TYPE;
502 48         52 $pscope = $$prop[CEH_ATTR] & CEH_ATTR_SCOPE;
503 48 100       93 $pname =
504             $pscope == CEH_PRIV
505             ? "${class}::$$prop[CEH_PPKG]"
506             : $$prop[CEH_PPKG];
507              
508             # Store the default values
509 14         31 $obj->_setProp( $pname,
510 12         38 $pattr == CEH_ARRAY ? @{ $$prop[CEH_PVAL] }
511 48 100       130 : $pattr == CEH_HASH ? %{ $$prop[CEH_PVAL] }
    100          
512             : $$prop[CEH_PVAL] );
513             }
514             }
515              
516 48         212 return $rv;
517             }
518              
519             sub _setProp ($$@) {
520              
521             # Purpose: Sets the designated property to the passed value(s).
522             # Does some rough validation according to attributes
523             # Returns: Boolean
524             # Usage: $rv = _setProp($obj, 'foo', qw(one two three));
525              
526 121     121   146 my $obj = CORE::shift;
527 121         163 my $prop = CORE::shift;
528 121         273 my @val = splice @_;
529 121         134 my $rv = 0;
530 121         131 my ( $pattr, $pundef, $pval, $pref );
531              
532             # NOTE: since we're screening for valid properties and access
533             # rights in the property method we won't be doing any validation
534             # here
535 121         144 $pattr = ${ $properties[$$obj] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  121         247  
536 121         134 $pundef = ${ $properties[$$obj] }{$prop}[CEH_ATTR] & CEH_NO_UNDEF;
  121         205  
537              
538             # Do some quick validation of references (not necessary for
539             # hash/array types)
540 121 100 100     423 if ( $pattr != CEH_ARRAY and $pattr != CEH_HASH ) {
541 64         90 $pref = ref $val[0];
542              
543 64 100       112 if ( not defined $val[0] ) {
544              
545             # Only allow undef values if the properties allow
546             # undef values
547 2 50       9 $rv = 1 if not $pundef;
548              
549             } else {
550              
551             # Check defined values
552 62 100       119 if ( $pattr == CEH_SCALAR ) {
    100          
    50          
    50          
553 52 50       126 $rv = 1 if $pref eq '';
554             } elsif ( $pattr == CEH_CODE ) {
555 8 50       22 $rv = 1 if $pref eq 'CODE';
556             } elsif ( $pattr == CEH_GLOB ) {
557 0 0       0 $rv = 1 if $pref eq 'GLOB';
558             } elsif ( $pattr == CEH_REF ) {
559 2 50       10 $rv = 1 if $pref ne '';
560             } else {
561 0         0 croak 'something\'s wrong with property attribute '
562             . "type for $prop";
563             }
564             }
565             } else {
566 57         78 $rv = 1;
567             }
568              
569             # In this context only hashes and arrays need special handling
570 121 100       234 if ($rv) {
571 111 100       226 if ( $pattr == CEH_ARRAY ) {
    100          
572 30         72 ${ $properties[$$obj] }{$prop}[CEH_PVAL] = [@val];
  30         63  
573             } elsif ( $pattr == CEH_HASH ) {
574 27         99 ${ $properties[$$obj] }{$prop}[CEH_PVAL] = {@val};
  27         64  
575             } else {
576 54         57 ${ $properties[$$obj] }{$prop}[CEH_PVAL] = $val[0];
  54         114  
577             }
578             }
579              
580 121         428 return $rv;
581             }
582              
583             sub _getProp ($$) {
584              
585             # Purpose: Returns the requested property value, dereferencing
586             # appropriately, depending on property type
587             # Returns: n/a
588             # Usage: $val = _getProp($obj, 'foo');
589             # Usage: @val = _getProp($obj, 'bar');
590             # Usage: %val = _getProp($obj, 'foo');
591              
592 85     85   199 my ( $obj, $prop ) = @_;
593 85         126 my ( $pattr, $pval );
594              
595             # NOTE: since we're screening for valid properties and access
596             # rights in the property method we won't be doing any validation
597             # here
598 85         96 $pattr = ${ $properties[$$obj] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  85         172  
599 85         104 $pval = ${ $properties[$$obj] }{$prop}[CEH_PVAL];
  85         147  
600              
601             # In this context only hashes and arrays need special handling
602             return
603 85 100       563 $pattr == CEH_ARRAY ? @$pval
    100          
604             : $pattr == CEH_HASH ? %$pval
605             : $pval;
606             }
607              
608             sub __declMethod {
609              
610             # Purpose: Registers a list of methods as scoped
611             # Returns: Boolean
612             # Usage: $rv = __declMethod($class, $attr, @methods);
613              
614 36     36   47 my $pkg = CORE::shift;
615 36         35 my $attr = CORE::shift;
616 36         62 my @names = splice @_;
617 36         37 my ( $code, $method, $mfqn );
618              
619 36 50       65 if ( defined $attr ) {
620              
621             # Quiet some warnings
622 9     9   63 no warnings qw(redefine prototype);
  9         222  
  9         471  
623 9     9   50 no strict 'refs';
  9         18  
  9         3387  
624              
625 36         44 foreach $method (@names) {
626              
627             # Get the fully qualified method name and associated code
628             # block
629 36         54 $mfqn = "${pkg}::${method}";
630 36         34 $code = *{$mfqn}{CODE};
  36         86  
631              
632             # Quick check to see if we've done this already -- if so
633             # we skip to the next
634 36 100       112 next if $methods{$mfqn};
635              
636 12 50       26 if ( defined $code ) {
637              
638             # Repackage
639 12 100       32 if ( $attr == CEH_PRIV ) {
    100          
640              
641             # Private methods
642 4         20 *{$mfqn} = sub {
643 8     8   9659 my $caller = caller;
644 8 100       27 goto &{$code} if $caller eq $pkg;
  4         20  
645 4         858 croak 'Attempted to call private method '
646             . "$method from $caller";
647 4         18 };
648              
649             } elsif ( $attr == CEH_RESTR ) {
650              
651             # Restricted methods
652 4         17 *{$mfqn} = sub {
653 10     10   3885 my $caller = caller;
654 10 100       81 goto &{$code} if "$caller"->isa($pkg);
  6         26  
655 4         476 croak 'Attempted to call restricted method '
656             . "$method from $caller";
657 4         56 };
658             }
659              
660             } else {
661 0         0 croak "Method $method declared but not defined";
662             }
663              
664             # Record our handling of this method
665 12         38 $methods{$mfqn} = 1;
666             }
667             }
668              
669 36         124 return 1;
670             }
671              
672             sub _declMethod {
673              
674             # Purpose: Wrapper for __declMethod, this is the public interface
675             # Returns: RV of __declMethod
676             # Usage: $rv = _declMethod($attr, @propNames);
677              
678 18     18   62 my $caller = caller;
679 18         59 my @args = splice @_;
680              
681 18         29 return __declMethod( $caller, @args );
682             }
683              
684             sub _loadMethods {
685              
686             # Purpose: Loads methods from @_methods
687             # Returns: Boolean
688             # Usage: $rv = _loadMethods();
689              
690 48     48   76 my $class = CORE::shift;
691 48         63 my $rv = 1;
692 48         54 my ( @_methods, $method );
693              
694             # Get the contents of the class array
695             {
696 9     9   46 no strict 'refs';
  9         16  
  9         2238  
  48         59  
697              
698 6         6 @_methods = @{ *{"${class}::_methods"}{ARRAY} }
  6         18  
  48         329  
699 48 100       45 if defined *{"${class}::_methods"};
700             }
701              
702             # Process the list
703 48         79 foreach $method (@_methods) {
704 18 50       31 next unless defined $method;
705 18 50       37 unless ( __declMethod( $class, @$method[ CEH_ATTR, CEH_PPKG ] ) )
706             {
707 0         0 $rv = 0;
708 0         0 last;
709             }
710             }
711              
712 48         153 return $rv;
713             }
714              
715             # PUBLISHED METHODS
716              
717             sub new ($;@) {
718              
719             # Purpose: Object constructor
720             # Returns: Object reference
721             # Usage: $obj = Class->new(@args);
722              
723 40     40 1 2012 my $class = CORE::shift;
724 40         72 my @args = @_;
725 40         56 my $self = bless \do { my $anon_scalar }, $class;
  40         118  
726 40         59 my ( $rv, @classes, $tclass, $nclass, $l, $n, $isaref );
727 0         0 my ( %super, $alias );
728              
729             # Set the id and register
730 40         99 $$self = _ident();
731 40         108 _regObj($self);
732              
733             # Assemble a list of superclasses derived from this class that
734             # will need initialization
735 9     9   45 no strict 'refs';
  9         14  
  9         32088  
736 40         44 $isaref = *{"${class}::ISA"}{ARRAY};
  40         245  
737 40 50       124 $isaref = [] unless defined $isaref;
738 40         85 foreach $tclass (@$isaref) {
739 40 100 100     435 CORE::push @classes, $tclass
740             if $tclass ne __PACKAGE__
741             and "$tclass"->isa(__PACKAGE__);
742             }
743 40         68 $n = 0;
744 40         54 $l = scalar @classes;
745 40         116 while ( $n < $l ) {
746 8         35 foreach $tclass ( @classes[ $n .. ( $l - 1 ) ] ) {
747 8         11 $isaref = *{"${tclass}::ISA"}{ARRAY};
  8         24  
748 8 50       22 $isaref = [] unless defined $isaref;
749 8         15 foreach $nclass (@$isaref) {
750 8 50 33     42 CORE::push @classes, $nclass
751             if $nclass ne __PACKAGE__
752             and "$nclass"->isa(__PACKAGE__);
753             }
754             }
755 8         25 $n = scalar @classes - $l + 1;
756 8         21 $l = scalar @classes;
757             }
758              
759             # uniq the superclass list and save it
760 40         75 %super = map { $_ => 0 } @classes;
  8         43  
761              
762             # Add our current package to the list
763 40         78 CORE::unshift @classes, $class;
764              
765             # Begin initialization from the top down
766 40         68 foreach $tclass ( reverse @classes ) {
767 48 50       132 unless ( $super{$tclass} ) {
768              
769             # Save the class list for the desconstructor
770 48         60 unshift @{ $objects[$$self][CEH_SUPER] }, $tclass;
  48         120  
771              
772             # First autoload @_properties & @_methods
773 48   33     122 $rv = _loadProps( $tclass, $self ) && _loadMethods($tclass);
774 48 50       107 unless ($rv) {
775 0         0 _deregObj($self);
776 0         0 $self = undef;
777 0         0 last;
778             }
779              
780             # Last, call _initialize()
781             $rv =
782 48         235 defined *{"${tclass}::_initialize"}
  28         105  
783 48 100       86 ? &{"${tclass}::_initialize"}( $self, @args )
784             : 1;
785              
786             # Track each super class initialization so we only do
787             # it once
788 48         172 $super{$tclass}++;
789             }
790              
791 48 50       151 unless ($rv) {
792 0         0 _deregObj($self);
793 0         0 $self = undef;
794 0         0 last;
795             }
796             }
797              
798             # Generate alias
799 40 50       128 if ($self) {
800 40         74 $alias = $objects[$$self][CEH_CNAME];
801 40         98 $objects[$$self][CEH_ALIAS]{$alias} = $self;
802 40         134 weaken $objects[$$self][CEH_ALIAS]{$alias};
803             }
804              
805 40         159 return $self;
806             }
807              
808             sub parent ($) {
809              
810             # Purpose: Returns a reference to the parent object
811             # Returns: Object reference
812             # Usage: $pref = $obj->parent;
813              
814 16     16 1 451 my $self = CORE::shift;
815              
816 16         45 return $objects[$$self][CEH_PREF];
817             }
818              
819             sub root ($) {
820              
821             # Purpose: Returns a reference to the ancestral root of the object
822             # tree
823             # Returns: Object reference
824             # Usage: $pref = $obj->root;
825              
826 1     1 1 2 my $self = CORE::shift;
827 1         2 my ( $obj, $parent );
828              
829 1         2 $obj = $self;
830 1         3 while ( defined( $parent = $obj->parent ) ) {
831 2         3 $obj = $parent;
832             }
833              
834 1         4 return $obj;
835             }
836              
837             sub children ($) {
838              
839             # Purpose: Returns a list of object references to this object's
840             # children
841             # Returns: Array
842             # Usage: @crefs = $obj->children;
843              
844 6     6 1 516 my $self = CORE::shift;
845              
846 6         7 return @{ $objects[$$self][CEH_CREF] };
  6         23  
847             }
848              
849             sub descendants ($) {
850              
851             # Purpose: Returns a list of object references to all
852             # (grand)children of this object
853             # Returns: Array
854             # Usage: @descendants = $obj->descendants;
855              
856 88     88 1 119 my $self = CORE::shift;
857 88         94 my @children = @{ $objects[$$self][CEH_CREF] };
  88         179  
858 88         136 my @rv = @children;
859              
860 88         151 foreach (@children) {
861 21         77 push @rv, $_->descendants;
862             }
863              
864 88         2188 return @rv;
865             }
866              
867             sub siblings ($) {
868              
869             # Purpose: Returns a list of object references to this object's
870             # siblings
871             # Returns: Array
872             # Usage: @crefs = $obj->siblings;
873              
874 0     0 1 0 my $self = CORE::shift;
875 0         0 my $pref = $objects[$$self][CEH_PREF];
876 0         0 my @rv;
877              
878 0 0       0 @rv = grep { $_ != $self } @{ $objects[$$pref][CEH_CREF] }
  0         0  
  0         0  
879             if defined $pref;
880              
881 0         0 return @rv;
882             }
883              
884             sub relative ($$) {
885              
886             # Purpose: Returns an object reference for an exact match on
887             # an alias
888             # Returns: Object reference
889             # Usage: $oref = $obj->relative('foo');
890              
891 11     11 1 27 my $self = CORE::shift;
892 11         17 my $alias = CORE::shift;
893 11         14 my $rv;
894              
895 11 50       35 if ( defined $alias ) {
896 11 100       55 $rv = $objects[$$self][CEH_ALIAS]{$alias}
897             if exists $objects[$$self][CEH_ALIAS]{$alias};
898             }
899              
900 11         62 return $rv;
901             }
902              
903             sub relatives ($$) {
904              
905             # Purpose: Returns an object reference for an regex match on
906             # an alias
907             # Returns: Array
908             # Usage: $oref = $obj->relatives('foo');
909              
910 1     1 1 2 my $self = CORE::shift;
911 1         3 my $alias = CORE::shift;
912 1         2 my ( @aliases, @rv );
913              
914 1 50       5 if ( defined $alias ) {
915 1         40 @aliases = grep m#^\Q$alias\E#sm,
916 1         3 keys %{ $objects[$$self][CEH_ALIAS] };
917 1         4 foreach $alias (@aliases) {
918 1         6 push @rv, $objects[$$self][CEH_ALIAS]{$alias};
919             }
920             }
921              
922 1         6 return @rv;
923             }
924              
925             sub alias ($;$) {
926              
927             # Purpose: Get/Set object alias
928             # Returns: String/Boolean
929             # Usage: $rv = $obj->alias;
930              
931 15     15 1 38 my $self = CORE::shift;
932 15         21 my $alias = CORE::shift;
933 15         16 my $rv;
934              
935 15 100       42 if ( defined $alias ) {
936              
937             # Set alias
938 3 50       13 if ( exists $objects[$$self][CEH_ALIAS]{$alias} ) {
939              
940             # Alias already in use -- fail
941 0         0 $rv = 0;
942              
943             } else {
944              
945             # Move to new alias
946 3         27 delete $objects[$$self][CEH_ALIAS]
947             { $objects[$$self][CEH_CNAME] };
948 3         10 $objects[$$self][CEH_ALIAS]{$alias} = $self;
949 3         48 $objects[$$self][CEH_CNAME] = $alias;
950 3         14 weaken $objects[$$self][CEH_ALIAS]{$alias};
951 3         5 $rv = 1;
952             }
953              
954             } else {
955              
956             # Get alias
957 12         26 $rv = $objects[$$self][CEH_CNAME];
958             }
959              
960 15         76 return $rv;
961             }
962              
963             sub adopt ($@) {
964              
965             # Purpose: Adopts the passed object references as children
966             # Returns: Boolean
967             # Usage: $rv = $obj->adopt($cobj1, $cobj2);
968              
969 15     15 1 1026 my $self = CORE::shift;
970 15         27 my @children = @_;
971 15         18 my $rv = 0;
972              
973 15 50       50 $rv = _assocObj( $self, @children ) if @children;
974              
975 15         91 return $rv;
976             }
977              
978             sub disown ($@) {
979              
980             # Purpose: Disowns the passed object references as children
981             # Returns: Boolean
982             # Usage: $rv = $obj->disown($cobj1, $cobj2);
983              
984 12     12 1 1644 my $self = CORE::shift;
985 12         22 my @children = @_;
986              
987 12         35 return _disassocObj( $self, @children );
988             }
989              
990             sub property ($$;$) {
991              
992             # Purpose: Gets/sets the requested property
993             # Returns: Boolean on value sets, value on gets
994             # Usage: @numbers = $obj->property('numbers');
995             # Usage: $rv = $obj->property('numbers',
996             # qw(555-1212 999-1111));
997              
998 186     186 1 54169 my $self = CORE::shift;
999 186         267 my $prop = CORE::shift;
1000 186         320 my @values = @_;
1001 186         314 my $caller = caller;
1002 186         193 my ($rv);
1003              
1004             # Check for access rights
1005 186         354 $prop = _chkAccess( $self, $caller, $prop );
1006              
1007             # Caller is authorized, determine the mode
1008 158 100       338 if (@values) {
1009              
1010             # set mode
1011 73         166 return _setProp( $self, $prop, @values );
1012              
1013             } else {
1014              
1015             # get mode
1016 85         184 return _getProp( $self, $prop );
1017             }
1018              
1019 0         0 return 1;
1020             }
1021              
1022             sub propertyNames ($) {
1023              
1024             # Purpose: Returns a list of all property names
1025             # Returns: Array
1026             # Usage: @names = $obj->propertyNames;
1027              
1028 6     6 1 2645 my $self = CORE::shift;
1029 6         11 my $caller = caller;
1030 6         8 my ( $opkg, $cscope, $pscope, @rv );
1031              
1032             # Get the object package
1033 6         13 $opkg = $objects[$$self][CEH_PKG];
1034              
1035             # Property CORE::exists, check the caller & property scopes
1036 6         13 $cscope = _cscope( $caller, $opkg );
1037              
1038             # Iterate over all properties get the ones accessible to the caller
1039 6         9 foreach ( keys %{ $properties[$$self] } ) {
  6         26  
1040 40         40 $pscope = ${ $properties[$$self] }{$_}[CEH_ATTR] & CEH_ATTR_SCOPE;
  40         67  
1041             next
1042 18         75 if $pscope == CEH_PRIV
1043 40 50 66     81 and ${ $properties[$$self] }{$_}[CEH_PPKG] ne $opkg;
1044 40 100       84 CORE::push @rv, $_ if $cscope >= $pscope;
1045             }
1046              
1047 6         29 return @rv;
1048             }
1049              
1050             # Array-specific methods
1051              
1052             sub push ($$@) {
1053              
1054             # Purpose: pushes values onto the requested array property,
1055             # Returns: The return value of the CORE::push
1056             # Usage: $rv = $obj->push($prop, @values);
1057              
1058 3     3 1 1018 my $self = CORE::shift;
1059 3         7 my $prop = CORE::shift;
1060 3         8 my @values = splice @_;
1061 3         6 my $caller = caller;
1062 3         4 my $pattr;
1063              
1064             # Check for access rights
1065 3         7 $prop = _chkAccess( $self, $caller, $prop );
1066              
1067             # Make sure it's an array
1068 2         3 $pattr = ${ $properties[$$self] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  2         4  
1069 2 100       103 croak "Can't push values onto a non-array like $prop"
1070             unless $pattr == CEH_ARRAY;
1071              
1072             # push the values
1073 1         2 return CORE::push @{ ${ $properties[$$self] }{$prop}[CEH_PVAL] },
  1         2  
  1         5  
1074             @values;
1075             }
1076              
1077             sub pop ($$) {
1078              
1079             # Purpose: pops values off of the requested array property,
1080             # Returns: The return value of CORE::pop
1081             # Usage: $rv = $obj->pop($prop);
1082              
1083 3     3 1 2632 my $self = CORE::shift;
1084 3         4 my $prop = CORE::shift;
1085 3         7 my $caller = caller;
1086 3         5 my $pattr;
1087              
1088             # Check for access rights
1089 3         6 $prop = _chkAccess( $self, $caller, $prop );
1090              
1091             # Make sure it's an array
1092 2         4 $pattr = ${ $properties[$$self] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  2         5  
1093 2 100       104 croak "Can't pop values off of a non-array like $prop"
1094             unless $pattr == CEH_ARRAY;
1095              
1096             # pop the values
1097 1         2 return CORE::pop @{ ${ $properties[$$self] }{$prop}[CEH_PVAL] };
  1         2  
  1         4  
1098             }
1099              
1100             sub unshift ($$@) {
1101              
1102             # Purpose: unshifts values onto the requested array property,
1103             # Returns: The return value of the CORE::unshift
1104             # Usage: $rv = $obj->unshift($prop, @values);
1105              
1106 3     3 1 1958 my $self = CORE::shift;
1107 3         5 my $prop = CORE::shift;
1108 3         8 my @values = splice @_;
1109 3         6 my $caller = caller;
1110 3         3 my $pattr;
1111              
1112             # Check for access rights
1113 3         6 $prop = _chkAccess( $self, $caller, $prop );
1114              
1115             # Make sure it's an array
1116 2         3 $pattr = ${ $properties[$$self] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  2         7  
1117 2 100       94 croak "Can't unshift values onto a non-array like $prop"
1118             unless $pattr == CEH_ARRAY;
1119              
1120             # unshift the values
1121 1         1 return CORE::unshift @{ ${ $properties[$$self] }{$prop}[CEH_PVAL] },
  1         2  
  1         5  
1122             @values;
1123             }
1124              
1125             sub shift ($$) {
1126              
1127             # Purpose: shifts values off of the requested array property,
1128             # Returns: The return value of CORE::shift
1129             # Usage: $rv = $obj->shift($prop);
1130              
1131 3     3 1 2321 my $self = CORE::shift;
1132 3         7 my $prop = CORE::shift;
1133 3         4 my $caller = caller;
1134 3         4 my $pattr;
1135              
1136             # Check for access rights
1137 3         7 $prop = _chkAccess( $self, $caller, $prop );
1138              
1139             # Make sure it's an array
1140 2         3 $pattr = ${ $properties[$$self] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  2         5  
1141 2 100       93 croak "Can't shift values off of a non-array like $prop"
1142             unless $pattr == CEH_ARRAY;
1143              
1144             # shift the values
1145 1         4 return CORE::shift @{ ${ $properties[$$self] }{$prop}[CEH_PVAL] };
  1         2  
  1         5  
1146             }
1147              
1148             # Hash-specific methods
1149              
1150             sub exists ($$$) {
1151              
1152             # Purpose: checks the existance of a key in the property hash
1153             # Returns: The return value of CORE::exists
1154             # Usage: $rv = $obj->exists($prop, $key);
1155              
1156 4     4 1 1906 my $self = CORE::shift;
1157 4         6 my $prop = CORE::shift;
1158 4         6 my $key = CORE::shift;
1159 4         8 my $caller = caller;
1160 4         3 my $pattr;
1161              
1162             # Check for access rights
1163 4         10 $prop = _chkAccess( $self, $caller, $prop );
1164              
1165             # Make sure it's a hash
1166 3         5 $pattr = ${ $properties[$$self] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  3         7  
1167 3 100       127 croak "Can't check for a key in a non-hash like $prop"
1168             unless $pattr == CEH_HASH;
1169              
1170             # Check for the key
1171 2         2 return CORE::exists ${ ${ $properties[$$self] }{$prop}[CEH_PVAL] }
  2         3  
  2         10  
1172             {$key};
1173             }
1174              
1175             sub keys ($$) {
1176              
1177             # Purpose: Retrieves a list of keys of the given hash property
1178             # Returns: The return value of CORE::keys
1179             # Usage: $rv = $obj->keys($prop, $key);
1180              
1181 6     6 1 3366 my $self = CORE::shift;
1182 6         12 my $prop = CORE::shift;
1183 6         12 my $caller = caller;
1184 6         9 my $pattr;
1185              
1186             # Check for access rights
1187 6         13 $prop = _chkAccess( $self, $caller, $prop );
1188              
1189             # Make sure it's a hash
1190 5         8 $pattr = ${ $properties[$$self] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  5         15  
1191 5 100       259 croak "Can't check for keys in a non-hash like $prop"
1192             unless $pattr == CEH_HASH;
1193              
1194             # Get the keys
1195 4         6 return CORE::keys %{ ${ $properties[$$self] }{$prop}[CEH_PVAL] };
  4         6  
  4         34  
1196             }
1197              
1198             # Unified hash/array methods
1199              
1200             sub store ($$@) {
1201              
1202             # Purpose: Adds elements to either an array or hash
1203             # Returns: Boolean
1204             # Usage: $rv = $obj->add($prop, foo => bar);
1205             # Usage: $rv = $obj->add($prop, 4 => foo, 5 => bar);
1206              
1207 3     3 1 3150 my $self = CORE::shift;
1208 3         5 my $prop = CORE::shift;
1209 3         13 my @pairs = splice @_;
1210 3         5 my $caller = caller;
1211 3         6 my ( $pattr, $i, $v );
1212              
1213             # Check for access rights
1214 3         8 $prop = _chkAccess( $self, $caller, $prop );
1215              
1216             # Make sure it's an array or hash
1217 3         4 $pattr = ${ $properties[$$self] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  3         9  
1218 3 50 66     15 croak "Can't retrieve values for non-hash/arrays like $prop"
1219             unless $pattr == CEH_HASH
1220             or $pattr == CEH_ARRAY;
1221              
1222 3 100       8 if ( $pattr == CEH_HASH ) {
1223              
1224             # Add the key-pairs
1225 1         1 %{ ${ $properties[$$self] }{$prop}[CEH_PVAL] } =
  1         7  
  1         4  
1226 1         3 ( %{ ${ $properties[$$self] }{$prop}[CEH_PVAL] }, @pairs );
  1         2  
1227              
1228             } else {
1229              
1230             # Set the values to the specified indices
1231 2         5 while (@pairs) {
1232 4         7 $i = CORE::shift @pairs;
1233 4         6 $v = CORE::shift @pairs;
1234 4         4 ${ $properties[$$self] }{$prop}[CEH_PVAL][$i] = $v;
  4         147  
1235             }
1236             }
1237              
1238 3         10 return 1;
1239             }
1240              
1241             sub retrieve ($$@) {
1242              
1243             # Purpose: Retrieves all the requested array or hash property
1244             # elements
1245             # Returns: List of values
1246             # Usage: @values = $obj->retrieve($array, 3 .. 5 );
1247             # Usage: @values = $obj->retrieve($hash, qw(foo bar) );
1248              
1249 5     5 1 5197 my $self = CORE::shift;
1250 5         11 my $prop = CORE::shift;
1251 5         15 my @elements = splice @_;
1252 5         10 my $caller = caller;
1253 5         6 my ( $pattr, $rv );
1254              
1255             # Check for access rights
1256 5         11 $prop = _chkAccess( $self, $caller, $prop );
1257              
1258             # Make sure it's an array or hash
1259 5         8 $pattr = ${ $properties[$$self] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  5         13  
1260 5 50 66     22 croak "Can't retrieve values for non-hash/arrays like $prop"
1261             unless $pattr == CEH_HASH
1262             or $pattr == CEH_ARRAY;
1263              
1264 5 100       15 if ( $pattr == CEH_ARRAY ) {
1265 3 50 66     11 if ( @elements == 1 and !wantarray ) {
1266 0         0 return ${ ${ $properties[$$self] }{$prop}[CEH_PVAL] }
  0         0  
  0         0  
1267             [ $elements[0] ];
1268             } else {
1269 3         4 return @{ ${ $properties[$$self] }{$prop}[CEH_PVAL] }
  3         3  
  3         16  
1270             [@elements];
1271             }
1272             } else {
1273 2 50 33     7 if ( @elements == 1 and !wantarray ) {
1274 0         0 return ${ ${ $properties[$$self] }{$prop}[CEH_PVAL] }
  0         0  
  0         0  
1275             { $elements[0] };
1276             } else {
1277 2         3 return @{ ${ $properties[$$self] }{$prop}[CEH_PVAL] }
  2         4  
  2         16  
1278             {@elements};
1279             }
1280             }
1281              
1282 0         0 return 1;
1283             }
1284              
1285             sub remove ($$@) {
1286              
1287             # Purpose: Removes the specified elements from the hash or array
1288             # Returns: Boolean
1289             # Usage: $obj->remove($prop, @keys);
1290              
1291 2     2 1 3076 my $self = CORE::shift;
1292 2         9 my $prop = CORE::shift;
1293 2         8 my @elements = splice @_;
1294 2         5 my $caller = caller;
1295 2         4 my ( $pattr, $i, @narray );
1296              
1297             # Check for access rights
1298 2         7 $prop = _chkAccess( $self, $caller, $prop );
1299              
1300             # Make sure it's an array or hash
1301 2         4 $pattr = ${ $properties[$$self] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  2         9  
1302 2 50 66     21 croak "Can't remove values for non-hash/arrays like $prop"
1303             unless $pattr == CEH_HASH
1304             or $pattr == CEH_ARRAY;
1305              
1306 2 100       7 if ( $pattr == CEH_ARRAY ) {
1307 1         2 @narray = @{ ${ $properties[$$self] }{$prop}[CEH_PVAL] };
  1         1  
  1         4  
1308 1         2 ${ $properties[$$self] }{$prop}[CEH_PVAL] = [];
  1         3  
1309 1         4 foreach ( $i = 0; $i <= $#narray; $i++ ) {
1310 7 100       9 next if grep { $_ == $i } @elements;
  14         30  
1311 5         4 CORE::push @{ ${ $properties[$$self] }{$prop}[CEH_PVAL] },
  5         6  
  5         16  
1312             $narray[$i];
1313             }
1314             } else {
1315 1         2 delete @{ ${ $properties[$$self] }{$prop}[CEH_PVAL] }{@elements};
  1         2  
  1         6  
1316             }
1317              
1318 2         9 return 1;
1319             }
1320              
1321             sub purge ($$) {
1322              
1323             # Purpose: Empties the specified hash or array property
1324             # Returns: Boolean
1325             # Usage: $obj->remove($prop);
1326              
1327 12     12 1 8058 my $self = CORE::shift;
1328 12         23 my $prop = CORE::shift;
1329 12         28 my @elements = splice @_;
1330 12         22 my $caller = caller;
1331 12         16 my ( $pattr, $i, @narray );
1332              
1333             # Check for access rights
1334 12         29 $prop = _chkAccess( $self, $caller, $prop );
1335              
1336             # Make sure it's an array or hash
1337 12         18 $pattr = ${ $properties[$$self] }{$prop}[CEH_ATTR] & CEH_ATTR_TYPE;
  12         34  
1338 12 50 66     58 croak "Can't remove values for non-hash/arrays like $prop"
1339             unless $pattr == CEH_HASH
1340             or $pattr == CEH_ARRAY;
1341              
1342 12 100       33 ${ $properties[$$self] }{$prop}[CEH_PVAL] =
  12         30  
1343             $pattr == CEH_ARRAY ? [] : {};
1344              
1345 12         70 return 1;
1346             }
1347              
1348             sub DESTROY ($) {
1349              
1350             # Purpose: Walks the child heirarchy and releases all those
1351             # children before finally releasing this object
1352             # Returns: Boolean
1353             # Usage: $obj->DESTROY;
1354              
1355 40     40   5597 my $self = CORE::shift;
1356 40         50 my ( @descendants, $child, $parent, $class );
1357              
1358 40 50       113 if ( defined $objects[$$self] ) {
1359              
1360             # Working backwards we'll disown each child and release it
1361 40         126 @descendants = $self->descendants;
1362 40         83 foreach $child ( reverse @descendants ) {
1363 10         30 $parent = $child->parent;
1364 10 50       30 $parent = $self unless defined $parent;
1365 10         26 $parent->disown($child);
1366 10         33 $child = undef;
1367             }
1368              
1369             # Third, execute the _deconstruct from the bottom up
1370 9     9   75 no strict 'refs';
  9         14  
  9         1340  
1371 40         62 foreach $class ( @{ $objects[$$self][CEH_SUPER] } ) {
  40         108  
1372 0         0 &{"${class}::_deconstruct"}($self)
  48         309  
1373 48 50       54 if defined *{"${class}::_deconstruct"};
1374             }
1375              
1376             # Fourth, deregister object
1377 40         98 _deregObj($self);
1378             }
1379              
1380 40         1133 return 1;
1381             }
1382             }
1383              
1384             1;
1385              
1386             __END__