wires 0.5.6 → 0.5.7
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/channel.rb +117 -0
- data/lib/wires/base/convenience.rb +5 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9f2487653b2bc09e49a835f4945890973744d1a
|
4
|
+
data.tar.gz: 273bf1a229f890c1a1bae0e7002cfa8c99c56e2d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a087b9a5bc3c6cc604d1272401e24d0e428b9868b6c3a615384bd35af3862b5ef896832bbb6d6c671b683871f8993ca6630ad37b53eff1f1ce418cb075ca888b
|
7
|
+
data.tar.gz: f6fd9105f3d1cbc90489e2e933065214657463a261e94de1fe85faac8f2c609689b303b6384bd6f50e388ccfd0b5689418c7caf6533406324700baf22ee89c62
|
data/lib/wires/base/channel.rb
CHANGED
@@ -291,6 +291,123 @@ module Wires.current_network::Namespace
|
|
291
291
|
fire(*args, **kwargs)
|
292
292
|
end
|
293
293
|
|
294
|
+
# Synchronize execution of this thread to an incoming event.
|
295
|
+
# The user block will be executed, and will not return until a matching
|
296
|
+
# incoming event has been fired
|
297
|
+
# (see the {SyncHelper})
|
298
|
+
#
|
299
|
+
# @note In order to use this method correctly, the "action" that causes the
|
300
|
+
# incoming event to be fired should happen within the user block. If
|
301
|
+
# it happens before the user block, one risks a race condition; if after,
|
302
|
+
# one risks deadlock (or timeout) due to the feedback event being missed.
|
303
|
+
# As long as the feedback event happens after execution of the user block
|
304
|
+
# has begun, the event is guaranteed to be caught and processed.
|
305
|
+
#
|
306
|
+
# @param *events [<Symbol, Event>] the event pattern(s) filter
|
307
|
+
# to listen with. (see {#register}).
|
308
|
+
# @param timeout [Fixnum] the timeout, in seconds.
|
309
|
+
# (see {SyncHelper#wait}).
|
310
|
+
# @param &block [Proc] the user block. This block will be executed inline
|
311
|
+
# and passed an instance of {SyncHelper}. Within this block, the helper
|
312
|
+
# should be configured using its methods. Optionally, {SyncHelper#wait}
|
313
|
+
# can be called to wait in a specific location in the block. Otherwise,
|
314
|
+
# it will be called implicitly at the end of the block.
|
315
|
+
#
|
316
|
+
def sync_on(*events, timeout:nil, &block)
|
317
|
+
SyncHelper.new(events, self, timeout:timeout, &block)
|
318
|
+
nil
|
319
|
+
end
|
320
|
+
|
321
|
+
# Helper class passed to user block in {Channel#sync} method.
|
322
|
+
# Read here for how to use the helper, but never instantiate it yourself.
|
323
|
+
class SyncHelper
|
324
|
+
|
325
|
+
# Don't instantiate this class directly, use {Channel#sync}
|
326
|
+
# @api private
|
327
|
+
def initialize(events, channel, timeout:nil)
|
328
|
+
@timeout = timeout
|
329
|
+
@lock, @cond = Mutex.new, ConditionVariable.new
|
330
|
+
@conditions = []
|
331
|
+
@executions = []
|
332
|
+
@received = []
|
333
|
+
|
334
|
+
# Create the temporary event handler to capture incoming matches
|
335
|
+
proc = Proc.new { |e,c| @lock.synchronize { snag e,c } }
|
336
|
+
|
337
|
+
# Run the user block within the lock and wait afterward if they didn't
|
338
|
+
@lock.synchronize {
|
339
|
+
channel.register events, &proc
|
340
|
+
yield self
|
341
|
+
wait unless @waited
|
342
|
+
channel.unregister &proc
|
343
|
+
}
|
344
|
+
end
|
345
|
+
|
346
|
+
# Add a condition which must be fulfilled for {#wait} to find a match.
|
347
|
+
#
|
348
|
+
# @param &block [Proc] the block specifiying the condition to be met.
|
349
|
+
# It will be passed the event and channel, and the truthiness of its
|
350
|
+
# return value will be evaluated to determine if the condition is met.
|
351
|
+
# It will only be executed if the +[event,channel]+ pair fits the
|
352
|
+
# filter and meets all of the other evaluated conditions so far.
|
353
|
+
#
|
354
|
+
def condition(&block)
|
355
|
+
@conditions << block if block
|
356
|
+
nil
|
357
|
+
end
|
358
|
+
|
359
|
+
# Add a execution to run on the matching event for each {#wait}.
|
360
|
+
#
|
361
|
+
# @param &block [Proc] the block to be executed.
|
362
|
+
# It will only be executed if the +[event,channel]+ pair fits the
|
363
|
+
# filter and met all of the conditions to fulfill the {#wait}.
|
364
|
+
# The block will not be run if the {#wait} times out.
|
365
|
+
#
|
366
|
+
def execute(&block)
|
367
|
+
@executions << block if block
|
368
|
+
nil
|
369
|
+
end
|
370
|
+
|
371
|
+
# Wait for exactly one matching event meeting all {#conditions} to come.
|
372
|
+
#
|
373
|
+
# @note This will be called once implicitly at the end of the user block
|
374
|
+
# unless it gets called explicitly somewhere within the user block.
|
375
|
+
# It can be called multiple times within the user block to require
|
376
|
+
# one matching event each time within the block.
|
377
|
+
#
|
378
|
+
# @param timeout [Fixnum] The maximum time to wait for a match,
|
379
|
+
# specified in seconds. By default, it will be the number used at
|
380
|
+
# instantiation (passed from {Channel#sync_on}).
|
381
|
+
#
|
382
|
+
# @return the matching {Event} object, or nil if timed out.
|
383
|
+
#
|
384
|
+
def wait(timeout=@timeout)
|
385
|
+
@waited = true
|
386
|
+
result = nil
|
387
|
+
|
388
|
+
# Loop through each result, making sure it matches the conditions,
|
389
|
+
# returning nil if the wait timed out and didn't push into @received
|
390
|
+
loop do
|
391
|
+
@cond.wait @lock, timeout
|
392
|
+
result = @received.pop
|
393
|
+
return nil unless result
|
394
|
+
break if !@conditions.detect { |blk| !blk.call *result }
|
395
|
+
end
|
396
|
+
|
397
|
+
# Run all the execute blocks on the result
|
398
|
+
@executions.each { |blk| blk.call *result }
|
399
|
+
result.first #=> return event
|
400
|
+
end
|
401
|
+
|
402
|
+
private
|
403
|
+
|
404
|
+
# Snag the given event and channel to try it out in the blocking thread
|
405
|
+
def snag(*args)
|
406
|
+
@received << args
|
407
|
+
@cond.signal # Pass execution back to blocking thread and block this one
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
294
411
|
# Determine if one channel matches another.
|
295
412
|
#
|
296
413
|
# In this context, a match indicates a receiver relationship.
|
@@ -13,6 +13,11 @@ module Wires.current_network::Namespace
|
|
13
13
|
codeblock
|
14
14
|
end
|
15
15
|
|
16
|
+
def sync_on(event, channel=self, **kwargs, &codeblock)
|
17
|
+
channel = Channel.new(channel) unless channel.is_a? Channel
|
18
|
+
channel.sync_on(event, **kwargs, &codeblock)
|
19
|
+
end
|
20
|
+
|
16
21
|
def fire(event, channel=self, **kwargs)
|
17
22
|
channel = Channel.new(channel) unless channel.is_a? Channel
|
18
23
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wires
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe McIlvain
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: threadlock
|
@@ -162,7 +162,7 @@ files:
|
|
162
162
|
- lib/wires/core_ext/time.rb
|
163
163
|
homepage: https://github.com/jemc/wires/
|
164
164
|
licenses:
|
165
|
-
- Copyright 2013 Joe McIlvain. All rights reserved.
|
165
|
+
- Copyright 2013-2014 Joe McIlvain. All rights reserved.
|
166
166
|
metadata: {}
|
167
167
|
post_install_message:
|
168
168
|
rdoc_options: []
|
@@ -185,3 +185,4 @@ signing_key:
|
|
185
185
|
specification_version: 4
|
186
186
|
summary: wires
|
187
187
|
test_files: []
|
188
|
+
has_rdoc:
|