volt 0.9.3.pre2 → 0.9.3.pre3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/app/volt/tasks/query_tasks.rb +0 -7
- data/app/volt/tasks/store_tasks.rb +0 -6
- data/docs/UPGRADE_GUIDE.md +2 -0
- data/lib/volt/cli/asset_compile.rb +2 -2
- data/lib/volt/cli/console.rb +21 -0
- data/lib/volt/config.rb +0 -10
- data/lib/volt/controllers/collection_helpers.rb +18 -0
- data/lib/volt/controllers/model_controller.rb +2 -12
- data/lib/volt/extra_core/object.rb +19 -0
- data/lib/volt/models.rb +14 -9
- data/lib/volt/models/array_model.rb +62 -22
- data/lib/volt/models/associations.rb +16 -1
- data/lib/volt/models/model.rb +27 -15
- data/lib/volt/models/model_helpers/model_helpers.rb +29 -0
- data/lib/volt/models/permissions.rb +15 -4
- data/lib/volt/models/persistors/array_store.rb +40 -0
- data/lib/volt/models/persistors/model_store.rb +2 -2
- data/lib/volt/models/persistors/query/query_listener.rb +3 -1
- data/lib/volt/models/persistors/store.rb +2 -1
- data/lib/volt/models/root_models/root_models.rb +31 -0
- data/lib/volt/models/root_models/store_root.rb +36 -0
- data/lib/volt/models/validators/unique_validator.rb +1 -1
- data/lib/volt/page/bindings/each_binding.rb +56 -47
- data/lib/volt/page/page.rb +5 -5
- data/lib/volt/reactive/reactive_array.rb +9 -6
- data/lib/volt/server.rb +2 -2
- data/lib/volt/server/component_templates.rb +7 -4
- data/lib/volt/server/message_bus/message_encoder.rb +9 -1
- data/lib/volt/server/rack/component_code.rb +8 -1
- data/lib/volt/server/rack/index_files.rb +5 -2
- data/lib/volt/tasks/{task_handler.rb → task.rb} +6 -6
- data/lib/volt/utils/promise.rb +429 -0
- data/lib/volt/utils/promise_extensions.rb +79 -0
- data/lib/volt/version.rb +1 -1
- data/lib/volt/volt/app.rb +5 -2
- data/lib/volt/volt/server_setup/app.rb +28 -7
- data/spec/apps/kitchen_sink/app/main/controllers/server/simple_http_controller.rb +1 -1
- data/spec/apps/kitchen_sink/app/main/views/main/store.html +3 -0
- data/spec/extra_core/object_spec.rb +13 -0
- data/spec/integration/store_spec.rb +10 -0
- data/spec/models/associations_spec.rb +48 -26
- data/spec/models/model_spec.rb +23 -7
- data/spec/models/persistors/store_spec.rb +28 -0
- data/spec/models/validators/unique_validator_spec.rb +1 -1
- data/spec/spec_helper.rb +4 -1
- data/spec/utils/promise_extensions_spec.rb +42 -0
- data/templates/component/config/initializers/boot.rb +10 -0
- data/templates/{project/app → component/config/initializers/client}/.empty_directory +0 -0
- data/templates/component/config/initializers/server/.empty_directory +0 -0
- data/templates/newgem/app/newgem/config/initializers/client/.empty_directory +0 -0
- data/templates/newgem/app/newgem/config/initializers/server/.empty_directory +0 -0
- data/templates/project/Gemfile.tt +6 -2
- data/templates/project/app/main/config/initializers/boot.rb +10 -0
- data/templates/project/app/main/config/initializers/client/.empty_directory +0 -0
- data/templates/project/app/main/config/initializers/server/.empty_directory +0 -0
- data/templates/project/config/app.rb.tt +3 -0
- data/templates/project/config/initializers/client/.empty_directory +0 -0
- data/templates/project/config/initializers/server/.empty_directory +0 -0
- metadata +22 -5
- data/lib/volt/utils/promise_patch.rb +0 -70
data/lib/volt/server.rb
CHANGED
@@ -10,7 +10,7 @@ require 'sprockets-sass'
|
|
10
10
|
|
11
11
|
require 'volt'
|
12
12
|
require 'volt/tasks/dispatcher'
|
13
|
-
require 'volt/tasks/
|
13
|
+
require 'volt/tasks/task'
|
14
14
|
require 'volt/server/component_handler'
|
15
15
|
require 'volt/server/rack/component_paths'
|
16
16
|
require 'volt/server/rack/index_files'
|
@@ -133,7 +133,7 @@ module Volt
|
|
133
133
|
|
134
134
|
# Serve the main html files from public, also figure out
|
135
135
|
# which JS/CSS files to serve.
|
136
|
-
@rack_app.use IndexFiles, @volt_app.component_paths, opal_files
|
136
|
+
@rack_app.use IndexFiles, @volt_app, @volt_app.component_paths, opal_files
|
137
137
|
|
138
138
|
@rack_app.use HttpResource, @volt_app, @volt_app.router
|
139
139
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'volt/server/html_parser/view_parser'
|
2
|
-
require 'volt/tasks/
|
2
|
+
require 'volt/tasks/task'
|
3
3
|
|
4
4
|
# Initialize with the path to a component and returns all the front-end
|
5
5
|
# setup code (for controllers, models, views, and routes)
|
@@ -91,7 +91,7 @@ module Volt
|
|
91
91
|
|
92
92
|
file_contents = File.read(view_path)
|
93
93
|
|
94
|
-
template_calls = []
|
94
|
+
# template_calls = []
|
95
95
|
|
96
96
|
# Process template if we have a handler for this file type
|
97
97
|
if handler = ComponentTemplates.handler_for_extension(format)
|
@@ -112,7 +112,7 @@ module Volt
|
|
112
112
|
binding_code = "{#{binding_code.join(', ')}}"
|
113
113
|
|
114
114
|
code << "#{page_reference}.add_template(#{name.inspect}, #{template['html'].inspect}, #{binding_code})\n"
|
115
|
-
template_calls << "template(#{name.inspect}, #{template['html'].inspect}, #{binding_code})"
|
115
|
+
# template_calls << "template(#{name.inspect}, #{template['html'].inspect}, #{binding_code})"
|
116
116
|
end
|
117
117
|
end
|
118
118
|
|
@@ -200,7 +200,10 @@ module Volt
|
|
200
200
|
end
|
201
201
|
|
202
202
|
def generate_initializers_code
|
203
|
-
"\nrequire_tree '#{@component_path}/config/initializers/'\n"
|
203
|
+
code = "\nrequire_tree '#{@component_path}/config/initializers/'\n"
|
204
|
+
code << "require_tree '#{@component_path}/config/initializers/client'\n"
|
205
|
+
|
206
|
+
code
|
204
207
|
end
|
205
208
|
|
206
209
|
end
|
@@ -5,8 +5,16 @@ module Volt
|
|
5
5
|
class MessageEncoder
|
6
6
|
attr_reader :encrypted
|
7
7
|
def initialize
|
8
|
+
# rbnacl is not supported on windows.
|
9
|
+
windows = Gem.win_platform?
|
10
|
+
|
11
|
+
if windows
|
12
|
+
Volt.logger.warn('Currently Message Bus encryption is not supported on windows.')
|
13
|
+
end
|
14
|
+
|
8
15
|
# Message bus is encrypted by default
|
9
|
-
|
16
|
+
disable = Volt.config.message_bus.try(:disable_encryption)
|
17
|
+
@encrypted = !windows && (disable != true)
|
10
18
|
|
11
19
|
if @encrypted
|
12
20
|
# Setup a RbNaCl simple box for handling encryption
|
@@ -27,7 +27,14 @@ module Volt
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def generate_config_code
|
30
|
-
|
30
|
+
# Setup Volt.config on the client
|
31
|
+
code = "\nVolt.setup_client_config(#{Volt.config.public.to_h.inspect})\n"
|
32
|
+
|
33
|
+
# Include the root initializers
|
34
|
+
code << "require_tree '#{Volt.root}/config/initializers'\n"
|
35
|
+
code << "require_tree '#{Volt.root}/config/initializers/client'\n"
|
36
|
+
|
37
|
+
code
|
31
38
|
end
|
32
39
|
end
|
33
40
|
end
|
@@ -4,12 +4,15 @@ require 'volt/router/routes'
|
|
4
4
|
# Serves the main pages
|
5
5
|
module Volt
|
6
6
|
class IndexFiles
|
7
|
-
def initialize(app, component_paths, opal_files)
|
7
|
+
def initialize(app, volt_app, component_paths, opal_files)
|
8
8
|
@app = app
|
9
|
+
@volt_app = volt_app
|
9
10
|
@component_paths = component_paths
|
10
11
|
@opal_files = opal_files
|
11
12
|
|
12
|
-
@@router
|
13
|
+
@@router = volt_app.router
|
14
|
+
|
15
|
+
@@router.define do
|
13
16
|
# Load routes for each component
|
14
17
|
component_paths.components.values.flatten.uniq.each do |component_path|
|
15
18
|
routes_path = "#{component_path}/config/routes.rb"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'volt/controllers/collection_helpers'
|
2
|
+
|
1
3
|
module Volt
|
2
4
|
class Task
|
3
5
|
if RUBY_PLATFORM == 'opal'
|
@@ -14,8 +16,11 @@ module Volt
|
|
14
16
|
$page.tasks.call(self.name, name, meta_data, *args, &block)
|
15
17
|
end
|
16
18
|
else
|
19
|
+
include CollectionHelpers
|
20
|
+
|
17
21
|
def initialize(volt_app, channel = nil, dispatcher = nil)
|
18
|
-
@volt_app
|
22
|
+
@volt_app = volt_app
|
23
|
+
@page = volt_app.page
|
19
24
|
@channel = channel
|
20
25
|
@dispatcher = dispatcher
|
21
26
|
end
|
@@ -39,11 +44,6 @@ module Volt
|
|
39
44
|
new(Volt.current_app, nil, nil).send(name, *args, &block)
|
40
45
|
end.resolve(nil)
|
41
46
|
end
|
42
|
-
|
43
|
-
# Provide access to the store collection
|
44
|
-
def store
|
45
|
-
$page.store
|
46
|
-
end
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -0,0 +1,429 @@
|
|
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
|