Simplify use of getopt() throughout

This commit is contained in:
Pragmatic Software 2021-07-30 15:01:38 -07:00
parent bbe5b58b97
commit 483984754a
12 changed files with 439 additions and 370 deletions

View File

@ -12,7 +12,6 @@ use parent 'PBot::Core::Class';
use Time::Duration;
use Time::HiRes qw(gettimeofday);
use Getopt::Long qw(GetOptionsFromArray);
use POSIX qw(strftime);
use Storable;
use LWP::UserAgent;
@ -94,25 +93,26 @@ sub cmd_factundo {
my $arguments = $context->{arguments};
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
my ($list_undos, $goto_revision);
my @opt_args = $self->{pbot}->{interpreter}->split_line($arguments, strip_quotes => 1);
GetOptionsFromArray(
\@opt_args,
'l:i' => \$list_undos,
'r=i' => \$goto_revision
my %opts = (
l => \$list_undos,
r => \$goto_revision,
);
return "/say $getopt_error -- $usage" if defined $getopt_error;
return $usage if @opt_args > 2;
return $usage if not @opt_args;
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$arguments,
\%opts,
['bundling'],
'l:i',
'r=i',
);
$arguments = join(' ', map { $_ = "'$_'" if $_ =~ m/ /; $_; } @opt_args);
return "/say $opt_error -- $usage" if defined $opt_error;
return $usage if @$opt_args > 2;
return $usage if not @$opt_args;
$arguments = join(' ', map { $_ = "'$_'" if $_ =~ m/ /; $_; } @$opt_args);
my $arglist = $self->{pbot}->{interpreter}->make_args($arguments);
my ($channel, $trigger) = $self->find_factoid_with_optional_channel(
@ -199,25 +199,26 @@ sub cmd_factredo {
my $arguments = $context->{arguments};
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
my ($list_undos, $goto_revision);
my @opt_args = $self->{pbot}->{interpreter}->split_line($arguments, strip_quotes => 1);
GetOptionsFromArray(
\@opt_args,
'l:i' => \$list_undos,
'r=i' => \$goto_revision
my %opts = (
l => \$list_undos,
r => \$goto_revision,
);
return "/say $getopt_error -- $usage" if defined $getopt_error;
return $usage if @opt_args > 2;
return $usage if not @opt_args;
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$arguments,
\%opts,
['bundling'],
'l:i',
'r=i',
);
$arguments = join(' ', map { $_ = "'$_'" if $_ =~ m/ /; $_; } @opt_args);
return "/say $opt_error -- $usage" if defined $opt_error;
return $usage if @$opt_args > 2;
return $usage if not @$opt_args;
$arguments = join(' ', map { $_ = "'$_'" if $_ =~ m/ /; $_; } @$opt_args);
my ($channel, $trigger) = $self->find_factoid_with_optional_channel(
$context->{from}, $context->{arguments}, 'factredo', explicit => 1, exact_channel => 1
@ -807,31 +808,30 @@ sub cmd_factrem {
sub cmd_factshow {
my ($self, $context) = @_;
my $factoids = $self->{pbot}->{factoids}->{data}->{storage};
$context->{preserve_whitespace} = 1;
my $usage = "Usage: factshow [-p] [channel] <keyword>; -p to paste";
return $usage if not length $context->{arguments};
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
my %opts;
my ($paste);
my @opt_args = $self->{pbot}->{interpreter}->split_line($context->{arguments}, strip_quotes => 1);
GetOptionsFromArray(
\@opt_args,
'p' => \$paste
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$context->{arguments},
\%opts,
['bundling'],
'p',
);
return "/say $getopt_error -- $usage" if defined $getopt_error;
return "Too many arguments -- $usage" if @opt_args > 2;
return "Missing argument -- $usage" if not @opt_args;
return "/say $opt_error -- $usage" if defined $opt_error;
return "Too many arguments -- $usage" if @$opt_args > 2;
return "Missing argument -- $usage" if not @$opt_args;
my ($chan, $trig) = @opt_args;
my $factoids = $self->{pbot}->{factoids}->{data}->{storage};
$context->{preserve_whitespace} = 1;
my ($chan, $trig) = @$opt_args;
$chan = $context->{from} if not defined $trig;
my $args = join(' ', map { $_ = "'$_'" if $_ =~ m/ /; $_; } @opt_args);
my $args = join(' ', map { $_ = "'$_'" if $_ =~ m/ /; $_; } @$opt_args);
my ($channel, $trigger) = $self->find_factoid_with_optional_channel($context->{from}, $args, 'factshow', usage => $usage);
return $channel if not defined $trigger; # if $trigger is not defined, $channel is an error message
@ -843,7 +843,7 @@ sub cmd_factshow {
my $result = "$trigger_name: ";
if ($paste) {
if ($opts{p}) {
$result .= $self->{pbot}->{webpaste}->paste($factoids->get_data($channel, $trigger, 'action'), no_split => 1);
$result = "[$channel_name] $result" if $channel ne lc $chan;
return $result;
@ -862,25 +862,25 @@ sub cmd_factlog {
return $usage if not length $context->{arguments};
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
my ($show_hostmask, $actual_timestamp);
my @opt_args = $self->{pbot}->{interpreter}->split_line($context->{arguments}, strip_quotes => 1);
GetOptionsFromArray(
\@opt_args,
'h' => \$show_hostmask,
't' => \$actual_timestamp
my %opts = (
h => \$show_hostmask,
t => \$actual_timestamp,
);
return "/say $getopt_error -- $usage" if defined $getopt_error;
return "Too many arguments -- $usage" if @opt_args > 2;
return "Missing argument -- $usage" if not @opt_args;
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$context->{arguments},
\%opts,
['bundling'],
qw(h t),
);
my $args = join(' ', map { $_ = "'$_'" if $_ =~ m/ /; $_; } @opt_args);
return "/say $opt_error -- $usage" if defined $opt_error;
return "Too many arguments -- $usage" if @$opt_args > 2;
return "Missing argument -- $usage" if not @$opt_args;
my $args = join(' ', map { $_ = "'$_'" if $_ =~ m/ /; $_; } @$opt_args);
my ($channel, $trigger) = $self->find_factoid_with_optional_channel($context->{from}, $args, 'factlog', usage => $usage, exact_channel => 1);

View File

@ -10,7 +10,6 @@ package PBot::Core::Commands::MessageHistory;
use PBot::Imports;
use parent 'PBot::Core::Class';
use Getopt::Long qw(GetOptionsFromArray);
use Time::HiRes qw(time tv_interval);
use Time::Duration;
@ -40,33 +39,30 @@ sub cmd_list_also_known_as {
return $usage;
}
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
my ($show_hostmasks, $show_gecos, $show_nickserv, $show_id, $show_relationship, $show_weak, $show_last_seen, $dont_use_aliases_table, $sort_method);
Getopt::Long::Configure("bundling_override");
my $sort_method = undef;
my ($show_hostmasks, $show_gecos, $show_nickserv, $show_id, $show_relationship, $show_weak, $show_last_seen, $dont_use_aliases_table);
my @opt_args = $self->{pbot}->{interpreter}->split_line($context->{arguments}, strip_quotes => 1);
GetOptionsFromArray(
\@opt_args,
'h' => \$show_hostmasks,
'l' => \$show_last_seen,
'n' => \$show_nickserv,
'r' => \$show_relationship,
'g' => \$show_gecos,
'w' => \$show_weak,
'z' => \$dont_use_aliases_table,
'i' => \$show_id,
'sort|s=s' => \$sort_method,
my %opts = (
h => \$show_hostmasks,
i => \$show_id,
l => \$show_last_seen,
n => \$show_nickserv,
g => \$show_gecos,
r => \$show_relationship,
w => \$show_weak,
z => \$dont_use_aliases_table,
sort => \$sort_method,
);
return "/say $getopt_error -- $usage" if defined $getopt_error;
return "Too many arguments -- $usage" if @opt_args > 1;
return "Missing argument -- $usage" if @opt_args != 1;
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$context->{arguments},
\%opts,
['bundling_override'],
qw(h i l n g r w z sort|s=s),
);
return "/say $opt_error -- $usage" if defined $opt_error;
return "Too many arguments -- $usage" if @$opt_args > 1;
return "Missing argument -- $usage" if @$opt_args != 1;
$sort_method = 'seen' if $show_last_seen and not defined $sort_method;
$sort_method = 'nick' if not defined $sort_method;
@ -146,10 +142,10 @@ sub cmd_list_also_known_as {
return "Invalid sort method '$sort_method'; valid methods are: " . join(', ', sort keys %sort) . "; prefix with - to invert sort direction.";
}
my %akas = $self->{pbot}->{messagehistory}->{database}->get_also_known_as($opt_args[0], $dont_use_aliases_table);
my %akas = $self->{pbot}->{messagehistory}->{database}->get_also_known_as($opt_args->[0], $dont_use_aliases_table);
if (%akas) {
my $result = "$opt_args[0] also known as:\n";
my $result = "$opt_args->[0] also known as:\n";
my %nicks;
my $sep = "";
@ -195,7 +191,7 @@ sub cmd_list_also_known_as {
}
return $result;
} else {
return "I don't know anybody named $opt_args[0].";
return "I don't know anybody named $opt_args->[0].";
}
}
@ -214,14 +210,7 @@ sub cmd_recall_message {
my @recalls = split /\s\+\s/, $arguments;
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
my $result = '';
Getopt::Long::Configure("bundling_override");
# global state
my ($recall_channel, $raw, $random);
@ -229,21 +218,34 @@ sub cmd_recall_message {
foreach my $recall (@recalls) {
my ($recall_nick, $recall_text, $recall_history, $recall_before, $recall_after, $recall_context, $recall_count);
my @opt_args = $self->{pbot}->{interpreter}->split_line($recall, strip_quotes => 1);
GetOptionsFromArray(
\@opt_args,
'channel|c=s' => \$recall_channel,
'history|h=s' => \$recall_history,
'text|t=s' => \$recall_text,
'before|b=i' => \$recall_before,
'after|a=i' => \$recall_after,
'count|n=i' => \$recall_count,
'context|x=s' => \$recall_context,
'raw|r' => \$raw,
'random' => \$random,
my %opts = (
'channel' => \$recall_channel,
'history' => \$recall_history,
'text' => \$recall_text,
'before' => \$recall_before,
'after' => \$recall_after,
'count' => \$recall_count,
'context' => \$recall_context,
'raw' => \$raw,
'random' => \$random,
);
return "/say $getopt_error -- $usage" if defined $getopt_error;
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$recall,
\%opts,
['bundling_override'],
'channel|c=s',
'history|h=s',
'text|t=s',
'before|b=i',
'after|a=i',
'count|n=i',
'context|x=s',
'raw|r',
'random',
);
return "/say $opt_error -- $usage" if defined $opt_error;
if (defined $recall_history and defined $recall_text) {
return "/say $context->{nick}: The -h and -t options cannot be used together.";
@ -254,16 +256,16 @@ sub cmd_recall_message {
my $channel_arg = 1 if defined $recall_channel;
my $history_arg = 1 if defined $recall_history;
$recall_nick = shift @opt_args if @opt_args;
$recall_history = shift @opt_args if @opt_args and not $history_arg and not defined $recall_text;
$recall_nick = shift @$opt_args if @$opt_args;
$recall_history = shift @$opt_args if @$opt_args and not $history_arg and not defined $recall_text;
if (not $channel_arg) {
$recall_channel = "@opt_args" if @opt_args;
$recall_channel = "@$opt_args" if @$opt_args;
} else {
if (defined $recall_history) {
$recall_history .= ' ';
}
$recall_history .= "@opt_args" if @opt_args;
$recall_history .= "@$opt_args" if @$opt_args;
}
if (defined $recall_text and not defined $recall_history) {

View File

@ -13,8 +13,6 @@ use parent 'PBot::Core::Class';
use Time::HiRes qw/gettimeofday/;
use Time::Duration qw/concise ago/;
use Getopt::Long qw/GetOptionsFromArray/;
sub initialize {
my ($self, %conf) = @_;
$self->{pbot}->{commands}->register(sub { $self->cmd_nicklist(@_) }, "nicklist", 1);
@ -25,30 +23,28 @@ sub cmd_nicklist {
my $usage = "Usage: nicklist (<channel [nick]> | <nick>) [-sort <by>] [-hostmask] [-join]; -hostmask shows hostmasks instead of nicks; -join includes join time";
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
Getopt::Long::Configure("bundling_override");
my $sort_method = 'nick';
my $full_hostmask = 0;
my $include_join = 0;
my @args = $self->{pbot}->{interpreter}->split_line($context->{arguments}, strip_quotes => 1);
GetOptionsFromArray(
\@args,
'sort|s=s' => \$sort_method,
'hostmask|hm' => \$full_hostmask,
'join|j' => \$include_join,
my %opts = (
sort => \$sort_method,
hostmask => \$full_hostmask,
join => \$include_join,
);
return "$getopt_error; $usage" if defined $getopt_error;
return "Too many arguments -- $usage" if @args > 2;
return $usage if @args == 0 or not length $args[0];
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$context->{arguments},
\%opts,
['bundling_override'],
'sort|s=s',
'hostmask|hm',
'join|j',
);
return "$opt_error; $usage" if defined $opt_error;
return "Too many arguments -- $usage" if @$opt_args > 2;
return $usage if @$opt_args == 0 or not length $opt_args->[0];
my %sort = (
'spoken' => sub {
@ -96,57 +92,57 @@ sub cmd_nicklist {
}
# insert from channel as first argument if first argument is not a channel
if ($args[0] !~ /^#/) {
unshift @args, $context->{from};
if ($opt_args->[0] !~ /^#/) {
unshift @$opt_args, $context->{from};
}
my $nicklist = $self->{pbot}->{nicklist}->{nicklist};
# ensure channel has a nicklist
if (not exists $nicklist->{lc $args[0]}) {
return "No nicklist for channel $args[0].";
if (not exists $nicklist->{lc $opt_args->[0]}) {
return "No nicklist for channel $opt_args->[0].";
}
my $result;
if (@args == 1) {
if (@$opt_args == 1) {
# nicklist for a specific channel
my $count = keys %{$nicklist->{lc $args[0]}};
my $count = keys %{$nicklist->{lc $opt_args->[0]}};
$result = "$count nick" . ($count == 1 ? '' : 's') . " in $args[0]:\n";
$result = "$count nick" . ($count == 1 ? '' : 's') . " in $opt_args->[0]:\n";
foreach my $entry (
sort {
$sort{$sort_method}->($nicklist->{lc $args[0]}, $sort_direction)
} keys %{$nicklist->{lc $args[0]}}
$sort{$sort_method}->($nicklist->{lc $opt_args->[0]}, $sort_direction)
} keys %{$nicklist->{lc $opt_args->[0]}}
) {
if ($full_hostmask) {
$result .= " $nicklist->{lc $args[0]}->{$entry}->{hostmask}";
$result .= " $nicklist->{lc $opt_args->[0]}->{$entry}->{hostmask}";
} else {
$result .= " $nicklist->{lc $args[0]}->{$entry}->{nick}";
$result .= " $nicklist->{lc $opt_args->[0]}->{$entry}->{nick}";
}
my $sep = ': ';
if ($nicklist->{lc $args[0]}->{$entry}->{timestamp} > 0) {
my $duration = concise ago (gettimeofday - $nicklist->{lc $args[0]}->{$entry}->{timestamp});
if ($nicklist->{lc $opt_args->[0]}->{$entry}->{timestamp} > 0) {
my $duration = concise ago (gettimeofday - $nicklist->{lc $opt_args->[0]}->{$entry}->{timestamp});
$result .= "${sep}last spoken $duration";
$sep = ', ';
}
if ($include_join and $nicklist->{lc $args[0]}->{$entry}->{join} > 0) {
my $duration = concise ago (gettimeofday - $nicklist->{lc $args[0]}->{$entry}->{join});
if ($include_join and $nicklist->{lc $opt_args->[0]}->{$entry}->{join} > 0) {
my $duration = concise ago (gettimeofday - $nicklist->{lc $opt_args->[0]}->{$entry}->{join});
$result .= "${sep}joined $duration";
$sep = ', ';
}
foreach my $key (sort keys %{$nicklist->{lc $args[0]}->{$entry}}) {
foreach my $key (sort keys %{$nicklist->{lc $opt_args->[0]}->{$entry}}) {
next if grep { $key eq $_ } qw/nick user host join timestamp hostmask/;
if ($nicklist->{lc $args[0]}->{$entry}->{$key} == 1) {
if ($nicklist->{lc $opt_args->[0]}->{$entry}->{$key} == 1) {
$result .= "$sep$key";
} else {
$result .= "$sep$key => $nicklist->{lc $args[0]}->{$entry}->{$key}";
$result .= "$sep$key => $nicklist->{lc $opt_args->[0]}->{$entry}->{$key}";
}
$sep = ', ';
}
@ -155,28 +151,28 @@ sub cmd_nicklist {
} else {
# nicklist for a specific user
if (not exists $nicklist->{lc $args[0]}->{lc $args[1]}) {
return "No such nick $args[1] in channel $args[0].";
if (not exists $nicklist->{lc $opt_args->[0]}->{lc $opt_args->[1]}) {
return "No such nick $opt_args->[1] in channel $opt_args->[0].";
}
$result = "Nicklist information for $nicklist->{lc $args[0]}->{lc $args[1]}->{hostmask} in $args[0]: ";
$result = "Nicklist information for $nicklist->{lc $opt_args->[0]}->{lc $opt_args->[1]}->{hostmask} in $opt_args->[0]: ";
my $sep = '';
if ($nicklist->{lc $args[0]}->{lc $args[1]}->{timestamp} > 0) {
my $duration = concise ago (gettimeofday - $nicklist->{lc $args[0]}->{lc $args[1]}->{timestamp});
if ($nicklist->{lc $opt_args->[0]}->{lc $opt_args->[1]}->{timestamp} > 0) {
my $duration = concise ago (gettimeofday - $nicklist->{lc $opt_args->[0]}->{lc $opt_args->[1]}->{timestamp});
$result .= "last spoken $duration";
$sep = ', ';
}
if ($nicklist->{lc $args[0]}->{lc $args[1]}->{join} > 0) {
my $duration = concise ago (gettimeofday - $nicklist->{lc $args[0]}->{lc $args[1]}->{join});
if ($nicklist->{lc $opt_args->[0]}->{lc $opt_args->[1]}->{join} > 0) {
my $duration = concise ago (gettimeofday - $nicklist->{lc $opt_args->[0]}->{lc $opt_args->[1]}->{join});
$result .= "${sep}joined $duration";
$sep = ', ';
}
foreach my $key (sort keys %{$nicklist->{lc $args[0]}->{lc $args[1]}}) {
foreach my $key (sort keys %{$nicklist->{lc $opt_args->[0]}->{lc $opt_args->[1]}}) {
next if grep { $key eq $_ } qw/nick user host join timestamp hostmask/;
$result .= "$sep$key => $nicklist->{lc $args[0]}->{lc $args[1]}->{$key}";
$result .= "$sep$key => $nicklist->{lc $opt_args->[0]}->{lc $opt_args->[1]}->{$key}";
$sep = ', ';
}

View File

@ -12,7 +12,6 @@ use parent 'PBot::Core::Class';
use Time::Duration qw/concise duration/;
use Time::HiRes qw/gettimeofday/;
use Getopt::Long qw/GetOptionsFromArray/;
sub initialize {
my ($self, %conf) = @_;
@ -30,26 +29,24 @@ sub cmd_ps {
my $usage = 'Usage: ps [-atu]; -a show all information; -t show running time; -u show user/channel';
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
Getopt::Long::Configure("bundling");
my ($show_all, $show_user, $show_running_time);
my @opt_args = $self->{pbot}->{interpreter}->split_line($context->{arguments}, strip_quotes => 1);
GetOptionsFromArray(
\@opt_args,
'all|a' => \$show_all,
'user|u' => \$show_user,
'time|t' => \$show_running_time
my %opts = (
all => \$show_all,
user => \$show_user,
time => \$show_running_time,
);
return "$getopt_error; $usage" if defined $getopt_error;
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$context->{arguments},
\%opts,
['bundling'],
'all|a',
'user|u',
'time|t',
);
return "$opt_error; $usage" if defined $opt_error;
my @processes;
@ -90,28 +87,26 @@ sub cmd_kill {
my $usage = 'Usage: kill [-a] [-t <seconds>] [-s <signal>] [pids...]; -a kill all processes; -t <seconds> kill processes running longer than <seconds>; -s send <signal> to processes';
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
Getopt::Long::Configure("bundling");
my ($kill_all, $kill_time, $signal);
my @opt_args = $self->{pbot}->{interpreter}->split_line($context->{arguments}, preserve_escapes => 1, strip_quotes => 1);
GetOptionsFromArray(
\@opt_args,
'all|a' => \$kill_all,
'time|t=i' => \$kill_time,
'signal|s=s' => \$signal,
my %opts = (
all => \$kill_all,
time => \$kill_time,
signal => \$signal,
);
return "$getopt_error; $usage" if defined $getopt_error;
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$context->{arguments},
\%opts,
['bundling'],
'all|a',
'time|t=i',
'signal|s=s',
);
if (not $kill_all and not $kill_time and not @opt_args) {
return "$opt_error; $usage" if defined $opt_error;
if (not $kill_all and not $kill_time and not @$opt_args) {
return "Must specify PIDs to kill unless options -a or -t are provided.";
}
@ -132,7 +127,7 @@ sub cmd_kill {
push @pids, $pid;
}
} else {
foreach my $pid (@opt_args) {
foreach my $pid (@$opt_args) {
return "No such pid $pid." if not exists $self->{pbot}->{process_manager}->{processes}->{$pid};
push @pids, $pid;
}

View File

@ -15,15 +15,14 @@ use parent 'PBot::Core::Class', 'PBot::Core::Registerable';
use PBot::Imports;
use PBot::Core::MessageHistory::Constants ':all';
use Time::HiRes qw/gettimeofday/;
use Time::Duration;
use PBot::Core::Utils::ValidateString;
use Encode;
use Getopt::Long qw(GetOptionsFromArray);
use Time::Duration;
use Time::HiRes qw(gettimeofday);
use Unicode::Truncate;
use PBot::Core::Utils::ValidateString;
sub initialize {
my ($self, %conf) = @_;
@ -422,7 +421,7 @@ sub interpret {
if (@factoids == 1) {
# found the factoid's channel
($fact_channel, $fact_trigger) = $factoids[0];
($fact_channel, $fact_trigger) = @{$factoids[0]};
} else {
# more than one factoid found, normally we would prompt to disambiguate
# but in this case we'll just go ahead and assume global
@ -1380,4 +1379,38 @@ sub lc_args {
for (my $i = 0; $i < @$args; $i++) { $args->[$i] = lc $args->[$i]; }
}
# getopt boilerplate in one place
# 99% of our getopt use is on a string
sub getopt {
my $self = shift;
$self->getopt_from_string(@_);
}
# getopt_from_string() uses our split_line() function instead of
# GetOpt::Long::GetOptionsFromString's Text::ParseWords
sub getopt_from_string {
my ($self, $string, $result, $config, @opts) = @_;
my @opt_args = $self->split_line($string, strip_quotes => 1);
return $self->getopt_from_array(\@opt_args, $result, $config, @opts);
}
sub getopt_from_array {
my ($self, $opt_args, $result, $config, @opts) = @_;
my $opt_error;
local $SIG{__WARN__} = sub {
$opt_error = shift;
chomp $opt_error;
};
Getopt::Long::Configure(@$config);
GetOptionsFromArray($opt_args, $result, @opts);
return ($opt_args, $opt_error);
}
1;

View File

@ -10,8 +10,6 @@ use parent 'PBot::Plugin::Base';
use PBot::Imports;
use Getopt::Long qw(GetOptionsFromArray);
sub initialize {
my ($self, %conf) = @_;
@ -31,29 +29,24 @@ sub unload {
sub cmd_date {
my ($self, $context) = @_;
my $usage = "date [-u <user account>] [timezone]";
my $usage = "Usage: date [-u <user account>] [timezone]";
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
my %opts;
my ($user_override, $show_usage);
my @opt_args = $self->{pbot}->{interpreter}->split_line($context->{arguments}, strip_quotes => 1);
Getopt::Long::Configure("bundling");
GetOptionsFromArray(
\@opt_args,
'u=s' => \$user_override,
'h' => \$show_usage
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$context->{arguments},
\%opts,
['bundling'],
'u=s',
'h',
);
return $usage if $show_usage;
return "/say $getopt_error -- $usage" if defined $getopt_error;
return $usage if $opts{h};
return "/say $opt_error -- $usage" if $opt_error;
$context->{arguments} = "@opt_args";
$context->{arguments} = "@$opt_args";
my $user_override = $opts{u};
my $tz_override;
# check for user timezone metadata

View File

@ -11,8 +11,6 @@ use parent 'PBot::Plugin::Base';
use PBot::Imports;
use Getopt::Long qw(GetOptionsFromArray);
sub initialize {
my ($self, %conf) = @_;

View File

@ -16,7 +16,6 @@ use PBot::Imports;
use HTML::Entities;
use Time::Duration;
use Time::HiRes qw(gettimeofday);
use Getopt::Long qw(GetOptionsFromArray);
use PBot::Plugin::Quotegrabs::Storage::SQLite; # use SQLite backend for quotegrabs database
#use PBot::Plugin::Quotegrabs::Storage::Hashtable; # use Perl hashtable backend for quotegrabs database
@ -60,17 +59,20 @@ sub export_quotegrabs {
my $text;
my $table_id = 1;
my $had_table = 0;
my $time = localtime;
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
open FILE, "> $self->{export_path}" or return "Could not open export path.";
my $time = localtime;
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
print FILE "<html>\n<head><link href=\"css/blue.css\" rel=\"stylesheet\" type=\"text/css\">\n";
print FILE '<script type="text/javascript" src="js/jquery-latest.js"></script>' . "\n";
print FILE '<script type="text/javascript" src="js/jquery.tablesorter.js"></script>' . "\n";
print FILE '<script type="text/javascript" src="js/picnet.table.filter.min.js"></script>' . "\n";
print FILE "</head>\n<body><i>Generated at $time</i><hr><h2>$botnick\'s Quotegrabs</h2>\n";
my $i = 0;
my $last_channel = "";
my $i = 0;
my $last_channel = '';
foreach my $quotegrab (sort { $$a{channel} cmp $$b{channel} or $$a{nick} cmp $$b{nick} } @$quotegrabs) {
if (not $quotegrab->{channel} =~ /^$last_channel$/i) {
print FILE "<a href='#" . encode_entities($quotegrab->{channel}) . "'>" . encode_entities($quotegrab->{channel}) . "</a><br>\n";
@ -78,7 +80,7 @@ sub export_quotegrabs {
}
}
$last_channel = "";
$last_channel = '';
foreach my $quotegrab (sort { $$a{channel} cmp $$b{channel} or lc $$a{nick} cmp lc $$b{nick} } @$quotegrabs) {
if (not $quotegrab->{channel} =~ /^$last_channel$/i) {
print FILE "</tbody>\n</table>\n" if $had_table;
@ -99,8 +101,11 @@ sub export_quotegrabs {
$last_channel = $quotegrab->{channel};
$i++;
if ($i % 2) { print FILE "<tr bgcolor=\"#dddddd\">\n"; }
else { print FILE "<tr>\n"; }
if ($i % 2) {
print FILE "<tr bgcolor=\"#dddddd\">\n";
} else {
print FILE "<tr>\n";
}
print FILE "<td>" . ($quotegrab->{id}) . "</td>";
@ -111,8 +116,11 @@ sub export_quotegrabs {
my $nick;
$text = $quotegrab->{text};
if ($text =~ s/^\/me\s+//) { $nick = "* $nicks[0]"; }
else { $nick = "<$nicks[0]>"; }
if ($text =~ s/^\/me\s+//) {
$nick = "* $nicks[0]";
} else {
$nick = "<$nicks[0]>";
}
$text = "<td><b>" . encode_entities($nick) . "</b> " . encode_entities($text) . "</td>\n";
print FILE $text;
@ -124,29 +132,30 @@ sub export_quotegrabs {
print FILE "</tbody>\n</table>\n" if $had_table;
print FILE "<script type='text/javascript'>\n";
$table_id--;
print FILE '$(document).ready(function() {' . "\n";
while ($table_id > 0) {
print FILE '$("#table' . $table_id . '").tablesorter();' . "\n";
print FILE '$("#table' . $table_id . '").tableFilter();' . "\n";
$table_id--;
}
print FILE "});\n";
print FILE "</script>\n";
print FILE "</body>\n</html>\n";
close(FILE);
close FILE;
return "$i quotegrabs exported.";
}
sub cmd_grab_quotegrab {
my ($self, $context) = @_;
if (not defined $context->{from}) {
$self->{pbot}->{logger}->log("Command missing ~from parameter!\n");
return "";
}
if (not defined $context->{arguments} or not length $context->{arguments}) {
if (not length $context->{arguments}) {
return
"Usage: grab <nick> [history [channel]] [+ <nick> [history [channel]] ...] -- where [history] is an optional regex argument; e.g., to grab a message containing 'pizza', use `grab nick pizza`; you can chain grabs with + to grab multiple messages";
}
@ -160,8 +169,12 @@ sub cmd_grab_quotegrab {
foreach my $grab (@grabs) {
($grab_nick, $grab_history, $channel) = $self->{pbot}->{interpreter}->split_line($grab, strip_quotes => 1);
$grab_history = $context->{nick} eq $grab_nick ? 2 : 1 if not defined $grab_history; # skip grab command if grabbing self without arguments
$channel = $context->{from} if not defined $channel;
if (not defined $grab_history) {
# skip grab command if grabbing self without arguments
$grab_history = lc $context->{nick} eq $grab_nick ? 2 : 1;
}
$channel //= $context->{from};
if (not $channel =~ m/^#/) {
return "'$channel' is not a valid channel; usage: grab <nick> [[history] channel] (you must specify a history parameter before the channel parameter)";
@ -169,18 +182,23 @@ sub cmd_grab_quotegrab {
my ($account, $found_nick) = $self->{pbot}->{messagehistory}->{database}->find_message_account_by_nick($grab_nick);
if (not defined $account) { return "I don't know anybody named $grab_nick"; }
if (not defined $account) {
return "I don't know anybody named $grab_nick";
}
$found_nick =~ s/!.*$//;
$grab_nick = $found_nick; # convert nick to proper casing
$grab_nick = $found_nick; # convert nick to proper casing
my $message;
if ($grab_history =~ /^\d+$/) {
# integral history
my $max_messages = $self->{pbot}->{messagehistory}->{database}->get_max_messages($account, $channel);
if ($grab_history < 1 || $grab_history > $max_messages) { return "Please choose a history between 1 and $max_messages"; }
if ($grab_history < 1 || $grab_history > $max_messages) {
return "Please choose a history between 1 and $max_messages";
}
$grab_history--;
@ -189,20 +207,29 @@ sub cmd_grab_quotegrab {
# regex history
$message = $self->{pbot}->{messagehistory}->{database}->recall_message_by_text($account, $channel, $grab_history, 'grab');
if (not defined $message) { return "No such message for nick $grab_nick in channel $channel containing text '$grab_history'"; }
if (not defined $message) {
return "No such message for nick $grab_nick in channel $channel containing text '$grab_history'";
}
}
$self->{pbot}->{logger}->log("$context->{nick} ($context->{from}) grabbed <$grab_nick/$channel> $message->{msg}\n");
if (not defined $grab_nicks) { $grab_nicks = $grab_nick; }
else { $grab_nicks .= "+$grab_nick"; }
if (not defined $grab_nicks) {
$grab_nicks = $grab_nick;
} else {
$grab_nicks .= "+$grab_nick";
}
my $text = $message->{msg};
if (not defined $grab_text) { $grab_text = $text; }
else {
if ($text =~ s/^\/me\s+//) { $grab_text .= " * $grab_nick $text"; }
else { $grab_text .= " <$grab_nick> $text"; }
if (not defined $grab_text) {
$grab_text = $text;
} else {
if ($text =~ s/^\/me\s+//) {
$grab_text .= " * $grab_nick $text";
} else {
$grab_text .= " <$grab_nick> $text";
}
}
}
@ -216,9 +243,11 @@ sub cmd_grab_quotegrab {
$quotegrab->{id} = $self->{database}->add_quotegrab($quotegrab);
if (not defined $quotegrab->{id}) { return "Failed to grab quote."; }
if (not defined $quotegrab->{id}) {
return "Failed to grab quote.";
}
$self->export_quotegrabs();
$self->export_quotegrabs;
my $text = $quotegrab->{text};
($grab_nick) = split /\+/, $grab_nicks, 2;
@ -239,21 +268,28 @@ sub cmd_delete_quotegrab {
my $quotegrab = $self->{database}->get_quotegrab($context->{arguments});
if (not defined $quotegrab) { return "/msg $context->{nick} No quotegrab matching id $context->{arguments} found."; }
if (not defined $quotegrab) {
return "/msg $context->{nick} No quotegrab matching id $context->{arguments} found.";
}
if (not $self->{pbot}->{users}->loggedin_admin($context->{from}, $context->{hostmask}) and $quotegrab->{grabbed_by} ne $context->{hostmask}) {
if (not $self->{pbot}->{users}->loggedin_admin($context->{from}, $context->{hostmask})
and $quotegrab->{grabbed_by} ne $context->{hostmask})
{
return "You are not the grabber of this quote.";
}
$self->{database}->delete_quotegrab($context->{arguments});
$self->export_quotegrabs();
$self->export_quotegrabs;
my $text = $quotegrab->{text};
my ($first_nick) = split /\+/, $quotegrab->{nick}, 2;
if ($text =~ s/^\/me\s+//) { return "Deleted $context->{arguments}: * $first_nick $text"; }
else { return "Deleted $context->{arguments}: <$first_nick> $text"; }
if ($text =~ s/^\/me\s+//) {
return "Deleted $context->{arguments}: * $first_nick $text";
} else {
return "Deleted $context->{arguments}: <$first_nick> $text";
}
}
sub cmd_show_quotegrab {
@ -261,63 +297,72 @@ sub cmd_show_quotegrab {
my $quotegrab = $self->{database}->get_quotegrab($context->{arguments});
if (not defined $quotegrab) { return "/msg $context->{nick} No quotegrab matching id $context->{arguments} found."; }
if (not defined $quotegrab) {
return "/msg $context->{nick} No quotegrab matching id $context->{arguments} found.";
}
my $timestamp = $quotegrab->{timestamp};
my $ago = ago(gettimeofday - $timestamp);
my $text = $quotegrab->{text};
my ($first_nick) = split /\+/, $quotegrab->{nick}, 2;
my $result = "$context->{arguments}: grabbed by $quotegrab->{grabbed_by} in $quotegrab->{channel} on " . localtime($timestamp) . " [$ago]";
if ($text =~ s/^\/me\s+//) {
return "$context->{arguments}: grabbed by $quotegrab->{grabbed_by} in $quotegrab->{channel} on " . localtime($timestamp) . " [$ago] * $first_nick $text";
return "$result * $first_nick $text";
} else {
return "$context->{arguments}: grabbed by $quotegrab->{grabbed_by} in $quotegrab->{channel} on " . localtime($timestamp) . " [$ago] <$first_nick> $text";
return "$result <$first_nick> $text";
}
}
sub cmd_show_random_quotegrab {
my ($self, $context) = @_;
my @quotes = ();
my ($nick_search, $channel_search, $text_search);
if (not defined $context->{from}) {
$self->{pbot}->{logger}->log("Command missing ~from parameter!\n");
return "";
}
my $usage = 'Usage: rq [nick [channel [text]]] [-c <channel>] [-t <text>]';
if (defined $context->{arguments}) {
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
my ($nick_search, $channel_search, $text_search);
my @opt_args = $self->{pbot}->{interpreter}->split_line($context->{arguments}, preserve_escapes => 1, strip_quotes => 1);
GetOptionsFromArray(
\@opt_args,
'channel|c=s' => \$channel_search,
'text|t=s' => \$text_search
if (length $context->{arguments}) {
my %opts = (
channel => \$channel_search,
text => \$text_search,
);
return "$getopt_error -- $usage" if defined $getopt_error;
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$context->{arguments},
\%opts,
['bundling'],
'channel|c=s',
'text|t=s',
);
$nick_search = shift @opt_args;
$channel_search = shift @opt_args if not defined $channel_search;
$text_search = shift @opt_args if not defined $text_search;
return "$opt_error -- $usage" if defined $opt_error;
if ($nick_search =~ m/^#/) {
$nick_search = shift @$opt_args;
if (not defined $channel_search) {
$channel_search = shift @$opt_args;
}
if (not defined $text_search) {
$text_search = shift @$opt_args;
}
if (defined $nick_search and $nick_search =~ m/^#/) {
my $tmp = $channel_search;
$channel_search = $nick_search;
$nick_search = $tmp;
}
if (not defined $channel_search) { $channel_search = $context->{from}; }
if (not defined $channel_search) {
$channel_search = $context->{from};
}
}
if (defined $channel_search and $channel_search !~ /^#/) {
if ($channel_search eq $context->{nick}) { $channel_search = undef; }
if ($channel_search eq $context->{nick}) {
$channel_search = undef;
}
elsif ($channel_search =~ m/^\./) {
# do nothing
} else {
@ -330,11 +375,17 @@ sub cmd_show_random_quotegrab {
if (not defined $quotegrab) {
my $result = "No quotes grabbed ";
if (defined $nick_search) { $result .= "for nick $nick_search "; }
if (defined $nick_search) {
$result .= "for nick $nick_search ";
}
if (defined $channel_search) { $result .= "in channel $channel_search "; }
if (defined $channel_search) {
$result .= "in channel $channel_search ";
}
if (defined $text_search) { $result .= "matching text '$text_search' "; }
if (defined $text_search) {
$result .= "matching text '$text_search' ";
}
return $result . "yet ($usage).";
}
@ -342,10 +393,18 @@ sub cmd_show_random_quotegrab {
my $text = $quotegrab->{text};
my ($first_nick) = split /\+/, $quotegrab->{nick}, 2;
my $channel = '';
$channel_search //= '';
if ($channel_search eq '.*' or $quotegrab->{channel} ne $context->{from}) {
$channel = "[$quotegrab->{channel}] ";
}
if ($text =~ s/^\/me\s+//) {
return "$quotegrab->{id}: " . (($channel_search eq '.*' or $quotegrab->{channel} ne $context->{from}) ? "[$quotegrab->{channel}] " : "") . "* $first_nick $text";
return "$quotegrab->{id}: $channel" . "* $first_nick $text";
} else {
return "$quotegrab->{id}: " . (($channel_search eq '.*' or $quotegrab->{channel} ne $context->{from}) ? "[$quotegrab->{channel}] " : "") . "<$first_nick> $text";
return "$quotegrab->{id}: $channel" . "<$first_nick> $text";
}
}

View File

@ -12,9 +12,8 @@ use parent 'PBot::Plugin::Base';
use PBot::Imports;
use DBI;
use Time::Duration qw/ago concise duration/;
use Time::HiRes qw/time/;
use Getopt::Long qw/GetOptionsFromArray/;
use Time::Duration qw(ago concise duration);
use Time::HiRes qw(time);
sub initialize {
my ($self, %conf) = @_;
@ -62,26 +61,28 @@ sub cmd_remindme {
my ($channel, $repeats, $text, $time, $list_reminders, $delete_id);
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
my @opt_args = $self->{pbot}->{interpreter}->split_line($context->{arguments}, strip_quotes => 1);
Getopt::Long::Configure("bundling");
GetOptionsFromArray(
\@opt_args,
'r=i' => \$repeats,
't=s' => \$time,
'c=s' => \$channel,
'm=s' => \$text,
'l:s' => \$list_reminders,
'd=i' => \$delete_id
my %opts = (
c => \$channel,
r => \$repeats,
m => \$text,
t => \$time,
l => \$list_reminders,
d => \$delete_id,
);
return "$getopt_error -- $usage" if defined $getopt_error;
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$context->{arguments},
\%opts,
['bundling'],
'r=i',
't=s',
'c=s',
'm=s',
'l:s',
'd=i',
);
return "$opt_error -- $usage" if defined $opt_error;
# option -l was provided; list reminders
if (defined $list_reminders) {
@ -187,9 +188,9 @@ sub cmd_remindme {
$text //= '';
# add to the reminder text anything left in the arguments
if (@opt_args) {
if (@$opt_args) {
$text .= ' ' if length $text;
$text .= join ' ', @opt_args;
$text .= "@$opt_args";
}
return "Please use -t to specify a time for this reminder." if not $time;

View File

@ -12,7 +12,6 @@ use PBot::Imports;
use PBot::Core::Utils::LWPUserAgentCached;
use XML::LibXML;
use Getopt::Long qw(GetOptionsFromArray);
sub initialize {
my ($self, %conf) = @_;
@ -26,28 +25,27 @@ sub unload {
sub cmd_weather {
my ($self, $context) = @_;
my $usage = "Usage: weather (<location> | -u <user account>)";
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
my $arguments = $context->{arguments};
Getopt::Long::Configure("bundling");
my %opts;
my ($user_override, $show_usage);
my @opt_args = $self->{pbot}->{interpreter}->split_line($arguments, strip_quotes => 1);
GetOptionsFromArray(
\@opt_args,
'u=s' => \$user_override,
'h' => \$show_usage
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$arguments,
\%opts,
['bundling'],
'u=s',
'h',
);
return $usage if $show_usage;
return "/say $getopt_error -- $usage" if defined $getopt_error;
$arguments = "@opt_args";
return $usage if $opts{h};
return "/say $opt_error -- $usage" if defined $opt_error;
$arguments = "@$opt_args";
my $user_override = $opts{u};
if (defined $user_override) {
my $userdata = $self->{pbot}->{users}->{storage}->get_data($user_override);

View File

@ -13,7 +13,6 @@ use PBot::Core::Utils::LWPUserAgentCached;
use JSON;
use URI::Escape qw/uri_escape_utf8/;
use Getopt::Long qw(GetOptionsFromArray);
sub initialize {
my ($self, %conf) = @_;
@ -31,50 +30,45 @@ sub cmd_wttr {
my $arguments = $context->{arguments};
my @wttr_options = (
"default",
"all",
"conditions",
"forecast",
"feelslike",
"uvindex",
"visibility",
"dewpoint",
"heatindex",
"cloudcover",
"wind",
"sun",
"sunhours",
"moon",
"chances",
"snowfall",
"location",
"qlocation",
"time",
"population",
'default',
'all',
'conditions',
'forecast',
'feelslike',
'uvindex',
'visibility',
'dewpoint',
'heatindex',
'cloudcover',
'wind',
'sun',
'sunhours',
'moon',
'chances',
'snowfall',
'location',
'qlocation',
'time',
'population',
);
my $usage = "Usage: wttr (<location> | -u <user account>) [" . join(' ', map { "-$_" } @wttr_options) . "]; to have me remember your location, use `my location <location>`.";
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
Getopt::Long::Configure("bundling_override", "ignorecase_always");
my %options;
my @opt_args = $self->{pbot}->{interpreter}->split_line($arguments, strip_quotes => 1);
GetOptionsFromArray(
\@opt_args,
my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt(
$arguments,
\%options,
['bundling_override', 'ignorecase_always'],
'u=s',
'h',
@wttr_options
@wttr_options,
);
return "/say $getopt_error -- $usage" if defined $getopt_error;
return $usage if exists $options{h};
$arguments = "@opt_args";
return "/say $opt_error -- $usage" if defined $opt_error;
return $usage if exists $options{h};
$arguments = "@$opt_args";
if (defined $options{u}) {
my $username = delete $options{u};

View File

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