これは、ロールを API ドライバー インスタンスに選択的に適用する大きな醜い Moose の例です。
script.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/役割/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 に目を向けるきっかけになれば幸いです。ドキュメントは優れています。特に、マニュアルとクックブックを確認してください。