File Coverage

blib/lib/IRC/Toolkit/Numerics.pm
Criterion Covered Total %
statement 50 50 100.0
branch 16 18 88.8
condition 5 9 55.5
subroutine 13 13 100.0
pod 8 8 100.0
total 92 98 93.8


line stmt bran cond sub pod time code
1             package IRC::Toolkit::Numerics;
2             $IRC::Toolkit::Numerics::VERSION = '0.092001';
3 1     1   17457 use strictures 2;
  1         1535  
  1         50  
4 1     1   186 use Carp 'confess';
  1         2  
  1         72  
5 1     1   569 use List::Objects::WithUtils 'hash';
  1         742  
  1         6  
6              
7 1     1   11525 use Module::Runtime 'use_package_optimistically';
  1         2  
  1         7  
8              
9 1     1   593 use parent 'Exporter::Tiny';
  1         263  
  1         5  
10             our @EXPORT = qw/
11             name_from_numeric
12             numeric_from_name
13             /;
14              
15             our %Numeric = (
16             '001' => 'RPL_WELCOME',
17             '002' => 'RPL_YOURHOST', # RFC2812
18             '003' => 'RPL_CREATED', # RFC2812
19             '004' => 'RPL_MYINFO', # RFC2812
20             '005' => 'RPL_ISUPPORT', # draft-brocklesby-irc-isupport-03
21             '008' => 'RPL_SNOMASK', # ircu
22             '009' => 'RPL_STATMEMTOT', # ircu
23             '010' => 'RPL_REDIR', # ratbox
24             '014' => 'RPL_YOURCOOKIE', # IRCnet
25             '015' => 'RPL_MAP', # ircu
26             '016' => 'RPL_MAPMORE', # ircu
27             '017' => 'RPL_MAPEND', # ircu
28             '020' => 'RPL_CONNECTING', # IRCnet
29             '042' => 'RPL_YOURID', # IRCnet
30             '043' => 'RPL_SAVENICK', # IRCnet
31             '050' => 'RPL_ATTEMPTINGJUNC', # aircd
32             '051' => 'RPL_ATTEMPTINGREROUTE', # aircd
33              
34             '200' => 'RPL_TRACELINK', # RFC1459
35             '201' => 'RPL_TRACECONNECTING', # RFC1459
36             '202' => 'RPL_TRACEHANDSHAKE', # RFC1459
37             '203' => 'RPL_TRACEUNKNOWN', # RFC1459
38             '204' => 'RPL_TRACEOPERATOR', # RFC1459
39             '205' => 'RPL_TRACEUSER', # RFC1459
40             '206' => 'RPL_TRACESERVER', # RFC1459
41             '207' => 'RPL_TRACECAPTURED', # hybrid (RFC2812 TRACESERVICE)
42             '208' => 'RPL_TRACENEWTYPE', # RFC1459
43             '209' => 'RPL_TRACECLASS', # RFC2812
44             '210' => 'RPL_STATS', # aircd (single stats reply)
45             '211' => 'RPL_STATSLINKINFO', # RFC1459
46             '212' => 'RPL_STATSCOMMANDS', # RFC1459
47             '213' => 'RPL_STATSCLINE', # RFC1459
48             '214' => 'RPL_STATSNLINE', # RFC1459
49             '215' => 'RPL_STATSILINE', # RFC1459
50             '216' => 'RPL_STATSKLINE', # RFC1459
51             '217' => 'RPL_STATSQLINE', # RFC1459
52             '218' => 'RPL_STATSYLINE', # RFC1459
53             '219' => 'RPL_ENDOFSTATS', # RFC1459
54              
55             '220' => 'RPL_STATSPLINE', # hybrid
56             '221' => 'RPL_UMODEIS', # RFC1459
57             '222' => 'RPL_SQLINE_NICK', # DALnet
58             '223' => 'RPL_STATSGLINE', # Unreal
59             '224' => 'RPL_STATSFLINE', # hybrid
60             '225' => 'RPL_STATSDLINE', # hybrid
61             '226' => 'RPL_STATSALINE', # hybrid
62             '227' => 'RPL_STATSVLINE', # Unreal
63             '228' => 'RPL_STATSCCOUNT', # hybrid
64              
65             '231' => 'RPL_SERVICEINFO', # RFC1459
66             '233' => 'RPL_SERVICE', # RFC1459
67             '234' => 'RPL_SERVLIST', # RFC1459
68             '235' => 'RPL_SERVLISTEND', # RFC1459
69             '239' => 'RPL_STATSIAUTH', # IRCnet
70              
71             '241' => 'RPL_STATSLLINE', # RFC1459
72             '242' => 'RPL_STATSUPTIME', # RFC1459
73             '243' => 'RPL_STATSOLINE', # RFC1459
74             '244' => 'RPL_STATSHLINE', # RFC1459
75             '245' => 'RPL_STATSSLINE', # Bahamut, IRCnet, hybrid
76             '247' => 'RPL_STATSXLINE', # hybrid
77             '248' => 'RPL_STATSULINE', # hybrid
78             '249' => 'RPL_STATSDEBUG', # hybrid
79              
80             '250' => 'RPL_STATSCONN', # ircu, Unreal, hybrid
81             '251' => 'RPL_LUSERCLIENT', # RFC1459
82             '252' => 'RPL_LUSEROP', # RFC1459
83             '253' => 'RPL_LUSERUNKNOWN', # RFC1459
84             '254' => 'RPL_LUSERCHANNELS', # RFC1459
85             '255' => 'RPL_LUSERME', # RFC1459
86             '256' => 'RPL_ADMINME', # RFC1459
87             '257' => 'RPL_ADMINLOC1', # RFC1459
88             '258' => 'RPL_ADMINLOC2', # RFC1459
89             '259' => 'RPL_ADMINEMAIL', # RFC1459
90              
91             '261' => 'RPL_TRACELOG', # RFC1459
92             '262' => 'RPL_ENDOFTRACE', # hybrid
93             '263' => 'RPL_LOAD2HI', # hybrid
94             '265' => 'RPL_LOCALUSERS', # aircd, Bahamut, hybrid
95             '266' => 'RPL_GLOBALUSERS', # aircd, Bahamut, hybrid
96             '267' => 'RPL_START_NETSTAT', # aircd
97             '268' => 'RPL_NETSTAT', # aircd
98             '269' => 'RPL_END_NETSTAT', # aircd
99              
100             '270' => 'RPL_PRIVS', # ircu
101             '271' => 'RPL_SILELIST', # ircu
102             '272' => 'RPL_ENDOFSILELIST', # ircu
103             '275' => 'RPL_WHOISSSL', # oftc-hybrid
104             '276' => 'RPL_WHOISCERTFP', # oftc-hybrid
105              
106             '280' => 'RPL_GLIST', # ircu
107             '281' => 'RPL_ACCEPTLIST', # ratbox/chary
108             '282' => 'RPL_ENDOFACCEPT', # ratbox/chary
109              
110             '300' => 'RPL_NONE', # RFC1459
111             '301' => 'RPL_AWAY', # RFC1459
112             '302' => 'RPL_USERHOST', # RFC1459
113             '303' => 'RPL_ISON', # RFC1459
114             '304' => 'RPL_TEXT', # hybrid
115             '305' => 'RPL_UNAWAY', # RFC1459
116             '306' => 'RPL_NOWAWAY', # RFC1459
117             '307' => 'RPL_WHOISNICKSERVREG', # An issue of contention.
118             '308' => 'RPL_WHOISADMIN', # hybrid
119              
120             '310' => 'RPL_WHOISMODES', # Plexus
121             '311' => 'RPL_WHOISUSER', # RFC1459
122             '312' => 'RPL_WHOISSERVER', # RFC1459
123             '313' => 'RPL_WHOISOPERATOR', # RFC1459
124             '314' => 'RPL_WHOWASUSER', # RFC1459
125             '315' => 'RPL_ENDOFWHO', # RFC1459
126             '316' => 'RPL_WHOISCHANOP', # reserved in rb/chary
127             '317' => 'RPL_WHOISIDLE', # RFC1459
128             '318' => 'RPL_ENDOFWHOIS', # RFC1459
129             '319' => 'RPL_WHOISCHANNELS', # RFC1459
130              
131             '321' => 'RPL_LISTSTART', # RFC1459
132             '322' => 'RPL_LIST', # RFC1459
133             '323' => 'RPL_LISTEND', # RFC1459
134             '324' => 'RPL_CHANNELMODEIS', # RFC1459
135             '325' => 'RPL_CHANNELMLOCK', # sorircd 1.3
136             '328' => 'RPL_CHANNELURL', # ratbox/chary
137             '329' => 'RPL_CREATIONTIME', # Bahamut
138              
139             '330' => 'RPL_WHOISLOGGEDIN', # ratbox/chary
140             '331' => 'RPL_NOTOPIC', # RFC1459
141             '332' => 'RPL_TOPIC', # RFC1459
142             '333' => 'RPL_TOPICWHOTIME', # ircu
143             '337' => 'RPL_WHOISTEXT', # ratbox/chary
144             '338' => 'RPL_WHOISACTUALLY', # Bahamut, ircu
145              
146             '340' => 'RPL_USERIP', # ircu
147             '341' => 'RPL_INVITING', # RFC1459
148             '342' => 'RPL_SUMMONING', # RFC1459
149             '345' => 'RPL_INVITED', # GameSurge
150             '346' => 'RPL_INVITELIST', # RFC2812
151             '347' => 'RPL_ENDOFINVITELIST', # RFC2812
152             '348' => 'RPL_EXCEPTLIST', # RFC2812
153             '349' => 'RPL_ENDOFEXCEPTLIST', # RFC2812
154              
155             '351' => 'RPL_VERSION', # RFC1459
156             '352' => 'RPL_WHOREPLY', # RFC1459
157             '353' => 'RPL_NAMREPLY', # RFC1459
158             '354' => 'RPL_WHOSPCRPL', # ircu
159              
160             '360' => 'RPL_WHOWASREAL', # ratbox/chary
161             '361' => 'RPL_KILLDONE', # RFC1459
162             '362' => 'RPL_CLOSING', # RFC1459
163             '363' => 'RPL_CLOSEEND', # RFC1459
164             '364' => 'RPL_LINKS', # RFC1459
165             '365' => 'RPL_ENDOFLINKS', # RFC1459
166             '366' => 'RPL_ENDOFNAMES', # RFC1459
167             '367' => 'RPL_BANLIST', # RFC1459
168             '368' => 'RPL_ENDOFBANLIST', # RFC1459
169             '369' => 'RPL_ENDOFWHOWAS', # RFC1459
170              
171             '371' => 'RPL_INFO', # RFC1459
172             '372' => 'RPL_MOTD', # RFC1459
173             '373' => 'RPL_INFOSTART', # RFC1459
174             '374' => 'RPL_ENDOFINFO', # RFC1459
175             '375' => 'RPL_MOTDSTART', # RFC1459
176             '376' => 'RPL_ENDOFMOTD', # RFC1459
177             '378' => 'RPL_WHOISHOST', # charybdis
178             # '379' => 'RPL_WHOISMODES', # hybrid-8.1.12, conflicts with 310
179              
180             '381' => 'RPL_YOUREOPER', # RFC1459
181             '382' => 'RPL_REHASHING', # RFC1459
182             '383' => 'RPL_YOURESERVICE', # RFC2812
183             '384' => 'RPL_MYPORTIS', # RFC1459
184             '385' => 'RPL_NOTOPERANYMORE', # AustHex, hybrid, Unreal
185             '386' => 'RPL_RSACHALLENGE', # ratbox
186              
187             '391' => 'RPL_TIME', # RFC1459
188             '392' => 'RPL_USERSSTART', # RFC1459
189             '393' => 'RPL_USERS', # RFC1459
190             '394' => 'RPL_ENDOFUSERS', # RFC1459
191             '395' => 'RPL_NOUSERS', # RFC1459
192             '396' => 'RPL_HOSTHIDDEN', # ircu
193              
194             '401' => 'ERR_NOSUCHNICK', # RFC1459
195             '402' => 'ERR_NOSUCHSERVER', # RFC1459
196             '403' => 'ERR_NOSUCHCHANNEL', # RFC1459
197             '404' => 'ERR_CANNOTSENDTOCHAN', # RFC1459
198             '405' => 'ERR_TOOMANYCHANNELS', # RFC1459
199             '406' => 'ERR_WASNOSUCHNICK', # RFC1459
200             '407' => 'ERR_TOOMANYTARGETS', # RFC1459
201             '408' => 'ERR_NOSUCHSERVICE', # RFC2812
202             '409' => 'ERR_NOORIGIN', # RFC1459
203              
204             '410' => 'ERR_INVALIDCAPCMD', # hybrid
205             '411' => 'ERR_NORECIPIENT', # RFC1459
206             '412' => 'ERR_NOTEXTTOSEND', # RFC1459
207             '413' => 'ERR_NOTOPLEVEL', # RFC1459
208             '414' => 'ERR_WILDTOPLEVEL', # RFC1459
209             '415' => 'ERR_BADMASK', # RFC2812
210             '416' => 'ERR_TOOMANYMATCHES', # ratbox
211              
212             '421' => 'ERR_UNKNOWNCOMMAND', # RFC1459
213             '422' => 'ERR_NOMOTD', # RFC1459
214             '423' => 'ERR_NOADMININFO', # RFC1459
215             '424' => 'ERR_FILEERROR', # RFC1459
216             '425' => 'ERR_NOOPERMOTD', # Unreal
217             '429' => 'ERR_TOOMANYAWAY', # Bahamut
218              
219             '430' => 'ERR_EVENTNICKCHANGE', # AustHex
220             '431' => 'ERR_NONICKNAMEGIVEN', # RFC1459
221             '432' => 'ERR_ERRONEUSNICKNAME', # RFC1459
222             '433' => 'ERR_NICKNAMEINUSE', # RFC1459
223             '436' => 'ERR_NICKCOLLISION', # RFC1459
224             '437' => 'ERR_UNAVAILRESOURCE', # hybrid
225             '438' => 'ERR_NICKTOOFAST', # hybrid
226             '439' => 'ERR_TARGETTOOFAST', # ircu
227              
228             '440' => 'ERR_SERVICESDOWN', # Bahamut, Unreal
229             '441' => 'ERR_USERNOTINCHANNEL', # RFC1459
230             '442' => 'ERR_NOTONCHANNEL', # RFC1459
231             '443' => 'ERR_USERONCHANNEL', # RFC1459
232             '444' => 'ERR_NOLOGIN', # RFC1459
233             '445' => 'ERR_SUMMONDISABLED', # RFC1459
234             '446' => 'ERR_USERSDISABLED', # RFC1459
235             '447' => 'ERR_NONICKCHANGE', # Unreal
236             '449' => 'ERR_NOTIMPLEMENTED', # ircu
237              
238             '451' => 'ERR_NOTREGISTERED', # RFC1459
239             '455' => 'ERR_HOSTILENAME', # Unreal
240             '456' => 'ERR_ACCEPTFULL', # hybrid
241             '457' => 'ERR_ACCEPTEXIST', # hybrid
242             '458' => 'ERR_ACCEPTNOT', # hybrid
243             '459' => 'ERR_NOHIDING', # Unreal
244              
245             '460' => 'ERR_NOTFORHALFOPS', # Unreal
246             '461' => 'ERR_NEEDMOREPARAMS', # RFC1459
247             '462' => 'ERR_ALREADYREGISTRED', # RFC1459
248             '463' => 'ERR_NOPERMFORHOST', # RFC1459
249             '464' => 'ERR_PASSWDMISMATCH', # RFC1459
250             '465' => 'ERR_YOUREBANNEDCREEP', # RFC1459
251             '466' => 'ERR_YOUWILLBEBANNED', # RFC1459
252             '467' => 'ERR_KEYSET', # RFC1459
253             '469' => 'ERR_LINKSET', # Unreal
254              
255             '470' => 'ERR_LINKCHANNEL', # charybdis
256             '471' => 'ERR_CHANNELISFULL', # RFC1459
257             '472' => 'ERR_UNKNOWNMODE', # RFC1459
258             '473' => 'ERR_INVITEONLYCHAN', # RFC1459
259             '474' => 'ERR_BANNEDFROMCHAN', # RFC1459
260             '475' => 'ERR_BADCHANNELKEY', # RFC1459
261             '476' => 'ERR_BADCHANMASK', # RFC2812
262             '477' => 'ERR_NEEDREGGEDNICK', # ratbox (REGONLYCHAN in hyb7)
263             '478' => 'ERR_BANLISTFULL', # ircu
264             '479' => 'ERR_BADCHANNAME', # hybrid
265              
266             '480' => 'ERR_SSLONLYCHAN', # ratbox
267             '481' => 'ERR_NOPRIVILEGES', # RFC1459
268             '482' => 'ERR_CHANOPRIVSNEEDED', # RFC1459
269             '483' => 'ERR_CANTKILLSERVER', # RFC1459
270             '484' => 'ERR_ISCHANSERVICE', # ratbox (ERR_RESTRICTED in hyb7)
271             '485' => 'ERR_BANNEDNICK', # ratbox
272             '488' => 'ERR_TSLESSCHAN', # IRCnet
273             '489' => 'ERR_VOICENEEDED', # ircu
274              
275             '491' => 'ERR_NOOPERHOST', # RFC1459
276             '492' => 'ERR_NOSERVICEHOST', # RFC1459
277             '493' => 'ERR_NOFEATURE', # ircu
278             '494' => 'ERR_OWNMODE', # Bahamut
279             '495' => 'ERR_BADLOGTYPE', # ircu
280             '496' => 'ERR_BADLOGSYS', # ircu
281             '497' => 'ERR_BADLOGVALUE', # ircu
282             '498' => 'ERR_ISOPERLCHAN', # ircu
283              
284             '501' => 'ERR_UMODEUNKNOWNFLAG', # RFC1459
285             '502' => 'ERR_USERSDONTMATCH', # RFC1459
286             '503' => 'ERR_GHOSTEDCLIENT', # hybrid
287             '504' => 'ERR_USERNOTONSERV', # hybrid
288              
289             '513' => 'ERR_WRONGPONG', # hybrid
290             '517' => 'ERR_DISABLED', # ircu
291             '518' => 'ERR_LONGMASK', # ircu
292              
293             '521' => 'ERR_LISTSYNTAX', # hybrid
294             '522' => 'ERR_WHOSYNTAX', # hybrid
295             '523' => 'ERR_WHOLIMITEXCEEDED', # hybrid
296             '524' => 'ERR_HELPNOTFOUND', # hybrid
297              
298             '670' => 'RPL_STARTTLS', # ircv3 tls-3.1
299             '671' => 'RPL_WHOISSECURE', # Unreal
300              
301             '691' => 'ERR_STARTTLS', # ircv3 tls-3.2
302              
303             '702' => 'RPL_MODLIST', # hybrid
304             '703' => 'RPL_ENDOFMODLIST', # hybrid
305             '704' => 'RPL_HELPSTART', # hybrid
306             '705' => 'RPL_HELPTXT', # hybrid
307             '706' => 'RPL_ENDOFHELP', # hybrid
308             '707' => 'ERR_TARGCHANGE', # ratbox
309              
310             '710' => 'RPL_KNOCK', # hybrid
311             '711' => 'RPL_KNOCKDLVR', # hybrid
312             '712' => 'ERR_TOOMANYKNOCK', # hybrid
313             '713' => 'ERR_CHANOPEN', # hybrid
314             '714' => 'ERR_KNOCKONCHAN', # hybrid
315             '715' => 'ERR_KNOCKDISABLED', # hybrid
316             '716' => 'RPL_TARGUMODEG', # hybrid
317             '717' => 'RPL_TARGNOTIFY', # hybrid
318             '718' => 'RPL_UMODEGMSG', # hybrid
319              
320             '720' => 'RPL_OMOTDSTART', # hybrid
321             '721' => 'RPL_OMOTD', # hybrid
322             '722' => 'RPL_ENDOFOMOTD', # hybrid
323             '723' => 'ERR_NOPRIVS', # hybrid
324             '724' => 'RPL_TESTMASK', # hybrid
325             '725' => 'RPL_TESTLINE', # hybrid
326             '726' => 'RPL_NOTESTLINE', # hybrid
327             '727' => 'RPL_TESTMASKGECOS', # ratbox
328             '728' => 'RPL_QUIETLIST', # charybdis
329             '729' => 'RPL_ENDOFQUIETLIST', # charybdis
330              
331             '730' => 'RPL_MONONLINE', # ircv3 monitor ext
332             '731' => 'RPL_MONOFFLINE', # ircv3 monitor ext
333             '732' => 'RPL_MONLIST', # ircv3 monitor ext
334             '733' => 'RPL_ENDOFMONLIST', # ircv3 monitor ext
335             '734' => 'ERR_MONLISTFULL', # ircv3 monitor ext
336              
337             '740' => 'RPL_RSACHALLENGE2', # ratbox
338             '741' => 'RPL_ENDOFRSACHALLENGE2', # ratbox
339             );
340              
341             our %Name = reverse %Numeric;
342              
343              
344             ## Functional interface.
345 1     1 1 963 sub name_from_numeric { $Numeric{$_[0]} }
346 1     1 1 431 sub numeric_from_name { $Name{$_[0]} }
347              
348             ## OO interface.
349             sub new {
350 2     2 1 2018 my ($cls, $type) = splice @_, 0, 2;
351              
352 2 100       8 if ($type) {
353             return
354 1         6 use_package_optimistically('IRC::Toolkit::Numerics::'.$type)->new(@_)
355             }
356              
357 1         3 bless +{ over_num => hash(), over_name => hash() }, $cls
358             }
359              
360             sub get_name_for {
361 6     6 1 806 my ($self, $numeric) = @_;
362              
363 6 100       17 if (ref $self) {
364 5 100       21 if (my $num = $self->{over_num}->get($numeric)) {
365 2         16 return $num
366             }
367             }
368 4         32 $Numeric{$numeric}
369             }
370              
371             sub get_numeric_for {
372 4     4 1 9 my ($self, $name) = @_;
373 4 100       13 if (ref $self) {
374 3 100       10 if (my $num = $self->{over_name}->get($name)) {
375 2         16 return $num
376             }
377             }
378 2         12 $Name{$name}
379             }
380              
381             sub associate_numeric {
382 1     1 1 2 my ($self, $numeric, $name) = @_;
383              
384 1 50       4 confess "associate_numeric() should be called on a blessed instance"
385             unless ref $self;
386              
387 1 50 33     7 confess "Expected a numeric and a label to map it to"
388             unless defined $numeric and defined $name;
389              
390 1         7 $self->{over_num}->set($numeric => $name);
391 1         20 $self->{over_name}->set($name => $numeric);
392             }
393              
394             sub export {
395 2 100 66 2 1 431 if (ref $_[0] && !$_[0]->{over_num}->is_empty) {
396 1         9 my ($self) = @_;
397 1         108 my %orig = %Numeric;
398 1         10 my $override = $self->{over_num};
399 1         5 @orig{ $override->keys->all } = $override->values->all;
400 1         75 return hash(%orig)
401             }
402 1         86 hash(%Numeric)
403             }
404              
405             sub export_by_name {
406 2 100 66 2 1 13611 if (ref $_[0] && !$_[0]->{over_name}->is_empty) {
407 1         7 my $self = $_[0];
408 1         88 my %orig = %Name;
409 1         9 my $override = $self->{over_name};
410 1         3 @orig{ $override->keys->all } = $override->values->all;
411 1         54 return hash(%orig)
412             }
413 1         65 hash(%Name)
414             }
415              
416             1;
417              
418             =pod
419              
420             =head1 NAME
421              
422             IRC::Toolkit::Numerics - Modern IRC numeric responses
423              
424             =head2 SYNOPSIS
425              
426             use IRC::Toolkit::Numerics;
427              
428             ## Functional interface returns defaults:
429             my $rpl = name_from_numeric( '001' ); # 'RPL_WELCOME'
430             my $num = numeric_from_name( 'RPL_USERSDONTMATCH' ); # '502'
431              
432             ## OO interface allows (re)mapping numerics:
433             my $numerics = IRC::Toolkit::Numerics->new;
434              
435             $numerics->get_name_for( '001' );
436             $numerics->get_numeric_for( 'RPL_WELCOME' );
437              
438             $numerics->associate_numeric( '486' => 'ERR_HTMDISABLED' );
439              
440             =head1 DESCRIPTION
441              
442             A pair of functions for translating IRC numerics into their "RPL" or "ERR"
443             name and back again.
444              
445             The included list attempts to be as complete as possible.
446              
447             In cases where there is a conflict
448             (typically between RFC2812, ircu, and hybrid/ratbox derivatives),
449             modern B labels are preferred, ratbox derivatives being the most
450             prevalent across large networks.
451              
452             In cases where that turns out not to be true, please send patches ;-)
453              
454             =head2 Functional interface
455              
456             =head3 name_from_numeric
457              
458             Given a numeric, B returns its proper RPL name.
459              
460             =head3 numeric_from_name
461              
462             Given a RPL name, B returns its assigned command numeric.
463              
464             =head2 Object interface
465              
466             =head3 new
467              
468             my $numerics = IRC::Toolkit::Numerics->new;
469              
470             Construct a new instance.
471              
472             =head3 associate_numeric
473              
474             ## A hybrid7 484 (overrides ratbox):
475             $numerics->associate_numeric( '484' => 'ERR_RESTRICTED' );
476              
477             Add or remap a numeric.
478              
479             =head3 get_name_for
480              
481             ## RPL_WELCOME:
482             my $name = $numerics->get_name_for('001');
483             ## ERR_CHANNELISFULL:
484             $name = $numerics->get_name_for(471);
485              
486             Retrieve the RPL/ERR label for a supplied numeric (or boolean false).
487              
488             =head3 get_numeric_for
489              
490             ## 471:
491             my $thisnum = $numerics->get_numeric_for('ERR_CHANNELISFULL');
492              
493             Retrieve the numeric for a supplied RPL/ERR label (or boolean false).
494              
495             =head3 export
496              
497             my $hash = IRC::Toolkit::Numerics->export;
498              
499             Exports a L mapping numerics to RPL/ERR names.
500              
501             If called on a blessed instance (rather than as a class method), numerics
502             remapped via L are included in the exported hash.
503              
504             =head3 export_by_name
505              
506             Like L, but returns the reversed hash (mapping RPL/ERR names to
507             numerics).
508              
509             =head1 SUBCLASSING
510              
511             It's possible for a subclass to override individual numerics (and otherwise
512             default to the standard list) by providing a constructor that uses
513             L to construct C-type objects containing
514             overrides:
515              
516             package My::Numerics;
517             use List::Objects::WithUtils 'hash';
518             use parent 'IRC::Toolkit::Numerics';
519             sub new {
520             bless +{
521             over_num => hash(304 => 'RPL_FOO'),
522             over_name => hash(RPL_RPL => 304),
523             }, $_[0]
524             }
525              
526             =head1 AUTHOR
527              
528             Jon Portnoy
529              
530             Default numerics list is based on the L list present
531             in L and the C definitions from hybrid-7.2.3,
532             oftc-hybrid-1.6.7, and ratbox-trunk.
533              
534             Interface is based on L
535             and helpful suggestions from
536              
537             =cut