use Carp 'confess';
use Algorithm::C3;
-our $VERSION = '0.01';
+our $VERSION = '0.03';
use base 'Class::MOP::Class';
-my $_find_method_in_superclass = sub {
+my $_find_method = sub {
my ($class, $method) = @_;
foreach my $super ($class->class_precedence_list) {
return $super->meta->get_method($method)
}
};
-sub initialize {
- my $class = shift;
- my $meta = $class->SUPER::initialize(@_);
- $meta->add_method('AUTOLOAD' => sub {
- my $meta = $_[0]->meta;
- my $method_name;
- {
- no strict 'refs';
- my $label = ${$meta->name . '::AUTOLOAD'};
- $method_name = (split /\:\:/ => $label)[-1];
- }
- my $method = $_find_method_in_superclass->($meta, $method_name);
+C3MethodDispatchOrder->meta->add_around_method_modifier('initialize' => sub {
+ my $cont = shift;
+ my $meta = $cont->(@_);
+
+ # we need to look at $AUTOLOAD in the package where the coderef belongs
+ # if subname works, then it'll be where this AUTOLOAD method was installed
+ # otherwise, it'll be $C3MethodDispatchOrder::AUTOLOAD. get_code_info
+ # tells us where AUTOLOAD will look
+ my $autoload;
+ $autoload = sub {
+ my ($package) = Class::MOP::get_code_info($autoload);
+ my $label = ${ $package->meta->get_package_symbol('$AUTOLOAD') };
+ my $method_name = (split /\:\:/ => $label)[-1];
+ my $method = $_find_method->($_[0]->meta, $method_name);
(defined $method) || confess "Method ($method_name) not found";
goto &$method;
- });
+ };
+
+ $meta->add_method('AUTOLOAD' => $autoload)
+ unless $meta->has_method('AUTOLOAD');
+
$meta->add_method('can' => sub {
- $_find_method_in_superclass->($_[0]->meta, $_[1]);
- });
- return $meta;
-}
+ $_find_method->($_[0]->meta, $_[1]);
+ }) unless $meta->has_method('can');
+
+ return $meta;
+});
sub superclasses {
my $self = shift;
- no strict 'refs';
+
+ $self->add_package_symbol('@SUPERS' => [])
+ unless $self->has_package_symbol('@SUPERS');
+
if (@_) {
my @supers = @_;
- @{$self->name . '::SUPERS'} = @supers;
+ @{$self->get_package_symbol('@SUPERS')} = @supers;
}
- @{$self->name . '::SUPERS'};
+ @{$self->get_package_symbol('@SUPERS')};
}
sub class_precedence_list {
=head1 DESCRIPTION
-=head1 AUTHOR
+This is an example of how you could change the method dispatch order of a
+class using L<Class::MOP>. Using the L<Algorithm::C3> module, this repleces
+the normal depth-first left-to-right perl dispatch order with the C3 method
+dispatch order (see the L<Algorithm::C3> or L<Class::C3> docs for more
+information about this).
+
+This example could be used as a template for other method dispatch orders
+as well, all that is required is to write a the C<class_precedence_list> method
+which will return a linearized list of classes to dispatch along.
+
+=head1 AUTHORS
Stevan Little E<lt>stevan@iinteractive.comE<gt>
+Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
+
=head1 COPYRIGHT AND LICENSE
-Copyright 2006 by Infinity Interactive, Inc.
+Copyright 2006-2008 by Infinity Interactive, Inc.
L<http://www.iinteractive.com>