wires 0.1.7 → 0.1.8
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/hub.rb +14 -8
- data/lib/wires/time.rb +85 -55
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07b54cd8c5d2566dc1df5dbbba359680e290cb44
|
4
|
+
data.tar.gz: 32392ed09eae7079456c55ace22840b5d504aa55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec3dc587a26c0373cb9b8fd9872208608b6bb5a3f2445dcfd398623ab108b1e7da3205864cb0e15d6911a982ec9ad594e5e06d3975b1bbde075a03532037a3f6
|
7
|
+
data.tar.gz: 5264ed0c4c84c2063e62e32876b1e40acd38587e52e9c40af05bb301ed9e381555c3d7a3fe588a4b0f48fedf149b44235b54db533d107db0054139844ca97798
|
data/lib/wires/hub.rb
CHANGED
@@ -20,8 +20,11 @@ class Hub
|
|
20
20
|
# Start the Hub event loop in a new thread
|
21
21
|
def run
|
22
22
|
if not @running
|
23
|
-
@
|
24
|
-
|
23
|
+
@thread = Thread.new() do
|
24
|
+
@running = true
|
25
|
+
self.send(:run_loop)
|
26
|
+
end
|
27
|
+
|
25
28
|
at_exit { @thread.join if not $! }
|
26
29
|
end
|
27
30
|
nil end
|
@@ -59,11 +62,14 @@ class Hub
|
|
59
62
|
@after_kills << func
|
60
63
|
end
|
61
64
|
|
62
|
-
# Put x in the queue, and block until x is processed
|
65
|
+
# Put x in the queue, and block until x is processed (if Hub is running)
|
63
66
|
def fire(x)
|
64
|
-
@
|
65
|
-
|
66
|
-
|
67
|
+
if @running # yield to event loop thread until awoken by it later
|
68
|
+
@queue << [x, Thread.current]
|
69
|
+
sleep
|
70
|
+
else # don't wait if Hub isn't running - would cause lockup
|
71
|
+
@queue << [x, nil]
|
72
|
+
end
|
67
73
|
end
|
68
74
|
def <<(x); fire(x); end
|
69
75
|
|
@@ -87,9 +93,9 @@ class Hub
|
|
87
93
|
string, event, blocking, proc = x
|
88
94
|
Thread.new do
|
89
95
|
begin
|
90
|
-
waiting_thread.wakeup unless blocking
|
96
|
+
waiting_thread.wakeup unless blocking or not waiting_thread
|
91
97
|
proc.call($event = event)
|
92
|
-
waiting_thread.wakeup if blocking
|
98
|
+
waiting_thread.wakeup if blocking and waiting_thread
|
93
99
|
|
94
100
|
rescue Interrupt, SystemExit => e
|
95
101
|
@running = false
|
data/lib/wires/time.rb
CHANGED
@@ -1,75 +1,105 @@
|
|
1
1
|
|
2
2
|
|
3
|
-
|
3
|
+
class StartSchedulerEvent < Event; end
|
4
4
|
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
# A singleton class to schedule future firing of events
|
6
|
+
class TimeScheduler
|
7
|
+
@schedule = Array.new
|
8
|
+
@schedule_lock = Mutex.new
|
9
|
+
@grain = 0.2.seconds
|
10
10
|
|
11
|
-
#
|
12
|
-
|
11
|
+
# Operate on the metaclass as a type of singleton pattern
|
12
|
+
class << self
|
13
13
|
|
14
|
-
#
|
15
|
-
|
14
|
+
# Get or set the time grain from outside the class
|
15
|
+
attr_accessor :grain
|
16
16
|
|
17
|
-
#
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
# Fire an event delayed by time value
|
18
|
+
def fire(time, event, channel='*')
|
19
|
+
if not time.is_a? Time
|
20
|
+
raise TypeError, "Expected #{time.inspect} to be an instance of Time."
|
21
|
+
end
|
22
22
|
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
# Under mutex, push the event into the schedule and sort
|
24
|
+
@schedule_lock.synchronize do
|
25
|
+
@schedule << [time, event, channel]
|
26
|
+
@schedule.sort! { |a,b| a[0] <=> b[0] }
|
27
|
+
end
|
28
28
|
|
29
|
-
|
29
|
+
end
|
30
30
|
|
31
|
-
|
31
|
+
private
|
32
32
|
|
33
|
-
|
33
|
+
def main_loop
|
34
34
|
|
35
|
-
|
35
|
+
pending = Array.new
|
36
36
|
|
37
|
-
|
37
|
+
while true
|
38
38
|
|
39
|
-
|
40
|
-
|
39
|
+
pending.clear
|
40
|
+
this_time = Time.now
|
41
41
|
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
# end
|
42
|
+
# Under mutex, pull any events that are ready
|
43
|
+
@schedule_lock.synchronize do
|
44
|
+
while ((not @schedule.empty?) and (this_time > @schedule[0][0]))
|
45
|
+
pending << @schedule.shift
|
46
|
+
end
|
47
|
+
end
|
49
48
|
|
50
|
-
#
|
51
|
-
|
49
|
+
# Fire pending events
|
50
|
+
pending.each { |x| Channel(x[2]).fire(x[1]) }
|
52
51
|
|
53
|
-
#
|
54
|
-
|
52
|
+
# Calculate the time to sleep based on the time left in the "grain"
|
53
|
+
sleep [@grain-(Time.now-this_time), 0].max
|
55
54
|
|
56
|
-
|
57
|
-
|
55
|
+
end
|
56
|
+
end
|
58
57
|
|
59
|
-
|
58
|
+
end
|
60
59
|
|
61
|
-
#
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
60
|
+
# Use fired event to only start scheduler when Hub is running
|
61
|
+
# This also gets the scheduler loop its own thread within the Hub's threads
|
62
|
+
on :start_scheduler, self do; main_loop; end;
|
63
|
+
Channel(self).fire(:start_scheduler)
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# Reopen the Time class and add the fire method to enable nifty syntax like:
|
68
|
+
# 32.minutes.from_now.fire :event
|
69
|
+
class Time
|
70
|
+
def fire(*args)
|
71
|
+
TimeScheduler.fire(self, *args)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
68
75
|
|
69
|
-
#
|
70
|
-
#
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
+
# Reopen ActiveSupport::Duration to enable nifty syntax like:
|
77
|
+
# 32.minutes.from_now do some_stuff end
|
78
|
+
class TimeSchedulerAnonEvent < Event; end
|
79
|
+
class ActiveSupport::Duration
|
80
|
+
|
81
|
+
alias :__original_since :since
|
82
|
+
def since(*args, &block)
|
83
|
+
if block
|
84
|
+
on :time_scheduler_anon, block.object_id do block.call end
|
85
|
+
__original_since(*args).fire :time_scheduler_anon, block.object_id
|
86
|
+
nil
|
87
|
+
else
|
88
|
+
__original_since(*args)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
alias :from_now :since
|
92
|
+
|
93
|
+
alias :__original_ago :ago
|
94
|
+
def ago(*args, &block)
|
95
|
+
if block
|
96
|
+
on :time_scheduler_anon, block.object_id do block.call end
|
97
|
+
__original_ago(*args).fire :time_scheduler_anon, block.object_id
|
98
|
+
nil
|
99
|
+
else
|
100
|
+
__original_ago(*args)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
alias :until :ago
|
104
|
+
|
105
|
+
end
|
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.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe McIlvain
|
@@ -9,7 +9,21 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
date: 2013-06-27 00:00:00.000000000 Z
|
12
|
-
dependencies:
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
description: An asynchronous (threaded) event routing framework in Ruby. Patch your
|
14
28
|
objects together with wires. Inspired by the python 'circuits' framework.
|
15
29
|
email: joe.eli.mac@gmail.com
|