balotelli 0.4.2.1 → 0.5.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: 7addde5a832912208f7790a6559c172d818a555a
4
- data.tar.gz: 0a86ccc08b3e928152d024d9e8e154aa36cdbf46
3
+ metadata.gz: 4af3a056d835bb509c9a8eeae2591a21c9f51f4a
4
+ data.tar.gz: fcb7b59a3e774c88e92318b375acdffe4ae3bde5
5
5
  SHA512:
6
- metadata.gz: a252b2a40886641e5912b5818416a53d014b3c2b1a026f9a688153c1a5397d162be1da2d4b755a36250ee27487cbe5526940eba3a77108c90a59b11982d18168
7
- data.tar.gz: 9f37a6595af818d752e9cfcdd7814ad183ccf09364b6b36f6445ca8137e3b685bfdacd64cb9c1b809ec0307eccfc1f5910bdab42dfba919e1f59dfaa245d6450
6
+ metadata.gz: 1cda3aa74be90d37dac1f12f4dabd1b34c9336c4972b941d3e1b65691421e00d95d7f52e904be66f82564859a5ec616294beba6eb4d65e629597b70251924083
7
+ data.tar.gz: 8dfff8deb52f2b9cfcff2bce18308b28b5d14f777d2edf34b1aa7e479fbf0d03b591da357f9a35a14fa37c70747eb2dedfc89c20481d9ebaa654ffee51b3fbd2
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- balotelli (0.4.2.1)
4
+ balotelli (0.5.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -10,6 +10,7 @@ GEM
10
10
  rake (10.4.2)
11
11
 
12
12
  PLATFORMS
13
+ java
13
14
  ruby
14
15
 
15
16
  DEPENDENCIES
@@ -1,11 +1,14 @@
1
1
  require 'balotelli/core/irc'
2
- require 'balotelli/core/router'
2
+ require 'balotelli/core/router/router'
3
+ require 'balotelli/core/router/match'
4
+ require 'balotelli/core/router/action'
3
5
  require 'balotelli/core/priv_msg'
4
6
  require 'balotelli/core/join'
5
7
  require 'balotelli/core/kick'
6
8
  require 'balotelli/core/irc_logger'
7
9
  require 'balotelli/core/utils'
8
10
  require 'balotelli/config'
11
+ require 'balotelli/thread/pool'
9
12
 
10
13
  module Balotelli
11
14
  class Base
@@ -66,6 +69,7 @@ module Balotelli
66
69
  def setup
67
70
  setup_router
68
71
 
72
+ @pool = Thread::Pool.new(Thread::Pool.cpu_count)
69
73
  @modules = {}
70
74
  @cache = Hash.new { |hash, key| hash[key] = {} }
71
75
  @cvs = {}
@@ -95,8 +99,6 @@ module Balotelli
95
99
  def mod_match(str, priv = false)
96
100
  if str =~ /\A[^a-zA-Z0-9\s]?(\S+) ?(.*)/
97
101
  if (mod = @cache[:modules][Regexp.last_match(1).downcase])
98
- str.slice!(0..Regexp.last_match(1).length)
99
- str.lstrip!
100
102
  mod.match(Regexp.last_match(2), priv)
101
103
  end
102
104
  elsif str == :join
@@ -126,7 +128,7 @@ module Balotelli
126
128
  elsif !(str =~ /(JOIN\s|PRIVMSG\s)/)
127
129
  process_table(str)
128
130
  else
129
- Thread.new { process_message(str) }
131
+ @pool.process { process_message(str) }
130
132
  end
131
133
  end
132
134
 
@@ -140,25 +142,23 @@ module Balotelli
140
142
 
141
143
  def process_private_message(str, user, channel, message)
142
144
  privacy = !(channel =~ /#.+/)
143
- if (route = match(message, privacy)) ||
144
- (route = mod_match(message, privacy))
145
- new_response(user, channel, message, route, Core::PrivMsg, privacy)
145
+ if (matched = match(message, privacy)) ||
146
+ (matched = mod_match(message, privacy))
147
+ new_response(user, channel, message, matched, Core::PrivMsg, privacy)
146
148
  end
147
149
  end
148
150
 
149
151
  def process_join(str, user, channel)
150
- if (route = match(:join)) || (route = mod_match(:join))
151
- new_response(user, channel, nil, route, Core::Join)
152
+ if (matched = match(:join)) || (matched = mod_match(:join))
153
+ new_response(user, channel, nil, matched, Core::Join)
152
154
  end
153
155
  end
154
156
 
155
157
 
156
158
  def new_response(user, channel, message, route_match, klass, priv = nil)
157
- route_pattern, block, module_name = route_match.flatten
158
159
  message = klass.new(*[user, channel, message, priv].compact)
159
- matchdata = message.content.match(route_pattern) if route_pattern.is_a?(Regexp)
160
- new(block, message, matchdata).tap do |response|
161
- response.extend(module_name) if module_name.class.to_s == 'Module'
160
+ new(route_match.block, message, route_match.match_data).tap do |response|
161
+ response.extend(route_match.mod_name) if route_match.mod_name.class == ::Module
162
162
  end.execute!
163
163
  end
164
164
 
@@ -8,6 +8,28 @@ module Balotelli
8
8
  "#{datetime.utc}: #{msg}\n"
9
9
  end
10
10
 
11
+ module Methods
12
+ def sgets
13
+ str = orig_sgets
14
+ to_log = "<<#{str.inspect}\n"
15
+ @log_file.info(to_log)
16
+ if str =~ /\A:?\S+ \S+ (#\S+) .*/
17
+ @logger.channel_log(Regexp.last_match(1).downcase, to_log)
18
+ end
19
+ str
20
+ end
21
+
22
+ def sputs(str)
23
+ orig_sputs(str)
24
+ to_log = ">>#{str.inspect}\n"
25
+ @log_file.info(to_log)
26
+ if str =~ /\A:?\S+ (#\S+) .*/
27
+ @logger.channel_log(Regexp.last_match(1).downcase, to_log)
28
+ end
29
+ str
30
+ end
31
+ end
32
+
11
33
  attr_reader :log_file, :dir, :channels, :channels_logs
12
34
 
13
35
  def initialize(dir = '', log_name = 'logs.log', channels = [])
@@ -44,28 +66,6 @@ module Balotelli
44
66
  end
45
67
  end
46
68
 
47
- module Methods
48
- def sgets
49
- str = orig_sgets
50
- to_log = "<<#{str.inspect}\n"
51
- @log_file.info(to_log)
52
- if str =~ /\A:?\S+ \S+ (#\S+) .*/
53
- @logger.channel_log(Regexp.last_match(1).downcase, to_log)
54
- end
55
- str
56
- end
57
-
58
- def sputs(str)
59
- orig_sputs(str)
60
- to_log = ">>#{str.inspect}\n"
61
- @log_file.info(to_log)
62
- if str =~ /\A:?\S+ (#\S+) .*/
63
- @logger.channel_log(Regexp.last_match(1).downcase, to_log)
64
- end
65
- str
66
- end
67
- end
68
-
69
69
  def define_log_method
70
70
  define_method :log_file do |str|
71
71
  class_variable_get(:@log_file)
@@ -0,0 +1,13 @@
1
+ module Balotelli
2
+ module Core
3
+ module Router
4
+ class Action
5
+ attr_reader :block, :mod_name
6
+ def initialize(block, mod_name)
7
+ @block = block
8
+ @mod_name = mod_name
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ module Balotelli
2
+ module Core
3
+ module Router
4
+ class Match
5
+ attr_reader :data, :pattern, :block, :mod_name
6
+ def initialize(data, pattern, action, privacy)
7
+ @data = data
8
+ @pattern = pattern
9
+ @block = action.block
10
+ @mod_name = action.mod_name
11
+ @private = privacy
12
+ end
13
+
14
+ def is_private?
15
+ @private
16
+ end
17
+
18
+ def match_data
19
+ @match_data ||= data.match(pattern) if pattern.is_a?(Regexp)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,51 @@
1
+ module Balotelli
2
+ module Core
3
+ module Router
4
+ RouteCollisionError = Class.new(StandardError)
5
+
6
+ def setup_router
7
+ @routes = {}
8
+ end
9
+
10
+ def on(route, options = {}, &block)
11
+ raise 'no block given' if block.nil?
12
+
13
+ privacy = options.fetch(:private, false)
14
+
15
+ if privacy == :both
16
+ on(route, options.clone.tap { |o| o[:private] = true }, &block)
17
+ on(route, options.clone.tap { |o| o[:private] = false }, &block)
18
+ return
19
+ end
20
+
21
+ @routes[route] ||= {}
22
+
23
+ if @routes[route][privacy] && !options[:force]
24
+ raise RouteCollisionError,
25
+ "Route #{route.inspect}, private: #{options[:private]} already exists"
26
+ end
27
+
28
+ @routes[route][privacy] = Action.new(block, self)
29
+ end
30
+
31
+ def match?(str, route)
32
+ case route
33
+ when Regexp
34
+ str =~ route
35
+ when String
36
+ str == route
37
+ when Symbol
38
+ str == route
39
+ end
40
+ end
41
+
42
+ def match(str, priv = false)
43
+ if (route = @routes.detect { |k, v| match?(str, k) && v[priv] })
44
+ pattern = route[0]
45
+ action = route[1][priv]
46
+ Match.new(str, pattern, action, priv)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,4 +1,4 @@
1
- require 'balotelli/core/router'
1
+ require 'balotelli/core/router/router'
2
2
 
3
3
  module Balotelli
4
4
  module Module
@@ -0,0 +1,470 @@
1
+ # https://github.com/meh/ruby-thread/blob/master/lib/thread/pool.rb
2
+ require 'thread'
3
+ require 'etc'
4
+
5
+ # A pool is a container of a limited amount of threads to which you can add
6
+ # tasks to run.
7
+ #
8
+ # This is usually more performant and less memory intensive than creating a
9
+ # new thread for every task.
10
+ class Thread::Pool
11
+ # A task incapsulates a block being ran by the pool and the arguments to pass
12
+ # to it.
13
+ class Task
14
+ Timeout = Class.new(Exception)
15
+ Asked = Class.new(Exception)
16
+
17
+ attr_reader :pool, :timeout, :exception, :thread, :started_at, :result
18
+
19
+ # Create a task in the given pool which will pass the arguments to the
20
+ # block.
21
+ def initialize(pool, *args, &block)
22
+ @pool = pool
23
+ @arguments = args
24
+ @block = block
25
+
26
+ @running = false
27
+ @finished = false
28
+ @timedout = false
29
+ @terminated = false
30
+ end
31
+
32
+ def running?
33
+ @running
34
+ end
35
+
36
+ def finished?
37
+ @finished
38
+ end
39
+
40
+ def timeout?
41
+ @timedout
42
+ end
43
+
44
+ def terminated?
45
+ @terminated
46
+ end
47
+
48
+ # Execute the task.
49
+ def execute
50
+ return if terminated? || running? || finished?
51
+
52
+ @thread = Thread.current
53
+ @running = true
54
+ @started_at = Time.now
55
+
56
+ pool.__send__ :wake_up_timeout
57
+
58
+ begin
59
+ @result = @block.call(*@arguments)
60
+ rescue Exception => reason
61
+ if reason.is_a? Timeout
62
+ @timedout = true
63
+ elsif reason.is_a? Asked
64
+ return
65
+ else
66
+ @exception = reason
67
+ raise @exception if Thread::Pool.abort_on_exception
68
+ end
69
+ end
70
+
71
+ @running = false
72
+ @finished = true
73
+ @thread = nil
74
+ end
75
+
76
+ # Raise an exception in the thread used by the task.
77
+ def raise(exception)
78
+ @thread.raise(exception) if @thread
79
+ end
80
+
81
+ # Terminate the exception with an optionally given exception.
82
+ def terminate!(exception = Asked)
83
+ return if terminated? || finished? || timeout?
84
+
85
+ @terminated = true
86
+
87
+ return unless running?
88
+
89
+ self.raise exception
90
+ end
91
+
92
+ # Force the task to timeout.
93
+ def timeout!
94
+ terminate! Timeout
95
+ end
96
+
97
+ # Timeout the task after the given time.
98
+ def timeout_after(time)
99
+ @timeout = time
100
+
101
+ pool.__send__ :timeout_for, self, time
102
+
103
+ self
104
+ end
105
+ end
106
+
107
+ attr_reader :min, :max, :spawned, :waiting
108
+
109
+ # Create the pool with minimum and maximum threads.
110
+ #
111
+ # The pool will start with the minimum amount of threads created and will
112
+ # spawn new threads until the max is reached in case of need.
113
+ #
114
+ # A default block can be passed, which will be used to {#process} the passed
115
+ # data.
116
+ def initialize(min, max = nil, &block)
117
+ @min = min
118
+ @max = max || min
119
+ @block = block
120
+
121
+ @cond = ConditionVariable.new
122
+ @mutex = Mutex.new
123
+
124
+ @done = ConditionVariable.new
125
+ @done_mutex = Mutex.new
126
+
127
+ @todo = []
128
+ @workers = []
129
+ @timeouts = {}
130
+
131
+ @spawned = 0
132
+ @waiting = 0
133
+ @shutdown = false
134
+ @trim_requests = 0
135
+ @auto_trim = false
136
+ @idle_trim = nil
137
+ @timeout = nil
138
+
139
+ @mutex.synchronize {
140
+ min.times {
141
+ spawn_thread
142
+ }
143
+ }
144
+ end
145
+
146
+ # Check if the pool has been shut down.
147
+ def shutdown?
148
+ !!@shutdown
149
+ end
150
+
151
+ # Check if auto trimming is enabled.
152
+ def auto_trim?
153
+ @auto_trim
154
+ end
155
+
156
+ # Enable auto trimming, unneeded threads will be deleted until the minimum
157
+ # is reached.
158
+ def auto_trim!
159
+ @auto_trim = true
160
+
161
+ self
162
+ end
163
+
164
+ # Disable auto trimming.
165
+ def no_auto_trim!
166
+ @auto_trim = false
167
+
168
+ self
169
+ end
170
+
171
+ # Check if idle trimming is enabled.
172
+ def idle_trim?
173
+ !@idle_trim.nil?
174
+ end
175
+
176
+ # Enable idle trimming. Unneeded threads will be deleted after the given number of seconds of inactivity.
177
+ # The minimum number of threads is respeced.
178
+ def idle_trim!(timeout)
179
+ @idle_trim = timeout
180
+
181
+ self
182
+ end
183
+
184
+ # Turn of idle trimming.
185
+ def no_idle_trim!
186
+ @idle_trim = nil
187
+
188
+ self
189
+ end
190
+
191
+ # Resize the pool with the passed arguments.
192
+ def resize(min, max = nil)
193
+ @min = min
194
+ @max = max || min
195
+
196
+ trim!
197
+ end
198
+
199
+ # Get the amount of tasks that still have to be run.
200
+ def backlog
201
+ @mutex.synchronize {
202
+ @todo.length
203
+ }
204
+ end
205
+
206
+ # Are all tasks consumed?
207
+ def done?
208
+ @mutex.synchronize {
209
+ _done?
210
+ }
211
+ end
212
+
213
+ # Wait until all tasks are consumed. The caller will be blocked until then.
214
+ def wait(what = :idle)
215
+ case what
216
+ when :done
217
+ until done?
218
+ @done_mutex.synchronize {
219
+ break if _done?
220
+
221
+ @done.wait @done_mutex
222
+ }
223
+ end
224
+
225
+ when :idle
226
+ until idle?
227
+ @done_mutex.synchronize {
228
+ break if _idle?
229
+
230
+ @done.wait @done_mutex
231
+ }
232
+ end
233
+ end
234
+
235
+ self
236
+ end
237
+
238
+ # Check if there are idle workers.
239
+ def idle?
240
+ @mutex.synchronize {
241
+ _idle?
242
+ }
243
+ end
244
+
245
+ # Add a task to the pool which will execute the block with the given
246
+ # argument.
247
+ #
248
+ # If no block is passed the default block will be used if present, an
249
+ # ArgumentError will be raised otherwise.
250
+ def process(*args, &block)
251
+ unless block || @block
252
+ raise ArgumentError, 'you must pass a block'
253
+ end
254
+
255
+ task = Task.new(self, *args, &(block || @block))
256
+
257
+ @mutex.synchronize {
258
+ raise 'unable to add work while shutting down' if shutdown?
259
+
260
+ @todo << task
261
+
262
+ if @waiting == 0 && @spawned < @max
263
+ spawn_thread
264
+ end
265
+
266
+ @cond.signal
267
+ }
268
+
269
+ task
270
+ end
271
+
272
+ alias << process
273
+
274
+ # Trim the unused threads, if forced threads will be trimmed even if there
275
+ # are tasks waiting.
276
+ def trim(force = false)
277
+ @mutex.synchronize {
278
+ if (force || @waiting > 0) && @spawned - @trim_requests > @min
279
+ @trim_requests += 1
280
+ @cond.signal
281
+ end
282
+ }
283
+
284
+ self
285
+ end
286
+
287
+ # Force #{trim}.
288
+ def trim!
289
+ trim true
290
+ end
291
+
292
+ # Shut down the pool instantly without finishing to execute tasks.
293
+ def shutdown!
294
+ @mutex.synchronize {
295
+ @shutdown = :now
296
+ @cond.broadcast
297
+ }
298
+
299
+ wake_up_timeout
300
+
301
+ self
302
+ end
303
+
304
+ # Shut down the pool, it will block until all tasks have finished running.
305
+ def shutdown
306
+ @mutex.synchronize {
307
+ @shutdown = :nicely
308
+ @cond.broadcast
309
+ }
310
+
311
+ until @workers.empty?
312
+ if worker = @workers.first
313
+ worker.join
314
+ end
315
+ end
316
+
317
+ if @timeout
318
+ @shutdown = :now
319
+
320
+ wake_up_timeout
321
+
322
+ @timeout.join
323
+ end
324
+ end
325
+
326
+ # Shutdown the pool after a given amount of time.
327
+ def shutdown_after(timeout)
328
+ Thread.new {
329
+ sleep timeout
330
+
331
+ shutdown
332
+ }
333
+ end
334
+
335
+ class << self
336
+ # If true, tasks will allow raised exceptions to pass through.
337
+ #
338
+ # Similar to Thread.abort_on_exception
339
+ attr_accessor :abort_on_exception
340
+
341
+ def cpu_count
342
+ Etc.nprocessors * 2
343
+ rescue
344
+ 16
345
+ end
346
+ end
347
+
348
+ private
349
+ def timeout_for(task, timeout)
350
+ unless @timeout
351
+ spawn_timeout_thread
352
+ end
353
+
354
+ @mutex.synchronize {
355
+ @timeouts[task] = timeout
356
+
357
+ wake_up_timeout
358
+ }
359
+ end
360
+
361
+ def wake_up_timeout
362
+ if defined? @pipes
363
+ @pipes.last.write_nonblock 'x' rescue nil
364
+ end
365
+ end
366
+
367
+ def spawn_thread
368
+ @spawned += 1
369
+
370
+ thread = Thread.new {
371
+ loop do
372
+ task = @mutex.synchronize {
373
+ if @todo.empty?
374
+ while @todo.empty?
375
+ if @trim_requests > 0
376
+ @trim_requests -= 1
377
+
378
+ break
379
+ end
380
+
381
+ break if shutdown?
382
+
383
+ @waiting += 1
384
+
385
+ done!
386
+
387
+ if @idle_trim and @spawned > @min
388
+ check_time = Time.now + @idle_trim
389
+ @cond.wait @mutex, @idle_trim
390
+ @trim_requests += 1 if Time.now >= check_time && @spawned - @trim_requests > @min
391
+ else
392
+ @cond.wait @mutex
393
+ end
394
+
395
+ @waiting -= 1
396
+ end
397
+
398
+ break if @todo.empty? && shutdown?
399
+ end
400
+
401
+ @todo.shift
402
+ } or break
403
+
404
+ task.execute
405
+
406
+ break if @shutdown == :now
407
+
408
+ trim if auto_trim? && @spawned > @min
409
+ end
410
+
411
+ @mutex.synchronize {
412
+ @spawned -= 1
413
+ @workers.delete thread
414
+ }
415
+ }
416
+
417
+ @workers << thread
418
+
419
+ thread
420
+ end
421
+
422
+ def spawn_timeout_thread
423
+ @pipes = IO.pipe
424
+ @timeout = Thread.new {
425
+ loop do
426
+ now = Time.now
427
+ timeout = @timeouts.map {|task, time|
428
+ next unless task.started_at
429
+
430
+ now - task.started_at + task.timeout
431
+ }.compact.min unless @timeouts.empty?
432
+
433
+ readable, = IO.select([@pipes.first], nil, nil, timeout)
434
+
435
+ break if @shutdown == :now
436
+
437
+ if readable && !readable.empty?
438
+ readable.first.read_nonblock 1024
439
+ end
440
+
441
+ now = Time.now
442
+ @timeouts.each {|task, time|
443
+ next if !task.started_at || task.terminated? || task.finished?
444
+
445
+ if now > task.started_at + task.timeout
446
+ task.timeout!
447
+ end
448
+ }
449
+
450
+ @timeouts.reject! { |task, _| task.terminated? || task.finished? }
451
+
452
+ break if @shutdown == :now
453
+ end
454
+ }
455
+ end
456
+
457
+ def _done?
458
+ @todo.empty? and @waiting == @spawned
459
+ end
460
+
461
+ def _idle?
462
+ @todo.length < @waiting
463
+ end
464
+
465
+ def done!
466
+ @done_mutex.synchronize {
467
+ @done.broadcast if _done? or _idle?
468
+ }
469
+ end
470
+ end
@@ -1,3 +1,3 @@
1
1
  module Balotelli
2
- VERSION = '0.4.2.1'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  end
@@ -37,8 +37,8 @@ class BaseTest < Minitest::Test
37
37
 
38
38
  def test_it_matches_module_routes
39
39
  TestBot.register(Balotelli::Module::Asdf)
40
- assert_equal TestBot.mod_match("asdf Yes, sir")[0], /yes/i
40
+ assert_equal TestBot.mod_match("asdf Yes, sir").pattern, /yes/i
41
41
  TestBot.register(Balotelli::Module::Xyz, "hoh")
42
- assert_equal TestBot.mod_match("!hoh Si si")[0], /si/i
42
+ assert_equal TestBot.mod_match("!hoh Si si").pattern, /si/i
43
43
  end
44
44
  end
@@ -20,7 +20,9 @@ class RouterTest < Minitest::Test
20
20
  def test_it_mathes_routes
21
21
  lam = -> { puts 'kk' }
22
22
  @route.on %r{ono}i, private: true, &lam
23
- assert @route.match('onOmatopeja', true) == [%r{ono}i, [lam, @route]]
23
+ first_match = @route.match('onOmatopeja', true)
24
+ assert first_match.pattern == %r{ono}i
25
+ assert first_match.block == lam
24
26
  refute @route.match('onOmatopeja', false)
25
27
  @route.on 'asdf', &lam
26
28
  assert @route.match('asdf')
metadata CHANGED
@@ -1,52 +1,52 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: balotelli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcin Henryk Bartkowiak
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-30 00:00:00.000000000 Z
11
+ date: 2016-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
18
  version: '0'
20
- type: :development
19
+ name: bundler
21
20
  prerelease: false
21
+ type: :development
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
32
  version: 10.4.2
34
- type: :development
33
+ name: rake
35
34
  prerelease: false
35
+ type: :development
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 10.4.2
41
41
  - !ruby/object:Gem::Dependency
42
- name: minitest
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - "~>"
46
45
  - !ruby/object:Gem::Version
47
46
  version: 5.8.0
48
- type: :development
47
+ name: minitest
49
48
  prerelease: false
49
+ type: :development
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
@@ -76,9 +76,12 @@ files:
76
76
  - lib/balotelli/core/join.rb
77
77
  - lib/balotelli/core/kick.rb
78
78
  - lib/balotelli/core/priv_msg.rb
79
- - lib/balotelli/core/router.rb
79
+ - lib/balotelli/core/router/action.rb
80
+ - lib/balotelli/core/router/match.rb
81
+ - lib/balotelli/core/router/router.rb
80
82
  - lib/balotelli/core/utils.rb
81
83
  - lib/balotelli/module/base.rb
84
+ - lib/balotelli/thread/pool.rb
82
85
  - lib/balotelli/version.rb
83
86
  - test/lib/balotelli/asdf.rb
84
87
  - test/lib/balotelli/balotelli_helper_test.rb
@@ -94,7 +97,7 @@ homepage: https://github.com/mhib/balotelli
94
97
  licenses:
95
98
  - MIT
96
99
  metadata: {}
97
- post_install_message:
100
+ post_install_message:
98
101
  rdoc_options: []
99
102
  require_paths:
100
103
  - lib
@@ -109,9 +112,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
112
  - !ruby/object:Gem::Version
110
113
  version: '0'
111
114
  requirements: []
112
- rubyforge_project:
113
- rubygems_version: 2.6.4
114
- signing_key:
115
+ rubyforge_project:
116
+ rubygems_version: 2.6.6
117
+ signing_key:
115
118
  specification_version: 4
116
119
  summary: Simple IRC bot framework
117
120
  test_files:
@@ -125,4 +128,3 @@ test_files:
125
128
  - test/lib/balotelli/special_one.rb
126
129
  - test/lib/balotelli/xyz.rb
127
130
  - test/test_helper.rb
128
- has_rdoc:
@@ -1,46 +0,0 @@
1
- module Balotelli
2
- module Core
3
- module Router
4
- def setup_router
5
- @routes = {}
6
- end
7
-
8
- def on(route, option = {}, &block)
9
- raise 'no block given' if block.nil?
10
-
11
- option[:private] = false if !option.key?(:private) || route == :join
12
-
13
- if option[:private] == :both
14
- on(route, option.clone.tap { |o| o[:private] = true }, &block)
15
- on(route, option.clone.tap { |o| o[:private] = false }, &block)
16
- return
17
- end
18
-
19
- @routes[route] ||= {}
20
-
21
- if @routes[route][option[:private]] && !option[:force]
22
- raise "Route #{route.inspect}, private: #{option[:private]} already exists"
23
- end
24
-
25
- @routes[route][option[:private]] = [block, self]
26
- end
27
-
28
- def match?(str, route)
29
- case route
30
- when Regexp
31
- str =~ route
32
- when String
33
- str == route
34
- when Symbol
35
- str == route
36
- end
37
- end
38
-
39
- def match(str, priv = false)
40
- if (m = @routes.detect { |k, v| match?(str, k) && v[priv] })
41
- [m[0], m[1][priv]]
42
- end
43
- end
44
- end
45
- end
46
- end