cinch 0.3.2 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/cinch.rb CHANGED
@@ -7,9 +7,10 @@ require 'optparse'
7
7
  require 'cinch/irc'
8
8
  require 'cinch/rules'
9
9
  require 'cinch/base'
10
+ require 'cinch/names'
10
11
 
11
12
  module Cinch
12
- VERSION = '0.3.2'
13
+ VERSION = '0.3.5'
13
14
 
14
15
  class << self
15
16
 
@@ -59,7 +59,7 @@ module Cinch
59
59
  add_pattern :ip4addr, /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/
60
60
  add_pattern :ip6addr, /[\dA-Fa-f](?::[\dA-Fa-f]){7}|0:0:0:0:0:(?:0|[Ff]{4}):#{pattern(:ip4addr)}/
61
61
  add_pattern :hostaddr, /#{pattern(:ip4addr)}|#{pattern(:ip6addr)}/
62
- add_pattern :shortname, /[A-Za-z0-9][A-Za-z0-9-]*/
62
+ add_pattern :shortname, /[A-Za-z0-9][A-Za-z0-9\-\/]*/
63
63
  add_pattern :hostname, /#{pattern(:shortname)}(?:\.#{pattern(:shortname)})*/
64
64
  add_pattern :host, /#{pattern(:hostname)}|#{pattern(:hostaddr)}/
65
65
 
@@ -0,0 +1,54 @@
1
+ module Cinch
2
+ module Names
3
+ attr_reader :channel_names
4
+
5
+ def tracking_names?
6
+ !!@tracking_names
7
+ end
8
+
9
+ def track_names
10
+ return if tracking_names?
11
+
12
+ @tracking_names = true
13
+
14
+ @channel_names = {}
15
+
16
+ on(:join) do |m|
17
+ if m.nick == nick
18
+ names(m.channel)
19
+ else
20
+ channel_names[m.channel] ||= []
21
+ channel_names[m.channel].push m.nick
22
+ end
23
+ end
24
+
25
+ on(353) do |m|
26
+ channel = m.params.detect { |c| c.match(/^#/) }
27
+ names = m.text.split.collect { |n| n.sub(/^@/, '') }
28
+ channel_names[channel] ||= []
29
+ channel_names[channel] += names
30
+ end
31
+
32
+ on(:part) do |m|
33
+ if m.nick == nick
34
+ channel_names.delete(m.channel)
35
+ else
36
+ channel_names[m.channel] ||= []
37
+ channel_names[m.channel].delete m.nick
38
+ end
39
+ end
40
+
41
+ on(:quit, :kill) do |m|
42
+ channel_names.each_value { |names| names.delete m.nick }
43
+ end
44
+
45
+ on(:nick) do |m|
46
+ channel_names.each_value { |names| names.push m.recipient if names.delete m.nick }
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ class Cinch::Base
53
+ include Cinch::Names
54
+ end
data/spec/base_spec.rb CHANGED
@@ -11,24 +11,7 @@ describe "Cinch::Base" do
11
11
  )
12
12
  end
13
13
 
14
- describe "::new" do
15
- it "should add a default ping listener" do
16
- @base.listeners.should include :ping
17
- end
18
-
19
- it "should add a default nick-taken listener" do
20
- @base.listeners.should include :"433"
21
- end
22
-
23
- it "should add a 004 listener, only if channels are set" do
24
- @base.listeners.should_not include :'004'
25
- @full.listeners.should include :'004'
26
- end
27
-
28
- it "should add a 433 nick taken listener" do
29
- @base.listeners.should include :'433'
30
- end
31
-
14
+ describe "::new" do
32
15
  it "should add a ctcp version listener" do
33
16
  @base.listeners.should include :ctcp
34
17
  @base.listeners[:ctcp].should include :version
@@ -0,0 +1,393 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ describe Cinch::Base do
4
+ before :each do
5
+ @bot = Cinch::Base.new
6
+ end
7
+
8
+ it 'should be able to track names' do
9
+ @bot.should respond_to(:track_names)
10
+ end
11
+
12
+ describe 'when tracking names' do
13
+ before :each do
14
+ @bot.track_names
15
+ end
16
+
17
+ it 'should indicate it is tracking names' do
18
+ @bot.tracking_names?.should == true
19
+ end
20
+
21
+ it 'should provide access to the stored channel names' do
22
+ @bot.should respond_to(:channel_names)
23
+ end
24
+
25
+ it 'should initialize the stored channel names as a hash' do
26
+ @bot.channel_names.should == {}
27
+ end
28
+
29
+ it 'should provide a join listener' do
30
+ @bot.listeners[:join].should_not be_nil
31
+ end
32
+
33
+ describe 'join listener' do
34
+ before :each do
35
+ @listener = @bot.listeners[:join].first
36
+ @message = Struct.new(:nick, :channel).new('someguy', '#somechan')
37
+
38
+ @bot.instance_variable_set('@channel_names', { @message.channel => [] })
39
+ end
40
+
41
+ it 'should be callable' do
42
+ @listener.should respond_to(:call)
43
+ end
44
+
45
+ it "should add the joiner's nick to the channel name list" do
46
+ @listener.call(@message)
47
+ @bot.channel_names[@message.channel].should == [@message.nick]
48
+ end
49
+
50
+ it "should not remove any already-present nicks in the channel name list" do
51
+ nicks = %w[tom mary joe]
52
+ @bot.instance_variable_set('@channel_names', { @message.channel => nicks.dup })
53
+ @listener.call(@message)
54
+ @bot.channel_names[@message.channel].sort.should == (nicks + [@message.nick]).sort
55
+ end
56
+
57
+ it 'should not affect any other channel name lists' do
58
+ channel_names = { '#otherchan' => %w[some people], @message.channel => [] }
59
+ @bot.instance_variable_set('@channel_names', channel_names.dup)
60
+ @listener.call(@message)
61
+ @bot.channel_names.should == { '#otherchan' => %w[some people], @message.channel => [@message.nick] }
62
+ end
63
+
64
+ it 'should handle the channel names not already tracking the channel' do
65
+ @bot.instance_variable_set('@channel_names', {})
66
+ @listener.call(@message)
67
+ @bot.channel_names[@message.channel].should == [@message.nick]
68
+ end
69
+
70
+ it 'should not issue a names command to the channel' do
71
+ @bot.should_receive(:names).never
72
+ @listener.call(@message)
73
+ end
74
+
75
+ describe 'and the joiner is the bot' do
76
+ before :each do
77
+ @message.nick = @bot.nick
78
+ end
79
+
80
+ it 'should not add the nick to the name list' do
81
+ @listener.call(@message)
82
+ @bot.channel_names[@message.channel].should_not include(@message.nick)
83
+ end
84
+
85
+ it 'should issue a names command to the channel' do
86
+ @bot.should_receive(:names).with(@message.channel)
87
+ @listener.call(@message)
88
+ end
89
+ end
90
+ end
91
+
92
+ it 'should provide a names listener' do
93
+ @bot.listeners[:'353'].should_not be_nil
94
+ end
95
+
96
+ describe 'names listener' do
97
+ before :each do
98
+ @listener = @bot.listeners[:'353'].first
99
+ @nick_text = 'cardroid admc cldwalker bmizerany'
100
+ @nicks = %w[cardroid admc cldwalker bmizerany]
101
+ @channel = '#github'
102
+ @message = Struct.new(:params, :text).new(['cardroid', '@', @channel, @nick_text], @nick_text)
103
+ end
104
+
105
+ it 'should be callable' do
106
+ @listener.should respond_to(:call)
107
+ end
108
+
109
+ it 'should set the channel name list to the given nick list' do
110
+ @listener.call(@message)
111
+ @bot.channel_names[@channel].should == @nicks
112
+ end
113
+
114
+ it 'should add the given nicks to an already-present channel name list' do
115
+ nicks = %w[other people already present]
116
+ @bot.instance_variable_set('@channel_names', { @channel => nicks.dup })
117
+
118
+ @listener.call(@message)
119
+ @bot.channel_names[@channel].should == (nicks + @nicks)
120
+ end
121
+
122
+ it 'should not affect any other channel name lists' do
123
+ channel_names = { '#otherchan' => %w[some people], @channel => [] }
124
+ @bot.instance_variable_set('@channel_names', channel_names.dup)
125
+ @listener.call(@message)
126
+ @bot.channel_names.should == { '#otherchan' => %w[some people], @channel => @nicks }
127
+ end
128
+
129
+ it 'should strip extra marking characters from the given nick list' do
130
+ nick_text = 'cardroid admc cldwalker bmizerany programble @luckiestmonkey @tekkub binjured ceej'
131
+ nicks = %w[cardroid admc cldwalker bmizerany programble luckiestmonkey tekkub binjured ceej]
132
+ @message.params[-1] = nick_text
133
+ @message.text = nick_text
134
+
135
+ @listener.call(@message)
136
+ @bot.channel_names[@channel].should == nicks
137
+ end
138
+ end
139
+
140
+ it 'should provide a part listener' do
141
+ @bot.listeners[:part].should_not be_nil
142
+ end
143
+
144
+ describe 'part listener' do
145
+ before :each do
146
+ @listener = @bot.listeners[:part].first
147
+ @message = Struct.new(:nick, :channel).new('someguy', '#somechan')
148
+
149
+ @bot.instance_variable_set('@channel_names', { @message.channel => [] })
150
+ end
151
+
152
+ it 'should be callable' do
153
+ @listener.should respond_to(:call)
154
+ end
155
+
156
+ it "should remove the parter's nick from the channel name list" do
157
+ @nicks = %w[bunch of people]
158
+ @bot.instance_variable_set('@channel_names', { @message.channel => (@nicks + [@message.nick]) })
159
+
160
+ @listener.call(@message)
161
+ @bot.channel_names[@message.channel].should == @nicks
162
+ end
163
+
164
+ it "should remove the parter's nick from the channel name list no matter where or how many times it occurs" do
165
+ @nicks = %w[bunch of people]
166
+ @bot.instance_variable_set('@channel_names', { @message.channel => @nicks.join(" #{@message.nick} ").split })
167
+
168
+ @listener.call(@message)
169
+ @bot.channel_names[@message.channel].should == @nicks
170
+ end
171
+
172
+ it 'should not affect any other channel name lists' do
173
+ @nicks = %w[bunch of people]
174
+ channel_names = { '#otherchan' => %w[some people], @message.channel => (@nicks + [@message.nick]) }
175
+ @bot.instance_variable_set('@channel_names', channel_names.dup)
176
+ @listener.call(@message)
177
+ @bot.channel_names.should == { '#otherchan' => %w[some people], @message.channel => @nicks }
178
+ end
179
+
180
+ it 'should handle the channel names not already tracking the channel' do
181
+ @bot.instance_variable_set('@channel_names', {})
182
+ @listener.call(@message)
183
+ @bot.channel_names[@message.channel].should == []
184
+ end
185
+
186
+ it 'should handle the nick not appearing on the list' do
187
+ @nicks = %w[bunch of people]
188
+ @bot.instance_variable_set('@channel_names', { @message.channel => @nicks.dup })
189
+
190
+ @listener.call(@message)
191
+ @bot.channel_names[@message.channel].should == @nicks
192
+ end
193
+
194
+ describe 'and the parter is the bot' do
195
+ before :each do
196
+ @message.nick = @bot.nick
197
+ end
198
+
199
+ it 'should completely remove the channel from the names hash' do
200
+ channel_names = { '#otherchan' => %w[some people], @message.channel => %w[bunch of people] }
201
+ @bot.instance_variable_set('@channel_names', channel_names.dup)
202
+ @listener.call(@message)
203
+ @bot.channel_names.should == { '#otherchan' => %w[some people] }
204
+ end
205
+ end
206
+ end
207
+
208
+ it 'should provide a quit listener' do
209
+ @bot.listeners[:quit].should_not be_nil
210
+ end
211
+
212
+ describe 'quit listener' do
213
+ before :each do
214
+ @listener = @bot.listeners[:quit].first
215
+ @message = Struct.new(:nick).new('someguy')
216
+ @channel = '#somechan'
217
+ @nicks = %w[bunch of people]
218
+ @other_chan = '#otherchan'
219
+ @other_nicks = %w[other people here]
220
+ end
221
+
222
+ it 'should be callable' do
223
+ @listener.should respond_to(:call)
224
+ end
225
+
226
+ it "should remove the quitter's nick from every channel name list" do
227
+ @bot.instance_variable_set('@channel_names', { @channel => (@nicks + [@message.nick]), @other_chan => (@other_nicks + [@message.nick]) })
228
+
229
+ @listener.call(@message)
230
+ @bot.channel_names.should == { @channel => @nicks, @other_chan => @other_nicks }
231
+ end
232
+
233
+ it "should remove the quitter's nick from every channel name list no matter where or how many times it occurs" do
234
+ @bot.instance_variable_set('@channel_names', { @channel => @nicks.join(" #{@message.nick} ").split, @other_chan => @other_nicks.join(" #{@message.nick} ").split })
235
+
236
+ @listener.call(@message)
237
+ @bot.channel_names.should == { @channel => @nicks, @other_chan => @other_nicks }
238
+ end
239
+
240
+ it 'should not affect any other channel name lists' do
241
+ @bot.instance_variable_set('@channel_names', { @channel => (@nicks + [@message.nick]), @other_chan => @other_nicks.dup })
242
+
243
+ @listener.call(@message)
244
+ @bot.channel_names.should == { @channel => @nicks, @other_chan => @other_nicks }
245
+ end
246
+ end
247
+
248
+ it 'should provide a kill listener' do
249
+ @bot.listeners[:kill].should_not be_nil
250
+ end
251
+
252
+ describe 'kill listener' do
253
+ before :each do
254
+ @listener = @bot.listeners[:kill].first
255
+ @message = Struct.new(:nick).new('someguy')
256
+ @channel = '#somechan'
257
+ @nicks = %w[bunch of people]
258
+ @other_chan = '#otherchan'
259
+ @other_nicks = %w[other people here]
260
+ end
261
+
262
+ it 'should be callable' do
263
+ @listener.should respond_to(:call)
264
+ end
265
+
266
+ it 'should remove the killed nick from every channel name list' do
267
+ @bot.instance_variable_set('@channel_names', { @channel => (@nicks + [@message.nick]), @other_chan => (@other_nicks + [@message.nick]) })
268
+
269
+ @listener.call(@message)
270
+ @bot.channel_names.should == { @channel => @nicks, @other_chan => @other_nicks }
271
+ end
272
+
273
+ it 'should remove the killed nick from every channel name list no matter where or how many times it occurs' do
274
+ @bot.instance_variable_set('@channel_names', { @channel => @nicks.join(" #{@message.nick} ").split, @other_chan => @other_nicks.join(" #{@message.nick} ").split })
275
+
276
+ @listener.call(@message)
277
+ @bot.channel_names.should == { @channel => @nicks, @other_chan => @other_nicks }
278
+ end
279
+
280
+ it 'should not affect any other channel name lists' do
281
+ @bot.instance_variable_set('@channel_names', { @channel => (@nicks + [@message.nick]), @other_chan => @other_nicks.dup })
282
+
283
+ @listener.call(@message)
284
+ @bot.channel_names.should == { @channel => @nicks, @other_chan => @other_nicks }
285
+ end
286
+ end
287
+
288
+ it 'should provide a nick listener' do
289
+ @bot.listeners[:nick].should_not be_nil
290
+ end
291
+
292
+ describe 'nick listener' do
293
+ before :each do
294
+ @listener = @bot.listeners[:nick].first
295
+ @message = Struct.new(:nick, :recipient).new('someguy', 'someotherguy')
296
+ @channel = '#somechan'
297
+ @nicks = %w[bunch of people]
298
+ @other_chan = '#otherchan'
299
+ @other_nicks = %w[other people here]
300
+ end
301
+
302
+ it 'should be callable' do
303
+ @listener.should respond_to(:call)
304
+ end
305
+
306
+ it 'should replace the changed nick in every channel name list' do
307
+ @bot.instance_variable_set('@channel_names', { @channel => (@nicks + [@message.nick]), @other_chan => (@other_nicks + [@message.nick]) })
308
+
309
+ @listener.call(@message)
310
+ @bot.channel_names.should == { @channel => (@nicks + [@message.recipient]), @other_chan => (@other_nicks + [@message.recipient]) }
311
+ end
312
+
313
+ it 'should replace the the changed nick in every channel name list no matter where or how many times it occurs' do
314
+ @bot.instance_variable_set('@channel_names', { @channel => @nicks.join(" #{@message.nick} ").split, @other_chan => @other_nicks.join(" #{@message.nick} ").split })
315
+
316
+ @listener.call(@message)
317
+ @bot.channel_names.should == { @channel => (@nicks + [@message.recipient]), @other_chan => (@other_nicks + [@message.recipient]) }
318
+ end
319
+
320
+ it 'should not affect any other channel name lists' do
321
+ @bot.instance_variable_set('@channel_names', { @channel => (@nicks + [@message.nick]), @other_chan => @other_nicks.dup })
322
+
323
+ @listener.call(@message)
324
+ @bot.channel_names.should == { @channel => (@nicks + [@message.recipient]), @other_chan => @other_nicks }
325
+ end
326
+ end
327
+
328
+ it 'should not interfere with other bots' do
329
+ @bot_one = Cinch::Base.new
330
+ @bot_two = Cinch::Base.new
331
+
332
+ @bot_one.track_names
333
+ @bot_two.track_names
334
+
335
+ @message = Struct.new(:nick, :channel)
336
+ @message_one = @message.new('someguy', '#somechan')
337
+ @message_two = @message.new('otherguy', '#otherchan')
338
+
339
+ @bot_one.listeners[:join].first.call(@message_one)
340
+ @bot_two.listeners[:join].first.call(@message_two)
341
+
342
+ @bot_one.channel_names.should == { @message_one.channel => [@message_one.nick] }
343
+ @bot_two.channel_names.should == { @message_two.channel => [@message_two.nick] }
344
+ end
345
+
346
+ it 'should not re-add listeners when asked to track names again' do
347
+ @bot.track_names
348
+ @bot.listeners[:join].length.should == 1
349
+ end
350
+
351
+ it 'should not reset the channel name list when asked to track names again' do
352
+ @message = Struct.new(:nick, :channel).new('someguy', '#somechan')
353
+ @bot.listeners[:join].first.call(@message)
354
+
355
+ @bot.track_names
356
+ @bot.channel_names.should == { @message.channel => [@message.nick] }
357
+ end
358
+ end
359
+
360
+ describe 'before tracking names' do
361
+ it 'should indicate it is not tracking names' do
362
+ @bot.tracking_names?.should == false
363
+ end
364
+
365
+ it 'should have no channel name list' do
366
+ @bot.channel_names.should be_nil
367
+ end
368
+
369
+ it 'should have no join listener' do
370
+ @bot.listeners[:join].should be_nil
371
+ end
372
+
373
+ it 'should have no names listener' do
374
+ @bot.listeners[:'353'].should be_nil
375
+ end
376
+
377
+ it 'should have no part listener' do
378
+ @bot.listeners[:part].should be_nil
379
+ end
380
+
381
+ it 'should have no quit listener' do
382
+ @bot.listeners[:quit].should be_nil
383
+ end
384
+
385
+ it 'should have no kill listener' do
386
+ @bot.listeners[:kill].should be_nil
387
+ end
388
+
389
+ it 'should have no nick listener' do
390
+ @bot.listeners[:nick].should be_nil
391
+ end
392
+ end
393
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cinch
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 2
10
- version: 0.3.2
9
+ - 5
10
+ version: 0.3.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Lee 'injekt' Jarvis
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-07-08 00:00:00 +01:00
18
+ date: 2010-07-25 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -45,6 +45,7 @@ extra_rdoc_files:
45
45
  files:
46
46
  - README.rdoc
47
47
  - Rakefile
48
+ - spec/names_spec.rb
48
49
  - spec/irc/message_spec.rb
49
50
  - spec/irc/parser_spec.rb
50
51
  - spec/irc/socket_spec.rb
@@ -55,6 +56,7 @@ files:
55
56
  - spec/base_spec.rb
56
57
  - spec/helper.rb
57
58
  - lib/cinch.rb
59
+ - lib/cinch/names.rb
58
60
  - lib/cinch/irc/socket.rb
59
61
  - lib/cinch/irc/message.rb
60
62
  - lib/cinch/irc/parser.rb