cassandra-driver 1.0.0.beta.2-java

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.
Files changed (118) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +4 -0
  3. data/README.md +125 -0
  4. data/lib/cassandra/auth/providers/password.rb +73 -0
  5. data/lib/cassandra/auth/providers.rb +16 -0
  6. data/lib/cassandra/auth.rb +97 -0
  7. data/lib/cassandra/client/batch.rb +212 -0
  8. data/lib/cassandra/client/client.rb +591 -0
  9. data/lib/cassandra/client/column_metadata.rb +54 -0
  10. data/lib/cassandra/client/connection_manager.rb +72 -0
  11. data/lib/cassandra/client/connector.rb +277 -0
  12. data/lib/cassandra/client/execute_options_decoder.rb +59 -0
  13. data/lib/cassandra/client/null_logger.rb +37 -0
  14. data/lib/cassandra/client/peer_discovery.rb +50 -0
  15. data/lib/cassandra/client/prepared_statement.rb +314 -0
  16. data/lib/cassandra/client/query_result.rb +230 -0
  17. data/lib/cassandra/client/request_runner.rb +71 -0
  18. data/lib/cassandra/client/result_metadata.rb +48 -0
  19. data/lib/cassandra/client/void_result.rb +78 -0
  20. data/lib/cassandra/client.rb +144 -0
  21. data/lib/cassandra/cluster/client.rb +768 -0
  22. data/lib/cassandra/cluster/connector.rb +244 -0
  23. data/lib/cassandra/cluster/control_connection.rb +425 -0
  24. data/lib/cassandra/cluster/metadata.rb +124 -0
  25. data/lib/cassandra/cluster/options.rb +42 -0
  26. data/lib/cassandra/cluster/registry.rb +198 -0
  27. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +47 -0
  28. data/lib/cassandra/cluster/schema/partitioners/ordered.rb +37 -0
  29. data/lib/cassandra/cluster/schema/partitioners/random.rb +37 -0
  30. data/lib/cassandra/cluster/schema/partitioners.rb +21 -0
  31. data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +92 -0
  32. data/lib/cassandra/cluster/schema/replication_strategies/none.rb +39 -0
  33. data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +44 -0
  34. data/lib/cassandra/cluster/schema/replication_strategies.rb +21 -0
  35. data/lib/cassandra/cluster/schema/type_parser.rb +138 -0
  36. data/lib/cassandra/cluster/schema.rb +340 -0
  37. data/lib/cassandra/cluster.rb +215 -0
  38. data/lib/cassandra/column.rb +92 -0
  39. data/lib/cassandra/compression/compressors/lz4.rb +72 -0
  40. data/lib/cassandra/compression/compressors/snappy.rb +66 -0
  41. data/lib/cassandra/compression.rb +66 -0
  42. data/lib/cassandra/driver.rb +111 -0
  43. data/lib/cassandra/errors.rb +79 -0
  44. data/lib/cassandra/execution/info.rb +51 -0
  45. data/lib/cassandra/execution/options.rb +80 -0
  46. data/lib/cassandra/execution/trace.rb +152 -0
  47. data/lib/cassandra/future.rb +675 -0
  48. data/lib/cassandra/host.rb +79 -0
  49. data/lib/cassandra/keyspace.rb +133 -0
  50. data/lib/cassandra/listener.rb +87 -0
  51. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +149 -0
  52. data/lib/cassandra/load_balancing/policies/round_robin.rb +132 -0
  53. data/lib/cassandra/load_balancing/policies/token_aware.rb +119 -0
  54. data/lib/cassandra/load_balancing/policies/white_list.rb +90 -0
  55. data/lib/cassandra/load_balancing/policies.rb +19 -0
  56. data/lib/cassandra/load_balancing.rb +113 -0
  57. data/lib/cassandra/protocol/cql_byte_buffer.rb +307 -0
  58. data/lib/cassandra/protocol/cql_protocol_handler.rb +323 -0
  59. data/lib/cassandra/protocol/frame_decoder.rb +128 -0
  60. data/lib/cassandra/protocol/frame_encoder.rb +48 -0
  61. data/lib/cassandra/protocol/request.rb +38 -0
  62. data/lib/cassandra/protocol/requests/auth_response_request.rb +47 -0
  63. data/lib/cassandra/protocol/requests/batch_request.rb +76 -0
  64. data/lib/cassandra/protocol/requests/credentials_request.rb +47 -0
  65. data/lib/cassandra/protocol/requests/execute_request.rb +103 -0
  66. data/lib/cassandra/protocol/requests/options_request.rb +39 -0
  67. data/lib/cassandra/protocol/requests/prepare_request.rb +50 -0
  68. data/lib/cassandra/protocol/requests/query_request.rb +153 -0
  69. data/lib/cassandra/protocol/requests/register_request.rb +38 -0
  70. data/lib/cassandra/protocol/requests/startup_request.rb +49 -0
  71. data/lib/cassandra/protocol/requests/void_query_request.rb +24 -0
  72. data/lib/cassandra/protocol/response.rb +38 -0
  73. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +41 -0
  74. data/lib/cassandra/protocol/responses/auth_success_response.rb +41 -0
  75. data/lib/cassandra/protocol/responses/authenticate_response.rb +41 -0
  76. data/lib/cassandra/protocol/responses/detailed_error_response.rb +60 -0
  77. data/lib/cassandra/protocol/responses/error_response.rb +50 -0
  78. data/lib/cassandra/protocol/responses/event_response.rb +39 -0
  79. data/lib/cassandra/protocol/responses/prepared_result_response.rb +64 -0
  80. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +43 -0
  81. data/lib/cassandra/protocol/responses/ready_response.rb +44 -0
  82. data/lib/cassandra/protocol/responses/result_response.rb +48 -0
  83. data/lib/cassandra/protocol/responses/rows_result_response.rb +139 -0
  84. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +60 -0
  85. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +57 -0
  86. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +42 -0
  87. data/lib/cassandra/protocol/responses/status_change_event_response.rb +44 -0
  88. data/lib/cassandra/protocol/responses/supported_response.rb +41 -0
  89. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +34 -0
  90. data/lib/cassandra/protocol/responses/void_result_response.rb +39 -0
  91. data/lib/cassandra/protocol/type_converter.rb +384 -0
  92. data/lib/cassandra/protocol.rb +93 -0
  93. data/lib/cassandra/reconnection/policies/constant.rb +48 -0
  94. data/lib/cassandra/reconnection/policies/exponential.rb +79 -0
  95. data/lib/cassandra/reconnection/policies.rb +20 -0
  96. data/lib/cassandra/reconnection.rb +49 -0
  97. data/lib/cassandra/result.rb +215 -0
  98. data/lib/cassandra/retry/policies/default.rb +47 -0
  99. data/lib/cassandra/retry/policies/downgrading_consistency.rb +71 -0
  100. data/lib/cassandra/retry/policies/fallthrough.rb +39 -0
  101. data/lib/cassandra/retry/policies.rb +21 -0
  102. data/lib/cassandra/retry.rb +142 -0
  103. data/lib/cassandra/session.rb +202 -0
  104. data/lib/cassandra/statement.rb +22 -0
  105. data/lib/cassandra/statements/batch.rb +95 -0
  106. data/lib/cassandra/statements/bound.rb +48 -0
  107. data/lib/cassandra/statements/prepared.rb +81 -0
  108. data/lib/cassandra/statements/simple.rb +58 -0
  109. data/lib/cassandra/statements/void.rb +33 -0
  110. data/lib/cassandra/statements.rb +23 -0
  111. data/lib/cassandra/table.rb +299 -0
  112. data/lib/cassandra/time_uuid.rb +142 -0
  113. data/lib/cassandra/util.rb +167 -0
  114. data/lib/cassandra/uuid.rb +104 -0
  115. data/lib/cassandra/version.rb +21 -0
  116. data/lib/cassandra.rb +428 -0
  117. data/lib/cassandra_murmur3.jar +0 -0
  118. metadata +211 -0
@@ -0,0 +1,675 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2014 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ # A Future represents a result of asynchronous execution. It can be used to
21
+ # block until a value is available or an error has happened, or register a
22
+ # listener to be notified whenever the execution is complete.
23
+ class Future
24
+ # a Future listener to be passed to {Cassandra::Future#add_listener}
25
+ #
26
+ # @note Listener methods can be called from application if a future has
27
+ # been resolved or failed by the time the listener is registered; or from
28
+ # background thread if it is resolved/failed after the listener has been
29
+ # registered.
30
+ #
31
+ # @abstract Actual listeners passed to {Cassandra::Future#add_listener} don't
32
+ # need to extend this class as long as they implement `#success` and
33
+ # `#failure` methods
34
+ class Listener
35
+ # @param value [Object] actual value the future has been resolved with
36
+ # @return [void]
37
+ def success(value)
38
+ end
39
+
40
+ # @param error [Exception] an exception used to fail the future
41
+ # @return [void]
42
+ def failure(error)
43
+ end
44
+ end
45
+
46
+ # @private
47
+ class Error < Future
48
+ def initialize(error)
49
+ raise ::ArgumentError, "error must be an exception, #{error.inspect} given" unless error.is_a?(::Exception)
50
+
51
+ @error = error
52
+ end
53
+
54
+ def get
55
+ raise(@error, @error.message, @error.backtrace)
56
+ end
57
+
58
+ def on_success
59
+ raise ::ArgumentError, "no block given" unless block_given?
60
+ self
61
+ end
62
+
63
+ def on_failure
64
+ raise ::ArgumentError, "no block given" unless block_given?
65
+ yield(@error) rescue nil
66
+ self
67
+ end
68
+
69
+ def on_complete
70
+ raise ::ArgumentError, "no block given" unless block_given?
71
+ yield(nil, @error) rescue nil
72
+ self
73
+ end
74
+
75
+ def add_listener(listener)
76
+ unless (listener.respond_to?(:success) && listener.respond_to?(:failure))
77
+ raise ::ArgumentError, "listener must respond to both #success and #failure"
78
+ end
79
+
80
+ listener.failure(@error) rescue nil
81
+ self
82
+ end
83
+
84
+ def join
85
+ self
86
+ end
87
+
88
+ def then
89
+ raise ::ArgumentError, "no block given" unless block_given?
90
+ self
91
+ end
92
+
93
+ def fallback
94
+ raise ::ArgumentError, "no block given" unless block_given?
95
+
96
+ begin
97
+ result = yield(@error)
98
+ result = Value.new(result) unless result.is_a?(Future)
99
+ result
100
+ rescue => e
101
+ Error.new(e)
102
+ end
103
+ end
104
+ end
105
+
106
+ # @private
107
+ class Value < Future
108
+ def initialize(value)
109
+ @value = value
110
+ end
111
+
112
+ def get
113
+ @value
114
+ end
115
+
116
+ def on_success
117
+ raise ::ArgumentError, "no block given" unless block_given?
118
+ yield(@value) rescue nil
119
+ self
120
+ end
121
+
122
+ def on_failure
123
+ raise ::ArgumentError, "no block given" unless block_given?
124
+ self
125
+ end
126
+
127
+ def on_complete
128
+ raise ::ArgumentError, "no block given" unless block_given?
129
+ yield(@value, nil) rescue nil
130
+ self
131
+ end
132
+
133
+ def add_listener(listener)
134
+ unless (listener.respond_to?(:success) && listener.respond_to?(:failure))
135
+ raise ::ArgumentError, "listener must respond to both #success and #failure"
136
+ end
137
+
138
+ listener.success(@value) rescue nil
139
+ self
140
+ end
141
+
142
+ def join
143
+ self
144
+ end
145
+
146
+ def then
147
+ raise ::ArgumentError, "no block given" unless block_given?
148
+
149
+ begin
150
+ result = yield(@value)
151
+ result = Value.new(result) unless result.is_a?(Future)
152
+ result
153
+ rescue => e
154
+ Error.new(e)
155
+ end
156
+ end
157
+
158
+ def fallback
159
+ raise ::ArgumentError, "no block given" unless block_given?
160
+ self
161
+ end
162
+ end
163
+
164
+ # Returns a future resolved to a given value
165
+ # @param value [Object] value for the future
166
+ # @return [Cassandra::Future<Object>] a future value
167
+ def self.value(value)
168
+ Value.new(value)
169
+ end
170
+
171
+ # Returns a future resolved to a given error
172
+ # @param error [Exception] error for the future
173
+ # @return [Cassandra::Future<Exception>] a future error
174
+ def self.error(error)
175
+ Error.new(error)
176
+ end
177
+
178
+ # Returns a future that resolves with values of all futures
179
+ # @overload all(*futures)
180
+ # @param *futures [Cassandra::Future] futures to combine
181
+ # @return [Cassandra::Future<Array<Object>>] a combined future
182
+ # @overload all(futures)
183
+ # @param futures [Enumerable<Cassandra::Future>] list of futures to
184
+ # combine
185
+ # @return [Cassandra::Future<Array<Object>>] a combined future
186
+ def self.all(*futures)
187
+ futures = Array(futures.first) if futures.one?
188
+ monitor = Monitor.new
189
+ promise = Promise.new
190
+ remaining = futures.length
191
+ values = Array.new(length)
192
+
193
+ futures.each_with_index do |future, i|
194
+ future.on_complete do |v, e|
195
+ if e
196
+ promise.break(e)
197
+ else
198
+ done = false
199
+ monitor.synchronize do
200
+ remaining -= 1
201
+ done = (remaining == 0)
202
+ values[i] = v
203
+ end
204
+ promise.fulfill(values) if done
205
+ end
206
+ end
207
+ end
208
+
209
+ promise.future
210
+ end
211
+
212
+ # @private
213
+ # Returns a new promise instance
214
+ def self.promise
215
+ Promise.new
216
+ end
217
+
218
+ # @private
219
+ def initialize(signal)
220
+ @signal = signal
221
+ end
222
+
223
+ # Returns future value or raises future error
224
+ # @note This method blocks until a future is resolved
225
+ # @raise [Exception] error used to resolve this future if any
226
+ # @return [Object] value used to resolve this future if any
227
+ def get
228
+ @signal.get
229
+ end
230
+
231
+ # Block until the future has been resolved
232
+ # @note This method blocks until a future is resolved
233
+ # @note This method won't raise any errors or return anything but the
234
+ # future itself
235
+ # @return [self]
236
+ def join
237
+ @signal.join
238
+ self
239
+ end
240
+
241
+ # Run block when future resolves to a value
242
+ # @note The block can be called synchronously from current thread if the
243
+ # future has already been resolved, or, asynchronously, from background
244
+ # thread upon resolution.
245
+ # @yieldparam value [Object] a value
246
+ # @raise [ArgumentError] if no block given
247
+ # @return [self]
248
+ def on_success(&block)
249
+ raise ::ArgumentError, "no block given" unless block_given?
250
+ @signal.on_success(&block)
251
+ self
252
+ end
253
+
254
+ # Run block when future resolves to error
255
+ # @note The block can be called synchronously from current thread if the
256
+ # future has already been resolved, or, asynchronously, from background
257
+ # thread upon resolution.
258
+ # @yieldparam error [Exception] an error
259
+ # @raise [ArgumentError] if no block given
260
+ # @return [self]
261
+ def on_failure(&block)
262
+ raise ::ArgumentError, "no block given" unless block_given?
263
+ @signal.on_failure(&block)
264
+ self
265
+ end
266
+
267
+ # Run block when future resolves. The block will always be called with 2
268
+ # arguments - value and error. In case a future resolves to an error, the
269
+ # error argument will be non-nil.
270
+ # @note The block can be called synchronously from current thread if the
271
+ # future has already been resolved, or, asynchronously, from background
272
+ # thread upon resolution.
273
+ # @yieldparam value [Object, nil] a value or nil
274
+ # @yieldparam error [Exception, nil] an error or nil
275
+ # @raise [ArgumentError] if no block given
276
+ # @return [self]
277
+ def on_complete(&block)
278
+ raise ::ArgumentError, "no block given" unless block_given?
279
+ @signal.on_complete(&block)
280
+ self
281
+ end
282
+
283
+ # Add future listener
284
+ # @note The listener can be notified synchronously, from current thread, if
285
+ # the future has already been resolved, or, asynchronously, from
286
+ # background thread upon resolution.
287
+ # @note that provided listener doesn't have to extend
288
+ # {Cassandra::Future::Listener}, only conform to the same interface
289
+ # @param listener [Cassandra::Future::Listener] an object that responds to
290
+ # `#success` and `#failure`
291
+ # @return [self]
292
+ def add_listener(listener)
293
+ unless (listener.respond_to?(:success) && listener.respond_to?(:failure))
294
+ raise ::ArgumentError, "listener must respond to both #success and #failure"
295
+ end
296
+
297
+ @signal.add_listener(listener)
298
+ self
299
+ end
300
+
301
+ # Returns a new future that will resolve to the result of the block.
302
+ # Besides regular values, block can return other futures, which will be
303
+ # transparently unwrapped before resolving the future from this method.
304
+ #
305
+ # @example Block returns a value
306
+ # future_users = session.execute_async('SELECT * FROM users WHERE user_name = ?', 'Sam')
307
+ # future_user = future_users.then {|users| users.first}
308
+ #
309
+ # @example Block returns a future
310
+ # future_statement = session.prepare_async('SELECT * FROM users WHERE user_name = ?')
311
+ # future_users = future_statement.then {|statement| session.execute_async(statement, 'Sam')}
312
+ #
313
+ # @note The block can be called synchronously from current thread if the
314
+ # future has already been resolved, or, asynchronously, from background
315
+ # thread upon resolution.
316
+ # @yieldparam value [Object] a value
317
+ # @yieldreturn [Cassandra::Future, Object] a future or a value to be
318
+ # wrapped in a future
319
+ # @raise [ArgumentError] if no block given
320
+ # @return [Cassandra::Future] a new future
321
+ def then(&block)
322
+ raise ::ArgumentError, "no block given" unless block_given?
323
+ @signal.then(&block)
324
+ end
325
+
326
+ # Returns a new future that will resolve to the result of the block in case
327
+ # of an error. Besides regular values, block can return other futures,
328
+ # which will be transparently unwrapped before resolving the future from
329
+ # this method.
330
+ #
331
+ # @example Recovering from errors
332
+ # future_error = session.execute_async('SELECT * FROM invalid-table')
333
+ # future = future_error.fallback {|error| "Execution failed with #{error.class.name}: #{error.message}"}
334
+ #
335
+ # @example Executing something else on error
336
+ # future_error = session.execute_async('SELECT * FROM invalid-table')
337
+ # future = future_error.fallback {|e| session.execute_async('SELECT * FROM another-table')}
338
+ #
339
+ # @note The block can be called synchronously from current thread if the
340
+ # future has already been resolved, or, asynchronously, from background
341
+ # thread upon resolution.
342
+ # @yieldparam error [Exception] an error
343
+ # @yieldreturn [Cassandra::Future, Object] a future or a value to be
344
+ # wrapped in a future
345
+ # @raise [ArgumentError] if no block given
346
+ # @return [Cassandra::Future] a new future
347
+ def fallback(&block)
348
+ raise ::ArgumentError, "no block given" unless block_given?
349
+ @signal.fallback(&block)
350
+ end
351
+ end
352
+
353
+ # @private
354
+ class Promise
355
+ # @private
356
+ class Signal
357
+ # @private
358
+ module Listeners
359
+ class Success < Future::Listener
360
+ def initialize(&block)
361
+ @block = block
362
+ end
363
+
364
+ def success(value)
365
+ @block.call(value)
366
+ end
367
+
368
+ def failure(error)
369
+ nil
370
+ end
371
+ end
372
+
373
+ class Failure < Future::Listener
374
+ def initialize(&block)
375
+ @block = block
376
+ end
377
+
378
+ def success(value)
379
+ nil
380
+ end
381
+
382
+ def failure(error)
383
+ @block.call(error)
384
+ end
385
+ end
386
+
387
+ class Complete < Future::Listener
388
+ def initialize(&block)
389
+ @block = block
390
+ end
391
+
392
+ def success(value)
393
+ @block.call(nil, value)
394
+ end
395
+
396
+ def failure(error)
397
+ @block.call(error, nil)
398
+ end
399
+ end
400
+
401
+ class Then < Future::Listener
402
+ def initialize(promise, &block)
403
+ @promise = promise
404
+ @block = block
405
+ end
406
+
407
+ def success(value)
408
+ result = @block.call(value)
409
+
410
+ if result.is_a?(Future)
411
+ @promise.observe(result)
412
+ else
413
+ @promise.fulfill(result)
414
+ end
415
+ rescue => e
416
+ @promise.break(e)
417
+ ensure
418
+ @promise = @block = nil
419
+ end
420
+
421
+ def failure(error)
422
+ @promise.break(error)
423
+ ensure
424
+ @promise = @block = nil
425
+ end
426
+ end
427
+
428
+ class Fallback < Future::Listener
429
+ def initialize(promise, &block)
430
+ @promise = promise
431
+ @block = block
432
+ end
433
+
434
+ def success(value)
435
+ @promise.fulfill(value)
436
+ ensure
437
+ @promise = @block = nil
438
+ end
439
+
440
+ def failure(error)
441
+ result = @block.call(error)
442
+
443
+ if result.is_a?(Future)
444
+ @promise.observe(result)
445
+ else
446
+ @promise.fulfill(result)
447
+ end
448
+ rescue => e
449
+ @promise.break(e)
450
+ ensure
451
+ @promise = @block = nil
452
+ end
453
+ end
454
+ end
455
+
456
+ include MonitorMixin
457
+
458
+ def initialize
459
+ mon_initialize
460
+
461
+ @cond = new_cond
462
+ @state = :pending
463
+ @waiting = 0
464
+ @error = nil
465
+ @value = nil
466
+ @listeners = []
467
+ end
468
+
469
+ def failure(error)
470
+ unless error.is_a?(::Exception)
471
+ raise ::ArgumentError, "error must be an exception, #{error.inspect} given"
472
+ end
473
+
474
+ return unless @state == :pending
475
+
476
+ listeners = nil
477
+
478
+ synchronize do
479
+ return unless @state == :pending
480
+
481
+ @error = error
482
+ @state = :broken
483
+
484
+ listeners, @listeners = @listeners, nil
485
+ end
486
+
487
+ listeners.each do |listener|
488
+ listener.failure(error) rescue nil
489
+ end
490
+
491
+ synchronize do
492
+ @cond.broadcast if @waiting > 0
493
+ end
494
+
495
+ self
496
+ end
497
+
498
+ def success(value)
499
+ return unless @state == :pending
500
+
501
+ listeners = nil
502
+
503
+ synchronize do
504
+ return unless @state == :pending
505
+
506
+ @value = value
507
+ @state = :fulfilled
508
+
509
+ listeners, @listeners = @listeners, nil
510
+ end
511
+
512
+ listeners.each do |listener|
513
+ listener.success(value) rescue nil
514
+ end
515
+
516
+ synchronize do
517
+ @cond.broadcast if @waiting > 0
518
+ end
519
+
520
+ self
521
+ end
522
+
523
+ def join
524
+ return unless @state == :pending
525
+
526
+ synchronize do
527
+ return unless @state == :pending
528
+
529
+ @waiting += 1
530
+ @cond.wait while @state == :pending
531
+ @waiting -= 1
532
+ end
533
+
534
+ nil
535
+ end
536
+
537
+ def get
538
+ join if @state == :pending
539
+
540
+ raise(@error, @error.message, @error.backtrace) if @state == :broken
541
+
542
+ @value
543
+ end
544
+
545
+ def add_listener(listener)
546
+ if @state == :pending
547
+ synchronize do
548
+ if @state == :pending
549
+ @listeners << listener
550
+
551
+ return self
552
+ end
553
+ end
554
+ end
555
+
556
+ listener.success(@value) rescue nil if @state == :fulfilled
557
+ listener.failure(@error) rescue nil if @state == :broken
558
+
559
+ self
560
+ end
561
+
562
+ def on_success(&block)
563
+ if @state == :pending
564
+ synchronize do
565
+ if @state == :pending
566
+ @listeners << Listeners::Success.new(&block)
567
+ return self
568
+ end
569
+ end
570
+ end
571
+
572
+ yield(@value) rescue nil if @state == :fulfilled
573
+
574
+ self
575
+ end
576
+
577
+ def on_failure(&block)
578
+ if @state == :pending
579
+ synchronize do
580
+ if @state == :pending
581
+ @listeners << Listeners::Failure.new(&block)
582
+ return self
583
+ end
584
+ end
585
+ end
586
+
587
+ yield(@error) rescue nil if @state == :broken
588
+
589
+ self
590
+ end
591
+
592
+ def on_complete(&block)
593
+ if @state == :pending
594
+ synchronize do
595
+ if @state == :pending
596
+ @listeners << Listeners::Complete.new(&block)
597
+ return self
598
+ end
599
+ end
600
+ end
601
+
602
+ yield(@value, @error) rescue nil
603
+
604
+ self
605
+ end
606
+
607
+ def then(&block)
608
+ if @state == :pending
609
+ synchronize do
610
+ if @state == :pending
611
+ promise = Promise.new
612
+ listener = Listeners::Then.new(promise, &block)
613
+ @listeners << listener
614
+ return promise.future
615
+ end
616
+ end
617
+ end
618
+
619
+ return Future::Error.new(@error) if @state == :broken
620
+
621
+ begin
622
+ result = yield(@value)
623
+ result = Future::Value.new(result) unless result.is_a?(Future)
624
+ result
625
+ rescue => e
626
+ Future::Error.new(e)
627
+ end
628
+ end
629
+
630
+ def fallback(&block)
631
+ if @state == :pending
632
+ synchronize do
633
+ if @state == :pending
634
+ promise = Promise.new
635
+ listener = Listeners::Fallback.new(promise, &block)
636
+ @listeners << listener
637
+ return promise.future
638
+ end
639
+ end
640
+ end
641
+
642
+ return Future::Value.new(@value) if @state == :fulfilled
643
+
644
+ begin
645
+ result = yield(@error)
646
+ result = Future::Value.new(result) unless result.is_a?(Future)
647
+ result
648
+ rescue => e
649
+ Future::Error.new(e)
650
+ end
651
+ end
652
+ end
653
+
654
+ attr_reader :future
655
+
656
+ def initialize
657
+ @signal = Signal.new
658
+ @future = Future.new(@signal)
659
+ end
660
+
661
+ def break(error)
662
+ @signal.failure(error)
663
+ self
664
+ end
665
+
666
+ def fulfill(value)
667
+ @signal.success(value)
668
+ self
669
+ end
670
+
671
+ def observe(future)
672
+ future.add_listener(@signal)
673
+ end
674
+ end
675
+ end