isaac 0.2.5 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +43 -0
- data/README.rdoc +41 -1
- data/isaac.gemspec +9 -6
- data/lib/isaac.rb +4 -210
- data/lib/isaac/bot.rb +338 -0
- metadata +5 -4
- data/LICENSE +0 -6
data/CHANGES
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
= master / unreleasedd
|
2
|
+
|
3
|
+
* Require 'isaac/bot' to avoid top level bot/methods [Julian Langschaedel]
|
4
|
+
|
5
|
+
* Add action(), kick() and mode() [Danny Tatom]
|
6
|
+
|
7
|
+
* SSL support - configure {|c| c.ssl = true} [postmodern]
|
8
|
+
|
9
|
+
* on :join/:part-events [postmodern]
|
10
|
+
|
11
|
+
= 0.2.5 / 2009-04-25
|
12
|
+
|
13
|
+
* Comply to the RFC - lines end with \r\n, not just \n.
|
14
|
+
|
15
|
+
= 0.2.4 / 2009-04-01
|
16
|
+
|
17
|
+
* Bug fixes.
|
18
|
+
|
19
|
+
= 0.2.3 / 2009-04-01
|
20
|
+
|
21
|
+
* Pass regular expression groups to block parameters.
|
22
|
+
|
23
|
+
* Internal refactoring of queue and tests.
|
24
|
+
|
25
|
+
= 0.2.2 / 2009-02-23
|
26
|
+
|
27
|
+
* Irrelevant.
|
28
|
+
|
29
|
+
= 0.2.1 / 2009-02-23
|
30
|
+
|
31
|
+
* config() has been renamed to configure().
|
32
|
+
|
33
|
+
* part() and topic() commands added.
|
34
|
+
|
35
|
+
* Comply to the RFC and wait for 001-004 messages until sending commands.
|
36
|
+
|
37
|
+
* Respond to CTCP action with the content of configure {|c| c.version = "" }.
|
38
|
+
|
39
|
+
* Improved documentation.
|
40
|
+
|
41
|
+
= 0.2.0 / 2009-02-23
|
42
|
+
|
43
|
+
* This is a complete rewrite of Isaac.
|
data/README.rdoc
CHANGED
@@ -74,8 +74,48 @@ Errors, as specified by RFC 1459, can be reacted upon as well. If you e.g. try t
|
|
74
74
|
|
75
75
|
Available variables: +nick+ and +channel+.
|
76
76
|
|
77
|
+
=== Non-top level bots
|
78
|
+
You might not want to pollute the top-level namespace with Isaac
|
79
|
+
helpers, or you want to define multiple bots. This can be done
|
80
|
+
easily, by requiring `isaac/bot` instead of `isaac`:
|
81
|
+
|
82
|
+
require 'isaac/bot'
|
83
|
+
|
84
|
+
bot = Isaac::Bot.new do
|
85
|
+
configure do
|
86
|
+
…
|
87
|
+
end
|
88
|
+
|
89
|
+
on :channel do
|
90
|
+
…
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
bot.start
|
95
|
+
|
77
96
|
== Contribute
|
78
97
|
The source is hosted at GitHub: http://github.com/ichverstehe/isaac
|
79
98
|
|
80
99
|
== License
|
81
|
-
|
100
|
+
Copyright (c) 2009 Harry Vangberg <harry@vangberg.name>
|
101
|
+
|
102
|
+
Permission is hereby granted, free of charge, to any person
|
103
|
+
obtaining a copy of this software and associated documentation
|
104
|
+
files (the "Software"), to deal in the Software without
|
105
|
+
restriction, including without limitation the rights to use,
|
106
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
107
|
+
copies of the Software, and to permit persons to whom the
|
108
|
+
Software is furnished to do so, subject to the following
|
109
|
+
conditions:
|
110
|
+
|
111
|
+
The above copyright notice and this permission notice shall be
|
112
|
+
included in all copies or substantial portions of the Software.
|
113
|
+
|
114
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
115
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
116
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
117
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
118
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
119
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
120
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
121
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/isaac.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "isaac"
|
3
|
-
s.version = "0.2.
|
4
|
-
s.date = "2009-
|
3
|
+
s.version = "0.2.6"
|
4
|
+
s.date = "2009-12-21"
|
5
5
|
s.summary = "The smallish DSL for writing IRC bots"
|
6
6
|
s.email = "harry@vangberg.name"
|
7
7
|
s.homepage = "http://github.com/ichverstehe/isaac"
|
@@ -9,11 +9,14 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.rubyforge_project = "isaac"
|
10
10
|
s.has_rdoc = true
|
11
11
|
s.authors = ["Harry Vangberg"]
|
12
|
-
s.files = [
|
13
|
-
"
|
12
|
+
s.files = [
|
13
|
+
"README.rdoc",
|
14
|
+
"CHANGES",
|
14
15
|
"isaac.gemspec",
|
15
|
-
"lib/isaac.rb"
|
16
|
+
"lib/isaac.rb",
|
17
|
+
"lib/isaac/bot.rb"
|
18
|
+
]
|
16
19
|
s.rdoc_options = ["--main", "README.rdoc"]
|
17
|
-
s.extra_rdoc_files = ["
|
20
|
+
s.extra_rdoc_files = ["CHANGES", "README.rdoc"]
|
18
21
|
end
|
19
22
|
|
data/lib/isaac.rb
CHANGED
@@ -1,217 +1,11 @@
|
|
1
|
-
require '
|
1
|
+
require 'isaac/bot'
|
2
2
|
|
3
|
-
|
4
|
-
VERSION = '0.2.1'
|
5
|
-
|
6
|
-
Config = Struct.new(:server, :port, :password, :nick, :realname, :version, :environment, :verbose)
|
7
|
-
|
8
|
-
def self.bot
|
9
|
-
@bot ||= Bot.new
|
10
|
-
end
|
11
|
-
|
12
|
-
class Bot
|
13
|
-
attr_accessor :config, :irc, :nick, :channel, :message, :userhost, :match,
|
14
|
-
:error
|
15
|
-
|
16
|
-
def initialize(&b)
|
17
|
-
@events = {}
|
18
|
-
@config = Config.new("localhost", 6667, nil, "isaac", "Isaac", 'isaac', :production, false)
|
19
|
-
|
20
|
-
instance_eval(&b) if block_given?
|
21
|
-
end
|
22
|
-
|
23
|
-
def configure(&b)
|
24
|
-
b.call(@config)
|
25
|
-
end
|
26
|
-
|
27
|
-
def on(event, match=//, &block)
|
28
|
-
match = match.to_s if match.is_a? Integer
|
29
|
-
(@events[event] ||= []) << [Regexp.new(match), block]
|
30
|
-
end
|
31
|
-
|
32
|
-
def helpers(&b)
|
33
|
-
instance_eval(&b)
|
34
|
-
end
|
35
|
-
|
36
|
-
def halt
|
37
|
-
throw :halt
|
38
|
-
end
|
39
|
-
|
40
|
-
def raw(command)
|
41
|
-
@irc.message(command)
|
42
|
-
end
|
43
|
-
|
44
|
-
def msg(recipient, text)
|
45
|
-
raw("PRIVMSG #{recipient} :#{text}")
|
46
|
-
end
|
47
|
-
|
48
|
-
def join(*channels)
|
49
|
-
channels.each {|channel| raw("JOIN #{channel}")}
|
50
|
-
end
|
51
|
-
|
52
|
-
def part(*channels)
|
53
|
-
channels.each {|channel| raw("PART #{channel}")}
|
54
|
-
end
|
55
|
-
|
56
|
-
def topic(channel, text)
|
57
|
-
raw("TOPIC #{channel} :#{text}")
|
58
|
-
end
|
59
|
-
|
60
|
-
def start
|
61
|
-
puts "Connecting to #{@config.server}:#{@config.port}" unless @config.environment == :test
|
62
|
-
@irc = IRC.new(self, @config)
|
63
|
-
@irc.connect
|
64
|
-
end
|
65
|
-
|
66
|
-
def dispatch(event, env={})
|
67
|
-
self.nick, self.userhost, self.channel, self.error =
|
68
|
-
env[:nick], env[:userhost], env[:channel], env[:error]
|
69
|
-
self.message = env[:message] || ""
|
70
|
-
|
71
|
-
if handler = find(event, message)
|
72
|
-
regexp, block = *handler
|
73
|
-
self.match = message.match(regexp).captures
|
74
|
-
invoke block
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
def find(type, message)
|
80
|
-
if events = @events[type]
|
81
|
-
events.detect {|regexp,_| message.match(regexp)}
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def invoke(block)
|
86
|
-
mc = class << self; self; end
|
87
|
-
mc.send :define_method, :__isaac_event_handler, &block
|
88
|
-
|
89
|
-
bargs = case block.arity <=> 0
|
90
|
-
when -1; match
|
91
|
-
when 0; []
|
92
|
-
when 1; match[0..block.arity-1]
|
93
|
-
end
|
94
|
-
|
95
|
-
catch(:halt) { __isaac_event_handler(*bargs) }
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
class IRC
|
100
|
-
def initialize(bot, config)
|
101
|
-
@bot, @config = bot, config
|
102
|
-
@transfered = 0
|
103
|
-
@registration = []
|
104
|
-
end
|
105
|
-
|
106
|
-
def connect
|
107
|
-
@socket = TCPSocket.open(@config.server, @config.port)
|
108
|
-
@queue = Queue.new(@socket, @bot.config.server)
|
109
|
-
message "PASS #{@config.password}" if @config.password
|
110
|
-
message "NICK #{@config.nick}"
|
111
|
-
message "USER #{@config.nick} 0 * :#{@config.realname}"
|
112
|
-
@queue.lock
|
113
|
-
|
114
|
-
while line = @socket.gets
|
115
|
-
parse line
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def parse(input)
|
120
|
-
puts "<< #{input}" if @bot.config.verbose
|
121
|
-
case input.chomp
|
122
|
-
when /(^:\S+ )?00([1-4])/
|
123
|
-
@registration << $2.to_i
|
124
|
-
if registered?
|
125
|
-
@queue.unlock
|
126
|
-
@bot.dispatch(:connect)
|
127
|
-
end
|
128
|
-
when /(^:(\S+)!\S+ )?PRIVMSG \S+ :?\001VERSION\001/
|
129
|
-
message "NOTICE #{$2} :\001VERSION #{@bot.config.version}\001"
|
130
|
-
when /^PING (\S+)/
|
131
|
-
@queue.unlock
|
132
|
-
message "PONG #{$1}"
|
133
|
-
when /(^:(\S+)!(\S+) )?PRIVMSG (\S+) :?(.*)/
|
134
|
-
env = { :nick => $2, :userhost => $3, :channel => $4, :message => $5 }
|
135
|
-
type = env[:channel].match(/^#/) ? :channel : :private
|
136
|
-
@bot.dispatch(type, env)
|
137
|
-
when /(^:\S+ )?([4-5]\d\d) \S+ (\S+)/
|
138
|
-
env = {:error => $2.to_i, :message => $2, :nick => $3, :channel => $3}
|
139
|
-
@bot.dispatch(:error, env)
|
140
|
-
when /(^:\S+ )?PONG/
|
141
|
-
@queue.unlock
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def registered?
|
146
|
-
([1,2,3,4] - @registration).empty?
|
147
|
-
end
|
148
|
-
|
149
|
-
def message(msg)
|
150
|
-
@queue << msg
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
class Queue
|
155
|
-
def initialize(socket, server)
|
156
|
-
# We need server for pinging us out of an excess flood
|
157
|
-
@socket, @server = socket, server
|
158
|
-
@queue, @lock, @transfered = [], false, 0
|
159
|
-
end
|
160
|
-
|
161
|
-
def lock
|
162
|
-
@lock = true
|
163
|
-
end
|
164
|
-
|
165
|
-
def unlock
|
166
|
-
@lock, @transfered = false, 0
|
167
|
-
invoke
|
168
|
-
end
|
169
|
-
|
170
|
-
def <<(message)
|
171
|
-
@queue << message
|
172
|
-
invoke
|
173
|
-
end
|
174
|
-
|
175
|
-
private
|
176
|
-
def message_to_send?
|
177
|
-
!@lock && !@queue.empty?
|
178
|
-
end
|
179
|
-
|
180
|
-
def transfered_after_next_send
|
181
|
-
@transfered + @queue.first.size + 2 # the 2 is for \r\n
|
182
|
-
end
|
183
|
-
|
184
|
-
def exceed_limit?
|
185
|
-
transfered_after_next_send > 1472
|
186
|
-
end
|
187
|
-
|
188
|
-
def lock_and_ping
|
189
|
-
lock
|
190
|
-
@socket.print "PING :#{@server}\r\n"
|
191
|
-
end
|
192
|
-
|
193
|
-
def next_message
|
194
|
-
@queue.shift.to_s.chomp + "\r\n"
|
195
|
-
end
|
196
|
-
|
197
|
-
def invoke
|
198
|
-
while message_to_send?
|
199
|
-
if exceed_limit?
|
200
|
-
lock_and_ping; break
|
201
|
-
else
|
202
|
-
@transfered = transfered_after_next_send
|
203
|
-
@socket.print next_message
|
204
|
-
# puts ">> #{msg}" if @bot.config.verbose
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
3
|
+
$bot = Isaac::Bot.new
|
210
4
|
|
211
5
|
%w(configure helpers on).each do |method|
|
212
6
|
eval(<<-EOF)
|
213
7
|
def #{method}(*args, &block)
|
214
|
-
|
8
|
+
$bot.#{method}(*args, &block)
|
215
9
|
end
|
216
10
|
EOF
|
217
11
|
end
|
@@ -219,6 +13,6 @@ end
|
|
219
13
|
at_exit do
|
220
14
|
unless defined?(Test::Unit)
|
221
15
|
raise $! if $!
|
222
|
-
|
16
|
+
$bot.start
|
223
17
|
end
|
224
18
|
end
|
data/lib/isaac/bot.rb
ADDED
@@ -0,0 +1,338 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Isaac
|
4
|
+
VERSION = '0.2.1'
|
5
|
+
|
6
|
+
Config = Struct.new(:server, :port, :ssl, :password, :nick, :realname, :version, :environment, :verbose)
|
7
|
+
|
8
|
+
class Bot
|
9
|
+
attr_accessor :config, :irc, :nick, :channel, :message, :user, :host, :match,
|
10
|
+
:error
|
11
|
+
|
12
|
+
def initialize(&b)
|
13
|
+
@events = {}
|
14
|
+
@config = Config.new("localhost", 6667, false, nil, "isaac", "Isaac", 'isaac', :production, false)
|
15
|
+
|
16
|
+
instance_eval(&b) if block_given?
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure(&b)
|
20
|
+
b.call(@config)
|
21
|
+
end
|
22
|
+
|
23
|
+
def on(event, match=//, &block)
|
24
|
+
match = match.to_s if match.is_a? Integer
|
25
|
+
(@events[event] ||= []) << [Regexp.new(match), block]
|
26
|
+
end
|
27
|
+
|
28
|
+
def helpers(&b)
|
29
|
+
instance_eval(&b)
|
30
|
+
end
|
31
|
+
|
32
|
+
def halt
|
33
|
+
throw :halt
|
34
|
+
end
|
35
|
+
|
36
|
+
def raw(command)
|
37
|
+
@irc.message(command)
|
38
|
+
end
|
39
|
+
|
40
|
+
def msg(recipient, text)
|
41
|
+
raw("PRIVMSG #{recipient} :#{text}")
|
42
|
+
end
|
43
|
+
|
44
|
+
def action(recipient, text)
|
45
|
+
raw("PRIVMSG #{recipient} :\001ACTION #{text}\001")
|
46
|
+
end
|
47
|
+
|
48
|
+
def join(*channels)
|
49
|
+
channels.each {|channel| raw("JOIN #{channel}")}
|
50
|
+
end
|
51
|
+
|
52
|
+
def part(*channels)
|
53
|
+
channels.each {|channel| raw("PART #{channel}")}
|
54
|
+
end
|
55
|
+
|
56
|
+
def topic(channel, text)
|
57
|
+
raw("TOPIC #{channel} :#{text}")
|
58
|
+
end
|
59
|
+
|
60
|
+
def mode(channel, option)
|
61
|
+
raw("MODE #{channel} #{option}")
|
62
|
+
end
|
63
|
+
|
64
|
+
def kick(channel, user, reason=nil)
|
65
|
+
raw("KICK #{channel} #{user} :#{reason}")
|
66
|
+
end
|
67
|
+
|
68
|
+
def quit(message=nil)
|
69
|
+
command = message ? "QUIT :#{message}" : "QUIT"
|
70
|
+
raw command
|
71
|
+
end
|
72
|
+
|
73
|
+
def start
|
74
|
+
puts "Connecting to #{@config.server}:#{@config.port}" unless @config.environment == :test
|
75
|
+
@irc = IRC.new(self, @config)
|
76
|
+
@irc.connect
|
77
|
+
end
|
78
|
+
|
79
|
+
def message
|
80
|
+
@message ||= ""
|
81
|
+
end
|
82
|
+
|
83
|
+
def dispatch(event, msg=nil)
|
84
|
+
if msg
|
85
|
+
@nick, @user, @host, @channel, @error, @message =
|
86
|
+
msg.nick, msg.user, msg.host, msg.channel, msg.error, msg.message
|
87
|
+
end
|
88
|
+
|
89
|
+
if handler = find(event, message)
|
90
|
+
regexp, block = *handler
|
91
|
+
self.match = message.match(regexp).captures
|
92
|
+
invoke block
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
def find(type, message)
|
98
|
+
if events = @events[type]
|
99
|
+
events.detect {|regexp,_| message.match(regexp)}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def invoke(block)
|
104
|
+
mc = class << self; self; end
|
105
|
+
mc.send :define_method, :__isaac_event_handler, &block
|
106
|
+
|
107
|
+
# -1 splat arg, send everything
|
108
|
+
# 0 no args, send nothing
|
109
|
+
# 1 defined number of args, send only those
|
110
|
+
bargs = case block.arity <=> 0
|
111
|
+
when -1; match
|
112
|
+
when 0; []
|
113
|
+
when 1; match[0..block.arity-1]
|
114
|
+
end
|
115
|
+
|
116
|
+
catch(:halt) { __isaac_event_handler(*bargs) }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class IRC
|
121
|
+
def initialize(bot, config)
|
122
|
+
@bot, @config = bot, config
|
123
|
+
@transfered = 0
|
124
|
+
@registration = []
|
125
|
+
end
|
126
|
+
|
127
|
+
def connect
|
128
|
+
tcp_socket = TCPSocket.open(@config.server, @config.port)
|
129
|
+
|
130
|
+
if @config.ssl
|
131
|
+
begin
|
132
|
+
require 'openssl'
|
133
|
+
rescue ::LoadError
|
134
|
+
raise(RuntimeError,"unable to require 'openssl'",caller)
|
135
|
+
end
|
136
|
+
|
137
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
138
|
+
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
139
|
+
|
140
|
+
unless @config.environment == :test
|
141
|
+
puts "Using SSL with #{@config.server}:#{@config.port}"
|
142
|
+
end
|
143
|
+
|
144
|
+
@socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, ssl_context)
|
145
|
+
@socket.sync = true
|
146
|
+
@socket.connect
|
147
|
+
else
|
148
|
+
@socket = tcp_socket
|
149
|
+
end
|
150
|
+
|
151
|
+
@queue = Queue.new(@socket, @bot.config.server)
|
152
|
+
message "PASS #{@config.password}" if @config.password
|
153
|
+
message "NICK #{@config.nick}"
|
154
|
+
message "USER #{@config.nick} 0 * :#{@config.realname}"
|
155
|
+
@queue.lock
|
156
|
+
|
157
|
+
while line = @socket.gets
|
158
|
+
parse line
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def parse(input)
|
163
|
+
puts "<< #{input}" if @bot.config.verbose
|
164
|
+
msg = Message.new(input)
|
165
|
+
|
166
|
+
if ("001".."004").include? msg.command
|
167
|
+
@registration << msg.command
|
168
|
+
if registered?
|
169
|
+
@queue.unlock
|
170
|
+
@bot.dispatch(:connect)
|
171
|
+
end
|
172
|
+
elsif msg.command == "PRIVMSG"
|
173
|
+
if msg.params.last == "\001VERSION\001"
|
174
|
+
message "NOTICE #{msg.nick} :\001VERSION #{@bot.config.version}\001"
|
175
|
+
end
|
176
|
+
|
177
|
+
type = msg.channel? ? :channel : :private
|
178
|
+
@bot.dispatch(type, msg)
|
179
|
+
elsif msg.error?
|
180
|
+
@bot.dispatch(:error, msg)
|
181
|
+
elsif msg.command == "PING"
|
182
|
+
@queue.unlock
|
183
|
+
message "PONG :#{msg.params.first}"
|
184
|
+
elsif msg.command == "PONG"
|
185
|
+
@queue.unlock
|
186
|
+
else
|
187
|
+
event = msg.command.downcase.to_sym
|
188
|
+
@bot.dispatch(event, msg)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def registered?
|
193
|
+
(("001".."004").to_a - @registration).empty?
|
194
|
+
end
|
195
|
+
|
196
|
+
def message(msg)
|
197
|
+
@queue << msg
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
class Message
|
202
|
+
attr_accessor :raw, :prefix, :command, :params
|
203
|
+
|
204
|
+
def initialize(msg=nil)
|
205
|
+
@raw = msg
|
206
|
+
parse if msg
|
207
|
+
end
|
208
|
+
|
209
|
+
def numeric_reply?
|
210
|
+
@numeric_reply ||= !!@command.match(/^\d\d\d$/)
|
211
|
+
end
|
212
|
+
|
213
|
+
def parse
|
214
|
+
match = @raw.match(/(^:(\S+) )?(\S+)(.*)/)
|
215
|
+
_, @prefix, @command, raw_params = match.captures
|
216
|
+
|
217
|
+
raw_params.strip!
|
218
|
+
if match = raw_params.match(/:(.*)/)
|
219
|
+
@params = match.pre_match.split(" ")
|
220
|
+
@params << match[1]
|
221
|
+
else
|
222
|
+
@params = raw_params.split(" ")
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def nick
|
227
|
+
return unless @prefix
|
228
|
+
@nick ||= @prefix[/^(\S+)!/, 1]
|
229
|
+
end
|
230
|
+
|
231
|
+
def user
|
232
|
+
return unless @prefix
|
233
|
+
@user ||= @prefix[/^\S+!(\S+)@/, 1]
|
234
|
+
end
|
235
|
+
|
236
|
+
def host
|
237
|
+
return unless @prefix
|
238
|
+
@host ||= @prefix[/@(\S+)$/, 1]
|
239
|
+
end
|
240
|
+
|
241
|
+
def server
|
242
|
+
return unless @prefix
|
243
|
+
return if @prefix.match(/[@!]/)
|
244
|
+
@server ||= @prefix[/^(\S+)/, 1]
|
245
|
+
end
|
246
|
+
|
247
|
+
def error?
|
248
|
+
!!error
|
249
|
+
end
|
250
|
+
|
251
|
+
def error
|
252
|
+
return @error if @error
|
253
|
+
@error = command.to_i if numeric_reply? && command[/[45]\d\d/]
|
254
|
+
end
|
255
|
+
|
256
|
+
def channel?
|
257
|
+
!!channel
|
258
|
+
end
|
259
|
+
|
260
|
+
def channel
|
261
|
+
return @channel if @channel
|
262
|
+
if regular_command? and params.first.start_with?("#")
|
263
|
+
@channel = params.first
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def message
|
268
|
+
return @message if @message
|
269
|
+
if error?
|
270
|
+
@message = error.to_s
|
271
|
+
elsif regular_command?
|
272
|
+
@message = params.last
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
private
|
277
|
+
# This is a late night hack. Fix.
|
278
|
+
def regular_command?
|
279
|
+
%w(PRIVMSG JOIN PART QUIT).include? command
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
class Queue
|
284
|
+
def initialize(socket, server)
|
285
|
+
# We need server for pinging us out of an excess flood
|
286
|
+
@socket, @server = socket, server
|
287
|
+
@queue, @lock, @transfered = [], false, 0
|
288
|
+
end
|
289
|
+
|
290
|
+
def lock
|
291
|
+
@lock = true
|
292
|
+
end
|
293
|
+
|
294
|
+
def unlock
|
295
|
+
@lock, @transfered = false, 0
|
296
|
+
invoke
|
297
|
+
end
|
298
|
+
|
299
|
+
def <<(message)
|
300
|
+
@queue << message
|
301
|
+
invoke
|
302
|
+
end
|
303
|
+
|
304
|
+
private
|
305
|
+
def message_to_send?
|
306
|
+
!@lock && !@queue.empty?
|
307
|
+
end
|
308
|
+
|
309
|
+
def transfered_after_next_send
|
310
|
+
@transfered + @queue.first.size + 2 # the 2 is for \r\n
|
311
|
+
end
|
312
|
+
|
313
|
+
def exceed_limit?
|
314
|
+
transfered_after_next_send > 1472
|
315
|
+
end
|
316
|
+
|
317
|
+
def lock_and_ping
|
318
|
+
lock
|
319
|
+
@socket.print "PING :#{@server}\r\n"
|
320
|
+
end
|
321
|
+
|
322
|
+
def next_message
|
323
|
+
@queue.shift.to_s.chomp + "\r\n"
|
324
|
+
end
|
325
|
+
|
326
|
+
def invoke
|
327
|
+
while message_to_send?
|
328
|
+
if exceed_limit?
|
329
|
+
lock_and_ping; break
|
330
|
+
else
|
331
|
+
@transfered = transfered_after_next_send
|
332
|
+
@socket.print next_message
|
333
|
+
# puts ">> #{msg}" if @bot.config.verbose
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: isaac
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Harry Vangberg
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-21 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -20,13 +20,14 @@ executables: []
|
|
20
20
|
extensions: []
|
21
21
|
|
22
22
|
extra_rdoc_files:
|
23
|
-
-
|
23
|
+
- CHANGES
|
24
24
|
- README.rdoc
|
25
25
|
files:
|
26
26
|
- README.rdoc
|
27
|
-
-
|
27
|
+
- CHANGES
|
28
28
|
- isaac.gemspec
|
29
29
|
- lib/isaac.rb
|
30
|
+
- lib/isaac/bot.rb
|
30
31
|
has_rdoc: true
|
31
32
|
homepage: http://github.com/ichverstehe/isaac
|
32
33
|
licenses: []
|
data/LICENSE
DELETED
@@ -1,6 +0,0 @@
|
|
1
|
-
------------------------------------------------------------------------------
|
2
|
-
"THE BEER-WARE LICENSE" (Revision 42):
|
3
|
-
<ichverstehe@gmail.com> wrote this file. As long as you retain this notice you
|
4
|
-
can do whatever you want with this stuff. If we meet some day, and you think
|
5
|
-
this stuff is worth it, you can buy me a beer in return.
|
6
|
-
------------------------------------------------------------------------------
|