2 package CXGN
::Tools
::Class
;
6 our @EXPORT_OK = qw
/parricide super_autoload/;
13 CXGN::Tools::Class - a bundle of little code snippets that make writing
14 robust object-oriented code a little easier
18 This module is deprecated. Do not use in new code. Build new code with Moose instead, and sidestep the multiple-inheritance DESTROY problem that parricide() was meant to solve.
33 # All of the below functions are EXPORT_OK.
37 # Desc: Call DESTROY on all the classes in a list, making sure
38 # not to do any one of them twice (originally from Conway
39 # p. 176, modified significantly to not try to store state
40 # in the destroyed object)
41 # Args: (Object, @ISA of that object)
42 # Ret : A list of all classes whose destructors get called by recursing
43 # up the class inheritance graph.
44 # Side Effects: Calls the DESTROY of all of the classes listed in ISA
45 # (and so recursively on all their superclasses, etc.)
46 # with the given object as the first argument.
49 # #in my witchy little class with multiple parent classes...
51 # # <any cleanups specific to your class>
52 # return parricide ($self, our @ISA);
56 # If all of your classes use this little jimmy, the destructors get
57 # automagically chained together, which is usually a good thing.
59 # Note: you *must* make sure that the return value from parricide gets
60 # returned by your destructor, so that parricide can know which
61 # superclasses it has destroyed. Really, this is important.
69 my ($object,@isa) = @_;
71 # print "isa: " . ref($object) . ": ";
72 # print join ", ", @isa;
75 # What's going on here is that if your object is of class C, where
76 # class C is a subclass of A and B, *and* A is a subclass of B, we
77 # must ensure that we call A's destructor before B's (if we call B's
78 # destructor first, and then A's destructor call's B's again, all
79 # sorts of badness may occur. So we'll topologically sort the @isa
80 # array into @toposort (sort things such that if one class is a
81 # descendant class of another in @isa, the subclass occurs first
84 while (@isa) { # until @isa is empty,
85 foreach my $class (@isa) { # take a class in @isa
86 my $degree = 0; # assume it's not anybody's superclass
87 foreach my $otherclass (@isa) { # for each otherclass in @isa
88 unless ($class eq $otherclass) { #
89 if ($otherclass->isa($class)) { # if class is an ancestor of otherclass
90 $degree=1; # then class is not a leaf of the class graph.
94 if ($degree == 0) { # if the class is a leaf (no subclasses)
95 push @toposort, $class; # push it onto the sorted array
96 @isa = grep { !/$class/ } @isa; # and remove it from @isa.
101 # warn ' 'x$indentation,"toposort: " . (join(", ", @toposort)). "\n";
103 # Here's where we call destructors. Each time we call a destructor,
104 # we get back a list of all the ancestor classes whose destructors
105 # get called when destroying any of the object's parents. We need
106 # to hold onto the names of classes that have already been killed, to
107 # avoid calling their destructors more than once.
108 my @already_dead = ();
109 foreach my $parent (@toposort) {
110 # warn ' 'x$indentation,"parent: " . $parent . "\n";
111 my $destructor = $parent->can('DESTROY');
112 # warn ' 'x$indentation, "already_dead 1: ".(join(" ", @already_dead))."\n";
114 unless (grep {$parent eq $_} @already_dead) {
115 # warn ' 'x$indentation,"calling DESTROY on $parent\n";
116 my @killed = $object->$destructor();
117 push @already_dead, ($parent,@killed);
120 # warn ' 'x$indentation, "already_dead 2: ".(join(" ", @already_dead))."\n";
123 # warn ' 'x$indentation, "all done\n";
125 # Finally, we return the class of our object.
127 return @already_dead;
131 =head2 super_autoload
133 Desc: check whether this object's superclass has an AUTOLOAD, and if so,
134 call it as the given method name, with the rest of the given
135 arguments, and return the result. Otherwise, croak with a
136 'method not found'. This function is useful when you're writing
137 an AUTOLOAD method, but your superclass also has an AUTOLOAD method,
138 and you want to pass control to that AUTOLOAD method if your AUTOLOAD
139 doesn't know how to handle the request.
141 If the method name you pass is qualified with a package name
142 (e.g. 'MySuperPackage::methodname'), this will call the method on
143 that particular class. Otherwise, it will call 'SUPER::methodname'.
144 Args: the current object, the requested method name, array of arguments
145 Ret : the results of the superclass function call
151 my $methodname = (split /::/,$AUTOLOAD)[-1];
152 if($methodname =~ /get_/) {
155 return supercall($this,$methodname,@_);
167 my ($package) = $method =~ /(.+)::[^:]+$/;
168 $package ||= 'SUPER';
169 my $fullmethod = "${package}::${method}";
171 if($package->can($method) || $package->can('AUTOLOAD') ) {
172 return $this->$fullmethod(@_);
174 croak
"Method '$method' not found";
181 # Robert Buels and Marty Kreuter