File: //usr/local/lib64/perl5/Cpanel/Class/Meta/Method/Wrapped.pm
package Cpanel::Class::Meta::Method::Wrapped;
use strict;
use warnings;
use Carp 'confess';
use Scalar::Util 'reftype', 'blessed';
use base 'Cpanel::Class::Meta::Method';
our $VERSION = '1.0.5';
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'};
}
};
sub wrap {
my $class = shift;
my $code = shift;
( blessed($code) && $code->isa('Cpanel::Class::Meta::Method') )
|| confess "Can only wrap blessed CODE";
my $modifier_table = {
cache => undef,
orig => $code,
before => [],
after => [],
around => {
cache => $code->body,
methods => [],
},
};
$_build_wrapped_method->($modifier_table);
my $method = $class->SUPER::wrap( sub { $modifier_table->{'cache'}->(@_) } );
$method->{'%!modifier_table'} = $modifier_table;
return $method;
}
sub get_original_method {
my $code = shift;
$code->{'%!modifier_table'}->{'orig'};
}
sub add_before_modifier {
my $code = shift;
my $modifier = shift;
unshift @{ $code->{'%!modifier_table'}->{'before'} } => $modifier;
$_build_wrapped_method->( $code->{'%!modifier_table'} );
}
sub add_after_modifier {
my $code = shift;
my $modifier = shift;
push @{ $code->{'%!modifier_table'}->{'after'} } => $modifier;
$_build_wrapped_method->( $code->{'%!modifier_table'} );
}
{
my $compile_around_method = sub {
{
my $f1 = pop;
return $f1 unless @_;
my $f2 = pop;
push @_, sub { $f2->( $f1, @_ ) };
redo;
}
};
sub add_around_modifier {
my $code = shift;
my $modifier = shift;
unshift @{ $code->{'%!modifier_table'}->{'around'}->{'methods'} } => $modifier;
$code->{'%!modifier_table'}->{'around'}->{'cache'} = $compile_around_method->( @{ $code->{'%!modifier_table'}->{'around'}->{'methods'} }, $code->{'%!modifier_table'}->{'orig'}->body );
$_build_wrapped_method->( $code->{'%!modifier_table'} );
}
}
1;