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 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(event) - "global" handler that catches all events and may
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
- return if handle :incoming_any, line
463
-
464
- case line
465
- # Numerics must be handled first! Otherwise a numeric message that's
466
- # formatted just right will accidentally match another handler.
467
- when /^:((.+?)(?:!.+?)?) (\d{3})\s+(\S+?) (.+?)$/
468
- handle_numeric($3.to_i, $1, $2, $4, $5)
469
- when /^PING :?(.+?)$/
470
- handle :incoming_ping, $1
471
- when /^:((.+?)(?:!.+?)?) INVITE \S+ :(\S+)/
472
- handle :incoming_invite, $1, $2, $3
473
- when /^:((.+?)(?:!.+?)?) PRIVMSG (\S+) :?\001ACTION (.+?)\001$/
474
- handle :incoming_act, $1, $2, $3, $4
475
- when /^:((.+?)(?:!.+?)?) PRIVMSG (\S+?) :?\001(.+?)\001$/
476
- handle :incoming_ctcp, $1, $2, $3, $4
477
- when /^:((.+?)(?:!.+?)?) PRIVMSG (\S+?) :?(.+?)$/
478
- handle :incoming_msg, $1, $2, $3, $4
479
- when /^:((.+?)(?:!.+?)?) NOTICE (\S+?) :?\001(.+?)\001$/
480
- handle :incoming_ctcpreply, $1, $2, $3, $4
481
- when /^:((.+?)(?:!.+?)?) NOTICE (\S+?) :?(.+?)$/
482
- handle :incoming_notice, $1, $2, $3, $4
483
- when /^:((.+?)(?:!.+?)?) MODE (\S+?) :?(\S+?)(?: (.+?))?$/
484
- handle :incoming_mode, $1, $2, $3, $4, $5
485
- when /^:((.+?)(?:!.+?)?) JOIN :?(\S+?)$/
486
- handle :incoming_join, $1, $2, $3
487
- when /^:((.+?)(?:!.+?)?) PART (\S+?)(?: :?(\S+?)?)?$/
488
- handle :incoming_part, $1, $2, $3, $4
489
- when /^:((.+?)(?:!.+?)?) KICK (\S+?) (\S+?) :?(.+?)$/
490
- handle :incoming_kick, $1, $2, $3, $4, $5
491
- when /^:((.+?)(?:!.+?)?) QUIT :?(.+?)$/
492
- handle :incoming_quit, $1, $2, $3
493
- when /^:((.+?)(?:!.+?)?) NICK :?(\S+?)$/
494
- handle :incoming_nick, $1, $2, $3
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 :incoming_miscellany, line
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,4 @@
1
+ $LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib")
2
+ require 'net/yail'
3
+ require 'net/yail/message_parser'
4
+ puts "VERSION: #{Net::YAIL::VERSION}"
@@ -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.2.3
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-17 00:00:00 -07:00
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