File Coverage

blib/lib/Stem/Class.pm
Criterion Covered Total %
statement 37 152 24.3
branch 19 88 21.5
condition 4 19 21.0
subroutine 5 14 35.7
pod 0 1 0.0
total 65 274 23.7


line stmt bran cond sub pod time code
1             # File: Stem/Class.pm
2              
3             # This file is part of Stem.
4             # Copyright (C) 1999, 2000, 2001 Stem Systems, Inc.
5              
6             # Stem is free software; you can redistribute it and/or modify
7             # it under the terms of the GNU General Public License as published by
8             # the Free Software Foundation; either version 2 of the License, or
9             # (at your option) any later version.
10              
11             # Stem is distributed in the hope that it will be useful,
12             # but WITHOUT ANY WARRANTY; without even the implied warranty of
13             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14             # GNU General Public License for more details.
15              
16             # You should have received a copy of the GNU General Public License
17             # along with Stem; if not, write to the Free Software
18             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19              
20             # For a license to use the Stem under conditions other than those
21             # described here, to purchase support for this software, or to purchase a
22             # commercial warranty contract, please contact Stem Systems at:
23              
24             # Stem Systems, Inc. 781-643-7504
25             # 79 Everett St. info@stemsystems.com
26             # Arlington, MA 02474
27             # USA
28              
29             package Stem::Class ;
30              
31 4     4   22 use strict ;
  4         6  
  4         7476  
32              
33             #use Data::Dumper ;
34              
35             # dispatch table for attribute 'type' checking and conversion
36              
37             my %type_to_code = (
38              
39             'boolean' => \&_type_boolean,
40             'hash' => \&_type_hash,
41             'list' => \&_type_list,
42             'HoL' => \&_type_hash_of_list,
43             'LoL' => \&_type_list_of_list,
44             'HoH' => \&_type_hash_of_hash,
45             'LoH' => \&_type_list_of_hash,
46             'addr' => \&_type_address,
47             'address' => \&_type_address,
48             'obj' => \&_type_object,
49             'object' => \&_type_object,
50             'cb_object' => \&_type_object,
51             'handle' => \&_type_handle,
52             ) ;
53              
54             sub parse_args {
55              
56 7     7 0 116 my( $attr_spec, %args_in ) = @_ ;
57              
58 7         21 my( $package ) = caller ;
59              
60             #print "PACK $package\n" ;
61              
62 7         28 my $obj = bless {}, $package ;
63              
64             #print Dumper( $attr_spec ) ;
65             #print "class args ", Dumper( \%args_in ) ;
66              
67 7         9 my( $cell_info_obj, $cell_info_name ) ;
68              
69 7   50     37 my $reg_name = $args_in{ 'reg_name' } || '' ;
70              
71 7         10 foreach my $field ( @{$attr_spec} ) {
  7         17  
72              
73 52 50       148 my $field_name = $field->{'name'} or next ;
74              
75 52         66 my $field_val = $args_in{ $field_name } ;
76              
77 52 50       103 if ( my $class = $field->{'class'} ) {
78              
79             # optinally force a sub-object build by passing a default empty list
80             # for its value
81             # Stem::Cell is always built
82              
83 0 0 0     0 if ( $field->{'always_create'} ||
84             $class eq 'Stem::Cell' ) {
85              
86 0   0     0 $field_val ||= [] ;
87             }
88              
89 0         0 my @class_args ;
90              
91 0 0       0 if ( ref $field_val eq 'HASH' ) {
    0          
92              
93 0         0 @class_args = %{$field_val} ;
  0         0  
94             }
95             elsif ( ref $field_val eq 'ARRAY' ) {
96              
97 0         0 @class_args = @{$field_val} ;
  0         0  
98             }
99             else {
100 0         0 next ;
101             }
102              
103 0         0 my $class_args = $field->{'class_args'} ;
104              
105 0 0 0     0 if ( $class_args && ref $class_args eq 'HASH' ) {
    0 0        
106              
107 0         0 push( @class_args, %{$class_args} ) ;
  0         0  
108             }
109             elsif ( $class_args && ref $class_args eq 'ARRAY' ) {
110              
111 0         0 push( @class_args, @{$class_args} ) ;
  0         0  
112             }
113              
114             # Stem::Cell wants to know its owner's cell name
115              
116 0 0       0 push( @class_args, 'reg_name' => $reg_name )
117             if $class eq 'Stem::Cell' ;
118              
119 0         0 $field_val = $class->new( @class_args ) ;
120              
121 0 0       0 return <
122             Missing attribute class object for '$field_name' for class $package
123             ERR
124              
125 0 0       0 return $field_val unless ref $field_val ;
126              
127             # track the field info for Stem::Cell for use later
128              
129 0 0       0 if ( $class eq 'Stem::Cell' ) {
130              
131 0         0 $cell_info_obj = $field_val ;
132 0         0 $cell_info_name = $field_name ;
133             }
134             }
135              
136             # handle a callback type attribute. it does all the parsing and object stuffing
137             # the callback should return
138              
139 52 50 33     119 if ( my $callback = $field->{'callback'} and $field_val ) {
140              
141              
142 0         0 my $cb_err = $callback->( $obj,
143             $field_name, $field_val ) ;
144              
145 0 0       0 return $cb_err if $cb_err ;
146              
147 0         0 next ;
148             }
149              
150 52 50       109 if ( my $env_name = $field->{'env'} ) {
151              
152 0 0       0 my @prefixes = ( $reg_name ) ?
153             ( "${reg_name}:", "${reg_name}_", '' ) :
154             ( '' ) ;
155              
156 0         0 foreach my $prefix ( @prefixes ) {
157              
158             #print "ENV NAME [$prefix$env_name]\n" ;
159              
160 0         0 my $env_val =
161             $Stem::Vars::Env{"$prefix$env_name"} ;
162              
163 0 0       0 next unless defined $env_val ;
164              
165 0         0 $field_val = $env_val ;
166             #print "ENV field $field_name [$env_val]\n" ;
167 0         0 last ;
168             }
169             }
170              
171 52 100       93 unless( defined $field_val ) {
172              
173 32 50       62 if ( $field->{'required'} ) {
174              
175 0         0 return <
176             Missing required field '$field_name' for class $package
177             ERR
178             }
179              
180 32 100       73 $field_val = $field->{'default'}
181             if exists $field->{'default'} ;
182             }
183              
184             #print "field $field_name [$field_val]\n" ;
185              
186 52 100       95 next unless defined $field_val ;
187              
188 38 100       110 if ( my $type = $field->{'type'} ) {
189            
190 21         38 my $type_code = $type_to_code{$type} ;
191 21 50       36 return "Unknown attribute type '$type'"
192             unless $type_code ;
193            
194 21         49 my $err = $type_code->(
195             \$field_val, $type, $field_name ) ;
196             #print "ERR $err\n" ;
197 21 50       50 return $err if $err ;
198             }
199              
200 38         132 $obj->{$field_name} = $field_val ;
201             }
202              
203 7 50       20 if ( $cell_info_obj ) {
204              
205 0 0       0 return <
206             Missing 'name' in configuration for class $package.
207             It is required for use by Stem::Cell
208             ERR
209              
210 0         0 $cell_info_obj->cell_init( $obj,
211             $reg_name,
212             $cell_info_name
213             ) ;
214             }
215              
216             #print "class obj ", Dumper( $obj ) ;
217              
218 7         25 return $obj ;
219             }
220              
221             sub _type_boolean {
222              
223 10     10   16 my ( $val_ref, $type ) = @_ ;
224              
225 10         86 return if ${$val_ref} =~ s/^(?:|1|Y|Yes)$/1/i ||
  3         294  
226 10 50 66     12 ${$val_ref} =~ s/^(?:|0|N|No)$/0/i ;
227              
228 0         0 return "Attribute value '${$val_ref}' is not boolean"
  0         0  
229             }
230              
231             sub _type_object {
232              
233 7     7   12 my ( $val_ref, $type ) = @_ ;
234              
235 7 50       7 return if ref ${$val_ref} ;
  7         26  
236              
237 0         0 return "Attribute value '${$val_ref}' is not an object"
  0         0  
238             }
239              
240             sub _type_address {
241              
242 0     0   0 my ( $val_ref, $type, $name ) = @_ ;
243              
244 0         0 my( $to_hub, $cell_name, $target ) =
245 0         0 Stem::Msg::split_address( ${$val_ref} ) ;
246              
247 0 0       0 return if $cell_name ;
248              
249 0         0 return "Attribute $name: value '${$val_ref}' is not a valid Stem address"
  0         0  
250             }
251              
252             sub _type_handle {
253              
254 4     4   7 my ( $val_ref, $type ) = @_ ;
255              
256 4 50       7 return if defined fileno( ${$val_ref} ) ;
  4         17  
257              
258 0           return "Attribute value '${$val_ref}' is not an open IO handle"
  0            
259             }
260              
261             sub _type_list {
262              
263 0     0     my ( $val_ref, $type ) = @_ ;
264              
265 0           my $err = _convert_to_list( $val_ref ) ;
266              
267 0 0         return unless $err ;
268              
269 0           return "Attribute value '${$val_ref}' is not a list\n$err" ;
  0            
270             }
271              
272             sub _type_hash {
273              
274 0     0     my ( $val_ref, $type ) = @_ ;
275              
276 0           my $err = _convert_to_hash( $val_ref ) ;
277              
278 0 0         return unless $err ;
279              
280 0           return "Attribute value '${$val_ref}' is not a hash\n$err" ;
  0            
281             }
282              
283             sub _type_list_of_list {
284              
285 0     0     my ( $val_ref, $type ) = @_ ;
286              
287             #print Dumper $val_ref ;
288 0           my $err = _convert_to_list( $val_ref ) ;
289              
290             #print Dumper $val_ref ;
291              
292 0 0         return $err if $err ;
293              
294 0           foreach my $sub_val ( @{$$val_ref}) {
  0            
295              
296 0           $err = _convert_to_list( \$sub_val ) ;
297 0 0         return <
298             Attribute's secondary value '$sub_val' can't be converted to a list\n$err" ;
299             ERR
300             }
301              
302             #print Dumper $val_ref ;
303              
304 0           return ;
305             }
306              
307             sub _type_list_of_hash {
308              
309 0     0     my ( $val_ref, $type ) = @_ ;
310              
311             #print Dumper $val_ref ;
312 0           my $err = _convert_to_list( $val_ref ) ;
313              
314             #print Dumper $val_ref ;
315              
316 0 0         return $err if $err ;
317              
318 0           foreach my $sub_val ( @{$$val_ref}) {
  0            
319              
320 0           $err = _convert_to_hash( \$sub_val ) ;
321 0 0         return <
322             Attribute's secondary value '$sub_val' can't be converted to a hash\n$err" ;
323             ERR
324             }
325              
326             #print Dumper $val_ref ;
327              
328 0           return ;
329             }
330              
331              
332             sub _type_hash_of_list {
333              
334 0     0     my ( $val_ref, $type ) = @_ ;
335              
336             #print Dumper $val_ref ;
337 0           my $err = _convert_to_hash( $val_ref ) ;
338              
339             #print Dumper $val_ref ;
340              
341 0 0         return $err if $err ;
342              
343 0           foreach my $val ( values %{$$val_ref}) {
  0            
344              
345 0           $err = _convert_to_list( \$val ) ;
346 0 0         return <
347             Attribute's secondary value '$val' can't be converted to a list\n$err" ;
348             ERR
349             }
350              
351             #print Dumper $val_ref ;
352              
353 0           return ;
354             }
355              
356             sub _type_hash_of_hash {
357              
358 0     0     my ( $val_ref, $type ) = @_ ;
359              
360             #print Dumper $val_ref ;
361 0           my $err = _convert_to_hash( $val_ref ) ;
362              
363             #print Dumper $val_ref ;
364              
365 0 0         return $err if $err ;
366              
367 0           foreach my $val ( values %{$$val_ref}) {
  0            
368              
369 0           $err = _convert_to_hash( \$val ) ;
370 0 0         return <
371             Attribute's secondary value '$val' can't be converted to a hash\n$err" ;
372             ERR
373             }
374              
375             #print Dumper $val_ref ;
376              
377 0           return ;
378             }
379              
380             sub _convert_to_list {
381              
382 0     0     my ( $val_ref ) = @_ ;
383              
384 0           my $val_type = ref ${$val_ref} ;
  0            
385              
386 0 0         return if $val_type eq 'ARRAY' ;
387              
388 0 0         unless ( $val_type ) {
389              
390 0           ${$val_ref} = [ ${$val_ref} ] ;
  0            
  0            
391 0           return ;
392             }
393              
394 0 0         if ( $val_type eq 'HASH' ) {
395              
396 0           ${$val_ref} = [ %{${$val_ref}} ] ;
  0            
  0            
  0            
397 0           return ;
398             }
399              
400 0           return 'It must be a scalar or a reference to an array or hash' ;
401             }
402              
403             sub _convert_to_hash {
404              
405 0     0     my ( $val_ref ) = @_ ;
406              
407 0           my $val_type = ref ${$val_ref} ;
  0            
408              
409 0 0         return if $val_type eq 'HASH' ;
410              
411 0 0         if ( $val_type eq 'ARRAY' ) {
412              
413 0           ${$val_ref} = { @{${$val_ref}} } ;
  0            
  0            
  0            
414 0           return ;
415             }
416              
417 0           return 'It must be a reference to an array or hash' ;
418             }
419              
420             1 ;