在Perl中,我可以仅将方法动态添加到包的一个对象中吗?

sim*_*que 1 perl monkeypatching www-mechanize

我正在努力WWW::Mechanize自动化基于网络的后台点击我需要做的是让我的测试电子商务订单进入我需要的状态来测试我对长的多部分的特定部分所做的更改流程.要批量处理大量订单,我需要Home经常点击链接.为了缩短这一点,我WWW::Mechanize在运行时将这样的方法入侵(基于brian d foy 掌握Perl的示例):

{ # Shortcut to go back to the home page by calling $mech->go_home
  # I know I'll get a warning and do not want it!
  no warnings 'once';
  my $homeLink = $mech->find_link( text => 'Home' )->url_abs();
  $homeLink =~ s/system=0/system=1/;
  *WWW::Mechanize::go_home = sub {
    my ($self) = @_;
    return $self->get($homeLink);
  };
}
Run Code Online (Sandbox Code Playgroud)

这很好用,并且不会伤害任何人,因为我使用它的脚本仅供我使用,而不是更大系统的一部分.

但现在我想知道是否有可能实际上只告诉一个$mech具有此方法的WWW::Mechanize对象,而另一个可能稍后创建的对象(比如说,做一些交叉引用而不混淆另一个具有活动会话的对象)我的后台办公室)不能使用那种方法.

我不确定这是否可行,因为如果我理解对象在Perl中的工作方式,那么->操作符会告诉它go_home在包中查找子例程并将第一个参数WWW::Mechanize传递$mech给它.如果这种理解是错误的,请纠正我.

我通过添加一种硬编码检查进行了实验,该检查只允许原始$mech对象使用该功能.

my $onlyThisMechMayAccessThisMethod = "$mech";
my $homeLink = $mech->find_link( text => 'Home' )->url_abs();
$homeLink =~ s/system=0/system=1/;
*WWW::Mechanize::go_home = sub {
  my ($self) = @_;
  return undef unless $self eq $onlyThisMechMayAccessThisMethod;
  return $self->get($homeLink);
};
Run Code Online (Sandbox Code Playgroud)

由于"$mech"包含数据存储位置的地址(例如WWW::Mechanize=HASH(0x2fa25e8)),因此在以这种方式进行字符串化时,另一个对象的外观会有所不同.

但我不相信这是要走的路.所以我的问题是:有没有更好的方法只让这个WWW::Mechanize类的一个对象有这个方法?关于这段代码的其他建议,我也很高兴.

Bor*_*din 5

这只是

$mech->follow_link(text => 'Home')
Run Code Online (Sandbox Code Playgroud)

而且我认为它不够特别,无法保证自己的方法,或者需要限制专属的物品俱乐部.

还值得注意的是,不需要使用typeglobs来在不同的包中声明子例程.例如,你只需要写

sub WWW::Mechanize::go_home {
    my ($self) = @_;
    return $self->get($homeLink);
};
Run Code Online (Sandbox Code Playgroud)

但是一般的解决方案是子类化WWW::Mechanize并仅将那些想要拥有新方法的对象声明为成员.


文件 MyMechanize.pm

package MyMechanize;

use strict;
use warnings;

use parent 'WWW::Mechanize';

sub go_home {
  my $self = shift;
  my $homeLink = $self->find_link(text => 'Home')->url_abs;
  $homeLink =~ s/system=0/system=1/;
  return $self->get($homeLink);
}

1;
Run Code Online (Sandbox Code Playgroud)

文件 test.pl

use strict;
use warnings;

use MyMechanize;

my $mech = MyMechanize->new;
$mech->get('http://mydomain.com/path/to/site/page.html')
$mech->go_home;
Run Code Online (Sandbox Code Playgroud)