/[cvs]/nfo/perl/libs/Class/Tangram-1.12.pm
ViewVC logotype

Annotation of /nfo/perl/libs/Class/Tangram-1.12.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations)
Thu Oct 17 02:34:45 2002 UTC (21 years, 6 months ago) by joko
Branch: MAIN
CVS Tags: HEAD
+ Class::Tangram 1.12

1 joko 1.1 package Class::Tangram;
2    
3     # Copyright (c) 2001, 2002 Sam Vilain. All right reserved. This file
4     # is licensed under the terms of the Perl Artistic license.
5    
6     =head1 NAME
7    
8     Class::Tangram - create constructors, accessor and update methods for
9     objects from a Tangram-compatible object specification.
10    
11     =head1 SYNOPSIS
12    
13     package MyObject;
14    
15     use base qw(Class::Tangram);
16    
17     our $fields => { int => [ qw(foo bar) ],
18     string => [ qw(baz quux) ] };
19    
20     package main;
21    
22     my $object = MyObject->new(foo => 2, baz => "hello");
23    
24     print $object->baz(); # prints "hello"
25    
26     $object->set_quux("Something");
27    
28     $object->set_foo("Something"); # dies - not an integer
29    
30     =head1 DESCRIPTION
31    
32     Class::Tangram is a tool for defining objects attributes. Simply
33     define your object's fields/attributes using the same syntax
34     introduced in _A Guided Tour of Tangram_, and you get objects that
35     work As You'd Expect(tm).
36    
37     Class::Tangram has no dependancy upon Tangram, and vice versa.
38     Neither requires anything special of your objects, nor do they insert
39     any special fields into your objects. This is a very important
40     feature with innumerable benefits, and few (if any) other object
41     persistence tools have this feature.
42    
43     So, fluff aside, let's run through how you use Class::Tangram to make
44     objects.
45    
46     First, you decide upon the attributes your object is going to have.
47     You might do this using UML, or you might pick an existing database
48     table and declare each column to be an attribute (you can leave out
49     "id"; that one is implicit).
50    
51     Your object should use Class::Tangram as a base class;
52    
53     use base qw(Class::Tangram)
54    
55     or for older versions of perl:
56    
57     use Class::Tangram;
58     use vars qw(@ISA);
59     @ISA = qw(Class::Tangram)
60    
61     You should then define a C<$fields> variable in the scope of the
62     package, that is a B<hash> from attribute B<types> (see
63     L<Tangram::Type>) to either an B<array> of B<attribute names>, or
64     another B<hash> from B<attribute names> to B<options hashes> (or
65     C<undef>). The layout of this structure coincides with the C<fields>
66     portion of a tangram schema (see L<Tangram::Schema>). Note: the term
67     `schema' is used frequently to refer to the C<$fields> structure.
68    
69     For example,
70    
71     package MyObject;
72     use base qw(Class::Tangram);
73    
74     our $fields = {
75     int => {
76     juiciness => undef,
77     segments => {
78     # this code reference is called when this
79     # attribute is set, to check the value is
80     # OK
81     check_func => sub {
82     die "too many segments"
83     if (${(shift)} > 30);
84     },
85     # the default for this attribute.
86     init_default => 7,
87     },
88     },
89     ref => {
90     grower => undef,
91     },
92    
93     # 'required' attributes - insist that these fields are
94     # set, both with constructor and set()/set_X methods
95     string => {
96     # true: 'type' must have non-empty value (for
97     # strings) or be logically true (for other types)
98     type => { required => 1 },
99    
100     # false: 'tag' must be defined but may be empty
101     tag => { required => '' },
102     },
103    
104     # fields allowed by Class::Tangram but not ever
105     # stored by Tangram - no type checking by default
106     transient => [ qw(_tangible) ],
107     };
108    
109     It is of critical importance to your sanity that you understand how
110     anonymous hashes and anonymous arrays work in Perl. Some additional
111     features are used above that have not yet been introduced, but you
112     should be able to look at the above data structure and see that it
113     satisfies the conditions stated in the paragraph before it. If it is
114     hazy, I recommend reading L<perlref> or L<perlreftut>.
115    
116     When the schema for the object is first imported (see L<Schema
117     import>), Class::Tangram defines accessor functions for each of the
118     attributes defined in the schema. These accessor functions are then
119     available as C<$object-E<gt>function> on created objects. By virtue
120     of inheritance, various other methods are available.
121    
122     From Class::Tangram 1.12 onwards, no use of perl's C<AUTOLOAD>
123     functionality is used.
124    
125     =cut
126    
127     use strict;
128     use Carp qw(croak cluck);
129    
130     use vars qw($VERSION %defaults);
131    
132     use Set::Object;
133    
134     use Pod::Constants -trim => 1,
135     'MODULE RELEASE' => sub { ($VERSION) = /(\d+\.\d+)/ },
136     'Default Type Checking' => sub { %defaults = eval; };
137    
138     # $types{$class}->{$attribute} is the tangram type of each attribute
139     my (%types);
140    
141     # $attribute_options{$class}->{$attribute} is the hash passed to tangram
142     # for the given attribute
143     my (%attribute_options);
144    
145     # $check{$class}->{$attribute}->($value) is a function that will die
146     # if $value is not alright, see check_X functions
147     my (%check);
148    
149     # Destructors for each attribute. They are called as
150     # $cleaners{$class}->{$attribute}->($self, $attribute);
151     my (%cleaners);
152    
153     # init_default values for each attribute. These could be hash refs,
154     # array refs, code refs, or simple scalars. They will be stored as
155     # $init_defaults{$class}->{$attribute}
156     my (%init_defaults);
157    
158     # $required_attributes{$class}->{$attribute} records which attributes
159     # are required... used only by new() at present.
160     my (%required_attributes);
161    
162     # if a class is abstract, complain if one is constructed.
163     my (%abstract);
164    
165     =head1 METHODS
166    
167     The following methods are available for all Class::Tangram objects
168    
169     =head2 Constructor
170    
171     A Constructor is a method that returns a new instance of an object.
172    
173     =over 4
174    
175     =item Class-E<gt>new (attribute1 =E<gt> value, attribute2 =E<gt> value)
176    
177     Sets up a new object of type C<Class>, with attributes set to the
178     values supplied.
179    
180     Can also be used as an object method (normal use is as a "class
181     method"), in which case it returns a B<copy> of the object, without
182     any deep copying.
183    
184     =cut
185    
186     sub new ($@)
187     {
188     my $invocant = shift;
189     my $class = ref $invocant || $invocant;
190    
191     (my @values, @_) = @_;
192    
193     # Setup the object
194     my $self = { };
195     bless $self, $class;
196    
197     # auto-load schema as necessary
198     exists $types{$class} or import_schema($class);
199    
200     croak "Attempt to instantiate an abstract type"
201     if ($abstract{$class});
202    
203     if (ref $invocant)
204     {
205     # The copy constructor; this could be better :)
206     # this has the side effect of much auto-vivification.
207     %$self = %$invocant;
208     $self->set (@values); # override with @values
209     }
210     else
211     {
212     $self->set (@values); # start with @values
213     }
214    
215     $self->_fill_init_default();
216     $self->_check_required();
217    
218     return $self;
219    
220     }
221    
222     sub _fill_init_default {
223     my $self = shift;
224     my $class = ref $self or die "_fill_init_default usage error";
225    
226     # fill in fields that have defaults
227     while ( my ($attribute, $default) =
228     each %{$init_defaults{$class}} ) {
229    
230     next if (exists $self->{$attribute});
231    
232     my $setter = "set_$attribute";
233     if (ref $default eq "CODE") {
234     # sub { }, attribute gets return value
235     $self->$setter( $default->($self) );
236    
237     } elsif (ref $default eq "HASH") {
238     # hash ref, copy hash
239     $self->$setter( { %{ $default } } );
240    
241     } elsif (ref $default eq "ARRAY") {
242     # array ref, copy array
243     $self->$setter( [ @{ $default } ] );
244    
245     } else {
246     # something else, an object or a scalar
247     $self->$setter($default);
248     }
249     }
250     }
251    
252     sub _check_required {
253     my $self = shift;
254     my $class = ref $self;
255    
256     # make sure field is not undef if 'required' option is set
257     if (my $required = $required_attributes{$class}) {
258    
259     # find the immediate caller outside of this package
260     my $i = 0;
261     $i++ while UNIVERSAL::isa($self, scalar(caller($i))||";->");
262    
263     # give Tangram some lenience - it is exempt from the effects
264     # of the "required" option
265     unless ( caller($i) =~ m/^Tangram::/ ) {
266     my @missing;
267     while ( my ($attribute, $value) = each %$required ) {
268     push(@missing, $attribute)
269     if ! exists $self->{$attribute};
270     }
271     croak("object missing required attribute(s): "
272     .join(', ',@missing).'.') if @missing;
273     }
274     }
275     }
276    
277     =back
278    
279     =head2 Accessing & Setting Attributes
280    
281     =over
282    
283     =item $instance->set(attribute => $value, ...)
284    
285     Sets the attributes of the given instance to the given values. croaks
286     if there is a problem with the values.
287    
288     This function simply calls C<$instance-E<gt>set_attribute($value)> for
289     each of the C<attribute =E<gt> $value> pairs passed to it.
290    
291     =cut
292    
293     sub set {
294     my $self = shift;
295    
296     # yes, this is a lot to do. yes, it's slow. But I'm fairly
297     # certain that this could be handled efficiently if it were to be
298     # moved inside the Perl interpreter or an XS module
299     UNIVERSAL::isa($self, "Class::Tangram") or croak "type mismatch";
300     my $class = ref $self;
301     exists $check{$class} or import_schema($class);
302     croak "set must be called with an even number of arguments"
303     if (scalar(@_) & 1);
304    
305     while (my ($name, $value) = splice @_, 0, 2) {
306    
307     my $setter = "set_".$name;
308    
309     croak "attempt to set an illegal field $name in a $class"
310     unless $self->can($setter);
311    
312     $self->$setter($value);
313     }
314     }
315    
316     =item $instance->get("attribute")
317    
318     Gets the value of C<$attribute>. This simply calls
319     C<$instance-E<gt>get_attribute>. If multiple attributes are listed,
320     then a list of the attribute values is returned in order. Note that
321     you get back the results of the scalar context C<get_attribute> call
322     in this case.
323    
324     =cut
325    
326     sub get {
327     my $self = shift;
328     croak "get what?" unless @_;
329     UNIVERSAL::isa($self, "Class::Tangram") or croak "type mismatch";
330    
331     my $class = ref $self;
332     exists $check{$class} or import_schema($class);
333    
334     my $multiget = (scalar(@_) != 1);
335    
336     my @return;
337     while ( my $field = shift ) {
338     my $getter = "get_".$field;
339     croak "attempt to read an illegal field $field in a $class"
340     unless $self->can($getter);
341    
342     if ( $multiget ) {
343     push @return, scalar($self->$getter());
344     } else {
345     return $self->$getter();
346     }
347     }
348    
349     return @return;
350     }
351    
352     =item $instance->attribute($value)
353    
354     If C<$value> is not given, then
355     this is equivalent to C<$instance-E<gt>get_attribute>
356    
357     If C<$value> is given, then this is equivalent to
358     C<$instance-E<gt>set_attribute($value)>. This usage issues a warning
359     if warnings are on; you should change your code to use the
360     set_attribute syntax for better readability. OO veterans will tell
361     you that for maintainability object method names should always be a
362     verb.
363    
364     =item $instance->get_attribute
365    
366     =item $instance->set_attribute($value)
367    
368     The normative way of getting and setting attributes. If you wish to
369     override the behaviour of an object when getting or setting an
370     attribute, override these functions. They will be called when you use
371     C<$instance-E<gt>attribute>, C<$instance-E<gt>get()>, constructors,
372     etc.
373    
374     =item $instance->attribute_includes(@objects)
375    
376     =item $instance->attribute_insert(@objects)
377    
378     =item $instance->attribute_size
379    
380     =item $instance->attribute_clear
381    
382     =item $instance->attribute_remove(@objects)
383    
384     This suite of functions applies to attributes that are sets (C<iset>
385     or C<set>). It could in theory also apply generally to all
386     collections - ie also arrays (C<iarray> or C<array>), and hashes
387     (C<hash>, C<ihash>). This will be implemented subject to user demand.
388    
389     =back
390    
391     B<Note:> The above functions can be overridden, but they may not be
392     called with the C<$self-E<gt>SUPER::> superclass chaining method.
393     This is because they are not defined within the scope of
394     Class::Tangram, only your package.
395    
396     =cut
397    
398     =head1 ATTRIBUTE TYPE CHECKING
399    
400     Class::Tangram provides type checking of attributes when attributes
401     are set - either using the default C<set_attribute> functions, or
402     created via the C<new> constructor.
403    
404     The checking has default behaviour for each type of attribute (see
405     L<Default Type Checking>), and can be extended arbitrarily via a
406     per-attribute C<check_func>, described below. Critical attributes can
407     be marked as such with the C<required> flag.
408    
409     The specification of this type checking is placed in the class schema,
410     in the per-attribute B<options hash>. This is a Class::Tangram
411     extension to the Tangram schema structure.
412    
413     =over
414    
415     =item check_func
416    
417     A function that is called with a B<reference> to the new value in
418     C<$_[0]>. It should call C<die()> if the value is bad. Note that
419     this check_func will never be passed an undefined value; this is
420     covered by the "required" option, below.
421    
422     In the example schema (above), the attribute C<segments> has a
423     C<check_func> that prevents setting the value to anything greater than
424     30. Note that it does not prevent you from setting the value to
425     something that is not an integer; if you define a C<check_func>, it
426     replaces the default.
427    
428     =item required
429    
430     If this option is set to a true value, then the attribute must be set
431     to a true value to pass type checking. For string attributes, this
432     means that the string must be defined and non-empty (so "0" is true).
433     For other attribute types, the normal Perl definition of logical truth
434     is used.
435    
436     If the required option is defined but logically false, (ie "" or 0),
437     then the attribute must also be defined, but may be set to a logically
438     false value.
439    
440     If the required option is undefined, then the attribute may be set to
441     an undefined value.
442    
443     For integration with tangram, the C<new()> function has a special
444     hack; if it is being invoked from within Tangram, then the required
445     test is skipped.
446    
447     =back
448    
449     =head2 Other per-attribute options
450    
451     Any of the following options may be inserted into the per-attribute
452     B<options hash>:
453    
454     =over
455    
456     =item init_default
457    
458     This value specifies the default value of the attribute when
459     it is created with C<new()>. It is a scalar value, it is
460     copied to the fresh object. If it is a code reference, that
461     code reference is called and its return value inserted into
462     the attribute. If it is an ARRAY or HASH reference, then
463     that array or hash is COPIED into the attribute.
464    
465     =item destroy_func
466    
467     If anything special needs to happen to this attribute before the
468     object is destroyed (or when someone calls
469     C<$object-E<gt>clear_refs()>), then define this. It is called as
470     C<$sub-E<gt>($object, "attribute")>.
471    
472     =back
473    
474     =head2 Default Type Checking
475    
476     # The following list is eval'ed from this documentation
477     # when Class::Tangram loads, and used as default attribute
478     # options for the specified types. So, eg, the default
479     # "init_default" for "set" types is a subroutine that
480     # returns a new Set::Object container.
481    
482     # "parse" is special - it is passed the options hash given
483     # by the user and should return (\&check_func,
484     # \&destroy_func). This is how the magical string type
485     # checking is performed - see the entry for parse_string(),
486     # below.
487    
488     int => { check_func => \&check_int },
489     real => { check_func => \&check_real },
490     string => { parse => \&parse_string },
491     ref => { check_func => \&check_obj,
492     destroy_func => \&destroy_ref },
493     array => { check_func => \&check_array,
494     destroy_func => \&destroy_array },
495     iarray => { check_func => \&check_array,
496     destroy_func => \&destroy_array },
497     flat_array => { check_func => \&check_flat_array },
498     set => { check_func => \&check_set,
499     destroy_func => \&destroy_set,
500     init_default => sub { Set::Object->new() } },
501     iset => { check_func => \&check_set,
502     destroy_func => \&destroy_set,
503     init_default => sub { Set::Object->new() } },
504     dmdatetime => { check_func => \&check_dmdatetime },
505     rawdatetime => { check_func => \&check_rawdatetime },
506     rawdate => { check_func => \&check_rawdate },
507     rawtime => { check_func => \&check_rawtime },
508     flat_hash => { check_func => \&check_flat_hash },
509     transient => { check_func => \&check_nothing },
510     hash => { check_func => \&check_hash,
511     destroy_func => \&destroy_hash,
512     get_func => \&get_hash },
513     perl_dump => { check_func => \&check_nothing }
514    
515     =over
516    
517     =item check_X (\$value)
518    
519     This series of internal functions are built-in C<check_func> functions
520     defined for all of the standard Tangram attribute types.
521    
522     =over
523    
524     =item check_string
525    
526     checks that the supplied value is less than 255 characters long.
527    
528     =cut
529    
530     sub check_string {
531     croak "string too long"
532     if (length ${$_[0]} > 255);
533     }
534    
535     =item check_int
536    
537     checks that the value is a (possibly signed) integer
538    
539     =cut
540    
541     my $int_re = qr/^-?\d+$/;
542     sub check_int {
543     croak "not an integer"
544     if (${$_[0]} !~ m/$int_re/o);
545     }
546    
547     =item check_real
548    
549     checks that the value is a real number, by stringifying it and
550     matching it against (C<m/^-?\d*(\.\d*)?(e-?\d*)?$/>). Inefficient?
551     Yes. Patches welcome.
552    
553     =cut
554    
555     my $real_re = qr/^-?\d*(\.\d*)?(e-?\d*)?$/;
556     sub check_real {
557     croak "not a real number"
558     if (${$_[0]} !~ m/$real_re/o);
559     }
560    
561     =item check_obj
562    
563     checks that the supplied variable is a reference to a blessed object
564    
565     =cut
566    
567     # this pattern matches a regular reference
568     my $obj_re = qr/^(?:HASH|ARRAY|SCALAR)?$/;
569     sub check_obj {
570     croak "not an object reference"
571     if ((ref ${$_[0]}) =~ m/$obj_re/o);
572     }
573    
574     =item check_flat_array
575    
576     checks that $value is a ref ARRAY and that all elements are unblessed
577     scalars. Does NOT currently check that all values are of the correct
578     type (int vs real vs string, etc)
579    
580     =cut
581    
582     sub check_flat_array {
583     croak "not a flat array"
584     if (ref ${$_[0]} ne "ARRAY");
585     croak "flat array may not contain references"
586     if (map { (ref $_ ? "1" : ()) } @{$_[0]});
587     }
588    
589     =item check_array
590    
591     checks that $value is a ref ARRAY, and that each element in the array
592     is a reference to a blessed object.
593    
594     =cut
595    
596     sub check_array {
597     croak "array attribute not passed an array ref"
598     if (ref ${$_[0]} ne "ARRAY");
599     for my $a (@{${$_[0]}}) {
600     croak "member in array not an object reference"
601     if ((ref $a) =~ m/$obj_re/o);
602     }
603     }
604    
605     =item check_set
606    
607     checks that $value->isa("Set::Object")
608    
609     =cut
610    
611     sub check_set {
612     croak "set type not passed a Set::Object"
613     unless (UNIVERSAL::isa(${$_[0]}, "Set::Object"));
614     }
615    
616     =item check_rawdate
617    
618     checks that $value is of the form YYYY-MM-DD, or YYYYMMDD, or YYMMDD.
619    
620     =cut
621    
622     # YYYY-MM-DD HH:MM:SS
623     my $rawdate_re = qr/^(?: \d{4}-\d{2}-\d{2}
624     | (?:\d\d){3,4}
625     )$/x;
626     sub check_rawdate {
627     croak "invalid SQL rawdate"
628     unless (${$_[0]} =~ m/$rawdate_re/o);
629     }
630    
631     =item check_rawtime
632    
633     checks that $value is of the form HH:MM(:SS)?
634    
635     =cut
636    
637     # YYYY-MM-DD HH:MM:SS
638     my $rawtime_re = qr/^\d{1,2}:\d{2}(?::\d{2})?$/;
639     sub check_rawtime {
640     croak "invalid SQL rawtime"
641     unless (${$_[0]} =~ m/$rawtime_re/o);
642     }
643    
644     =item check_rawdatetime
645    
646     checks that $value is of the form YYYY-MM-DD HH:MM(:SS)? (the time
647     and/or the date can be missing), or a string of numbers between 6 and
648     14 numbers long.
649    
650     =cut
651    
652     my $rawdatetime_re = qr/^(?:
653     # YYYY-MM-DD HH:MM:SS
654     (?: (?:\d{4}-\d{2}-\d{2}\s+)?
655     \d{1,2}:\d{2}(?::\d{2})?
656     | \d{4}-\d{2}-\d{2}
657     )
658     | # YYMMDD, etc
659     (?:\d\d){3,7}
660     )$/x;
661     sub check_rawdatetime {
662     croak "invalid SQL rawdatetime dude"
663     unless (${$_[0]} =~ m/$rawdatetime_re/o);
664     }
665    
666     =item check_dmdatetime
667    
668     checks that $value is of the form YYYYMMDDHH:MM:SS, or those allowed
669     for rawdatetime.
670    
671     =cut
672    
673     sub check_dmdatetime {
674     croak "invalid SQL rawdatetime dude"
675     unless (${$_[0]} =~ m/^\d{10}:\d\d:\d\d$|$rawdatetime_re/o);
676     }
677    
678     =item check_flat_hash
679    
680     checks that $value is a ref HASH and all values are scalars. Does NOT
681     currently check that all values are of the correct type (int vs real
682     vs string, etc)
683    
684     =cut
685    
686     sub check_flat_hash {
687     croak "not a hash"
688     unless (ref ${$_[0]} eq "HASH");
689     while (my ($k, $v) = each %${$_[0]}) {
690     croak "hash not flat"
691     if (ref $k or ref $v);
692     }
693     }
694    
695     =item check_hash
696    
697     checks that $value is a ref HASH, that every key in the hash is a
698     scalar, and that every value is a blessed object.
699    
700     =cut
701    
702     sub check_hash {
703     croak "not a hash"
704     unless (ref ${$_[0]} eq "HASH");
705     while (my ($k, $v) = each %${$_[0]}) {
706     croak "hash key not flat"
707     if (ref $k);
708     croak "hash value not an object"
709     if (ref $v !~ m/$obj_re/);
710     }
711     }
712    
713     =item check_nothing
714    
715     checks whether Australians like sport
716    
717     =cut
718    
719     sub check_nothing { }
720    
721     =back
722    
723     =item destroy_X ($instance, $attr)
724    
725     Similar story with the check_X series of functions, these are called
726     during object destruction on every attribute that has a reference that
727     might need breaking. Note: B<these functions all assume that
728     attributes belonging to an object that is being destroyed may be
729     destroyed also>. In other words, do not allow distinct objects to
730     share Set::Object containers or hash references in their attributes,
731     otherwise when one gets destroyed the others will lose their data.
732    
733     Available functions:
734    
735     =over
736    
737     =item destroy_array
738    
739     empties an array
740    
741     =cut
742    
743     sub destroy_array {
744     my $self = shift;
745     my $attr = shift;
746     my $t = tied $self->{$attr};
747     @{$self->{$attr}} = ()
748     unless (defined $t and $t =~ m,Tangram::CollOnDemand,);
749     delete $self->{$attr};
750     }
751    
752     =item destroy_set
753    
754     Calls Set::Object::clear to clear the set
755    
756     =cut
757    
758     sub destroy_set {
759     my $self = shift;
760     my $attr = shift;
761    
762     my $t = tied $self->{$attr};
763     return if (defined $t and $t =~ m,Tangram::CollOnDemand,);
764     if (ref $self->{$attr} eq "Set::Object") {
765     $self->{$attr}->clear;
766     }
767     delete $self->{$attr};
768     }
769    
770     =item destroy_hash
771    
772     empties a hash
773    
774     =cut
775    
776     sub destroy_hash {
777     my $self = shift;
778     my $attr = shift;
779     my $t = tied $self->{$attr};
780     %{$self->{$attr}} = ()
781     unless (defined $t and $t =~ m,Tangram::CollOnDemand,);
782     delete $self->{$attr};
783     }
784    
785     =item destroy_ref
786    
787     destroys a reference.
788    
789     =cut
790    
791     sub destroy_ref {
792     my $self = shift;
793     delete $self->{shift};
794     }
795    
796     =back
797    
798     =item parse_X ($attribute, { schema option })
799    
800     Parses the schema option field, and returns one or two closures that
801     act as a check_X and a destroy_X function for the attribute.
802    
803     This is currently a very ugly hack, parsing the SQL type definition of
804     an object. But it was bloody handy in my case for hacking this in
805     quickly. This is probably unmanagably unportable across databases;
806     but send me bug reports on it anyway, and I'll try and make the
807     parsers work for as many databases as possible.
808    
809     This perhaps should be replaced by primitives that go the other way,
810     building the SQL type definition from a more abstract definition of
811     the type.
812    
813     Available functions:
814    
815     =over
816    
817     =item parse_string
818    
819     parses SQL types of:
820    
821     =over
822    
823     =cut
824    
825     use vars qw($quoted_part $sql_list);
826    
827     $quoted_part = qr/(?: \"([^\"]+)\" | \'([^\']+)\' )/x;
828     $sql_list = qr/\(\s*
829     (
830     $quoted_part
831     (?:\s*,\s* $quoted_part )*
832     ) \s*\)/x;
833    
834     sub parse_string {
835    
836     my $attribute = shift;
837     my $option = shift;
838    
839     # simple case; return the check_string function. We don't
840     # need a destructor for a string so don't return one.
841     if (!$option->{sql}) {
842     return \&check_string;
843     }
844    
845     =item CHAR(N), VARCHAR(N)
846    
847     closure checks length of string is less than N characters
848    
849     =cut
850    
851     if ($option->{sql} =~ m/^\s*(?:var)?char\s*\(\s*(\d+)\s*\)/ix) {
852     my $max_length = $1;
853     return sub {
854     die "string too long for $attribute"
855     if (length ${$_[0]} > $max_length);
856     };
857    
858     =item TINYBLOB, BLOB, LONGBLOB
859    
860     checks max. length of string to be 255, 65535 or 16777215 chars
861     respectively. Also works with "TEXT" instead of "BLOB"
862    
863     =cut
864    
865     } elsif ($option->{sql} =~ m/^\s*(?:tiny|long|medium)?
866     (?:blob|text)/ix) {
867     my $max_length = ($1 ? ($1 eq "tiny"?255:2**24 - 1)
868     : 2**16 - 1);
869     return sub {
870     die "string too long for $attribute"
871     if (${$_[0]} and length ${$_[0]} > $max_length);
872     };
873    
874     =item SET("members", "of", "set")
875    
876     checks that the value passed is valid as a SQL set type, and that all
877     of the passed values are allowed to be a member of that set.
878    
879     =cut
880    
881     } elsif (my ($members) = $option->{sql} =~
882     m/^\s*set\s*$sql_list/oi) {
883    
884     my %members;
885     $members{lc($1 || $2)} = 1
886     while ( $members =~ m/\G[,\s]*$quoted_part/cog );
887    
888     return sub {
889     for my $x (split /\s*,\s*/, ${$_[0]}) {
890     croak ("SQL set badly formed or invalid member $x "
891     ." (SET" . join(",", keys %members). ")")
892     if (not exists $members{lc($x)});
893     }
894     };
895    
896     =item ENUM("possible", "values")
897    
898     checks that the value passed is one of the allowed values.
899    
900     =cut
901    
902     } elsif (my ($values) = $option->{sql} =~
903     m/^\s*enum\s*$sql_list/oi ) {
904    
905     my %values;
906     $values{lc($1 || $2)} = 1
907     while ( $values =~ m/\G[,\s]*$quoted_part/gc);
908    
909     return sub {
910     croak ("invalid enum value ${$_[0]} must be ("
911     . join(",", keys %values). ")")
912     if (not exists $values{lc(${$_[0]})});
913     }
914    
915    
916     } else {
917     die ("Please build support for your string SQL type in "
918     ."Class::Tangram (".$option->{sql}.")");
919     }
920     }
921    
922     =back
923    
924     =back
925    
926     =back
927    
928     =head2 Quick Object Dumping and Destruction
929    
930     =over
931    
932     =item $instance->quickdump
933    
934     Quickly show the blessed hash of an object, without descending into
935     it. Primarily useful when you have a large interconnected graph of
936     objects so don't want to use the B<x> command within the debugger.
937     It also doesn't have the side effect of auto-vivifying members.
938    
939     This function returns a string, suitable for print()ing. It does not
940     currently escape unprintable characters.
941    
942     =cut
943    
944     sub quickdump($) {
945     my $self = shift;
946    
947     my $r = "REF ". (ref $self). "\n";
948     for my $k (sort keys %$self) {
949     $r .= (" $k => "
950     . (
951     tied $self->{$k}
952     || ( ref $self->{$k}
953     ? $self->{$k}
954     : "'".$self->{$k}."'" )
955     )
956     . "\n");
957     }
958     return $r;
959     }
960    
961    
962     =item $instance->DESTROY
963    
964     This function ensures that all of your attributes have their
965     destructors called. It calls the destroy_X function for attributes
966     that have it defined, if that attribute exists in the instance that we
967     are destroying. It calls the destroy_X functions as destroy_X($self,
968     $k)
969    
970     =cut
971    
972     sub DESTROY($) {
973     my $self = shift;
974    
975     my $class = ref $self;
976    
977     # if no cleaners are known for this class, it hasn't been imported
978     # yet. Don't call import_schema, that would be a bad idea in a
979     # destructor.
980     exists $cleaners{$class} or return;
981    
982     # for every attribute that is defined, and has a cleaner function,
983     # call the cleaner function.
984     for my $k (keys %$self) {
985     if (defined $cleaners{$class}->{$k} and exists $self->{$k}) {
986     $cleaners{$class}->{$k}->($self, $k);
987     }
988     }
989     $self->{_DESTROYED} = 1;
990     }
991    
992     =item $instance->clear_refs
993    
994     This clears all references from this object, ie exactly what DESTROY
995     normally does, but calling an object's destructor method directly is
996     bad form. Also, this function has no qualms with loading the class'
997     schema with import_schema() as needed.
998    
999     This is useful for breaking circular references, if you know you are
1000     no longer going to be using an object then you can call this method,
1001     which in many cases will end up cleaning up most of the objects you
1002     want to get rid of.
1003    
1004     However, it still won't do anything about Tangram's internal reference
1005     to the object, which must still be explicitly unlinked with the
1006     Tangram::Storage->unload method.
1007    
1008     =cut
1009    
1010     sub clear_refs($) {
1011     my $self = shift;
1012     my $class = ref $self;
1013    
1014     exists $cleaners{$class} or import_schema($class);
1015    
1016     # break all ref's, sets, arrays
1017     for my $k (keys %$self) {
1018     if (defined $cleaners{$class}->{$k} and exists $self->{$k}) {
1019     $cleaners{$class}->{$k}->($self, $k);
1020     }
1021     }
1022     $self->{_NOREFS} = 1;
1023     }
1024    
1025     =back
1026    
1027     =head1 FUNCTIONS
1028    
1029     The following functions are not intended to be called as object
1030     methods.
1031    
1032     =head2 Schema Import
1033    
1034     our $fields = { int => [ qw(foo bar) ],
1035     string => [ qw(baz quux) ] };
1036    
1037     # Version 1.115 and below compatibility:
1038     our $schema = {
1039     fields => { int => [ qw(foo bar) ],
1040     string => [ qw(baz quux) ] }
1041     };
1042    
1043     =over
1044    
1045     =item Class::Tangram::import_schema($class)
1046    
1047     Parses a tangram object field list, in C<${"${class}::fields"}> (or
1048     C<${"${class}::schema"}-E<gt>{fields}> to the internal type information
1049     hashes. It will also define all of the attribute accessor and update
1050     methods in the C<$class> package.
1051    
1052     Note that calling this function twice for the same class is not
1053     tested and may produce arbitrary results. Patches welcome.
1054    
1055     =cut
1056    
1057     sub import_schema($) { # Damn this function is long
1058     my $class = shift;
1059    
1060     eval {
1061     my ($fields, $bases, $abstract);
1062     {
1063    
1064     # Here, we go hunting around for their defined schema and
1065     # options
1066     no strict 'refs';
1067     local $^W=0;
1068     eval {
1069     $fields = (${"${class}::fields"} ||
1070     ${"${class}::schema"}->{fields});
1071     $abstract = (${"${class}::abstract"} ||
1072     ${"${class}::schema"}->{abstract});
1073     $bases = ${"${class}::schema"}->{bases};
1074     };
1075     if ( my @stack = @{"${class}::ISA"}) {
1076     # clean "bases" information from @ISA
1077     my %seen = map { $_ => 1 } $class, __PACKAGE__;
1078     $bases = [];
1079     while ( my $super = pop @stack ) {
1080     if ( defined ${"${super}::schema"}
1081     or defined ${"${super}::fields"} ) {
1082     push @$bases, $super;
1083     } else {
1084     push @stack, grep { !$seen{$_}++ }
1085     @{"${super}::ISA"};
1086     }
1087     }
1088     if ( !$fields and !@$bases ) {
1089     die ("No schema and no Class::Tangram "
1090     ."superclass for $class; define "
1091     ."${class}::fields!");
1092     }
1093     }
1094     }
1095    
1096     # if this is an abstract type, do not allow it to be
1097     # instantiated
1098     if ($abstract) {
1099     $abstract{$class} = 1;
1100     }
1101    
1102     # If there are any base classes, import them first so that the
1103     # check, cleaners and init_defaults can be inherited
1104     if (defined $bases) {
1105     (ref $bases eq "ARRAY")
1106     or die "bases not an array ref for $class";
1107    
1108     # Note that the order of your bases is significant, that
1109     # is if you are using multiple iheritance then the later
1110     # classes override the earlier ones.
1111     for my $super ( @$bases ) {
1112     import_schema $super unless (exists $check{$super});
1113    
1114     # copy each of the per-class configuration hashes to
1115     # this class as defaults.
1116     my ($k, $v);
1117    
1118     # FIXME - this repetition of code is getting silly :)
1119     $types{$class}->{$k} = $v
1120     while (($k, $v) = each %{ $types{$super} } );
1121     $check{$class}->{$k} = $v
1122     while (($k, $v) = each %{ $check{$super} } );
1123     $cleaners{$class}->{$k} = $v
1124     while (($k, $v) = each %{ $cleaners{$super} } );
1125     $attribute_options{$class}->{$k} = $v
1126     while (($k, $v) = each %{ $attribute_options{$super} } );
1127     $init_defaults{$class}->{$k} = $v
1128     while (($k, $v) = each %{ $init_defaults{$super} } );
1129     $required_attributes{$class}->{$k} = $v
1130     while (($k, $v) = each %{ $required_attributes{$super} } );
1131     }
1132     }
1133    
1134     # iterate over each of the *types* of fields (string, int, ref, etc.)
1135     while (my ($type, $v) = each %$fields) {
1136     if (ref $v eq "ARRAY") {
1137     $v = { map { $_, undef } @$v };
1138     }
1139     my $def = $defaults{$type};
1140    
1141     # iterate each of the *attributes* of a particular type
1142     while (my ($attribute, $options) = each %$v) {
1143    
1144     # this is what we are finding out about each attribute
1145     # $type is already set
1146     my ($default, $check_func, $required, $cleaner);
1147     # set defaults from what they give
1148     $options ||= {};
1149     if (ref $options eq "HASH" or
1150     UNIVERSAL::isa($options, 'Tangram::Type')) {
1151     ($check_func, $default, $required, $cleaner)
1152     = @{$options}{qw(check_func init_default
1153     required destroy_func)};
1154     }
1155    
1156     # Fill their settings with info from defaults
1157     if (ref $def eq "HASH") {
1158    
1159     # try to magically parse their options
1160     if ( $def->{parse} and !($check_func and $cleaner) ) {
1161     my @a = $def->{parse}->($attribute, $options);
1162     $check_func ||= $a[0];
1163     $cleaner ||= $a[1];
1164     }
1165    
1166     # fall back to defaults for this class
1167     $check_func ||= $def->{check_func};
1168     $cleaner ||= $def->{destroy_func};
1169     $default = $def->{init_default} unless defined $default;
1170     }
1171    
1172     # everything must be checked!
1173     die "No check function for ${class}\->$attribute (type $type)"
1174     unless (ref $check_func eq "CODE");
1175    
1176     $types{$class}->{$attribute} = $type;
1177     $check{$class}->{$attribute} = $check_func;
1178     {
1179     no strict "refs";
1180     local ($^W) = 0;
1181    
1182     # build an appropriate "get_attribute" method, and
1183     # define other per-type methods
1184     my ($get_closure, $set_closure);
1185    
1186     # implement with closures for speed
1187     if ( $type =~ m/i?set/ ) {
1188    
1189     # GET_$attribute (Set::Object)
1190     $get_closure = sub {
1191     my $self = shift;
1192     if ( !defined $self->{$attribute} ) {
1193     $self->{$attribute} = Set::Object->new();
1194     }
1195     my $set = $self->{$attribute};
1196     ( wantarray ? $set->members : $set )
1197     };
1198    
1199     # and add a whole load of other functions too
1200     for my $set_method (qw(includes insert size clear
1201     remove)) {
1202    
1203     # ${attribute}_includes, etc
1204     my $set_method_closure = sub {
1205     my $self = shift;
1206     $self->{$attribute} = Set::Object->new()
1207     unless defined $self->{$attribute};
1208     return $self->{$attribute}->$set_method(@_);
1209     };
1210     *{$class."::${attribute}_$set_method"} =
1211     $set_method_closure unless
1212     (defined &{$class."::${attribute}_$set_method"});
1213     }
1214    
1215     } elsif ( $type =~ m/i?array/ ) {
1216    
1217     # GET_$attribute (array)
1218     # allow array slices, and return whole array
1219     # in list context
1220     $get_closure = sub {
1221     my $array = ($_[0]->{$attribute} ||= []);
1222     shift;
1223     if ( @_ ) {
1224     @{$array}[@_];
1225     } else {
1226     ( wantarray ? @{ $array } : $array )
1227     }
1228     };
1229    
1230     } elsif ( $type =~ m/i?hash/ ) {
1231     # GET_$attribute (hash)
1232     # allow hash slices, and return whole hash in
1233     # list context
1234     $get_closure = sub {
1235     my $hash = ($_[0]->{$attribute} ||= {});
1236     shift;
1237     if ( @_ ) {
1238     @{$hash}{@_}
1239     } else {
1240     ( wantarray ? %{ $hash } : $hash );
1241     }
1242     };
1243     } else {
1244     # GET_$attribute (scalar)
1245     # return value only
1246     $get_closure = sub { $_[0]->{$attribute}; };
1247     }
1248    
1249     *{$class."::get_$attribute"} = $get_closure
1250     unless (defined &{$class."::get_$attribute"});
1251    
1252     # SET_$attribute (all)
1253     my $checkit = \$check{$class}->{$attribute};
1254    
1255     # required hack for strings - duplicate the code
1256     # to avoid the following string comparison for
1257     # every set
1258     if ( $type eq "string" ) {
1259     $set_closure = sub {
1260     my $self = shift;
1261     my $value = shift;
1262     eval {
1263     if ( defined $value and length $value ) {
1264     ${$checkit}->(\$value);
1265     } elsif ( $required ) {
1266     die "value is required"
1267     } elsif ( defined $required ) {
1268     die "value must be defined"
1269     unless defined $value;
1270     }
1271     };
1272     $@ && croak("value failed type check - ${class}->"
1273     ."set_$attribute('$value') ($@)");
1274     $self->{$attribute} = $value;
1275     };
1276     } else {
1277     $set_closure = sub {
1278     my $self = shift;
1279     my $value = shift;
1280     eval {
1281     if ( $value ) {
1282     ${$checkit}->(\$value);
1283     } elsif ( $required ) {
1284     die "value is required"
1285     } elsif ( defined $required ) {
1286     die "value must be defined"
1287     unless defined $value;
1288     }
1289     };
1290     $@ && croak("value failed type check - ${class}->"
1291     ."set_$attribute('$value') ($@)");
1292     $self->{$attribute} = $value;
1293     };
1294     }
1295    
1296     # now export them into the caller's namespace
1297     my ($getter, $setter)
1298     = ("get_$attribute", "set_$attribute");
1299     *{$class."::$getter"} = $get_closure
1300     unless defined &{$class."::$getter"};
1301     *{$class."::$setter"} = $set_closure
1302     unless defined &{$class."::$setter"};
1303    
1304     *{$class."::$attribute"} = sub {
1305     my $self = shift;
1306     if ( @_ ) {
1307     warn("The OO Police say change your call "
1308     ."to ->set_$attribute") if ($^W);
1309     #goto $set_closure; # NO! BAD!! :-)
1310     return $self->$setter(@_);
1311     } else {
1312     return $self->$getter(@_);
1313     #goto $get_closure;
1314     }
1315     } unless defined &{$class."::$attribute"};
1316     }
1317    
1318     $cleaners{$class}->{$attribute} = $cleaner
1319     if (defined $cleaner);
1320     $init_defaults{$class}->{$attribute} = $default
1321     if (defined $default);
1322     $required_attributes{$class}->{$attribute} = $required
1323     if (defined $required);
1324     $attribute_options{$class}->{$attribute} =
1325     ( $options || {} );
1326     }
1327     }
1328     };
1329    
1330     $@ && die "$@ while trying to import schema for $class";
1331     }
1332    
1333     =back
1334    
1335     =head2 Run-time type information
1336    
1337     It is possible to access the data structures that Class::Tangram uses
1338     internally to verify attributes, create objects and so on.
1339    
1340     This should be considered a B<HIGHLY EXPERIMENTAL> interface to
1341     B<INTERNALS> of Class::Tangram.
1342    
1343     Class::Tangram keeps seven internal hashes:
1344    
1345     =over
1346    
1347     =item C<%types>
1348    
1349     C<$types{$class}-E<gt>{$attribute}> is the tangram type of each attribute,
1350     ie "ref", "iset", etc. See L<Tangram::Type>.
1351    
1352     =item C<%attribute_options>
1353    
1354     C<$attribute_options{$class}-E<gt>{$attribute}> is the options hash
1355     for a given attribute.
1356    
1357     =item C<%required_attributes>
1358    
1359     C<$required_attributes{$class}-E<gt>{$attribute}> is the 'required'
1360     option setting for a given attribute.
1361    
1362     =item C<%check>
1363    
1364     C<$check{$class}-E<gt>{$attribute}> is a function that will be passed
1365     a reference to the value to be checked and either throw an exception
1366     (die) or return true.
1367    
1368     =item C<%cleaners>
1369    
1370     C<$attribute_options{$class}-E<gt>{$attribute}> is a reference to a
1371     destructor function for that attribute. It is called as an object
1372     method on the object being destroyed, and should ensure that any
1373     circular references that this object is involved in get cleared.
1374    
1375     =item C<%abstract>
1376    
1377     C<$abstract-E<gt>{$class}> is set if the class is abstract
1378    
1379     =item C<%init_defaults>
1380    
1381     C<$init_defaults{$class}-E<gt>{$attribute}> represents what an
1382     attribute is set to automatically if it is not specified when an
1383     object is created. If this is a scalar value, the attribute is set to
1384     the value. If it is a function, then that function is called (as a
1385     method) and should return the value to be placed into that attribute.
1386     If it is a hash ref or an array ref, then that structure is COPIED in
1387     to the new object. If you don't want that, you can do something like
1388     this:
1389    
1390     [...]
1391     flat_hash => {
1392     attribute => {
1393     init_default => sub { { key => "value" } },
1394     },
1395     },
1396     [...]
1397    
1398     Now, every new object will share the same hash for that attribute.
1399    
1400     =back
1401    
1402     There are currently four functions that allow you to access parts of
1403     this information.
1404    
1405     =over
1406    
1407     =item Class::Tangram::attribute_options($class)
1408    
1409     Returns a hash ref to a data structure from attribute names to the
1410     option hash for that attribute.
1411    
1412     =cut
1413    
1414     sub attribute_options($) {
1415     my $class = shift;
1416     return $attribute_options{$class};
1417     }
1418    
1419     =item Class::Tangram::attribute_types($class)
1420    
1421     Returns a hash ref from attribute names to the tangram type for that
1422     attribute.
1423    
1424     =cut
1425    
1426     sub attribute_types($) {
1427     my $class = shift;
1428     return $types{$class};
1429     }
1430    
1431     =item Class::Tangram::required_attributes($class)
1432    
1433     Returns a hash ref from attribute names to the 'required' option setting for
1434     that attribute. May also be called as a method, as in
1435     C<$instance-E<gt>required_attributes>.
1436    
1437     =cut
1438    
1439     sub required_attributes($) {
1440     my $class = ref $_[0] || $_[0];
1441     return $required_attributes{$class};
1442     }
1443    
1444     =item Class::Tangram::init_defaults($class)
1445    
1446     Returns a hash ref from attribute names to the default intial values for
1447     that attribute. May also be called as a method, as in
1448     C<$instance-E<gt>init_defaults>.
1449    
1450     =cut
1451    
1452     sub init_defaults($) {
1453     my $class = ref $_[0] || $_[0];
1454     return $init_defaults{$class};
1455     }
1456    
1457     =item Class::Tangram::known_classes
1458    
1459     This function returns a list of all the classes that have had their
1460     object schema imported by Class::Tangram.
1461    
1462     =cut
1463    
1464     sub known_classes {
1465     return keys %types;
1466     }
1467    
1468     =item Class::Tangram::is_abstract($class)
1469    
1470     This function returns true if the supplied class is abstract.
1471    
1472     =cut
1473    
1474     sub is_abstract {
1475     my $class = shift;
1476     $class eq "Class::Tangram" && ($class = shift);
1477    
1478     exists $cleaners{$class} or import_schema($class);
1479     }
1480    
1481     =item Class->set_init_default(attribute => $value);
1482    
1483     Sets the default value on an attribute for newly created "Class"
1484     objects, as if it had been declared with init_default. Can be called
1485     as a class or an instance method.
1486    
1487     =cut
1488    
1489     sub set_init_default {
1490     my $invocant = shift;
1491     my $class = ref $invocant || $invocant;
1492    
1493     exists $init_defaults{$class} or import_schema($class);
1494    
1495     while ( my ($attribute, $value) = splice @_, 0, 2) {
1496     $init_defaults{$class}->{$attribute} = $value;
1497     }
1498     }
1499    
1500     =back
1501    
1502     =cut
1503    
1504     # a little embedded package
1505    
1506     package Tangram::Transient;
1507    
1508     BEGIN {
1509     eval "use base qw(Tangram::Type)";
1510     if ( $@ ) {
1511     # no tangram
1512     } else {
1513     $Tangram::Schema::TYPES{transient} = bless {}, __PACKAGE__;
1514     }
1515     }
1516    
1517     sub coldefs { }
1518    
1519     sub get_exporter { }
1520     sub get_importer { }
1521    
1522     sub get_import_cols {
1523     # print "Get_import_cols:" , Dumper \@_;
1524     return ();
1525     }
1526    
1527     =head1 SEE ALSO
1528    
1529     L<Tangram::Schema>
1530    
1531     B<A guided tour of Tangram, by Sound Object Logic.>
1532    
1533     http://www.soundobjectlogic.com/tangram/guided_tour/fs.html
1534    
1535     =head1 DEPENDENCIES
1536    
1537     The following modules are required to be installed to use
1538     Class::Tangram:
1539    
1540     Set::Object => 1.02
1541     Pod::Constants => 0.11
1542     Test::Simple => 0.18
1543     Date::Manip => 5.21
1544    
1545     Test::Simple and Date::Manip are only required to run the test suite.
1546    
1547     If you find Class::Tangram passes the test suite with earlier versions
1548     of the above modules, please send me an e-mail.
1549    
1550     =head2 MODULE RELEASE
1551    
1552     This is Class::Tangram version 1.12.
1553    
1554     =head1 BUGS/TODO
1555    
1556     There should be more functions for breaking loops; in particular, a
1557     standard function called C<drop_refs($obj)>, which replaces references
1558     to $obj with the appropriate C<Tangram::RefOnDemand> object so that an
1559     object can be unloaded via C<Tangram::Storage->unload()> and actually
1560     have a hope of being reclaimed. Another function that would be handy
1561     would be a deep "mark" operation for manual mark & sweep garbage
1562     collection.
1563    
1564     Need to think about writing some functions using C<Inline> for speed.
1565     One of these days...
1566    
1567     Allow C<init_default> values to be set in a default import function?
1568    
1569     ie
1570    
1571     use MyClassTangramObject -defaults => { foo => "bar" };
1572    
1573     =head1 AUTHOR
1574    
1575     Sam Vilain, <sam@vilain.net>
1576    
1577     =head2 CREDITS
1578    
1579     # Some modifications
1580     # Copyright © 2001 Micro Sharp Technologies, Inc., Vancouver, WA, USA
1581     # Author: Karl M. Hegbloom <karlheg@microsharp.com>
1582     # Perl Artistic Licence.
1583    
1584     Many thanks to Charles Owens and David Wheeler for their feedback,
1585     ideas, patches and bug testing.
1586    
1587     =cut
1588    
1589     69;
1590    
1591     __END__
1592    
1593     # From old SYNOPSIS, I decided it was too long. A lot of
1594     # the information here needs to be re-integrated into the
1595     # POD.
1596    
1597     package Project;
1598    
1599     # here's where we build the individual object schemas into
1600     # a Tangram::Schema object, which the Tangram::Storage
1601     # class uses to know which tables and columns to find
1602     # objects.
1603     use Tangram::Schema;
1604    
1605     # TIMTOWTDI - this is the condensed manpage version :)
1606     my $dbschema = Tangram::Schema->new
1607     ({ classes =>
1608     [ 'Orange' => { fields => $Orange::fields },
1609     'MyObject' => { fields => $MyObject::schema }, ]});
1610    
1611     sub schema { $dbschema };
1612    
1613     package main;
1614    
1615     # See Tangram::Relational for instructions on using
1616     # "deploy" to create the database this connects to. You
1617     # only have to do this if you want to write the objects to
1618     # a database.
1619     use Tangram::Relational;
1620     my ($dsn, $u, $p);
1621     my $storage = Tangram::Relational->connect
1622     (Project->schema, $dsn, $u, $p);
1623    
1624     # Create an orange
1625     my $orange = Orange->new(
1626     juiciness => 8,
1627     type => 'Florida',
1628     tag => '', # required
1629     );
1630    
1631     # Store it
1632     $storage->insert($orange);
1633    
1634     # This is how you get values out of the objects
1635     my $juiciness = $orange->juiciness;
1636    
1637     # a "ref" must be set to a blessed object, any object
1638     my $grower = bless { name => "Joe" }, "Farmer";
1639     $orange->set_grower ($grower);
1640    
1641     # these are all illegal - type checking is fairly strict
1642     my $orange = eval { Orange->new; }; print $@;
1643     eval { $orange->set_juiciness ("Yum"); }; print $@;
1644     eval { $orange->set_segments (31); }; print $@;
1645     eval { $orange->set_grower ("Mr. Nice"); }; print $@;
1646    
1647     # Demonstrate some "required" functionality
1648     eval { $orange->set_type (''); }; print $@;
1649     eval { $orange->set_type (undef); }; print $@;
1650     eval { $orange->set_tag (undef); }; print $@;
1651    
1652     # this works too, but is slower
1653     $orange->get( "juiciness" );
1654     $orange->set( juiciness => 123,
1655     segments => 17 );
1656    
1657     # Re-configure init_default - make each new orange have a
1658     # random juiciness
1659     $orange->set_init_default( juiciness => sub { int(rand(45)) } );

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed