/
CommandHandler.pm
89 lines (73 loc) · 2.13 KB
/
CommandHandler.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use v6;
enum RequiredIntro is export <
NONE
NICK
PREFIX
EITHER
BOTH
>;
role Command[Str $command-name, Bool $abbreviate = True] {
has $.command-name = $command-name;
has $.abbreviate = $abbreviate;
}
multi trait_mod:<is>(Routine:D $m, :$cmd!) is export {
if $cmd !~~ Bool {
my $opts = $cmd.hash;
$m does Command[
( $opts<name> // $m.name ),
( $opts<abbreviate> !eqv False ),
];
}
else {
$m does Command[$m.name];
}
}
sub abbrev($name) { [\~] $name.comb }
role Net::IRC::CommandHandler {
has Str $.prefix is rw = '!';
has RequiredIntro $.required-intro is rw = EITHER;
has @!cmds = self.^methods>>.candidates.flat.grep(Command);
has %cmd-names = {}.push( @!cmds.map({ $^n.command-name => $^n }) );
has %short-names = {}.push(
@!cmds.grep(*.abbreviate).map({ abbrev($^n.command-name) X=> $^n }).flat
);
method recognized($handler: $ev) {
return $ev.cache<CommandHandler>{$handler.prefix} //= sub {
$ev.what ~~ token {
# Intro
^
[ \s* $<nick>=("$ev.state()<nick>") [ <[:,]> | \s ] ]? \s*
[ $<prefix>=("$handler.prefix()") \s* ]?
# Actual command (and optional params)
$<command>=(\w+) [ <?> | \s+ $<params>=(.*) ] #++# <- Fool sublime's perl parser
$
} or return False;
# Let private chat act as specifying the bot's nick
my $nick = $<nick> || $ev.where eq $ev.state<nick>;
given $.required-intro {
when NICK { return False unless $nick }
when PREFIX { return False unless $<prefix> }
when EITHER { return False unless $<prefix> || $nick }
when BOTH { return False unless $<prefix> && $nick }
}
return $/;
}();
}
multi method said ($ev where { $/ := $.recognized($ev) }) {
self!dispatch($<command>, $ev, $/);
}
method !dispatch($name, *@args) {
with %cmd-names{$name} -> $candidates {
# Handle all exact matches.
$candidates>>.(self, |@args)
}
orwith %short-names{$name} -> $candidates {
# Only handle non-ambiguous abbreviations, though.
$candidates.(self, |@args) if $candidates.elems == 1
}
}
method usage($ev, $usage) {
$ev.msg("Usage: $usage");
}
}
# vim: ft=perl6 tabstop=4 shiftwidth=4