isaac 0.2.2 → 0.2.5

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.
Files changed (4) hide show
  1. data/README.rdoc +7 -14
  2. data/isaac.gemspec +3 -2
  3. data/lib/isaac.rb +116 -75
  4. metadata +6 -4
@@ -45,6 +45,13 @@ If you want to match private messages use the +on :private+ event:
45
45
  msg nick, "Login successful!"
46
46
  end
47
47
 
48
+ You can also pass the RegExp captures as block arguments:
49
+
50
+ on :channel, /catch this: (.*) and this: (.*)/ do |first, last|
51
+ # `first` will contain the first regexp capture,
52
+ # `last` the second.
53
+ end
54
+
48
55
  === Defining helpers
49
56
  Helpers should not be defined in the top level, but instead using the +helpers+-constructor:
50
57
 
@@ -67,20 +74,6 @@ Errors, as specified by RFC 1459, can be reacted upon as well. If you e.g. try t
67
74
 
68
75
  Available variables: +nick+ and +channel+.
69
76
 
70
- === Send commands from outside an event (not implemented in Shaft atm)
71
- You might want to send messages, join channels etc. without it strictly being the result of an on()-event, e.g. send a message every time a RSS feed is updated or whatever. You can use +Isaac.execute+ for that, and all your normal commands, +msg+, +join+, +topic+ etc. will be available:
72
-
73
- class K
74
- def smoke(brand)
75
- Isaac.execute { msg "harryjr", "you should smoke #{brand} cigarettes" }
76
- end
77
- end
78
-
79
- on :connect do
80
- k = K.new
81
- k.smoke("Lucky Strike")
82
- end
83
-
84
77
  == Contribute
85
78
  The source is hosted at GitHub: http://github.com/ichverstehe/isaac
86
79
 
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "isaac"
3
- s.version = "0.2.2"
4
- s.date = "2009-02-23"
3
+ s.version = "0.2.5"
4
+ s.date = "2009-04-25"
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"
@@ -16,3 +16,4 @@ Gem::Specification.new do |s|
16
16
  s.rdoc_options = ["--main", "README.rdoc"]
17
17
  s.extra_rdoc_files = ["LICENSE", "README.rdoc"]
18
18
  end
19
+
@@ -20,53 +20,29 @@ module Isaac
20
20
  instance_eval(&b) if block_given?
21
21
  end
22
22
 
23
- def start
24
- puts "========================================="
25
- puts "Connecting to #{@config.server}:#{@config.port}"
26
- @irc = IRC.new(self, @config)
27
- @irc.connect
28
- puts "========================================="
23
+ def configure(&b)
24
+ b.call(@config)
29
25
  end
30
26
 
31
- def on(event, match=//, &b)
27
+ def on(event, match=//, &block)
32
28
  match = match.to_s if match.is_a? Integer
33
- (@events[event] ||= []) << [Regexp.new(match), b]
29
+ (@events[event] ||= []) << [Regexp.new(match), block]
34
30
  end
35
31
 
36
32
  def helpers(&b)
37
- instance_eval &b
38
- end
39
-
40
- def configure(&b)
41
- b.call(@config)
42
- end
43
-
44
- def dispatch(event, env={})
45
- self.nick, self.userhost, self.channel, self.error =
46
- env[:nick], env[:userhost], env[:channel], env[:error]
47
- self.message = env[:message] || ""
48
-
49
- event = @events[event] && @events[event].detect do |regexp,_|
50
- message.match(regexp)
51
- end
52
-
53
- if event
54
- regexp, block = *event
55
- self.match = message.match(regexp).captures
56
- catch(:halt) { instance_eval(&block) }
57
- end
33
+ instance_eval(&b)
58
34
  end
59
35
 
60
36
  def halt
61
37
  throw :halt
62
38
  end
63
39
 
64
- def raw(m)
65
- @irc.message(m)
40
+ def raw(command)
41
+ @irc.message(command)
66
42
  end
67
43
 
68
- def msg(recipient, m)
69
- raw("PRIVMSG #{recipient} :#{m}")
44
+ def msg(recipient, text)
45
+ raw("PRIVMSG #{recipient} :#{text}")
70
46
  end
71
47
 
72
48
  def join(*channels)
@@ -80,6 +56,44 @@ module Isaac
80
56
  def topic(channel, text)
81
57
  raw("TOPIC #{channel} :#{text}")
82
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
83
97
  end
84
98
 
85
99
  class IRC
@@ -87,56 +101,44 @@ module Isaac
87
101
  @bot, @config = bot, config
88
102
  @transfered = 0
89
103
  @registration = []
90
- @lock = false
91
- @queue = []
92
104
  end
93
105
 
94
106
  def connect
95
107
  @socket = TCPSocket.open(@config.server, @config.port)
96
- message "PASSWORD #{@config.password}" if @config.password
108
+ @queue = Queue.new(@socket, @bot.config.server)
109
+ message "PASS #{@config.password}" if @config.password
97
110
  message "NICK #{@config.nick}"
98
111
  message "USER #{@config.nick} 0 * :#{@config.realname}"
99
- @lock = true
112
+ @queue.lock
100
113
 
101
- # This should probably be somewhere else..
102
- if @config.environment == :test
103
- Thread.start {
104
- while line = @socket.gets
105
- parse line
106
- end
107
- }
108
- else
109
- while line = @socket.gets
110
- parse line
111
- end
114
+ while line = @socket.gets
115
+ parse line
112
116
  end
113
117
  end
114
118
 
115
119
  def parse(input)
116
120
  puts "<< #{input}" if @bot.config.verbose
117
- case input
118
- when /^:\S+ 00([1-4])/
119
- @registration << $1.to_i
121
+ case input.chomp
122
+ when /(^:\S+ )?00([1-4])/
123
+ @registration << $2.to_i
120
124
  if registered?
121
- @lock = false
125
+ @queue.unlock
122
126
  @bot.dispatch(:connect)
123
- continue_queue
124
127
  end
125
- when /^:(\S+)!\S+ PRIVMSG \S+ :?\001VERSION\001/
126
- message "NOTICE #{$1} :\001VERSION #{@bot.config.version}\001"
128
+ when /(^:(\S+)!\S+ )?PRIVMSG \S+ :?\001VERSION\001/
129
+ message "NOTICE #{$2} :\001VERSION #{@bot.config.version}\001"
127
130
  when /^PING (\S+)/
128
- @transfered, @lock = 0, false
131
+ @queue.unlock
129
132
  message "PONG #{$1}"
130
- when /^:(\S+)!(\S+) PRIVMSG (\S+) :?(.*)/
131
- env = { :nick => $1, :userhost => $2, :channel => $3, :message => $4 }
133
+ when /(^:(\S+)!(\S+) )?PRIVMSG (\S+) :?(.*)/
134
+ env = { :nick => $2, :userhost => $3, :channel => $4, :message => $5 }
132
135
  type = env[:channel].match(/^#/) ? :channel : :private
133
136
  @bot.dispatch(type, env)
134
- when /^:\S+ ([4-5]\d\d) \S+ (\S+)/
135
- env = {:error => $1.to_i, :message => $1, :nick => $2, :channel => $2}
137
+ when /(^:\S+ )?([4-5]\d\d) \S+ (\S+)/
138
+ env = {:error => $2.to_i, :message => $2, :nick => $3, :channel => $3}
136
139
  @bot.dispatch(:error, env)
137
- when /^:\S+ PONG/
138
- @transfered, @lock = 0, false
139
- continue_queue
140
+ when /(^:\S+ )?PONG/
141
+ @queue.unlock
140
142
  end
141
143
  end
142
144
 
@@ -146,21 +148,60 @@ module Isaac
146
148
 
147
149
  def message(msg)
148
150
  @queue << msg
149
- continue_queue
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"
150
195
  end
151
196
 
152
- def continue_queue
153
- # <= 1472 allows for \n
154
- while !@lock && msg = @queue.shift
155
- if (@transfered + msg.size) < 1472
156
- @socket.puts msg
157
- puts ">> #{msg}" if @bot.config.verbose
158
- @transfered += msg.size + 1
197
+ def invoke
198
+ while message_to_send?
199
+ if exceed_limit?
200
+ lock_and_ping; break
159
201
  else
160
- @queue.unshift(msg)
161
- @lock = true
162
- @socket.puts "PING :#{@bot.config.server}"
163
- break
202
+ @transfered = transfered_after_next_send
203
+ @socket.print next_message
204
+ # puts ">> #{msg}" if @bot.config.verbose
164
205
  end
165
206
  end
166
207
  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.2
4
+ version: 0.2.5
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-02-23 00:00:00 +01:00
12
+ date: 2009-04-25 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -29,6 +29,8 @@ files:
29
29
  - lib/isaac.rb
30
30
  has_rdoc: true
31
31
  homepage: http://github.com/ichverstehe/isaac
32
+ licenses: []
33
+
32
34
  post_install_message:
33
35
  rdoc_options:
34
36
  - --main
@@ -50,9 +52,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
52
  requirements: []
51
53
 
52
54
  rubyforge_project: isaac
53
- rubygems_version: 1.3.1
55
+ rubygems_version: 1.3.3
54
56
  signing_key:
55
- specification_version: 2
57
+ specification_version: 3
56
58
  summary: The smallish DSL for writing IRC bots
57
59
  test_files: []
58
60