wires 0.6.0 → 0.6.1
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 +4 -4
- data/lib/wires/base.rb +2 -0
- data/lib/wires/base/channel.rb +4 -97
- data/lib/wires/base/channel/sync_helper.rb +104 -0
- data/lib/wires/base/future.rb +133 -0
- data/lib/wires/base/launcher.rb +20 -16
- data/lib/wires/base/util/router_table.rb +4 -2
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6ef896589b7b29bffcde2800b2a0205c993bf70
|
4
|
+
data.tar.gz: 849f9147f51646922d9148fdae2d592dc3998fc2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a27d75fe9e4020189e732e04e93cc6e22493390b7b28ebe616d31420a97d18e1a3c56a43b940a2030f75dfba27e396ea0762965dad59f47496bc0f2d8c40b6d9
|
7
|
+
data.tar.gz: ba4092b89082a0fd4f6da1af2aa7664eca682a6017e6cb5ebaa00b7d8e8804305b6f1f26107fb2eba318807456a08353f09ca5c34b7d5feef88ed316b022adec
|
data/lib/wires/base.rb
CHANGED
@@ -48,9 +48,11 @@ loader.call 'base/util/hooks'
|
|
48
48
|
loader.call 'base/util/router_table'
|
49
49
|
|
50
50
|
loader.call 'base/event'
|
51
|
+
loader.call 'base/future'
|
51
52
|
loader.call 'base/launcher'
|
52
53
|
loader.call 'base/router'
|
53
54
|
loader.call 'base/channel'
|
55
|
+
loader.call 'base/channel/sync_helper'
|
54
56
|
loader.call 'base/time_scheduler_item'
|
55
57
|
loader.call 'base/time_scheduler'
|
56
58
|
loader.call 'base/convenience'
|
data/lib/wires/base/channel.rb
CHANGED
@@ -263,6 +263,10 @@ module Wires.current_network::Namespace
|
|
263
263
|
end
|
264
264
|
end
|
265
265
|
|
266
|
+
procs.map! do |pr|
|
267
|
+
Future.new &pr
|
268
|
+
end
|
269
|
+
|
266
270
|
# Fire to selected targets
|
267
271
|
threads = procs.uniq.map do |pr|
|
268
272
|
Launcher.spawn \
|
@@ -330,103 +334,6 @@ module Wires.current_network::Namespace
|
|
330
334
|
nil
|
331
335
|
end
|
332
336
|
|
333
|
-
# Helper class passed to user block in {Channel#sync_on} method.
|
334
|
-
# Read here for how to use the helper, but never instantiate it yourself.
|
335
|
-
class SyncHelper
|
336
|
-
|
337
|
-
# Don't instantiate this class directly, use {Channel#sync_on}
|
338
|
-
# @api private
|
339
|
-
def initialize(events, channel, timeout:nil)
|
340
|
-
@timeout = timeout
|
341
|
-
@lock, @cond = Mutex.new, ConditionVariable.new
|
342
|
-
@conditions = []
|
343
|
-
@executions = []
|
344
|
-
@received = []
|
345
|
-
@thread = Thread.current
|
346
|
-
|
347
|
-
# Create the temporary event handler to capture incoming matches
|
348
|
-
proc = Proc.new do |e,c|
|
349
|
-
if Thread.current==@thread
|
350
|
-
snag e,c
|
351
|
-
else
|
352
|
-
@lock.synchronize { snag e,c }
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
# Run the user block within the lock and wait afterward if they didn't
|
357
|
-
@lock.synchronize {
|
358
|
-
channel.register events, &proc
|
359
|
-
yield self
|
360
|
-
wait unless @waited
|
361
|
-
channel.unregister &proc
|
362
|
-
}
|
363
|
-
end
|
364
|
-
|
365
|
-
# Add a condition which must be fulfilled for {#wait} to find a match.
|
366
|
-
#
|
367
|
-
# @param block [Proc] the block specifiying the condition to be met.
|
368
|
-
# It will be passed the event and channel, and the truthiness of its
|
369
|
-
# return value will be evaluated to determine if the condition is met.
|
370
|
-
# It will only be executed if the +[event,channel]+ pair fits the
|
371
|
-
# filter and meets all of the other evaluated conditions so far.
|
372
|
-
#
|
373
|
-
def condition(&block)
|
374
|
-
@conditions << block if block
|
375
|
-
nil
|
376
|
-
end
|
377
|
-
|
378
|
-
# Add a execution to run on the matching event for each {#wait}.
|
379
|
-
#
|
380
|
-
# @param block [Proc] the block to be executed.
|
381
|
-
# It will only be executed if the +[event,channel]+ pair fits the
|
382
|
-
# filter and met all of the conditions to fulfill the {#wait}.
|
383
|
-
# The block will not be run if the {#wait} times out.
|
384
|
-
#
|
385
|
-
def execute(&block)
|
386
|
-
@executions << block if block
|
387
|
-
nil
|
388
|
-
end
|
389
|
-
|
390
|
-
# Wait for exactly one matching event meeting all {#condition}s to come.
|
391
|
-
#
|
392
|
-
# @note This will be called once implicitly at the end of the user block
|
393
|
-
# unless it gets called explicitly somewhere within the user block.
|
394
|
-
# It can be called multiple times within the user block to require
|
395
|
-
# one matching event each time within the block.
|
396
|
-
#
|
397
|
-
# @param timeout [Fixnum] The maximum time to wait for a match,
|
398
|
-
# specified in seconds. By default, it will be the number used at
|
399
|
-
# instantiation (passed from {Channel#sync_on}).
|
400
|
-
#
|
401
|
-
# @return the matching {Event} object, or nil if timed out.
|
402
|
-
#
|
403
|
-
def wait(timeout=@timeout)
|
404
|
-
@waited = true
|
405
|
-
result = nil
|
406
|
-
|
407
|
-
# Loop through each result, making sure it matches the conditions,
|
408
|
-
# returning nil if the wait timed out and didn't push into @received
|
409
|
-
loop do
|
410
|
-
@cond.wait @lock, timeout if @received.empty?
|
411
|
-
result = @received.pop
|
412
|
-
return nil unless result
|
413
|
-
break if !@conditions.detect { |blk| !blk.call *result }
|
414
|
-
end
|
415
|
-
|
416
|
-
# Run all the execute blocks on the result
|
417
|
-
@executions.each { |blk| blk.call *result }
|
418
|
-
result.first #=> return event
|
419
|
-
end
|
420
|
-
|
421
|
-
private
|
422
|
-
|
423
|
-
# Snag the given event and channel to try it out in the blocking thread
|
424
|
-
def snag(*args)
|
425
|
-
@received << args
|
426
|
-
@cond.signal # Pass execution back to blocking thread and block this one
|
427
|
-
end
|
428
|
-
end
|
429
|
-
|
430
337
|
# Determine if one channel matches another.
|
431
338
|
#
|
432
339
|
# In this context, a match indicates a receiver relationship.
|
@@ -0,0 +1,104 @@
|
|
1
|
+
|
2
|
+
module Wires.current_network::Namespace
|
3
|
+
|
4
|
+
class Channel
|
5
|
+
|
6
|
+
# Helper class passed to user block in {Channel#sync_on} method.
|
7
|
+
# Read here for how to use the helper, but never instantiate it yourself.
|
8
|
+
class SyncHelper
|
9
|
+
|
10
|
+
# Don't instantiate this class directly, use {Channel#sync_on}
|
11
|
+
# @api private
|
12
|
+
def initialize(events, channel, timeout:nil)
|
13
|
+
@timeout = timeout
|
14
|
+
@lock, @cond = Mutex.new, ConditionVariable.new
|
15
|
+
@conditions = []
|
16
|
+
@executions = []
|
17
|
+
@received = []
|
18
|
+
@thread = Thread.current
|
19
|
+
|
20
|
+
# Create the temporary event handler to capture incoming matches
|
21
|
+
proc = Proc.new do |e,c|
|
22
|
+
if Thread.current==@thread
|
23
|
+
snag e,c
|
24
|
+
else
|
25
|
+
@lock.synchronize { snag e,c }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Run the user block within the lock and wait afterward if they didn't
|
30
|
+
@lock.synchronize {
|
31
|
+
channel.register events, &proc
|
32
|
+
yield self
|
33
|
+
wait unless @waited
|
34
|
+
channel.unregister &proc
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add a condition which must be fulfilled for {#wait} to find a match.
|
39
|
+
#
|
40
|
+
# @param block [Proc] the block specifiying the condition to be met.
|
41
|
+
# It will be passed the event and channel, and the truthiness of its
|
42
|
+
# return value will be evaluated to determine if the condition is met.
|
43
|
+
# It will only be executed if the +[event,channel]+ pair fits the
|
44
|
+
# filter and meets all of the other evaluated conditions so far.
|
45
|
+
#
|
46
|
+
def condition(&block)
|
47
|
+
@conditions << block if block
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
# Add a execution to run on the matching event for each {#wait}.
|
52
|
+
#
|
53
|
+
# @param block [Proc] the block to be executed.
|
54
|
+
# It will only be executed if the +[event,channel]+ pair fits the
|
55
|
+
# filter and met all of the conditions to fulfill the {#wait}.
|
56
|
+
# The block will not be run if the {#wait} times out.
|
57
|
+
#
|
58
|
+
def execute(&block)
|
59
|
+
@executions << block if block
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# Wait for exactly one matching event meeting all {#condition}s to come.
|
64
|
+
#
|
65
|
+
# @note This will be called once implicitly at the end of the user block
|
66
|
+
# unless it gets called explicitly somewhere within the user block.
|
67
|
+
# It can be called multiple times within the user block to require
|
68
|
+
# one matching event each time within the block.
|
69
|
+
#
|
70
|
+
# @param timeout [Fixnum] The maximum time to wait for a match,
|
71
|
+
# specified in seconds. By default, it will be the number used at
|
72
|
+
# instantiation (passed from {Channel#sync_on}).
|
73
|
+
#
|
74
|
+
# @return the matching {Event} object, or nil if timed out.
|
75
|
+
#
|
76
|
+
def wait(timeout=@timeout)
|
77
|
+
@waited = true
|
78
|
+
result = nil
|
79
|
+
|
80
|
+
# Loop through each result, making sure it matches the conditions,
|
81
|
+
# returning nil if the wait timed out and didn't push into @received
|
82
|
+
loop do
|
83
|
+
@cond.wait @lock, timeout if @received.empty?
|
84
|
+
result = @received.pop
|
85
|
+
return nil unless result
|
86
|
+
break if !@conditions.detect { |blk| !blk.call *result }
|
87
|
+
end
|
88
|
+
|
89
|
+
# Run all the execute blocks on the result
|
90
|
+
@executions.each { |blk| blk.call *result }
|
91
|
+
result.first #=> return event
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# Snag the given event and channel to try it out in the blocking thread
|
97
|
+
def snag(*args)
|
98
|
+
@received << args
|
99
|
+
@cond.signal # Pass execution back to blocking thread and block this one
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
|
2
|
+
module Wires.current_network::Namespace
|
3
|
+
|
4
|
+
# In this context, a {Future} is thread-safe container for a {#codeblock}
|
5
|
+
# and for the {#result} produced when it is {#execute}d.
|
6
|
+
#
|
7
|
+
# Call {#execute} to run the block in place, or {#start} to {#execute} in
|
8
|
+
# a new thread. After {#execute} is done, the {#result} will be available.
|
9
|
+
# Calling {#result} will block if {#execute} has not yet finished.
|
10
|
+
# The block is guaranteed to run at most one time, so any subsequent
|
11
|
+
# calls to {#execute} will merely return the existing {#result}.
|
12
|
+
# If running the block again is desired, use {#dup} to create a new {Future}
|
13
|
+
# with the same {#codeblock}.
|
14
|
+
#
|
15
|
+
# future = Future.new { |*args| expensive_operation *args }
|
16
|
+
# future.start 1,2,3 # Run expensive_operation in a thread with args=1,2,3
|
17
|
+
# # ...
|
18
|
+
# puts future.result # Block until expensive_operation is done and print result
|
19
|
+
#
|
20
|
+
# @note Primarily, {Future} is included in this library for the return value
|
21
|
+
# of {Launcher.spawn} (and, by extension, {Channel#fire}), but users should
|
22
|
+
# feel free to use it's documented API for other purposes as well.
|
23
|
+
#
|
24
|
+
class Future
|
25
|
+
|
26
|
+
# The block passed at {#initialize} to be run when {#execute} is called.
|
27
|
+
# It will be run at most one time.
|
28
|
+
#
|
29
|
+
attr_reader :codeblock
|
30
|
+
|
31
|
+
# @param codeblock [Proc] The code block to run when {#execute} is called.
|
32
|
+
# @raise [ArgumentError] If +codeblock+ is not given.
|
33
|
+
#
|
34
|
+
def initialize &codeblock
|
35
|
+
raise ArgumentError, "Future must be instantiated with a block" \
|
36
|
+
unless codeblock
|
37
|
+
|
38
|
+
@codeblock = codeblock
|
39
|
+
@state = :initial
|
40
|
+
@result = nil
|
41
|
+
@statelock = Mutex.new
|
42
|
+
@cond = ConditionVariable.new
|
43
|
+
end
|
44
|
+
|
45
|
+
# Run {#execute} in a new +Thread+. If {#execute} raises an +Exception+,
|
46
|
+
# it will be rescued at the top level of the +Thread+, but will be raised
|
47
|
+
# when {#result} is called.
|
48
|
+
#
|
49
|
+
# @param args The arguments to pass to {#codeblock} in {#execute}.
|
50
|
+
# @param block The block argument to pass to {#codeblock} in {#execute}.
|
51
|
+
# @return [Thread] The spawned +Thread+.
|
52
|
+
#
|
53
|
+
def start *args, &block
|
54
|
+
Thread.new do
|
55
|
+
begin
|
56
|
+
execute *args, &block
|
57
|
+
rescue Exception
|
58
|
+
# Exceptions get raised through when #result is called.
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Run the {#codeblock} passed to {#initialize} with the given arguments.
|
64
|
+
#
|
65
|
+
# If the {#codeblock} has already been {#execute}d, it won't be run again;
|
66
|
+
# instead, the result returned by the first call will be returned again.
|
67
|
+
#
|
68
|
+
# @param args The arguments to pass to {#codeblock}.
|
69
|
+
# @param block The block argument to pass to {#codeblock}.
|
70
|
+
# @return The return value of the call to {#codeblock}.
|
71
|
+
# @raise The exception raised by the call to {#codeblock}, if any.
|
72
|
+
#
|
73
|
+
def execute *args, &block
|
74
|
+
@statelock.synchronize do
|
75
|
+
return @result if @state == :complete
|
76
|
+
@state = :running
|
77
|
+
|
78
|
+
begin
|
79
|
+
@codeblock.call(*args, &block).tap do |result|
|
80
|
+
@result = result
|
81
|
+
@state = :complete
|
82
|
+
end
|
83
|
+
rescue Exception => exception
|
84
|
+
@result = exception
|
85
|
+
@state = :exception
|
86
|
+
raise exception
|
87
|
+
ensure
|
88
|
+
@cond.broadcast
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
alias call execute
|
93
|
+
|
94
|
+
# Get the return value of the call to {#codeblock}.
|
95
|
+
#
|
96
|
+
# If {#execute} has not yet been called, or if it is still {#running?},
|
97
|
+
# {#result} will block until the {#codeblock} has been run.
|
98
|
+
#
|
99
|
+
# @return The return value of the call to {#codeblock}.
|
100
|
+
# @raise The exception raised by the call to {#codeblock}, if any.
|
101
|
+
#
|
102
|
+
def result
|
103
|
+
@statelock.synchronize do
|
104
|
+
@cond.wait @statelock unless complete?
|
105
|
+
@state==:exception ? raise(@result) : @result
|
106
|
+
end
|
107
|
+
end
|
108
|
+
alias join result
|
109
|
+
|
110
|
+
# @return [Boolean]
|
111
|
+
# +true+ if {#codeblock} is currently executing, else +false+.
|
112
|
+
def running?; @state == :running; end
|
113
|
+
alias executing? running?
|
114
|
+
|
115
|
+
# @return [Boolean]
|
116
|
+
# +true+ if {#codeblock} has already executed, else +false+.
|
117
|
+
def complete?; @state == :complete || @state == :exception; end
|
118
|
+
alias ready? complete?
|
119
|
+
|
120
|
+
# Duplicate the Future, without copying its {#running?}/{#complete?} state.
|
121
|
+
# This is the preferred way to "reuse" a {Future}, because each {Future}
|
122
|
+
# is guaranteed to run at most one time. It is the same as creating a
|
123
|
+
# new {Future} with the same {#codeblock} object passed to {#initialize}.
|
124
|
+
#
|
125
|
+
# @return [Future] A new {Future} with the same {#codeblock}.
|
126
|
+
#
|
127
|
+
def dup
|
128
|
+
self.class.new &@codeblock
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
data/lib/wires/base/launcher.rb
CHANGED
@@ -18,7 +18,6 @@ module Wires.current_network::Namespace
|
|
18
18
|
|
19
19
|
# Moved to a dedicated method for subclass' sake
|
20
20
|
def class_init
|
21
|
-
# @queue = Queue.new
|
22
21
|
@max_children = nil
|
23
22
|
@children = Array.new
|
24
23
|
@children .extend MonitorMixin
|
@@ -45,10 +44,10 @@ module Wires.current_network::Namespace
|
|
45
44
|
nil end
|
46
45
|
|
47
46
|
def reset_neglect_procs
|
48
|
-
@on_neglect = Proc.new do
|
47
|
+
@on_neglect = Proc.new do |*args|
|
49
48
|
$stderr.puts "#{self} neglected to spawn task: #{args.inspect}"
|
50
49
|
end
|
51
|
-
@on_neglect_done = Proc.new do
|
50
|
+
@on_neglect_done = Proc.new do |*args|
|
52
51
|
$stderr.puts "#{self} finally spawned neglected task: #{args.inspect}"
|
53
52
|
end
|
54
53
|
nil end
|
@@ -64,25 +63,27 @@ module Wires.current_network::Namespace
|
|
64
63
|
end
|
65
64
|
|
66
65
|
# Spawn a task - user code should never call this directly
|
67
|
-
def spawn(*args) # :args: event, chan,
|
66
|
+
def spawn(*args) # :args: event, chan, future, blocking, parallel, fire_bt
|
68
67
|
|
69
|
-
event, chan,
|
68
|
+
event, chan, future, blocking, parallel, fire_bt = *args
|
70
69
|
*proc_args = event, chan
|
71
70
|
*exc_args = event, chan, fire_bt
|
72
71
|
|
73
|
-
# If not parallel, run the
|
72
|
+
# If not parallel, run the future in this thread
|
74
73
|
if !parallel
|
75
74
|
begin
|
76
|
-
|
75
|
+
future.call(*proc_args)
|
77
76
|
rescue Exception => exc
|
78
77
|
unhandled_exception(exc, *exc_args)
|
79
78
|
end
|
80
79
|
|
81
|
-
return
|
80
|
+
return future
|
82
81
|
end
|
83
82
|
|
84
|
-
|
85
|
-
|
83
|
+
if @hold_lock.instance_variable_get(:@mon_mutex).locked?
|
84
|
+
neglect(*args)
|
85
|
+
return future
|
86
|
+
end
|
86
87
|
|
87
88
|
# If not parallel, clear old threads and spawn a new thread
|
88
89
|
Thread.exclusive do
|
@@ -93,7 +94,7 @@ module Wires.current_network::Namespace
|
|
93
94
|
# Start the new child thread; follow with chain of neglected tasks
|
94
95
|
@children << Thread.new do
|
95
96
|
begin
|
96
|
-
|
97
|
+
future.call(*proc_args)
|
97
98
|
rescue Exception => exc
|
98
99
|
unhandled_exception(exc, *exc_args)
|
99
100
|
ensure
|
@@ -103,9 +104,12 @@ module Wires.current_network::Namespace
|
|
103
104
|
end
|
104
105
|
|
105
106
|
# Capture ThreadError from either OS or user-set limitation
|
106
|
-
rescue ThreadError
|
107
|
+
rescue ThreadError
|
108
|
+
neglect(*args)
|
109
|
+
return future
|
110
|
+
end
|
107
111
|
|
108
|
-
return
|
112
|
+
return future
|
109
113
|
end
|
110
114
|
|
111
115
|
end
|
@@ -142,13 +146,13 @@ module Wires.current_network::Namespace
|
|
142
146
|
@on_neglect.call(*args)
|
143
147
|
@neglected << args
|
144
148
|
end
|
145
|
-
|
149
|
+
nil end
|
146
150
|
|
147
151
|
# Run a chain of @neglected tasks in place until no more are waiting
|
148
152
|
def spawn_neglected_task_chain
|
149
153
|
args = @neglected.synchronize do
|
150
154
|
return nil if @neglected.empty?
|
151
|
-
|
155
|
+
@neglected.shift.tap { |a| a[3] = true } # Call with blocking
|
152
156
|
end
|
153
157
|
spawn(*args)
|
154
158
|
@on_neglect_done.call(*args)
|
@@ -160,7 +164,7 @@ module Wires.current_network::Namespace
|
|
160
164
|
until (cease||=false)
|
161
165
|
args = @neglected.synchronize do
|
162
166
|
break if (cease = @neglected.empty?)
|
163
|
-
|
167
|
+
@neglected.shift.tap { |a| a[3] = false } # Call without blocking
|
164
168
|
end
|
165
169
|
break if cease
|
166
170
|
spawn(*args)
|
@@ -9,7 +9,7 @@ module Wires.current_network::Namespace
|
|
9
9
|
def weak?; @weak end
|
10
10
|
|
11
11
|
def initialize(obj)
|
12
|
-
raise
|
12
|
+
raise ArgumentError, "#{self.class} referent cannot be nil" if obj.nil?
|
13
13
|
|
14
14
|
# Make initial weak reference (if possible)
|
15
15
|
begin
|
@@ -64,7 +64,9 @@ module Wires.current_network::Namespace
|
|
64
64
|
|
65
65
|
def []=(key, value)
|
66
66
|
begin; ObjectSpace.define_finalizer key, @finalizer
|
67
|
-
rescue RuntimeError
|
67
|
+
rescue RuntimeError => e
|
68
|
+
raise unless e.message =~ /can't modify frozen/
|
69
|
+
end
|
68
70
|
|
69
71
|
@lock.synchronize do
|
70
72
|
id = key.object_id
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wires
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe McIlvain
|
@@ -150,6 +150,20 @@ dependencies:
|
|
150
150
|
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: yard
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
153
167
|
description: A lightweight, extensible asynchronous event routing framework in Ruby.
|
154
168
|
email: joe.eli.mac@gmail.com
|
155
169
|
executables: []
|
@@ -162,8 +176,10 @@ files:
|
|
162
176
|
- lib/wires/base.rb
|
163
177
|
- lib/wires/base/actor.rb
|
164
178
|
- lib/wires/base/channel.rb
|
179
|
+
- lib/wires/base/channel/sync_helper.rb
|
165
180
|
- lib/wires/base/convenience.rb
|
166
181
|
- lib/wires/base/event.rb
|
182
|
+
- lib/wires/base/future.rb
|
167
183
|
- lib/wires/base/launcher.rb
|
168
184
|
- lib/wires/base/router.rb
|
169
185
|
- lib/wires/base/time_scheduler.rb
|
@@ -194,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
194
210
|
version: '0'
|
195
211
|
requirements: []
|
196
212
|
rubyforge_project:
|
197
|
-
rubygems_version: 2.2.
|
213
|
+
rubygems_version: 2.2.2
|
198
214
|
signing_key:
|
199
215
|
specification_version: 4
|
200
216
|
summary: wires
|