Support named-parameters in command registration

- convert several plugins to use named-parameters
- misc clean-ups in unrelated files
This commit is contained in:
Pragmatic Software 2021-07-30 19:01:24 -07:00
parent 483984754a
commit 926d57990b
19 changed files with 130 additions and 49 deletions

View File

@ -82,7 +82,7 @@ sub initialize {
# process command-line arguments for path and registry overrides
foreach my $arg (@ARGV) {
if ($arg =~ m/^-?(?:general\.)?((?:data|module|plugin|update)_dir)=(.*)$/) {
if ($arg =~ m/^-?(?:general\.)?((?:data|module|update)_dir)=(.*)$/) {
# check command-line arguments for directory overrides
my $override = $1;
my $value = $2;

View File

@ -10,13 +10,12 @@ package PBot::Core::Commands;
use parent 'PBot::Core::Class';
use PBot::Imports;
use PBot::Core::Utils::LoadModules qw/load_modules/;
sub initialize {
my ($self, %conf) = @_;
# registered commands hash table
# registered commands hashtable
$self->{commands} = {};
# command metadata stored as a HashObject
@ -31,20 +30,45 @@ sub initialize {
sub load_commands {
my ($self) = @_;
# load commands in Commands directory
$self->{pbot}->{logger}->log("Loading commands:\n");
load_modules($self, 'PBot::Core::Commands');
}
# named parameters interface to register()
sub add {
my ($self, %args) = @_;
$self->register(
delete $args{subref},
delete $args{name},
delete $args{requires_cap},
delete $args{help},
);
# die if any unhandled arguments were passed
foreach my $key (keys %args) {
$self->{pbot}->{logger}->log("Commands: error: extra arguments provided to add(): $key\n");
die;
}
}
# alias to unregister() for conisistency
sub remove {
my ($self) = @_;
$self->unregister(@_);
}
sub register {
my ($self, $subref, $name, $requires_cap) = @_;
my ($self, $subref, $name, $requires_cap, $help) = @_;
if (not defined $subref or not defined $name) {
Carp::croak("Missing parameters to Commands::register");
}
$name = lc $name;
$requires_cap //= 0;
$help //= '';
if (exists $self->{commands}->{$name}) {
$self->{pbot}->{logger}->log("Commands: warning: overwriting existing command $name\n");
@ -52,19 +76,27 @@ sub register {
# register command
$self->{commands}->{$name} = {
requires_cap => $requires_cap // 0,
requires_cap => $requires_cap,
subref => $subref,
};
# update command metadata
if (not $self->{metadata}->exists($name)) {
# create new metadata
$self->{metadata}->add($name, { requires_cap => $requires_cap, help => '' }, 1);
$self->{metadata}->add($name, { requires_cap => $requires_cap, help => $help }, 1);
} else {
# metadata already exists, just update requires_cap unless it's already set.
# metadata already exists
# we update data unless it's already set so the metadata file can be edited manually.
# update requires_cap unless it's already set.
if (not defined $self->get_meta($name, 'requires_cap')) {
$self->{metadata}->set($name, 'requires_cap', $requires_cap, 1);
}
# update help text unless it's already set.
if (not $self->get_meta($name, 'help')) {
$self->{metadata}->set($name, 'help', $help, 1);
}
}
# add can-<command> capability to PBot capabilities if required

View File

@ -9,19 +9,15 @@ package PBot::Core::Handlers;
use parent 'PBot::Core::Class';
use PBot::Imports;
use PBot::Core::Utils::LoadModules qw/load_modules/;
sub initialize {
my ($self, %conf) = @_;
# load the handlers in the Handlers directory
$self->load_handlers(%conf);
}
sub load_handlers {
my ($self, %conf) = @_;
$self->{pbot}->{logger}->log("Loading handlers:\n");
load_modules($self, 'PBot::Core::Handlers');
}

View File

@ -47,7 +47,12 @@ sub initialize {
my ($self, %conf) = @_;
# register bot command
$self->{pbot}->{commands}->register(sub { $self->cmd_actiontrigger(@_) }, 'actiontrigger', 1);
$self->{pbot}->{commands}->add(
name => 'actiontrigger',
help => 'Manages regular expression triggers to invoke bot commands',
requires_cap => 1,
subref => sub { $self->cmd_actiontrigger(@_) },
);
# add capability to admin group
$self->{pbot}->{capabilities}->add('admin', 'can-actiontrigger', 1);
@ -75,7 +80,7 @@ sub unload {
$self->dbi_end;
# unregister bot command
$self->{pbot}->{commands}->unregister('actiontrigger');
$self->{pbot}->{commands}->remove('actiontrigger');
# remove capability
$self->{pbot}->{capabilities}->remove('can-actiontrigger');

View File

@ -63,7 +63,11 @@ sub initialize {
my ($self, %conf) = @_;
# register `battleship` bot command
$self->{pbot}->{commands}->register(sub { $self->cmd_battleship(@_) }, 'battleship', 0);
$self->{pbot}->{commands}->add(
name => 'battleship',
help => 'Battleship board game, simplified for IRC',
subref => sub { $self->cmd_battleship(@_) },
);
# set the channel where to send game messages
$self->{channel} = $self->{pbot}->{registry}->get_value('battleship', 'channel') // '##battleship';
@ -128,7 +132,7 @@ sub unload {
my ($self) = @_;
# unregister `battleship` bot command
$self->{pbot}->{commands}->unregister('battleship');
$self->{pbot}->{commands}->remove('battleship');
# remove battleship loop event from event queue
$self->end_game_loop;

View File

@ -19,7 +19,12 @@ $Data::Dumper::Sortkeys = 1;
sub initialize {
my ($self, %conf) = @_;
$self->{pbot}->{commands}->register(sub { $self->cmd_connect4(@_) }, 'connect4', 0);
$self->{pbot}->{commands}->add(
name => 'connect4',
help => 'Connect-4 board game',
subref => sub { $self->cmd_connect4(@_) },
);
$self->{pbot}->{event_dispatcher}->register_handler('irc.part', sub { $self->on_departure(@_) });
$self->{pbot}->{event_dispatcher}->register_handler('irc.quit', sub { $self->on_departure(@_) });
@ -32,7 +37,7 @@ sub initialize {
sub unload {
my $self = shift;
$self->{pbot}->{commands}->unregister('connect4');
$self->{pbot}->{commands}->remove('connect4');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.part');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.quit');
$self->{pbot}->{event_dispatcher}->remove_handler('irc.kick');

View File

@ -18,12 +18,16 @@ sub initialize {
$self->{pbot}->{registry}->add_default('text', 'date', 'default_timezone', 'UTC');
# register `date` bot command
$self->{pbot}->{commands}->register(sub { $self->cmd_date(@_) }, "date", 0);
$self->{pbot}->{commands}->add(
name => 'date',
help => 'Show date and time',
subref => sub { $self->cmd_date(@_) },
);
}
sub unload {
my $self = shift;
$self->{pbot}->{commands}->unregister("date");
$self->{pbot}->{commands}->remove('date');
}
sub cmd_date {

View File

@ -22,12 +22,16 @@ sub initialize {
$self->{pbot}->{registry}->set_default('googlesearch', 'api_key', 'private', 1);
$self->{pbot}->{registry}->set_default('googlesearch', 'context', 'private', 1);
$self->{pbot}->{commands}->register(sub { $self->cmd_googlesearch(@_) }, 'google', 0);
$self->{pbot}->{commands}->add(
name => 'google',
help => 'Google search',
subref => sub { $self->cmd_googlesearch(@_) },
);
}
sub unload {
my $self = shift;
$self->{pbot}->{commands}->unregister('google');
my ($self) = @_;
$self->{pbot}->{commands}->remove('google');
}
sub cmd_googlesearch {

View File

@ -15,12 +15,16 @@ use Time::Duration qw/duration/;
sub initialize {
my ($self, %conf) = @_;
$self->{pbot}->{commands}->register(sub { return $self->cmd_parsedate(@_) }, "pd", 0);
$self->{pbot}->{commands}->add(
name => 'pd',
help => 'Simple command to test ParseDate interface',
subref =>sub { return $self->cmd_parsedate(@_) },
);
}
sub unload {
my $self = shift;
$self->{pbot}->{commands}->unregister("pd");
$self->{pbot}->{commands}->remove('pd');
}
sub cmd_parsedate {

View File

@ -90,16 +90,17 @@ sub initialize {
);
# register the `plang` command
$self->{pbot}->{commands}->register(sub { $self->cmd_plang(@_) }, "plang", 0);
$self->{pbot}->{commands}->register(sub { $self->cmd_plang(@_) }, 'plang');
# register the `plangrepl` command (does not reset environment)
$self->{pbot}->{commands}->register(sub { $self->cmd_plangrepl(@_) }, "plangrepl", 0);
$self->{pbot}->{commands}->register(sub { $self->cmd_plangrepl(@_) }, 'plangrepl');
}
# runs when plugin is unloaded
sub unload {
my $self = shift;
$self->{pbot}->{commands}->unregister("plang");
$self->{pbot}->{commands}->unregister('plang');
$self->{pbot}->{commands}->unregister('plangrepl');
}
sub cmd_plang {

View File

@ -33,10 +33,10 @@ sub initialize {
$self->{pbot}->{atexit}->register(sub { $self->{database}->end(); return; });
$self->{pbot}->{commands}->register(sub { $self->cmd_grab_quotegrab(@_) }, 'grab', 0);
$self->{pbot}->{commands}->register(sub { $self->cmd_show_quotegrab(@_) }, 'getq', 0);
$self->{pbot}->{commands}->register(sub { $self->cmd_delete_quotegrab(@_) }, 'delq', 0);
$self->{pbot}->{commands}->register(sub { $self->cmd_show_random_quotegrab(@_) }, 'rq', 0);
$self->{pbot}->{commands}->register(sub { $self->cmd_grab_quotegrab(@_) }, 'grab');
$self->{pbot}->{commands}->register(sub { $self->cmd_show_quotegrab(@_) }, 'getq');
$self->{pbot}->{commands}->register(sub { $self->cmd_delete_quotegrab(@_) }, 'delq');
$self->{pbot}->{commands}->register(sub { $self->cmd_show_random_quotegrab(@_) }, 'rq' );
}
sub unload {

View File

@ -19,7 +19,11 @@ sub initialize {
my ($self, %conf) = @_;
# register `remindme` bot command
$self->{pbot}->{commands}->register(sub { $self->cmd_remindme(@_) }, 'remindme', 0);
$self->{pbot}->{commands}->add(
name => 'remindme',
help => 'Manage personal reminder notifications',
subref => sub { $self->cmd_remindme(@_) },
);
# set location of sqlite database
$self->{filename} = $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/reminders.sqlite3';
@ -41,7 +45,7 @@ sub unload {
$self->dbi_end;
# unregister `remindme` command
$self->{pbot}->{commands}->unregister('remindme');
$self->{pbot}->{commands}->remove('remindme');
# remove all reminder events from event queue
$self->{pbot}->{event_queue}->dequeue_event('reminder .*');

View File

@ -18,10 +18,11 @@ use Storable qw/dclone/;
sub initialize {
my ($self, %conf) = @_;
$self->{pbot}->{commands}->register(sub { $self->cmd_mod(@_) }, 'mod', 0);
$self->{pbot}->{commands}->set_meta(
'mod', 'help',
'Provides restricted moderation abilities to voiced users. They can kick/ban/etc only users that are not admins, whitelisted, voiced or opped.'
$self->{pbot}->{commands}->add(
name => 'mod',
help => 'Provides restricted moderation abilities to voiced users. They can kick/ban/etc only users that are not admins, whitelisted, voiced or opped.',
subref => sub { $self->cmd_mod(@_) },
);
$self->{pbot}->{capabilities}->add('chanmod', 'can-mod', 1);
@ -42,7 +43,7 @@ sub initialize {
sub unload {
my ($self) = @_;
$self->{pbot}->{commands}->unregister('mod');
$self->{pbot}->{commands}->remove('mod');
$self->{pbot}->{capabilities}->remove('chanmod');
}

View File

@ -30,12 +30,17 @@ use IPC::Run qw/start pump finish/;
sub initialize {
my ($self, %conf) = @_;
$self->{pbot}->{commands}->register(sub { $self->cmd_runcmd(@_) }, "runcmd", 1);
$self->{pbot}->{commands}->add(
name => 'runcmd',
help => 'Executes a system command and outputs each line in real-time',
requires_cap => 1,
subref => sub { $self->cmd_runcmd(@_) },
);
}
sub unload {
my $self = shift;
$self->{pbot}->{commands}->unregister("runcmd");
$self->{pbot}->{commands}->remove('runcmd');
}
sub cmd_runcmd {

View File

@ -41,7 +41,8 @@ $Data::Dumper::Useqq = 1;
sub initialize {
my ($self, %conf) = @_;
$self->{pbot}->{commands}->register(sub { $self->cmd_spinach(@_) }, 'spinach', 0);
$self->{pbot}->{commands}->register(sub { $self->cmd_spinach(@_) }, 'spinach');
$self->{pbot}->{event_dispatcher}->register_handler('irc.part', sub { $self->on_departure(@_) });
$self->{pbot}->{event_dispatcher}->register_handler('irc.quit', sub { $self->on_departure(@_) });

View File

@ -15,12 +15,17 @@ use XML::LibXML;
sub initialize {
my ($self, %conf) = @_;
$self->{pbot}->{commands}->register(sub { $self->cmd_weather(@_) }, "weather", 0);
$self->{pbot}->{commands}->add(
name => 'weather',
help => 'Provides weather service via AccuWeather',
subref => sub { $self->cmd_weather(@_) },
);
}
sub unload {
my $self = shift;
$self->{pbot}->{commands}->unregister("weather");
$self->{pbot}->{commands}->remove('weather');
}
sub cmd_weather {

View File

@ -22,12 +22,17 @@ sub initialize {
# make `wolfram.appid` registry entry private by default
$self->{pbot}->{registry}->set_default('wolfram', 'appid', 'private', 1);
$self->{pbot}->{commands}->register(sub { $self->cmd_wolfram(@_) }, 'wolfram', 0);
# add wolfram command
$self->{pbot}->{commands}->add(
name => 'wolfram',
help => 'Queries Wolfram|Alpha Short Answers API',
subref => sub { $self->cmd_wolfram(@_) },
);
}
sub unload {
my ($self) = @_;
$self->{pbot}->{commands}->unregister('wolfram');
$self->{pbot}->{commands}->remove('wolfram');
}
sub cmd_wolfram {

View File

@ -16,12 +16,17 @@ use URI::Escape qw/uri_escape_utf8/;
sub initialize {
my ($self, %conf) = @_;
$self->{pbot}->{commands}->register(sub { $self->cmd_wttr(@_) }, "wttr", 0);
$self->{pbot}->{commands}->add(
name => 'wttr',
help => 'Provides weather information via wttr.in',
subref => sub { $self->cmd_wttr(@_) },
);
}
sub unload {
my $self = shift;
$self->{pbot}->{commands}->unregister("wttr");
$self->{pbot}->{commands}->remove('wttr');
}
sub cmd_wttr {

View File

@ -25,7 +25,7 @@ use PBot::Imports;
# These are set by the /misc/update_version script
use constant {
BUILD_NAME => "PBot",
BUILD_REVISION => 4328,
BUILD_REVISION => 4329,
BUILD_DATE => "2021-07-30",
};