vetinari 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/README.md +1 -1
- data/lib/vetinari/bot.rb +8 -0
- data/lib/vetinari/callback.rb +4 -0
- data/lib/vetinari/callback_container.rb +5 -1
- data/lib/vetinari/channel.rb +41 -2
- data/lib/vetinari/irc.rb +47 -3
- data/lib/vetinari/version.rb +1 -1
- data/spec/callback_spec.rb +9 -0
- data/spec/join_spec.rb +75 -0
- data/spec/rename_spec.rb +60 -0
- data/vetinari.gemspec +1 -1
- metadata +10 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7b2a839017a8a6ad9cb366e4983223d18d79125
|
4
|
+
data.tar.gz: e9283985e9363ac330abaf31f07965ec26ef3049
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8faa48002d977fe10bed20ed4aa6e0f39669c0abdae838be9e13fa7d713e42c2361c63e0c499211e13bc68f63eb488ab14347d1110dc7a022f3a5beb6e19e43
|
7
|
+
data.tar.gz: 2c6726ab26892d11914ec986ae1ec5e7afe57c5dd35fa1164c9004c98dd4c19645a27dfb013d84c06db7f71681c5d4805b15cf0650f8f1b809a4ef34c522abde
|
data/Gemfile
CHANGED
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(/ /)
|
data/lib/vetinari/callback.rb
CHANGED
@@ -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
|
|
data/lib/vetinari/channel.rb
CHANGED
@@ -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
|
-
|
37
|
-
|
38
|
-
|
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
|
data/lib/vetinari/version.rb
CHANGED
data/spec/callback_spec.rb
CHANGED
@@ -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
|
data/spec/rename_spec.rb
ADDED
@@ -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', '
|
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.
|
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-
|
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:
|
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:
|
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
|