factoids: improved handling of factoids belonging to other channels; significantly

This commit is contained in:
Pragmatic Software 2011-01-29 01:21:17 +00:00
parent 65920bbe33
commit 9336428ea2
3 changed files with 83 additions and 62 deletions

View File

@ -168,57 +168,37 @@ sub save {
} }
sub find_index { sub find_index {
my ($self, $primary_index_key, $secondary_index_key) = @_; my $self = shift;
my $result; my ($primary_index_key, $secondary_index_key) = map {lc} @_;
if(not $secondary_index_key) { return undef if not defined $primary_index_key;
$result = eval {
foreach my $index (keys %{ $self->hash }) {
if($primary_index_key =~ m/^\Q$index\E$/i) {
return $index;
}
}
return undef; return $primary_index_key if not $secondary_index_key;
};
if($@) { return undef if not exists $self->hash->{$primary_index_key};
Carp::carp ("find_index: bad regex: $@\n");
return undef;
}
} else {
$result = eval {
foreach my $index (keys %{ $self->hash->{$primary_index_key} }) {
if($secondary_index_key =~ m/^\Q$index\E$/i) {
return $index;
}
}
return undef; foreach my $index (keys %{ $self->hash->{$primary_index_key} }) {
}; return $index if $secondary_index_key eq lc $index;
if($@) {
Carp::carp ("find_index: bad regex: $@\n");
return undef;
}
} }
return $result; return undef;
} }
sub levenshtein_matches { sub levenshtein_matches {
my ($self, $primary_index_key, $secondary_index_key) = @_; my ($self, $primary_index_key, $secondary_index_key, $distance) = @_;
my $comma = ''; my $comma = '';
my $result = ""; my $result = "";
$distance = 0.60 if not defined $distance;
$primary_index_key = '.*' if not defined $primary_index_key; $primary_index_key = '.*' if not defined $primary_index_key;
if(not $secondary_index_key) { if(not $secondary_index_key) {
foreach my $index (sort keys %{ $self->hash }) { foreach my $index (sort keys %{ $self->hash }) {
my $distance = fastdistance($primary_index_key, $index); my $distance_result = fastdistance($primary_index_key, $index);
my $length = (length($primary_index_key) > length($index)) ? length $primary_index_key : length $index; my $length = (length($primary_index_key) > length($index)) ? length $primary_index_key : length $index;
if($distance / $length < 0.50) { if($distance_result / $length < $distance) {
$result .= $comma . $index; $result .= $comma . $index;
$comma = ", "; $comma = ", ";
} }
@ -230,13 +210,23 @@ sub levenshtein_matches {
return 'none'; return 'none';
} }
foreach my $index (sort keys %{ $self->hash->{$primary} }) { my $last_header = "";
my $distance = fastdistance($secondary_index_key, $index); my $header = "";
my $length = (length($secondary_index_key) > length($index)) ? length $secondary_index_key : length $index;
if($distance / $length < 0.60) { foreach my $index1 (sort keys %{ $self->hash }) {
$result .= $comma . $index; $header = "[$index1] ";
$comma = ", "; $header = "[global channel] " if $header eq "[.*] ";
foreach my $index2 (sort keys %{ $self->hash->{$index1} }) {
my $distance_result = fastdistance($secondary_index_key, $index2);
my $length = (length($secondary_index_key) > length($index2)) ? length $secondary_index_key : length $index2;
if($distance_result / $length < $distance) {
$header = "" if $last_header eq $header;
$last_header = $header;
$result .= $comma . $header . $index2;
$comma = ", ";
}
} }
} }
} }

View File

@ -37,10 +37,7 @@ sub initialize {
my $export_path = delete $conf{export_path}; my $export_path = delete $conf{export_path};
my $export_site = delete $conf{export_site}; my $export_site = delete $conf{export_site};
my $pbot = delete $conf{pbot}; my $pbot = delete $conf{pbot} || Carp::croak("Missing pbot reference to Factoids");
if(not defined $pbot) {
Carp::croak("Missing pbot reference to Factoids");
}
$self->{factoids} = PBot::DualIndexHashObject->new(name => 'Factoids', filename => $filename); $self->{factoids} = PBot::DualIndexHashObject->new(name => 'Factoids', filename => $filename);
$self->{export_path} = $export_path; $self->{export_path} = $export_path;
@ -199,23 +196,54 @@ sub find_factoid {
sub interpreter { sub interpreter {
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $count, $keyword, $arguments, $tonick) = @_; my ($from, $nick, $user, $host, $count, $keyword, $arguments, $tonick, $ref_from) = @_;
my ($result, $channel); my ($result, $channel);
my $pbot = $self->{pbot}; my $pbot = $self->{pbot};
$from = lc $from;
return undef if not length $keyword; return undef if not length $keyword;
$from = lc $from;
$ref_from = "" if not defined $ref_from;
my $original_keyword = $keyword; my $original_keyword = $keyword;
($channel, $keyword) = $self->find_factoid($from, $keyword, $arguments); ($channel, $keyword) = $self->find_factoid($from, $keyword, $arguments);
if(not defined $keyword) { if(not defined $keyword) {
my $matches = $self->factoids->levenshtein_matches('.*', lc $original_keyword); # first check all channels for this keyword
my $chans = "";
my $comma = "";
my $found = 0;
my ($fwd_chan, $fwd_trig);
return undef if $matches eq 'none'; foreach my $chan (keys %{ $self->factoids->hash }) {
foreach my $trig (keys %{ $self->factoids->hash->{$chan} }) {
if(lc $trig eq lc $original_keyword) {
$chans .= $comma . $chan;
$comma = ", ";
$found++;
$fwd_chan = $chan;
$fwd_trig = $trig;
last;
}
}
}
return "No such factoid '$original_keyword'; did you mean $matches?"; if($found > 1) {
return $ref_from . "Ambiguous keyword '$original_keyword' exists in multiple locations (choose one): $chans";
}
elsif($found == 1) {
$pbot->logger->log("Found '$original_keyword' as '$fwd_trig' in [$fwd_chan]\n");
return $ref_from . $pbot->factoids->interpreter($fwd_chan, $nick, $user, $host, $count, $fwd_trig, $arguments, undef, "[$fwd_chan] ");
} else {
# if keyword hasn't been found, display similiar matches for all channels
my $matches = $self->factoids->levenshtein_matches('.*', lc $original_keyword);
# don't say anything if nothing similiar was found
return undef if $matches eq 'none';
return $ref_from . "No such factoid '$original_keyword'; did you mean $matches?";
}
} }
my $type = $self->factoids->hash->{$channel}->{$keyword}->{type}; my $type = $self->factoids->hash->{$channel}->{$keyword}->{type};
@ -235,7 +263,7 @@ sub interpreter {
$self->factoids->hash->{$channel}->{$keyword}->{ref_user} = $nick; $self->factoids->hash->{$channel}->{$keyword}->{ref_user} = $nick;
$self->factoids->hash->{$channel}->{$keyword}->{last_referenced_on} = gettimeofday; $self->factoids->hash->{$channel}->{$keyword}->{last_referenced_on} = gettimeofday;
return $pbot->interpreter->interpret($from, $nick, $user, $host, $count, $command); return $ref_from . $pbot->interpreter->interpret($from, $nick, $user, $host, $count, $command, $ref_from);
} }
my $last_ref_in = 0; my $last_ref_in = 0;
@ -248,13 +276,13 @@ sub interpreter {
} }
if(($last_ref_in == 1) and (gettimeofday - $self->factoids->hash->{$channel}->{$keyword}->{last_referenced_on} < $self->factoids->hash->{$channel}->{$keyword}->{rate_limit})) { if(($last_ref_in == 1) and (gettimeofday - $self->factoids->hash->{$channel}->{$keyword}->{last_referenced_on} < $self->factoids->hash->{$channel}->{$keyword}->{rate_limit})) {
return "/msg $nick '$keyword' is rate-limited; try again in " . ($self->factoids->hash->{$channel}->{$keyword}->{rate_limit} - int(gettimeofday - $self->factoids->hash->{$channel}->{$keyword}->{last_referenced_on})) . " seconds."; return "/msg $nick $ref_from'$keyword' is rate-limited; try again in " . ($self->factoids->hash->{$channel}->{$keyword}->{rate_limit} - int(gettimeofday - $self->factoids->hash->{$channel}->{$keyword}->{last_referenced_on})) . " seconds.";
} }
} }
if($self->factoids->hash->{$channel}->{$keyword}->{enabled} == 0) { if($self->factoids->hash->{$channel}->{$keyword}->{enabled} == 0) {
$self->{pbot}->logger->log("$keyword disabled.\n"); $self->{pbot}->logger->log("$keyword disabled.\n");
return "/msg $nick $keyword is currently disabled."; return "/msg $nick $ref_from$keyword is currently disabled.";
} }
elsif($self->factoids->hash->{$channel}->{$keyword}->{type} eq 'module') { elsif($self->factoids->hash->{$channel}->{$keyword}->{type} eq 'module') {
$self->{pbot}->logger->log("Found module\n"); $self->{pbot}->logger->log("Found module\n");
@ -264,7 +292,7 @@ sub interpreter {
$self->factoids->hash->{$channel}->{$keyword}->{last_referenced_on} = gettimeofday; $self->factoids->hash->{$channel}->{$keyword}->{last_referenced_on} = gettimeofday;
$self->factoids->hash->{$channel}->{$keyword}->{last_referenced_in} = $from || "stdin"; $self->factoids->hash->{$channel}->{$keyword}->{last_referenced_in} = $from || "stdin";
return $self->{factoidmodulelauncher}->execute_module($from, $tonick, $nick, $user, $host, $keyword, $arguments); return $ref_from . $self->{factoidmodulelauncher}->execute_module($from, $tonick, $nick, $user, $host, $keyword, $arguments);
} }
elsif($self->factoids->hash->{$channel}->{$keyword}->{type} eq 'text') { elsif($self->factoids->hash->{$channel}->{$keyword}->{type} eq 'text') {
$self->{pbot}->logger->log("Found factoid\n"); $self->{pbot}->logger->log("Found factoid\n");
@ -353,9 +381,9 @@ sub interpreter {
if($result =~ s/^\/say\s+//i || $result =~ /^\/me\s+/i if($result =~ s/^\/say\s+//i || $result =~ /^\/me\s+/i
|| $result =~ /^\/msg\s+/i) { || $result =~ /^\/msg\s+/i) {
return $result; return $ref_from . $result;
} else { } else {
return "$keyword is $result"; return $ref_from . "$keyword is $result";
} }
} elsif($self->factoids->hash->{$channel}->{$keyword}->{type} eq 'regex') { } elsif($self->factoids->hash->{$channel}->{$keyword}->{type} eq 'regex') {
$result = eval { $result = eval {
@ -382,21 +410,24 @@ sub interpreter {
$cmd = $self->factoids->hash->{$channel}->{$keyword}->{action}; $cmd = $self->factoids->hash->{$channel}->{$keyword}->{action};
} }
$result = $pbot->interpreter->interpret($from, $nick, $user, $host, $count, $cmd); $result = $pbot->interpreter->interpret($from, $nick, $user, $host, $count, $cmd, $ref_from);
return $result; return $ref_from . $result;
}; };
if($@) { if($@) {
$self->{pbot}->logger->log("Regex fail: $@\n"); $self->{pbot}->logger->log("Regex fail: $@\n");
return "/msg $nick Fail."; return "/msg $nick $ref_from" . "Fail.";
} }
return $result; return $ref_from . $result;
} else { } else {
$self->{pbot}->logger->log("($from): $nick!$user\@$host): Unknown command type for '$keyword'\n"); $self->{pbot}->logger->log("($from): $nick!$user\@$host): Unknown command type for '$keyword'\n");
return "/me blinks."; return "/me blinks." . " $ref_from";
} }
return "/me wrinkles her nose.";
# should never be reached; if it has, something has gone horribly wrong.
# (advanced notification of corruption or a waste of space?)
return "/me wrinkles her nose." . " $ref_from";
} }
sub export_path { sub export_path {

View File

@ -13,7 +13,7 @@ use warnings;
# These are set automatically by the build/commit script # These are set automatically by the build/commit script
use constant { use constant {
BUILD_NAME => "PBot", BUILD_NAME => "PBot",
BUILD_REVISION => 275, BUILD_REVISION => 276,
BUILD_DATE => "2011-01-28", BUILD_DATE => "2011-01-28",
}; };