Perl 在Moose子例程中,$meta是如何进入@的?
让我对Moose子程序Perl 在Moose子例程中,$meta是如何进入@的?,perl,moose,Perl,Moose,让我对Moose子程序产生了好奇。我正在查看Moose源代码,注意到在has子例程中,有一个$meta变量从@解包。$meta来自哪里?我已经开始涉猎各种各样的Moose和Class::MOP模块。在许多子例程中,$meta似乎通常作为@中的第一个参数出现,即使它没有作为参数专门传递给它 编辑:以下是has子例程的原始源代码: sub has { my $meta = shift; my $name = shift; Moose->throw_error('Usa
产生了好奇。我正在查看Moose源代码,注意到在has
子例程中,有一个$meta
变量从@
解包。$meta
来自哪里?我已经开始涉猎各种各样的Moose和Class::MOP模块。在许多子例程中,$meta
似乎通常作为@
中的第一个参数出现,即使它没有作为参数专门传递给它
编辑:以下是has
子例程的原始源代码:
sub has {
my $meta = shift;
my $name = shift;
Moose->throw_error('Usage: has \'name\' => ( key => value, ... )')
if @_ % 2 == 1;
my %options = ( definition_context => Moose::Util::_caller_info(), @_ );
my $attrs = ( ref($name) eq 'ARRAY' ) ? $name : [ ($name) ];
$meta->add_attribute( $_, %options ) for @$attrs;
}
你正在寻找的特殊魔法就在这里。您可以通过Moose.pm从以下代码获得has
方法:
Moose::Exporter->setup_import_methods(
with_meta => [
qw( extends with has before after around override augment )
],
as_is => [
qw( super inner ),
\&Carp::confess,
\&Scalar::Util::blessed,
],
);
注意setup\u import\u methods
的“with\u meta”选项——它将这些方法导入调用方的名称空间,确保传递的第一个参数是元类对象
扩展Moose的各种MooseX模块使用Moose::Exporter将新符号导入调用方的名称空间。您可以在烹饪书中阅读更多有关此过程的信息,从开始。实际导入到包中的不是命名的has()子例程,而是插入元对象的闭包。您可以清楚地看到这是如何发生的:
$ perl -we'use Data::Dump::Streamer; use Moose; Dump(\&has)'
my ($extra,$sub,@ex_args);
$extra = sub {
package Moose::Exporter;
use warnings;
use strict 'refs';
Class::MOP::class_of(shift @_);
};
$sub = sub {
package Moose;
use warnings;
use strict 'refs';
my $meta = shift @_;
my $name = shift @_;
'Moose'->throw_error(q[Usage: has 'name' => ( key => value, ... )]) if @_ % 2 == 1;
my(%options) = ('definition_context', Moose::Util::_caller_info(), @_);
my $attrs = ref $name eq 'ARRAY' ? $name : [$name];
$meta->add_attribute($_, %options) foreach (@$attrs);
};
@ex_args = ( 'main' );
$CODE1 = sub {
package Moose::Exporter;
use warnings;
use strict 'refs';
my(@curry) = &$extra(@ex_args);
return &$sub(@curry, @_);
};
$CODE1
是闭包本身;上面是其中引用的变量。分子
注释:
我不确定has子例程是如何转换为这个闭包的,但这肯定显示了导入has的curried性质
下面是一个(希望如此!)如何实现这一目标的简单示例(但我怀疑它是以更复杂、更好的方式实现的!)
Meta.pm
package Meta;
sub new {
my $class = shift;
bless { @_ }, $class;
}
sub has {
my $meta = shift;
print "Given => @_ \n";
print "meta $_ => ", $meta->{$_}, "\n" for keys %$meta;
}
1;
package Import;
use strict;
use warnings;
use Meta;
# some arbitrary meta info!
our $Meta = Meta->new( a => 'A', b => 'B' );
sub import {
my $caller = caller;
# import 'has' into caller namespace
no strict 'refs';
*{$caller . '::has'} = sub { $Meta->has(@_) };
}
1;
导入.pm
package Meta;
sub new {
my $class = shift;
bless { @_ }, $class;
}
sub has {
my $meta = shift;
print "Given => @_ \n";
print "meta $_ => ", $meta->{$_}, "\n" for keys %$meta;
}
1;
package Import;
use strict;
use warnings;
use Meta;
# some arbitrary meta info!
our $Meta = Meta->new( a => 'A', b => 'B' );
sub import {
my $caller = caller;
# import 'has' into caller namespace
no strict 'refs';
*{$caller . '::has'} = sub { $Meta->has(@_) };
}
1;
meta_有.pl
use strict;
use warnings;
use Import;
has name => ( is => 'rw', isa => 'Int' );
现在,如果运行meta_has.pl
,您将得到:
# Given => name is rw isa Int
# meta a => A
# meta b => B
希望有帮助
/I3az/+1谢谢。我知道我需要花一点时间研究Moose::Exporter,然后才能真正理解它。我仍然不清楚$meta
(或者更准确地说,$meta
后面提到的引用)是如何进入@
的,但您肯定为我指明了正确的方向。您可能特别想看看中的私有方法\u make\u wrapped\u sub\u with\u meta
。这个函数的返回值是Moose安装的has
,我相信我把它改成了perl-we'package X;使用数据::转储::拖缆;使用驼鹿;转储(\&has)
以使其在我的Debian Lenny机器上工作。+1谢谢。我不确定has
子例程是如何转换为这个闭包的,但这肯定显示了导入的has
的curried性质。对于希望看到输出稍微不那么混乱的人,请尝试将一行程序中的转储(\&has)
替换为转储(\&after)
。