Don't make a method object for calls to has_method, just for get_method
[gitmo/Class-MOP.git] / examples / C3MethodDispatchOrder.pod
CommitLineData
f3f5bd34 1
2package # hide from PAUSE
3 C3MethodDispatchOrder;
4
5use strict;
6use warnings;
7
8use Carp 'confess';
9use Algorithm::C3;
10
2f6d5412 11our $VERSION = '0.03';
f3f5bd34 12
13use base 'Class::MOP::Class';
14
96ceced8 15my $_find_method = sub {
f3f5bd34 16 my ($class, $method) = @_;
17 foreach my $super ($class->class_precedence_list) {
18 return $super->meta->get_method($method)
19 if $super->meta->has_method($method);
20 }
21};
22
a4258ffd 23C3MethodDispatchOrder->meta->add_around_method_modifier('initialize' => sub {
24 my $cont = shift;
25 my $meta = $cont->(@_);
87f3c133 26
27 # we need to look at $AUTOLOAD in the package where the coderef belongs
28 # if subname works, then it'll be where this AUTOLOAD method was installed
29 # otherwise, it'll be $C3MethodDispatchOrder::AUTOLOAD. get_code_info
30 # tells us where AUTOLOAD will look
31 my $autoload;
32 $autoload = sub {
33 my ($package) = Class::MOP::get_code_info($autoload);
34 my $label = ${ $package->meta->get_package_symbol('$AUTOLOAD') };
35 my $method_name = (split /\:\:/ => $label)[-1];
36 my $method = $_find_method->($_[0]->meta, $method_name);
f3f5bd34 37 (defined $method) || confess "Method ($method_name) not found";
38 goto &$method;
87f3c133 39 };
40
41 $meta->add_method('AUTOLOAD' => $autoload)
42 unless $meta->has_method('AUTOLOAD');
43
f3f5bd34 44 $meta->add_method('can' => sub {
96ceced8 45 $_find_method->($_[0]->meta, $_[1]);
6d5355c3 46 }) unless $meta->has_method('can');
87f3c133 47
a4258ffd 48 return $meta;
49});
f3f5bd34 50
51sub superclasses {
52 my $self = shift;
6d5355c3 53
58d75218 54 $self->add_package_symbol('@SUPERS' => [])
55 unless $self->has_package_symbol('@SUPERS');
6d5355c3 56
f3f5bd34 57 if (@_) {
58 my @supers = @_;
58d75218 59 @{$self->get_package_symbol('@SUPERS')} = @supers;
f3f5bd34 60 }
58d75218 61 @{$self->get_package_symbol('@SUPERS')};
f3f5bd34 62}
63
64sub class_precedence_list {
65 my $self = shift;
66 return map {
67 $_->name;
68 } Algorithm::C3::merge($self, sub {
69 my $class = shift;
70 map { $_->meta } $class->superclasses;
71 });
72}
73
741;
75
76__END__
77
78=pod
79
80=head1 NAME
81
82C3MethodDispatchOrder - An example attribute metaclass for changing to C3 method dispatch order
83
84=head1 SYNOPSIS
85
86 # a classic diamond inheritence graph
87 #
88 # <A>
89 # / \
90 # <B> <C>
91 # \ /
92 # <D>
93
94 package A;
95 use metaclass 'C3MethodDispatchOrder';
96
97 sub hello { return "Hello from A" }
98
99 package B;
100 use metaclass 'C3MethodDispatchOrder';
101 B->meta->superclasses('A');
102
103 package C;
104 use metaclass 'C3MethodDispatchOrder';
105 C->meta->superclasses('A');
106
107 sub hello { return "Hello from C" }
108
109 package D;
110 use metaclass 'C3MethodDispatchOrder';
111 D->meta->superclasses('B', 'C');
112
113 print join ", " => D->meta->class_precedence_list; # prints C3 order D, B, C, A
114
115 # later in other code ...
116
117 print D->hello; # print 'Hello from C' instead of the normal 'Hello from A'
118
119=head1 DESCRIPTION
120
1c020571 121This is an example of how you could change the method dispatch order of a
122class using L<Class::MOP>. Using the L<Algorithm::C3> module, this repleces
123the normal depth-first left-to-right perl dispatch order with the C3 method
124dispatch order (see the L<Algorithm::C3> or L<Class::C3> docs for more
125information about this).
126
127This example could be used as a template for other method dispatch orders
128as well, all that is required is to write a the C<class_precedence_list> method
129which will return a linearized list of classes to dispatch along.
130
1a09d9cc 131=head1 AUTHORS
f3f5bd34 132
133Stevan Little E<lt>stevan@iinteractive.comE<gt>
134
1a09d9cc 135Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
136
f3f5bd34 137=head1 COPYRIGHT AND LICENSE
138
69e3ab0a 139Copyright 2006-2008 by Infinity Interactive, Inc.
f3f5bd34 140
141L<http://www.iinteractive.com>
142
143This library is free software; you can redistribute it and/or modify
144it under the same terms as Perl itself.
145
146=cut