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