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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2b7c2dd1598b631eb5b5db562ca8fcc480c7e5bd
4
- data.tar.gz: c04825a10cddd424a1e7a3dcab51c92106d72d94
3
+ metadata.gz: 04ad9bc6ef2ce9a54aad3343c13fca6ca69f1895
4
+ data.tar.gz: cf519182f4a9cd03776cb749d3bd922aeb5add3a
5
5
  SHA512:
6
- metadata.gz: 1fa7da548738147947d300b015d6f6e3e0c1317429af697a41aa933b1f7f912402c45e367e7d43dc51d915aa7dd3a171b220c015108e9ca68758adec644d34de
7
- data.tar.gz: 92d1414f7dabd03d733b1fdbb9a04ee618428c6e57c03efb3df6edff6f1baaba9da9f2c95c5c7f398a970d0e3d2974bedf0ada9410a5ddfebf597d8200155132
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 :target_list
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 = Mutex.new
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
- @target_list = []
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.new_from(*events)
42
+ events = Event.list_from *events
40
43
 
41
44
  @@aim_lock.synchronize do
42
- @target_list << [events, proc] \
43
- unless @target_list.include? [events, proc]
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(*events, &proc)
52
- events = events.empty? ? [] : Event.new_from(*events)
53
-
54
+ def unregister(proc)
54
55
  @@aim_lock.synchronize do
55
- !!(@target_list.reject! do |es,pr|
56
- (proc and proc==pr) and \
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.new_from(*input)
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.target_list.each do |elist, pr|
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!(event)
131
- kwargs[:blocking] ||= true
116
+ def fire!(*args, **kwargs)
117
+ kwargs[:blocking] = true unless kwargs.has_key? :blocking
132
118
  fire(*args, **kwargs)
133
119
  end
134
120
 
@@ -26,7 +26,7 @@ module Wires
26
26
  nil end
27
27
 
28
28
  def fire!(*args, **kwargs)
29
- kwargs[:blocking] ||= true
29
+ kwargs[:blocking] = true unless kwargs.has_key? :blocking
30
30
  fire(*args, **kwargs)
31
31
  end
32
32
 
@@ -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 = {}
@@ -10,6 +10,9 @@ module Wires
10
10
 
11
11
  class << self
12
12
 
13
+ # Refuse to instantiate; it's a singleton!
14
+ private :new
15
+
13
16
  # Add an event to the schedule
14
17
  def add(*args)
15
18
  new_item = args.first
@@ -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("../../wires.rb", File.dirname(__FILE__))
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
@@ -0,0 +1,7 @@
1
+
2
+ # Add Time#fire for timed firing of events
3
+ class ::Time
4
+ def fire(events, channel, **kwargs)
5
+ Wires::TimeScheduler.add(self, events, channel, **kwargs)
6
+ end
7
+ end
@@ -1,65 +1,4 @@
1
1
 
2
- module Wires
3
- module Convenience
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
- require 'thread'
3
- require 'threadlock'
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
- require_relative 'wires/util/hooks'
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.3
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-10-06 00:00:00.000000000 Z
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: wires-test
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: jemc-reporter
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/util/build_alt.rb
81
- - lib/wires/util/hooks.rb
82
- - lib/wires/convenience.rb
83
- - lib/wires/channel.rb
84
- - lib/wires/time_scheduler_item.rb
85
- - lib/wires/time_scheduler.rb
86
- - lib/wires/event.rb
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