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

Contents of /nfo/perl/libs/Class/Tangram.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (show annotations)
Tue May 11 23:28:49 2004 UTC (19 years, 11 months ago) by joko
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +1 -1 lines
fixed regex (capturing) in "sub parse_string" regarding field length check

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

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