如果我在这篇文章中滥用了某些术语,请原谅我。我正在推动我的Perl和编程技能超越我以前所做的,所以我不确定对于我想要做的一些事情的正确术语是什么。
我正在编写一个小型Perl模块,以便更轻松地与程序的XML-RPC API进行通信。我在我的模块类中创建了一些方法来处理最频繁的调用。然后,我正在使用AUTOLOAD为API的其余调用动态创建方法。这很有效,我对结果感到满意。
我希望提出的一个改进是改进我调用API方法的语法。 API将其调用分为命名空间,并使用句点作为命名空间分隔符。例如,一些调用是:
当我在Perl中调用它时,我无法在方法名称中使用句点,所以我用下划线替换它。这是我的AUTOLOAD方法。
sub AUTOLOAD {
my $self = shift;
our $AUTOLOAD;
(my $method = $AUTOLOAD) =~ s/.*:://s; # remove package name
$method =~ s/_/./g;
return if $method =~ /DESTROY/;
perform_rpc_call( $self, $method, @_ );
}
当我使用Perl代码进行调用时,它们看起来像这样:
$obj->user_delete( $username );
有没有比用下划线替换句号更优雅的方式?如果可能的话,我更愿意将方法调用为$obj->user->delete( $username )
。是否有用于处理这种情况的模块或Perl设计模式?我花了两天的时间阅读Perl常见问题解答,搜索网络,并通过CPAN搜索无济于事。
我正在与之通信的API有一个调用,它将返回它支持的所有调用的列表。我想我可以在我的构造函数中检索它,并以某种方式使用它来使AUTOLOAD做我想要的。但我想知道是否有更好的方法。
答案 0 :(得分:3)
如果您可以告诉user
是名称空间或成员而不是通话,那么这是可能的。
package Class;
sub AUTOLOAD {
(my $method = our $AUTOLOAD) =~ s/^.*:://s;
return if $method =~ /DESTROY/;
my $self = shift;
return bless([$self, $method], 'Class::Helper');
if $self->is_namespace($method);
perform_rpc_call($self, $method, @_);
}
package Class::Helper;
sub AUTOLOAD {
(my $method = our $AUTOLOAD) =~ s/^.*:://s;
return if $method =~ /DESTROY/;
my ($self, $ns) = @{ shift };
$method = "$ns.$method";
return bless([$self, $method], 'Class::Helper');
if $self->is_namespace($method);
perform_rpc_call($self, $method, @_);
}
这甚至适用于user.mail.send
。
如果您无法判断user
是否是命名空间或来电,那么您所需的语法就会赢得' twork。您必须使用
$obj->user->delete->(@args) # Error prone. See below
或
$obj->user->delete->call(@args) # Same problem, but a little more obvious
或
$obj->api_call('user.delete', @args)
第一个选项非常容易出错。如果您忘记了最后->
,则RPC方法不会被调用。我建议不要那个。
这是第二种选择的实施方式:
package Class;
sub AUTOLOAD {
(my $method = our $AUTOLOAD) =~ s/^.*:://s;
return if $method =~ /DESTROY/;
my $self = shift;
return bless([$self, $method], 'Class::Helper');
}
package Class::Helper;
sub AUTOLOAD {
(my $method = our $AUTOLOAD) =~ s/^.*:://s;
return if $method =~ /DESTROY/;
my ($self, $ns) = @{ shift };
$method = "$ns.$method";
return bless([$self, $method], 'Class::Helper');
}
sub call {
my ($self, $method) = @{ shift };
perform_rpc_call($self, $method, @_);
}