ocean-rails 3.8.8 → 3.8.9
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 +4 -4
- data/lib/ocean/api.rb +103 -50
- data/lib/ocean/api_remote_resource.rb +20 -19
- data/lib/ocean/continuation_experiments.rb +139 -0
- data/lib/ocean/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25d86f8d69015565033c12e60edb7017186d6829
|
4
|
+
data.tar.gz: 83a3f9b85153a9708225aa5ab46ad58e5b7837fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7540bf449eb3e0d3aa5755f2fa75fd9ed22b8e74f6fd7409908a4836bd6f3e858e4f82cadbeb50a6236fe50d17d39cc891b9a87068347d14201e7ba8b084a1e
|
7
|
+
data.tar.gz: 00618f27d71e1446ac3f1135757c8944a0b8dd69873d5978166f6d058b6694e47173892ccbbf22bd4104511dc1afc4b41d5a8542e9d3acff1cf783c732b24448
|
data/lib/ocean/api.rb
CHANGED
@@ -172,7 +172,8 @@ class Api
|
|
172
172
|
reauthentication: true,
|
173
173
|
ssl_verifypeer: true, ssl_verifyhost: 2,
|
174
174
|
retries: 0, backoff_time: 1, backoff_rate: 0.9, backoff_max: 30,
|
175
|
-
x_metadata: Thread.current[:metadata]
|
175
|
+
x_metadata: Thread.current[:metadata],
|
176
|
+
&block)
|
176
177
|
# Set up the request
|
177
178
|
headers['Accept'] = "application/json"
|
178
179
|
headers['Content-Type'] = "application/json" if [:post, :put].include?(http_method)
|
@@ -181,63 +182,109 @@ class Api
|
|
181
182
|
headers['X-API-Token'] = x_api_token if x_api_token.present?
|
182
183
|
headers['X-Metadata'] = x_metadata if x_metadata.present?
|
183
184
|
|
184
|
-
response = nil
|
185
185
|
tries_done = 0
|
186
186
|
max_tries = [:get, "GET", "get"].include?(http_method) ? retries + 1 : 1
|
187
|
-
while (true) do
|
188
|
-
tries_done += 1
|
189
|
-
last_try = tries_done >= max_tries
|
190
|
-
|
191
|
-
while (true) do
|
192
|
-
request = Typhoeus::Request.new(url,
|
193
|
-
method: http_method,
|
194
|
-
headers: headers,
|
195
|
-
params: args,
|
196
|
-
body: body,
|
197
|
-
ssl_verifypeer: ssl_verifypeer,
|
198
|
-
ssl_verifyhost: ssl_verifyhost)
|
199
|
-
# Run it
|
200
|
-
response = Response.new(request.run)
|
201
|
-
# If successful, return
|
202
|
-
return response if response.success?
|
203
|
-
|
204
|
-
# Not successful, deal with it
|
205
|
-
if last_try
|
206
|
-
raise Api::TimeoutError, "Api.request timed out" if response.timed_out?
|
207
|
-
raise Api::NoResponseError, "Api.request could not obtain a response" if response.status == 0
|
208
|
-
else
|
209
|
-
break if response.timed_out?
|
210
|
-
break if response.status == 0
|
211
|
-
end
|
212
187
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
188
|
+
@hydra ||= Typhoeus::Hydra.hydra
|
189
|
+
request = nil # For clarity
|
190
|
+
response = nil
|
191
|
+
|
192
|
+
# This is a Proc when run queues the request and schedules retries
|
193
|
+
enqueue_request = Proc.new do
|
194
|
+
# First construct a request. It will not be sent yet.
|
195
|
+
request = Typhoeus::Request.new(url,
|
196
|
+
method: http_method,
|
197
|
+
headers: headers,
|
198
|
+
params: args,
|
199
|
+
body: body,
|
200
|
+
ssl_verifypeer: ssl_verifypeer,
|
201
|
+
ssl_verifyhost: ssl_verifyhost)
|
202
|
+
|
203
|
+
# Define a callback to process the response and do retries
|
204
|
+
request.on_complete do |typhoeus_response|
|
205
|
+
response = Response.new(typhoeus_response)
|
206
|
+
case response.status
|
207
|
+
when 100..199
|
208
|
+
enqueue_request.call # Ignore and retry
|
209
|
+
when 200..299, 304
|
210
|
+
# Success, call the post-processor if any
|
211
|
+
if block
|
212
|
+
response = block.call response
|
222
213
|
end
|
223
|
-
|
224
|
-
|
225
|
-
|
214
|
+
when 300..399
|
215
|
+
nil # Done, redirect
|
216
|
+
when 400, 419
|
217
|
+
if reauthentication && x_api_token.present?
|
218
|
+
# Re-authenticate and retry
|
219
|
+
if credentials
|
220
|
+
x_api_token = Api.authenticate(*Api.decode_credentials(credentials))
|
221
|
+
headers['X-API-Token'] = x_api_token
|
222
|
+
else
|
223
|
+
Api.reset_service_token
|
224
|
+
headers['X-API-Token'] = Api.service_token
|
225
|
+
end
|
226
|
+
reauthentication = false # This prevents us from ending up here twice
|
227
|
+
enqueue_request.call
|
228
|
+
else
|
229
|
+
nil # Done, fail
|
230
|
+
end
|
231
|
+
when 400..499
|
232
|
+
nil # Done, fail
|
226
233
|
else
|
227
|
-
# Retry
|
228
|
-
|
234
|
+
# Retry if there are any retries left
|
235
|
+
if retries > 0
|
236
|
+
retries -= 1
|
237
|
+
sleep backoff_time
|
238
|
+
backoff_time = [backoff_time + backoff_time * backoff_rate, 30].min
|
239
|
+
enqueue_request.call
|
240
|
+
else
|
241
|
+
nil # Done, don't retry
|
242
|
+
end
|
229
243
|
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Finally, queue the request (and its callback) for execution
|
247
|
+
@hydra.queue request
|
248
|
+
# Return nil, to emphasise that the side effects are what's important
|
249
|
+
nil
|
250
|
+
end
|
230
251
|
|
252
|
+
# So create and enqueue the request
|
253
|
+
enqueue_request.call
|
254
|
+
# Run it, unless we're accumulating calls inside an Api.simultaneously block
|
255
|
+
unless @inside_simultaneously
|
256
|
+
# The next line blocks until completed, possibly after several retries
|
257
|
+
@hydra.run
|
258
|
+
if response.is_a?(Response)
|
259
|
+
# Raise any exceptions
|
260
|
+
raise Api::TimeoutError, "Api.request timed out" if response.timed_out?
|
261
|
+
raise Api::NoResponseError, "Api.request could not obtain a response" if response.status == 0
|
231
262
|
end
|
232
|
-
|
233
|
-
break if last_try
|
234
|
-
sleep backoff_time
|
235
|
-
seconds = [backoff_time + backoff_time * backoff_rate, 30].min
|
236
|
-
backoff_time = seconds
|
263
|
+
return response
|
237
264
|
end
|
238
|
-
# Return
|
239
|
-
|
240
|
-
end
|
265
|
+
# Return nil: we have no response yet
|
266
|
+
nil
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
def self.simultaneously (&block)
|
271
|
+
raise "block required" unless block
|
272
|
+
@inside_simultaneously = true
|
273
|
+
@hydra = nil
|
274
|
+
block.call
|
275
|
+
ensure
|
276
|
+
@inside_simultaneously = false
|
277
|
+
end
|
278
|
+
|
279
|
+
|
280
|
+
def self.simultaneously?
|
281
|
+
@inside_simultaneously ||= false
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
# http://liufengyun.chaos-lab.com/prog/2013/10/23/continuation-in-ruby.html
|
286
|
+
# http://gnuu.org/2009/03/21/demystifying-continuations-in-ruby/
|
287
|
+
# http://www.ruby-doc.org/core-2.1.3/Continuation.html
|
241
288
|
|
242
289
|
|
243
290
|
class TimeoutError < StandardError; end
|
@@ -556,6 +603,7 @@ class Api
|
|
556
603
|
h
|
557
604
|
end
|
558
605
|
|
606
|
+
|
559
607
|
#
|
560
608
|
# Takes the same args as +.async_job_body+, post an +AsyncJob+ and returns the +Response+.
|
561
609
|
# The +AsyncJob+ is always created as the service +ApiUser+; the job carries its own
|
@@ -564,8 +612,13 @@ class Api
|
|
564
612
|
# +:job+ as the only parameter.
|
565
613
|
#
|
566
614
|
# A block may be given. It will be called with any +TimeoutError+ or +NoResponseError+,
|
567
|
-
# which allows +Api.run_async_job+ to be used very tersely in controllers.
|
615
|
+
# which allows +Api.run_async_job+ to be used very tersely in controllers, e.g.:
|
568
616
|
#
|
617
|
+
# Api.run_async_job(...) do |e|
|
618
|
+
# render_api_error 422, e.message
|
619
|
+
# return
|
620
|
+
# end
|
621
|
+
#
|
569
622
|
def self.run_async_job(href=nil, method=nil, job: nil, **keywords, &block)
|
570
623
|
job ||= async_job_body(href, method, **keywords)
|
571
624
|
Api.request "#{INTERNAL_OCEAN_API_URL}/v1/async_jobs", :post,
|
@@ -271,7 +271,7 @@ class Api
|
|
271
271
|
# Instance method to GET a resource or any of its hyperlinks. Will raise exceptions
|
272
272
|
# if they occur, otherwise will return the resource itself.
|
273
273
|
#
|
274
|
-
def get!(hlink=nil)
|
274
|
+
def get!(hlink=nil, args: nil)
|
275
275
|
RemoteResource._retrieve self unless present?
|
276
276
|
hlink = hlink.to_s if hlink
|
277
277
|
if !hlink || hlink == 'self'
|
@@ -305,7 +305,7 @@ class Api
|
|
305
305
|
# Instance method to do a PUT to a resource or any of its hyperlinks. Will raise exceptions
|
306
306
|
# if they occur, otherwise will return the resource itself.
|
307
307
|
#
|
308
|
-
def put!(hlink=nil, body: {})
|
308
|
+
def put!(hlink=nil, args: nil, body: {})
|
309
309
|
get!
|
310
310
|
hlink = hlink.to_s if hlink
|
311
311
|
if !hlink || hlink == 'self'
|
@@ -315,7 +315,7 @@ class Api
|
|
315
315
|
hl_data = hyperlink[hlink]
|
316
316
|
raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data
|
317
317
|
hl_res = RemoteResource.new(hl_data['href'])
|
318
|
-
hl_res.send :_modify, body
|
318
|
+
hl_res.send :_modify, body, args: args
|
319
319
|
hl_res
|
320
320
|
end
|
321
321
|
end
|
@@ -325,7 +325,7 @@ class Api
|
|
325
325
|
# exceptions if they occur, but will always return the resource itself.
|
326
326
|
# A missing hyperlink, though, will always raise a HyperlinkMissing exception.
|
327
327
|
#
|
328
|
-
def put(hlink=nil, body: {})
|
328
|
+
def put(hlink=nil, args: nil, body: {})
|
329
329
|
get
|
330
330
|
hlink = hlink.to_s if hlink
|
331
331
|
if !hlink || hlink == 'self'
|
@@ -335,7 +335,7 @@ class Api
|
|
335
335
|
hl_data = hyperlink[hlink]
|
336
336
|
raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data
|
337
337
|
hl_res = RemoteResource.new(hl_data['href'])
|
338
|
-
hl_res.send :_modify, body
|
338
|
+
hl_res.send :_modify, body, args: args
|
339
339
|
hl_res
|
340
340
|
end
|
341
341
|
end
|
@@ -345,12 +345,12 @@ class Api
|
|
345
345
|
# Instance method to do a POST to a resource or any of its hyperlinks. Will raise exceptions
|
346
346
|
# if they occur, otherwise will return the resource itself.
|
347
347
|
#
|
348
|
-
def post!(hlink=nil, body: {})
|
348
|
+
def post!(hlink=nil, args: nil, body: {})
|
349
349
|
get!
|
350
350
|
hlink = (hlink || 'self').to_s
|
351
351
|
hl_data = hyperlink[hlink]
|
352
352
|
raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data
|
353
|
-
_create(hl_data['href'], body)
|
353
|
+
_create(hl_data['href'], body, args: args)
|
354
354
|
end
|
355
355
|
|
356
356
|
#
|
@@ -358,12 +358,12 @@ class Api
|
|
358
358
|
# exceptions if they occur, but will always return the resource itself.
|
359
359
|
# A missing hyperlink, though, will always raise a HyperlinkMissing exception.
|
360
360
|
#
|
361
|
-
def post(hlink=nil, body: {})
|
361
|
+
def post(hlink=nil, args: nil, body: {})
|
362
362
|
get
|
363
363
|
hlink = (hlink || 'self').to_s
|
364
364
|
hl_data = hyperlink[hlink]
|
365
365
|
raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data
|
366
|
-
_create(hl_data['href'], body) rescue nil
|
366
|
+
_create(hl_data['href'], body, args: args) rescue nil
|
367
367
|
end
|
368
368
|
|
369
369
|
|
@@ -371,12 +371,12 @@ class Api
|
|
371
371
|
# Instance method to do a DELETE to a resource or any of its hyperlinks. Will raise exceptions
|
372
372
|
# if they occur, otherwise will return the resource itself.
|
373
373
|
#
|
374
|
-
def delete!(hlink=nil)
|
374
|
+
def delete!(hlink=nil, args: nil)
|
375
375
|
get!
|
376
376
|
hlink = (hlink || 'self').to_s
|
377
377
|
hl_data = hyperlink[hlink]
|
378
378
|
raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data
|
379
|
-
_destroy(hl_data['href'])
|
379
|
+
_destroy(hl_data['href'], args: args)
|
380
380
|
self
|
381
381
|
end
|
382
382
|
|
@@ -385,12 +385,12 @@ class Api
|
|
385
385
|
# exceptions if they occur, but will always return the resource itself.
|
386
386
|
# A missing hyperlink, though, will always raise a HyperlinkMissing exception.
|
387
387
|
#
|
388
|
-
def delete(hlink=nil)
|
388
|
+
def delete(hlink=nil, args: nil)
|
389
389
|
get
|
390
390
|
hlink = (hlink || 'self').to_s
|
391
391
|
hl_data = hyperlink[hlink]
|
392
392
|
raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data
|
393
|
-
_destroy(hl_data['href']) rescue nil
|
393
|
+
_destroy(hl_data['href'], args: args) rescue nil
|
394
394
|
self
|
395
395
|
end
|
396
396
|
|
@@ -466,6 +466,7 @@ class Api
|
|
466
466
|
rr
|
467
467
|
end
|
468
468
|
|
469
|
+
|
469
470
|
def _conditional_get
|
470
471
|
credentials, token = RemoteResource._credentials(self)
|
471
472
|
response = Api.request Api.internalize_uri(uri), :get,
|
@@ -515,12 +516,12 @@ class Api
|
|
515
516
|
end
|
516
517
|
|
517
518
|
|
518
|
-
def _modify(body)
|
519
|
+
def _modify(body, args: nil)
|
519
520
|
credentials, token = RemoteResource._credentials(self)
|
520
521
|
response = Api.request Api.internalize_uri(uri), :put, headers: {}, body: body.to_json,
|
521
522
|
credentials: credentials, x_api_token: token,
|
522
523
|
retries: retries, backoff_time: backoff_time, backoff_rate: backoff_rate,
|
523
|
-
backoff_max: backoff_max
|
524
|
+
backoff_max: backoff_max, args: args
|
524
525
|
self.response = response
|
525
526
|
self.status = response.status
|
526
527
|
self.status_message = response.message
|
@@ -540,12 +541,12 @@ class Api
|
|
540
541
|
end
|
541
542
|
|
542
543
|
|
543
|
-
def _create(post_uri, body)
|
544
|
+
def _create(post_uri, body, args: nil)
|
544
545
|
credentials, token = RemoteResource._credentials(self)
|
545
546
|
response = Api.request Api.internalize_uri(post_uri), :post, headers: {}, body: body.to_json,
|
546
547
|
credentials: credentials, x_api_token: token,
|
547
548
|
retries: retries, backoff_time: backoff_time, backoff_rate: backoff_rate,
|
548
|
-
backoff_max: backoff_max
|
549
|
+
backoff_max: backoff_max, args: args
|
549
550
|
self.response = response
|
550
551
|
self.status = response.status
|
551
552
|
self.status_message = response.message
|
@@ -564,12 +565,12 @@ class Api
|
|
564
565
|
end
|
565
566
|
|
566
567
|
|
567
|
-
def _destroy(delete_uri)
|
568
|
+
def _destroy(delete_uri, args: nil)
|
568
569
|
credentials, token = RemoteResource._credentials(self)
|
569
570
|
response = Api.request Api.internalize_uri(delete_uri), :delete, headers: {},
|
570
571
|
credentials: credentials, x_api_token: token,
|
571
572
|
retries: retries, backoff_time: backoff_time, backoff_rate: backoff_rate,
|
572
|
-
backoff_max: backoff_max
|
573
|
+
backoff_max: backoff_max, args: args
|
573
574
|
self.response = response
|
574
575
|
self.status = response.status
|
575
576
|
self.status_message = response.message
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'continuation'
|
2
|
+
|
3
|
+
# Api.simultaneously takes a block. It executes the block straight away.
|
4
|
+
#
|
5
|
+
# When executing inside an Api.simultaneously block, Api.request only enqueues its request,
|
6
|
+
# but doesn't run it. They register on_complete handlers that will be run asynchronously
|
7
|
+
# when Api.simultaneously fires hydra to run after the block.
|
8
|
+
#
|
9
|
+
# When Api.request runs outside Api.simultaneously, it simply returns an Api::Response.
|
10
|
+
# When running inside Api.simultaneously, however, Api.request creates a continuation
|
11
|
+
# and registers it with Api.simultaneously. After the block has run, Api.simultaneously
|
12
|
+
# invokes each continuation in turn with another continuation to allow the next
|
13
|
+
# continuation to be called. When there are no more continuations to process,
|
14
|
+
# Api.simultaneously returns normally. In this way, all continuations are executed serially
|
15
|
+
# to process the Api.request results, no matter who called them or from where.
|
16
|
+
|
17
|
+
class Quux
|
18
|
+
|
19
|
+
require 'continuation'
|
20
|
+
|
21
|
+
|
22
|
+
def self.simultaneously?
|
23
|
+
!!@continuations
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.accumulating?
|
27
|
+
@accumulating
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def self.simultaneously
|
32
|
+
raise "Api.simultaneously may not be nested" if simultaneously?
|
33
|
+
@continuations = []
|
34
|
+
# Execute the block
|
35
|
+
begin
|
36
|
+
puts "--------------------------- ACCUMULATING ------------------------"
|
37
|
+
@accumulating = true
|
38
|
+
yield @continuations
|
39
|
+
ensure
|
40
|
+
@accumulating = false
|
41
|
+
end
|
42
|
+
|
43
|
+
# The continuations array should now have entries. Create a continuation
|
44
|
+
# to return to this point.
|
45
|
+
begin
|
46
|
+
puts '', "--------------------------- EXECUTING ------------------------"
|
47
|
+
cc, results, result = callcc { |cc, results, result| [cc, [], :init] }
|
48
|
+
# '-BACK AT TOP LEVEL-----', [cc, results, result].inspect
|
49
|
+
raise "must be a continuation" unless cc.is_a? Continuation
|
50
|
+
results << result if result && result != :init
|
51
|
+
# Call the first accumulated continuation (if any) with it. When they call
|
52
|
+
# here, the next continuation will be called (if any). This is a loop,
|
53
|
+
# continuation style.
|
54
|
+
if @continuations.size > 0
|
55
|
+
@continuations.shift.call(cc, results)
|
56
|
+
end
|
57
|
+
ensure
|
58
|
+
# No longer nested
|
59
|
+
@continuations = nil
|
60
|
+
end
|
61
|
+
results
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def self.doubler (arg, k: nil)
|
66
|
+
raise "K is not a continuation: #{k.inspect}" if k && !k.is_a?(Continuation)
|
67
|
+
cc, acc = callcc { |cc, acc| [cc, acc] }
|
68
|
+
puts '', '-CONTINUATION CALL TO DOUBLER-----', [cc, acc].inspect
|
69
|
+
return cc if accumulating?
|
70
|
+
|
71
|
+
# Execution phase
|
72
|
+
|
73
|
+
# Calculate a result
|
74
|
+
result = arg * 2 # Calculate the result
|
75
|
+
|
76
|
+
# Transfer back
|
77
|
+
k.call(k, result) if k # Go elsewhere if k is there (e.g. to a nested caller)
|
78
|
+
cc.call(cc, acc, result) # Return to caller
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
def self.nested(arg, k: nil)
|
83
|
+
raise "K is not a continuation: #{k.inspect}" if k && !k.is_a?(Continuation)
|
84
|
+
cc, acc = callcc { |cc, acc| [cc, acc] }
|
85
|
+
puts '', '-CONTINUATION CALL TO NESTED-----', [cc, acc].inspect
|
86
|
+
return cc if accumulating?
|
87
|
+
|
88
|
+
# Execution phase
|
89
|
+
# Set up the overriding continuation for the callee
|
90
|
+
callee_k, result = callcc { |callee_k, result| [callee_k, result] }
|
91
|
+
# The callee returns to the following statement
|
92
|
+
result = doubler(arg, k: callee_k) unless result # Can't be nil or false (fix later)
|
93
|
+
|
94
|
+
# Calculate a result
|
95
|
+
result = "#{result} processed"
|
96
|
+
|
97
|
+
# Transfer back
|
98
|
+
k.call(k, result) if k # Go elsewhere if k is there (e.g. to a nested caller)
|
99
|
+
cc.call(cc, acc, result) # Return to caller
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def self.deeply_nested(arg, k: nil)
|
104
|
+
raise "K is not a continuation: #{k.inspect}" if k && !k.is_a?(Continuation)
|
105
|
+
cc, acc = callcc { |cc, acc| [cc, acc] }
|
106
|
+
puts '', '-CONTINUATION CALL TO DEEPLY_NESTED-----', [cc, acc].inspect
|
107
|
+
return cc if accumulating?
|
108
|
+
|
109
|
+
# Execution phase
|
110
|
+
# Set up the overriding continuation for the callee
|
111
|
+
callee_k, result = callcc { |callee_k, result| [callee_k, result] }
|
112
|
+
# The callee returns to the following statement
|
113
|
+
result = nested(arg, k: callee_k) unless result # Can't be nil or false (fix later)
|
114
|
+
|
115
|
+
# Calculate a result
|
116
|
+
result = "#{result} more deeply"
|
117
|
+
|
118
|
+
# Transfer back
|
119
|
+
k.call(k, result) if k # Go elsewhere if k is there (e.g. to a nested caller)
|
120
|
+
cc.call(cc, acc, result) # Return to caller
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
# This accumulates stuff
|
128
|
+
res = Quux.simultaneously do |r|
|
129
|
+
r << Quux.doubler(24)
|
130
|
+
r << Quux.nested("hej")
|
131
|
+
r << Quux.doubler(100)
|
132
|
+
r << Quux.deeply_nested("woo")
|
133
|
+
r << Quux.doubler(1)
|
134
|
+
end
|
135
|
+
|
136
|
+
puts
|
137
|
+
puts res.inspect
|
138
|
+
puts
|
139
|
+
|
data/lib/ocean/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ocean-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.8.
|
4
|
+
version: 3.8.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Bengtson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: typhoeus
|
@@ -252,6 +252,7 @@ files:
|
|
252
252
|
- lib/ocean/api.rb
|
253
253
|
- lib/ocean/api_remote_resource.rb
|
254
254
|
- lib/ocean/api_resource.rb
|
255
|
+
- lib/ocean/continuation_experiments.rb
|
255
256
|
- lib/ocean/engine.rb
|
256
257
|
- lib/ocean/flooding.rb
|
257
258
|
- lib/ocean/ocean_application_controller.rb
|