首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Perl中对实例方法进行猴子补丁?

如何在Perl中对实例方法进行猴子补丁?
EN

Stack Overflow用户
提问于 2009-01-16 06:42:20
回答 8查看 6.1K关注 0票数 23

我试图对一个LWP::UserAgent实例进行猴子补丁(鸭-穿孔:-),如下所示:

代码语言:javascript
复制
sub _user_agent_get_basic_credentials_patch {
  return ($username, $password);
}

my $agent = LWP::UserAgent->new();
$agent->get_basic_credentials = _user_agent_get_basic_credentials_patch;

这不是正确的语法--它会产生:

不能修改模块行lineno上的非lvalue子程序调用.

我还记得(从Perl编程中),调度查找是基于受祝福的包(我相信是ref($agent))动态执行的,所以我不确定实例猴子补丁会如何工作而不会影响受祝福的包。

我知道我可以子类UserAgent,但我更喜欢更简洁的猴子补丁方法。同意的成年人和你有什么。;-)

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2009-01-16 17:25:45

如果动态范围(使用local)不能令人满意,则可以自动使用自定义包恢复技术:

代码语言:javascript
复制
MONKEY_PATCH_INSTANCE:
{
  my $counter = 1; # could use a state var in perl 5.10

  sub monkey_patch_instance
  {
    my($instance, $method, $code) = @_;
    my $package = ref($instance) . '::MonkeyPatch' . $counter++;
    no strict 'refs';
    @{$package . '::ISA'} = (ref($instance));
    *{$package . '::' . $method} = $code;
    bless $_[0], $package; # sneaky re-bless of aliased argument
  }
}

示例用法:

代码语言:javascript
复制
package Dog;
sub new { bless {}, shift }
sub speak { print "woof!\n" }

...

package main;

my $dog1 = Dog->new;
my $dog2 = Dog->new;

monkey_patch_instance($dog2, speak => sub { print "yap!\n" });

$dog1->speak; # woof!
$dog2->speak; # yap!
票数 18
EN

Stack Overflow用户

发布于 2009-01-16 07:50:04

正如Fayland Lam所回答的,正确的语法是:

代码语言:javascript
复制
    local *LWP::UserAgent::get_basic_credentials = sub {
        return ( $username, $password );
    };

但这是修补(动态限定范围)整个类,而不仅仅是实例。在你的情况下,你也许能逃脱这一切。

如果您确实希望只影响实例,请使用您所描述的子类。这可以像这样“在飞行中”完成:

代码语言:javascript
复制
{
   package My::LWP::UserAgent;
   our @ISA = qw/LWP::UserAgent/;
   sub get_basic_credentials {
      return ( $username, $password );
   };

   # ... and rebless $agent into current package
   $agent = bless $agent;
}
票数 20
EN

Stack Overflow用户

发布于 2009-01-16 14:51:27

本着Perl“让困难的事情成为可能”的精神,下面是一个例子,说明如何在不使用继承的情况下进行单实例猴子修补。

我不建议您在任何其他人都必须支持、调试或依赖的代码中实际这样做(正如您所说的,成年人同意这样做):

代码语言:javascript
复制
#!/usr/bin/perl

use strict;
use warnings;
{

    package Monkey;

    sub new { return bless {}, shift }
    sub bar { return 'you called ' . __PACKAGE__ . '::bar' }
}

use Scalar::Util qw(refaddr);

my $f = Monkey->new;
my $g = Monkey->new;
my $h = Monkey->new;

print $f->bar, "\n";    # prints "you called Monkey::bar"

monkey_patch( $f, 'bar', sub { "you, sir, are an ape" } );
monkey_patch( $g, 'bar', sub { "you, also, are an ape" } );

print $f->bar, "\n";    # prints "you, sir, are an ape"
print $g->bar, "\n";    # prints "you, also, are an ape"
print $h->bar, "\n";    # prints "you called Monkey::bar"

my %originals;
my %monkeys;

sub monkey_patch {
    my ( $obj, $method, $new ) = @_;
    my $package = ref($obj);
    $originals{$method} ||= $obj->can($method) or die "no method $method in $package";
    no strict 'refs';
    no warnings 'redefine';
    $monkeys{ refaddr($obj) }->{$method} = $new;
    *{ $package . '::' . $method } = sub {
        if ( my $monkey_patch = $monkeys{ refaddr( $_[0] ) }->{$method} ) {
            return $monkey_patch->(@_);
        } else {
            return $originals{$method}->(@_);
        }
    };
}
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/449690

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档