balotelli 0.4.2.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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