X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FClass%2FMOP%2FMethod.pm;h=8b3c2b4df1363b62887f029a585e5e63beb79193;hb=96ceced87583646c1396bba4fdfa92d0b6c37058;hp=c0ed04c34dace35eb73a678f22214b1687c4a27f;hpb=a4258ffd7a0a2bb8db5f01936068185d4f879b1a;p=gitmo%2FClass-MOP.git diff --git a/lib/Class/MOP/Method.pm b/lib/Class/MOP/Method.pm index c0ed04c..8b3c2b4 100644 --- a/lib/Class/MOP/Method.pm +++ b/lib/Class/MOP/Method.pm @@ -43,6 +43,13 @@ sub name { svref_2object($code)->GV->NAME; } +sub fully_qualified_name { + my $code = shift; + (blessed($code)) + || confess "Can only ask the package name of a blessed CODE"; + $code->package_name . '::' . $code->name; +} + package Class::MOP::Method::Wrapped; use strict; @@ -50,11 +57,67 @@ use warnings; use Carp 'confess'; use Scalar::Util 'reftype', 'blessed'; +use Sub::Name 'subname'; our $VERSION = '0.01'; our @ISA = ('Class::MOP::Method'); +# NOTE: +# this ugly beast is the result of trying +# to micro optimize this as much as possible +# while not completely loosing maintainability. +# At this point it's "fast enough", after all +# you can't get something for nothing :) +my $_build_wrapped_method = sub { + my $modifier_table = shift; + my ($before, $after, $around) = ( + $modifier_table->{before}, + $modifier_table->{after}, + $modifier_table->{around}, + ); + if (@$before && @$after) { + $modifier_table->{cache} = sub { + $_->(@_) for @{$before}; + my @rval; + ((defined wantarray) ? + ((wantarray) ? + (@rval = $around->{cache}->(@_)) + : + ($rval[0] = $around->{cache}->(@_))) + : + $around->{cache}->(@_)); + $_->(@_) for @{$after}; + return unless defined wantarray; + return wantarray ? @rval : $rval[0]; + } + } + elsif (@$before && !@$after) { + $modifier_table->{cache} = sub { + $_->(@_) for @{$before}; + return $around->{cache}->(@_); + } + } + elsif (@$after && !@$before) { + $modifier_table->{cache} = sub { + my @rval; + ((defined wantarray) ? + ((wantarray) ? + (@rval = $around->{cache}->(@_)) + : + ($rval[0] = $around->{cache}->(@_))) + : + $around->{cache}->(@_)); + $_->(@_) for @{$after}; + return unless defined wantarray; + return wantarray ? @rval : $rval[0]; + } + } + else { + $modifier_table->{cache} = $around->{cache}; + } +}; + my %MODIFIERS; sub wrap { @@ -63,32 +126,17 @@ sub wrap { (blessed($code) && $code->isa('Class::MOP::Method')) || confess "Can only wrap blessed CODE"; my $modifier_table = { + cache => undef, orig => $code, before => [], after => [], around => { cache => $code, - methods => [], + methods => [], }, }; - my $method = $class->SUPER::wrap(sub { - $_->(@_) for @{$modifier_table->{before}}; - my (@rlist, $rval); - if (defined wantarray) { - if (wantarray) { - @rlist = $modifier_table->{around}->{cache}->(@_); - } - else { - $rval = $modifier_table->{around}->{cache}->(@_); - } - } - else { - $modifier_table->{around}->{cache}->(@_); - } - $_->(@_) for @{$modifier_table->{after}}; - return unless defined wantarray; - return wantarray ? @rlist : $rval; - }); + $_build_wrapped_method->($modifier_table); + my $method = $class->SUPER::wrap(sub { $modifier_table->{cache}->(@_) }); $MODIFIERS{$method} = $modifier_table; $method; } @@ -103,6 +151,7 @@ sub add_before_modifier { ('CODE' eq (reftype($code) || '')) || confess "You must supply a CODE reference for a modifier"; unshift @{$MODIFIERS{$code}->{before}} => $modifier; + $_build_wrapped_method->($MODIFIERS{$code}); } sub add_after_modifier { @@ -115,9 +164,16 @@ sub add_after_modifier { ('CODE' eq (reftype($code) || '')) || confess "You must supply a CODE reference for a modifier"; push @{$MODIFIERS{$code}->{after}} => $modifier; + $_build_wrapped_method->($MODIFIERS{$code}); } { + # NOTE: + # this is another possible canidate for + # optimization as well. There is an overhead + # associated with the currying that, if + # eliminated might make around modifiers + # more manageable. my $compile_around_method = sub {{ my $f1 = pop; return $f1 unless @_; @@ -140,6 +196,7 @@ sub add_after_modifier { @{$MODIFIERS{$code}->{around}->{methods}}, $MODIFIERS{$code}->{orig} ); + $_build_wrapped_method->($MODIFIERS{$code}); } } @@ -188,10 +245,6 @@ to this class. This simply blesses the C<&code> reference passed to it. -=item B - -This wraps an existing method so that it can handle method modifiers. - =back =head2 Informational @@ -202,6 +255,20 @@ This wraps an existing method so that it can handle method modifiers. =item B +=item B + +=back + +=head1 Class::MOP::Method::Wrapped METHODS + +=head2 Construction + +=over 4 + +=item B + +This simply blesses the C<&code> reference passed to it. + =back =head2 Modifiers