raibo 0.0.1 → 0.0.2

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/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ Botfile
data/Gemfile CHANGED
@@ -2,3 +2,6 @@ source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in raibo.gemspec
4
4
  gemspec
5
+
6
+ # Development dependencies
7
+ gem 'rspec'
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'raibo'
5
+
6
+ botfile = ARGV.shift || 'Botfile'
7
+
8
+ if Dir[botfile].empty?
9
+ puts "Usage: raibo [botfile]"
10
+ end
11
+
12
+ b = Raibo::Bot.new('irc.he.net', :nick => 'raibot', :port => 6667, :verbose => true)
13
+ b.instance_eval(File.read(botfile))
14
+ b.run
@@ -0,0 +1,25 @@
1
+ # This is a simple example of a module that could be used with Raibo.
2
+ # An associated Botfile might look like this:
3
+ #
4
+ # require_relative 'example/test_module'
5
+ # use ExampleModule.new(/hello/, 'goodbye')
6
+ # use ExampleModule.new(/goodbye/, 'hello')
7
+ #
8
+ # This will run a bot that responds to a message containing "hello"
9
+ # by saying "goodbye", and vice versa.
10
+ #
11
+ # Bots can maintain whatever state they want to. The only requirement
12
+ # is that they respond to a #call method with a Raibo::Connection as
13
+ # the first parameter and Raibo::Message as the second.
14
+
15
+ class ExampleModule
16
+ def initialize(regexp, response)
17
+ @regexp, @response = regexp, response
18
+ end
19
+
20
+ def call(c, message)
21
+ if message.body =~ @regexp
22
+ c.say @response
23
+ end
24
+ end
25
+ end
@@ -5,3 +5,5 @@ require 'socket'
5
5
 
6
6
  require 'raibo/version'
7
7
  require 'raibo/connection'
8
+ require 'raibo/bot'
9
+ require 'raibo/message'
@@ -0,0 +1,66 @@
1
+ module Raibo
2
+ class Bot
3
+ def initialize(*args)
4
+ @handlers = []
5
+
6
+ if args.first.is_a?(Raibo::Connection)
7
+ @connection = args.shift
8
+ else
9
+ @connection = Raibo::Connection.new(*args)
10
+ end
11
+ end
12
+
13
+ def use(handler=nil, &block)
14
+ @handlers.push(handler || block)
15
+ end
16
+
17
+ def match(regexp, &block)
18
+ use do |msg|
19
+ if msg.body =~ regexp
20
+ exec_with_var_arity($~, msg, &block)
21
+ end
22
+ end
23
+ end
24
+
25
+ def run(async=false)
26
+ if async
27
+ @thread = Thread.new { run_sync }
28
+ @thread.abort_on_exception = true
29
+ else
30
+ run_sync
31
+ end
32
+ end
33
+
34
+ def stop
35
+ @thread.kill if @thread
36
+ @connection.close
37
+ end
38
+
39
+ def alive?
40
+ @thread.alive? if @thread
41
+ end
42
+
43
+ private
44
+ def run_sync
45
+ @connection.open
46
+ @connection.handle_lines do |line|
47
+ begin
48
+ message = Raibo::Message.new(line)
49
+ rescue => e
50
+ if @connection.verbose
51
+ puts "Error parsing line:"
52
+ puts " #{line}"
53
+ puts " #{e.backtrace}"
54
+ end
55
+ end
56
+ @handlers.each do |handler|
57
+ if handler.is_a?(Proc)
58
+ break if @connection.instance_exec(message, &handler)
59
+ else
60
+ break if handler.call(@connection, message)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -3,23 +3,23 @@ module Raibo
3
3
  attr_accessor :server, :port, :nick, :channel
4
4
 
5
5
  def initialize(server, opts={})
6
- @server = server
7
- @port = opts[:port] || 6667
8
- @nick = opts[:nick] || 'Raibo'
9
- @channel = opts[:channel] || '#raibo'
10
- @verbose = !!opts[:verbose]
6
+ @server = server
7
+ @port = opts[:port] || 6667
8
+ @nick = opts[:nick] || 'Raibo'
9
+ @channel = opts[:channel] || '#raibo'
10
+ @verbose = !!opts[:verbose]
11
11
  end
12
12
 
13
13
  def open
14
14
  @connection = TCPSocket.new(@server, @port)
15
- send "USER #{@nick} 0 * :Hi"
15
+ send "USER #{@nick} 0 * :Hello"
16
16
  nick @nick
17
17
 
18
18
  handle_lines do |line|
19
19
  case line
20
- when /:Nickname is already in use./
21
- @nick = "#{@nick}_"
22
- nick @nick
20
+ when /:Nickname is already in use/
21
+ @connection.close
22
+ raise "Connection error: Nickname is already in use."
23
23
  when /001/
24
24
  join @channel
25
25
  break
@@ -41,6 +41,8 @@ module Raibo
41
41
  yield line
42
42
  end
43
43
  end
44
+ rescue IOError
45
+ close
44
46
  end
45
47
 
46
48
  def nick(nick)
@@ -67,5 +69,14 @@ module Raibo
67
69
  puts "<-- #{str}" if @verbose
68
70
  @connection.puts(str)
69
71
  end
72
+
73
+ def exec_with_var_arity(*args, &block)
74
+ arity = block.arity
75
+ if arity <= 0
76
+ instance_eval(&block)
77
+ else
78
+ instance_exec(*args.take(block.arity), &block)
79
+ end
80
+ end
70
81
  end
71
82
  end
@@ -0,0 +1,63 @@
1
+ module Raibo
2
+ class Message
3
+ # Readers for the components of the actual IRC protocol line.
4
+ attr_reader :prefix, :type, :middle, :trailing
5
+
6
+ # Readers for higher-level attributes of the message.
7
+ attr_reader :kind, :from, :to, :body
8
+
9
+ def initialize(line)
10
+ @prefix, @type, @middle, @trailing = parse_line(line)
11
+
12
+ @kind = get_kind
13
+ @from = get_from
14
+ @to = get_to
15
+ @body = get_body
16
+ end
17
+
18
+ private
19
+ def parse_line(line)
20
+ prefix, type, params = line.match(/:(\S+) (\S+) (.*)/).captures
21
+ if params
22
+ middle, _, trailing = params.partition(':')
23
+ middle = middle.split
24
+ trailing.chomp!
25
+ end
26
+ [prefix, type, middle, trailing]
27
+ end
28
+
29
+ def get_kind
30
+ case type
31
+ when 'PRIVMSG'
32
+ if trailing =~ /^\001ACTION/
33
+ :emote
34
+ else
35
+ :message
36
+ end
37
+ when 'JOIN'
38
+ :join
39
+ when 'PART'
40
+ :part
41
+ end
42
+ end
43
+
44
+ def get_from
45
+ prefix[/^([^!@ ]*)/, 1]
46
+ end
47
+
48
+ def get_to
49
+ if [:message, :emote].include?(kind)
50
+ middle.first
51
+ end
52
+ end
53
+
54
+ def get_body
55
+ case kind
56
+ when :message
57
+ trailing
58
+ when :emote
59
+ trailing[/\001ACTION ([^\001]*)/, 1]
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,3 +1,3 @@
1
1
  module Raibo
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ module Raibo
4
+ describe Message do
5
+ it 'parses a message' do
6
+ m = Raibo::Message.new(":someone!someone@Nightstar-251832d1.snfc22.example.com PRIVMSG #raibo :foo bar baz")
7
+
8
+ m.kind.should == :message
9
+ m.from.should == 'someone'
10
+ m.to.should == '#raibo'
11
+ m.body.should == 'foo bar baz'
12
+ end
13
+
14
+ it 'parses an emote' do
15
+ m = Raibo::Message.new(":someone!someone@Nightstar-251832d1.snfc22.example.com PRIVMSG #raibo :\001ACTION foo bar baz\001")
16
+
17
+ m.kind.should == :emote
18
+ m.from.should == 'someone'
19
+ m.to.should == '#raibo'
20
+ m.body.should == 'foo bar baz'
21
+ end
22
+
23
+ it 'parses a join' do
24
+ m = Raibo::Message.new(":someone!someone@Nightstar-251832d1.snfc22.example.com JOIN :#raibo")
25
+
26
+ m.kind.should == :join
27
+ m.from.should == 'someone'
28
+ m.to.should == nil
29
+ m.body.should == nil
30
+ end
31
+
32
+ it 'parses a part' do
33
+ m = Raibo::Message.new(":someone!someone@Nightstar-251832d1.snfc22.example.com PART #raibo")
34
+
35
+ m.kind.should == :part
36
+ m.from.should == 'someone'
37
+ m.to.should == nil
38
+ m.body.should == nil
39
+ end
40
+
41
+ it 'parses an arbitrary line' do
42
+ m = Raibo::Message.new(":Deepthought.NY.US.Nightstar.Net 255 Raibo :I have 83 clients and 1 servers")
43
+ m.kind.should == nil
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,2 @@
1
+ require 'rubygems'
2
+ require 'raibo'
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: raibo
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
5
4
  prerelease:
6
- segments:
7
- - 0
8
- - 0
9
- - 1
10
- version: 0.0.1
5
+ version: 0.0.2
11
6
  platform: ruby
12
7
  authors:
13
8
  - Ryan Fitzgerald
@@ -15,15 +10,15 @@ autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2011-07-12 00:00:00 -07:00
13
+ date: 2011-07-17 00:00:00 -07:00
19
14
  default_executable:
20
15
  dependencies: []
21
16
 
22
17
  description: ""
23
18
  email:
24
19
  - rwfitzge@gmail.com
25
- executables: []
26
-
20
+ executables:
21
+ - raibo
27
22
  extensions: []
28
23
 
29
24
  extra_rdoc_files: []
@@ -32,10 +27,16 @@ files:
32
27
  - .gitignore
33
28
  - Gemfile
34
29
  - Rakefile
30
+ - bin/raibo
31
+ - example/example_module.rb
35
32
  - lib/raibo.rb
33
+ - lib/raibo/bot.rb
36
34
  - lib/raibo/connection.rb
35
+ - lib/raibo/message.rb
37
36
  - lib/raibo/version.rb
38
37
  - raibo.gemspec
38
+ - spec/message_spec.rb
39
+ - spec/spec_helper.rb
39
40
  has_rdoc: true
40
41
  homepage: ""
41
42
  licenses: []
@@ -50,25 +51,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
50
51
  requirements:
51
52
  - - ">="
52
53
  - !ruby/object:Gem::Version
53
- hash: 3
54
- segments:
55
- - 0
56
54
  version: "0"
57
55
  required_rubygems_version: !ruby/object:Gem::Requirement
58
56
  none: false
59
57
  requirements:
60
58
  - - ">="
61
59
  - !ruby/object:Gem::Version
62
- hash: 3
63
- segments:
64
- - 0
65
60
  version: "0"
66
61
  requirements: []
67
62
 
68
63
  rubyforge_project: raibo
69
- rubygems_version: 1.5.1
64
+ rubygems_version: 1.5.2
70
65
  signing_key:
71
66
  specification_version: 3
72
67
  summary: A simple IRC library
73
- test_files: []
74
-
68
+ test_files:
69
+ - spec/message_spec.rb
70
+ - spec/spec_helper.rb