File Coverage

blib/lib/MRP/BaseClass.pm
Criterion Covered Total %
statement 88 352 25.0
branch 14 162 8.6
condition 7 65 10.7
subroutine 12 29 41.3
pod 4 5 80.0
total 125 613 20.3


line stmt bran cond sub pod time code
1             package MRP::BaseClass;
2              
3 1     1   1532 use Exporter;
  1         2  
  1         42  
4 1     1   4 use Carp;
  1         2  
  1         86  
5 1     1   5 use strict;
  1         4  
  1         38  
6              
7 1     1   633 use MRP::Introspection;
  1         2  
  1         47  
8 1     1   613 use MRP::Text;
  1         3  
  1         27  
9 1     1   1640 use MRP::Interface;
  1         2  
  1         34  
10              
11 1     1   6 use vars qw($AUTOLOAD %cache $VERSION);
  1         2  
  1         6689  
12              
13             $VERSION = 1.0;
14              
15             # print nice diagnostics when functions are incorrectly called
16             #
17             sub AUTOLOAD {
18 0     0   0 my ($package,$name) = $AUTOLOAD =~ /^(.+?)::([^:]+)$/;
19 0 0       0 return if $name eq 'DESTROY';
20             #print "Called with @_ and autoload $AUTOLOAD\n";
21 0   0     0 my $self = shift || die $package."->".$name." called for nothing!";
22 0   0     0 my $ref = ref $self || $self;
23 0 0       0 my $message = ($ref eq $self) ? "Can't access '$name' in class $ref:\n" :
24             "Can't access '$name' in object $self:\n";
25 0         0 my ($member,$func);
26 0 0       0 if($^W) {
27 0 0       0 if(ref $self) {
28 0         0 foreach $member (sort keys %$self) {
29 0 0 0     0 if( $member =~ /$name/i || $name =~ /$member/i ) {
30 0         0 $message .= "Did you mean member\t'$member'?\n";
31             }
32             }
33             }
34 0         0 my %funcs = MRP::Introspection::recursiveInheritance($self,'MRP::Introspection::functions');
35 0         0 foreach $func (sort keys %funcs) {
36 0         0 my ($funcn) = $func =~ /([^:]+)$/;
37 0 0 0     0 if( $funcn =~ /$name/i || $name =~ /$funcn/i ) {
38 0         0 $message .= "Did you mean function\t'$func'?\n";
39             }
40             }
41 0         0 my ($package, $filename, $line) = caller;
42 0         0 $message .= "in $filename at line $line\n";
43 0         0 $message .= "\n".$self->_printMembers()."\n";
44             }
45 0         0 confess $message;
46             }
47              
48             # returns a MRP::MyBase object
49             # use this for all derived classes
50             #
51             sub new {
52 0     0 1 0 my $ref = shift;
53 0   0     0 my $class = ref($ref) || $ref;
54 0         0 my $self = {};
55            
56 0         0 rebless($self,$class);
57              
58             # print "Created $self\n";
59 0         0 return $self;
60             }
61              
62 0     0   0 sub DESTROY {
63             # my $self = shift;
64             # print "Destroying $self\n";
65             }
66              
67             sub clone {
68 0     0 1 0 my $self = shift;
69 0         0 my $depth = shift;
70 0         0 my $clone = {};
71 0         0 my ($name, $value);
72 0         0 my $ref;
73              
74 0 0       0 $depth = defined($depth)
    0          
75             ? ($depth =~ /'shallow'/) ? '' : 1
76             : '';
77              
78 0         0 while (($name, $value) = each %$self) {
79 0 0       0 if($depth) { # if we are doing a deep copy
80 0 0       0 if($ref = ref($value)) { # and we have a reference
81 0         0 for($ref) { # what type of reference?
82 0 0       0 /^HASH$/ && do { %{$self->{$name}} = %$value; next; };
  0         0  
  0         0  
  0         0  
83 0 0       0 /^ARRAY$/ && do { @{$self->{$name}} = @$value; next; };
  0         0  
  0         0  
  0         0  
84 0 0       0 /^SCALAR$/ && do { my $tmp = $$value; $self->{$name} = \$tmp; next; };
  0         0  
  0         0  
  0         0  
85 0 0       0 $clone->{$name} = $value->can('clone') # and clone this object
86             ? $value->clone() # by hook
87             : $value->MRP::BaseClass::clone($depth); # or by crook
88             }
89             } else {
90 0         0 $clone->{$name} = $value;
91             }
92             } else { # if wee are doing a shallow copy
93 0         0 $clone->{$name} = $value; # add each filed itself.
94             }
95             }
96            
97 0         0 bless $clone, ref $self;
98 0         0 return $clone;
99             }
100              
101             # reblesses a reference to a base class object into your class
102             # adds the apropreate members with their default values as
103             # defined in the %fields hash, and modified by initialize
104             # If the default value for any of the fields is a hash or
105             # array ref, puts in a new ref for the object.
106             #
107              
108             sub rebless {
109 0     0 1 0 my ($self,$class,%fields);
110 0 0       0 if(ref $_[0]) {
111 0   0     0 $self = shift || confess "You must give an object to rebless";
112 0   0     0 $class = shift || confess "You must give a package to rebless $self into";
113             } else {
114 0         0 $class = shift;
115 0         0 $self = {};
116 0         0 my @parents = @_;
117 0 0       0 %$self = map { ref $_
  0         0  
118             ? %$_
119             : confess "You tried to treat scalar $_ as an object for rebless"
120             } @parents; # add all the parental fileds to this object
121             #print "Multiple inheritance. $self is created from ", MRP::Text->pretyArray(@parents), "\n";
122             }
123              
124             # add this classes fields to the object
125 0         0 %fields = _fields($class);
126 0         0 foreach my $field (sort keys %fields) {
127 0         0 my $val = $fields{$field};
128 0         0 for (ref $val) {
129 0 0       0 /^ARRAY$/ && do {
130 0         0 $fields{$field} = [];
131 0         0 last;
132             };
133 0 0       0 /^HASH$/ && do {
134 0         0 $fields{$field} = {};
135 0         0 last;
136             };
137             }
138             }
139 0         0 %{$self} = (%{$self}, %fields);
  0         0  
  0         0  
140             #print "Reblessing $self into $class\n";
141 0         0 bless $self, $class;
142 0         0 my $initialize = MRP::Introspection::function($self,'initialize');
143 0 0       0 &$initialize($self) if defined $initialize;
144              
145 0         0 return $self;
146             }
147              
148             # prints a list of all members out - nice but not necisary. Will be lost
149             #
150             sub _printMembers {
151 0     0   0 my $self = shift;
152 0         0 my ($key, $val);
153 0         0 my ($func, $scalar, $hash, $array, $ref);
154 0         0 my $text;
155 0         0 local $^W = undef;
156 0 0       0 if(ref $self) {
157 0         0 $text = "Dumping model for $self\n";
158 0         0 $text .= "Members\n";
159 0         0 $text .= MRP::Text->pretyHash("\t", $self);
160             }
161 0         0 $text .= "Methods\n";
162 0         0 my %funcs = MRP::Introspection::recursiveInheritance($self,'MRP::Introspection::functions');
163 0         0 foreach $func (sort keys %funcs) {
164 0         0 $ref = $funcs{$func};
165 0 0       0 $func =~ /:_/ && next;
166 0 0       0 $func =~ /:memberAccess::.*?_/ && next;
167 0 0       0 $func =~ /(croak)|(confess)|(carp)/ && next;
168 0         0 $text .= "\t$func\t= $ref\n";
169             }
170 0         0 $text .= "Variables\n";
171 0         0 my %scalars = MRP::Introspection::scalars($self);
172 0         0 while (($scalar, $ref) = each %scalars) {
173 0         0 $text .= "\t\$$scalar\t= $$ref\n";
174             }
175 0         0 my %hashes = MRP::Introspection::hashes($self);
176 0         0 while (($hash, $ref) = each %hashes) {
177 0         0 $text .= "\t\%$hash\t= $ref=\n".MRP::Text->pretyHash("\t\t", $ref)."\n";
178             }
179 0         0 my %arrays = MRP::Introspection::arrays($self);
180 0         0 while (($array, $ref) = each %arrays) {
181 0         0 $text .= "\t\@$array\t= $ref=".MRP::Text->pretyArray($ref)."\n";
182             }
183 0         0 return $text;
184             }
185              
186             sub _fields ($) {
187 4     4   13 my $thingy = shift;
188 4         15 my $fields = MRP::Introspection::hash($thingy,'fields');
189 4 50       23 return () unless defined $fields;
190             return (wantarray)
191 0 0       0 ? %$fields
192             : $fields;
193             }
194              
195             # checks for name clashes between a class and all of it's base classes and delegates.
196             # Supports multiple inheritance, and multi-level inheritance
197             #
198             # also makes sure that $package::memberAccess is at the beginning of @$package::INC
199             sub check4Clashes {
200 2     2 1 5 my $class = shift;
201 2         3 my %debug = @_;
202 2         6 my $memberPackage = $class."::memberAccess";
203             # print "Checking $class\n";
204             # open the debug streams
205 2         3 my ($VARIABLES, $DELEGATES);
206 2 50       6 if(exists $debug{'variables'}) {
207 0 0       0 unless(defined(my $fh = $debug{'variables'})) {
    0          
208 0         0 $VARIABLES = \*STDERR;
209             } elsif (ref($fh) eq 'GLOB') {
210 0         0 $VARIABLES = $fh;
211 0         0 $debug{'variables'} = undef;
212             } else {
213 0 0       0 open(VARIABLES, ">>$fh") || die "Could not open $fh for appending: $!";
214 0         0 $VARIABLES = \*VARIABLES;
215 0         0 $debug{'variables'} = 'close';
216             }
217 2         5 } else { $VARIABLES = undef; }
218 2 50       3 if(exists $debug{'delegates'}) {
219 0 0       0 unless(defined(my $fh = $debug{'delegates'})) {
    0          
220 0         0 $DELEGATES = \*STDERR;
221             } elsif (ref($fh) eq 'GLOB') {
222 0         0 $DELEGATES = $fh;
223 0         0 $debug{'delegates'} = undef;
224             } else {
225 0 0       0 open(DELEGATES, ">>$fh") || die "Could not open $fh for output: $!";
226 0         0 $DELEGATES = \*DELEGATES;
227 0         0 $debug{'delegates'} = 'close';
228             }
229 2         5 } else { $DELEGATES = undef; }
230            
231             # get the fields has for $class
232 2   50     352 my $fields = $class->MRP::BaseClass::_fields() || {};
233 2   50     6 my $delegates = MRP::Introspection::hash($class,'delegates') || {};
234 2   50     8 my $variables = MRP::Introspection::array($class,'public_vars') || [];
235 0         0 my %variables = map {
236 2         5 /^([\@\$\%])(.*)$/;
237 0 0       0 ($2,($1 eq '@')
    0          
238             ? []
239             : ($1 eq '%')
240             ? {} : undef
241             )
242             } @$variables;
243 2   50     8 my $default = MRP::Introspection::array($class,'defaults') || [];
244 0         0 my %default = map {
245 2         5 /^([\@\$\%])(.*)$/;
246 0 0       0 ($2,($1 eq '@')
    0          
247             ? []
248             : ($1 eq '%')
249             ? {} : undef
250             )
251             } @$default;
252 2         7 my %all = map { ($_,1) } keys %$fields, keys %variables, keys %default;
  0         0  
253 2   50     7 my $isaref = MRP::Introspection::ISA($class) || [];
254 2         4 my $override;
255 2         3 my @found = ();
256            
257             # check for ambiguous functions
258 2         3 my $isaCache;
259 2         5 my @lISA = @$isaref;
260              
261 2 100       5 if(@lISA) {
262 1         2 my $firstParent = shift @lISA;
263 1         2 $isaCache = $cache{$firstParent};
264 1 50       6 unless($isaCache) {
265 1         30 $firstParent->MRP::BaseClass::check4Clashes();
266 1         2 $isaCache = $cache{$firstParent};
267             }
268             # print "$class: Adding $firstParent\n";
269             }
270              
271 2         3 my @clashes;
272 2 100       3 my %allfunctions = %{scalar($isaCache->{'functions'}) || {}};
  2         31  
273 2 100       5 my %allfields = %{scalar($isaCache->{'fields'}) || {}};
  2         17  
274 2         8 my $classCache = {functions=>{},fields=>{}};
275 2         8 my %classFunctions = MRP::Introspection::functions($class);
276 2         9 my %classFields = MRP::BaseClass->_fields($class);
277 2         8 foreach (keys %classFunctions) { $classFunctions{$_} = [$class, $classFunctions{$_}] }
  30         75  
278 2         7 foreach (keys %classFields) { $classFields{$_} = $class }
  0         0  
279              
280 2         5 foreach my $isa (@lISA) {
281             # print "$class: Checking $isa for clashes\n";
282 0   0     0 my $isaCache = $cache{$isa} || do {$isa->MRP::BaseClass::check4Clashes, $cache{$isa}};
283 0 0       0 my %functions = %{scalar($isaCache->{'functions'}) || {}};
  0         0  
284 0 0       0 my %fields = %{scalar($isaCache->{'fields'}) || {}};
  0         0  
285 0         0 foreach my $function (keys %functions) {
286 0         0 my ($package,$ref) = @{$functions{$function}};
  0         0  
287 0 0       0 if(my $clash = $allfunctions{$function}) {
288 0 0       0 if($clash->[1] ne $ref) {
289 0 0       0 unless($classFunctions{$function}) {
290 0         0 push @clashes, "$package->$function\t <----->\t$clash->[0]"."->$function";
291             }
292             }
293             }
294 0         0 $allfunctions{$function} = $functions{$function};
295             }
296 0         0 foreach my $field (keys %fields) {
297 0 0       0 if(my $clash = $allfields{$field}) {
298 0         0 push @clashes, "method: $isa->$field\t <----->\t$clash->$field";
299             }
300 0         0 $allfields{$field} = $fields{$field};
301             }
302             }
303              
304 2         5 foreach my $delegate (keys %$delegates) {
305 0         0 my $list = $delegates->{$delegate};
306 0 0       0 ref $list || next;
307 0         0 my @list;
308 0         0 foreach my $func (@$list) {
309 0 0 0     0 (ref($func)) and
310             push @list, $func->functions() or
311             push @list, $func;
312             }
313 0         0 foreach my $func (@list) {
314 0 0       0 if(my $clash = $allfunctions{$func}) {
315 0 0       0 unless($classFunctions{$func}) {
316 0         0 push @clashes, "delegate: $delegate->$func\t <-----> " . $clash->[0] . "->$func";
317             }
318             }
319             }
320             }
321              
322 2         42 %allfunctions = (%allfunctions, %classFunctions);
323 2         9 %allfields = (%allfields, %classFields);
324              
325             # check that delegate functions do not clash with fields or inherited functions
326 2         5 foreach my $field (keys %$fields) {
327 0         0 foreach my $delegate (keys %$delegates) {
328 0 0 0     0 push @clashes,
329 0         0 map { ($field eq $_ and
330             not MRP::Introspection::function($class,$field))
331             ? "field $field clashes with $delegate->$_"
332             : ();
333 0         0 } @{$delegates->{$delegate}}
334             }
335             }
336              
337             # check that default variables don't clash with package/field or inherited field variables
338 2         4 foreach my $default (keys %default) {
339 0 0       0 if(exists $fields->{$default}) {
    0          
    0          
340 0         0 push @clashes, "default $default clashes with field";
341             } elsif (exists $allfields{$default}) {
342 0         0 push @clashes, "default $default clashes with inherited field";
343             } elsif (exists $variables{$default}) {
344 0         0 push @clashes, "default $default clashes with variable";
345             }
346             }
347 2         5 %$fields = (%$fields, map { ($_,undef) } keys %default);
  0         0  
348              
349 2 50       6 if(@clashes) {
350 0         0 die "The following parts of $class are ambiguous:\n",
351             join "\n",@clashes,"\n";
352             }
353              
354 2         3 my $func;
355             # add the member access functions
356 2         5 foreach my $item (keys %all) {
357 0         0 my $item_ref = $item.'_ref';
358 0         0 my $item_field = $item.'_field';
359 0         0 my $item_global = $item.'_global';
360 0 0       0 MRP::Introspection::function($memberPackage,$item)
361             && confess "$item already exists in $memberPackage\n";
362             # generate the @default member access functions
363 0 0       0 if(exists $default{$item}) {
    0          
364             #print "Generating defualt function for '$item'\n";
365 0         0 for (ref $default{$item}) {
366 0 0       0 if(/^ARRAY$/) { # this is an array member
    0          
367 0         0 $func = $class->_fieldArrayFunc($memberPackage,$item_field,$item);
368 0         0 $func.= $class->_packageArrayFunc($memberPackage,$item_global,$item);
369             } elsif (/^HASH$/) { # this is a hash member
370 0         0 $func = $class->_fieldHashFunc($memberPackage,$item_field,$item);
371 0         0 $func.= $class->_packageHashFunc($memberPackage,$item_global,$item);
372             } else {
373 0         0 $func = $class->_fieldScalarFunc($memberPackage,$item_field,$item,$fields->{$item});
374 0         0 $func.= $class->_packageScalarFunc($memberPackage,$item_global,$item);
375             }
376             }
377 0         0 $func .= $class->_defaultField($memberPackage, $item,
378             $item_field, $item_global)
379             } elsif(exists $fields->{$item}) {
380 0 0       0 if(exists $variables{$item}) {
381             # Generate access functions for duel field/package items
382             #print "generating dual acces for '$item'\n";
383 0         0 for (ref $fields->{$item}) {
384 0 0       0 if(/^ARRAY$/) {
    0          
385 0         0 $func = $class->_fieldArrayFunc($memberPackage,$item_field,$item);
386             } elsif (/^HASH$/) {
387 0         0 $func = $class->_fieldHashFunc($memberPackage,$item_field,$item);
388             } else {
389 0         0 $func = $class->_fieldScalarFunc($memberPackage,$item_field,$item,$fields->{$item});
390             }
391             }
392 0         0 for (ref $variables{$item}) {
393 0 0       0 if(/^ARRAY$/) {
    0          
394 0         0 $func .= $class->_packageArrayFunc($memberPackage,$item_global,$item);
395             } elsif (/^HASH$/) {
396 0         0 $func .= $class->_packageHashFunc($memberPackage,$item_global,$item);
397             } else {
398 0         0 $func .= $class->_packageScalarFunc($memberPackage,$item_global,$item);
399             }
400             }
401 0         0 $func .= $class->_packageAndField($memberPackage, $item,
402             $item_field, $item_global)
403             } else {
404             # generate field member functions
405             #print "generating field '$item'\n";
406 0         0 for (ref $fields->{$item}) {
407 0 0       0 if(/^ARRAY$/) {
    0          
408 0         0 $func = $class->_fieldArrayFunc($memberPackage,$item);
409             } elsif (/^HASH$/) {
410 0         0 $func = $class->_fieldHashFunc($memberPackage,$item);
411             } else {
412 0         0 $func = $class->_fieldScalarFunc($memberPackage,$item,$fields->{$item});
413             }
414             }
415             }
416             } else {
417             # generate package member functions
418             #print "Generating package member function '$item'";
419 0         0 for (ref $variables{$item}) {
420 0 0       0 if(/^ARRAY$/) {
    0          
421 0         0 $func = $class->_packageArrayFunc($memberPackage,$item);
422             } elsif (/^HASH$/) {
423 0         0 $func = $class->_packageHashFunc($memberPackage,$item);
424             } else {
425 0         0 $func = $class->_packageScalarFunc($memberPackage,$item);
426             }
427             }
428             }
429 0 0       0 $VARIABLES && print $VARIABLES $func;
430             # print "Compiling member access:\n$func\n";
431 0 0       0 eval $func; $@ && die "Error compiling code: $@";
  0         0  
432             }
433             # add the delegation functions
434 2         5 foreach my $delegate (keys %$delegates) {
435             # print "Processing delegate $delegate\n";
436 0 0       0 exists $fields->{$delegate} and
437             die "You have specified $class->$delegate as a delegate but there is a field by that name";
438 0         0 my @interfaces = ();
439 0         0 my $func = "";
440 0         0 foreach my $item (@{$delegates->{$delegate}}) {
  0         0  
441             # print "Generating delegate for '$delegate->$item'\n";
442 0 0       0 if(ref($item)) {
443 0         0 $func .= join '', map { $class->_delegateFunc($memberPackage,$delegate,$_) } ($item->functions());
  0         0  
444 0         0 push @interfaces, $item;
445             } else {
446 0         0 $func .= $class->_delegateFunc($memberPackage,$delegate,$item); # make a function for it
447             }
448 0 0       0 $DELEGATES && print $DELEGATES $func;
449             }
450 0         0 $func .= $class->_delegateAccess($memberPackage,$delegate,@interfaces);
451             # print "Compiling delegates:\n$func\n";
452 0 0       0 eval $func; $@ && die "Error compiling code:\n$func";
  0         0  
453             }
454             # now add that entry to @ISA
455 2         3 my %ISA = map { ($_,1) } @$isaref;
  1         5  
456 2 50 33     13 if(((%all or %$delegates) and not exists $ISA{$class."::memberAccess"})) {
      33        
457 0         0 $memberPackage->MRP::BaseClass::check4Clashes();
458 0         0 unshift(@$isaref, $class."::memberAccess");
459 0         0 %allfunctions = (%allfunctions,%{$cache{$memberPackage}->{functions}});
  0         0  
460             }
461              
462 2         23 $classCache->{functions} = {%allfunctions};
463 2         7 $classCache->{fields} = {%allfields};
464             # print "$class has interface\n", MRP::Text->pretyHash(' ', %allfunctions), "\n";
465            
466 2         5 $cache{$class} = $classCache;
467 2 50       6 close $VARIABLES if $debug{'variables'};
468 2 50       59 close $DELEGATES if $debug{'delegates'};
469             # print "Checked $class\n";
470             }
471              
472             sub _delegateFunc {
473 0     0     my ($thingy, $memberPackage, $delegate, $function) = @_;
474              
475 0           return qq(
476             package $memberPackage;
477             sub $function {
478             my \$self = shift;
479             return \$self->$delegate->$function(\@_);
480             }
481             );
482             }
483              
484             sub _delegateAccess {
485 0     0     my ($thingy, $memberPackage, $item) = (shift,shift,shift);
486              
487 0           my $performChecks = join ";\n", map {qq(MRP::Interface->$_->implementedBy(\$value) or
  0            
488             Carp::confess "Delegate \$value must implement interface $_")
489 0           } map { $_->name() } @_;
490              
491 0           return qq(
492             package $memberPackage;
493             sub $item {
494             my \$self = shift;
495             if(\@_) {
496             my \$value = shift;
497             $performChecks;
498             return \$self->{'$item'} = \$value;
499             } else {
500             return \$self->{'$item'};
501             }
502             }
503             );
504             }
505              
506             sub _fieldScalarFunc {
507 0     0     my ($thingy, $memberPackage, $name, $interface, $item) = @_;
508 0   0       $item ||= $name;
509              
510 0           my $interfaceText = "";
511 0 0         if(ref($interface)) {
512 0           $interface = $interface->name;
513 0           $interfaceText = qq(MRP::Interface->$interface->implementedBy(\$_[0]) or
514             Carp::confess "field \$_[0] must implement interface $interface";);
515              
516             }
517              
518 0           return qq(
519             package $memberPackage;
520             sub $name {
521             my \$self = shift;
522             (\@_)
523             ? do { $interfaceText
524             \$self->{'$item'} = \$_[0];
525             }
526             : \$self->{'$item'};
527             }
528             );
529             }
530              
531             sub _packageScalarFunc {
532 0     0     my ($thingy, $memberPackage, $name, $item) = @_;
533 0   0       $item ||= $name;
534 0           my $packagevar = $thingy.'::'.$item;
535              
536 0           return qq(
537             package $memberPackage;
538             sub $name {
539             my \$class = shift;
540             scalar(\@_)
541             ? \$$packagevar = \$_[0]
542             : \$$packagevar;
543             }
544             );
545             }
546              
547             sub _fieldArrayFunc {
548 0     0     my ($thingy, $memberPackage, $name, $item) = @_;
549 0   0       $item ||= $name;
550 0           my $name_ref = $name.'_ref';
551              
552 0           return qq(
553             package $memberPackage;
554             sub $name {
555             my \$self = shift;
556             if (\@_ or not defined wantarray) {
557             \$self->{'$item'} = [] if not defined \$self->{'$item'};
558             \@{\$self->{'$item'}} = \@_;
559             }
560             my \$ret = \$self->{'$item'};
561             return ref(\$ret)
562             ? (wantarray)
563             ? \@{\$self->{'$item'}}
564             : \$self->{'$item'}
565             : (not defined \$ret)
566             ? undef
567             : &Carp::confess("Ilegal value for $item in \$self\n".\$self->_printMembers);
568             }
569             ) . $thingy->_fieldScalarFunc($memberPackage, $name_ref, undef, $item);
570             }
571              
572             sub _packageArrayFunc {
573 0     0     my ($thingy, $memberPackage, $name, $item) = @_;
574 0   0       $item ||= $name;
575 0           my $packagevar = $thingy.'::'.$item;
576              
577 0           return qq(
578             package $memberPackage;
579             sub $name {
580             my \$class = shift;
581             \@$packagevar = \@_ if (\@_) or not defined wantarray;
582             wantarray
583             ? \@$packagevar
584             : \\\@$packagevar;
585             }
586             );
587             }
588              
589             sub _fieldHashFunc {
590 0     0     my ($thingy, $memberPackage, $name, $item) = @_;
591 0   0       $item ||= $name;
592 0           my $name_ref = $item.'_ref';
593              
594 0           return qq(
595             package $memberPackage;
596             sub $name {
597             my \$self = shift;
598             if(\@_ or not defined wantarray) {
599             if(\@_==1) {
600             my \$val = shift;
601             if(ref \$val eq 'HASH') {
602             %{\$self->{'$item'}} = %\$val;
603             } elsif (ref \$_[0] eq 'ARRAY') {
604             %{\$self->{'$item'}} = \@\$val;
605             } else {
606             Carp::confess "Can not set the hash member variable '$item' to \$val";
607             }
608             } else {
609             %{\$self->{'$item'}} = \@_;
610             }
611             }
612             my \$ret = \$self->{'$item'};
613             return (ref \$ret)
614             ? (wantarray)
615             ? (%{\$self->{'$item'}})
616             : (\$self->{'$item'})
617             : not defined(\$ret)
618             ? undef
619             : Carp::confess "Member $item of \$self has gained the ilegal value '\$ret'" . \$self->_printMembers;
620             }
621             ) . $thingy->_fieldScalarFunc($memberPackage, $name_ref, undef, $item);
622             }
623              
624             sub _packageHashFunc {
625 0     0     my ($thingy, $memberPackage, $name, $item) = @_;
626 0   0       $item ||= $name;
627 0           my $packagevar = $thingy.'::'.$item;
628              
629 0           return qq(
630             package $memberPackage;
631             sub $name {
632             my \$class = shift;
633             \%$packagevar = \@_ if (\@_ or not defined wantarray);
634             wantarray
635             ?\%$packagevar
636             : \\%$packagevar;
637             }
638             );
639             }
640              
641             sub _packageAndField {
642 0     0     my ($thingy,$memberPackage,$item,$fieldFunc,$packageFunc) = @_;
643              
644 0           return qq(
645             package $memberPackage;
646             sub $item {
647             my \$thingy = shift;
648             ref(\$thingy)
649             ? \$thingy->$fieldFunc(\@_)
650             : \$thingy->$packageFunc(\@_);
651             }
652             );
653             }
654              
655             sub _defaultField {
656 0     0     my ($thingy,$memberPackage,$item,$fieldFunc,$packageFunc) = @_;
657              
658 0           return qq(
659             package $memberPackage;
660             sub $item {
661             my \$thingy = shift;
662             my \@return;
663             ref(\$thingy)
664             ? do {
665             \@return = (\$thingy->$fieldFunc(\@_));
666             (\@return &&
667             not (\@return == 1 && not defined(\$return[0])))
668             ? \@return
669             : \$thingy->$packageFunc(\@_)
670             }
671             : \$thingy->$packageFunc(\@_);
672             }
673             );
674             }
675              
676 1     1   13 use vars qw(%builtInRefs);
  1         9  
  1         157  
677             %builtInRefs = map { ($_,1) } qw(REF SCALAR ARRAY HASH CODE GLOB);
678              
679             sub isObject {
680 0     0 0   my $self = shift;
681 0           my $ref = shift;
682 0   0       $ref = ref($ref) || return undef;
683 0 0         exists $builtInRefs{$ref} && return undef;
684 0           return $ref;
685             }
686              
687             BEGIN {
688 1     1   5 use vars qw(@ISA);
  1         2  
  1         49  
689 1     1   21 @ISA = qw(Exporter);
690 1         5 MRP::BaseClass->check4Clashes();
691             }
692              
693             $VERSION; # says use was ok
694             __END__