File Coverage

blib/lib/Class/Gomor.pm
Criterion Covered Total %
statement 75 87 86.2
branch 16 22 72.7
condition 1 6 16.6
subroutine 16 17 94.1
pod 8 8 100.0
total 116 140 82.8


line stmt bran cond sub pod time code
1             #
2             # $Id: Gomor.pm 1633 2009-05-23 13:30:33Z gomor $
3             #
4             package Class::Gomor;
5 10     10   14030 use strict; use warnings;
  10     10   23  
  10         577  
  10         54  
  10         20  
  10         434  
6              
7             our $VERSION = '1.02';
8              
9 10     10   55 use Exporter;
  10         15  
  10         666  
10 10     10   60 use base qw(Exporter);
  10         21  
  10         1154  
11              
12 10     10   65 use Carp;
  10         20  
  10         785  
13              
14 10     10   52 no strict 'refs';
  10         22  
  10         5083  
15              
16             our $Debug = 0;
17             our $NoCheck = 0;
18             our @EXPORT_OK = qw($Debug $NoCheck);
19              
20             sub cgCheckParams {
21 6     6 1 17 my $self = shift;
22 6         12 my ($userParams, $accessors) = @_;
23 6         33 for my $u (keys %$userParams) {
24 2         3 my $valid;
25             my $defined;
26 2         7 for (@$accessors) {
27 3 100       10 ($u eq $_) ? $valid++ : next;
28 2 50       7 defined($userParams->{$u}) && do { $defined++; last };
  2         3  
  2         5  
29             }
30 2 50       14 if (! $valid) {
31 0         0 carp("$self: parameter is invalid: `$u'");
32 0         0 next;
33             }
34 2 50       17 if (! $defined) {
35 0         0 carp("$self: parameter is undef: `$u'");
36 0         0 next;
37             }
38             }
39             }
40              
41             sub cgGetIsaTree {
42 30     30 1 59 my $self = shift;
43 30         42 my ($classes) = @_;
44 30         40 for (@{$self.'::ISA'}) {
  30         122  
45 30         72 push @$classes, $_;
46 30 100       488 $_->cgGetIsaTree($classes) if $_->can('cgGetIsaTree');
47             }
48             }
49            
50             sub cgGetAttributes {
51 10     10 1 83 my $self = shift;
52 10         31 my $classes = [ $self ];
53 10         10589 $self->cgGetIsaTree($classes);
54 10         23 my @attributes = ();
55             {
56             # On perl 5.10.0, we have a warning message:
57             # "::AS" used only once: possible typo ...
58 10     10   68 no warnings;
  10         17  
  10         8106  
  10         19  
59 10         25 for (@$classes) {
60 40 100       46 push @attributes, @{$_.'::AS'} if @{$_.'::AS'};
  10         34  
  40         174  
61 40 100       49 push @attributes, @{$_.'::AA'} if @{$_.'::AA'};
  10         26  
  40         256  
62 40 100       44 push @attributes, @{$_.'::AO'} if @{$_.'::AO'};
  10         32  
  40         177  
63             }
64             }
65 10         511 \@attributes;
66             }
67              
68             sub cgClone {
69 4     4 1 39 my $self = shift;
70 4   33     65 my $class = ref($self) || $self;
71 4 100       169 return bless([ @$self ], $class)
72             if UNIVERSAL::isa($self, 'Class::Gomor::Array');
73 2 50       21 return bless({ %$self }, $class)
74             if UNIVERSAL::isa($self, 'Class::Gomor::Hash');
75 0         0 $self;
76             }
77              
78             sub cgFullClone {
79 2     2 1 6 my $self = shift;
80 2         4 my ($n) = @_;
81 2         8 return [ map { $self->cgFullClone } 1..$n ];
  20         55  
82             }
83              
84             sub cgBuildAccessorsScalar {
85 8     8 1 281 my $self = shift;
86 8         23 my ($accessors) = @_;
87 8         30 for my $a (@$accessors) {
88 8     32   74 *{$self.'::'.$a} = sub { shift->_cgAccessorScalar($a, @_) }
  32         267  
89 8         71 }
90             }
91              
92             sub cgBuildAccessorsArray {
93 8     8 1 100 my $self = shift;
94 8         40 my ($accessors) = @_;
95 8         18 for my $a (@{$accessors}) {
  8         25  
96 8     14   62 *{$self.'::'.$a} = sub { shift->_cgAccessorArray($a, @_) }
  14         186  
97 8         54 }
98             }
99              
100             sub cgDebugPrint {
101 0     0 1   my $self = shift;
102 0           my ($level, $msg) = @_;
103 0 0         return if $Debug < $level;
104 0   0       my $class = ref($self) || $self;
105 0           $class =~ s/^.*:://;
106 0           $msg =~ s/^/DEBUG: $class: /gm;
107 0           print STDERR $msg."\n";
108             }
109              
110             1;
111              
112             =head1 NAME
113              
114             Class::Gomor - another class and object builder
115              
116             =head1 DESCRIPTION
117              
118             This module is yet another class builder. This one adds parameter checking in B constructor, that is to check for attributes existence, and definedness.
119              
120             In order to validate parameters, the module needs to find attributes, and that is the reason for declaring attributes in global variables named B<@AS>, B<@AA>, B<@AO>. They respectively state for Attributes Scalar, Attributes Array and Attributes Other. The last one is used to avoid autocreation of accessors, that is to let you declare your own ones.
121              
122             Attribute validation is performed by looking at classes hierarchy, by following @ISA tree inheritance.
123              
124             The loss in speed by validating all attributes is quite negligeable on a decent machine (Pentium IV, 2.4 GHz) with Perl 5.8.x. But if you want to avoid checking, you can do it, see below.
125              
126             This class is the base class for B and B, so they will inherite the following methods.
127              
128             =head1 GLOBAL VARIABLES
129              
130             =over 4
131              
132             =item B<$NoCheck>
133              
134             Import it in your namespace like this:
135              
136             use Class::Gomor qw($NoCheck);
137              
138             If you want to disable B to improve speed once your program is frozen, you can use this variable. Set it to 1 to disable parameter checking.
139              
140             =item B<$Debug>
141              
142             Import it in your namespace like this:
143              
144             use Class::Gomor qw($Debug);
145              
146             This variable is used by the B method.
147              
148             =back
149              
150             =head1 METHODS
151              
152             =over 4
153              
154             =item B (hash ref, array ref)
155              
156             The attribute checking method takes two arguments, the first is user passed attributes (as a hash reference), the second is the list of valid attributes, gathered via B method (as an array ref). A message is displayed if passed parameters are not valid.
157              
158             =item B (array ref)
159              
160             A recursive method. You pass a class in an array reference as an argument, and then the @ISA array is browsed, recursively. The array reference passed as an argument is increased with new classes, pushed into it. It returns nothing, result is stored in the array ref.
161              
162             =item B
163              
164             This method returns available attributes for caller's object class. It uses B to search recursively in class hierarchy. It then returns an array reference with all possible attributes.
165              
166             =item B (array ref)
167              
168             Accessor creation method. Takes an array reference containing all scalar attributes to create. Scalar accessors are stored in a global variable names B<@AS>. So you call this method at the beginning of your class like that:
169              
170             __PACKAGE__->cgBuildAccessorsScalar(\@AS);
171              
172             =item B (array ref)
173              
174             Accessor creation method. Takes an array reference containing all array attributes to create. Array accessors are stored in a global variable names B<@AA>. So you call this method at the beginning of your class like that:
175              
176             __PACKAGE__->cgBuildAccessorsArray(\@AA);
177              
178             =item B [ (scalar) ]
179              
180             You can clone one of your objects by calling this method. An optional parameter may be used to create multiple clones. Cloning will occure only on the first level attributes, that is, if you have attributes containing other objects, they will not be cloned.
181              
182             =item B [ (scalar) ]
183              
184             This method is the same as B, but will clone all attributes recursively, but only if they are subclassed from B. So, objects created with other modules than B or B will not be cloned.
185              
186             Another thing to note, there is no catch for cycling references (when you link two objects with each others). You have been warned.
187              
188             =item B (scalar, scalar)
189              
190             First argument is a debug level. It is compared with global B<$Debug>, and if it is less than it, the second argument (a message string) is displayed. This method exists because I use it, maybe you will not like it.
191              
192             =back
193              
194             =head1 SEE ALSO
195              
196             L, L
197              
198             =head1 AUTHOR
199            
200             Patrice EGomoRE Auffret
201            
202             =head1 COPYRIGHT AND LICENSE
203              
204             Copyright (c) 2004-2009, Patrice EGomoRE Auffret
205              
206             You may distribute this module under the terms of the Artistic license.
207             See LICENSE.Artistic file in the source distribution archive.
208              
209             =cut