thomas_utils 0.1.18 → 0.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7d8863b06f5f048eab689b989c66dd14e4d29b4f
4
- data.tar.gz: c5d8484310812422078cf2e147ef9caa1eb5c845
3
+ metadata.gz: 1020f2a07e22d03f1be48e6c97fdc68b4c03631b
4
+ data.tar.gz: 35873e679f97bab51c4cad7b613efeca95733a60
5
5
  SHA512:
6
- metadata.gz: f7a8d86e988a34be705829a487d9404e8e385a03f6eb7bf8c06dec02f7a95cfb6da37fb80eac00eb4efb6e2074aa88e8718e9086005e701f7b447ae586018218
7
- data.tar.gz: 99dc2ba2d5513d7148963fa76edebe30280900673158468ae393fdd6fbe392297f78c84e8ca9a06c378c7269dd80fdcbce6fb622658e6cd433dd09af97302703
6
+ metadata.gz: 2cd4e5f2b799142ea45e3ad1026fd748cfa2e2520072d3a0ca836b61b98dd39e3db42d61f3a88f72f1ec70168fe34d94e6ceb8f020e6a36f54715d057789d029
7
+ data.tar.gz: a511baf55abad9d03c3f8f70ce972fad75e3defd6c2b46c1b58235c940450d7e15e74c262062d5f76f02444097202eb9f5b46ba61cc0b468d59495db5ad15c96
@@ -25,4 +25,7 @@ require 'thomas_utils/multi_future_wrapper'
25
25
  require 'thomas_utils/key_comparer'
26
26
  require 'thomas_utils/key_indexer'
27
27
  require 'thomas_utils/key_child'
28
+ require 'thomas_utils/executor_service'
29
+ require 'thomas_utils/constant_var'
30
+ require 'thomas_utils/observation'
28
31
  require 'thomas_utils/future'
@@ -0,0 +1,47 @@
1
+ module ThomasUtils
2
+ class ConstantVar < Struct.new(:time, :value, :reason)
3
+
4
+ def self.value(value)
5
+ new(Time.now, value, nil)
6
+ end
7
+
8
+ def self.none
9
+ new(Time.now, nil, nil)
10
+ end
11
+
12
+ def self.error(error)
13
+ new(Time.now, nil, error)
14
+ end
15
+
16
+ def value!
17
+ raise reason if reason
18
+ value
19
+ end
20
+
21
+ def add_observer(observer = nil, func = :update, &block)
22
+ if block
23
+ observer = block
24
+ func = :call
25
+ end
26
+ observer.public_send(func, time, value, reason)
27
+ end
28
+
29
+ def with_observer(observer = nil, func = :update, &block)
30
+ add_observer(observer, func, &block)
31
+ self
32
+ end
33
+
34
+ def delete_observer(_)
35
+ raise NotImplementedError
36
+ end
37
+
38
+ def delete_observers
39
+ raise NotImplementedError
40
+ end
41
+
42
+ def count_observers
43
+ raise NotImplementedError
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,7 @@
1
+ module Concurrent
2
+ module ExecutorService
3
+ def execute(*args, &block)
4
+ post(*args, &block)
5
+ end
6
+ end
7
+ end
@@ -1,42 +1,53 @@
1
1
  module ThomasUtils
2
- class Future
2
+ class Future < Observation
3
3
  DEFAULT_EXECUTOR = ::Concurrent::CachedThreadPool.new
4
+ IMMEDIATE_EXECUTOR = ::Concurrent::ImmediateExecutor.new
4
5
 
5
- def initialize(options = {})
6
- options[:executor] ||= DEFAULT_EXECUTOR
7
-
8
- @mutex = Mutex.new
9
- @future = ::Concurrent::Future.execute(executor: options[:executor]) do
10
- begin
11
- @result = yield
12
- @result = @result.get if @result.is_a?(FutureWrapper)
13
- @mutex.synchronize { @success_callback.call(@result) if @success_callback }
14
- @result
15
- rescue => e
16
- @error = e
17
- @mutex.synchronize { @failure_callback.call(e) if @failure_callback }
18
- end
19
- end
6
+ def self.value(value)
7
+ Observation.new(IMMEDIATE_EXECUTOR, ConstantVar.value(value))
8
+ end
9
+
10
+ def self.immediate(&block)
11
+ none.then(&block)
20
12
  end
21
13
 
22
- def get
23
- result = @future.value
24
- raise @error if @error
25
- result
14
+ def self.none
15
+ Observation.new(IMMEDIATE_EXECUTOR, ConstantVar.none)
26
16
  end
27
17
 
28
- def join
29
- get rescue nil
18
+ def self.error(error)
19
+ Observation.new(IMMEDIATE_EXECUTOR, ConstantVar.error(error))
30
20
  end
31
21
 
32
- def on_success(&block)
33
- @mutex.synchronize { @success_callback = block }
34
- @success_callback.call(@result) if @future.fulfilled? && !@error
22
+ def self.all(observations)
23
+ observable = Concurrent::IVar.new
24
+ left = observations.count
25
+ buffer = [nil] * left
26
+ mutex = Mutex.new
27
+ observations.each_with_index do |observation, index|
28
+ observation.on_complete do |value, error|
29
+ if error
30
+ observable.fail(error)
31
+ else
32
+ buffer[index] = value
33
+ done = false
34
+ mutex.synchronize do
35
+ left -= 1
36
+ done = !!left.zero?
37
+ end
38
+ observable.set(buffer) if done
39
+ end
40
+ end
41
+ end
42
+ Observation.new(DEFAULT_EXECUTOR, observable)
35
43
  end
36
44
 
37
- def on_failure(&block)
38
- @mutex.synchronize { @failure_callback = block }
39
- @failure_callback.call(@error) if @future.fulfilled? && @error
45
+ def initialize(options = {}, &block)
46
+ executor = options.fetch(:executor) { DEFAULT_EXECUTOR }
47
+ observable = Concurrent::Future.execute(executor: executor, &block)
48
+ super(executor, observable)
40
49
  end
50
+
41
51
  end
42
- end
52
+ end
53
+
@@ -0,0 +1,167 @@
1
+ module ThomasUtils
2
+ class Observation
3
+ extend Forwardable
4
+
5
+ def_delegator :@observable, :value!, :get
6
+
7
+ def initialize(executor, observable)
8
+ @executor = executor
9
+ @observable = observable
10
+ end
11
+
12
+ def on_success
13
+ @observable.add_observer do |_, value, error|
14
+ @executor.post do
15
+ yield value unless error
16
+ end
17
+ end
18
+ self
19
+ end
20
+
21
+ def on_failure
22
+ @observable.add_observer do |_, _, error|
23
+ @executor.post do
24
+ yield error if error
25
+ end
26
+ end
27
+ self
28
+ end
29
+
30
+ def on_complete
31
+ @observable.add_observer do |_, value, error|
32
+ @executor.post do
33
+ yield value, error
34
+ end
35
+ end
36
+ self
37
+ end
38
+
39
+ def join
40
+ @observable.value
41
+ self
42
+ end
43
+
44
+ def then(&block)
45
+ successive(:on_complete_then, &block)
46
+ end
47
+
48
+ def none_fallback
49
+ self.then do |result|
50
+ result || yield
51
+ end
52
+ end
53
+
54
+ def fallback(&block)
55
+ successive(:on_complete_fallback, &block)
56
+ end
57
+
58
+ def ensure(&block)
59
+ successive(:on_complete_ensure, &block)
60
+ end
61
+
62
+ def on_success_ensure(&block)
63
+ self.then do |result|
64
+ child_result = block.call(result)
65
+ if result_is_observation?(child_result)
66
+ child_result.then { result }
67
+ else
68
+ result
69
+ end
70
+ end
71
+ end
72
+
73
+ def on_failure_ensure(&block)
74
+ self.fallback do |error|
75
+ result = block.call(error)
76
+ error_observation = Observation.new(@executor, ConstantVar.error(error))
77
+ if result_is_observation?(result)
78
+ result.then { error_observation }
79
+ else
80
+ error_observation
81
+ end
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def successive(method, &block)
88
+ observable = Concurrent::IVar.new
89
+ send(method, observable, &block)
90
+ Observation.new(@executor, observable)
91
+ end
92
+
93
+ def on_complete_then(observable, &block)
94
+ on_complete do |value, error|
95
+ if error
96
+ observable.fail(error)
97
+ else
98
+ on_success_then(observable, value, &block)
99
+ end
100
+ end
101
+ end
102
+
103
+ def on_complete_fallback(observable, &block)
104
+ on_complete do |value, error|
105
+ if error
106
+ on_failure_fallback(observable, error, &block)
107
+ else
108
+ observable.set(value)
109
+ end
110
+ end
111
+ end
112
+
113
+ def on_success_then(observable, value)
114
+ result = yield value
115
+ if result_is_observation?(result)
116
+ result.on_complete do |child_result, child_error|
117
+ ensure_then(child_error, observable, child_result)
118
+ end
119
+ else
120
+ observable.set(result)
121
+ end
122
+ rescue Exception => error
123
+ observable.fail(error)
124
+ end
125
+
126
+ alias :on_failure_fallback :on_success_then
127
+
128
+ def on_complete_ensure(observable)
129
+ on_complete do |value, error|
130
+ begin
131
+ result = yield value, error
132
+ if result_is_observation?(result)
133
+ ensure_complete_then(error, observable, result, value)
134
+ else
135
+ ensure_then(error, observable, value)
136
+ end
137
+ rescue Exception => child_error
138
+ observable.fail(child_error)
139
+ end
140
+ end
141
+ end
142
+
143
+ def ensure_complete_then(error, observable, result, value)
144
+ result.on_complete do |_, child_error|
145
+ if child_error
146
+ observable.fail(child_error)
147
+ elsif error
148
+ observable.fail(error)
149
+ else
150
+ observable.set(value)
151
+ end
152
+ end
153
+ end
154
+
155
+ def ensure_then(error, observable, value)
156
+ if error
157
+ observable.fail(error)
158
+ else
159
+ observable.set(value)
160
+ end
161
+ end
162
+
163
+ def result_is_observation?(result)
164
+ result.respond_to?(:on_complete) && result.respond_to?(:then)
165
+ end
166
+ end
167
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thomas_utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.18
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas RM Rogers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-14 00:00:00.000000000 Z
11
+ date: 2016-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: '0.8'
19
+ version: 1.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: '0.8'
26
+ version: 1.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: workers
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -50,6 +50,8 @@ files:
50
50
  - LICENSE.txt
51
51
  - README.md
52
52
  - lib/thomas_utils.rb
53
+ - lib/thomas_utils/constant_var.rb
54
+ - lib/thomas_utils/executor_service.rb
53
55
  - lib/thomas_utils/future.rb
54
56
  - lib/thomas_utils/future_wrapper.rb
55
57
  - lib/thomas_utils/key_child.rb
@@ -57,6 +59,7 @@ files:
57
59
  - lib/thomas_utils/key_indexer.rb
58
60
  - lib/thomas_utils/multi_future_wrapper.rb
59
61
  - lib/thomas_utils/object_stream.rb
62
+ - lib/thomas_utils/observation.rb
60
63
  - lib/thomas_utils/periodic_flusher.rb
61
64
  - lib/thomas_utils/symbol_helpers.rb
62
65
  homepage: https://www.github.com/thomasrogers03/thomas_utils