net-yail 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +2 -0
- data/lib/net/yail.rb +70 -36
- data/lib/net/yail/message_parser.rb +66 -0
- data/tests/net_yail.rb +4 -0
- data/tests/tc_message_parser.rb +60 -0
- metadata +6 -4
data/README
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
Rubyforge page: http://rubyforge.org/projects/ruby-irc-yail
|
2
2
|
|
3
|
+
*Want to jump straight to the examples instead of reading this lame "about the project" doc? Just click on Net::YAIL !*
|
4
|
+
|
3
5
|
Net::YAIL is a library built for dealing with IRC communications in Ruby.
|
4
6
|
This is a project I've been building for about three years, based
|
5
7
|
originally on the very messy initial release of IRCSocket (back when I first
|
data/lib/net/yail.rb
CHANGED
@@ -9,6 +9,9 @@ require 'net/yail/magic_events'
|
|
9
9
|
require 'net/yail/default_events'
|
10
10
|
require 'net/yail/output_api'
|
11
11
|
|
12
|
+
# Finally, a real class to include!
|
13
|
+
require 'net/yail/message_parser.rb'
|
14
|
+
|
12
15
|
# If a thread crashes, I want the app to die. My threads are persistent, not
|
13
16
|
# temporary.
|
14
17
|
Thread.abort_on_exception = true
|
@@ -36,7 +39,7 @@ module Net
|
|
36
39
|
# ==Incoming Events
|
37
40
|
#
|
38
41
|
# Current list of incoming events and the parameters sent to the handler:
|
39
|
-
# * :incoming_any(
|
42
|
+
# * :incoming_any(raw) - "global" handler that catches all events and may
|
40
43
|
# modify their data as necessary before the real handler is hit. This
|
41
44
|
# only be used in cases where it's necessary to grab a lot of events that
|
42
45
|
# also need to be processed elsewhere, such as doing input filtering for
|
@@ -227,6 +230,8 @@ class YAIL
|
|
227
230
|
include Net::IRCEvents::Defaults
|
228
231
|
include Net::IRCOutputAPI
|
229
232
|
|
233
|
+
VERSION = '1.3.0'
|
234
|
+
|
230
235
|
attr_reader(
|
231
236
|
:me, # Nickname on the IRC server
|
232
237
|
:registered, # If true, we've been welcomed
|
@@ -458,42 +463,71 @@ class YAIL
|
|
458
463
|
|
459
464
|
# Gets some input, sends stuff off to a handler. Yay.
|
460
465
|
def process_input(line)
|
461
|
-
# Allow global handler to break the chain, filter the line, whatever
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
when
|
492
|
-
|
493
|
-
|
494
|
-
|
466
|
+
# Allow global handler to break the chain, filter the line, whatever. For
|
467
|
+
# this release, it's a hack. 2.0 will be better.
|
468
|
+
for handler in @handlers[:incoming_any]
|
469
|
+
result = handler.call(line)
|
470
|
+
return if result == true
|
471
|
+
end
|
472
|
+
|
473
|
+
# Use the exciting new parser
|
474
|
+
msg = Net::YAIL::MessageParser.new(line)
|
475
|
+
|
476
|
+
# In the legacy system, there are never situations where we want the params
|
477
|
+
# separated into array elements. So we convert them here, since so many
|
478
|
+
# handlers require a param or two followed by "everything else".
|
479
|
+
params = msg.params.dup
|
480
|
+
param1 = params.shift
|
481
|
+
other1 = params.join(' ') || ''
|
482
|
+
param2 = params.shift
|
483
|
+
other2 = params.join(' ') || ''
|
484
|
+
|
485
|
+
case msg.command
|
486
|
+
# Ping is important to handle quickly, so it comes first.
|
487
|
+
when 'PING'
|
488
|
+
handle(:incoming_ping, msg.params.first)
|
489
|
+
when /^\d{3}$/
|
490
|
+
handle_numeric(msg.command.to_i, msg.prefix, msg.nick, param1, other1)
|
491
|
+
when 'INVITE'
|
492
|
+
handle(:incoming_invite, msg.prefix, msg.nick, msg.params.last)
|
493
|
+
|
494
|
+
# This can encompass three possible messages, so further refining happens here - the last param
|
495
|
+
# is always the message itself, so we look for patterns there.
|
496
|
+
when 'PRIVMSG'
|
497
|
+
case msg.params.last
|
498
|
+
when /^\001ACTION (.+?)\001$/
|
499
|
+
handle(:incoming_act, msg.prefix, msg.nick, msg.params.first, $1)
|
500
|
+
when /^\001(.+?)\001$/
|
501
|
+
handle(:incoming_ctcp, msg.prefix, msg.nick, msg.params.first, $1)
|
502
|
+
else
|
503
|
+
handle(:incoming_msg, msg.prefix, msg.nick, param1, other1)
|
504
|
+
end
|
505
|
+
|
506
|
+
# This can encompass two possible messages, again based on final param
|
507
|
+
when 'NOTICE'
|
508
|
+
case msg.params.last
|
509
|
+
when /^\001(.+?)\001$/
|
510
|
+
handle(:incoming_ctcpreply, msg.prefix, msg.nick, msg.params.first, $1)
|
511
|
+
else
|
512
|
+
handle(:incoming_notice, msg.prefix, msg.nick, param1, other1)
|
513
|
+
end
|
514
|
+
|
515
|
+
when 'MODE'
|
516
|
+
handle(:incoming_mode, msg.prefix, msg.nick, param1, param2, other2)
|
517
|
+
when 'JOIN'
|
518
|
+
handle(:incoming_join, msg.prefix, msg.nick, param1)
|
519
|
+
when 'PART'
|
520
|
+
handle(:incoming_part, msg.prefix, msg.nick, param1, other1)
|
521
|
+
when 'KICK'
|
522
|
+
handle(:incoming_kick, msg.prefix, msg.nick, param1, param2, other2)
|
523
|
+
when 'QUIT'
|
524
|
+
handle(:incoming_quit, msg.prefix, msg.nick, param1)
|
525
|
+
when 'NICK'
|
526
|
+
handle(:incoming_nick, msg.prefix, msg.nick, param1)
|
527
|
+
|
528
|
+
# Unknown line!
|
495
529
|
else
|
496
|
-
handle
|
530
|
+
handle(:incoming_miscellany, line)
|
497
531
|
end
|
498
532
|
end
|
499
533
|
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Net
|
2
|
+
class YAIL
|
3
|
+
|
4
|
+
# This is my lame attempt to convert the BNF-style grammar from RFC 1459 into
|
5
|
+
# useable ruby regexes. The hope here is that one can effectively match an
|
6
|
+
# incoming message with high accuracy. Usage:
|
7
|
+
#
|
8
|
+
# line = ':Nerdmaster!jeremy@nerdbucket.com PRIVMSG Nerdminion :Do my bidding!!'
|
9
|
+
# message = Net::YAIL::MessageParser.new(line)
|
10
|
+
# # hash now has all kinds of useful pieces of the incoming message:
|
11
|
+
# puts line.nick # "Nerdmaster"
|
12
|
+
# puts line.user # "jeremy"
|
13
|
+
# puts line.host # "nerdbucket.com"
|
14
|
+
# puts line.prefix # "Nerdmaster!jeremy@nerdbucket.com"
|
15
|
+
# puts line.command # "PRIVMSG"
|
16
|
+
# puts line.params # ["Nerdminion", "Do my bidding!!"]
|
17
|
+
class MessageParser
|
18
|
+
attr_reader :nick, :user, :host, :prefix, :command, :params, :servername
|
19
|
+
|
20
|
+
# Note that all regexes are non-greedy. I'm scared of greedy regexes, sirs.
|
21
|
+
USER = /\S+?/
|
22
|
+
NICK = /\w[\w\d\\`'^{}\]\[-]+?/
|
23
|
+
HOST = /\S+?/
|
24
|
+
SERVERNAME = /\S+?/
|
25
|
+
|
26
|
+
# This is automatically grouped for ease of use in the parsing. Group 1 is
|
27
|
+
# the full prefix; 2, 3, and 4 are nick/user/host; 1 is also servername if
|
28
|
+
# there was no match to populate 2, 3, and 4.
|
29
|
+
PREFIX = /((#{NICK})!(#{USER})@(#{HOST})|#{SERVERNAME})/
|
30
|
+
COMMAND = /(\w+|\d{3})/
|
31
|
+
TRAILING = /\:\S*?/
|
32
|
+
MIDDLE = /(?: +([^ :]\S*))/
|
33
|
+
|
34
|
+
MESSAGE = /^(?::#{PREFIX} +)?#{COMMAND}(.*)$/
|
35
|
+
|
36
|
+
def initialize(line)
|
37
|
+
@params = []
|
38
|
+
|
39
|
+
if line =~ MESSAGE
|
40
|
+
matches = Regexp.last_match
|
41
|
+
|
42
|
+
@prefix = matches[1]
|
43
|
+
if (matches[2])
|
44
|
+
@nick = matches[2]
|
45
|
+
@user = matches[3]
|
46
|
+
@host = matches[4]
|
47
|
+
else
|
48
|
+
@servername = matches[1]
|
49
|
+
end
|
50
|
+
|
51
|
+
@command = matches[5]
|
52
|
+
|
53
|
+
# Args are a bit tricky. First off, we know there must be a single
|
54
|
+
# space before the arglist, so we need to strip that. Then we have to
|
55
|
+
# separate the trailing arg as it can contain nearly any character. And
|
56
|
+
# finally, we split the "middle" args on space.
|
57
|
+
arglist = matches[6].sub(/^ +/, '')
|
58
|
+
(middle_args, trailing_arg) = arglist.split(/ +:/, 2)
|
59
|
+
@params.push(middle_args.split(/ +/), trailing_arg)
|
60
|
+
@params.flatten!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
data/tests/net_yail.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.dirname(__FILE__) + '/net_yail'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class MessageParserText < Test::Unit::TestCase
|
6
|
+
# Very simple parsing of easy strings
|
7
|
+
def test_parse_basic
|
8
|
+
# Basic test of privmsg-type command
|
9
|
+
msg = Net::YAIL::MessageParser.new(':Nerdmaster!jeremy@nerdbucket.com PRIVMSG Nerdminion :Do my bidding!!')
|
10
|
+
assert_equal 'Nerdmaster', msg.nick
|
11
|
+
assert_equal 'jeremy', msg.user
|
12
|
+
assert_equal 'nerdbucket.com', msg.host
|
13
|
+
assert_equal 'Nerdmaster!jeremy@nerdbucket.com', msg.prefix
|
14
|
+
assert_equal 'PRIVMSG', msg.command
|
15
|
+
assert_equal 'Nerdminion', msg.params[0]
|
16
|
+
assert_equal 'Do my bidding!!', msg.params[1]
|
17
|
+
|
18
|
+
# Server command of some type
|
19
|
+
msg = Net::YAIL::MessageParser.new(':nerdbucket.com SERVERCOMMAND arg1 arg2 :final :trailing :arg, --fd9823')
|
20
|
+
assert_equal 'nerdbucket.com', msg.servername
|
21
|
+
assert_nil msg.user
|
22
|
+
assert_nil msg.nick
|
23
|
+
assert_nil msg.host
|
24
|
+
assert_equal 'nerdbucket.com', msg.prefix
|
25
|
+
assert_equal 'arg1', msg.params[0]
|
26
|
+
assert_equal 'arg2', msg.params[1]
|
27
|
+
assert_equal 'final :trailing :arg, --fd9823', msg.params[2]
|
28
|
+
|
29
|
+
# WTF? Well, IRC spec says it's valid
|
30
|
+
msg = Net::YAIL::MessageParser.new('MAGICFUNKYFRESHCMD arg1 arg2')
|
31
|
+
assert_nil msg.servername
|
32
|
+
assert_equal 'MAGICFUNKYFRESHCMD', msg.command
|
33
|
+
assert_equal 'arg1', msg.params[0]
|
34
|
+
assert_equal 'arg2', msg.params[1]
|
35
|
+
|
36
|
+
# Action
|
37
|
+
msg = Net::YAIL::MessageParser.new(':Nerdmaster!jeremy@nerdbucket.com PRIVMSG #bottest :\001ACTION gives Towelie a joint\001')
|
38
|
+
assert_equal 'Nerdmaster', msg.nick
|
39
|
+
assert_equal 'PRIVMSG', msg.command
|
40
|
+
assert_equal '#bottest', msg.params.first
|
41
|
+
assert_equal '\001ACTION gives Towelie a joint\001', msg.params.last
|
42
|
+
|
43
|
+
# Bot sets mode
|
44
|
+
msg = Net::YAIL::MessageParser.new(':Towelie!~x2e521146@towelie.foo.bar MODE Towelie :+i')
|
45
|
+
assert_equal 'Towelie', msg.nick
|
46
|
+
assert_equal 'towelie.foo.bar', msg.host
|
47
|
+
assert_equal 'MODE', msg.command
|
48
|
+
assert_equal 'Towelie', msg.params.first
|
49
|
+
assert_equal '+i', msg.params.last
|
50
|
+
|
51
|
+
# Numeric message with a : before final param
|
52
|
+
msg = Net::YAIL::MessageParser.new(':someserver.co.uk.fn.bb 366 Towelie #bottest :End of /NAMES list.')
|
53
|
+
assert_nil msg.nick
|
54
|
+
assert_nil msg.host
|
55
|
+
assert_equal '366', msg.command
|
56
|
+
assert_equal 'Towelie', msg.params.shift
|
57
|
+
assert_equal '#bottest', msg.params.shift
|
58
|
+
assert_equal 'End of /NAMES list.', msg.params.shift
|
59
|
+
end
|
60
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-yail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Echols
|
@@ -9,7 +9,7 @@ autorequire: net/yail
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-28 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -31,6 +31,7 @@ files:
|
|
31
31
|
- lib/net/yail/magic_events.rb
|
32
32
|
- lib/net/yail/eventmap.yml
|
33
33
|
- lib/net/yail/IRCBot.rb
|
34
|
+
- lib/net/yail/message_parser.rb
|
34
35
|
- README
|
35
36
|
has_rdoc: true
|
36
37
|
homepage: http://ruby-irc-yail.nerdbucket.com/
|
@@ -59,5 +60,6 @@ rubygems_version: 1.2.0
|
|
59
60
|
signing_key:
|
60
61
|
specification_version: 2
|
61
62
|
summary: "Yet Another IRC Library: wrapper for IRC communications in Ruby."
|
62
|
-
test_files:
|
63
|
-
|
63
|
+
test_files:
|
64
|
+
- tests/net_yail.rb
|
65
|
+
- tests/tc_message_parser.rb
|