Add built local::lib
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / Class / C3 / Adopt / NEXT.pm
CommitLineData
3fea05b9 1use strict;
2use warnings;
3
4package Class::C3::Adopt::NEXT;
5
6use NEXT;
7use MRO::Compat;
8use List::MoreUtils qw/none/;
9use warnings::register;
10
11our $VERSION = '0.12';
12
13{
14 my %c3_mro_ok;
15 my %warned_for;
16 my @no_warn_regexes;
17
18 {
19 my $orig = NEXT->can('AUTOLOAD');
20
21 no warnings 'redefine';
22 *NEXT::AUTOLOAD = sub {
23 my $class = ref $_[0] || $_[0];
24 my $caller = caller();
25
26 # 'NEXT::AUTOLOAD' is cargo-culted from C::P::C3, I have no idea if/why it's needed
27 my $wanted = our $AUTOLOAD || 'NEXT::AUTOLOAD';
28 my ($wanted_class) = $wanted =~ m{(.*)::};
29
30 unless (exists $c3_mro_ok{$class}) {
31 eval { mro::get_linear_isa($class, 'c3') };
32 if (my $error = $@) {
33 warn "Class::C3::calculateMRO('${class}') Error: '${error}';"
34 . ' Falling back to plain NEXT.pm behaviour for this class';
35 $c3_mro_ok{$class} = 0;
36 }
37 else {
38 $c3_mro_ok{$class} = 1;
39 }
40 }
41
42 if (length $c3_mro_ok{$class} && $c3_mro_ok{$class}) {
43 unless ($warned_for{$caller}) {
44 $warned_for{$caller} = 1;
45 if (!@no_warn_regexes || none { $caller =~ $_ } @no_warn_regexes) {
46 warnings::warnif("${caller} uses NEXT, which is deprecated. Please see "
47 . "the Class::C3::Adopt::NEXT documentation for details. NEXT used ");
48 }
49 }
50 }
51
52 unless ($c3_mro_ok{$class}) {
53 $NEXT::AUTOLOAD = $wanted;
54 goto &$orig;
55 }
56
57 goto &next::method if $wanted_class =~ /^NEXT:.*:ACTUAL/;
58 goto &maybe::next::method;
59 };
60
61 *NEXT::ACTUAL::AUTOLOAD = \&NEXT::AUTOLOAD;
62 }
63
64 sub import {
65 my ($class, @args) = @_;
66 my $target = caller();
67
68 for my $arg (@args) {
69 $warned_for{$target} = 1
70 if $arg eq '-no_warn';
71 }
72 }
73
74 sub unimport {
75 my $class = shift;
76 my @strings = grep { !ref $_ || ref($_) ne 'Regexp' } @_;
77 my @regexes = grep { ref($_) && ref($_) eq 'Regexp' } @_;
78 @c3_mro_ok{@strings} = ('') x @strings;
79 push @no_warn_regexes, @regexes;
80 }
81}
82
831;
84
85__END__
86
87=head1 NAME
88
89Class::C3::Adopt::NEXT - make NEXT suck less
90
91=head1 SYNOPSIS
92
93 package MyApp::Plugin::FooBar;
94 #use NEXT;
95 use Class::C3::Adopt::NEXT;
96 # or 'use Class::C3::Adopt::NEXT -no_warn;' to suppress warnings
97
98 # Or use warnings::register
99 # no warnings 'Class::C3::Adopt::NEXT';
100
101 # Or suppress warnings in a set of modules from one place
102 # no Class::C3::Adopt::NEXT qw/ Module1 Module2 Module3 /;
103 # Or suppress using a regex
104 # no Class::C3::Adopt::NEXT qr/^Module\d$/;
105
106 sub a_method {
107 my ($self) = @_;
108 # Do some stuff
109
110 # Re-dispatch method
111 # Note that this will generate a warning the _first_ time the package
112 # uses NEXT unless you un comment the 'no warnings' line above.
113 $self->NEXT::method();
114 }
115
116=head1 DESCRIPTION
117
118L<NEXT> was a good solution a few years ago, but isn't any more. It's slow,
119and the order in which it re-dispatches methods appears random at times. It
120also encourages bad programming practices, as you end up with code to
121re-dispatch methods when all you really wanted to do was run some code before
122or after a method fired.
123
124However, if you have a large application, then weaning yourself off C<NEXT>
125isn't easy.
126
127This module is intended as a drop-in replacement for NEXT, supporting the same
128interface, but using L<Class::C3> to do the hard work. You can then write new
129code without C<NEXT>, and migrate individual source files to use C<Class::C3>
130or method modifiers as appropriate, at whatever pace you're comfortable with.
131
132=head1 WARNINGS
133
134This module will warn once for each package using NEXT. It uses
135L<warnings::register>, and so can be disabled like by adding C<no warnings
136'Class::C3::Adopt::NEXT';> to each package which generates a warning, or adding
137C<use Class::C3::Adopt::NEXT -no_warn;>, or disable multiple modules at once by
138saying:
139
140 no Class::C3::Adopt::NEXT qw/ Module1 Module2 Module3 /;
141
142somewhere before the warnings are first triggered. You can also setup entire
143name spaces of modules which will not warn using a regex, e.g.
144
145 no Class::C3::Adopt::NEXT qr/^Module\d$/;
146
147=head1 MIGRATING
148
149=head2 Current code using NEXT
150
151You add C<use MRO::Compat> to the top of a package as you start converting it,
152and gradually replace your calls to C<NEXT::method()> with
153C<maybe::next::method()>, and calls to C<NEXT::ACTUAL::method()> with
154C<next::method()>.
155
156Example:
157
158 sub yourmethod {
159 my $self = shift;
160
161 # $self->NEXT::yourmethod(@_); becomes
162 $self->maybe::next::method();
163 }
164
165 sub othermethod {
166 my $self = shift;
167
168 # $self->NEXT::ACTUAL::yourmethodname(); becomes
169 $self->next::method();
170 }
171
172On systems with L<Class::C3::XS> present, this will automatically be used to
173speed up method re-dispatch. If you are running perl version 5.9.5 or greater
174then the C3 method resolution algorithm is included in perl. Correct use of
175L<MRO::Compat> as shown above allows your code to be seamlessly forward and
176backwards compatible, taking advantage of native versions if available, but
177falling back to using pure perl C<Class::C3>.
178
179=head2 Writing new code
180
181Use L<Moose> and make all of your plugins L<Moose::Roles|Moose::Role>, then use
182method modifiers to wrap methods.
183
184Example:
185
186 package MyApp::Role::FooBar;
187 use Moose::Role;
188
189 before 'a_method' => sub {
190 my ($self) = @_;
191 # Do some stuff
192 };
193
194 around 'a_method' => sub {
195 my $orig = shift;
196 my $self = shift;
197 # Do some stuff before
198 my $ret = $self->$orig(@_); # Run wrapped method (or not!)
199 # Do some stuff after
200 return $ret;
201 };
202
203 package MyApp;
204 use Moose;
205
206 with 'MyApp::Role::FooBar';
207
208=head1 CAVEATS
209
210There are some inheritance hierarchies that it is possible to create which
211cannot be resolved to a simple C3 hierarchy. In that case, this module will
212fall back to using C<NEXT>. In this case a warning will be emitted.
213
214Because calculating the MRO of every class every time C<< ->NEXT::foo >> is
215used from within it is too expensive, runtime manipulations of C<@ISA> are
216prohibited.
217
218=head1 FUNCTIONS
219
220This module replaces C<NEXT::AUTOLOAD> with it's own version. If warnings are
221enabled then a warning will be emitted on the first use of C<NEXT> by each
222package.
223
224=head1 SEE ALSO
225
226L<MRO::Compat> and L<Class::C3> for method re-dispatch and L<Moose> for method
227modifiers and L<roles|Moose::Role>.
228
229L<NEXT> for documentation on the functionality you'll be removing.
230
231=head1 AUTHORS
232
233Florian Ragwitz C<rafl@debian.org>
234
235Tomas Doran C<bobtfish@bobtfish.net>
236
237=head1 COPYRIGHT AND LICENSE
238
239Copyright (c) 2008, 2009 Florian Ragwitz
240
241You may distribute this code under the same terms as Perl itself.
242
243=cut