代码之家  ›  专栏  ›  技术社区  ›  Christopher Bottoms zerkms

在moose子程序中,$meta如何进入@?

  •  6
  • Christopher Bottoms zerkms  · 技术社区  · 14 年前

    chromatic's recent blog 我对驼鹿的子程序很好奇 has . 我在查看驼鹿的源代码时发现 子程序,有一个 $meta 变量解包自 @_ . 在哪里 元元 来自何方?我已经开始涉猎各种驼鹿和class::mop模块。在许多子程序中,似乎 元元 通常作为 @ ,即使它不是作为参数专门传递给它的。

    编辑:这里是 子程序:

    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;
    }
    
    3 回复  |  直到 14 年前
        1
  •  2
  •   Community nesinervink    7 年前

    molecules ysth answer :

    我不确定HAS子例程是如何转换成这个闭包的,但这确实显示了导入HAS的课程性质。

    这是(希望!)一个简单的例子来说明如何实现这一点(不过我怀疑 Moose 是不是更复杂更好的方法!)

    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分析

    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/

        2
  •  12
  •   Ether    14 年前

    你要找的魔法是 Moose::Exporter . 你得到了 has 方法通过moose.pm从该代码:

    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,
        ],
    );
    

    注意“with \u meta”选项 setup_import_methods --它以确保传递的第一个参数将是元类对象的方式将这些方法导入调用方的命名空间。

    扩展moose的各种moosex模块使用moose::exporter将新符号导入调用者的名称空间。您可以在食谱中阅读更多关于这个过程的信息,从 Moose::Cookbook::Extending::Recipe1 .

        3
  •  6
  •   ysth    14 年前

    实际上导入到包中的不是命名的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 是闭包本身;上面是它所引用的变量。