vetinari 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8caa318b353a259ce354a4f33ac6512929a70ddc
4
- data.tar.gz: 6b0c114d8756323c6c93c7945e44b5c1392ee852
3
+ metadata.gz: a7b2a839017a8a6ad9cb366e4983223d18d79125
4
+ data.tar.gz: e9283985e9363ac330abaf31f07965ec26ef3049
5
5
  SHA512:
6
- metadata.gz: edd9ea43bb5a3636a2a4dec5246c205c40d18c310d24782e4d43cfce515fa89558c83ae2f261b823053d45456265f38aca52e0d9d7a2ade0969894ba1f3a601d
7
- data.tar.gz: ce1804db1898b39dfc6869dac32f98b3c2b1a9846e02a8ef8881c504e7b48bcaa71101b3ddad80a3d72009be0f106bcf14e1de00336cce6f9e223f5852d3d7d8
6
+ metadata.gz: e8faa48002d977fe10bed20ed4aa6e0f39669c0abdae838be9e13fa7d713e42c2361c63e0c499211e13bc68f63eb488ab14347d1110dc7a022f3a5beb6e19e43
7
+ data.tar.gz: 2c6726ab26892d11914ec986ae1ec5e7afe57c5dd35fa1164c9004c98dd4c19645a27dfb013d84c06db7f71681c5d4805b15cf0650f8f1b809a4ef34c522abde
data/Gemfile CHANGED
@@ -1,2 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
+
4
+ gem 'celluloid', github: 'celluloid/celluloid'
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Vetinari [![Gem Version](https://badge.fury.io/rb/vetinari.png)](http://badge.fury.io/rb/vetinari)
1
+ # Vetinari [![Gem Version](https://badge.fury.io/rb/vetinari.png)](http://badge.fury.io/rb/vetinari) [![Dependency Status](https://gemnasium.com/tbuehlmann/vetinari.png)](https://gemnasium.com/tbuehlmann/vetinari)
2
2
  Vetinari is a Domain Specific Language for writing IRC Bots using the [Celluloid::IO](https://github.com/celluloid/celluloid-io "Celluloid::IO") library.
3
3
 
4
4
  ## Requirements
data/lib/vetinari/bot.rb CHANGED
@@ -346,6 +346,14 @@ module Vetinari
346
346
  env[:user].renamed_to(env.delete(:new_nick))
347
347
  end
348
348
 
349
+ on :topic do |env|
350
+ # TODO: Update existing users with user/host information.
351
+ env.delete(:user)
352
+ env.delete(:host)
353
+ env[:channel] = @channels[env.delete(:channel)]
354
+ env[:user] = @users[env.delete(:nick)]
355
+ end
356
+
349
357
  # Response to MODE command, giving back the channel modes.
350
358
  on 324 do |env|
351
359
  split = env[:params].split(/ /)
@@ -27,6 +27,10 @@ module Vetinari
27
27
  @container.remove(@event, @uuid)
28
28
  end
29
29
 
30
+ def remove_and_terminate
31
+ @container.remove(@event, @uuid, true)
32
+ end
33
+
30
34
  def inspect
31
35
  event = @event.inspect
32
36
  options = @options.inspect
@@ -35,12 +35,16 @@ module Vetinari
35
35
  callback
36
36
  end
37
37
 
38
- def remove(event, uuid)
38
+ def remove(event, uuid, terminate = false)
39
39
  @mutex.synchronize do
40
40
  if @callbacks.key?(event)
41
41
  hash = @callbacks[event].delete(uuid)
42
42
 
43
43
  if hash
44
+ if terminate && hash[:callback].alive?
45
+ hash[:callback].async.terminate
46
+ end
47
+
44
48
  # https://github.com/celluloid/celluloid/issues/197
45
49
  # callback.soft_terminate
46
50
 
@@ -4,9 +4,9 @@ module Vetinari
4
4
  #
5
5
  # Example:
6
6
  # {'ponder' => {:user => #<User nick="Ponder">, :modes => ['v', 'o']}}
7
- #
8
- # TODO: Actor?
9
7
  class Channel
8
+ include Celluloid
9
+
10
10
  attr_reader :name, :users, :users_with_modes, :modes, :lists
11
11
 
12
12
  def initialize(name, bot)
@@ -95,11 +95,50 @@ module Vetinari
95
95
  end
96
96
 
97
97
  def join(key = nil)
98
+ if @bot.channels.has_channel?(@name)
99
+ return Future.new { :already_joined }
100
+ end
101
+
102
+ condition = Celluloid::Condition.new
103
+ callbacks = Set.new
104
+
105
+ callbacks << @bot.on(:join) do |env|
106
+ if env[:channel].name == @name
107
+ condition.signal :joined
108
+ callbacks.each { |cb| cb.remove_and_terminate }
109
+ end
110
+ end
111
+
112
+ raw_messages = {
113
+ 475 => :locked,
114
+ 471 => :full,
115
+ 474 => :banned,
116
+ 473 => :invite_only
117
+ }
118
+
119
+ raw_messages.each do |raw, msg|
120
+ callbacks << @bot.on(raw) do |env|
121
+ channel_name = env[:params].split(' ')[1]
122
+
123
+ if channel_name == @name
124
+ condition.signal msg
125
+ callbacks.each { |cb| cb.remove_and_terminate }
126
+ end
127
+ end
128
+ end
129
+
130
+ after(5) do
131
+ condition.signal :timeout
132
+ callbacks.each { |cb| cb.remove_and_terminate }
133
+ end
134
+
98
135
  if key
99
136
  @bot.raw "JOIN #{@name} #{key}"
100
137
  else
101
138
  @bot.raw "JOIN #{@name}"
102
139
  end
140
+
141
+ Future.new { condition.wait }
103
142
  end
104
143
 
105
144
  def part(message = nil)
data/lib/vetinari/irc.rb CHANGED
@@ -7,7 +7,41 @@ module Vetinari
7
7
  end
8
8
 
9
9
  def rename(nick)
10
+ if nick.length > @config.isupport['NICKLEN']
11
+ nick = nick.slice(0, @config.isupport['NICKLEN'])
12
+ end
13
+
14
+ return Celluloid::Future.new { nick } if @user.nick == nick
15
+
16
+ condition = Celluloid::Condition.new
17
+ callbacks = Set.new
18
+
19
+ callbacks << on(:nick_change) do |env|
20
+ if env[:user].bot?
21
+ condition.signal env[:user].nick
22
+ callbacks.each { |cb| cb.remove_and_terminate }
23
+ end
24
+ end
25
+
26
+ raw_messages = {
27
+ 432 => :erroneous_nickname,
28
+ 433 => :nickname_in_use
29
+ }
30
+
31
+ raw_messages.each do |raw, msg|
32
+ callbacks << on(raw) do |env|
33
+ condition.signal(msg)
34
+ callbacks.each { |cb| cb.remove_and_terminate }
35
+ end
36
+ end
37
+
38
+ after(5) do
39
+ condition.signal(:timeout)
40
+ callbacks.each { |cb| cb.remove_and_terminate }
41
+ end
42
+
10
43
  raw "NICK :#{nick}"
44
+ Celluloid::Future.new { condition.wait }
11
45
  end
12
46
 
13
47
  def away(message = nil)
@@ -33,9 +67,19 @@ module Vetinari
33
67
  end
34
68
 
35
69
  def join(channel_name, key = nil)
36
- unless @channels.has_channel?(channel_name)
37
- channel = Channel.new(channel_name, @actor)
38
- channel.join key
70
+ channel = Channel.new(channel_name, @actor)
71
+ channel.join(key)
72
+ end
73
+
74
+ def message(receiver, message)
75
+ channel = @config.isupport['CHANTYPES'].any? do |chantype|
76
+ receiver.start_with?(chantype)
77
+ end
78
+
79
+ if channel
80
+ Channel.new(receiver, @actor).message(message)
81
+ else
82
+ User.new(receiver, @actor).message(message)
39
83
  end
40
84
  end
41
85
  end
@@ -1,3 +1,3 @@
1
1
  module Vetinari
2
- VERSION = Gem::Version.new('0.1.0')
2
+ VERSION = Gem::Version.new('0.2.0')
3
3
  end
@@ -16,4 +16,13 @@ describe 'Callback' do
16
16
  cb.remove
17
17
  expect(callbacks[:channel]).to have(1).callback
18
18
  end
19
+
20
+ it 'can be removed and terminated' do
21
+ cb = subject.on(:channel)
22
+ expect(callbacks[:channel]).to have(2).callback
23
+ expect(cb.alive?).to be_true
24
+ cb.remove_and_terminate
25
+ expect(callbacks[:channel]).to have(1).callback
26
+ expect(cb.alive?).to be_false
27
+ end
19
28
  end
data/spec/join_spec.rb ADDED
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Bot#join' do
4
+ subject { Vetinari::Bot.new { |c| c.verbose = false } }
5
+
6
+ before(:each) do
7
+ subject.parse(':server 001 Vetinari :Welcome message')
8
+ subject.parse(':server 376 Vetinari :End of /MOTD command.')
9
+ end
10
+
11
+ it 'returns a Future' do
12
+ expect(subject.join('#mended_drum')).to be_a(Celluloid::Future)
13
+ end
14
+
15
+ it 'returns :joined if joined' do
16
+ future = subject.join('#mended_drum')
17
+
18
+ Thread.new do
19
+ subject.parse(':Vetinari!foo@bar JOIN #mended_drum')
20
+ end
21
+
22
+ expect(future.value).to be(:joined)
23
+ end
24
+
25
+ it 'returns :already_joined if already in the channel' do
26
+ subject.parse(':Vetinari!foo@bar JOIN #mended_drum')
27
+ future = subject.join('#mended_drum')
28
+ expect(future.value).to be(:already_joined)
29
+ end
30
+
31
+ it 'returns :locked if channel is locked' do
32
+ future = subject.join('#mended_drum')
33
+
34
+ Thread.new do
35
+ subject.parse(':server 475 Vetinari #mended_drum :Cannot join channel (+k) - bad key')
36
+ end
37
+
38
+ expect(future.value).to be(:locked)
39
+ end
40
+
41
+ it 'returns :full if channel is full' do
42
+ future = subject.join('#mended_drum')
43
+
44
+ Thread.new do
45
+ subject.parse(':server 471 Vetinari #mended_drum :Cannot join channel (+l) - channel is full, try again later')
46
+ end
47
+
48
+ expect(future.value).to be(:full)
49
+ end
50
+
51
+ it 'returns :banned if the bot is banned from the channel' do
52
+ future = subject.join('#mended_drum')
53
+
54
+ Thread.new do
55
+ subject.parse(':server 474 Vetinari #mended_drum :Cannot join channel (+b) - you are banned')
56
+ end
57
+
58
+ expect(future.value).to be(:banned)
59
+ end
60
+
61
+ it 'returns :banned if the bot is banned from the channel' do
62
+ future = subject.join('#mended_drum')
63
+
64
+ Thread.new do
65
+ subject.parse(':server 473 Vetinari #mended_drum :Cannot join channel (+i) - you must be invited')
66
+ end
67
+
68
+ expect(future.value).to be(:invite_only)
69
+ end
70
+
71
+ it 'returns :timeout if no answer comes from the server' do
72
+ future = subject.join('#mended_drum')
73
+ expect(future.value).to be(:timeout)
74
+ end
75
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Bot#rename' do
4
+ subject { Vetinari::Bot.new { |c| c.verbose = false } }
5
+
6
+ before(:each) do
7
+ subject.parse(':server 001 Vetinari :Welcome message')
8
+ subject.parse(':server 376 Vetinari :End of /MOTD command.')
9
+ subject.parse(':server 005 Vetinari NICKLEN=10')
10
+ end
11
+
12
+ it 'returns a Future' do
13
+ expect(subject.rename('Havelock')).to be_a(Celluloid::Future)
14
+ end
15
+
16
+ it 'returns the current nickname if no changes would happen' do
17
+ future = subject.rename('Vetinari')
18
+ expect(future.value).to be_a(String)
19
+ expect(future.value).to eq('Vetinari')
20
+ end
21
+
22
+ it 'returns String if renamed' do
23
+ future = subject.rename('Havelock')
24
+
25
+ Thread.new do
26
+ subject.parse(':Vetinari!foo@bar NICK :Havelock')
27
+ end
28
+
29
+ expect(future.value).to be_a(String)
30
+ expect(future.value).to eq('Havelock')
31
+ end
32
+
33
+ it 'returns :erroneous_nickname if nickname is erroneous' do
34
+ future = subject.rename('NickServ')
35
+
36
+ Thread.new do
37
+ subject.parse(':server 432 Vetinari NickServ :Erroneous Nickname')
38
+ end
39
+
40
+ expect(future.value).to be_a(Symbol)
41
+ expect(future.value).to eq(:erroneous_nickname)
42
+ end
43
+
44
+ it 'returns :nickname_in_use if nickname is taken' do
45
+ future = subject.rename('TheLibrarian')
46
+
47
+ Thread.new do
48
+ subject.parse(':server 433 Vetinari TheLibrarian :Nickname is already in use.')
49
+ end
50
+
51
+ expect(future.value).to be_a(Symbol)
52
+ expect(future.value).to eq(:nickname_in_use)
53
+ end
54
+
55
+ it 'slices the nick if it is too long' do
56
+ bare = subject.bare_object
57
+ expect(bare).to receive(:raw).with('NICK :1234567890').once
58
+ subject.rename('1234567890over')
59
+ end
60
+ end
data/vetinari.gemspec CHANGED
@@ -26,5 +26,5 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency 'bundler', '~> 1.3'
27
27
  spec.add_development_dependency 'pry', '~> 0.9'
28
28
  spec.add_development_dependency 'rake', '~> 10.0'
29
- spec.add_development_dependency 'rspec', '~> 2.13'
29
+ spec.add_development_dependency 'rspec', '2.14.0.rc1'
30
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vetinari
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Bühlmann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-14 00:00:00.000000000 Z
11
+ date: 2013-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid-io
@@ -70,16 +70,16 @@ dependencies:
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: '2.13'
75
+ version: 2.14.0.rc1
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: '2.13'
82
+ version: 2.14.0.rc1
83
83
  description: |2
84
84
  Vetinari is a multithreaded IRC Bot Framework using the Celluloid::IO
85
85
  library.
@@ -119,6 +119,8 @@ files:
119
119
  - spec/channel_spec.rb
120
120
  - spec/default_callbacks_spec.rb
121
121
  - spec/isupport_spec.rb
122
+ - spec/join_spec.rb
123
+ - spec/rename_spec.rb
122
124
  - spec/spec_helper.rb
123
125
  - spec/user_management_spec.rb
124
126
  - spec/user_spec.rb
@@ -153,6 +155,8 @@ test_files:
153
155
  - spec/channel_spec.rb
154
156
  - spec/default_callbacks_spec.rb
155
157
  - spec/isupport_spec.rb
158
+ - spec/join_spec.rb
159
+ - spec/rename_spec.rb
156
160
  - spec/spec_helper.rb
157
161
  - spec/user_management_spec.rb
158
162
  - spec/user_spec.rb