ponder 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,10 +1,9 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
1
+ require 'rubygems'
2
+ require 'rspec/core/rake_task'
2
3
 
3
- task :test do
4
- require 'test/test_async_irc.rb'
5
- require 'test/test_callback.rb'
6
- require 'test/test_irc.rb'
7
- end
4
+ desc 'Run all specs'
5
+ RSpec::Core::RakeTask.new(:spec)
8
6
 
9
- task :default => :test
7
+ task :test => :spec
8
+ task :default => :spec
10
9
 
@@ -3,115 +3,118 @@ require 'timeout'
3
3
 
4
4
  module Ponder
5
5
  module AsyncIRC
6
+ TIMEOUT = 30
7
+
6
8
  def get_topic(channel)
7
9
  queue = Queue.new
8
10
  @observer_queues[queue] = [/:\S+ (331|332|403|442) \S+ #{Regexp.escape(channel)} :/i]
9
11
  raw "TOPIC #{channel}"
10
-
12
+
11
13
  topic = begin
12
- Timeout::timeout(30) do
13
- response = queue.pop
14
- raw_numeric = response.scan(/^:\S+ (\d{3})/)[0][0]
15
-
16
- case raw_numeric
17
- when '331'
18
- {:raw_numeric => 331, :message => 'No topic is set'}
19
- when '332'
20
- {:raw_numeric => 332, :message => response.scan(/ :(.*)/)[0][0]}
21
- when '403'
22
- {:raw_numeric => 403, :message => 'No such channel'}
23
- when '442'
24
- {:raw_numeric => 442, :message => "You're not on that channel"}
25
- end
14
+ Timeout::timeout(TIMEOUT) do
15
+ response = queue.pop
16
+ raw_numeric = response.scan(/^:\S+ (\d{3})/)[0][0]
17
+
18
+ case raw_numeric
19
+ when '331'
20
+ {:raw_numeric => 331, :message => 'No topic is set'}
21
+ when '332'
22
+ {:raw_numeric => 332, :message => response.scan(/ :(.*)/)[0][0]}
23
+ when '403'
24
+ {:raw_numeric => 403, :message => 'No such channel'}
25
+ when '442'
26
+ {:raw_numeric => 442, :message => "You're not on that channel"}
27
+ end
26
28
  end
27
29
  rescue Timeout::Error
28
30
  false
29
31
  end
30
-
32
+
31
33
  @observer_queues.delete queue
32
34
  return topic
33
35
  end
34
-
36
+
35
37
  def channel_info(channel)
36
38
  queue = Queue.new
37
- @observer_queues[queue] = [/:\S+ (324|329|403) \S+ #{Regexp.escape(channel)}/i]
39
+ @observer_queues[queue] = [/:\S+ (324|329|403|442) \S+ #{Regexp.escape(channel)}/i]
38
40
  raw "MODE #{channel}"
39
41
  information = {}
40
42
  running = true
41
-
43
+
42
44
  begin
43
- Timeout::timeout(30) do
45
+ Timeout::timeout(TIMEOUT) do
44
46
  while running
45
47
  response = queue.pop
46
48
  raw_numeric = response.scan(/^:\S+ (\d{3})/)[0][0]
47
-
48
- case raw_numeric
49
- when '324'
50
- information[:modes] = response.scan(/^:\S+ 324 \S+ \S+ \+(\w*)/)[0][0].split('')
51
- limit = response.scan(/^:\S+ 324 \S+ \S+ \+\w* (\w*)/)[0]
52
- information[:channel_limit] = limit[0].to_i if limit
53
- when '329'
54
- information[:created_at] = Time.at(response.scan(/^:\S+ 329 \S+ \S+ (\d+)/)[0][0].to_i)
55
- running = false
56
- when '403'
57
- information = false
58
- running = false
59
- end
60
- end
49
+
50
+ case raw_numeric
51
+ when '324'
52
+ information[:modes] = response.scan(/^:\S+ 324 \S+ \S+ \+(\w*)/)[0][0].split('')
53
+ limit = response.scan(/^:\S+ 324 \S+ \S+ \+\w* (\w*)/)[0]
54
+ information[:channel_limit] = limit[0].to_i if limit
55
+ when '329'
56
+ information[:created_at] = Time.at(response.scan(/^:\S+ 329 \S+ \S+ (\d+)/)[0][0].to_i)
57
+ running = false
58
+ when '403', '442'
59
+ information = false
60
+ running = false
61
+ end
62
+ end
61
63
  end
62
64
  rescue Timeout::Error
63
65
  information = false
64
66
  end
65
-
67
+
66
68
  @observer_queues.delete queue
67
69
  return information
68
70
  end
69
-
71
+
70
72
  def whois(nick)
71
73
  queue = Queue.new
72
- @observer_queues[queue] = [/^:\S+ (307|311|312|318|319|401) \S+ #{Regexp.escape(nick)}/i]
74
+ @observer_queues[queue] = [/^:\S+ (307|311|312|318|319|330|401) \S+ #{Regexp.escape(nick)}/i]
73
75
  raw "WHOIS #{nick}"
74
76
  whois = {}
75
77
  running = true
76
-
77
- while running
78
- begin
79
- Timeout::timeout(30) do
80
- response = queue.pop
81
- raw_numeric = response.scan(/^:\S+ (\d{3})/)[0][0]
82
-
83
- case raw_numeric
84
- when '307'
85
- whois[:registered] = true
86
- when '311'
87
- response = response.scan(/^:\S+ 311 \S+ (\S+) (\S+) (\S+) \* :(.*)$/)[0]
88
- whois[:nick] = response[0]
89
- whois[:username] = response[1]
90
- whois[:host] = response[2]
91
- whois[:real_name] = response[3]
92
- when '312'
93
- response = response.scan(/^:\S+ 312 \S+ \S+ (\S+) :(.*)/)[0]
94
- whois[:server] = {:address => response[0], :name => response[1]}
95
- when '318'
96
- running = false
97
- when '319'
98
- channels_with_mode = response.scan(/^:\S+ 319 \S+ \S+ :(.*)/)[0][0].split(' ')
99
- whois[:channels] = {}
100
- channels_with_mode.each do |c|
101
- whois[:channels][c.scan(/(.)?(#\S+)/)[0][1]] = c.scan(/(.)?(#\S+)/)[0][0]
102
- end
103
- when '401'
104
- whois = false
105
- running = false
106
- end
78
+
79
+ begin
80
+ Timeout::timeout(TIMEOUT) do
81
+ while running
82
+ response = queue.pop
83
+ raw_numeric = response.scan(/^:\S+ (\d{3})/)[0][0]
84
+
85
+ case raw_numeric
86
+ when '307', '330'
87
+ whois[:registered] = true
88
+ when '311'
89
+ response = response.scan(/^:\S+ 311 \S+ (\S+) :?(\S+) (\S+) \* :(.*)$/)[0]
90
+ whois[:nick] = response[0]
91
+ whois[:username] = response[1]
92
+ whois[:host] = response[2]
93
+ whois[:real_name] = response[3]
94
+ when '312'
95
+ response = response.scan(/^:\S+ 312 \S+ \S+ (\S+) :(.*)/)[0]
96
+ whois[:server] = {:address => response[0], :name => response[1]}
97
+ when '318'
98
+ running = false
99
+ when '319'
100
+ channels_with_mode = response.scan(/^:\S+ 319 \S+ \S+ :(.*)/)[0][0].split(' ')
101
+ whois[:channels] = {}
102
+ channels_with_mode.each do |c|
103
+ whois[:channels][c.scan(/(.)?(#\S+)/)[0][1]] = c.scan(/(.)?(#\S+)/)[0][0]
104
+ end
105
+ when '401'
106
+ whois = false
107
+ running = false
108
+ end
107
109
  end
108
- rescue Timeout::Error
109
- nil
110
110
  end
111
+ rescue Timeout::Error
112
+ nil
111
113
  end
112
-
114
+
113
115
  @observer_queues.delete queue
114
116
  return whois
115
117
  end
116
118
  end
117
119
  end
120
+
@@ -27,9 +27,7 @@ module Ponder
27
27
  reconnect @thaum.config.server, @thaum.config.port
28
28
  end
29
29
  else
30
- EventMachine::stop_event_loop
31
30
  @thaum.logger.close
32
- @thaum.console_logger.close
33
31
  end
34
32
  end
35
33
 
@@ -12,7 +12,7 @@ module Ponder
12
12
  include IRC
13
13
  include AsyncIRC
14
14
 
15
- attr_reader :config
15
+ attr_reader :config, :callbacks
16
16
  attr_accessor :connected, :logger, :console_logger
17
17
 
18
18
  def initialize
@@ -46,7 +46,7 @@ module Ponder
46
46
  end
47
47
 
48
48
  on :query, /^\001VERSION\001$/ do |event_data|
49
- notice event_data[:nick], "\001VERSION Ponder #{Ponder::VERSION} (http://github.com/tbuehlmann/ponder)\001"
49
+ notice event_data[:nick], "\001VERSION Ponder #{Ponder::VERSION} (https://github.com/tbuehlmann/ponder)\001"
50
50
  end
51
51
 
52
52
  on :query, /^\001TIME\001$/ do |event_data|
@@ -1,4 +1,4 @@
1
1
  module Ponder
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  end
4
4
 
@@ -5,7 +5,7 @@ require 'lib/ponder/version'
5
5
  Gem::Specification.new do |s|
6
6
  s.name = 'ponder'
7
7
  s.version = Ponder::VERSION
8
- s.date = '2011-01-29'
8
+ s.date = '2011-05-19'
9
9
  s.summary = 'IRC bot framework'
10
10
  s.description = 'Ponder (Stibbons) is a Domain Specific Language for writing IRC Bots using the EventMachine library.'
11
11
 
@@ -15,6 +15,7 @@ Gem::Specification.new do |s|
15
15
 
16
16
  s.required_ruby_version = '>= 1.8.6'
17
17
  s.add_dependency('eventmachine', '>= 0.12.10')
18
+ s.add_development_dependency('rspec')
18
19
  s.files = %w[
19
20
  LICENSE
20
21
  README.md
@@ -34,10 +35,11 @@ Gem::Specification.new do |s|
34
35
  lib/ponder/thaum.rb
35
36
  lib/ponder/version.rb
36
37
  ponder.gemspec
37
- test/test_async_irc.rb
38
- test/test_callback.rb
39
- test/test_helper.rb
40
- test/test_irc.rb
38
+ spec/async_irc_spec.rb
39
+ spec/callback_spec.rb
40
+ spec/irc_spec.rb
41
+ spec/spec_helper.rb
42
+ spec/thaum_spec.rb
41
43
  ]
42
44
  end
43
45
 
@@ -0,0 +1,145 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require 'spec_helper'
4
+ require 'ponder/thaum'
5
+
6
+ describe Ponder::AsyncIRC do
7
+ PERIODIC_TIME = 0.01
8
+
9
+ before(:each) do
10
+ @ponder = Ponder::Thaum.new
11
+ @ponder.configure { |c| c.verbose = false }
12
+ end
13
+
14
+ context 'tries to get a topic when' do
15
+ it 'there is no topic set' do
16
+ @ponder.should_receive(:raw).with('TOPIC #channel')
17
+ EM.run do
18
+ EM.defer(Proc.new { @result = @ponder.get_topic('#channel') }, Proc.new { EM.schedule { EM.stop } })
19
+ EM::PeriodicTimer.new(PERIODIC_TIME) { @ponder.parse(":server 331 Ponder #channel :No topic is set.\r\n") }
20
+ end
21
+ @result.should eql({:raw_numeric => 331, :message => 'No topic is set'})
22
+ end
23
+
24
+ it 'there is no topic set' do
25
+ @ponder.should_receive(:raw).with('TOPIC #channel')
26
+ EM.run do
27
+ EM.defer(Proc.new { @result = @ponder.get_topic('#channel') }, Proc.new { EM.schedule { EM.stop } })
28
+ EM::PeriodicTimer.new(PERIODIC_TIME) { @ponder.parse(":server 332 Ponder #channel :topic content\r\n") }
29
+ end
30
+ @result.should eql({:raw_numeric => 332, :message => 'topic content'})
31
+ end
32
+
33
+ it 'there is no such channel' do
34
+ @ponder.should_receive(:raw).with('TOPIC #no_channel')
35
+ EM.run do
36
+ EM.defer(Proc.new { @result = @ponder.get_topic('#no_channel') }, Proc.new { EM.schedule { EM.stop } })
37
+ EM::PeriodicTimer.new(PERIODIC_TIME) { @ponder.parse(":server 403 Ponder #no_channel :No such channel\r\n") }
38
+ end
39
+ @result.should eql({:raw_numeric => 403, :message => 'No such channel'})
40
+ end
41
+
42
+ it "you're not on that channel" do
43
+ @ponder.should_receive(:raw).with('TOPIC #channel')
44
+ EM.run do
45
+ EM.defer(Proc.new { @result = @ponder.get_topic('#channel') }, Proc.new { EM.schedule { EM.stop } })
46
+ EM::PeriodicTimer.new(PERIODIC_TIME) { @ponder.parse(":server 442 Ponder #channel :You're not on that channel\r\n") }
47
+ end
48
+ @result.should eql({:raw_numeric => 442, :message => "You're not on that channel"})
49
+ end
50
+ end
51
+
52
+ context 'it tries to get channel information when' do
53
+ it 'there is no such channel' do
54
+ @ponder.should_receive(:raw).with('MODE #no_channel')
55
+ EM.run do
56
+ EM.defer(Proc.new { @result = @ponder.channel_info('#no_channel') }, Proc.new { EM.schedule { EM.stop } })
57
+ EM::PeriodicTimer.new(PERIODIC_TIME) { @ponder.parse(":server 403 Ponder #no_channel :No such channel\r\n") }
58
+ end
59
+ @result.should be_false
60
+ end
61
+
62
+ it "you're not on that channel" do
63
+ @ponder.should_receive(:raw).with('MODE #channel')
64
+ EM.run do
65
+ EM.defer(Proc.new { @result = @ponder.channel_info('#channel') }, Proc.new { EM.schedule { EM.stop } })
66
+ EM::PeriodicTimer.new(PERIODIC_TIME) { @ponder.parse(":server 442 Ponder #channel :You're not on that channel\r\n") }
67
+ end
68
+ @result.should be_false
69
+ end
70
+
71
+ it "there are regular channel modes" do
72
+ @ponder.should_receive(:raw).with('MODE #channel')
73
+ EM.run do
74
+ EM.defer(Proc.new { @result = @ponder.channel_info('#channel') }, Proc.new { EM.schedule { EM.stop } })
75
+ EM::PeriodicTimer.new(PERIODIC_TIME) do
76
+ @ponder.parse(":server 324 Ponder #channel +cnst\r\n")
77
+ @ponder.parse(":server 329 Ponder #channel 1233034048\r\n")
78
+ end
79
+ end
80
+ @result.should be_kind_of(Hash)
81
+ @result[:modes].should include('c', 'n', 's', 't')
82
+ @result[:created_at].should eql(Time.at(1233034048))
83
+ end
84
+
85
+ it "there are regular channel modes with a limit" do
86
+ @ponder.should_receive(:raw).with('MODE #channel')
87
+ EM.run do
88
+ EM.defer(Proc.new { @result = @ponder.channel_info('#channel') }, Proc.new { EM.schedule { EM.stop } })
89
+ EM::PeriodicTimer.new(PERIODIC_TIME) do
90
+ @ponder.parse(":server 324 Ponder #channel +cnstl 8\r\n")
91
+ @ponder.parse(":server 329 Ponder #channel 1233034048\r\n")
92
+ end
93
+ end
94
+ @result.should be_kind_of(Hash)
95
+ @result[:modes].should include('c', 'n', 's', 't')
96
+ @result[:created_at].should eql(Time.at(1233034048))
97
+ @result[:channel_limit].should equal(8)
98
+ end
99
+ end
100
+
101
+ context 'tries to get whois information when' do
102
+ it 'there is no such nick' do
103
+ @ponder.should_receive(:raw).with('WHOIS not_online')
104
+ EM.run do
105
+ EM.defer(Proc.new { @result = @ponder.whois('not_online') }, Proc.new { EM.schedule { EM.stop } })
106
+ EM::PeriodicTimer.new(PERIODIC_TIME) { @ponder.parse(":server 401 Ponder not_online :No such nick\r\n") }
107
+ end
108
+ @result.should be_false
109
+ end
110
+
111
+ it 'the user is online' do
112
+ @ponder.should_receive(:raw).with('WHOIS Ridcully')
113
+ EM.run do
114
+ EM.defer(Proc.new { @result = @ponder.whois('Ridcully') }, Proc.new { EM.schedule { EM.stop } })
115
+ EM::PeriodicTimer.new(PERIODIC_TIME) do
116
+ @ponder.parse(":server 311 Ponder Ridcully :ridc host * :Ridcully the wizard\r\n")
117
+ @ponder.parse(":server 312 Ponder Ridcully foo.host.net :That host thing\r\n")
118
+ @ponder.parse(":server 319 Ponder Ridcully :#foo ##bar <#baz @#sushi +#ramen\r\n")
119
+ @ponder.parse(":server 330 Ponder Ridcully rid_ :is logged in as\r\n")
120
+ @ponder.parse(":server 318 Ponder Ridcully :End of /WHOIS list.\r\n")
121
+ end
122
+ end
123
+
124
+ @result.should be_kind_of(Hash)
125
+ @result[:nick].should eql('Ridcully')
126
+ @result[:username].should eql('ridc')
127
+ @result[:host].should eql('host')
128
+ @result[:real_name].should eql('Ridcully the wizard')
129
+
130
+ @result[:server].should be_kind_of(Hash)
131
+ @result[:server][:address].should eql('foo.host.net')
132
+ @result[:server][:name].should eql('That host thing')
133
+
134
+ @result[:channels].should be_kind_of(Hash)
135
+ @result[:channels]['#foo'].should be_nil
136
+ @result[:channels]['##bar'].should be_nil
137
+ @result[:channels]['#baz'].should eql('<')
138
+ @result[:channels]['#sushi'].should eql('@')
139
+ @result[:channels]['#ramen'].should eql('+')
140
+
141
+ @result[:registered].should be_true
142
+ end
143
+ end
144
+ end
145
+
@@ -0,0 +1,68 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require 'spec_helper'
4
+ require 'ponder/thaum'
5
+
6
+ describe Ponder::Callback do
7
+ before(:all) { @proc = Proc.new { } }
8
+
9
+ before(:each) do
10
+ @ponder = Ponder::Thaum.new
11
+ @ponder.configure { |c| c.verbose = true }
12
+ end
13
+
14
+ context 'tries to create a callback' do
15
+ it 'with valid arguments' do
16
+ lambda { Ponder::Callback.new(:channel, /foo/, @proc) }.should_not raise_error
17
+ end
18
+
19
+ it 'with an invalid type' do
20
+ lambda { Ponder::Callback.new(:invalid, /foo/, @proc) }.should raise_error(TypeError)
21
+ end
22
+
23
+ it 'with an invalid match' do
24
+ lambda { Ponder::Callback.new(:channel, 8, @proc) }.should raise_error(TypeError)
25
+ end
26
+
27
+ it 'with an invalid proc' do
28
+ lambda { Ponder::Callback.new(:channel, /foo/, 8) }.should raise_error(TypeError)
29
+ end
30
+ end
31
+
32
+ it "calls the callback's proc on right match" do
33
+ callback = Ponder::Callback.new(:channel, /wizzard/, Proc.new { 8 })
34
+ callback.call(:channel, {:message => 'I like wizzards'}).should eql(8)
35
+ end
36
+
37
+ it "does not call the callback's proc on the wrong match" do
38
+ p = Proc.new { 8 }
39
+ p.should_not_receive(:call)
40
+ callback = Ponder::Callback.new(:channel, /wizzard/, p)
41
+ callback.call(:channel, {:message => 'I like hot dogs'}).should be_nil
42
+ end
43
+
44
+ it "calls the callback's proc on the right match and the right event type" do
45
+ # `@proc.should_receive(:call).once` does not work here in 1.8.7
46
+ proc = Proc.new { @called = true }
47
+ @ponder.on(:channel, /wizzard/, &proc)
48
+ EM.run do
49
+ @ponder.process_callbacks(:channel, {:message => 'I like wizzards'})
50
+ EM.schedule { EM.stop }
51
+ end
52
+
53
+ @called.should be_true
54
+ end
55
+
56
+ it "calls the callback's proc on the right match and the right event type with multiple types" do
57
+ # `@proc.should_receive(:call).once` does not work here in 1.8.7
58
+ proc = Proc.new { @called = true }
59
+ @ponder.on([:channel, :query], /wizzard/, &proc)
60
+ EM.run do
61
+ @ponder.process_callbacks(:query, {:message => 'I like wizzards'})
62
+ EM.schedule { EM.stop }
63
+ end
64
+
65
+ @called.should be_true
66
+ end
67
+ end
68
+
@@ -0,0 +1,131 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require 'spec_helper'
4
+ require 'ponder/thaum'
5
+
6
+ describe Ponder::IRC do
7
+ before(:each) do
8
+ @ponder = Ponder::Thaum.new
9
+ @ponder.configure do |c|
10
+ c.nick = 'Ponder'
11
+ c.username = 'Ponder'
12
+ c.real_name = 'Ponder Stibbons'
13
+ c.reconnect = true
14
+ end
15
+ end
16
+
17
+ it 'sends a message to a recipient' do
18
+ @ponder.should_receive(:raw).with('PRIVMSG recipient :foo bar baz').once
19
+ @ponder.message('recipient', 'foo bar baz')
20
+ end
21
+
22
+ it 'registers with the server' do
23
+ @ponder.should_receive(:raw).with('NICK Ponder').once
24
+ @ponder.should_receive(:raw).with('USER Ponder * * :Ponder Stibbons').once
25
+ @ponder.register
26
+ end
27
+
28
+ it 'registers with the server with a password' do
29
+ @ponder.should_receive(:raw).with('NICK Ponder').once
30
+ @ponder.should_receive(:raw).with('USER Ponder * * :Ponder Stibbons').once
31
+ @ponder.should_receive(:raw).with('PASS secret').once
32
+ @ponder.configure { |c| c.password = 'secret' }
33
+ @ponder.register
34
+ end
35
+
36
+ it 'sends a notice to a recipient' do
37
+ @ponder.should_receive(:raw).with('NOTICE Ponder :You are cool!').once
38
+ @ponder.notice('Ponder', 'You are cool!')
39
+ end
40
+
41
+ it 'sets a mode' do
42
+ @ponder.should_receive(:raw).with('MODE Ponder +ao').once
43
+ @ponder.mode('Ponder', '+ao')
44
+ end
45
+
46
+ it 'kicks an user from a channel' do
47
+ @ponder.should_receive(:raw).with('KICK #channel Nanny_Ogg').once
48
+ @ponder.kick('#channel', 'Nanny_Ogg')
49
+ end
50
+
51
+ it 'kicks an user from a channel with a reason' do
52
+ @ponder.should_receive(:raw).with('KICK #channel Nanny_Ogg :Go away!').once
53
+ @ponder.kick('#channel', 'Nanny_Ogg', 'Go away!')
54
+ end
55
+
56
+ it 'performs an action' do
57
+ @ponder.should_receive(:raw).with("PRIVMSG #channel :\001ACTION HEX is working!\001").once
58
+ @ponder.action('#channel', 'HEX is working!')
59
+ end
60
+
61
+ it 'sets the topic for a channel' do
62
+ @ponder.should_receive(:raw).with('TOPIC #channel :I like dried frog pills.').once
63
+ @ponder.topic('#channel', 'I like dried frog pills.')
64
+ end
65
+
66
+ it 'joins a channel' do
67
+ @ponder.should_receive(:raw).with('JOIN #channel').once
68
+ @ponder.join('#channel')
69
+ end
70
+
71
+ it 'joins a channel with password' do
72
+ @ponder.should_receive(:raw).with('JOIN #channel secret').once
73
+ @ponder.join('#channel', 'secret')
74
+ end
75
+
76
+ it 'parts a channel' do
77
+ @ponder.should_receive(:raw).with('PART #channel').once
78
+ @ponder.part('#channel')
79
+ end
80
+
81
+ it 'parts a channel with a message' do
82
+ @ponder.should_receive(:raw).with('PART #channel :Partpart').once
83
+ @ponder.part('#channel', 'Partpart')
84
+ end
85
+
86
+ it 'quits from the server' do
87
+ @ponder.should_receive(:raw).with('QUIT').once
88
+ @ponder.config.reconnect.should eql(true)
89
+ @ponder.quit
90
+ @ponder.config.reconnect.should eql(false)
91
+ end
92
+
93
+ it 'quits from the server with a message' do
94
+ @ponder.should_receive(:raw).with('QUIT :Gone!').once
95
+ @ponder.config.reconnect.should eql(true)
96
+ @ponder.quit('Gone!')
97
+ @ponder.config.reconnect.should eql(false)
98
+ end
99
+
100
+ it 'renames itself' do
101
+ @ponder.should_receive(:raw).with('NICK :Ridcully').once
102
+ @ponder.rename('Ridcully')
103
+ end
104
+
105
+ it 'goes away' do
106
+ @ponder.should_receive(:raw).with('AWAY').once
107
+ @ponder.away
108
+ end
109
+
110
+ it 'goes away with a reason' do
111
+ @ponder.should_receive(:raw).with('AWAY :At the Mended Drum').once
112
+ @ponder.away('At the Mended Drum')
113
+ end
114
+
115
+ it 'comes back from its absence' do
116
+ @ponder.should_receive(:raw).with('AWAY').twice
117
+ @ponder.away
118
+ @ponder.back
119
+ end
120
+
121
+ it 'invites an user to a channel' do
122
+ @ponder.should_receive(:raw).with('INVITE TheLibrarian #mended_drum').once
123
+ @ponder.invite('TheLibrarian', '#mended_drum')
124
+ end
125
+
126
+ it 'bans an user from a channel' do
127
+ @ponder.should_receive(:raw).with('MODE #mended_drum +b foo!bar@baz').once
128
+ @ponder.ban('#mended_drum', 'foo!bar@baz')
129
+ end
130
+ end
131
+
@@ -1,5 +1,6 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
 
4
- require 'test/unit'
4
+ require 'rubygems'
5
+ require 'rspec'
5
6
 
@@ -0,0 +1,63 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require 'spec_helper'
4
+ require 'ponder'
5
+
6
+ describe Ponder::Thaum do
7
+ before(:each) do
8
+ @ponder = Ponder::Thaum.new
9
+ end
10
+
11
+ it 'sets a default configuration without calling the #configure method' do
12
+ @ponder.config.server.should eql('localhost')
13
+ @ponder.config.port.should equal(6667)
14
+ @ponder.config.nick.should eql('Ponder')
15
+ @ponder.config.username.should eql('Ponder')
16
+ @ponder.config.real_name.should eql('Ponder')
17
+ @ponder.config.verbose.should be_true
18
+ @ponder.config.logging.should be_false
19
+ @ponder.config.reconnect.should be_true
20
+ @ponder.config.reconnect_interval.should equal(30)
21
+
22
+ @ponder.logger.should be_an_instance_of(Ponder::BlindIo)
23
+ @ponder.console_logger.should be_an_instance_of(Ponder::Twoflogger)
24
+ end
25
+
26
+ it 'sets the logger correctly' do
27
+ FileUtils.stub!(:mkdir_p)
28
+ Ponder::Twoflogger.should_receive(:new)
29
+ @ponder.configure { |c| c.logging = true }
30
+ end
31
+
32
+ it 'sets default callbacks' do
33
+ @ponder.callbacks.should have(3)[:query]
34
+ end
35
+
36
+ context 'creates a correct default callback for' do
37
+ it 'PING PONG' do
38
+ time = Time.now.to_i
39
+ @ponder.should_receive(:notice).with('Peter', "\001PING #{time}\001")
40
+ EM.run do
41
+ @ponder.process_callbacks(:query, {:nick => 'Peter', :message => "\001PING #{time}\001"})
42
+ EM.schedule { EM.stop }
43
+ end
44
+ end
45
+
46
+ it 'VERSION' do
47
+ @ponder.should_receive(:notice).with('Peter', "\001VERSION Ponder #{Ponder::VERSION} (https://github.com/tbuehlmann/ponder)\001")
48
+ EM.run do
49
+ @ponder.process_callbacks(:query, {:nick => 'Peter', :message => "\001VERSION\001"})
50
+ EM.schedule { EM.stop }
51
+ end
52
+ end
53
+
54
+ it 'TIME' do
55
+ @ponder.should_receive(:notice).with('Peter', "\001TIME #{Time.now.strftime('%a %b %d %H:%M:%S %Y')}\001")
56
+ EM.run do
57
+ @ponder.process_callbacks(:query, {:nick => 'Peter', :message => "\001TIME\001"})
58
+ EM.schedule { EM.stop }
59
+ end
60
+ end
61
+ end
62
+ end
63
+
metadata CHANGED
@@ -1,48 +1,45 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: ponder
3
- version: !ruby/object:Gem::Version
4
- hash: 27
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 1
9
- - 0
10
- version: 0.1.0
11
6
  platform: ruby
12
- authors:
13
- - "Tobias B\xC3\xBChlmann"
7
+ authors:
8
+ - Tobias Bühlmann
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-01-29 00:00:00 +01:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2011-05-19 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: eventmachine
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &16716980 !ruby/object:Gem::Requirement
25
17
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 59
30
- segments:
31
- - 0
32
- - 12
33
- - 10
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
34
21
  version: 0.12.10
35
22
  type: :runtime
36
- version_requirements: *id001
37
- description: Ponder (Stibbons) is a Domain Specific Language for writing IRC Bots using the EventMachine library.
23
+ prerelease: false
24
+ version_requirements: *16716980
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &16716600 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *16716600
36
+ description: Ponder (Stibbons) is a Domain Specific Language for writing IRC Bots
37
+ using the EventMachine library.
38
38
  email: tobias.buehlmann@gmx.de
39
39
  executables: []
40
-
41
40
  extensions: []
42
-
43
41
  extra_rdoc_files: []
44
-
45
- files:
42
+ files:
46
43
  - LICENSE
47
44
  - README.md
48
45
  - Rakefile
@@ -61,45 +58,33 @@ files:
61
58
  - lib/ponder/thaum.rb
62
59
  - lib/ponder/version.rb
63
60
  - ponder.gemspec
64
- - test/test_async_irc.rb
65
- - test/test_callback.rb
66
- - test/test_helper.rb
67
- - test/test_irc.rb
68
- has_rdoc: true
61
+ - spec/async_irc_spec.rb
62
+ - spec/callback_spec.rb
63
+ - spec/irc_spec.rb
64
+ - spec/spec_helper.rb
65
+ - spec/thaum_spec.rb
69
66
  homepage: http://github.com/tbuehlmann/ponder
70
67
  licenses: []
71
-
72
68
  post_install_message:
73
69
  rdoc_options: []
74
-
75
- require_paths:
70
+ require_paths:
76
71
  - lib
77
- required_ruby_version: !ruby/object:Gem::Requirement
72
+ required_ruby_version: !ruby/object:Gem::Requirement
78
73
  none: false
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- hash: 59
83
- segments:
84
- - 1
85
- - 8
86
- - 6
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
87
77
  version: 1.8.6
88
- required_rubygems_version: !ruby/object:Gem::Requirement
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
79
  none: false
90
- requirements:
91
- - - ">="
92
- - !ruby/object:Gem::Version
93
- hash: 3
94
- segments:
95
- - 0
96
- version: "0"
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
97
84
  requirements: []
98
-
99
85
  rubyforge_project:
100
- rubygems_version: 1.4.1
86
+ rubygems_version: 1.7.2
101
87
  signing_key:
102
88
  specification_version: 3
103
89
  summary: IRC bot framework
104
90
  test_files: []
105
-
@@ -1,103 +0,0 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
-
3
- require 'test_helper'
4
- require 'ponder/async_irc'
5
-
6
- include Ponder::AsyncIRC
7
- def raw(*args)
8
- end
9
-
10
- class TestAsyncIRC < Test::Unit::TestCase
11
- def setup
12
- @observer_queues = {}
13
- end
14
-
15
- def test_get_topic_no_topic_set
16
- topic = Thread.new do
17
- assert_equal({:raw_numeric => 331, :message => 'No topic is set'}, get_topic('#mended_drum'))
18
- end
19
-
20
- event_loop = Thread.new do
21
- loop do
22
- message = ':server 331 Ponder #mended_drum :No topic is set.'
23
- @observer_queues.each do |queue, regexps|
24
- regexps.each do |regexp|
25
- if message =~ regexp
26
- queue << message
27
- end
28
- end
29
- end
30
-
31
- sleep 0.1
32
- end
33
- end
34
- topic.join
35
- end
36
-
37
- def test_get_topic
38
- topic = Thread.new do
39
- assert_equal({:raw_numeric => 332, :message => 'No dwarfs in here!'}, get_topic('#mended_drum'))
40
- end
41
-
42
- event_loop = Thread.new do
43
- loop do
44
- message = ':server 332 Ponder #mended_drum :No dwarfs in here!'
45
- @observer_queues.each do |queue, regexps|
46
- regexps.each do |regexp|
47
- if message =~ regexp
48
- queue << message
49
- end
50
- end
51
- end
52
-
53
- sleep 0.1
54
- end
55
- end
56
- topic.join
57
- end
58
-
59
- def test_get_topic_no_such_channel
60
- topic = Thread.new do
61
- assert_equal({:raw_numeric => 403, :message => 'No such channel'}, get_topic('#mended_drum'))
62
- end
63
-
64
- event_loop = Thread.new do
65
- loop do
66
- message = ':server 403 Ponder #mended_drum :No such channel'
67
- @observer_queues.each do |queue, regexps|
68
- regexps.each do |regexp|
69
- if message =~ regexp
70
- queue << message
71
- end
72
- end
73
- end
74
-
75
- sleep 0.1
76
- end
77
- end
78
- topic.join
79
- end
80
-
81
- def test_get_topic_you_are_not_on_that_channel
82
- topic = Thread.new do
83
- assert_equal({:raw_numeric => 442, :message => "You're not on that channel"}, get_topic('#mended_drum'))
84
- end
85
-
86
- event_loop = Thread.new do
87
- loop do
88
- message = ":server 442 Ponder #mended_drum :You're not on that channel"
89
- @observer_queues.each do |queue, regexps|
90
- regexps.each do |regexp|
91
- if message =~ regexp
92
- queue << message
93
- end
94
- end
95
- end
96
-
97
- sleep 0.1
98
- end
99
- end
100
- topic.join
101
- end
102
- end
103
-
@@ -1,55 +0,0 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
-
3
- require 'test_helper'
4
- require 'ponder/callback'
5
-
6
- module Ponder
7
- class Callback
8
- attr_reader :event_type, :match, :proc
9
- end
10
- end
11
-
12
- class TestCallback < Test::Unit::TestCase
13
- def setup
14
- @empty_proc = Proc.new { }
15
- end
16
-
17
- def test_perfect_case
18
- callback = Ponder::Callback.new(:channel, /foo/, @empty_proc)
19
-
20
- assert_equal(/foo/, callback.match)
21
- assert_equal(@empty_proc, callback.proc)
22
- end
23
-
24
- def test_unsupported_event_type
25
- assert_raise(TypeError) do
26
- Ponder::Callback.new('fu', /foo/, @empty_proc)
27
- end
28
- end
29
-
30
- def test_regexp
31
- assert_raise(TypeError) do
32
- Ponder::Callback.new(:channel, 8, @empty_proc)
33
- end
34
- end
35
-
36
- def test_proc
37
- assert_raise(TypeError) do
38
- Ponder::Callback.new(:channel, /foo/, 8)
39
- end
40
- end
41
-
42
- def test__trivial_proc
43
- proc = Proc.new { 7 + 1 }
44
-
45
- assert_equal(proc, Ponder::Callback.new(:channel, //, proc).proc)
46
- end
47
-
48
- def test_call
49
- proc = Proc.new { 8 }
50
-
51
- assert_equal(8, Ponder::Callback.new(:channel, /wizzard/, proc).call(:channel, {:message => 'I like wizzards'}))
52
- assert_nil(Ponder::Callback.new(:channel, /wizzard/, proc).call(:channel, {:message => 'I am a wizard'}))
53
- end
54
- end
55
-
@@ -1,129 +0,0 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
-
3
- require 'test_helper'
4
- require 'ponder/thaum'
5
-
6
- class TestIRC < Test::Unit::TestCase
7
- def setup
8
- @ponder = Ponder::Thaum.new
9
-
10
- @ponder.configure do |c|
11
- c.nick = 'Ponder'
12
- c.username = 'Ponder'
13
- c.real_name = 'Ponder Stibbons'
14
- c.password = 'secret'
15
- c.reconnect = true
16
- end
17
-
18
- def @ponder.raw(message)
19
- $output << "#{message}\r\n"
20
- return "#{message}\r\n"
21
- end
22
-
23
- $output = []
24
- end
25
-
26
- def test_message
27
- assert_equal("PRIVMSG recipient :foo bar baz\r\n", @ponder.message('recipient', 'foo bar baz'))
28
- end
29
-
30
- def test_register
31
- @ponder.register
32
-
33
- assert_equal(["NICK Ponder\r\n", "USER Ponder * * :Ponder Stibbons\r\n", "PASS secret\r\n"], $output)
34
- end
35
-
36
- def test_register_without_password
37
- @ponder.configure { |c| c.password = nil }
38
-
39
- @ponder.register
40
-
41
- assert_equal(["NICK Ponder\r\n", "USER Ponder * * :Ponder Stibbons\r\n"], $output)
42
- end
43
-
44
- def test_notice
45
- assert_equal("NOTICE Ponder :You are cool!\r\n", @ponder.notice('Ponder', 'You are cool!'))
46
- end
47
-
48
- def test_mode
49
- assert_equal("MODE Ponder +ao\r\n", @ponder.mode('Ponder', '+ao'))
50
- end
51
-
52
- def test_kick
53
- assert_equal("KICK #channel Nanny_Ogg\r\n", @ponder.kick('#channel', 'Nanny_Ogg'))
54
- end
55
-
56
- def test_kick_with_reason
57
- assert_equal("KICK #channel Nanny_Ogg :Go away!\r\n", @ponder.kick('#channel', 'Nanny_Ogg', 'Go away!'))
58
- end
59
-
60
- def test_action
61
- assert_equal("PRIVMSG #channel :\001ACTION HEX is working!\001\r\n", @ponder.action('#channel', 'HEX is working!'))
62
- end
63
-
64
- def test_topic
65
- assert_equal("TOPIC #channel :I like dried frog pills.\r\n", @ponder.topic('#channel', 'I like dried frog pills.'))
66
- end
67
-
68
- def test_join
69
- assert_equal("JOIN #channel\r\n", @ponder.join('#channel'))
70
- end
71
-
72
- def test_join_with_password
73
- assert_equal("JOIN #channel secret\r\n", @ponder.join('#channel', 'secret'))
74
- end
75
-
76
- def test_part
77
- assert_equal("PART #channel\r\n", @ponder.part('#channel'))
78
- end
79
-
80
- def test_part_with_message
81
- assert_equal("PART #channel :Partpart\r\n", @ponder.part('#channel', 'Partpart'))
82
- end
83
-
84
- def test_quit
85
-
86
- @ponder.quit
87
-
88
- assert_equal(["QUIT\r\n"], $output)
89
- end
90
-
91
- def test_quit_with_message
92
- @ponder.quit('GONE')
93
-
94
- assert_equal(["QUIT :GONE\r\n"], $output)
95
- end
96
-
97
- def test_quit_reconnect_change
98
- assert_equal(true, @ponder.config.reconnect)
99
-
100
- @ponder.quit
101
-
102
- assert_equal(false, @ponder.config.reconnect)
103
- end
104
-
105
- def test_rename
106
- assert_equal("NICK :Ridcully\r\n", @ponder.rename('Ridcully'))
107
- end
108
-
109
- def test_away
110
- assert_equal("AWAY\r\n", @ponder.away)
111
- end
112
-
113
- def test_away_with_message
114
- assert_equal("AWAY :At the Mended Drum\r\n", @ponder.away('At the Mended Drum'))
115
- end
116
-
117
- def test_back
118
- assert_equal("AWAY\r\n", @ponder.back)
119
- end
120
-
121
- def test_invite
122
- assert_equal("INVITE TheLibrarian #mended_drum\r\n", @ponder.invite('TheLibrarian', '#mended_drum'))
123
- end
124
-
125
- def test_ban
126
- assert_equal("MODE #mended_drum +b foo!bar@baz\r\n", @ponder.ban('#mended_drum', 'foo!bar@baz'))
127
- end
128
- end
129
-