volt 0.9.5.pre3 → 0.9.5.pre4

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.
@@ -168,43 +168,23 @@ module Volt
168
168
  end
169
169
 
170
170
  # Call a method on the model once the model is loaded. Return a promise
171
- # that will resolve the result of the method, or reject with any
172
- # Exceptions.
173
- def run_once_loaded(block)
171
+ # that will resolve when the model is loaded
172
+ def run_once_loaded
174
173
  promise = Promise.new
175
174
 
176
- # call once the method is loaded.
177
- model_loaded = proc do
178
- begin
179
- result = yield
180
- promise.resolve(result)
181
- rescue Exception => error
182
- promise.reject(error)
183
- end
184
- end
185
-
186
- # Run the block after resolve if a block is passed in
187
- if block
188
- promise2 = promise.then do |val|
189
- block.call(val)
190
- end
191
- else
192
- promise2 = promise
193
- end
194
-
195
175
  if @model.loaded_state == :loaded
196
- model_loaded.call
176
+ promise.resolve(nil)
197
177
  else
198
178
  proc do |comp|
199
179
  if @model.loaded_state == :loaded
200
- model_loaded.call
180
+ promise.resolve(nil)
201
181
 
202
182
  comp.stop
203
183
  end
204
184
  end.watch!
205
185
  end
206
186
 
207
- promise2
187
+ promise
208
188
  end
209
189
 
210
190
  # Returns a promise that is resolved/rejected when the query is complete. Any
@@ -25,7 +25,6 @@ module Volt
25
25
  super
26
26
  end
27
27
 
28
- # puts "GOT: #{res.inspect}"
29
28
  res
30
29
  end
31
30
 
@@ -11,13 +11,16 @@ module Volt
11
11
  @old_size = 0
12
12
  end
13
13
 
14
+ def respond_to_missing?(method_name, include_private = false)
15
+ @array.respond_to?(method_name, include_private) || super
16
+ end
17
+
14
18
  # Forward any missing methods to the array
15
19
  def method_missing(method_name, *args, &block)
16
20
  # Long term we should probably handle all Enum methods
17
21
  # directly for smarter updating. For now, just depend on size
18
22
  # so updates retrigger the whole method call.
19
23
  @size_dep.depend
20
-
21
24
  @array.send(method_name, *args, &block)
22
25
  end
23
26
 
@@ -77,7 +77,7 @@ module Volt
77
77
  connect_to_peers
78
78
  end
79
79
  else
80
- Volt.logger.error('Unable to connect to the database. Volt will still run, but the message bus requires a database connection to setup connections between nodes, so the message bus has been disabled. This means updates will not be propagated between instances (server, console, runners, etc...)')
80
+ Volt.logger.error('Unable to connect to the database. Currently Volt requires running mongodb for a few things to work. Volt will still run, but the message bus requires a database connection to setup connections between nodes, so the message bus has been disabled. Also, the store collection can not be used without a database. This means updates will not be propagated between instances (server, console, runners, etc...)')
81
81
  end
82
82
  end
83
83
 
@@ -181,7 +181,7 @@ module Volt
181
181
  def still_alive?(peer_server_id)
182
182
  # Unable to write to the socket, retry until the instance is no
183
183
  # longer marking its self as active in the database
184
- peer_table = @volt_app.store._active_volt_instances
184
+ peer_table = @volt_app.store.active_volt_instances
185
185
  peer = peer_table.where(server_id: peer_server_id).first.sync
186
186
  if peer
187
187
  # Found the peer, retry if it has reported in in the last 2
@@ -33,7 +33,7 @@ module Volt
33
33
 
34
34
  # Register this server as active with the database
35
35
  def register
36
- instances = @volt_app.store._active_volt_instances
36
+ instances = @volt_app.store.active_volt_instances
37
37
  instances.where(server_id: @server_id).first.then do |item|
38
38
  ips = local_ips.join(',')
39
39
  time = Time.now.to_i
@@ -50,10 +50,11 @@ module Volt
50
50
 
51
51
  rack_app.use HttpResource, volt_app, volt_app.router
52
52
 
53
+ # serve assets from public
53
54
  rack_app.use Rack::Static,
54
55
  urls: ['/'],
55
- root: 'config/base',
56
- index: '',
56
+ root: 'public',
57
+ index: 'index.html',
57
58
  header_rules: [
58
59
  [:all, { 'Cache-Control' => 'public, max-age=86400' }]
59
60
  ]
@@ -4,6 +4,16 @@ require 'uri'
4
4
  # from the dependencies.rb files.
5
5
  module Volt
6
6
  class AssetFiles
7
+ def self.from_cache(component_name, component_paths)
8
+ # @cache ||= {}
9
+
10
+ # @cache[component_name] ||= begin
11
+ # not cached, create
12
+
13
+ self.new(component_name, component_paths)
14
+ # end
15
+ end
16
+
7
17
  def initialize(component_name, component_paths)
8
18
  @component_paths = component_paths
9
19
  @assets = []
@@ -61,6 +71,14 @@ module Volt
61
71
  end
62
72
  end
63
73
 
74
+ # Called when you want to add a gem to the opal load path so it can be
75
+ # required on the client side.
76
+ def opal_gem(gem_name)
77
+ Opal.use_gem(gem_name)
78
+ Opal.paths.uniq!
79
+ # require(gem_name)
80
+ end
81
+
64
82
  def components
65
83
  @included_components.keys
66
84
  end
@@ -17,7 +17,7 @@ module Volt
17
17
  # Start with config code
18
18
  code = @client ? generate_config_code : ''
19
19
 
20
- asset_files = AssetFiles.new(@component_name, @component_paths)
20
+ asset_files = AssetFiles.from_cache(@component_name, @component_paths)
21
21
  asset_files.component_paths.each do |component_path, component_name|
22
22
  code << ComponentTemplates.new(component_path, component_name, @client).code
23
23
  code << "\n\n"
@@ -58,11 +58,11 @@ module Volt
58
58
 
59
59
  def javascript_tags
60
60
  # TODO: Cache somehow, this is being loaded every time
61
- AssetFiles.new('main', @component_paths).javascript_tags(@volt_app)
61
+ AssetFiles.from_cache('main', @component_paths).javascript_tags(@volt_app)
62
62
  end
63
63
 
64
64
  def css_tags
65
- AssetFiles.new('main', @component_paths).css_tags
65
+ AssetFiles.from_cache('main', @component_paths).css_tags
66
66
  end
67
67
  end
68
68
  end
@@ -72,6 +72,9 @@ module Volt
72
72
  run environment
73
73
  end
74
74
 
75
+ # Remove dup paths
76
+ Opal.paths.uniq!
77
+
75
78
  @environment.logger.level ||= Logger::DEBUG
76
79
  source_map_enabled = Volt.source_maps?
77
80
  if source_map_enabled
@@ -29,8 +29,6 @@ module Volt
29
29
  RSpec.configuration.filter_run_excluding type: :feature
30
30
  end
31
31
 
32
-
33
-
34
32
  cleanup_db = -> do
35
33
  volt_app.database.drop_database
36
34
 
@@ -1,6 +1,3 @@
1
- # Require the original promise library first.
2
- require 'volt/utils/promise'
3
-
4
1
  # A temp patch for promises until https://github.com/opal/opal/pull/725 is released.
5
2
  class Promise
6
3
  class UnrealizedPromiseException < RuntimeError ; end
@@ -113,6 +110,10 @@ class Promise
113
110
  end
114
111
 
115
112
  if error
113
+ if error.is_a?(RSpec::Expectations::ExpectationNotMetError)
114
+ # re-raise
115
+ raise error
116
+ end
116
117
  err_str = "Exception in Promise at .sync: #{error.inspect}"
117
118
  err_str += error.backtrace.join("\n") if error.respond_to?(:backtrace)
118
119
  Volt.logger.error(err_str)
data/lib/volt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Volt
2
2
  module Version
3
- STRING = '0.9.5.pre3'
3
+ STRING = '0.9.5.pre4'
4
4
  end
5
5
  end
data/lib/volt/volt/app.rb CHANGED
@@ -88,6 +88,11 @@ module Volt
88
88
 
89
89
  load_app_code
90
90
 
91
+ # Load up the main component dependencies. This is needed to load in
92
+ # any opal_gem calls in dependencies.rb
93
+ # TODO: Needs to support all components
94
+ AssetFiles.from_cache('main', component_paths)
95
+
91
96
  reset_query_pool!
92
97
 
93
98
  # Setup the middleware that we can only setup after all components boot.
@@ -93,12 +93,12 @@ module Volt
93
93
 
94
94
  # Put in a deprecation placeholder
95
95
  def user
96
- Volt.logger.warn('deprication: Volt.user has been renamed to Volt.current_user (to be more clear about what it returns). Volt.user will be deprecated in the future.')
96
+ Volt.logger.warn('Deprecation: Volt.user has been renamed to Volt.current_user (to be more clear about what it returns). Volt.user will be deprecated in the future.')
97
97
  current_user
98
98
  end
99
99
 
100
100
  def fetch_current_user
101
- Volt.logger.warn("Deprication Warning: fetch current user have been depricated, Volt.current_user returns a promise now.")
101
+ Volt.logger.warn("Deprecation Warning: fetch current user have been depricated, Volt.current_user returns a promise now.")
102
102
  current_user
103
103
  end
104
104
 
@@ -3,6 +3,7 @@ require 'volt/extra_core/array'
3
3
 
4
4
  class TestClassAttributes
5
5
  class_attribute :some_data
6
+ class_attribute :attr2
6
7
  end
7
8
 
8
9
  class TestSubClassAttributes < TestClassAttributes
@@ -30,4 +31,14 @@ describe 'extra_core class addons' do
30
31
  expect(TestSubClassAttributes.some_data).to eq(10)
31
32
  expect(TestSubClassAttributes2.some_data).to eq(15)
32
33
  end
34
+
35
+ it 'should let you change a class attribute on the child without affecting the parent' do
36
+ TestClassAttributes.attr2 = 1
37
+ expect(TestSubClassAttributes.attr2).to eq(1)
38
+
39
+ TestSubClassAttributes.attr2 = 2
40
+ expect(TestClassAttributes.attr2).to eq(1)
41
+ expect(TestSubClassAttributes.attr2).to eq(2)
42
+ expect(TestSubClassAttributes2.attr2).to eq(1)
43
+ end
33
44
  end
@@ -3,7 +3,6 @@ require 'spec_helper'
3
3
  describe 'bindings test', type: :feature, sauce: true do
4
4
  it 'should load the page' do
5
5
  visit '/'
6
- sleep 10
7
6
 
8
7
  expect(page).to have_content('Kitchen Sink')
9
8
  end
@@ -21,4 +21,20 @@ describe Volt::ArrayModel do
21
21
  Volt::Computation.flush!
22
22
  expect(count).to eq(2)
23
23
  end
24
+
25
+ it 'should return the index of a model' do
26
+ array_model = Volt::ArrayModel.new([1,2,3])
27
+
28
+ expect(array_model.index(2)).to eq(1)
29
+ end
30
+
31
+ it 'should flatten' do
32
+ array = Volt::ArrayModel.new([])
33
+
34
+ array << Volt::ArrayModel.new([Volt::ArrayModel.new([1,2]), Volt::ArrayModel.new([3])])
35
+ array << Volt::ArrayModel.new([Volt::ArrayModel.new([4,5]), Volt::ArrayModel.new([6])])
36
+
37
+ expect(array.flatten.size).to eq(6)
38
+ expect(array.to_a.flatten.size).to eq(6)
39
+ end
24
40
  end
@@ -6,6 +6,9 @@ class ExampleModelWithField < Volt::Model
6
6
  field :value, Numeric
7
7
  end
8
8
 
9
+ class ExampleModelWithField2 < ExampleModelWithField
10
+ end
11
+
9
12
  describe 'field helpers' do
10
13
  let(:model) { ExampleModelWithField.new }
11
14
  it 'should allow a user to setup a field that can be written to and read' do
@@ -23,7 +26,7 @@ describe 'field helpers' do
23
26
 
24
27
  it 'should raise an error when an invalid cast type is provided' do
25
28
  expect do
26
- ExampleModelWithField.field :awesome, Array
29
+ ExampleModelWithField2.field :awesome, Array
27
30
  end.to raise_error(FieldHelpers::InvalidFieldClass)
28
31
  end
29
32
 
@@ -42,4 +45,8 @@ describe 'field helpers' do
42
45
  expect(error).to eq({})
43
46
  end
44
47
  end
48
+
49
+ it 'should track the fields on the model class' do
50
+ expect(ExampleModelWithField.fields_data).to eq({:name=>[nil, {}], :value=>[Numeric, {}]})
51
+ end
45
52
  end
@@ -46,6 +46,17 @@ class ::TestUpdateReadCheck < Volt::Model
46
46
  end
47
47
  end
48
48
 
49
+ class ::TestPromisePermission < Volt::Model
50
+ attr_reader :called_deny
51
+ permissions(:create) do
52
+ $test_promise = Promise.new
53
+ $test_promise.then do
54
+ @called_deny = true
55
+ deny
56
+ end
57
+ end
58
+ end
59
+
49
60
  describe 'model permissions' do
50
61
  let(:user_todo) { TestUserTodo.new }
51
62
 
@@ -162,5 +173,19 @@ describe 'model permissions' do
162
173
 
163
174
  expect(model.read_check).to eq(nil)
164
175
  end
176
+
177
+ it 'should allow permission blocks to return a promise' do
178
+ promise = store._test_promise_permissions.create({})
179
+
180
+ expect(promise.resolved?).to eq(false)
181
+ expect(promise.rejected?).to eq(false)
182
+ $test_promise.resolve(nil)
183
+
184
+ expect(promise.resolved?).to eq(false)
185
+ expect(promise.rejected?).to eq(true)
186
+ # puts "#{promise.error.inspect}"
187
+ # puts promise.error.backtrace.join("\n")
188
+ expect(promise.error.to_s).to match(/permissions did not allow create for/)
189
+ end
165
190
  end
166
191
  end
data/volt.gemspec CHANGED
@@ -44,7 +44,7 @@ Gem::Specification.new do |spec|
44
44
  spec.add_development_dependency 'capybara', '~> 2.4.2'
45
45
 
46
46
  # There is a big performance issue with selenium-webdriver on v2.45.0
47
- spec.add_development_dependency 'selenium-webdriver', '~> 2.43.0'
47
+ spec.add_development_dependency 'selenium-webdriver', '~> 2.46.2'
48
48
  spec.add_development_dependency 'chromedriver2-helper', '~> 0.0.8'
49
49
  spec.add_development_dependency 'poltergeist', '~> 1.5.0'
50
50
  spec.add_development_dependency 'thin', '~> 1.6.3'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: volt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5.pre3
4
+ version: 0.9.5.pre4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Stout
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-24 00:00:00.000000000 Z
11
+ date: 2015-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -212,14 +212,14 @@ dependencies:
212
212
  requirements:
213
213
  - - "~>"
214
214
  - !ruby/object:Gem::Version
215
- version: 2.43.0
215
+ version: 2.46.2
216
216
  type: :development
217
217
  prerelease: false
218
218
  version_requirements: !ruby/object:Gem::Requirement
219
219
  requirements:
220
220
  - - "~>"
221
221
  - !ruby/object:Gem::Version
222
- version: 2.43.0
222
+ version: 2.46.2
223
223
  - !ruby/object:Gem::Dependency
224
224
  name: chromedriver2-helper
225
225
  requirement: !ruby/object:Gem::Requirement
@@ -374,6 +374,7 @@ files:
374
374
  - app/volt/assets/js/volt_watch.js
375
375
  - app/volt/config/dependencies.rb
376
376
  - app/volt/controllers/notices_controller.rb
377
+ - app/volt/models/active_volt_instance.rb
377
378
  - app/volt/models/user.rb
378
379
  - app/volt/tasks/live_query/live_query.rb
379
380
  - app/volt/tasks/live_query/live_query_pool.rb
@@ -572,7 +573,6 @@ files:
572
573
  - lib/volt/utils/logging/task_logger.rb
573
574
  - lib/volt/utils/modes.rb
574
575
  - lib/volt/utils/parsing.rb
575
- - lib/volt/utils/promise.rb
576
576
  - lib/volt/utils/promise_extensions.rb
577
577
  - lib/volt/utils/read_write_lock.rb
578
578
  - lib/volt/utils/set_patch.rb
@@ -1,429 +0,0 @@
1
- # A copy of the opal 0.8 promise library. The one in 0.7.x has some bugs.
2
-
3
- # {Promise} is used to help structure asynchronous code.
4
- #
5
- # It is available in the Opal standard library, and can be required in any Opal
6
- # application:
7
- #
8
- # require 'promise'
9
- #
10
- # ## Basic Usage
11
- #
12
- # Promises are created and returned as objects with the assumption that they
13
- # will eventually be resolved or rejected, but never both. A {Promise} has
14
- # a {#then} and {#fail} method (or one of their aliases) that can be used to
15
- # register a block that gets called once resolved or rejected.
16
- #
17
- # promise = Promise.new
18
- #
19
- # promise.then {
20
- # puts "resolved!"
21
- # }.fail {
22
- # puts "rejected!"
23
- # }
24
- #
25
- # # some time later
26
- # promise.resolve
27
- #
28
- # # => "resolved!"
29
- #
30
- # It is important to remember that a promise can only be resolved or rejected
31
- # once, so the block will only ever be called once (or not at all).
32
- #
33
- # ## Resolving Promises
34
- #
35
- # To resolve a promise, means to inform the {Promise} that it has succeeded
36
- # or evaluated to a useful value. {#resolve} can be passed a value which is
37
- # then passed into the block handler:
38
- #
39
- # def get_json
40
- # promise = Promise.new
41
- #
42
- # HTTP.get("some_url") do |req|
43
- # promise.resolve req.json
44
- # end
45
- #
46
- # promise
47
- # end
48
- #
49
- # get_json.then do |json|
50
- # puts "got some JSON from server"
51
- # end
52
- #
53
- # ## Rejecting Promises
54
- #
55
- # Promises are also designed to handle error cases, or situations where an
56
- # outcome is not as expected. Taking the previous example, we can also pass
57
- # a value to a {#reject} call, which passes that object to the registered
58
- # {#fail} handler:
59
- #
60
- # def get_json
61
- # promise = Promise.new
62
- #
63
- # HTTP.get("some_url") do |req|
64
- # if req.ok?
65
- # promise.resolve req.json
66
- # else
67
- # promise.reject req
68
- # end
69
- #
70
- # promise
71
- # end
72
- #
73
- # get_json.then {
74
- # # ...
75
- # }.fail { |req|
76
- # puts "it went wrong: #{req.message}"
77
- # }
78
- #
79
- # ## Chaining Promises
80
- #
81
- # Promises become even more useful when chained together. Each {#then} or
82
- # {#fail} call returns a new {Promise} which can be used to chain more and more
83
- # handlers together.
84
- #
85
- # promise.then { wait_for_something }.then { do_something_else }
86
- #
87
- # Rejections are propagated through the entire chain, so a "catch all" handler
88
- # can be attached at the end of the tail:
89
- #
90
- # promise.then { ... }.then { ... }.fail { ... }
91
- #
92
- # ## Composing Promises
93
- #
94
- # {Promise.when} can be used to wait for more than one promise to resolve (or
95
- # reject). Using the previous example, we could request two different json
96
- # requests and wait for both to finish:
97
- #
98
- # Promise.when(get_json, get_json2).then |first, second|
99
- # puts "got two json payloads: #{first}, #{second}"
100
- # end
101
- #
102
- class Promise
103
- def self.value(value)
104
- new.resolve(value)
105
- end
106
-
107
- def self.error(value)
108
- new.reject(value)
109
- end
110
-
111
- def self.when(*promises)
112
- When.new(promises)
113
- end
114
-
115
- attr_reader :error, :prev, :next
116
-
117
- def initialize(action = {})
118
- @action = action
119
-
120
- @realized = false
121
- @exception = false
122
- @value = nil
123
- @error = nil
124
- @delayed = false
125
-
126
- @prev = nil
127
- @next = nil
128
- end
129
-
130
- def value
131
- if Promise === @value
132
- @value.value
133
- else
134
- @value
135
- end
136
- end
137
-
138
- def act?
139
- @action.has_key?(:success) || @action.has_key?(:always)
140
- end
141
-
142
- def action
143
- @action.keys
144
- end
145
-
146
- def exception?
147
- @exception
148
- end
149
-
150
- def realized?
151
- !!@realized
152
- end
153
-
154
- def resolved?
155
- @realized == :resolve
156
- end
157
-
158
- def rejected?
159
- @realized == :reject
160
- end
161
-
162
- def ^(promise)
163
- promise << self
164
- self >> promise
165
-
166
- promise
167
- end
168
-
169
- def <<(promise)
170
- @prev = promise
171
-
172
- self
173
- end
174
-
175
- def >>(promise)
176
- @next = promise
177
-
178
- if exception?
179
- promise.reject(@delayed[0])
180
- elsif resolved?
181
- promise.resolve(@delayed ? @delayed[0] : value)
182
- elsif rejected?
183
- if !@action.has_key?(:failure) || Promise === (@delayed ? @delayed[0] : @error)
184
- promise.reject(@delayed ? @delayed[0] : error)
185
- elsif promise.action.include?(:always)
186
- promise.reject(@delayed ? @delayed[0] : error)
187
- end
188
- end
189
-
190
- self
191
- end
192
-
193
- def resolve(value = nil)
194
- if realized?
195
- raise ArgumentError, 'the promise has already been realized'
196
- end
197
-
198
- if Promise === value
199
- return (value << @prev) ^ self
200
- end
201
-
202
- begin
203
- if block = @action[:success] || @action[:always]
204
- value = block.call(value)
205
- end
206
-
207
- resolve!(value)
208
- rescue Exception => e
209
- exception!(e)
210
- end
211
-
212
- self
213
- end
214
-
215
- def resolve!(value)
216
- @realized = :resolve
217
- @value = value
218
-
219
- if @next
220
- @next.resolve(value)
221
- else
222
- @delayed = [value]
223
- end
224
- end
225
-
226
- def reject(value = nil)
227
- if realized?
228
- raise ArgumentError, 'the promise has already been realized'
229
- end
230
-
231
- if Promise === value
232
- return (value << @prev) ^ self
233
- end
234
-
235
- begin
236
- if block = @action[:failure] || @action[:always]
237
- value = block.call(value)
238
- end
239
-
240
- if @action.has_key?(:always)
241
- resolve!(value)
242
- else
243
- reject!(value)
244
- end
245
- rescue Exception => e
246
- exception!(e)
247
- end
248
-
249
- self
250
- end
251
-
252
- def reject!(value)
253
- @realized = :reject
254
- @error = value
255
-
256
- if @next
257
- @next.reject(value)
258
- else
259
- @delayed = [value]
260
- end
261
- end
262
-
263
- def exception!(error)
264
- @exception = true
265
-
266
- reject!(error)
267
- end
268
-
269
- def then(&block)
270
- if @next
271
- raise ArgumentError, 'a promise has already been chained'
272
- end
273
-
274
- self ^ Promise.new(success: block)
275
- end
276
-
277
- alias do then
278
-
279
- def fail(&block)
280
- if @next
281
- raise ArgumentError, 'a promise has already been chained'
282
- end
283
-
284
- self ^ Promise.new(failure: block)
285
- end
286
-
287
- alias rescue fail
288
- alias catch fail
289
-
290
- def always(&block)
291
- if @next
292
- raise ArgumentError, 'a promise has already been chained'
293
- end
294
-
295
- self ^ Promise.new(always: block)
296
- end
297
-
298
- alias finally always
299
- alias ensure always
300
-
301
- def trace(depth = nil, &block)
302
- if @next
303
- raise ArgumentError, 'a promise has already been chained'
304
- end
305
-
306
- self ^ Trace.new(depth, block)
307
- end
308
-
309
- def inspect
310
- result = "#<#{self.class}(#{object_id})"
311
-
312
- if @next
313
- result += " >> #{@next.inspect}"
314
- end
315
-
316
- if realized?
317
- result += ": #{(@value || @error).inspect}>"
318
- else
319
- result += ">"
320
- end
321
-
322
- result
323
- end
324
-
325
- class Trace < self
326
- def self.it(promise)
327
- current = []
328
-
329
- if promise.act? || promise.prev.nil?
330
- current.push(promise.value)
331
- end
332
-
333
- if prev = promise.prev
334
- current.concat(it(prev))
335
- else
336
- current
337
- end
338
- end
339
-
340
- def initialize(depth, block)
341
- @depth = depth
342
-
343
- super success: -> {
344
- trace = Trace.it(self).reverse
345
- trace.pop
346
-
347
- if depth && depth <= trace.length
348
- trace.shift(trace.length - depth)
349
- end
350
-
351
- block.call(*trace)
352
- }
353
- end
354
- end
355
-
356
- class When < self
357
- def initialize(promises = [])
358
- super()
359
-
360
- @wait = []
361
-
362
- promises.each {|promise|
363
- wait promise
364
- }
365
- end
366
-
367
- def each(&block)
368
- raise ArgumentError, 'no block given' unless block
369
-
370
- self.then {|values|
371
- values.each(&block)
372
- }
373
- end
374
-
375
- def collect(&block)
376
- raise ArgumentError, 'no block given' unless block
377
-
378
- self.then {|values|
379
- When.new(values.map(&block))
380
- }
381
- end
382
-
383
- def inject(*args, &block)
384
- self.then {|values|
385
- values.reduce(*args, &block)
386
- }
387
- end
388
-
389
- alias map collect
390
-
391
- alias reduce inject
392
-
393
- def wait(promise)
394
- unless Promise === promise
395
- promise = Promise.value(promise)
396
- end
397
-
398
- if promise.act?
399
- promise = promise.then
400
- end
401
-
402
- @wait << promise
403
-
404
- promise.always {
405
- try if @next
406
- }
407
-
408
- self
409
- end
410
-
411
- alias and wait
412
-
413
- def >>(*)
414
- super.tap {
415
- try
416
- }
417
- end
418
-
419
- def try
420
- if @wait.all?(&:realized?)
421
- if promise = @wait.find(&:rejected?)
422
- reject(promise.error)
423
- else
424
- resolve(@wait.map(&:value))
425
- end
426
- end
427
- end
428
- end
429
- end