5

啊哈!

我有一个角色,我正忙于在名为 Authable 的 Moose 类中定义该角色,该类本质上组合成任何将来可能需要某种形式的身份验证的类;这是一个相当简单的角色,这是全部内容:

package Trello::API::Roles::Authable;

use Moose::Role;

#authentication information
has key => (
    is => "rw",
    isa => "Str",
);

has token => (
    is => "rw",
    isa => "Str",
);

1;

无论出于何种原因,当我尝试使用多个不同的语句将其组合成一个类时,即使用 "Trello::API::Roles::Authable"; 或使用“Roles::Authable”;

我一直收到同样的错误信息:You can only consume roles, Roles::Authable is not a Moose role.

知道为什么会发生这种情况吗?

编辑!

顺便说一句,我检查了 Moose::Role 的实际来源,并看到了这一点:

    unless ($meta && $meta->isa('Moose::Meta::Role') ) {
        require Moose;
        Moose->throw_error( "You can only consume roles, "
                . $role->[0]
                . " is not a Moose role" );
    }

这似乎是发生错误的地方,所以似乎出于某种原因,我正在实施的角色并没有说明它是元类中的角色。虽然我可能弄错了!任何帮助,将不胜感激。

另一个方便的编辑!

奖励:调用 with 例程的代码上下文。

package Trello::API::Resource;

use Moose;
use URI::Escape;
use LWP::UserAgent;


with 'Roles::Authable';

当我这样做时,它智能地知道尝试使用 Roles/Authable.pm 但无论出于何种原因,它都无法运行!

4

2 回答 2

1

首先,我必须同意 Piers 的观​​点,从技术上讲,您确实应该将其称为with 'Trello::API::Roles::Authable'.

所以,你要求的是一些我没有发现在基本 Moose 中实现的东西。我之前使用过通用命名空间池的想法。它们是一种通用名称空间,您可以向其提供半匿名服务——无需锁定固定名称空间。我在 Moose(真的MOP)支持下完善了命名空间池的基本概念。

在 Perl 的狂野西部时代,您所要做的就是将一个 stash 分配给另一个符号,如下所示:

{   no strict 'refs'; 
    *{$short_pkg_name.'::'} = \*{$full_pkg_name.'::'};
};

而且,这两个包是一模一样的东西!

但是现在,我们更多地使用词汇来保护我们的数据。而且因为 Class::MOP 小心翼翼地在词汇散列中保护它的元对象,所以你必须添加其他东西:

Class::MOP::store_metaclass_by_name( 
       $short_pkg_name
     , Class::MOP::get_metaclass_by_name( $full_pkg_name )
     );

现在它们对于 Perl 和 MOP 来说是完全一样的。

因此,您可以创建只是其他包的命名空间存储库的包——现在有了MOP支持!

package Namespace::Pool;
use strict;
use warnings;
use Params::Util qw<_POSINT>;

sub import { 
    shift; # It's just me.
    my $full_pkg_name = caller();
    Carp::croak( "'$full_pkg_name' is short enough!" ) 
        unless my $pool_name 
            = shift // [ split /::/, $full_pkg_name ]->[-2]
            ;
    Carp::croak( "'::$pool_name\::' not found in '$full_pkg_name'" ) 
        unless (  _POSINT( my $pos = rindex( $full_pkg_name, "::$pool_name\::" ))
               or my $is_short = _POSINT( index( $pool_name, '::' ))
               ); 
    my $short_pkg_name 
        = $is_short ? $poll_name 
        :             substr( $full_pkg_name, $pos + 2 )
        ;
    {   no strict 'refs'; 
        if ( %{$short_pkg_name.'::'} ) { 
            Carp::croak( "You have already defined $short_pkg_name!" );
        }
        *{$short_pkg_name.'::'} = \*{$full_pkg_name.'::'};
    };

    if ( my $meta = Class::MOP::get_metaclass_by_name( $full_pkg_name )) { 
        Class::MOP::store_metaclass_by_name( $short_pkg_name, $meta );
    }
    return;
}

因此,在您的角色包中,您可以执行以下操作:

package Trello::API::Roles::Authable;
use strict;
use warnings;
use Moose::Role;
use Namespace::Pool 'Roles';
...

并且知道它将在“角色”的命名空间中可用。

于 2012-08-01T18:03:59.647 回答
0

就我而言,我只是不小心将我的角色命名为“Test”,但我的系统上已经安装了一个名为“Test”的模块,因此 Moose 认为我想使用该模块而不是我创建的新 Moose 角色。一旦我按角色重命名为“可测试”,一切正常。

于 2014-01-23T05:49:19.203 回答