diff --git a/lib/PBot/Core/Commands/Factoids.pm b/lib/PBot/Core/Commands/Factoids.pm index 45769513..dd29ee57 100644 --- a/lib/PBot/Core/Commands/Factoids.pm +++ b/lib/PBot/Core/Commands/Factoids.pm @@ -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] ; -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); diff --git a/lib/PBot/Core/Commands/MessageHistory.pm b/lib/PBot/Core/Commands/MessageHistory.pm index 7c748d0f..d8cee27f 100644 --- a/lib/PBot/Core/Commands/MessageHistory.pm +++ b/lib/PBot/Core/Commands/MessageHistory.pm @@ -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) { diff --git a/lib/PBot/Core/Commands/NickList.pm b/lib/PBot/Core/Commands/NickList.pm index 9bf0ab19..b219b28e 100644 --- a/lib/PBot/Core/Commands/NickList.pm +++ b/lib/PBot/Core/Commands/NickList.pm @@ -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 ( | ) [-sort ] [-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 = ', '; } diff --git a/lib/PBot/Core/Commands/ProcessManager.pm b/lib/PBot/Core/Commands/ProcessManager.pm index 983bd995..d23b2b85 100644 --- a/lib/PBot/Core/Commands/ProcessManager.pm +++ b/lib/PBot/Core/Commands/ProcessManager.pm @@ -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 ] [-s ] [pids...]; -a kill all processes; -t kill processes running longer than ; -s send 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; } diff --git a/lib/PBot/Core/Interpreter.pm b/lib/PBot/Core/Interpreter.pm index 7b8426fb..03d39edb 100644 --- a/lib/PBot/Core/Interpreter.pm +++ b/lib/PBot/Core/Interpreter.pm @@ -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; diff --git a/lib/PBot/Plugin/Date.pm b/lib/PBot/Plugin/Date.pm index 2a6bbe4d..f6b3dbf6 100644 --- a/lib/PBot/Plugin/Date.pm +++ b/lib/PBot/Plugin/Date.pm @@ -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 ] [timezone]"; + my $usage = "Usage: date [-u ] [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 diff --git a/lib/PBot/Plugin/Plang.pm b/lib/PBot/Plugin/Plang.pm index 6514e550..0bcb929c 100644 --- a/lib/PBot/Plugin/Plang.pm +++ b/lib/PBot/Plugin/Plang.pm @@ -11,8 +11,6 @@ use parent 'PBot::Plugin::Base'; use PBot::Imports; -use Getopt::Long qw(GetOptionsFromArray); - sub initialize { my ($self, %conf) = @_; diff --git a/lib/PBot/Plugin/Quotegrabs.pm b/lib/PBot/Plugin/Quotegrabs.pm index 78769a2a..149d7dfd 100644 --- a/lib/PBot/Plugin/Quotegrabs.pm +++ b/lib/PBot/Plugin/Quotegrabs.pm @@ -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 "\n\n"; print FILE '' . "\n"; print FILE '' . "\n"; print FILE '' . "\n"; print FILE "\nGenerated at $time

$botnick\'s Quotegrabs

\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 "" . encode_entities($quotegrab->{channel}) . "
\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 "\n\n" if $had_table; @@ -99,8 +101,11 @@ sub export_quotegrabs { $last_channel = $quotegrab->{channel}; $i++; - if ($i % 2) { print FILE "\n"; } - else { print FILE "\n"; } + if ($i % 2) { + print FILE "\n"; + } else { + print FILE "\n"; + } print FILE "" . ($quotegrab->{id}) . ""; @@ -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 = "" . encode_entities($nick) . " " . encode_entities($text) . "\n"; print FILE $text; @@ -124,29 +132,30 @@ sub export_quotegrabs { print FILE "\n\n" if $had_table; print FILE "\n"; print FILE "\n\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 [history [channel]] [+ [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 [[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 ] [-t ]'; - 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"; } } diff --git a/lib/PBot/Plugin/RemindMe.pm b/lib/PBot/Plugin/RemindMe.pm index 2f718b94..2c492131 100644 --- a/lib/PBot/Plugin/RemindMe.pm +++ b/lib/PBot/Plugin/RemindMe.pm @@ -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; diff --git a/lib/PBot/Plugin/Weather.pm b/lib/PBot/Plugin/Weather.pm index 59237475..0a4bf795 100644 --- a/lib/PBot/Plugin/Weather.pm +++ b/lib/PBot/Plugin/Weather.pm @@ -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 ( | -u )"; - 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); diff --git a/lib/PBot/Plugin/Wttr.pm b/lib/PBot/Plugin/Wttr.pm index cd6fc60e..2eca99f8 100644 --- a/lib/PBot/Plugin/Wttr.pm +++ b/lib/PBot/Plugin/Wttr.pm @@ -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 ( | -u ) [" . join(' ', map { "-$_" } @wttr_options) . "]; to have me remember your location, use `my 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}; diff --git a/lib/PBot/VERSION.pm b/lib/PBot/VERSION.pm index ebe8069f..230a85f1 100644 --- a/lib/PBot/VERSION.pm +++ b/lib/PBot/VERSION.pm @@ -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 {}