wires 0.4.3 → 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 +4 -4
- data/lib/wires/{channel.rb → base/channel.rb} +18 -32
- data/lib/wires/{convenience.rb → base/convenience.rb} +1 -1
- data/lib/wires/base/event.rb +71 -0
- data/lib/wires/{hub.rb → base/hub.rb} +7 -4
- data/lib/wires/{router.rb → base/router.rb} +4 -1
- data/lib/wires/{time_scheduler.rb → base/time_scheduler.rb} +3 -0
- data/lib/wires/base/time_scheduler_item.rb +92 -0
- data/lib/wires/{util → base/util}/build_alt.rb +3 -1
- data/lib/wires/{util → base/util}/hooks.rb +0 -0
- data/lib/wires/base.rb +14 -0
- data/lib/wires/core_ext/numeric.rb +35 -0
- data/lib/wires/core_ext/symbol.rb +11 -0
- data/lib/wires/core_ext/time.rb +7 -0
- data/lib/wires/core_ext.rb +3 -64
- data/lib/wires.rb +4 -12
- metadata +74 -13
- data/lib/wires/event.rb +0 -102
- data/lib/wires/time_scheduler_item.rb +0 -81
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04ad9bc6ef2ce9a54aad3343c13fca6ca69f1895
|
4
|
+
data.tar.gz: cf519182f4a9cd03776cb749d3bd922aeb5add3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 435a2df3af44aa3bd5b00a3f37d7abb273cb9be65276bfb717441b64bed14bb38b2b7bbc9044c60708b66db168799172319da9ef317bfb7ac0873d23ef3a9b15
|
7
|
+
data.tar.gz: b753ee2f1123be7b186f59ea37bfab07ba20d737e9fde3ec931d1cbe2cefc616d1149b4021da73b010210b81a4d3987b9dc9b424cdd39444909d2de3a53cea40
|
@@ -4,16 +4,19 @@ module Wires
|
|
4
4
|
class Channel
|
5
5
|
|
6
6
|
attr_reader :name
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :handlers
|
8
8
|
attr_accessor :not_firable
|
9
9
|
|
10
10
|
def inspect; "#{self.class}(#{name.inspect})"; end
|
11
11
|
|
12
12
|
@hub = Hub
|
13
13
|
@router = Router::Default
|
14
|
-
@new_lock =
|
14
|
+
@new_lock = Monitor.new
|
15
15
|
@@aim_lock = Mutex.new
|
16
16
|
|
17
|
+
# Add hook methods
|
18
|
+
extend Util::Hooks
|
19
|
+
|
17
20
|
class << self
|
18
21
|
attr_accessor :hub
|
19
22
|
attr_accessor :router
|
@@ -28,7 +31,7 @@ module Wires
|
|
28
31
|
|
29
32
|
def initialize(name)
|
30
33
|
@name = name
|
31
|
-
@
|
34
|
+
@handlers = []
|
32
35
|
end
|
33
36
|
|
34
37
|
# Register a proc to be triggered by an event on this channel
|
@@ -36,11 +39,11 @@ module Wires
|
|
36
39
|
def register(*events, &proc)
|
37
40
|
raise ArgumentError, "No callable given to execute on event: #{events}" \
|
38
41
|
unless proc.respond_to? :call
|
39
|
-
events = Event.
|
42
|
+
events = Event.list_from *events
|
40
43
|
|
41
44
|
@@aim_lock.synchronize do
|
42
|
-
@
|
43
|
-
unless @
|
45
|
+
@handlers << [events, proc] \
|
46
|
+
unless @handlers.include? [events, proc]
|
44
47
|
end
|
45
48
|
|
46
49
|
proc
|
@@ -48,33 +51,16 @@ module Wires
|
|
48
51
|
|
49
52
|
# Unregister a proc from the target list of this channel
|
50
53
|
# Return true if at least one matching target was unregistered, else false
|
51
|
-
def unregister(
|
52
|
-
events = events.empty? ? [] : Event.new_from(*events)
|
53
|
-
|
54
|
+
def unregister(proc)
|
54
55
|
@@aim_lock.synchronize do
|
55
|
-
!!(@
|
56
|
-
|
57
|
-
(events.map{|event| es.map{|e| event=~e}.any?}.all?)
|
56
|
+
!!(@handlers.reject! do |stored_events, stored_proc|
|
57
|
+
proc==stored_proc
|
58
58
|
end)
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
# Add hook methods
|
63
|
-
class << self
|
64
|
-
include Util::Hooks
|
65
|
-
|
66
|
-
def before_fire(*args, &proc)
|
67
|
-
add_hook(:@before_fire, *args, &proc)
|
68
|
-
end
|
69
|
-
|
70
|
-
def after_fire(*args, &proc)
|
71
|
-
add_hook(:@after_fire, *args, &proc)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
62
|
# Fire an event on this channel
|
76
63
|
def fire(input, blocking:false, parallel:!blocking)
|
77
|
-
|
78
64
|
raise *@not_firable if @not_firable
|
79
65
|
|
80
66
|
return [] << Thread.new { fire(input, blocking:true, parallel:false) } \
|
@@ -82,7 +68,7 @@ module Wires
|
|
82
68
|
|
83
69
|
backtrace = caller
|
84
70
|
|
85
|
-
event = Event.
|
71
|
+
event = Event.list_from input
|
86
72
|
|
87
73
|
case event.count
|
88
74
|
when 0
|
@@ -93,14 +79,14 @@ module Wires
|
|
93
79
|
raise ArgumentError,"Can't fire on multiple events: #{event.inspect}"
|
94
80
|
end
|
95
81
|
|
96
|
-
self.class.run_hooks(:@before_fire, event, self)
|
82
|
+
self.class.run_hooks(:@before_fire, event, self.name)
|
97
83
|
|
98
84
|
# Select appropriate targets
|
99
85
|
procs = []
|
100
86
|
@@aim_lock.synchronize do
|
101
87
|
self.class.router
|
102
88
|
.get_receivers(self).each do |chan|
|
103
|
-
chan.
|
89
|
+
chan.handlers.each do |elist, pr|
|
104
90
|
elist.each do |e|
|
105
91
|
procs << pr if e =~ event
|
106
92
|
end
|
@@ -121,14 +107,14 @@ module Wires
|
|
121
107
|
|
122
108
|
threads.each &:join if blocking and parallel
|
123
109
|
|
124
|
-
self.class.run_hooks(:@after_fire, event, self)
|
110
|
+
self.class.run_hooks(:@after_fire, event, self.name)
|
125
111
|
|
126
112
|
threads
|
127
113
|
end
|
128
114
|
|
129
115
|
# Fire a blocking event on this channel
|
130
|
-
def fire!(
|
131
|
-
kwargs[:blocking]
|
116
|
+
def fire!(*args, **kwargs)
|
117
|
+
kwargs[:blocking] = true unless kwargs.has_key? :blocking
|
132
118
|
fire(*args, **kwargs)
|
133
119
|
end
|
134
120
|
|
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
module Wires
|
3
|
+
|
4
|
+
class Event
|
5
|
+
attr_accessor :type
|
6
|
+
attr_accessor :kwargs
|
7
|
+
attr_accessor :args
|
8
|
+
attr_accessor :codeblock
|
9
|
+
|
10
|
+
# Return a friendly output upon inspection
|
11
|
+
def inspect
|
12
|
+
list = [*args, **kwargs]
|
13
|
+
list << codeblock.to_s if codeblock
|
14
|
+
list = list.map(&:inspect).join ', '
|
15
|
+
the_type = type ? type.inspect : ''
|
16
|
+
"#{the_type}:[#{list}]"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Internalize all *args and **kwargs and &block to be accessed later
|
20
|
+
def initialize(*args, **kwargs, &block)
|
21
|
+
if kwargs.has_key? :type
|
22
|
+
@type = kwargs[:type]
|
23
|
+
kwargs.delete :type
|
24
|
+
else
|
25
|
+
@type = :*
|
26
|
+
end
|
27
|
+
|
28
|
+
@args = args
|
29
|
+
@kwargs = kwargs
|
30
|
+
@codeblock = block
|
31
|
+
|
32
|
+
@kwargs.keys
|
33
|
+
.reject{ |m| [:kwargs, :args, :codeblock].include? m }
|
34
|
+
.each { |m| singleton_class.send(:define_method, m) { @kwargs[m] } }
|
35
|
+
end
|
36
|
+
|
37
|
+
# Convert to a Wires::Event; returns self, unaltered
|
38
|
+
def to_wires_event; self; end
|
39
|
+
|
40
|
+
# Directly access contents of @kwargs by key
|
41
|
+
def [](key); @kwargs[key]; end
|
42
|
+
|
43
|
+
# Returns true if all meaningful components of two events are equal
|
44
|
+
# Use #equal? instead if you want object identity comparison
|
45
|
+
def ==(other)
|
46
|
+
(other = other.to_wires_event if other.respond_to? :to_wires_event) ?
|
47
|
+
((self.type == other.type) and
|
48
|
+
(self.args == other.args) and
|
49
|
+
(self.kwargs == other.kwargs) and
|
50
|
+
(self.codeblock == other.codeblock)) :
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns true if listening for 'self' would hear a firing of 'other'
|
55
|
+
# (not commutative)
|
56
|
+
def =~(other)
|
57
|
+
(other = other.to_wires_event if other.respond_to? :to_wires_event) ?
|
58
|
+
(([:*, other.type].include? self.type) and
|
59
|
+
(not self.kwargs.each_pair.detect{|k,v| other.kwargs[k]!=v}) and
|
60
|
+
(not self.args.each_with_index.detect{|a,i| other.args[i]!=a})) :
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return an array of Event instance objects from the input
|
65
|
+
def self.list_from(*args)
|
66
|
+
args.flatten.map &:to_wires_event
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -5,6 +5,9 @@ module Wires
|
|
5
5
|
class self::Hub
|
6
6
|
class << self
|
7
7
|
|
8
|
+
# Refuse to instantiate; it's a singleton!
|
9
|
+
private :new
|
10
|
+
|
8
11
|
# Allow user to get/set limit to number of child threads
|
9
12
|
attr_accessor :max_children
|
10
13
|
|
@@ -60,12 +63,9 @@ module Wires
|
|
60
63
|
spawn_neglected_task_threads
|
61
64
|
end
|
62
65
|
|
63
|
-
# Spawn a task
|
66
|
+
# Spawn a task - user code should never call this directly
|
64
67
|
def spawn(*args) # :args: event, chan, proc, blocking, fire_bt
|
65
68
|
|
66
|
-
return neglect(*args) \
|
67
|
-
if @hold_lock.instance_variable_get(:@mon_mutex).locked?
|
68
|
-
|
69
69
|
event, chan, proc, blocking, parallel, fire_bt = *args
|
70
70
|
*proc_args = event, chan
|
71
71
|
*exc_args = event, chan, fire_bt
|
@@ -81,6 +81,9 @@ module Wires
|
|
81
81
|
return nil
|
82
82
|
end
|
83
83
|
|
84
|
+
return neglect(*args) \
|
85
|
+
if @hold_lock.instance_variable_get(:@mon_mutex).locked?
|
86
|
+
|
84
87
|
# If not parallel, clear old threads and spawn a new thread
|
85
88
|
Thread.exclusive do
|
86
89
|
begin
|
@@ -2,9 +2,10 @@
|
|
2
2
|
module Wires
|
3
3
|
module Router
|
4
4
|
|
5
|
-
|
6
5
|
class Default
|
7
6
|
class << self
|
7
|
+
# Refuse to instantiate; it's a singleton!
|
8
|
+
private :new
|
8
9
|
|
9
10
|
def clear_channels()
|
10
11
|
@table = {}
|
@@ -42,6 +43,8 @@ module Wires
|
|
42
43
|
|
43
44
|
class Simple
|
44
45
|
class << self
|
46
|
+
# Refuse to instantiate; it's a singleton!
|
47
|
+
private :new
|
45
48
|
|
46
49
|
def clear_channels()
|
47
50
|
@table = {}
|
@@ -0,0 +1,92 @@
|
|
1
|
+
|
2
|
+
module Wires
|
3
|
+
|
4
|
+
class TimeSchedulerItem
|
5
|
+
|
6
|
+
attr_accessor :schedulers
|
7
|
+
attr_reader :time, :events, :channel,
|
8
|
+
:count, :interval, :jitter
|
9
|
+
attr_accessor :fire_kwargs
|
10
|
+
|
11
|
+
def initialize(time, events, channel,
|
12
|
+
count:1, interval:0, jitter:0,
|
13
|
+
ignore_past:false, active:true,
|
14
|
+
**fire_kwargs)
|
15
|
+
|
16
|
+
time ||= Time.now
|
17
|
+
|
18
|
+
@events = Event.list_from(events)
|
19
|
+
@channel = channel.is_a?(Channel) ? channel : Channel.new(channel)
|
20
|
+
|
21
|
+
@interval = interval
|
22
|
+
@jitter = jitter
|
23
|
+
|
24
|
+
@active = active
|
25
|
+
@fire_kwargs = fire_kwargs
|
26
|
+
|
27
|
+
tempcount = count
|
28
|
+
if ignore_past
|
29
|
+
while (time < Time.now) and (tempcount > 0)
|
30
|
+
time += interval
|
31
|
+
tempcount -= 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
self.count = tempcount
|
35
|
+
|
36
|
+
@time = time
|
37
|
+
|
38
|
+
@schedulers = []
|
39
|
+
end
|
40
|
+
|
41
|
+
def active?; @active end
|
42
|
+
def active=(x) @active=x end
|
43
|
+
|
44
|
+
def ready?(at_time=Time.now)
|
45
|
+
@active and (at_time>=@time)
|
46
|
+
end
|
47
|
+
|
48
|
+
def time_until(from_time=Time.now)
|
49
|
+
(@active ? [(@time - from_time), 0].max : nil)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Set @count (and apply constraints)
|
53
|
+
def count=(new_count)
|
54
|
+
@count=[new_count,0].max
|
55
|
+
.tap { |c| @active&&=(c>0) }
|
56
|
+
end
|
57
|
+
|
58
|
+
# Inc/dec @count. Necessary because += and -= without lock are not atomic!
|
59
|
+
def count_inc(diff=1); self.count=(@count+diff) end
|
60
|
+
def count_dec(diff=1); self.count=(@count-diff) end
|
61
|
+
|
62
|
+
# Fire the event now, regardless of time or active status
|
63
|
+
def fire(**kwargs) # kwargs merge with and override @kwargs
|
64
|
+
@channel.fire(@events, **(@fire_kwargs.merge kwargs))
|
65
|
+
count_dec
|
66
|
+
|
67
|
+
if @active
|
68
|
+
@time = [@time, Time.now].max + (@interval + (Random.rand*2-1)*@jitter)
|
69
|
+
end
|
70
|
+
notify_schedulers
|
71
|
+
true end
|
72
|
+
|
73
|
+
# Fire the event only if it is ready
|
74
|
+
def fire_if_ready(**kwargs)
|
75
|
+
self.fire(**kwargs) if ready?
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def notify_schedulers
|
81
|
+
@schedulers.each &:refresh
|
82
|
+
end
|
83
|
+
|
84
|
+
# Lock some of the methods to try to make them atomic
|
85
|
+
# Must exclude methods that get called from within the TimeScheduler lock
|
86
|
+
threadlock :fire,
|
87
|
+
:count=,
|
88
|
+
:count_inc,
|
89
|
+
:count_dec
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
@@ -8,7 +8,7 @@ module Wires
|
|
8
8
|
# >> module MyModule; end
|
9
9
|
# >> Wires::Util.build_alt "::MyModule::MyWires"
|
10
10
|
def self.build_alt(module_path)
|
11
|
-
main_file = File.expand_path("../../
|
11
|
+
main_file = File.expand_path("../../base.rb", File.dirname(__FILE__))
|
12
12
|
|
13
13
|
File.read(main_file)
|
14
14
|
.scan(/require_relative[\s\(]+(["'])(.*)\1/)
|
@@ -16,6 +16,8 @@ module Wires
|
|
16
16
|
.map { |file| File.expand_path("#{file}.rb", File.dirname(main_file)) }
|
17
17
|
.map { |file| File.read file }
|
18
18
|
.each { |code| eval code.gsub("Wires", "#{module_path}") }
|
19
|
+
|
20
|
+
eval "#{module_path}"
|
19
21
|
end
|
20
22
|
|
21
23
|
end
|
File without changes
|
data/lib/wires/base.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
require 'thread'
|
3
|
+
require 'threadlock'
|
4
|
+
|
5
|
+
require_relative 'base/util/hooks'
|
6
|
+
require_relative 'base/util/build_alt'
|
7
|
+
|
8
|
+
require_relative 'base/event'
|
9
|
+
require_relative 'base/hub'
|
10
|
+
require_relative 'base/router'
|
11
|
+
require_relative 'base/channel'
|
12
|
+
require_relative 'base/time_scheduler_item'
|
13
|
+
require_relative 'base/time_scheduler'
|
14
|
+
require_relative 'base/convenience'
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
# Add Numeric => Numeric time-factor converters
|
3
|
+
{
|
4
|
+
[:second, :seconds] => '1',
|
5
|
+
[:minute, :minutes] => '60',
|
6
|
+
[:hour, :hours] => '3600',
|
7
|
+
[:day, :days] => '24.hours',
|
8
|
+
[:week, :weeks] => '7.days',
|
9
|
+
[:fortnight, :fortnights] => '2.weeks',
|
10
|
+
}.each_pair do |k,v|
|
11
|
+
::Numeric.class_eval <<-CODE
|
12
|
+
def #{k.last}
|
13
|
+
self * #{v}
|
14
|
+
end
|
15
|
+
alias #{k.first.inspect} #{k.last.inspect}
|
16
|
+
CODE
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# Add Numeric => Time converters with implicit anonymous fire
|
21
|
+
{
|
22
|
+
[:from_now, :since] => '+',
|
23
|
+
[:until, :ago] => '-',
|
24
|
+
}.each_pair do |k,v|
|
25
|
+
::Numeric.class_eval <<-CODE
|
26
|
+
def #{k.last}(time = ::Time.now, &block)
|
27
|
+
if block
|
28
|
+
Wires::Channel[block.object_id].register :time_scheduler_anon, &block
|
29
|
+
self.#{k.last}(time).fire(:time_scheduler_anon, block.object_id)
|
30
|
+
end
|
31
|
+
time #{v} self
|
32
|
+
end
|
33
|
+
alias #{k.first.inspect} #{k.last.inspect}
|
34
|
+
CODE
|
35
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
# Add implicit conversion of symbol into an event
|
3
|
+
class ::Symbol
|
4
|
+
# Create a Wires::Event from any symbol with a payload of arguments
|
5
|
+
def [](*args, **kwargs, &block)
|
6
|
+
Wires::Event.new(*args, **kwargs, type:self, &block)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Convert to a Wires::Event; returns an empty event with type:self
|
10
|
+
def to_wires_event; self.[]; end
|
11
|
+
end
|
data/lib/wires/core_ext.rb
CHANGED
@@ -1,65 +1,4 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
@core_ext = true
|
6
|
-
|
7
|
-
class << self
|
8
|
-
|
9
|
-
# Set this attribute to false to disable core_ext on include
|
10
|
-
attr_accessor :core_ext
|
11
|
-
|
12
|
-
# Call extend_core on include unless attribute is set to false
|
13
|
-
def included(*args)
|
14
|
-
super
|
15
|
-
self.extend_core if @core_ext
|
16
|
-
end
|
17
|
-
|
18
|
-
# Add methods to ::Time and ::Numeric
|
19
|
-
def extend_core
|
20
|
-
# Add Time#fire for timed firing of events
|
21
|
-
::Time.class_eval <<-CODE
|
22
|
-
def fire(event, channel='*', **kwargs)
|
23
|
-
#{TimeScheduler}.add(self, event, channel, **kwargs)
|
24
|
-
end
|
25
|
-
CODE
|
26
|
-
|
27
|
-
# Add Numeric => Numeric time-factor converters
|
28
|
-
{
|
29
|
-
[:second, :seconds] => '1',
|
30
|
-
[:minute, :minutes] => '60',
|
31
|
-
[:hour, :hours] => '3600',
|
32
|
-
[:day, :days] => '24.hours',
|
33
|
-
[:week, :weeks] => '7.days',
|
34
|
-
[:fortnight, :fortnights] => '2.weeks',
|
35
|
-
}.each_pair do |k,v|
|
36
|
-
::Numeric.class_eval <<-CODE
|
37
|
-
def #{k.last}
|
38
|
-
self * #{v}
|
39
|
-
end
|
40
|
-
alias #{k.first.inspect} #{k.last.inspect}
|
41
|
-
CODE
|
42
|
-
end
|
43
|
-
|
44
|
-
# Add Numeric => Time converters with implicit anonymous fire
|
45
|
-
{
|
46
|
-
[:from_now, :since] => '+',
|
47
|
-
[:until, :ago] => '-',
|
48
|
-
}.each_pair do |k,v|
|
49
|
-
::Numeric.class_eval <<-CODE
|
50
|
-
def #{k.last}(time = ::Time.now, &block)
|
51
|
-
if block
|
52
|
-
Channel[block.object_id].register :time_scheduler_anon, &block
|
53
|
-
self.#{k.last}(time).fire(:time_scheduler_anon, block.object_id)
|
54
|
-
end
|
55
|
-
time #{v} self
|
56
|
-
end
|
57
|
-
alias #{k.first.inspect} #{k.last.inspect}
|
58
|
-
CODE
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
end
|
2
|
+
require_relative 'core_ext/symbol'
|
3
|
+
require_relative 'core_ext/time'
|
4
|
+
require_relative 'core_ext/numeric'
|
data/lib/wires.rb
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
require '
|
2
|
+
# Require all core wires functionality through 'wires/clean'
|
3
|
+
# If you don't consent to the core extensions, require 'wires/clean' directly
|
4
|
+
require_relative 'wires/base'
|
4
5
|
|
5
|
-
|
6
|
-
require_relative 'wires/util/build_alt'
|
7
|
-
|
8
|
-
require_relative 'wires/event'
|
9
|
-
require_relative 'wires/hub'
|
10
|
-
require_relative 'wires/router'
|
11
|
-
require_relative 'wires/channel'
|
12
|
-
require_relative 'wires/time_scheduler_item'
|
13
|
-
require_relative 'wires/time_scheduler'
|
6
|
+
# Add core extensions for syntax sugar and ease
|
14
7
|
require_relative 'wires/core_ext'
|
15
|
-
require_relative 'wires/convenience'
|
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.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe McIlvain
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-11-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: threadlock
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rdoc
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -53,7 +53,63 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-rescue
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: fivemat
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: timecop
|
57
113
|
requirement: !ruby/object:Gem::Requirement
|
58
114
|
requirements:
|
59
115
|
- - ">="
|
@@ -74,16 +130,20 @@ extensions: []
|
|
74
130
|
extra_rdoc_files: []
|
75
131
|
files:
|
76
132
|
- lib/wires.rb
|
77
|
-
- lib/wires/hub.rb
|
78
|
-
- lib/wires/router.rb
|
79
133
|
- lib/wires/core_ext.rb
|
80
|
-
- lib/wires/
|
81
|
-
- lib/wires/
|
82
|
-
- lib/wires/
|
83
|
-
- lib/wires/
|
84
|
-
- lib/wires/
|
85
|
-
- lib/wires/
|
86
|
-
- lib/wires/
|
134
|
+
- lib/wires/core_ext/time.rb
|
135
|
+
- lib/wires/core_ext/symbol.rb
|
136
|
+
- lib/wires/core_ext/numeric.rb
|
137
|
+
- lib/wires/base/hub.rb
|
138
|
+
- lib/wires/base/router.rb
|
139
|
+
- lib/wires/base/util/build_alt.rb
|
140
|
+
- lib/wires/base/util/hooks.rb
|
141
|
+
- lib/wires/base/convenience.rb
|
142
|
+
- lib/wires/base/channel.rb
|
143
|
+
- lib/wires/base/time_scheduler_item.rb
|
144
|
+
- lib/wires/base/time_scheduler.rb
|
145
|
+
- lib/wires/base/event.rb
|
146
|
+
- lib/wires/base.rb
|
87
147
|
- LICENSE
|
88
148
|
- README.md
|
89
149
|
homepage: https://github.com/jemc/wires/
|
@@ -111,3 +171,4 @@ signing_key:
|
|
111
171
|
specification_version: 4
|
112
172
|
summary: wires
|
113
173
|
test_files: []
|
174
|
+
has_rdoc:
|
data/lib/wires/event.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
|
2
|
-
module Wires
|
3
|
-
|
4
|
-
class Event
|
5
|
-
attr_accessor :event_type
|
6
|
-
|
7
|
-
# Return a friendly output upon inspection
|
8
|
-
def inspect
|
9
|
-
list = [*args, **kwargs].map(&:inspect).join ', '
|
10
|
-
type = event_type ? event_type.inspect : ''
|
11
|
-
"#{self.class}#{type}(#{list})"
|
12
|
-
end
|
13
|
-
|
14
|
-
# Internalize all *args and **kwargs and &block to be accessed later
|
15
|
-
def initialize(*args, **kwargs, &block)
|
16
|
-
cls = self.class
|
17
|
-
self.event_type = cls unless cls==Wires::Event
|
18
|
-
|
19
|
-
@ignore = []
|
20
|
-
@kwargs = kwargs.dup
|
21
|
-
|
22
|
-
@kwargs.keys.each do |m|
|
23
|
-
if respond_to? m
|
24
|
-
(class << self; self; end).class_eval do
|
25
|
-
undef_method m
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
(@kwargs[:args] = args.freeze; @ignore<<:args) \
|
31
|
-
unless @kwargs.has_key? :args
|
32
|
-
(@kwargs[:codeblock] = block; @ignore<<:codeblock) \
|
33
|
-
unless @kwargs.has_key? :codeblock
|
34
|
-
@kwargs.freeze
|
35
|
-
end
|
36
|
-
|
37
|
-
# Directly access contents of @kwargs by key
|
38
|
-
def [](key); @kwargs[key]; end
|
39
|
-
|
40
|
-
# Used to fake a sort of read-only openstruct from contents of @kwargs
|
41
|
-
def method_missing(sym, *args, &block)
|
42
|
-
args.empty? and @kwargs.has_key?(sym) ?
|
43
|
-
@kwargs[sym] :
|
44
|
-
(sym==:kwargs ? @kwargs.reject{|k| @ignore.include? k} : super)
|
45
|
-
end
|
46
|
-
|
47
|
-
# Returns true if listening for 'self' would hear a firing of 'other'
|
48
|
-
# (not commutative)
|
49
|
-
def =~(other)
|
50
|
-
(other.is_a? Event) ?
|
51
|
-
((self.class >= other.class) \
|
52
|
-
and (self.event_type.nil? or self.event_type==other.event_type \
|
53
|
-
or (self.event_type.is_a? Class and other.event_type.is_a? Class \
|
54
|
-
and self.event_type >= other.event_type)) \
|
55
|
-
and (not self.kwargs.each_pair.detect{|k,v| other.kwargs[k]!=v}) \
|
56
|
-
and (not self.args.each_with_index.detect{|a,i| other.args[i]!=a})) :
|
57
|
-
super
|
58
|
-
end
|
59
|
-
|
60
|
-
# Return an array of Event instance objects generated from
|
61
|
-
# specially formatted input (see spec/event_spec.rb).
|
62
|
-
def self.new_from(*args)
|
63
|
-
args.flatten!
|
64
|
-
list = []
|
65
|
-
|
66
|
-
args.each do |x|
|
67
|
-
(x.is_a? Hash) ?
|
68
|
-
(x.each_pair { |x,y| list << [x,y] }) :
|
69
|
-
(list << [x,[]])
|
70
|
-
end
|
71
|
-
|
72
|
-
list.map! do |type, args|
|
73
|
-
case type
|
74
|
-
when Event; obj = type
|
75
|
-
when Class;
|
76
|
-
if type<=Event
|
77
|
-
obj = type.new(*args)
|
78
|
-
end
|
79
|
-
when Symbol
|
80
|
-
obj = self.new(*args)
|
81
|
-
obj.event_type = type
|
82
|
-
obj if self==Wires::Event
|
83
|
-
end
|
84
|
-
obj
|
85
|
-
end.tap do |x|
|
86
|
-
raise ArgumentError,
|
87
|
-
"Invalid event creation input: #{args} \noutput: #{x}" \
|
88
|
-
if x.empty? or !x.all?
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# Ensure that self.new_from is not inherited
|
93
|
-
def self.inherited(subcls)
|
94
|
-
super
|
95
|
-
class << subcls
|
96
|
-
undef_method :new_from
|
97
|
-
end if self == Wires::Event
|
98
|
-
end
|
99
|
-
|
100
|
-
end
|
101
|
-
|
102
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
|
2
|
-
module Wires
|
3
|
-
|
4
|
-
class TimeSchedulerItem
|
5
|
-
|
6
|
-
attr_reader :time, :event, :channel, :interval
|
7
|
-
attr_accessor :schedulers
|
8
|
-
|
9
|
-
def initialize(time, event, channel='*',
|
10
|
-
interval:0.seconds, count:1,
|
11
|
-
ignore_past:false, cancel:false,
|
12
|
-
**kwargs)
|
13
|
-
|
14
|
-
time ||= Time.now
|
15
|
-
|
16
|
-
@active = (not cancel)
|
17
|
-
tempcount = count
|
18
|
-
|
19
|
-
while (time < Time.now) and (tempcount > 0)
|
20
|
-
time += interval
|
21
|
-
tempcount -= 1
|
22
|
-
end
|
23
|
-
if not ignore_past
|
24
|
-
time -= interval
|
25
|
-
self.count = count
|
26
|
-
else
|
27
|
-
self.count = tempcount
|
28
|
-
end
|
29
|
-
|
30
|
-
@time = time
|
31
|
-
@interval = interval
|
32
|
-
|
33
|
-
@event = Event.new_from(event)
|
34
|
-
@channel = channel.is_a?(Channel) ? channel : Channel.new(channel)
|
35
|
-
@kwargs = kwargs
|
36
|
-
|
37
|
-
@schedulers = []
|
38
|
-
end
|
39
|
-
|
40
|
-
def active?; @active end
|
41
|
-
def inactive?; !@active end
|
42
|
-
|
43
|
-
def ready?(at_time=Time.now); @active and (at_time>=@time) end
|
44
|
-
|
45
|
-
def time_until; (@active ? [(@time - Time.now), 0].max : nil) end
|
46
|
-
|
47
|
-
def cancel; self.count=0 ;nil end
|
48
|
-
|
49
|
-
# Get/set @count (and apply constraints on set)
|
50
|
-
def count; @count end
|
51
|
-
#TODO: handle explicit cancel?
|
52
|
-
def count=(x); @count=[x,0].max; @active&&=(count>0) ;nil end
|
53
|
-
|
54
|
-
# Inc/dec @count. Necessary because += and -= outside of lock are not atomic!
|
55
|
-
def count_inc(x=1); self.count=(@count+x) end
|
56
|
-
def count_dec(x=1); self.count=(@count-x) end
|
57
|
-
|
58
|
-
# Fire the event now, regardless of time or active status
|
59
|
-
def fire(**kwargs) # kwargs merge with and override @kwargs
|
60
|
-
@channel.fire(@event, **(@kwargs.merge(kwargs)))
|
61
|
-
count_dec
|
62
|
-
@time += @interval if @active
|
63
|
-
notify_schedulers
|
64
|
-
nil end
|
65
|
-
|
66
|
-
# Fire the event only if it is ready
|
67
|
-
def fire_if_ready(**args); self.fire(**kwargs) if ready? end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def notify_schedulers; @schedulers.each &:refresh end
|
72
|
-
|
73
|
-
# Lock some of the methods to try to make them atomic
|
74
|
-
# Must exclude methods that get called from within the TimeScheduler lock
|
75
|
-
threadlock :fire,
|
76
|
-
:count=,
|
77
|
-
:count_inc,
|
78
|
-
:count_dec
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|