added some of uri's utility actions for build script
[urisagit/Stem.git] / lib / Stem / Class.pm
CommitLineData
4536f655 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
29package Stem::Class ;
30
31use strict ;
32
33#use Data::Dumper ;
34
35# dispatch table for attribute 'type' checking and conversion
36
37my %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
54sub parse_args {
55
56 my( $attr_spec, %args_in ) = @_ ;
57
58 my( $package ) = caller ;
59
60#print "PACK $package\n" ;
61
62 my $obj = bless {}, $package ;
63
64#print Dumper( $attr_spec ) ;
65#print "class args ", Dumper( \%args_in ) ;
66
67 my( $cell_info_obj, $cell_info_name ) ;
68
69 my $reg_name = $args_in{ 'reg_name' } || '' ;
70
71 foreach my $field ( @{$attr_spec} ) {
72
73 my $field_name = $field->{'name'} or next ;
74
75 my $field_val = $args_in{ $field_name } ;
76
77 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 if ( $field->{'always_create'} ||
84 $class eq 'Stem::Cell' ) {
85
86 $field_val ||= [] ;
87 }
88
89 my @class_args ;
90
91 if ( ref $field_val eq 'HASH' ) {
92
93 @class_args = %{$field_val} ;
94 }
95 elsif ( ref $field_val eq 'ARRAY' ) {
96
97 @class_args = @{$field_val} ;
98 }
99 else {
100 next ;
101 }
102
103 my $class_args = $field->{'class_args'} ;
104
105 if ( $class_args && ref $class_args eq 'HASH' ) {
106
107 push( @class_args, %{$class_args} ) ;
108 }
109 elsif ( $class_args && ref $class_args eq 'ARRAY' ) {
110
111 push( @class_args, @{$class_args} ) ;
112 }
113
114# Stem::Cell wants to know its owner's cell name
115
116 push( @class_args, 'reg_name' => $reg_name )
117 if $class eq 'Stem::Cell' ;
118
119 $field_val = $class->new( @class_args ) ;
120
121 return <<ERR unless $field_val ;
122Missing attribute class object for '$field_name' for class $package
123ERR
124
125 return $field_val unless ref $field_val ;
126
127# track the field info for Stem::Cell for use later
128
129 if ( $class eq 'Stem::Cell' ) {
130
131 $cell_info_obj = $field_val ;
132 $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 if ( my $callback = $field->{'callback'} and $field_val ) {
140
141
142 my $cb_err = $callback->( $obj,
143 $field_name, $field_val ) ;
144
145 return $cb_err if $cb_err ;
146
147 next ;
148 }
149
150 if ( my $env_name = $field->{'env'} ) {
151
152 my @prefixes = ( $reg_name ) ?
153 ( "${reg_name}:", "${reg_name}_", '' ) :
154 ( '' ) ;
155
156 foreach my $prefix ( @prefixes ) {
157
158#print "ENV NAME [$prefix$env_name]\n" ;
159
160 my $env_val =
161 $Stem::Vars::Env{"$prefix$env_name"} ;
162
163 next unless defined $env_val ;
164
165 $field_val = $env_val ;
166#print "ENV field $field_name [$env_val]\n" ;
167 last ;
168 }
169 }
170
171 unless( defined $field_val ) {
172
173 if ( $field->{'required'} ) {
174
175 return <<ERR ;
176Missing required field '$field_name' for class $package
177ERR
178 }
179
180 $field_val = $field->{'default'}
181 if exists $field->{'default'} ;
182 }
183
184#print "field $field_name [$field_val]\n" ;
185
186 next unless defined $field_val ;
187
188 if ( my $type = $field->{'type'} ) {
189
190 my $type_code = $type_to_code{$type} ;
191 return "Unknown attribute type '$type'"
192 unless $type_code ;
193
194 my $err = $type_code->(
195 \$field_val, $type, $field_name ) ;
196#print "ERR $err\n" ;
197 return $err if $err ;
198 }
199
200 $obj->{$field_name} = $field_val ;
201 }
202
203 if ( $cell_info_obj ) {
204
205 return <<ERR unless $reg_name ;
206Missing 'name' in configuration for class $package.
207It is required for use by Stem::Cell
208ERR
209
210 $cell_info_obj->cell_init( $obj,
211 $reg_name,
212 $cell_info_name
213 ) ;
214 }
215
216#print "class obj ", Dumper( $obj ) ;
217
218 return $obj ;
219}
220
221sub _type_boolean {
222
223 my ( $val_ref, $type ) = @_ ;
224
225 return if ${$val_ref} =~ s/^(?:|1|Y|Yes)$/1/i ||
226 ${$val_ref} =~ s/^(?:|0|N|No)$/0/i ;
227
228 return "Attribute value '${$val_ref}' is not boolean"
229}
230
231sub _type_object {
232
233 my ( $val_ref, $type ) = @_ ;
234
235 return if ref ${$val_ref} ;
236
237 return "Attribute value '${$val_ref}' is not an object"
238}
239
240sub _type_address {
241
242 my ( $val_ref, $type, $name ) = @_ ;
243
244 my( $to_hub, $cell_name, $target ) =
245 Stem::Msg::split_address( ${$val_ref} ) ;
246
247 return if $cell_name ;
248
249 return "Attribute $name: value '${$val_ref}' is not a valid Stem address"
250}
251
252sub _type_handle {
253
254 my ( $val_ref, $type ) = @_ ;
255
256 return if defined fileno( ${$val_ref} ) ;
257
258 return "Attribute value '${$val_ref}' is not an open IO handle"
259}
260
261sub _type_list {
262
263 my ( $val_ref, $type ) = @_ ;
264
265 my $err = _convert_to_list( $val_ref ) ;
266
267 return unless $err ;
268
269 return "Attribute value '${$val_ref}' is not a list\n$err" ;
270}
271
272sub _type_hash {
273
274 my ( $val_ref, $type ) = @_ ;
275
276 my $err = _convert_to_hash( $val_ref ) ;
277
278 return unless $err ;
279
280 return "Attribute value '${$val_ref}' is not a hash\n$err" ;
281}
282
283sub _type_list_of_list {
284
285 my ( $val_ref, $type ) = @_ ;
286
287#print Dumper $val_ref ;
288 my $err = _convert_to_list( $val_ref ) ;
289
290#print Dumper $val_ref ;
291
292 return $err if $err ;
293
294 foreach my $sub_val ( @{$$val_ref}) {
295
296 $err = _convert_to_list( \$sub_val ) ;
297 return <<ERR if $err ;
298Attribute's secondary value '$sub_val' can't be converted to a list\n$err" ;
299ERR
300 }
301
302#print Dumper $val_ref ;
303
304 return ;
305}
306
307sub _type_list_of_hash {
308
309 my ( $val_ref, $type ) = @_ ;
310
311#print Dumper $val_ref ;
312 my $err = _convert_to_list( $val_ref ) ;
313
314#print Dumper $val_ref ;
315
316 return $err if $err ;
317
318 foreach my $sub_val ( @{$$val_ref}) {
319
320 $err = _convert_to_hash( \$sub_val ) ;
321 return <<ERR if $err ;
322Attribute's secondary value '$sub_val' can't be converted to a hash\n$err" ;
323ERR
324 }
325
326#print Dumper $val_ref ;
327
328 return ;
329}
330
331
332sub _type_hash_of_list {
333
334 my ( $val_ref, $type ) = @_ ;
335
336#print Dumper $val_ref ;
337 my $err = _convert_to_hash( $val_ref ) ;
338
339#print Dumper $val_ref ;
340
341 return $err if $err ;
342
343 foreach my $val ( values %{$$val_ref}) {
344
345 $err = _convert_to_list( \$val ) ;
346 return <<ERR if $err ;
347Attribute's secondary value '$val' can't be converted to a list\n$err" ;
348ERR
349 }
350
351#print Dumper $val_ref ;
352
353 return ;
354}
355
356sub _type_hash_of_hash {
357
358 my ( $val_ref, $type ) = @_ ;
359
360#print Dumper $val_ref ;
361 my $err = _convert_to_hash( $val_ref ) ;
362
363#print Dumper $val_ref ;
364
365 return $err if $err ;
366
367 foreach my $val ( values %{$$val_ref}) {
368
369 $err = _convert_to_hash( \$val ) ;
370 return <<ERR if $err ;
371Attribute's secondary value '$val' can't be converted to a hash\n$err" ;
372ERR
373 }
374
375#print Dumper $val_ref ;
376
377 return ;
378}
379
380sub _convert_to_list {
381
382 my ( $val_ref ) = @_ ;
383
384 my $val_type = ref ${$val_ref} ;
385
386 return if $val_type eq 'ARRAY' ;
387
388 unless ( $val_type ) {
389
390 ${$val_ref} = [ ${$val_ref} ] ;
391 return ;
392 }
393
394 if ( $val_type eq 'HASH' ) {
395
396 ${$val_ref} = [ %{${$val_ref}} ] ;
397 return ;
398 }
399
400 return 'It must be a scalar or a reference to an array or hash' ;
401}
402
403sub _convert_to_hash {
404
405 my ( $val_ref ) = @_ ;
406
407 my $val_type = ref ${$val_ref} ;
408
409 return if $val_type eq 'HASH' ;
410
411 if ( $val_type eq 'ARRAY' ) {
412
413 ${$val_ref} = { @{${$val_ref}} } ;
414 return ;
415 }
416
417 return 'It must be a reference to an array or hash' ;
418}
419
4201 ;