Permalink
Browse files

Merge pull request #4 from okxchg/master

Argument naming and argument count validation in Plugin::BotCommand
  • Loading branch information...
2 parents d05ef95 + 7aa2512 commit 9cc9f652845dfa7fc26211ecb35ee330023270c3 @bingos committed Sep 19, 2012
@@ -14,6 +14,13 @@ sub new {
$args{Method} = 'notice' if !defined $args{Method};
for my $cmd (keys %{ $args{Commands} }) {
+ if (ref $args{Commands}->{$cmd} eq 'HASH') {
+ croak "$cmd: no info provided"
+ if !exists $args{Commands}->{$cmd}->{info} ;
+ croak "$cmd: no arguments provided"
+ if !@{ $args{Commands}->{$cmd}->{args} };
+
+ }
$args{Commands}->{lc $cmd} = delete $args{Commands}->{$cmd};
}
return bless \%args, $package;
@@ -99,6 +106,47 @@ sub _handle_cmd {
my $public = $where =~ /^[$chantypes]/ ? 1 : 0;
$cmd = lc $cmd;
+ if (defined $self->{Commands}->{$cmd}) {
+ if (ref $self->{Commands}->{$cmd} eq 'HASH') {
+ my @args_array = defined $args ? split /\s+/, $args : ();
+ if (@args_array < @{ $self->{Commands}->{$cmd}->{args} } ||
+ (!defined $self->{Commands}->{$cmd}->{variable} &&
+ @args_array > @{ $self->{Commands}->{$cmd}->{args} })
+ ) {
+ $irc->yield($self->{Method}, $where,
+ "Not enough or too many arguments. See help for $cmd");
+ return;
+ }
+
+ $args = {};
+ for (@{ $self->{Commands}->{$cmd}->{args} }) {
+ my $in_arg = shift @args_array;
+ if (ref $self->{Commands}->{$cmd}->{$_} eq 'ARRAY') {
+ my @values = @{ $self->{Commands}->{$cmd}->{$_} };
+ shift @values;
+
+ use List::MoreUtils qw(none);
+ # Check if argument has one of possible values
+ if (none { $_ eq $in_arg} @values) {
+ $irc->yield($self->{Method}, $where,
+ "$_ can be one of ".join '|', @values);
+ return;
+ }
+
+ }
+ $args->{$_} = $in_arg;
+ }
+
+ # Process remaining arguments if variable is set
+ my $arg_cnt = 0;
+ if (defined $self->{Commands}->{$cmd}->{variable}) {
+ for (@args_array) {
+ $args->{"opt".$arg_cnt++} = $_;
+ }
+ }
+ }
+ }
+
if (ref $self->{Auth_sub} eq 'CODE') {
my ($authed, $errors) = $self->{Auth_sub}->($self->{irc}, $who, $where, $cmd, $args);
@@ -139,7 +187,31 @@ sub _get_help {
if (defined $args) {
my $cmd = (split /\s+/, $args, 2)[0];
if (exists $self->{Commands}->{$cmd}) {
- @help = split /\015?\012/, $self->{Commands}->{$cmd};
+ if (ref $self->{Commands}->{$cmd} eq 'HASH') {
+ push @help, "Syntax: $cmd ".
+ (join ' ', @{ $self->{Commands}->{$cmd}->{args} }).
+ (defined $self->{Commands}->{$cmd}->{variable} ?
+ " ..." : "");
+ push @help, split /\015?\012/,
+ "Description: ".$self->{Commands}->{$cmd}->{info};
+ push @help, "Arguments:";
+
+ for my $arg (@{ $self->{Commands}->{$cmd}->{args} }) {
+ next if not defined $self->{Commands}->{$cmd}->{$arg};
+ if (ref $self->{Commands}->{$cmd}->{$arg} eq 'ARRAY') {
+ my @arg_usage = @{$self->{Commands}->{$cmd}->{$arg}};
+ push @help, " $arg: ".$arg_usage[0].
+ " (".(join '|', @arg_usage[1..$#arg_usage]).")"
+ }
+ else {
+ push @help, " $arg: ".
+ $self->{Commands}->{$cmd}->{$arg};
+ }
+ }
+ }
+ else {
+ @help = split /\015?\012/, $self->{Commands}->{$cmd};
+ }
}
else {
push @help, "Unknown command: $cmd";
@@ -163,6 +235,11 @@ sub add {
my ($self, $cmd, $usage) = @_;
$cmd = lc $cmd;
return if exists $self->{Commands}->{$cmd};
+
+ if (ref $usage eq 'HASH') {
+ return if !exists $usage->{info} || !@{ $usage->{args} };
+ }
+
$self->{Commands}->{$cmd} = $usage;
return 1;
}
@@ -289,6 +366,22 @@ B<'Commands'>, a hash reference, with your commands as keys, and usage
information as values. If the usage string contains newlines, the plugin
will send one message for each line.
+If a command's value is a HASH ref like this:
+
+ $irc->plugin_add('BotCommand', POE::Component::IRC::Plugin::BotCommand->new(
+ Commands => {
+ slap => {
+ info => 'Slap someone',
+ args => [qw(nickname)],
+ nickname => 'nickname to slap'
+ }
+ }
+ ));
+
+The args array reference is than used to validate number of arguments required
+and to name arguments passed to event handler. Help is than generated from
+C<info> and other hash keys which represent arguments (they are optional).
+
=head3 Accepting commands
B<'In_channels'>, a boolean value indicating whether to accept commands in
@@ -359,8 +452,9 @@ L<POE::Component::IRC|POE::Component::IRC>'s C<plugin_add> method.
=head2 C<add>
Adds a new command. Takes two arguments, the name of the command, and a string
-containing its usage information. Returns false if the command has already been
-defined, true otherwise.
+or hash reference containing its usage information (see C<new>). Returns false
+if the command has already been defined or no info or arguments are provided,
+true otherwise.
=head2 C<remove>
@@ -370,7 +464,7 @@ if the command wasn't defined to begin with, true otherwise.
=head2 C<list>
Takes no arguments. Returns a list of key/value pairs, the keys being the
-command names and the values being the usage strings.
+command names and the values being the usage strings or hash references.
=head1 OUTPUT EVENTS
@@ -387,7 +481,8 @@ every time someone issued that command. It receives the following arguments:
=item * C<ARG1> is the name of the channel in which the command was issued,
or the sender's nickname if this was a private message.
-=item * C<ARG2>: a string of arguments to the command, or undef if there
+=item * C<ARG2>: a string of arguments to the command, or hash reference with
+arguments in case you defined command along with arguments, or undef if there
were no arguments
=back
@@ -5,7 +5,7 @@ use POE;
use POE::Component::IRC;
use POE::Component::IRC::Plugin::BotCommand;
use POE::Component::Server::IRC;
-use Test::More tests => 18;
+use Test::More tests => 22;
my $bot1 = POE::Component::IRC->spawn(
Flood => 1,
@@ -31,6 +31,7 @@ POE::Session->create(
irc_join
irc_botcmd_cmd1
irc_botcmd_cmd2
+ irc_botcmd_cmd3
irc_disconnected
)],
],
@@ -89,18 +90,27 @@ sub irc_001 {
my $plugin = POE::Component::IRC::Plugin::BotCommand->new(
Commands => {
cmd1 => 'First test command',
+ cmd2 => {
+ info => 'First test command with argument count checking',
+ args => [qw(test_arg test_arg2)],
+ variable => 1,
+ test_arg => ['Description of first arg', qw(value1 value2)],
+ test_arg2 => 'Description of second arg',
+ optional_arg => 'Description of optional arg',
+ },
foo => 'This will get removed',
},
);
- ok($irc->plugin_add(BotCommand => $plugin), 'Add plugin with two commands');
- ok($plugin->add(cmd2 => 'Second test command'), 'Add another command');
+ ok($irc->plugin_add(BotCommand => $plugin), 'Add plugin with three commands');
+ ok($plugin->add(cmd3 => 'Third test command'), 'Add another command');
ok($plugin->remove('foo'), 'Remove command');
my %cmds = $plugin->list();
- is(keys %cmds, 2, 'Correct number of commands');
+ is(keys %cmds, 3, 'Correct number of commands');
ok($cmds{cmd1}, 'First command is present');
ok($cmds{cmd2}, 'Second command is present');
+ ok($cmds{cmd3}, 'Third command is present');
}
sub irc_join {
@@ -116,8 +126,11 @@ sub irc_join {
# try command
$bot2->yield(privmsg => $where, "TestBot1: cmd1 foo bar");
+ # try command with predefined arguments
+ $bot2->yield(privmsg => $where, "TestBot1: cmd2 value1 bar opt_arg");
+
# and one with color
- $bot2->yield(privmsg => $where, "\x0302TestBot1\x0f: \x02cmd2\x0f");
+ $bot2->yield(privmsg => $where, "\x0302TestBot1\x0f: \x02cmd3\x0f");
}
sub irc_botcmd_cmd1 {
@@ -135,6 +148,17 @@ sub irc_botcmd_cmd2 {
my $nick = (split /!/, $user)[0];
my $irc = $sender->get_heap();
+ is($nick, $bot2->nick_name(), 'Command with args (user)');
+ is($where, '#testchannel', 'Command with args (channel)');
+ is_deeply($args, { test_arg => 'value1', test_arg2 => 'bar', opt0 => 'opt_arg'},
+ 'Command with args (arguments)');
+}
+
+sub irc_botcmd_cmd3 {
+ my ($sender, $user, $where, $args) = @_[SENDER, ARG0..ARG2];
+ my $nick = (split /!/, $user)[0];
+ my $irc = $sender->get_heap();
+
is($nick, $bot2->nick_name(), 'Colored command (user)');
is($where, '#testchannel', 'Colored command (channel)');
ok(!defined $args, 'Colored command (arguments)');
@@ -5,7 +5,7 @@ use POE;
use POE::Component::IRC;
use POE::Component::IRC::Plugin::BotCommand;
use POE::Component::Server::IRC;
-use Test::More tests => 14;
+use Test::More tests => 25;
my $bot1 = POE::Component::IRC->spawn(
Flood => 1,
@@ -35,6 +35,14 @@ POE::Session->create(
],
);
+my @bar_help = (
+ "Syntax: bar arg1 arg2 ...",
+ "Description: Test command2",
+ "Arguments:",
+ " arg1: What to bar (table|chair)",
+ " arg2: Where to bar"
+);
+
$poe_kernel->run();
sub _start {
@@ -121,13 +129,24 @@ sub irc_notice {
like($what, qr/^Unknown command:/, 'Bot reply');
my ($p) = grep { $_->isa('POE::Component::IRC::Plugin::BotCommand') } values %{ $bot1->plugin_list() };
ok($p->add(foo => 'Test command'), 'Add command foo');
+ ok($p->add(bar => {
+ info => 'Test command2',
+ args => [qw(arg1 arg2)],
+ arg1 => ['What to bar', qw(table chair)],
+ arg2 => 'Where to bar',
+ variable => 1,
+ }), 'Add command bar');
$irc->yield(privmsg => $where, "TestBot1: help");
+ $irc->yield(privmsg => $where, "TestBot1: help bar");
}
elsif ($heap->{replies} == 4) {
is($nick, $bot1->nick_name(), 'Bot nickname');
- like($what, qr/^Commands: foo/, 'Bot reply');
+ like($what, qr/^Commands: bar, foo/, 'Bot reply');
}
- elsif ($heap->{replies} == 5) {
+ elsif ($heap->{replies} >= 6 && $heap->{replies} <= 11) {
+ is($nick, $bot1->nick_name(), 'Bot nickname');
+ is($what, shift @bar_help, 'Command with args help');
+
$bot1->yield('quit');
$bot2->yield('quit');
}

0 comments on commit 9cc9f65

Please sign in to comment.