| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package POOF; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 6 |  |  | 6 |  | 649 | use 5.007; | 
|  | 6 |  |  |  |  | 17 |  | 
|  | 6 |  |  |  |  | 293 |  | 
| 4 | 7 |  |  | 5 |  | 457 | use strict; | 
|  | 5 |  |  |  |  | 9 |  | 
|  | 5 |  |  |  |  | 121 |  | 
| 5 | 7 |  |  | 5 |  | 41 | use warnings; | 
|  | 5 |  |  |  |  | 558 |  | 
|  | 5 |  |  |  |  | 89 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 5 |  |  | 5 |  | 24 | use B::Deparse; | 
|  | 5 |  |  |  |  | 18 |  | 
|  | 5 |  |  |  |  | 701 |  | 
| 8 | 5 |  |  | 3 |  | 5947 | use Attribute::Handlers; | 
|  | 5 |  |  |  |  | 40595 |  | 
|  | 5 |  |  |  |  | 34 |  | 
| 9 | 3 |  |  | 3 |  | 161 | use Scalar::Util qw(blessed refaddr); | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 415 |  | 
| 10 | 3 |  |  | 3 |  | 24 | use Carp qw(croak confess cluck); | 
|  | 3 |  |  |  |  | 8 |  | 
|  | 3 |  |  |  |  | 208 |  | 
| 11 | 3 |  |  | 3 |  | 3828 | use Class::ISA; | 
|  | 3 |  |  |  |  | 10139 |  | 
|  | 3 |  |  |  |  | 93 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 | 3 |  |  | 3 |  | 2011 | use POOF::Properties; | 
|  | 3 |  |  |  |  | 10 |  | 
|  | 3 |  |  |  |  | 113 |  | 
| 15 | 3 |  |  | 3 |  | 27 | use POOF::DataType; | 
|  | 3 |  |  |  |  | 8 |  | 
|  | 3 |  |  |  |  | 181 |  | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | our $VERSION = '1.4'; | 
| 18 |  |  |  |  |  |  | our $TRACE = 0; | 
| 19 |  |  |  |  |  |  | our $RAISE_EXCEPTION = 'trap'; | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 23 | 3 |  |  | 3 |  | 17 | use constant PROPERTIES      => { }; | 
|  | 3 |  |  |  |  | 8 |  | 
|  | 3 |  |  |  |  | 371 |  | 
| 24 | 3 |  |  | 3 |  | 19 | use constant PROPERTYINDEX   => { }; | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 142 |  | 
| 25 | 3 |  |  | 3 |  | 18 | use constant METHODS         => { }; | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 175 |  | 
| 26 | 3 |  |  | 3 |  | 16 | use constant GROUPS          => { }; | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 164 |  | 
| 27 | 3 |  |  | 3 |  | 17 | use constant PROPBACKREF     => { }; | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 237 |  | 
| 28 | 3 |  |  | 3 |  | 16 | use constant PROPBACKDOOR    => { }; | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 140 |  | 
| 29 | 3 |  |  | 3 |  | 17 | use constant CLASSES         => { }; | 
|  | 3 |  |  |  |  | 4 |  | 
|  | 3 |  |  |  |  | 128 |  | 
| 30 | 3 |  |  | 3 |  | 16 | use constant METHODDISPATCH  => { }; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 240 |  | 
| 31 | 3 |  |  | 3 |  | 17 | use constant ENCFQCLASSNAMES => { }; | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 151 |  | 
| 32 | 3 |  |  | 3 |  | 17 | use constant PROCESSEDFILES  => { }; | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 417 |  | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 36 |  |  |  |  |  |  | # access levels | 
| 37 | 3 |  |  |  |  | 21891 | use constant ACCESSLEVEL => | 
| 38 |  |  |  |  |  |  | { | 
| 39 |  |  |  |  |  |  | 'Private'   => 0, | 
| 40 |  |  |  |  |  |  | 'Protected' => 1, | 
| 41 |  |  |  |  |  |  | 'Public'    => 2, | 
| 42 | 3 |  |  | 3 |  | 18 | }; | 
|  | 3 |  |  |  |  | 5 |  | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 45 |  |  |  |  |  |  | sub new | 
| 46 |  |  |  |  |  |  | { | 
| 47 | 5 |  |  | 5 | 1 | 1198 | my $class = shift; | 
| 48 | 5 |  |  |  |  | 13 | my %args = @_; | 
| 49 |  |  |  |  |  |  |  | 
| 50 | 5 | 50 |  |  |  | 16 | confess "This class cannot be instantiated as a stand along object, it must be inherited instead" | 
| 51 |  |  |  |  |  |  | if $class eq 'POOF'; | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | # define main constructor property definition array | 
| 54 | 5 |  |  |  |  | 17 | my @properties = _processParentProperties($class,{}); | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | # deal with self | 
| 57 | 5 |  |  |  |  | 10 | foreach my $property (@{ +PROPERTIES->{ $class } }) | 
|  | 5 |  |  |  |  | 12 |  | 
| 58 |  |  |  |  |  |  | { | 
| 59 | 15 | 50 |  |  |  | 49 | if (exists $property->{'name'}) | 
| 60 |  |  |  |  |  |  | { | 
| 61 |  |  |  |  |  |  | # add to Properties.pm constructor args | 
| 62 | 15 |  |  |  |  | 77 | push(@properties,{ | 
| 63 |  |  |  |  |  |  | 'class'   => $class, | 
| 64 |  |  |  |  |  |  | 'name'    => $property->{'name'}, | 
| 65 |  |  |  |  |  |  | 'access'  => $property->{'data'}->{'access'}, | 
| 66 |  |  |  |  |  |  | 'virtual' => $property->{'data'}->{'virtual'}, | 
| 67 |  |  |  |  |  |  | 'data'    => POOF::DataType->new($property->{'data'}), | 
| 68 |  |  |  |  |  |  | 'datadef' => $property->{'data'} | 
| 69 |  |  |  |  |  |  | }); | 
| 70 |  |  |  |  |  |  | } | 
| 71 |  |  |  |  |  |  | } | 
| 72 |  |  |  |  |  |  |  | 
| 73 | 5 |  |  |  |  | 10 | my $obj; | 
| 74 | 5 |  |  |  |  | 6 | tie %{$obj}, 'POOF::Properties', \@properties, $class, \&pErrors, \+GROUPS, \+PROPBACKREF, @_; | 
|  | 5 |  |  |  |  | 36 |  | 
| 75 | 3 |  |  |  |  | 5 | bless $obj,$class; | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 3 |  |  |  |  | 6 | $obj->{'___refobj___'} = $obj; | 
| 78 |  |  |  |  |  |  |  | 
| 79 | 3 | 50 | 33 |  |  | 9 | $RAISE_EXCEPTION = $args{'RaiseException'} | 
| 80 |  |  |  |  |  |  | if exists $args{'RaiseException'} && defined $args{'RaiseException'}; | 
| 81 |  |  |  |  |  |  |  | 
| 82 | 3 |  |  |  |  | 23 | $obj->_init( @_ ); | 
| 83 |  |  |  |  |  |  |  | 
| 84 | 0 |  |  |  |  | 0 | return $obj; | 
| 85 |  |  |  |  |  |  | } | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | sub _processParentProperties | 
| 88 |  |  |  |  |  |  | { | 
| 89 | 10 |  |  | 5 |  | 24 | my $class = shift; | 
| 90 | 10 |  |  |  |  | 48 | my $seen = shift; | 
| 91 | 10 |  |  |  |  | 31 | my @properties = @_; | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | # deal with parents | 
| 94 | 10 |  |  |  |  | 45 | foreach my $parent (reverse Class::ISA::super_path($class)) | 
| 95 |  |  |  |  |  |  | { | 
| 96 | 10 | 50 |  |  |  | 225 | next if $seen->{$parent}++; | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | # process it's parents first | 
| 99 | 5 | 100 | 33 |  |  | 17 | @properties = _processParentProperties($parent,$seen,@properties) | 
| 100 |  |  |  |  |  |  | if (exists +PROPERTIES->{ $parent } && $parent ne 'POOF'); | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | # skip any non-defined parent | 
| 103 | 5 | 100 |  |  |  | 17 | next unless exists +PROPERTIES->{ $parent }; | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | # deal with each parent property | 
| 106 | 0 |  |  |  |  | 0 | foreach my $property (@{ +PROPERTIES->{ $parent } }) | 
|  | 0 |  |  |  |  | 0 |  | 
| 107 |  |  |  |  |  |  | { | 
| 108 | 0 | 50 |  |  |  | 0 | if (exists $property->{'name'}) | 
| 109 |  |  |  |  |  |  | { | 
| 110 |  |  |  |  |  |  | # add to Properties.pm constructor args | 
| 111 | 0 |  |  |  |  | 0 | push(@properties,{ | 
| 112 |  |  |  |  |  |  | 'class'   => $parent, | 
| 113 |  |  |  |  |  |  | 'name'    => $property->{'name'}, | 
| 114 |  |  |  |  |  |  | 'access'  => $property->{'data'}->{'access'}, | 
| 115 |  |  |  |  |  |  | 'virtual' => $property->{'data'}->{'virtual'}, | 
| 116 |  |  |  |  |  |  | 'data'    => POOF::DataType->new($property->{'data'}), | 
| 117 |  |  |  |  |  |  | 'datadef' => $property->{'data'} | 
| 118 |  |  |  |  |  |  | }); | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  | } | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  |  | 
| 123 | 5 |  |  |  |  | 14 | return (@properties); | 
| 124 |  |  |  |  |  |  | } | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | sub _init | 
| 127 |  |  |  |  |  |  | { | 
| 128 | 5 |  |  | 5 |  | 6 | my $obj = shift; | 
| 129 | 5 |  |  |  |  | 11 | my %args = @_; | 
| 130 | 5 |  |  |  |  | 13 | return (@_); | 
| 131 |  |  |  |  |  |  | } | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 135 |  |  |  |  |  |  | # Error handling | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | my $ERRORS; | 
| 138 |  |  |  |  |  |  | sub pErrors | 
| 139 |  |  |  |  |  |  | { | 
| 140 | 0 |  |  | 3 | 1 | 0 | my $obj = shift; | 
| 141 | 0 |  |  |  |  | 0 | my ($k,$e) = @_; | 
| 142 |  |  |  |  |  |  |  | 
| 143 | 0 | 0 |  |  |  | 0 | $e->{'description'} = "$e->{'description'}" | 
| 144 |  |  |  |  |  |  | if ref($e); | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | return | 
| 147 | 0 |  |  |  |  | 0 | @_ == 0 | 
| 148 | 0 | 0 |  |  |  | 0 | ? scalar keys %{$ERRORS->{ refaddr($obj) }} | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | : @_ == 1 | 
| 150 |  |  |  |  |  |  | ? delete $ERRORS->{ refaddr($obj) }->{ $k } | 
| 151 |  |  |  |  |  |  | : @_ == 2 | 
| 152 |  |  |  |  |  |  | ? $obj->_AddError($k,$e) | 
| 153 |  |  |  |  |  |  | : undef; | 
| 154 |  |  |  |  |  |  | } | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | sub pGetErrors | 
| 157 |  |  |  |  |  |  | { | 
| 158 | 0 |  |  | 0 | 1 | 0 | my $obj = shift; | 
| 159 |  |  |  |  |  |  | return | 
| 160 | 0 | 0 |  |  |  | 0 | ref $ERRORS->{ refaddr($obj) } | 
| 161 |  |  |  |  |  |  | ? $ERRORS->{ refaddr($obj) } | 
| 162 |  |  |  |  |  |  | : { }; | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | sub pAllErrors | 
| 166 |  |  |  |  |  |  | { | 
| 167 | 0 |  |  | 0 | 0 | 0 | my ($obj) = @_; | 
| 168 | 0 |  |  |  |  | 0 | return scalar(keys %{$obj->pGetAllErrors}); | 
|  | 0 |  |  |  |  | 0 |  | 
| 169 |  |  |  |  |  |  | } | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | sub pGetAllErrors | 
| 172 |  |  |  |  |  |  | { | 
| 173 | 0 |  |  | 0 | 1 | 0 | my ($obj,$parent) = @_; | 
| 174 | 0 |  |  |  |  | 0 | my $errors = {}; | 
| 175 |  |  |  |  |  |  |  | 
| 176 | 0 | 0 |  |  |  | 0 | $parent = | 
| 177 |  |  |  |  |  |  | $parent | 
| 178 |  |  |  |  |  |  | ? "$parent-" | 
| 179 |  |  |  |  |  |  | : ''; | 
| 180 |  |  |  |  |  |  |  | 
| 181 | 0 | 0 |  |  |  | 0 | if ($obj->_Relationship(ref($obj),'POOF::Collection') =~ /^(?:self|child)$/) | 
| 182 |  |  |  |  |  |  | { | 
| 183 | 0 |  |  |  |  | 0 | for(my $i=0; $i<=$#{$obj}; $i++) | 
|  | 0 |  |  |  |  | 0 |  | 
| 184 |  |  |  |  |  |  | { | 
| 185 |  |  |  |  |  |  | # skip non initialized elements of collection | 
| 186 | 0 | 0 |  |  |  | 0 | next unless exists $obj->[$i]; | 
| 187 | 0 | 0 |  |  |  | 0 | if ($obj->_Relationship(ref($obj->[$i]),'POOF') =~ /^(?:self|child)$/) | 
| 188 |  |  |  |  |  |  | { | 
| 189 | 0 |  |  |  |  | 0 | my $error = $obj->[$i]->pGetAllErrors("$parent$i"); | 
| 190 | 0 | 0 |  |  |  | 0 | %{$errors} = (%{$errors},%{$error}) | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 191 |  |  |  |  |  |  | if $error; | 
| 192 |  |  |  |  |  |  | } | 
| 193 |  |  |  |  |  |  | } | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  | else | 
| 196 |  |  |  |  |  |  | { | 
| 197 | 0 |  |  |  |  | 0 | foreach my $prop (@{+PROPERTIES->{ ref($obj) }}) | 
|  | 0 |  |  |  |  | 0 |  | 
| 198 |  |  |  |  |  |  | { | 
| 199 | 0 | 0 |  |  |  | 0 | if ($obj->_Relationship(ref($obj->{$prop->{'name'}}),'POOF') =~ /^(?:self|child)$/) | 
| 200 |  |  |  |  |  |  | { | 
| 201 | 0 |  |  |  |  | 0 | my $error = $obj->{$prop->{'name'}}->pGetAllErrors("$parent$prop->{'name'}"); | 
| 202 | 0 | 0 |  |  |  | 0 | %{$errors} = (%{$errors},%{$error}) | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 203 |  |  |  |  |  |  | if $error; | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  | } | 
| 207 |  |  |  |  |  |  |  | 
| 208 | 0 |  |  |  |  | 0 | my $myErrors = $obj->pGetErrors; | 
| 209 | 0 |  |  |  |  | 0 | map { $errors->{"$parent$_"} = $myErrors->{$_} } keys %{$myErrors}; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 210 | 0 |  |  |  |  | 0 | return $errors; | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | sub _AddError | 
| 214 |  |  |  |  |  |  | { | 
| 215 | 0 |  |  | 0 |  | 0 | my ($obj,$k,$e) = @_; | 
| 216 | 0 | 0 |  |  |  | 0 | unless ($RAISE_EXCEPTION eq 'trap') | 
| 217 |  |  |  |  |  |  | { | 
| 218 | 0 | 0 |  |  |  | 0 | my $error_string = "\nException for " . ref($obj) . "->{'$k'}\n" . "-"x50 . "\n" | 
| 219 |  |  |  |  |  |  | . "\n\tcode = $e->{'code'}" | 
| 220 |  |  |  |  |  |  | . "\n\tvalue = " . (defined $e->{'value'} ? $e->{'value'} : 'undef') | 
| 221 |  |  |  |  |  |  | . "\n\tdescription = $e->{'description'}"; | 
| 222 |  |  |  |  |  |  |  | 
| 223 | 0 | 0 |  |  |  | 0 | if ($RAISE_EXCEPTION eq 'warn') | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | { | 
| 225 | 0 |  |  |  |  | 0 | warn $error_string; | 
| 226 |  |  |  |  |  |  | } | 
| 227 |  |  |  |  |  |  | elsif($RAISE_EXCEPTION eq 'print') | 
| 228 |  |  |  |  |  |  | { | 
| 229 | 0 |  |  |  |  | 0 | print $error_string; | 
| 230 |  |  |  |  |  |  | } | 
| 231 |  |  |  |  |  |  | elsif($RAISE_EXCEPTION eq 'cluck') | 
| 232 |  |  |  |  |  |  | { | 
| 233 | 0 |  |  |  |  | 0 | cluck $error_string ."\n\tstack = "; | 
| 234 |  |  |  |  |  |  | } | 
| 235 |  |  |  |  |  |  | elsif($RAISE_EXCEPTION eq 'confess') | 
| 236 |  |  |  |  |  |  | { | 
| 237 | 0 |  |  |  |  | 0 | confess $error_string ."\n\tstack = "; | 
| 238 |  |  |  |  |  |  | } | 
| 239 |  |  |  |  |  |  | elsif($RAISE_EXCEPTION eq 'croak') | 
| 240 |  |  |  |  |  |  | { | 
| 241 | 0 |  |  |  |  | 0 | croak $error_string; | 
| 242 |  |  |  |  |  |  | } | 
| 243 |  |  |  |  |  |  | elsif($RAISE_EXCEPTION eq 'die') | 
| 244 |  |  |  |  |  |  | { | 
| 245 | 0 |  |  |  |  | 0 | die $error_string; | 
| 246 |  |  |  |  |  |  | } | 
| 247 |  |  |  |  |  |  | } | 
| 248 |  |  |  |  |  |  |  | 
| 249 | 0 |  |  |  |  | 0 | return $ERRORS->{ refaddr($obj) }->{ $k } = $e; | 
| 250 |  |  |  |  |  |  | } | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | sub pRaiseException | 
| 253 |  |  |  |  |  |  | { | 
| 254 | 0 |  |  | 0 | 0 | 0 | my ($obj,$val) = @_; | 
| 255 |  |  |  |  |  |  | return | 
| 256 | 0 | 0 |  |  |  | 0 | defined $val | 
| 257 |  |  |  |  |  |  | ? $RAISE_EXCEPTION = $val | 
| 258 |  |  |  |  |  |  | : $RAISE_EXCEPTION; | 
| 259 |  |  |  |  |  |  | } | 
| 260 |  |  |  |  |  |  |  | 
| 261 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 262 |  |  |  |  |  |  | # Group operations | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | sub pGetPropertiesOfGroups | 
| 265 |  |  |  |  |  |  | { | 
| 266 | 0 |  |  | 0 | 1 | 0 | my $obj = shift; | 
| 267 | 0 |  |  |  |  | 0 | my %props; | 
| 268 | 0 |  |  |  |  | 0 | @props{ $obj->pGetNamesOfGroup(@_) } = $obj->pGetValuesOfGroup(@_); | 
| 269 | 0 |  |  |  |  | 0 | return (%props); | 
| 270 |  |  |  |  |  |  | } | 
| 271 |  |  |  |  |  |  |  | 
| 272 |  |  |  |  |  |  | sub pGetGroups | 
| 273 |  |  |  |  |  |  | { | 
| 274 | 0 |  |  | 0 | 1 | 0 | my ($obj) = @_; | 
| 275 | 0 |  |  |  |  | 0 | return (keys %{ +GROUPS->{ ref $obj } }); | 
|  | 0 |  |  |  |  | 0 |  | 
| 276 |  |  |  |  |  |  | } | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | sub pGetNamesOfGroup | 
| 279 |  |  |  |  |  |  | { | 
| 280 | 2 |  |  | 2 | 1 | 3 | my ($obj,$group) = @_; | 
| 281 |  |  |  |  |  |  |  | 
| 282 |  |  |  |  |  |  | return | 
| 283 | 2 |  |  |  |  | 10 | defined $group && exists +GROUPS->{ ref $obj }->{ $group } | 
| 284 | 2 | 50 | 33 |  |  | 13 | ? (@{ +GROUPS->{ ref $obj }->{ $group } }) | 
| 285 |  |  |  |  |  |  | : (); | 
| 286 |  |  |  |  |  |  | } | 
| 287 |  |  |  |  |  |  |  | 
| 288 |  |  |  |  |  |  | sub pGroup | 
| 289 |  |  |  |  |  |  | { | 
| 290 | 2 |  |  | 2 | 1 | 3 | my ($obj,$group) = @_; | 
| 291 | 2 |  |  |  |  | 8 | return $obj->pGetNamesOfGroup($group); | 
| 292 |  |  |  |  |  |  | } | 
| 293 |  |  |  |  |  |  |  | 
| 294 |  |  |  |  |  |  | sub pGroupEncoded | 
| 295 |  |  |  |  |  |  | { | 
| 296 | 0 |  |  | 0 | 1 | 0 | my ($obj,$group) = @_; | 
| 297 | 0 |  |  |  |  | 0 | return (map { $obj->_encodeFullyQualifyClassName . '-' . $_  }  $obj->pGetNamesOfGroup($group)); | 
|  | 0 |  |  |  |  | 0 |  | 
| 298 |  |  |  |  |  |  | } | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | sub pPropertyNamesEncoded | 
| 301 |  |  |  |  |  |  | { | 
| 302 | 0 |  |  | 0 | 1 | 0 | my ($obj,$refObj,@names) = @_; | 
| 303 | 0 |  |  |  |  | 0 | my $class = ref $refObj; | 
| 304 | 0 |  |  |  |  | 0 | return (map { $obj->_encodeFullyQualifyClassName($refObj) . '-' . $_  }  @names ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 305 |  |  |  |  |  |  | } | 
| 306 |  |  |  |  |  |  |  | 
| 307 |  |  |  |  |  |  | sub pGetValuesOfGroup | 
| 308 |  |  |  |  |  |  | { | 
| 309 | 0 |  |  | 0 | 1 | 0 | my ($obj,$group) = @_; | 
| 310 |  |  |  |  |  |  | return | 
| 311 | 0 |  |  |  |  | 0 | defined $group && $obj->pGetNamesOfGroup($group) | 
| 312 | 0 | 0 | 0 |  |  | 0 | ? (@{$obj}{ $obj->pGetNamesOfGroup($group) }) | 
| 313 |  |  |  |  |  |  | : (); | 
| 314 |  |  |  |  |  |  | } | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | sub pValidGroupName | 
| 317 |  |  |  |  |  |  | { | 
| 318 | 0 | 0 |  | 0 | 1 | 0 | my $obj = ref $_[0] ? +shift : undef; | 
| 319 | 0 |  |  |  |  | 0 | my ($name) = @_; | 
| 320 |  |  |  |  |  |  | return | 
| 321 | 0 | 0 |  |  |  | 0 | $name !~ /^\s*$/ | 
| 322 |  |  |  |  |  |  | ? 1 | 
| 323 |  |  |  |  |  |  | : 0; | 
| 324 |  |  |  |  |  |  | } | 
| 325 |  |  |  |  |  |  |  | 
| 326 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 327 |  |  |  |  |  |  |  | 
| 328 |  |  |  |  |  |  |  | 
| 329 |  |  |  |  |  |  | sub pSetPropertyDeeply | 
| 330 |  |  |  |  |  |  | { | 
| 331 | 0 |  |  | 0 | 1 | 0 | my ($obj,$ref,$val,@path) = @_; | 
| 332 | 0 |  |  |  |  | 0 | my $level = shift @path; | 
| 333 |  |  |  |  |  |  |  | 
| 334 | 0 | 0 |  |  |  | 0 | if (@path) | 
| 335 |  |  |  |  |  |  | { | 
| 336 |  |  |  |  |  |  | # look ahead to see if this is a collection | 
| 337 | 0 | 0 | 0 |  |  | 0 | if (ref($ref->{$level}) && $obj->_Relationship($ref->{$level},'POOF::Collection') =~ /^(?:self|child)$/o ) | 
| 338 |  |  |  |  |  |  | { | 
| 339 |  |  |  |  |  |  | # it's a collection | 
| 340 | 0 |  |  |  |  | 0 | $obj->pSetPropertyDeeply($ref->{$level}->[ shift @path ],$val,@path); | 
| 341 |  |  |  |  |  |  | } | 
| 342 |  |  |  |  |  |  | else | 
| 343 |  |  |  |  |  |  | { | 
| 344 |  |  |  |  |  |  | # no it's not | 
| 345 | 0 |  |  |  |  | 0 | $obj->pSetPropertyDeeply($ref->{$level},$val,@path) | 
| 346 |  |  |  |  |  |  | } | 
| 347 |  |  |  |  |  |  | } | 
| 348 |  |  |  |  |  |  | else | 
| 349 |  |  |  |  |  |  | { | 
| 350 | 0 |  |  |  |  | 0 | $ref->{$level} = $val; | 
| 351 |  |  |  |  |  |  | } | 
| 352 |  |  |  |  |  |  | } | 
| 353 |  |  |  |  |  |  |  | 
| 354 |  |  |  |  |  |  | sub pGetPropertyDeeply | 
| 355 |  |  |  |  |  |  | { | 
| 356 | 0 |  |  | 0 | 1 | 0 | my ($obj,$ref,@path) = @_; | 
| 357 | 0 |  |  |  |  | 0 | my $level = shift @path; | 
| 358 |  |  |  |  |  |  | return | 
| 359 | 0 | 0 |  |  |  | 0 | scalar (@path) | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 360 |  |  |  |  |  |  | ? ref($ref) eq 'ARRAY' | 
| 361 |  |  |  |  |  |  | ? $obj->pGetPropertyDeeply($ref->[$level],@path) | 
| 362 |  |  |  |  |  |  | : $obj->pGetPropertyDeeply($ref->{$level},@path) | 
| 363 |  |  |  |  |  |  | : ref($ref) eq 'ARRAY' | 
| 364 |  |  |  |  |  |  | ? $ref->[$level] | 
| 365 |  |  |  |  |  |  | : $ref->{$level}; | 
| 366 |  |  |  |  |  |  | } | 
| 367 |  |  |  |  |  |  |  | 
| 368 |  |  |  |  |  |  | sub pInstantiate | 
| 369 |  |  |  |  |  |  | { | 
| 370 | 0 |  |  | 0 | 0 | 0 | my ($obj,$prop) = @_; | 
| 371 |  |  |  |  |  |  | return | 
| 372 | 0 |  |  |  |  | 0 | $obj->pPropertyDefinition($prop)->{'otype'}->new | 
| 373 |  |  |  |  |  |  | ( | 
| 374 |  |  |  |  |  |  | $obj->pGetPropertiesOfGroups('Application'), | 
| 375 |  |  |  |  |  |  | RaiseException => $POOF::RAISE_EXCEPTION | 
| 376 |  |  |  |  |  |  | ); | 
| 377 |  |  |  |  |  |  | } | 
| 378 |  |  |  |  |  |  |  | 
| 379 |  |  |  |  |  |  | sub pReInstantiateSelf | 
| 380 |  |  |  |  |  |  | { | 
| 381 | 0 |  |  | 0 | 0 | 0 | my ($obj,%args) = @_; | 
| 382 |  |  |  |  |  |  | return | 
| 383 | 0 |  |  |  |  | 0 | ref($obj)->new( | 
| 384 |  |  |  |  |  |  | $obj->pGetPropertiesOfGroups('Application'), | 
| 385 |  |  |  |  |  |  | %args | 
| 386 |  |  |  |  |  |  | ); | 
| 387 |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  |  | 
| 389 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 390 |  |  |  |  |  |  | # property definitions | 
| 391 |  |  |  |  |  |  |  | 
| 392 |  |  |  |  |  |  | sub pPropertyEnumOptions | 
| 393 |  |  |  |  |  |  | { | 
| 394 | 0 |  |  | 0 | 1 | 0 | my ($obj,$propName) = @_; | 
| 395 | 0 | 0 |  |  |  | 0 | confess "There are no properties associated with " . ref($obj) | 
| 396 |  |  |  |  |  |  | unless exists +PROPBACKREF->{ ref($obj) }; | 
| 397 | 0 |  |  |  |  | 0 | return +PROPBACKREF->{ ref($obj) }->EnumOptions($propName); | 
| 398 |  |  |  |  |  |  | } | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | sub pPropertyDefinition | 
| 401 |  |  |  |  |  |  | { | 
| 402 | 0 |  |  | 0 | 1 | 0 | my ($obj,$propName) = @_; | 
| 403 | 0 | 0 |  |  |  | 0 | confess "There are no properties associated with " . ref($obj) | 
| 404 |  |  |  |  |  |  | unless exists +PROPBACKREF->{ ref($obj) }; | 
| 405 |  |  |  |  |  |  |  | 
| 406 | 0 |  |  |  |  | 0 | return +PROPBACKREF->{ ref($obj) }->Definition($propName); | 
| 407 |  |  |  |  |  |  | } | 
| 408 |  |  |  |  |  |  |  | 
| 409 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 410 |  |  |  |  |  |  | our $AUTOLOAD; | 
| 411 |  |  |  |  |  |  | sub AUTOLOAD | 
| 412 |  |  |  |  |  |  | { | 
| 413 | 0 |  |  | 0 |  | 0 | my $obj = shift; | 
| 414 |  |  |  |  |  |  |  | 
| 415 | 0 |  |  |  |  | 0 | my $name = $AUTOLOAD; | 
| 416 | 0 |  |  |  |  | 0 | $name =~ s/.*://;   # strip fully-qualified portion | 
| 417 |  |  |  |  |  |  |  | 
| 418 | 0 | 0 |  |  |  | 0 | my $super = | 
| 419 |  |  |  |  |  |  | $AUTOLOAD =~ /\:SUPER\:/o | 
| 420 |  |  |  |  |  |  | ? 1 | 
| 421 |  |  |  |  |  |  | : 0; | 
| 422 |  |  |  |  |  |  |  | 
| 423 | 0 |  | 0 |  |  | 0 | my $class = ref($obj) || confess "$obj is not an object"; | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | # TDB: handle super correctly, if the parent does not have the method | 
| 426 |  |  |  |  |  |  | # then try his parent and so on until we hit the top, if no method | 
| 427 |  |  |  |  |  |  | # is found then throw and exeption. | 
| 428 | 0 |  |  |  |  | 0 | my $package = | 
| 429 |  |  |  |  |  |  | $super | 
| 430 | 0 | 0 |  |  |  | 0 | ? shift @{[ Class::ISA::super_path( $class ) ]} | 
| 431 |  |  |  |  |  |  | : $class; | 
| 432 |  |  |  |  |  |  |  | 
| 433 |  |  |  |  |  |  | # just return undef if we are dealing with built in methods like DESTROY | 
| 434 | 0 | 0 |  |  |  | 0 | return if $name eq 'DESTROY'; | 
| 435 |  |  |  |  |  |  |  | 
| 436 | 0 | 0 |  |  |  | 0 | if ($TRACE) | 
| 437 |  |  |  |  |  |  | { | 
| 438 | 3 |  |  | 3 |  | 214 | no warnings; | 
|  | 3 |  |  |  |  | 21 |  | 
|  | 3 |  |  |  |  | 4655 |  | 
| 439 | 0 |  |  |  |  | 0 | warn qq|$AUTOLOAD for ($package) called from | . (caller(0))[0] . "\n"; | 
| 440 | 0 |  |  |  |  | 0 | warn qq|$AUTOLOAD for ($package) called from | . (caller(1))[0] . "\n"; | 
| 441 | 0 |  |  |  |  | 0 | warn qq|$AUTOLOAD for ($package) called from | . (caller(2))[0] . "\n"; | 
| 442 | 0 |  |  |  |  | 0 | warn qq|$AUTOLOAD for ($package) called from | . (caller(3))[0] . "\n"; | 
| 443 | 0 |  |  |  |  | 0 | warn qq|$AUTOLOAD for ($package) called from | . (caller(4))[0] . "\n"; | 
| 444 | 0 |  |  |  |  | 0 | warn "\twith " . scalar(@_) . " parameters\n"; | 
| 445 |  |  |  |  |  |  | } | 
| 446 |  |  |  |  |  |  |  | 
| 447 |  |  |  |  |  |  |  | 
| 448 |  |  |  |  |  |  | # make sure we apply the inheritance rules the first time a class is used. | 
| 449 | 0 | 0 |  |  |  | 0 | $obj->_BuildMethodDispatch( $package ) | 
| 450 |  |  |  |  |  |  | unless exists +METHODDISPATCH->{ $package }; | 
| 451 |  |  |  |  |  |  |  | 
| 452 | 0 | 0 | 0 |  |  | 0 | confess "$name method does not exist in class $package" | 
| 453 |  |  |  |  |  |  | unless ( | 
| 454 |  |  |  |  |  |  | exists +METHODDISPATCH->{ $package }->{ $name } | 
| 455 |  |  |  |  |  |  | and exists +METHODDISPATCH->{ $package }->{ $name }->{'code'} | 
| 456 |  |  |  |  |  |  | ); | 
| 457 |  |  |  |  |  |  |  | 
| 458 | 0 |  |  |  |  | 0 | my $method = +METHODDISPATCH->{ $package }->{ $name }->{'code'}; | 
| 459 | 0 |  |  |  |  | 0 | my $access = +METHODDISPATCH->{ $package }->{ $name }->{'access'}; | 
| 460 |  |  |  |  |  |  |  | 
| 461 | 0 | 0 |  |  |  | 0 | $access = | 
| 462 |  |  |  |  |  |  | exists ACCESSLEVEL->{ $access } | 
| 463 |  |  |  |  |  |  | ? ACCESSLEVEL->{ $access } | 
| 464 |  |  |  |  |  |  | : ACCESSLEVEL->{ 'Public' }; | 
| 465 |  |  |  |  |  |  |  | 
| 466 | 0 |  |  |  |  | 0 | my $context = $obj->_AccessContext; | 
| 467 |  |  |  |  |  |  |  | 
| 468 | 0 | 0 |  |  |  | 0 | confess "Illegal access of method $name" | 
| 469 |  |  |  |  |  |  | unless $access >= $context; | 
| 470 |  |  |  |  |  |  |  | 
| 471 | 0 |  |  |  |  | 0 | return &{$method}($obj,@_); | 
|  | 0 |  |  |  |  | 0 |  | 
| 472 |  |  |  |  |  |  | } | 
| 473 |  |  |  |  |  |  |  | 
| 474 |  |  |  |  |  |  |  | 
| 475 |  |  |  |  |  |  | sub _BuildMethodDispatch | 
| 476 |  |  |  |  |  |  | { | 
| 477 | 0 |  |  | 0 |  | 0 | my $obj = shift; | 
| 478 | 0 |  |  |  |  | 0 | my $package = shift; | 
| 479 |  |  |  |  |  |  |  | 
| 480 |  |  |  |  |  |  | # get all parents | 
| 481 | 0 |  |  |  |  | 0 | my @parents = Class::ISA::super_path($package); | 
| 482 |  |  |  |  |  |  |  | 
| 483 |  |  |  |  |  |  | # go through each class on the chain | 
| 484 | 0 |  |  |  |  | 0 | foreach my $parent (reverse @parents) | 
| 485 |  |  |  |  |  |  | { | 
| 486 |  |  |  |  |  |  | # non-defined parent will simply get and empty hash | 
| 487 |  |  |  |  |  |  | # and we'll skip to the next parent | 
| 488 | 0 | 0 |  |  |  | 0 | unless (exists +METHODS->{ $parent }) | 
| 489 |  |  |  |  |  |  | { | 
| 490 | 0 |  |  |  |  | 0 | +METHODDISPATCH->{ $parent } = { }; | 
| 491 | 0 |  |  |  |  | 0 | next; | 
| 492 |  |  |  |  |  |  | } | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | # deal with each parent methods | 
| 495 | 0 |  |  |  |  | 0 | foreach my $name (keys %{ +METHODS->{ $parent } }) | 
|  | 0 |  |  |  |  | 0 |  | 
| 496 |  |  |  |  |  |  | { | 
| 497 | 0 |  |  |  |  | 0 | my $method = +METHODS->{ $parent }->{ $name }; | 
| 498 |  |  |  |  |  |  | # skip any private property since they are not accessible | 
| 499 |  |  |  |  |  |  | # from this context, they are only accessible from the class in | 
| 500 |  |  |  |  |  |  | # which they are defined. | 
| 501 | 0 | 0 |  |  |  | 0 | next if $method->{'access'} eq 'Private'; | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | # croak if a method is redefined and it's not marked at virtual | 
| 504 | 0 | 0 | 0 |  |  | 0 | confess "A non-virtual $name has been redefined in $parent" | 
| 505 |  |  |  |  |  |  | if (exists +METHODDISPATCH->{ $package }->{ $name } | 
| 506 |  |  |  |  |  |  | and +METHODDISPATCH->{ $package }->{ $name }->{'virtual'} != 1); | 
| 507 |  |  |  |  |  |  |  | 
| 508 |  |  |  |  |  |  | # add method to dispatch table | 
| 509 | 0 |  |  |  |  | 0 | +METHODDISPATCH->{ $package }->{ $name } = $method; | 
| 510 |  |  |  |  |  |  | } | 
| 511 |  |  |  |  |  |  | } | 
| 512 |  |  |  |  |  |  |  | 
| 513 |  |  |  |  |  |  | # deal with each method in this package | 
| 514 | 0 |  |  |  |  | 0 | foreach my $name (keys %{ +METHODS->{ $package } }) | 
|  | 0 |  |  |  |  | 0 |  | 
| 515 |  |  |  |  |  |  | { | 
| 516 | 0 |  |  |  |  | 0 | my $method = +METHODS->{ $package }->{ $name }; | 
| 517 |  |  |  |  |  |  |  | 
| 518 |  |  |  |  |  |  | # croak if a method is redefined and it's not marked at virtual | 
| 519 | 0 | 0 | 0 |  |  | 0 | confess "A non-virtual $name has been redefined in $package" | 
| 520 |  |  |  |  |  |  | if (exists +METHODDISPATCH->{ $package }->{ $name } | 
| 521 |  |  |  |  |  |  | and +METHODDISPATCH->{ $package }->{ $name }->{'virtual'} != 1); | 
| 522 |  |  |  |  |  |  |  | 
| 523 |  |  |  |  |  |  | # add method to dispatch table | 
| 524 | 0 |  |  |  |  | 0 | +METHODDISPATCH->{ $package }->{ $name } = $method; | 
| 525 |  |  |  |  |  |  | } | 
| 526 |  |  |  |  |  |  | } | 
| 527 |  |  |  |  |  |  |  | 
| 528 |  |  |  |  |  |  |  | 
| 529 |  |  |  |  |  |  | sub _AccessContext | 
| 530 |  |  |  |  |  |  | { | 
| 531 | 0 |  |  | 0 |  | 0 | my ($obj) = @_; | 
| 532 | 0 |  |  |  |  | 0 | my $self = ref($obj); | 
| 533 |  |  |  |  |  |  |  | 
| 534 | 0 |  |  |  |  | 0 | my ($caller) = (caller(1))[0]; | 
| 535 |  |  |  |  |  |  |  | 
| 536 | 0 |  |  |  |  | 0 | my $relationship = $obj->_Relationship($caller,$self); | 
| 537 |  |  |  |  |  |  |  | 
| 538 |  |  |  |  |  |  | return | 
| 539 | 0 | 0 |  |  |  | 0 | $relationship eq 'self' | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 540 |  |  |  |  |  |  | ? 0                         # 'private' | 
| 541 |  |  |  |  |  |  | : $relationship eq 'child' | 
| 542 |  |  |  |  |  |  | ? 1                     # 'protected' | 
| 543 |  |  |  |  |  |  | : $relationship eq 'parent' | 
| 544 |  |  |  |  |  |  | ? 1                 # 'protected' This is wierd shit, but I'm too tired now to fix it. | 
| 545 |  |  |  |  |  |  | : 2                     # 'public'; | 
| 546 |  |  |  |  |  |  | } | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | sub _CallerContext | 
| 549 |  |  |  |  |  |  | { | 
| 550 | 0 |  |  | 0 |  | 0 | my ($obj) = @_; | 
| 551 | 0 | 0 |  |  |  | 0 | $obj->Trace if $TRACE; | 
| 552 | 0 |  |  |  |  | 0 | return (caller(1))[0]; | 
| 553 |  |  |  |  |  |  | } | 
| 554 |  |  |  |  |  |  |  | 
| 555 |  |  |  |  |  |  | sub _Relationship | 
| 556 |  |  |  |  |  |  | { | 
| 557 | 0 |  |  | 0 |  | 0 | my $obj = shift; | 
| 558 | 0 | 0 |  |  |  | 0 | my ($class1,$class2) = map { $_ ? ref $_ ? ref $_ : $_ : '' } @_; | 
|  | 0 | 0 |  |  |  | 0 |  | 
| 559 |  |  |  |  |  |  |  | 
| 560 | 0 | 0 |  |  |  | 0 | return 'self' if $class1 eq $class2; | 
| 561 |  |  |  |  |  |  |  | 
| 562 | 0 |  |  |  |  | 0 | my %family1 = map { $_ => 1 } Class::ISA::super_path( $class1 ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 563 | 0 |  |  |  |  | 0 | my %family2 = map { $_ => 1 } Class::ISA::super_path( $class2 ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 564 |  |  |  |  |  |  |  | 
| 565 |  |  |  |  |  |  | return | 
| 566 | 0 | 0 |  |  |  | 0 | exists $family1{ $class2 } | 
|  |  | 0 |  |  |  |  |  | 
| 567 |  |  |  |  |  |  | ? 'child' | 
| 568 |  |  |  |  |  |  | : exists $family2{ $class1 } | 
| 569 |  |  |  |  |  |  | ? 'parent' | 
| 570 |  |  |  |  |  |  | : 'unrelated'; | 
| 571 |  |  |  |  |  |  | } | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  |  | 
| 574 |  |  |  |  |  |  | sub _DumpAccessContext | 
| 575 |  |  |  |  |  |  | { | 
| 576 | 0 |  |  | 0 |  | 0 | my $obj  = shift; | 
| 577 | 0 |  |  |  |  | 0 | my %caller; | 
| 578 |  |  |  |  |  |  |  | 
| 579 | 0 |  |  |  |  | 0 | for(2 .. 5) | 
| 580 |  |  |  |  |  |  | { | 
| 581 | 0 |  |  |  |  | 0 | @caller{ qw( | 
| 582 |  |  |  |  |  |  | 0-package | 
| 583 |  |  |  |  |  |  | 1-filename | 
| 584 |  |  |  |  |  |  | 2-line | 
| 585 |  |  |  |  |  |  | 3-subr | 
| 586 |  |  |  |  |  |  | 4-has_args | 
| 587 |  |  |  |  |  |  | 5-wantarray | 
| 588 |  |  |  |  |  |  | 6-evaltext | 
| 589 |  |  |  |  |  |  | 7-is_required | 
| 590 |  |  |  |  |  |  | 8-hints | 
| 591 |  |  |  |  |  |  | 9-bitmask | 
| 592 |  |  |  |  |  |  | ) } = caller($_); | 
| 593 |  |  |  |  |  |  |  | 
| 594 | 0 | 0 |  |  |  | 0 | last unless defined $caller{'0-package'}; | 
| 595 |  |  |  |  |  |  |  | 
| 596 | 0 |  |  |  |  | 0 | warn "\ncaller $_\n" . "-"x50 . "\n"; | 
| 597 | 0 |  |  |  |  | 0 | $obj->_DumpCaller(\%caller); | 
| 598 |  |  |  |  |  |  | } | 
| 599 |  |  |  |  |  |  | } | 
| 600 |  |  |  |  |  |  |  | 
| 601 |  |  |  |  |  |  | sub _DumpCore | 
| 602 |  |  |  |  |  |  | { | 
| 603 | 0 |  |  | 0 |  | 0 | my ($obj) = @_; | 
| 604 |  |  |  |  |  |  |  | 
| 605 |  |  |  |  |  |  | #warn "Dumping Core\n"; | 
| 606 |  |  |  |  |  |  | #warn "-"x50 . "\n"; | 
| 607 |  |  |  |  |  |  | #warn "METHODS: ",Dumper( +METHODDISPATCH), "\n"; | 
| 608 |  |  |  |  |  |  | #warn "PROPERTYINDEX: ",Dumper( +PROPERTYINDEX), "\n"; | 
| 609 |  |  |  |  |  |  | #warn "PROPERTIES: ",Dumper( +PROPERTIES), "\n"; | 
| 610 |  |  |  |  |  |  | } | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 614 |  |  |  |  |  |  | # function attribute handlers | 
| 615 |  |  |  |  |  |  |  | 
| 616 | 3 |  |  | 3 | 1 | 26 | sub Method      : ATTR(CODE,BEGIN) { _processFile(@_) } | 
|  | 3 |  |  | 6 |  | 6 |  | 
|  | 3 |  |  |  |  | 33 |  | 
|  | 6 |  |  |  |  | 790 |  | 
| 617 | 3 |  |  | 3 | 0 | 2024 | sub Property    : ATTR(CODE,BEGIN) { _processFile(@_) } | 
|  | 3 |  |  | 14 |  | 8 |  | 
|  | 3 |  |  |  |  | 19 |  | 
|  | 14 |  |  |  |  | 2330 |  | 
| 618 | 3 |  |  | 3 | 1 | 1082 | sub Private     : ATTR(CODE,BEGIN) { _processFile(@_) } | 
|  | 3 |  |  | 2 |  | 8 |  | 
|  | 3 |  |  |  |  | 98 |  | 
|  | 2 |  |  |  |  | 109 |  | 
| 619 | 3 |  |  | 3 | 1 | 1429 | sub Protected   : ATTR(CODE,BEGIN) { _processFile(@_) } | 
|  | 3 |  |  | 0 |  | 6 |  | 
|  | 3 |  |  |  |  | 14 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 620 | 3 |  |  | 3 | 1 | 1729 | sub Public      : ATTR(CODE,BEGIN) { _processFile(@_) } | 
|  | 3 |  |  | 17 |  | 7 |  | 
|  | 3 |  |  |  |  | 13 |  | 
|  | 17 |  |  |  |  | 944 |  | 
| 621 | 3 |  |  | 3 | 1 | 1464 | sub Virtual     : ATTR(CODE,BEGIN) { _processFile(@_) } | 
|  | 3 |  |  | 6 |  | 7 |  | 
|  | 3 |  |  |  |  | 13 |  | 
|  | 6 |  |  |  |  | 272 |  | 
| 622 | 3 |  |  | 3 | 0 | 1358 | sub Doc         : ATTR(CODE,BEGIN) { _processFile(@_) } | 
|  | 3 |  |  | 0 |  | 9 |  | 
|  | 3 |  |  |  |  | 13 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 623 |  |  |  |  |  |  |  | 
| 624 |  |  |  |  |  |  |  | 
| 625 |  |  |  |  |  |  | sub _processFile | 
| 626 |  |  |  |  |  |  | { | 
| 627 | 45 |  |  | 45 |  | 91 | my ($package, $symbol, $referent, $attr, $data, $phase) = @_; | 
| 628 |  |  |  |  |  |  |  | 
| 629 | 45 | 100 |  |  |  | 164 | return if $package =~ /POOF::TEMPORARYNAMESPACE/; | 
| 630 |  |  |  |  |  |  |  | 
| 631 |  |  |  |  |  |  | # convert package name to a path | 
| 632 | 22 | 50 |  |  |  | 30 | my ($filename) = map { exists $INC{"$_.pm"} ? $INC{"$_.pm"} : $0 } map { s!::!/!go; $_ } ($package); | 
|  | 22 |  |  |  |  | 98 |  | 
|  | 22 |  |  |  |  | 77 |  | 
|  | 22 |  |  |  |  | 53 |  | 
| 633 |  |  |  |  |  |  |  | 
| 634 |  |  |  |  |  |  | # just return if we already processed this file | 
| 635 | 22 | 100 |  |  |  | 103 | return if +PROCESSEDFILES->{$filename}++; | 
| 636 |  |  |  |  |  |  |  | 
| 637 | 3 |  |  |  |  | 6 | my $source; | 
| 638 |  |  |  |  |  |  | my $exception; | 
| 639 |  |  |  |  |  |  |  | 
| 640 |  |  |  |  |  |  | # read source from file and untaint it | 
| 641 | 3 | 50 |  |  |  | 277 | open(SOURCEFILE,$filename) || confess "Could not open $filename\n"; | 
| 642 |  |  |  |  |  |  | { | 
| 643 | 3 |  |  |  |  | 8 | local $/ = undef; | 
|  | 3 |  |  |  |  | 17 |  | 
| 644 | 3 |  |  |  |  | 186 | =~ /(.*)/ms;  # put untainted code in $1 | 
| 645 | 3 |  |  |  |  | 22 | $source = $1; | 
| 646 |  |  |  |  |  |  | } | 
| 647 | 3 |  |  |  |  | 39 | close(SOURCEFILE); | 
| 648 |  |  |  |  |  |  |  | 
| 649 |  |  |  |  |  |  | # let's rename the packages so we don't brack perl's inheritance stuff | 
| 650 | 3 |  |  |  |  | 22 | $source =~ s/^package\s+/package POOF::TEMPORARYNAMESPACE/g; | 
| 651 |  |  |  |  |  |  |  | 
| 652 |  |  |  |  |  |  | # now let's evaluate the source using the same nasty string eval which is | 
| 653 |  |  |  |  |  |  | # the reason we have to jump through hoops here (caramba!). | 
| 654 |  |  |  |  |  |  | { | 
| 655 |  |  |  |  |  |  | # creating block to squelch perl's complaining | 
| 656 | 3 |  |  | 3 |  | 4763 | no strict 'refs'; | 
|  | 3 |  |  |  |  | 8 |  | 
|  | 3 |  |  |  |  | 226 |  | 
|  | 3 |  |  |  |  | 36 |  | 
| 657 | 3 |  |  | 3 |  | 17 | no warnings 'redefine'; | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 2047 |  | 
| 658 | 3 |  |  | 3 |  | 47 | eval $source; | 
|  | 3 |  |  | 3 |  | 8 |  | 
|  | 3 |  |  | 3 |  | 617 |  | 
|  | 3 |  |  | 3 |  | 18 |  | 
|  | 3 |  |  | 2 |  | 5 |  | 
|  | 3 |  |  | 4 |  | 223 |  | 
|  | 3 |  |  |  |  | 19 |  | 
|  | 3 |  |  |  |  | 14 |  | 
|  | 3 |  |  |  |  | 333 |  | 
|  | 3 |  |  |  |  | 16 |  | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 468 |  | 
|  | 2 |  |  |  |  | 18 |  | 
|  | 3 |  |  |  |  | 480 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 659 | 3 | 100 |  |  |  | 220 | if($@) | 
| 660 |  |  |  |  |  |  | { | 
| 661 | 1 |  |  |  |  | 2 | $exception = $@; | 
| 662 | 1 |  |  |  |  | 10 | my ($error,$file) = split /\(eval \d+\)/, $exception; | 
| 663 | 1 |  |  |  |  | 5 | my ($replace,$line) = split /\] line /, $file; | 
| 664 | 1 | 50 |  |  |  | 7 | $exception = qq|$error [$filename]| . ($line ? " line $line" : $replace); | 
| 665 | 1 |  |  |  |  | 56 | die $exception; | 
| 666 |  |  |  |  |  |  | } | 
| 667 |  |  |  |  |  |  | } | 
| 668 |  |  |  |  |  |  |  | 
| 669 |  |  |  |  |  |  | # split source into packages but keep the keyword package in each piece; | 
| 670 | 2 |  |  |  |  | 22 | my @packages = map { "package $_" } split(/^package\s+/,$source); | 
|  | 4 |  |  |  |  | 19 |  | 
| 671 |  |  |  |  |  |  |  | 
| 672 |  |  |  |  |  |  | # process each package one at a time | 
| 673 | 2 |  |  |  |  | 7 | foreach my $package (@packages) | 
| 674 |  |  |  |  |  |  | { | 
| 675 | 4 | 100 |  |  |  | 20 | next unless $package =~ m/^package\s+([^\s]+)\s*;/; | 
| 676 | 2 |  |  |  |  | 5 | my $tempclass = $1; | 
| 677 | 2 |  |  |  |  | 5 | my $class = $tempclass; | 
| 678 |  |  |  |  |  |  |  | 
| 679 | 2 |  |  |  |  | 297 | $class =~ s/POOF::TEMPORARYNAMESPACE//g; | 
| 680 |  |  |  |  |  |  |  | 
| 681 |  |  |  |  |  |  | # identify all properties and methods by steping through each line one at a time | 
| 682 | 2 |  |  |  |  | 549 | my @lines = split(/(?:\x0A|\x0D\x0A)/o,$package); | 
| 683 | 2 |  |  |  |  | 14 | foreach (@lines) | 
| 684 |  |  |  |  |  |  | { | 
| 685 | 191 |  |  |  |  | 352 | s/#.*$//; | 
| 686 | 191 | 100 |  |  |  | 445 | if(/\bsub\b\s*([^\s\{\(\:]+)\s*:\s*([^\{]+)\s*(\{|$)?/o) | 
| 687 |  |  |  |  |  |  | { | 
| 688 |  |  |  |  |  |  |  | 
| 689 | 9 |  |  |  |  | 19 | chomp(); | 
| 690 | 9 | 50 |  |  |  | 40 | my ($sub,$end) = ($1,$3 ? $3 : ''); | 
| 691 | 9 |  |  |  |  | 30 | my %attrs = map { $_ => 1 } map { _trim($_) } split(/\s+/,$2); | 
|  | 21 |  |  |  |  | 51 |  | 
|  | 21 |  |  |  |  | 98 |  | 
| 692 |  |  |  |  |  |  |  | 
| 693 |  |  |  |  |  |  | # classify into property or method | 
| 694 | 9 | 100 |  |  |  | 38 | if (exists $attrs{'Method'}) # process method | 
|  |  | 50 |  |  |  |  |  | 
| 695 |  |  |  |  |  |  | { | 
| 696 |  |  |  |  |  |  | # determine access | 
| 697 | 3 |  |  |  |  | 11 | my $access = _determineAccess(%attrs); | 
| 698 |  |  |  |  |  |  | # determine virtual | 
| 699 | 3 |  |  |  |  | 9 | my $virtual = _determineVirtual(%attrs); | 
| 700 |  |  |  |  |  |  |  | 
| 701 |  |  |  |  |  |  | # creating block to squelch perl's complaining | 
| 702 |  |  |  |  |  |  | { | 
| 703 | 3 |  |  | 3 |  | 22 | no strict 'refs'; | 
|  | 3 |  |  |  |  | 69 |  | 
|  | 3 |  |  |  |  | 105 |  | 
|  | 3 |  |  |  |  | 98 |  | 
| 704 | 3 |  |  | 3 |  | 20 | no warnings 'redefine'; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 440 |  | 
| 705 | 3 |  |  |  |  | 4 | +METHODS->{ $class }->{ $sub }->{'code'} = \&{$class . '::' . $sub}; | 
|  | 3 |  |  |  |  | 38 |  | 
| 706 |  |  |  |  |  |  | } | 
| 707 |  |  |  |  |  |  |  | 
| 708 |  |  |  |  |  |  | # handle access | 
| 709 | 3 |  |  |  |  | 1573 | +METHODS->{ $class }->{ $sub }->{'access'} = $access; | 
| 710 |  |  |  |  |  |  |  | 
| 711 |  |  |  |  |  |  | # handle virtual | 
| 712 | 3 |  |  |  |  | 15 | +METHODS->{ $class }->{ $sub }->{'virtual'} = $virtual; | 
| 713 |  |  |  |  |  |  |  | 
| 714 |  |  |  |  |  |  | ## handle documentation | 
| 715 |  |  |  |  |  |  | #+METHODS->{ $class }->{ $sub }->{'doc'} = $doc; | 
| 716 |  |  |  |  |  |  |  | 
| 717 |  |  |  |  |  |  | } | 
| 718 |  |  |  |  |  |  | elsif(exists $attrs{'Property'}) # process property | 
| 719 |  |  |  |  |  |  | { | 
| 720 |  |  |  |  |  |  |  | 
| 721 |  |  |  |  |  |  | # determine access | 
| 722 | 6 |  |  |  |  | 27 | my $access = _determineAccess(%attrs); | 
| 723 |  |  |  |  |  |  | # determine virtual | 
| 724 | 6 |  |  |  |  | 18 | my $virtual = _determineVirtual(%attrs); | 
| 725 |  |  |  |  |  |  |  | 
| 726 | 6 |  |  |  |  | 10 | my $objdef; | 
| 727 |  |  |  |  |  |  | # creating block to squelch perl's complaining | 
| 728 |  |  |  |  |  |  | { | 
| 729 | 3 |  |  | 3 |  | 17 | no strict 'refs'; | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 104 |  | 
|  | 6 |  |  |  |  | 8 |  | 
| 730 | 3 |  |  | 3 |  | 15 | no warnings 'redefine'; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 1309 |  | 
| 731 |  |  |  |  |  |  |  | 
| 732 | 6 |  |  |  |  | 170 | $objdef = | 
| 733 | 6 |  |  |  |  | 251 | ref(&{$tempclass . '::' . $sub}) eq 'HASH' | 
| 734 | 0 |  |  |  |  | 0 | ? &{$tempclass . '::' . $sub} | 
| 735 | 6 | 50 |  |  |  | 13 | : { &{$tempclass . '::' . $sub} }; | 
| 736 |  |  |  |  |  |  | } | 
| 737 |  |  |  |  |  |  | # this should return the hash that defines the property | 
| 738 | 6 | 50 |  |  |  | 18 | %{$objdef} || confess "Properties must be defined by returning a hash ref with their attributes"; | 
|  | 6 |  |  |  |  | 20 |  | 
| 739 |  |  |  |  |  |  |  | 
| 740 | 6 | 50 |  |  |  | 21 | unless (exists +PROPERTYINDEX->{ $class }->{ $sub }) | 
| 741 |  |  |  |  |  |  | { | 
| 742 | 6 |  |  |  |  | 13 | push(@{ +PROPERTIES->{ $class } },{ 'name' => $sub }); | 
|  | 6 |  |  |  |  | 73 |  | 
| 743 | 6 |  |  |  |  | 10 | +PROPERTYINDEX->{ $class }->{ $sub } = $#{ +PROPERTIES->{ $class } }; | 
|  | 6 |  |  |  |  | 23 |  | 
| 744 |  |  |  |  |  |  |  | 
| 745 |  |  |  |  |  |  | # handle groups | 
| 746 | 6 | 100 | 66 |  |  | 40 | if (exists $objdef->{'groups'} && ref($objdef->{'groups'}) eq 'ARRAY') | 
| 747 |  |  |  |  |  |  | { | 
| 748 | 3 |  |  |  |  | 2 | foreach my $group (@{$objdef->{'groups'}}) | 
|  | 3 |  |  |  |  | 9 |  | 
| 749 |  |  |  |  |  |  | { | 
| 750 |  |  |  |  |  |  | #confess "Invalid group name ($group} used in property $sub" | 
| 751 |  |  |  |  |  |  | #    unless ValidGroupName($group); | 
| 752 |  |  |  |  |  |  | } | 
| 753 |  |  |  |  |  |  | } | 
| 754 |  |  |  |  |  |  |  | 
| 755 | 6 |  |  |  |  | 11 | +PROPERTIES->{ $class }->[ +PROPERTYINDEX->{ $class }->{ $sub } ]->{ 'data' } = { %{$objdef},access => $access, virtual => $virtual }; | 
|  | 6 |  |  |  |  | 63 |  | 
| 756 |  |  |  |  |  |  | } | 
| 757 |  |  |  |  |  |  | } | 
| 758 |  |  |  |  |  |  | else | 
| 759 |  |  |  |  |  |  | { | 
| 760 |  |  |  |  |  |  | # just skip, they might be using a non POOF function attribute or a Doc attribute | 
| 761 | 0 |  |  |  |  | 0 | next; | 
| 762 |  |  |  |  |  |  | } | 
| 763 |  |  |  |  |  |  | } | 
| 764 |  |  |  |  |  |  |  | 
| 765 |  |  |  |  |  |  | } | 
| 766 |  |  |  |  |  |  |  | 
| 767 |  |  |  |  |  |  | { | 
| 768 | 3 |  |  | 3 |  | 17 | no strict 'refs'; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 90 |  | 
|  | 2 |  |  |  |  | 5 |  | 
| 769 | 3 |  |  | 3 |  | 14 | no warnings 'redefine'; | 
|  | 3 |  |  |  |  | 11 |  | 
|  | 3 |  |  |  |  | 2304 |  | 
| 770 | 2 |  |  |  |  | 141 | my $table = eval '\\%' . $class . '::'; | 
| 771 | 2 |  |  |  |  | 6 | foreach my $item (keys %{$table}) | 
|  | 2 |  |  |  |  | 10 |  | 
| 772 |  |  |  |  |  |  | { | 
| 773 | 20 | 100 | 100 |  |  | 172 | if (exists +PROPERTYINDEX->{ $class }->{ $item } || exists +METHODS->{ $class }->{ $item }) | 
| 774 |  |  |  |  |  |  | { | 
| 775 | 5 |  |  |  |  | 9 | *{ $table->{$item} } = undef; | 
|  | 5 |  |  |  |  | 506 |  | 
| 776 |  |  |  |  |  |  | } | 
| 777 |  |  |  |  |  |  | } | 
| 778 |  |  |  |  |  |  | } | 
| 779 |  |  |  |  |  |  | } | 
| 780 |  |  |  |  |  |  | } | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | sub _determineAccess | 
| 783 |  |  |  |  |  |  | { | 
| 784 | 9 |  |  | 11 |  | 20 | my %attrs = @_; | 
| 785 |  |  |  |  |  |  | # go from most secure to least secure | 
| 786 |  |  |  |  |  |  | return | 
| 787 | 9 | 50 |  |  |  | 51 | exists $attrs{'Private'} | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 788 |  |  |  |  |  |  | ? 'Private' | 
| 789 |  |  |  |  |  |  | : exists $attrs{'Protected'} | 
| 790 |  |  |  |  |  |  | ? 'Protected' | 
| 791 |  |  |  |  |  |  | : exists $attrs{'Public'} | 
| 792 |  |  |  |  |  |  | ? 'Public' | 
| 793 |  |  |  |  |  |  | : 'Protected'; # will default to procted if nothing has been specified | 
| 794 |  |  |  |  |  |  | } | 
| 795 |  |  |  |  |  |  |  | 
| 796 |  |  |  |  |  |  | sub _determineVirtual | 
| 797 |  |  |  |  |  |  | { | 
| 798 | 9 |  |  | 11 |  | 20 | my %attrs = @_; | 
| 799 |  |  |  |  |  |  | # we make a distinction between properties and methods as they have different defaults | 
| 800 |  |  |  |  |  |  | return | 
| 801 | 9 | 50 |  |  |  | 47 | exists $attrs{'Property'} | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 802 |  |  |  |  |  |  | ? exists $attrs{'Virtual'} | 
| 803 |  |  |  |  |  |  | ? 1 | 
| 804 |  |  |  |  |  |  | : exists $attrs{'NonVirtual'} | 
| 805 |  |  |  |  |  |  | ? 0 | 
| 806 |  |  |  |  |  |  | : 0 # Properties default to Virtual | 
| 807 |  |  |  |  |  |  | : exists $attrs{'Method'} | 
| 808 |  |  |  |  |  |  | ? exists $attrs{'Virtual'} | 
| 809 |  |  |  |  |  |  | ? 1 | 
| 810 |  |  |  |  |  |  | : 0 # Methods default to NonVirtual | 
| 811 |  |  |  |  |  |  | : 0; | 
| 812 |  |  |  |  |  |  | } | 
| 813 |  |  |  |  |  |  |  | 
| 814 |  |  |  |  |  |  | sub _trim | 
| 815 |  |  |  |  |  |  | { | 
| 816 | 21 |  |  | 21 |  | 26 | my ($dat) = @_; | 
| 817 | 21 |  |  |  |  | 71 | $dat =~ s/^\s*//go; | 
| 818 | 21 |  |  |  |  | 97 | $dat =~ s/\s*$//go; | 
| 819 | 21 |  |  |  |  | 49 | return $dat; | 
| 820 |  |  |  |  |  |  | } | 
| 821 |  |  |  |  |  |  |  | 
| 822 |  |  |  |  |  |  | sub log2file | 
| 823 |  |  |  |  |  |  | { | 
| 824 | 0 | 0 |  | 2 | 0 |  | open(FH,">>/tmp/debug_log") || die "Could not open debug_log to write\n($!)\n"; | 
| 825 | 0 |  |  |  |  |  | print FH join(' ', @_) . "\n"; | 
| 826 | 0 |  |  |  |  |  | close(FH) | 
| 827 |  |  |  |  |  |  | } | 
| 828 |  |  |  |  |  |  |  | 
| 829 |  |  |  |  |  |  |  | 
| 830 |  |  |  |  |  |  |  | 
| 831 |  |  |  |  |  |  |  | 
| 832 |  |  |  |  |  |  | 1; | 
| 833 |  |  |  |  |  |  | __END__ |