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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (hide annotations)
Sun Nov 17 07:20:51 2002 UTC (21 years, 5 months ago) by jonen
Branch: MAIN
Changes since 1.4: +11 -0 lines
+ sub class_is_abstract

1 cvsjoko 1.1 package Class::Tangram;
2    
3 joko 1.3 # Copyright (c) 2001, 2002 Sam Vilain. All right reserved. This file
4     # is licensed under the terms of the Perl Artistic license.
5 cvsjoko 1.1
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 joko 1.3 package MyObject;
14 cvsjoko 1.1
15     use base qw(Class::Tangram);
16    
17 joko 1.3 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 cvsjoko 1.1
28 joko 1.3 $object->set_foo("Something"); # dies - not an integer
29 cvsjoko 1.1
30 joko 1.3 =head1 DESCRIPTION
31 cvsjoko 1.1
32 joko 1.3 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 cvsjoko 1.1
69 joko 1.3 For example,
70 cvsjoko 1.1
71 joko 1.3 package MyObject;
72     use base qw(Class::Tangram);
73 cvsjoko 1.1
74 joko 1.3 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 cvsjoko 1.1
93 joko 1.3 # '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 cvsjoko 1.1
100 joko 1.3 # false: 'tag' must be defined but may be empty
101     tag => { required => '' },
102     },
103 cvsjoko 1.1
104 joko 1.3 # fields allowed by Class::Tangram but not ever
105     # stored by Tangram - no type checking by default
106     transient => [ qw(_tangible) ],
107     };
108 cvsjoko 1.1
109 joko 1.3 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 cvsjoko 1.1
122 joko 1.4 From Class::Tangram 1.13 onwards, no use of perl's C<AUTOLOAD>
123 joko 1.3 functionality is used.
124 cvsjoko 1.1
125     =cut
126    
127     use strict;
128     use Carp qw(croak cluck);
129    
130 joko 1.3 use vars qw($VERSION %defaults);
131 cvsjoko 1.1
132 joko 1.3 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 cvsjoko 1.1
138     # $types{$class}->{$attribute} is the tangram type of each attribute
139     my (%types);
140    
141 joko 1.3 # $attribute_options{$class}->{$attribute} is the hash passed to tangram
142     # for the given attribute
143     my (%attribute_options);
144    
145 cvsjoko 1.1 # $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 joko 1.3 # $required_attributes{$class}->{$attribute} records which attributes
159     # are required... used only by new() at present.
160     my (%required_attributes);
161    
162 cvsjoko 1.1 # if a class is abstract, complain if one is constructed.
163     my (%abstract);
164    
165 joko 1.4 # records the inheritances of classes.
166     my (%bases);
167    
168 cvsjoko 1.1 =head1 METHODS
169    
170 joko 1.3 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 cvsjoko 1.1 =over 4
177    
178     =item Class-E<gt>new (attribute1 =E<gt> value, attribute2 =E<gt> value)
179    
180 joko 1.3 Sets up a new object of type C<Class>, with attributes set to the
181     values supplied.
182 cvsjoko 1.1
183 joko 1.3 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 cvsjoko 1.1
187     =cut
188    
189     sub new ($@)
190     {
191     my $invocant = shift;
192     my $class = ref $invocant || $invocant;
193    
194 joko 1.3 (my @values, @_) = @_;
195 cvsjoko 1.1
196     # Setup the object
197     my $self = { };
198     bless $self, $class;
199    
200 joko 1.3 # auto-load schema as necessary
201     exists $types{$class} or import_schema($class);
202 cvsjoko 1.1
203     croak "Attempt to instantiate an abstract type"
204     if ($abstract{$class});
205    
206 joko 1.3 if (ref $invocant)
207 cvsjoko 1.1 {
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 joko 1.3 }
217    
218     $self->_fill_init_default();
219     $self->_check_required();
220 cvsjoko 1.1
221 joko 1.3 return $self;
222    
223     }
224 cvsjoko 1.1
225 joko 1.3 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 cvsjoko 1.1
248 joko 1.3 } else {
249     # something else, an object or a scalar
250     $self->$setter($default);
251     }
252     }
253     }
254 cvsjoko 1.1
255 joko 1.3 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 cvsjoko 1.1 }
274 joko 1.3 croak("object missing required attribute(s): "
275     .join(', ',@missing).'.') if @missing;
276 cvsjoko 1.1 }
277     }
278     }
279    
280 joko 1.3 =back
281    
282     =head2 Accessing & Setting Attributes
283    
284     =over
285    
286 cvsjoko 1.1 =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 joko 1.3 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 cvsjoko 1.1 =cut
295    
296 joko 1.3 sub set {
297     my $self = shift;
298 cvsjoko 1.1
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 joko 1.3 UNIVERSAL::isa($self, "Class::Tangram") or croak "type mismatch";
303 cvsjoko 1.1 my $class = ref $self;
304     exists $check{$class} or import_schema($class);
305 joko 1.3 croak "set must be called with an even number of arguments"
306     if (scalar(@_) & 1);
307 cvsjoko 1.1
308 joko 1.3 while (my ($name, $value) = splice @_, 0, 2) {
309 cvsjoko 1.1
310 joko 1.3 my $setter = "set_".$name;
311 cvsjoko 1.1
312 joko 1.3 croak "attempt to set an illegal field $name in a $class"
313     unless $self->can($setter);
314 cvsjoko 1.1
315 joko 1.3 $self->$setter($value);
316 cvsjoko 1.1 }
317     }
318    
319 joko 1.3 =item $instance->get("attribute")
320 cvsjoko 1.1
321 joko 1.3 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 cvsjoko 1.1
327     =cut
328    
329 joko 1.3 sub get {
330     my $self = shift;
331     croak "get what?" unless @_;
332     UNIVERSAL::isa($self, "Class::Tangram") or croak "type mismatch";
333    
334 cvsjoko 1.1 my $class = ref $self;
335     exists $check{$class} or import_schema($class);
336    
337 joko 1.3 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 cvsjoko 1.1 }
350     }
351    
352 joko 1.3 return @return;
353 cvsjoko 1.1 }
354    
355     =item $instance->attribute($value)
356    
357 joko 1.3 If C<$value> is not given, then
358     this is equivalent to C<$instance-E<gt>get_attribute>
359 cvsjoko 1.1
360 joko 1.3 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 cvsjoko 1.1
367     =item $instance->get_attribute
368    
369     =item $instance->set_attribute($value)
370    
371 joko 1.3 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 cvsjoko 1.1
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 joko 1.3 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 cvsjoko 1.1
399     =cut
400    
401 joko 1.3 =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 cvsjoko 1.1
459 joko 1.3 =item init_default
460 cvsjoko 1.1
461 joko 1.3 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 cvsjoko 1.1
468 joko 1.3 =item destroy_func
469 cvsjoko 1.1
470 joko 1.3 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 cvsjoko 1.1
475 joko 1.3 =back
476 cvsjoko 1.1
477 joko 1.3 =head2 Default Type Checking
478 cvsjoko 1.1
479 joko 1.3 # 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 cvsjoko 1.1
518 joko 1.3 =over
519 cvsjoko 1.1
520     =item check_X (\$value)
521    
522 joko 1.3 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 cvsjoko 1.1
527 joko 1.3 =item check_string
528 cvsjoko 1.1
529 joko 1.3 checks that the supplied value is less than 255 characters long.
530 cvsjoko 1.1
531     =cut
532    
533     sub check_string {
534 joko 1.3 croak "string too long"
535 cvsjoko 1.1 if (length ${$_[0]} > 255);
536     }
537    
538 joko 1.3 =item check_int
539 cvsjoko 1.1
540 joko 1.3 checks that the value is a (possibly signed) integer
541 cvsjoko 1.1
542     =cut
543    
544     my $int_re = qr/^-?\d+$/;
545     sub check_int {
546 joko 1.3 croak "not an integer"
547     if (${$_[0]} !~ m/$int_re/o);
548 cvsjoko 1.1 }
549    
550 joko 1.3 =item check_real
551 cvsjoko 1.1
552 joko 1.3 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 cvsjoko 1.1
556     =cut
557    
558     my $real_re = qr/^-?\d*(\.\d*)?(e-?\d*)?$/;
559     sub check_real {
560 joko 1.3 croak "not a real number"
561     if (${$_[0]} !~ m/$real_re/o);
562 cvsjoko 1.1 }
563    
564 joko 1.3 =item check_obj
565 cvsjoko 1.1
566 joko 1.3 checks that the supplied variable is a reference to a blessed object
567 cvsjoko 1.1
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 joko 1.3 if ((ref ${$_[0]}) =~ m/$obj_re/o);
575 cvsjoko 1.1 }
576    
577 joko 1.3 =item check_flat_array
578 cvsjoko 1.1
579 joko 1.3 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 cvsjoko 1.1
583     =cut
584    
585     sub check_flat_array {
586     croak "not a flat array"
587     if (ref ${$_[0]} ne "ARRAY");
588 joko 1.3 croak "flat array may not contain references"
589     if (map { (ref $_ ? "1" : ()) } @{$_[0]});
590 cvsjoko 1.1 }
591    
592 joko 1.3 =item check_array
593 cvsjoko 1.1
594 joko 1.3 checks that $value is a ref ARRAY, and that each element in the array
595     is a reference to a blessed object.
596 cvsjoko 1.1
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 joko 1.3 if ((ref $a) =~ m/$obj_re/o);
605 cvsjoko 1.1 }
606     }
607    
608 joko 1.3 =item check_set
609 cvsjoko 1.1
610 joko 1.3 checks that $value->isa("Set::Object")
611 cvsjoko 1.1
612     =cut
613    
614     sub check_set {
615     croak "set type not passed a Set::Object"
616 joko 1.3 unless (UNIVERSAL::isa(${$_[0]}, "Set::Object"));
617 cvsjoko 1.1 }
618    
619 joko 1.3 =item check_rawdate
620 cvsjoko 1.1
621 joko 1.3 checks that $value is of the form YYYY-MM-DD, or YYYYMMDD, or YYMMDD.
622 cvsjoko 1.1
623     =cut
624    
625     # YYYY-MM-DD HH:MM:SS
626 joko 1.3 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 cvsjoko 1.1 }
646    
647 joko 1.3 =item check_rawdatetime
648 cvsjoko 1.1
649 joko 1.3 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 cvsjoko 1.1
653     =cut
654    
655 joko 1.3 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 cvsjoko 1.1 }
668    
669 joko 1.3 =item check_dmdatetime
670 cvsjoko 1.1
671 joko 1.3 checks that $value is of the form YYYYMMDDHH:MM:SS, or those allowed
672     for rawdatetime.
673 cvsjoko 1.1
674     =cut
675    
676 joko 1.3 sub check_dmdatetime {
677     croak "invalid SQL rawdatetime dude"
678     unless (${$_[0]} =~ m/^\d{10}:\d\d:\d\d$|$rawdatetime_re/o);
679 cvsjoko 1.1 }
680    
681 joko 1.3 =item check_flat_hash
682 cvsjoko 1.1
683 joko 1.3 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 cvsjoko 1.1
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 joko 1.3 =item check_hash
699 cvsjoko 1.1
700 joko 1.3 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 cvsjoko 1.1
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 joko 1.3 =item check_nothing
717 cvsjoko 1.1
718 joko 1.3 checks whether Australians like sport
719 cvsjoko 1.1
720     =cut
721    
722     sub check_nothing { }
723    
724 joko 1.3 =back
725    
726 cvsjoko 1.1 =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 joko 1.3 Available functions:
737    
738     =over
739 cvsjoko 1.1
740 joko 1.3 =item destroy_array
741    
742     empties an array
743 cvsjoko 1.1
744     =cut
745    
746     sub destroy_array {
747 joko 1.3 my $self = shift;
748     my $attr = shift;
749 cvsjoko 1.1 my $t = tied $self->{$attr};
750 joko 1.3 @{$self->{$attr}} = ()
751     unless (defined $t and $t =~ m,Tangram::CollOnDemand,);
752 cvsjoko 1.1 delete $self->{$attr};
753     }
754    
755 joko 1.3 =item destroy_set
756 cvsjoko 1.1
757 joko 1.3 Calls Set::Object::clear to clear the set
758 cvsjoko 1.1
759     =cut
760    
761     sub destroy_set {
762 joko 1.3 my $self = shift;
763     my $attr = shift;
764 cvsjoko 1.1
765     my $t = tied $self->{$attr};
766 joko 1.3 return if (defined $t and $t =~ m,Tangram::CollOnDemand,);
767 cvsjoko 1.1 if (ref $self->{$attr} eq "Set::Object") {
768     $self->{$attr}->clear;
769     }
770     delete $self->{$attr};
771     }
772    
773 joko 1.3 =item destroy_hash
774 cvsjoko 1.1
775 joko 1.3 empties a hash
776 cvsjoko 1.1
777     =cut
778    
779     sub destroy_hash {
780 joko 1.3 my $self = shift;
781     my $attr = shift;
782 cvsjoko 1.1 my $t = tied $self->{$attr};
783 joko 1.3 %{$self->{$attr}} = ()
784     unless (defined $t and $t =~ m,Tangram::CollOnDemand,);
785 cvsjoko 1.1 delete $self->{$attr};
786     }
787    
788 joko 1.3 =item destroy_ref
789 cvsjoko 1.1
790 joko 1.3 destroys a reference.
791 cvsjoko 1.1
792     =cut
793    
794     sub destroy_ref {
795 joko 1.3 my $self = shift;
796     delete $self->{shift};
797     }
798 cvsjoko 1.1
799 joko 1.3 =back
800 cvsjoko 1.1
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 joko 1.3 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 cvsjoko 1.1
816     Available functions:
817    
818 joko 1.3 =over
819    
820     =item parse_string
821    
822     parses SQL types of:
823    
824     =over
825 cvsjoko 1.1
826     =cut
827    
828 joko 1.3 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 cvsjoko 1.1 sub parse_string {
838    
839 joko 1.3 my $attribute = shift;
840     my $option = shift;
841 cvsjoko 1.1
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 joko 1.3 =item CHAR(N), VARCHAR(N)
849 cvsjoko 1.1
850 joko 1.3 closure checks length of string is less than N characters
851 cvsjoko 1.1
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 joko 1.3 =item TINYBLOB, BLOB, LONGBLOB
862 cvsjoko 1.1
863 joko 1.3 checks max. length of string to be 255, 65535 or 16777215 chars
864     respectively. Also works with "TEXT" instead of "BLOB"
865 cvsjoko 1.1
866     =cut
867    
868 joko 1.3 } elsif ($option->{sql} =~ m/^\s*(?:tiny|long|medium)?
869     (?:blob|text)/ix) {
870 cvsjoko 1.1 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 joko 1.3 if (${$_[0]} and length ${$_[0]} > $max_length);
875 cvsjoko 1.1 };
876    
877 joko 1.3 =item SET("members", "of", "set")
878 cvsjoko 1.1
879 joko 1.3 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 cvsjoko 1.1
882     =cut
883    
884 joko 1.3 } 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 cvsjoko 1.1 return sub {
892 joko 1.3 for my $x (split /\s*,\s*/, ${$_[0]}) {
893 cvsjoko 1.1 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 joko 1.3 =item ENUM("possible", "values")
900 cvsjoko 1.1
901 joko 1.3 checks that the value passed is one of the allowed values.
902 cvsjoko 1.1
903     =cut
904    
905 joko 1.3 } 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 cvsjoko 1.1 return sub {
913     croak ("invalid enum value ${$_[0]} must be ("
914     . join(",", keys %values). ")")
915     if (not exists $values{lc(${$_[0]})});
916     }
917    
918 joko 1.3
919 cvsjoko 1.1 } else {
920     die ("Please build support for your string SQL type in "
921     ."Class::Tangram (".$option->{sql}.")");
922     }
923     }
924    
925 joko 1.3 =back
926 cvsjoko 1.1
927 joko 1.3 =back
928 cvsjoko 1.1
929 joko 1.3 =back
930 cvsjoko 1.1
931 joko 1.3 =head2 Quick Object Dumping and Destruction
932 cvsjoko 1.1
933 joko 1.3 =over
934 cvsjoko 1.1
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 joko 1.3 my $self = shift;
949 cvsjoko 1.1
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 joko 1.3 my $self = shift;
977 cvsjoko 1.1
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 joko 1.3 my $self = shift;
1015 cvsjoko 1.1 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 joko 1.3 =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 joko 1.4 #$bases = []; # will anything break without this? it's needed for recording inheritances later on
1082 joko 1.3 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 joko 1.4 # record bases of current class for later retrieval via Run-time type information
1112     $bases{$class} = $bases;
1113    
1114 joko 1.3 # 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 cvsjoko 1.1
1406     =back
1407    
1408 joko 1.3 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 joko 1.4 =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 jonen 1.5 =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 joko 1.3 =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 cvsjoko 1.1 =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 joko 1.3 =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 joko 1.4 This is Class::Tangram version 1.13.
1581 joko 1.3
1582 cvsjoko 1.1 =head1 BUGS/TODO
1583    
1584 joko 1.3 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 cvsjoko 1.1
1595 joko 1.3 Allow C<init_default> values to be set in a default import function?
1596 cvsjoko 1.1
1597 joko 1.3 ie
1598 cvsjoko 1.1
1599 joko 1.3 use MyClassTangramObject -defaults => { foo => "bar" };
1600 cvsjoko 1.1
1601     =head1 AUTHOR
1602    
1603     Sam Vilain, <sam@vilain.net>
1604    
1605 joko 1.3 =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 cvsjoko 1.1 =cut
1616    
1617     69;
1618 joko 1.3
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