ponder 0.1.0 → 0.1.1

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/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
-