[inseparable changes from match from perl-5.003_97b to perl-5.003_97c]
[p5sagit/p5-mst-13.2.git] / lib / Class / Struct.pm
1 package Class::Struct;
2
3 ## See POD after __END__
4
5 require 5.002;
6
7 use strict;
8 use vars qw(@ISA @EXPORT);
9
10 use Carp;
11
12 require Exporter;
13 @ISA = qw(Exporter);
14 @EXPORT = qw(struct);
15
16 ## Tested on 5.002 and 5.003 without class membership tests:
17 my $CHECK_CLASS_MEMBERSHIP = ($] >= 5.003_95);
18
19 my $print = 0;
20 sub printem {
21     if (@_) { $print = shift }
22     else    { $print++ }
23 }
24
25 {
26     package Class::Struct::Tie_ISA;
27
28     sub TIEARRAY {
29         my $class = shift;
30         return bless [], $class;
31     }
32
33     sub STORE {
34         my ($self, $index, $value) = @_;
35         Class::Struct::_subclass_error();
36     }
37
38     sub FETCH {
39         my ($self, $index) = @_;
40         $self->[$index];
41     }
42
43     sub DESTROY { }
44 }
45
46 sub struct {
47
48     # Determine parameter list structure, one of:
49     #   struct( class => [ element-list ])
50     #   struct( class => { element-list })
51     #   struct( element-list )
52     # Latter form assumes current package name as struct name.
53
54     my ($class, @decls);
55     my $base_type = ref $_[1];
56     if ( $base_type eq 'HASH' ) {
57         $class = shift;
58         @decls = %{shift()};
59         _usage_error() if @_;
60     }
61     elsif ( $base_type eq 'ARRAY' ) {
62         $class = shift;
63         @decls = @{shift()};
64         _usage_error() if @_;
65     }
66     else {
67         $base_type = 'ARRAY';
68         $class = (caller())[0];
69         @decls = @_;
70     }
71     _usage_error() if @decls % 2 == 1;
72
73     # Ensure we are not, and will not be, a subclass.
74
75     my $isa = do {
76         no strict 'refs';
77         \@{$class . '::ISA'};
78     };
79     _subclass_error() if @$isa;
80     tie @$isa, 'Class::Struct::Tie_ISA';
81
82     # Create constructor.
83
84     croak "function 'new' already defined in package $class"
85         if do { no strict 'refs'; defined &{$class . "::new"} };
86
87     my @methods = ();
88     my %refs = ();
89     my %arrays = ();
90     my %hashes = ();
91     my %classes = ();
92     my $got_class = 0;
93     my $out = '';
94
95     $out = "{\n  package $class;\n  use Carp;\n  sub new {\n";
96
97     my $cnt = 0;
98     my $idx = 0;
99     my( $cmt, $name, $type, $elem );
100
101     if( $base_type eq 'HASH' ){
102         $out .= "    my(\$r) = {};\n";
103         $cmt = '';
104     }
105     elsif( $base_type eq 'ARRAY' ){
106         $out .= "    my(\$r) = [];\n";
107     }
108     while( $idx < @decls ){
109         $name = $decls[$idx];
110         $type = $decls[$idx+1];
111         push( @methods, $name );
112         if( $base_type eq 'HASH' ){
113             $elem = "{'$name'}";
114         }
115         elsif( $base_type eq 'ARRAY' ){
116             $elem = "[$cnt]";
117             ++$cnt;
118             $cmt = " # $name";
119         }
120         if( $type =~ /^\*(.)/ ){
121             $refs{$name}++;
122             $type = $1;
123         }
124         if( $type eq '@' ){
125             $out .= "    \$r->$elem = [];$cmt\n";
126             $arrays{$name}++;
127         }
128         elsif( $type eq '%' ){
129             $out .= "    \$r->$elem = {};$cmt\n";
130             $hashes{$name}++;
131         }
132         elsif ( $type eq '$') {
133             $out .= "    \$r->$elem = undef;$cmt\n";
134         }
135         elsif( $type =~ /^\w+(?:::\w+)*$/ ){
136             $out .= "    \$r->$elem = '${type}'->new();$cmt\n";
137             $classes{$name} = $type;
138             $got_class = 1;
139         }
140         else{
141             croak "'$type' is not a valid struct element type";
142         }
143         $idx += 2;
144     }
145     $out .= "    bless \$r;\n  }\n";
146
147     # Create accessor methods.
148
149     if ( $got_class && $CHECK_CLASS_MEMBERSHIP ) {
150         $out .= "  use UNIVERSAL;\n";
151     }
152     my( $pre, $pst, $sel );
153     $cnt = 0;
154     foreach $name (@methods){
155         if ( do { no strict 'refs'; defined &{$class . "::$name"} } ) {
156             carp "function '$name' already defined, overrides struct accessor method"
157                 if $^W;
158         }
159         else {
160             $pre = $pst = $cmt = $sel = '';
161             if( defined $refs{$name} ){
162                 $pre = "\\(";
163                 $pst = ")";
164                 $cmt = " # returns ref";
165             }
166             $out .= "  sub $name {$cmt\n    my \$r = shift;\n";
167             if( $base_type eq 'ARRAY' ){
168                 $elem = "[$cnt]";
169                 ++$cnt;
170             }
171             elsif( $base_type eq 'HASH' ){
172                 $elem = "{'$name'}";
173             }
174             if( defined $arrays{$name} ){
175                 $out .= "    my \$i;\n";
176                 $out .= "    \@_ ? (\$i = shift) : return $pre\$r->$elem$pst;\n";
177                 $sel = "->[\$i]";
178             }
179             elsif( defined $hashes{$name} ){
180                 $out .= "    my \$i;\n";
181                 $out .= "    \@_ ? (\$i = shift) : return $pre\$r->$elem$pst;\n";
182                 $sel = "->{\$i}";
183             }
184             elsif( defined $classes{$name} ){
185                 if ( $CHECK_CLASS_MEMBERSHIP ) {
186                     $out .= "    croak '$name argument is wrong class' if \@_ && ! UNIVERSAL::isa(\$_[0], '$type');\n";
187                 }
188             }
189             $out .= "    croak 'Too many args to $name' if \@_ > 1;\n";
190             $out .= "    \@_ ? ($pre\$r->$elem$sel = shift$pst) : $pre\$r->$elem$sel$pst;\n";
191             $out .= "  }\n";
192         }
193     }
194     $out .= "}\n1;\n";
195
196     print $out if $print;
197     my $result = eval $out;
198     carp $@ if $@;
199 }
200
201 sub _usage_error {
202     confess "struct usage error";
203 }
204
205 sub _subclass_error {
206     croak 'struct class cannot be a subclass (@ISA not allowed)';
207 }
208
209 1; # for require
210
211
212 __END__
213
214 =head1 NAME
215
216 Class::Struct - declare struct-like datatypes as Perl classes
217
218 =head1 SYNOPSIS
219
220     use Class::Struct;
221             # declare struct, based on array:
222     struct( CLASS_NAME => [ ELEMENT_NAME => ELEMENT_TYPE, ... ]);
223             # declare struct, based on hash:
224     struct( CLASS_NAME => { ELEMENT_NAME => ELEMENT_TYPE, ... });
225
226     package CLASS_NAME;
227     use Class::Struct;
228             # declare struct, based on array, implicit class name:
229     struct( ELEMENT_NAME => ELEMENT_TYPE, ... );
230
231
232     package Myobj;
233     use Class::Struct;
234             # declare struct with four types of elements:
235     struct( s => '$', a => '@', h => '%', c => 'My_Other_Class' );
236
237     $obj = new Myobj;               # constructor
238
239                                     # scalar type accessor:
240     $element_value = $obj->s;           # element value
241     $obj->s('new value');               # assign to element
242
243                                     # array type accessor:
244     $ary_ref = $obj->a;                 # reference to whole array
245     $ary_element_value = $obj->a(2);    # array element value
246     $obj->a(2, 'new value');            # assign to array element
247
248                                     # hash type accessor:
249     $hash_ref = $obj->h;                # reference to whole hash
250     $hash_element_value = $obj->h('x'); # hash element value
251     $obj->h('x', 'new value');        # assign to hash element
252
253                                     # class type accessor:
254     $element_value = $obj->c;           # object reference
255     $obj->c->method(...);               # call method of object
256     $obj->c(new My_Other_Class);        # assign a new object
257
258
259 =head1 DESCRIPTION
260
261 C<Class::Struct> exports a single function, C<struct>.
262 Given a list of element names and types, and optionally
263 a class name, C<struct> creates a Perl 5 class that implements
264 a "struct-like" data structure.
265
266 The new class is given a constructor method, C<new>, for creating
267 struct objects.
268
269 Each element in the struct data has an accessor method, which is
270 used to assign to the element and to fetch its value.  The
271 default accessor can be overridden by declaring a C<sub> of the
272 same name in the package.  (See Example 2.)
273
274 Each element's type can be scalar, array, hash, or class.
275
276
277 =head2 The C<struct()> function
278
279 The C<struct> function has three forms of parameter-list.
280
281     struct( CLASS_NAME => [ ELEMENT_LIST ]);
282     struct( CLASS_NAME => { ELEMENT_LIST });
283     struct( ELEMENT_LIST );
284
285 The first and second forms explicitly identify the name of the
286 class being created.  The third form assumes the current package
287 name as the class name.
288
289 An object of a class created by the first and third forms is
290 based on an array, whereas an object of a class created by the
291 second form is based on a hash. The array-based forms will be
292 somewhat faster and smaller; the hash-based forms are more
293 flexible.
294
295 The class created by C<struct> must not be a subclass of another
296 class other than C<UNIVERSAL>.
297
298 A function named C<new> must not be explicitly defined in a class
299 created by C<struct>.
300
301 The I<ELEMENT_LIST> has the form
302
303     NAME => TYPE, ...
304
305 Each name-type pair declares one element of the struct. Each
306 element name will be defined as an accessor method unless a
307 method by that name is explicitly defined; in the latter case, a
308 warning is issued if the warning flag (-w) is set.
309
310
311 =head2 Element Types and Accessor Methods
312
313 The four element types -- scalar, array, hash, and class -- are
314 represented by strings -- C<'$'>, C<'@'>, C<'%'>, and a class name --
315 optionally preceded by a C<'*'>.
316
317 The accessor method provided by C<struct> for an element depends
318 on the declared type of the element.
319
320 =over
321
322 =item Scalar (C<'$'> or C<'*$'>)
323
324 The element is a scalar, and is initialized to C<undef>.
325
326 The accessor's argument, if any, is assigned to the element.
327
328 If the element type is C<'$'>, the value of the element (after
329 assignment) is returned. If the element type is C<'*$'>, a reference
330 to the element is returned.
331
332 =item Array (C<'@'> or C<'*@'>)
333
334 The element is an array, initialized to C<()>.
335
336 With no argument, the accessor returns a reference to the
337 element's whole array.
338
339 With one or two arguments, the first argument is an index
340 specifying one element of the array; the second argument, if
341 present, is assigned to the array element.  If the element type
342 is C<'@'>, the accessor returns the array element value.  If the
343 element type is C<'*@'>, a reference to the array element is
344 returned.
345
346 =item Hash (C<'%'> or C<'*%'>)
347
348 The element is a hash, initialized to C<()>.
349
350 With no argument, the accessor returns a reference to the
351 element's whole hash.
352
353 With one or two arguments, the first argument is a key specifying
354 one element of the hash; the second argument, if present, is
355 assigned to the hash element.  If the element type is C<'%'>, the
356 accessor returns the hash element value.  If the element type is
357 C<'*%'>, a reference to the hash element is returned.
358
359 =item Class (C<'Class_Name'> or C<'*Class_Name'>)
360
361 The element's value must be a reference blessed to the named
362 class or to one of its subclasses. The element is initialized to
363 the result of calling the C<new> constructor of the named class.
364
365 The accessor's argument, if any, is assigned to the element. The
366 accessor will C<croak> if this is not an appropriate object
367 reference.
368
369 If the element type does not start with a C<'*'>, the accessor
370 returns the element value (after assignment). If the element type
371 starts with a C<'*'>, a reference to the element itself is returned.
372
373 =back
374
375 =head1 EXAMPLES
376
377 =over
378
379 =item Example 1
380
381 Giving a struct element a class type that is also a struct is how
382 structs are nested.  Here, C<timeval> represents a time (seconds and
383 microseconds), and C<rusage> has two elements, each of which is of
384 type C<timeval>.
385
386     use Class::Struct;
387
388     struct( rusage => {
389         ru_utime => timeval,  # seconds
390         ru_stime => timeval,  # microseconds
391     });
392
393     struct( timeval => [
394         tv_secs  => '$',
395         tv_usecs => '$',
396     ]);
397
398         # create an object:
399     my $t = new rusage;
400         # $t->ru_utime and $t->ru_stime are objects of type timeval.
401
402         # set $t->ru_utime to 100.0 sec and $t->ru_stime to 5.0 sec.
403     $t->ru_utime->tv_secs(100);
404     $t->ru_utime->tv_usecs(0);
405     $t->ru_stime->tv_secs(5);
406     $t->ru_stime->tv_usecs(0);
407
408
409 =item Example 2
410
411 An accessor function can be redefined in order to provide
412 additional checking of values, etc.  Here, we want the C<count>
413 element always to be nonnegative, so we redefine the C<count>
414 accessor accordingly.
415
416     package MyObj;
417     use Class::Struct;
418
419                 # declare the struct
420     struct ( 'MyObj', { count => '$', stuff => '%' } );
421
422                 # override the default accessor method for 'count'
423     sub count {
424         my $self = shift;
425         if ( @_ ) {
426             die 'count must be nonnegative' if $_[0] < 0;
427             $self->{'count'} = shift;
428             warn "Too many args to count" if @_;
429         }
430         return $self->{'count'};
431     }
432
433     package main;
434     $x = new MyObj;
435     print "\$x->count(5) = ", $x->count(5), "\n";
436                             # prints '$x->count(5) = 5'
437
438     print "\$x->count = ", $x->count, "\n";
439                             # prints '$x->count = 5'
440
441     print "\$x->count(-5) = ", $x->count(-5), "\n";
442                             # dies due to negative argument!
443
444
445 =head1 Author and Modification History
446
447
448 Renamed to C<Class::Struct> and modified by Jim Miner, 1997-04-02.
449
450     members() function removed.
451     Documentation corrected and extended.
452     Use of struct() in a subclass prohibited.
453     User definition of accessor allowed.
454     Treatment of '*' in element types corrected.
455     Treatment of classes as element types corrected.
456     Class name to struct() made optional.
457     Diagnostic checks added.
458
459
460 Originally C<Class::Template> by Dean Roehrich.
461
462     # Template.pm   --- struct/member template builder
463     #   12mar95
464     #   Dean Roehrich
465     #
466     # changes/bugs fixed since 28nov94 version:
467     #  - podified
468     # changes/bugs fixed since 21nov94 version:
469     #  - Fixed examples.
470     # changes/bugs fixed since 02sep94 version:
471     #  - Moved to Class::Template.
472     # changes/bugs fixed since 20feb94 version:
473     #  - Updated to be a more proper module.
474     #  - Added "use strict".
475     #  - Bug in build_methods, was using @var when @$var needed.
476     #  - Now using my() rather than local().
477     #
478     # Uses perl5 classes to create nested data types.
479     # This is offered as one implementation of Tom Christiansen's "structs.pl"
480     # idea.
481
482 =cut