这是一个丑陋的 Moose 示例,它选择性地将角色应用于 API 驱动程序实例。
脚本.pl
use Example::User;
# User object creates and authenticates a default API object.
my $user = Example::User->new( id => '12345' );
# When user metadata is accessed, we automatically
# * Load the API driver code.
# * Get the data and make it available.
print "User phone number is: ", $user->phone_number, "\n";
# Same thing with Friends.
print "User has ", $user->count_friends, " friends\n";
print "User never logged in\n" unless $user->has_logged_in;
Example/API.pm - 基本协议驱动类:
package Example::API;
use Moose;
has 'host' => (
is => 'ro',
default => '127.0.0.1',
);
sub Authenticate {
return 1;
}
# Load the user metadata API driver if needed.
# Load user metadata
sub GetUserInfo {
my $self = shift;
require Example::API::Role::UserInfo;
Example::API::Role::UserInfo->meta->apply($self)
unless $self->does('Example::API::Role::UserInfo');
$self->_Get_UserInfo(@_);
}
# Load the friends API driver if needed.
# Load friends data and return an array ref of Friend objects
sub GetFriends {
my $self = shift;
#require Example::API::Role::Friends;
Example::API::Role::Friends->meta->apply($self)
unless $self->does('Example::API::Role::Friends');
$self->_Get_Friends(@_);
}
用户元数据和朋友数据驱动程序构建为“角色”,根据需要动态应用于 API 驱动程序实例。
示例/API/Role/UserInfo.pm:
package Example::API::Role::UserInfo;
use Moose::Role;
sub _Get_UserInfo {
my $self = shift;
my $id = shift;
my $ui = Example::API::User::MetaData->new(
name => 'Joe-' . int rand 100,
phone_number => int rand 999999,
);
return $ui;
}
示例/API/角色/Friends.pm:
use Moose::Role;
sub _Get_Friends {
my $self = shift;
my $id = shift;
my @friends = map {
Example::API::Friend->new(
friend_id => "$id-$_",
name => 'John Smith'
);
} 1 .. (1 + int rand(5));
return \@friends;
}
朋友对象:
示例/API/Friend.pm
package Example::API::Friend;
use Moose;
has 'friend_id' => (
is => 'ro',
isa => 'Str',
required => 1,
);
has 'name' => ( isa => 'Str', is => 'ro', required => 1 );
和一个用户元数据对象。
示例/API/用户/MetaData.pm
package Example::API::User::MetaData;
use Moose;
has 'name' => (
is => 'ro',
isa => 'Str',
);
has 'phone_number' => (
is => 'ro',
isa => 'Str',
);
has 'last_login' => (
is => 'ro',
isa => 'DateTime',
predicate => 'has_logged_in',
);
最后是一个用户对象。我使用了许多 Moose 特性,使这个对象成为一个非常强大的对象,只需要少量的命令式代码。
package Example::User;
use Moose;
has 'id' => (
is => 'ro',
isa => 'Int',
required => 1,
);
has 'server_connection' => (
is => 'ro',
isa => 'Example::API',
builder => '_build_server_connection',
);
# Work with a collection of friend objects.
has 'friends' => (
is => 'ro',
isa => 'ArrayRef[Example::API::Friend]',
traits => ['Array'],
handles => {
all_friends => 'elements',
map_friends => 'map',
filter_friends => 'grep',
find_option => 'first',
get_option => 'get',
join_friends => 'join',
count_friends => 'count',
has_no_friends => 'is_empty',
sorted_friends => 'sort',
},
lazy_build => 1,
);
has 'user_info' => (
is => 'ro',
isa => 'Example::API::User::MetaData',
handles => {
name => 'name',
last_login => 'last_login',
phone_number => 'phone_number',
has_logged_in => 'has_logged_in',
},
lazy_build => 1,
);
sub _build_server_connection {
my $api = Example::API->new();
$api->Authenticate();
return $api;
}
sub _build_friends {
my $self = shift;
$self->server_connection->GetFriends( $self->id );
}
sub _build_user_info {
my $self = shift;
$self->server_connection->GetUserInfo( $self->id );
}
这个例子使用了很多 Moose 魔法,但是你最终得到了一个非常简单的界面供那些使用这些对象的人使用。虽然这接近 200 行格式化代码,但我们完成了大量工作。
添加类型强制将提供更简单的界面。原始字符串日期可以自动解析为 DateTime 对象。原始 IP 地址和服务器名称可以转换为 API 服务器。
我希望这能激励你看看 Moose。文档非常好,特别是查看手册和食谱。