Don't make a method object for calls to has_method, just for get_method
[gitmo/Class-MOP.git] / examples / C3MethodDispatchOrder.pod
1
2 package # hide from PAUSE 
3     C3MethodDispatchOrder;
4     
5 use strict;
6 use warnings;
7
8 use Carp 'confess';
9 use Algorithm::C3;
10
11 our $VERSION = '0.03';
12
13 use base 'Class::MOP::Class';
14
15 my $_find_method = sub {
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
23 C3MethodDispatchOrder->meta->add_around_method_modifier('initialize' => sub {
24         my $cont = shift;
25     my $meta = $cont->(@_);
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);
37         (defined $method) || confess "Method ($method_name) not found";
38         goto &$method;
39     };
40
41     $meta->add_method('AUTOLOAD' => $autoload)
42         unless $meta->has_method('AUTOLOAD');
43     
44     $meta->add_method('can' => sub {
45         $_find_method->($_[0]->meta, $_[1]);
46     }) unless $meta->has_method('can');   
47     
48         return $meta;
49 });
50
51 sub superclasses {
52     my $self = shift;
53     
54     $self->add_package_symbol('@SUPERS' => [])    
55         unless $self->has_package_symbol('@SUPERS');
56             
57     if (@_) {
58         my @supers = @_;
59         @{$self->get_package_symbol('@SUPERS')} = @supers;
60     }
61     @{$self->get_package_symbol('@SUPERS')};        
62 }
63
64 sub 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
74 1;
75
76 __END__
77
78 =pod
79
80 =head1 NAME
81
82 C3MethodDispatchOrder - 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
121 This is an example of how you could change the method dispatch order of a 
122 class using L<Class::MOP>. Using the L<Algorithm::C3> module, this repleces 
123 the normal depth-first left-to-right perl dispatch order with the C3 method 
124 dispatch order (see the L<Algorithm::C3> or L<Class::C3> docs for more 
125 information about this).
126
127 This example could be used as a template for other method dispatch orders 
128 as well, all that is required is to write a the C<class_precedence_list> method 
129 which will return a linearized list of classes to dispatch along. 
130
131 =head1 AUTHORS
132
133 Stevan Little E<lt>stevan@iinteractive.comE<gt>
134
135 Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
136
137 =head1 COPYRIGHT AND LICENSE
138
139 Copyright 2006-2008 by Infinity Interactive, Inc.
140
141 L<http://www.iinteractive.com>
142
143 This library is free software; you can redistribute it and/or modify
144 it under the same terms as Perl itself.
145
146 =cut