our %METHOD_CACHE;
sub method {
- my $level = 1;
+ my $indirect = caller() =~ /^(?:next|maybe::next)$/;
+ my $level = $indirect ? 2 : 1;
+
my ($method_caller, $label, @label);
while ($method_caller = (caller($level++))[3]) {
@label = (split '::', $method_caller);
my $self = $_[0];
my $class = blessed($self) || $self;
- goto &{ $METHOD_CACHE{"$class|$caller|$label"} ||= do {
+ my $method = $METHOD_CACHE{"$class|$caller|$label"} ||= do {
+
+ my @MRO = Class::C3::calculateMRO($class);
+
+ my $current;
+ while ($current = shift @MRO) {
+ last if $caller eq $current;
+ }
+
+ no strict 'refs';
+ my $found;
+ foreach my $class (@MRO) {
+ next if (defined $Class::C3::MRO{$class} &&
+ defined $Class::C3::MRO{$class}{methods}{$label});
+ last if (defined ($found = *{$class . '::' . $label}{CODE}));
+ }
+
+ $found;
+ };
- my @MRO = Class::C3::calculateMRO($class);
+ return $method if $indirect;
- my $current;
- while ($current = shift @MRO) {
- last if $caller eq $current;
- }
+ die "No next::method '$label' found for $self" if !$method;
- no strict 'refs';
- my $found;
- foreach my $class (@MRO) {
- next if (defined $Class::C3::MRO{$class} &&
- defined $Class::C3::MRO{$class}{methods}{$label});
- last if (defined ($found = *{$class . '::' . $label}{CODE}));
- }
+ goto &{$method};
+}
- die "No next::method '$label' found for $self" unless $found;
+sub can { method($_[0]) }
- $found;
- } };
-}
+package # hide me from PAUSE
+ maybe::next;
+
+use strict;
+use warnings;
+
+our $VERSION = '0.01';
+
+sub method { (next::method($_[0]) || return)->(@_) }
1;
The next thing to keep in mind is that you will need to pass all arguments to C<next::method> it can
not automatically use the current C<@_>.
+If C<next::method> cannot find a next method to re-dispatch the call to, it will throw an exception.
+You can use C<next::can> to see if C<next::method> will succeed before you call it like so:
+
+ $self->next::method(@_) if $self->next::can;
+
+Additionally, you can use C<maybe::next::method> as a shortcut to only call the next method if it exists.
+The previous example could be simply written as:
+
+ $self->maybe::next::method(@_);
+
There are some caveats about using C<next::method>, see below for those.
=head1 CAVEATS
=item Thanks to Justin Guenther for making C<next::method> more robust by handling
calls inside C<eval> and anon-subs.
+=item Thanks to Robert Norris for adding support for C<next::can> and
+C<maybe::next::method>.
+
=back
=head1 AUTHOR