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