Содержание
A role is a standalone, named, and reusable unit of behavior. You can compose a role into a class at compile time or add it to an individual object at runtime.
That's an abstract definition best explained by an example. This program demonstrates a simple and pluggable IRC bot framework which understands a few simple commands.
# XXX This is VERY preliminary code and needs filling out. But it
# does provide opportunities to discuss runtime mixins, compile time
# composition, requirements and a few other bits.
my regex nick { \w+ }
my regex join-line { ... <nick> ... }
my regex message-line { $<sender>=[...] $<message>=[...] }
class IRCBot {
has $.bot-nick;
method run($server) {
...
}
}
role KarmaTracking {
has %!karma-scores;
multi method on-message($sender, $msg where /^karma <ws> <nick>/) {
if %!karma-scores{$<nick>} -> $karma {
return $<nick> ~ " has karma $karma";
}
else {
return $<nick> ~ " has neutral karma";
}
}
multi method on-message($sender, $msg where /<nick> '++'/) {
%!karma-scores{$<nick>}++;
}
multi method on-message($sender, $msg where /<nick> '--'/) {
%!karma-scores{$<nick>}--;
}
}
role Oping {
has @!whoz-op;
multi method on-join($nick) {
if $nick eq any(@!whoz-op) {
return "/mode +o $nick";
}
}
# I'm tempted to add another candidate here which checks any(@!whoz-op)
multi method on-message($sender, $msg where /^trust <ws> <nick>/) {
if $sender eq any(@!whoz-op) {
push @!whoz-op, $<nick>;
return "I now trust " ~ $<nick>;
}
else {
return "But $sender, I don't trust you";
}
}
}
role AnswerToAll {
method process($raw-in) {
if $raw-in ~~ /<on-join>/ {
self.*on-join($<nick>);
}
elsif $raw-in ~~ /<on-message>/ {
self.*on-message($<sender>, $<message>)
}
}
}
role AnswerIfTalkedTo {
method bot-nick() { ... }
method process($raw-in) {
if $raw-in ~~ /<on-join>/ {
self.*on-join($<nick>);
}
elsif $raw-in ~~ /<on-message>/ -> $msg {
my $my-nick = self.bot-nick();
if $msg<msg> ~~ /^ $my-nick ':'/ {
self.*on-message($msg<sender>, $msg<message>)
}
}
}
}
my %pluggables =
karma => KarmaTracking,
op => Oping;
role Plugins {
multi method on-message($self is rw: $sender, $msg where /^youdo <ws> (\w+)/) {
if %pluggables{$0} -> $plug-in {
$self does $plug-in;
return "Loaded $0";
}
}
}
class AdminBot is IRCBot does KarmaTracking does Oping {}
class KarmaKeeper is IRCBot does KarmaTracking does AnswerToAll {}
class NothingBot is IRCBot does AnswerIfTalkedTo does Plugins {}
You don't have to understand everything in this example yet. It's only
important right now to notice that the classes KarmaKeeper and NothingBot
share some behavior by inheriting from IRCBot and differentiate their
behaviors by performing different roles.