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