Data-Util
view release on metacpan or search on metacpan
lib/Data/Util/PurePerl.pm view on Meta::CPAN
no strict 'refs';
return \&{$package . '::' . $name};
}
else{
_fail('a flag', @flags);
}
}
my $stash = get_stash($package) or return undef;
if(defined(my $glob = $stash->{$name})){
if(ref(\$glob) eq 'GLOB'){
return *{$glob}{CODE};
}
else{ # a stub or special constant
no strict 'refs';
return *{$package . '::' . $name}{CODE};
}
}
return undef;
}
sub curry{
my $is_method = !is_code_ref($_[0]);
my $proc;
$proc = shift if !$is_method;
my $args = \@_;
my @tmpl;
my $i = 0;
my $max_ph = -1;
my $min_ph = 0;
foreach my $arg(@_){
if(is_scalar_ref($arg) && is_integer($$arg)){
push @tmpl, sprintf '$_[%d]', $$arg;
if($$arg >= 0){
$max_ph = $$arg if $$arg > $max_ph;
}
else{
$min_ph = $$arg if $$arg < $min_ph;
}
}
elsif(defined($arg) && (\$arg) == \*_){
push @tmpl, '@_[$max_ph .. $#_ + $min_ph]';
}
else{
push @tmpl, sprintf '$args->[%d]', $i;
}
$i++;
}
$max_ph++;
my($pkg, $file, $line, $hints, $bitmask) = (caller 0 )[0, 1, 2, 8, 9];
my $body = sprintf <<'END_CXT', $pkg, $line, $file;
BEGIN{ $^H = $hints; ${^WARNING_BITS} = $bitmask; }
package %s;
#line %s %s
END_CXT
if($is_method){
my $selfp = shift @tmpl;
$proc = shift @tmpl;
$body .= sprintf q{ sub {
my $self = %s;
my $method = %s;
$self->$method(%s);
} }, $selfp, defined($proc) ? $proc : 'undef', join(q{,}, @tmpl);
}
else{
$body .= sprintf q{ sub { $proc->(%s) } }, join q{,}, @tmpl;
}
eval $body or die $@;
}
BEGIN{
our %modifiers;
my $initializer;
$initializer = sub{
require Hash::Util::FieldHash::Compat;
Hash::Util::FieldHash::Compat::fieldhash(\%modifiers);
undef $initializer;
};
sub modify_subroutine{
my $code = code_ref shift;
if((@_ % 2) != 0){
_croak('Odd number of arguments for modify_subroutine()');
}
my %args = @_;
my(@before, @around, @after);
@before = map{ code_ref $_ } @{array_ref delete $args{before}} if exists $args{before};
@around = map{ code_ref $_ } @{array_ref delete $args{around}} if exists $args{around};
@after = map{ code_ref $_ } @{array_ref delete $args{after}} if exists $args{after};
if(%args){
_fail('a modifier property', join ', ', keys %args);
}
my %props = (
before => \@before,
around => \@around,
after => \@after,
current_ref => \$code,
);
#$code = curry($_, (my $tmp = $code), *_) for @around;
for my $ar_code(reverse @around){
my $next = $code;
$code = sub{ $ar_code->($next, @_) };
}
my($pkg, $file, $line, $hints, $bitmask) = (caller 0)[0, 1, 2, 8, 9];
my $context = sprintf <<'END_CXT', $pkg, $line, $file;
BEGIN{ $^H = $hints; ${^WARNING_BITS} = $bitmask; }
package %s;
#line %s %s(modify_subroutine)
END_CXT
my $modified = eval $context . q{sub{
$_->(@_) for @before;
if(wantarray){ # list context
my @ret = $code->(@_);
$_->(@_) for @after;
return @ret;
}
elsif(defined wantarray){ # scalar context
my $ret = $code->(@_);
$_->(@_) for @after;
return $ret;
}
else{ # void context
$code->(@_);
$_->(@_) for @after;
return;
}
}} or die $@;
$initializer->() if $initializer;
$modifiers{$modified} = \%props;
return $modified;
}
my %valid_modifiers = map{ $_ => undef } qw(before around after);
sub subroutine_modifier{
my $modified = code_ref shift;
my $props_ref = $modifiers{$modified};
unless(@_){ # subroutine_modifier($subr) - only checking
return defined $props_ref;
}
unless($props_ref){ # otherwise, it should be modified subroutines
_fail('a modified subroutine', $modified);
}
my($name, @subs) = @_;
(is_string($name) && exists $valid_modifiers{$name}) or _fail('a modifier property', $name);
my $property = $props_ref->{$name};
if(@subs){
if($name eq 'after'){
push @{$property}, map{ code_ref $_ } @subs;
}
else{
unshift @{$property}, reverse map{ code_ref $_ } @subs;
}
if($name eq 'around'){
my $current_ref = $props_ref->{current_ref};
for my $ar(reverse @subs){
my $base = $$current_ref;
( run in 0.681 second using v1.01-cache-2.11-cpan-97f6503c9c8 )