promise.rb 0.6.1 → 0.7.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b98cd2e53ffcbfb4c387c41a85c9699b8c050f5e
4
+ data.tar.gz: 22cf6c2bd54e4490470520aca42aa9f15abb24b4
5
+ SHA512:
6
+ metadata.gz: 990eedfbc0cfb55355f2ca0bc963e0cec24d3668b7a22e8e97fb643bb6abd71da10dec39c9e4846f243bc3bad51b5e6a544a270d04a600f7fbca2b3d060e7f96
7
+ data.tar.gz: dffd4ca2bd12d3ee92acb2dc4c719a7aacbe20a4563da016b21ad63d2909c1f22a5c68947b9369f3792b1440edf5e2b37f4b13d8b4e8aa4d14c0d4795ee83e25
data/.travis.yml CHANGED
@@ -1,18 +1,14 @@
1
+ sudo: false
1
2
  language: ruby
2
3
  rvm:
3
- - 1.9.3
4
- - 2.0.0
5
- - 2.1.0
4
+ - 1.9
5
+ - 2.0
6
+ - 2.1
7
+ - 2.2
6
8
  - jruby
7
- - rbx
8
- - ruby-head
9
- - jruby-head
9
+ - rbx-3.14
10
10
  matrix:
11
- allow_failures:
12
- - rvm: 2.1.0 # https://github.com/dkubb/adamantium/issues/30
13
- - rvm: ruby-head
14
- - rvm: jruby-head
15
11
  fast_finish: true
16
- script: bundle exec rake -t metrics:coverage ci
17
12
  before_install:
18
- - gem install bundler -v '= 1.5.1'
13
+ - gem install bundler
14
+ script: bundle exec rake -t
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # promise.rb changelog
2
2
 
3
+ ## 0.7.0.rc1 (February 9, 2016)
4
+
5
+ ### Bug Fixes
6
+
7
+ * Return instances of the custom promise class from its methods (pull #10)
8
+
9
+ ### Features
10
+
11
+ * Add Promise.resolve utility method (pull #8)
12
+ * Add Promise.all utility method (pull #9)
13
+
3
14
  ## 0.6.1 (January 14, 2014)
4
15
 
5
16
  * The rejection reason now defaults to Promise::Error.
data/Gemfile CHANGED
@@ -4,15 +4,18 @@ source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
6
 
7
- gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
8
- gem 'fuubar', git: 'https://github.com/lgierth/fuubar.git',
9
- ref: 'static-percentage'
7
+ if Gem.ruby_version >= Gem::Version.new('2.1')
8
+ gem 'devtools', '~> 0.1.4'
9
+ end
10
+ gem 'fuubar', '~> 2.0.0'
10
11
  gem 'awesome_print'
11
12
 
13
+ gem 'rake'
14
+ gem 'rspec', '~> 3.4.0'
15
+ gem 'rspec-its'
16
+ gem 'coveralls', '~> 0.8.9'
17
+
12
18
  platform :rbx do
13
19
  gem 'rubysl', '~> 2.0'
14
20
  gem 'rubinius', '~> 2.0'
15
21
  end
16
-
17
- # Added by devtools
18
- eval_gemfile 'Gemfile.devtools'
data/README.md CHANGED
@@ -1,11 +1,12 @@
1
1
  # promise.rb [![Build Status](https://travis-ci.org/lgierth/promise.rb.png?branch=master)](https://travis-ci.org/lgierth/promise.rb) [![Code Climate](https://codeclimate.com/github/lgierth/promise.rb.png)](https://codeclimate.com/github/lgierth/promise.rb) [![Coverage Status](https://coveralls.io/repos/lgierth/promise.rb/badge.png?branch=master)](https://coveralls.io/r/lgierth/promise.rb?branch=master)
2
2
 
3
3
  Ruby implementation of the [Promises/A+ spec](http://promisesaplus.com/).
4
- 100% [mutation coverage](https://github.com/mbj/mutant), tested on 1.9, 2.0, Rubinius, and JRuby.
4
+ 100% [mutation coverage](https://github.com/mbj/mutant),
5
+ tested on MRI 1.9, 2.0, 2.1, 2.2, Rubinius, and JRuby.
5
6
 
6
7
  Similar projects:
7
8
 
8
- - [concurrent-ruby](https://github.com/jdantonio/concurrent-ruby/blob/master/md/promise.md), Promises/A(+) implementation, thread based
9
+ - [concurrent-ruby](https://github.com/jdantonio/concurrent-ruby), Promises/A(+) implementation, thread based
9
10
  - [ruby-thread](https://github.com/meh/ruby-thread), thread/mutex/condition variable based, thread safe
10
11
  - [promise](https://github.com/bhuga/promising-future), a.k.a. promising-future, classic promises and futures, thread based
11
12
  - [celluloid-promise](https://github.com/cotag/celluloid-promise), inspired by Q, backed by a Celluloid actor
@@ -64,8 +65,10 @@ def nonblocking_stuff
64
65
  promise
65
66
  end
66
67
 
67
- nonblocking_stuff.then { |value| p value }
68
- nonblocking_stuff.then(proc { |value| p value })
68
+ EM.run do
69
+ nonblocking_stuff.then { |value| p value }
70
+ nonblocking_stuff.then(proc { |value| p value })
71
+ end
69
72
  ```
70
73
 
71
74
  Rejection works similarly:
@@ -77,7 +80,9 @@ def failing_stuff
77
80
  promise
78
81
  end
79
82
 
80
- failing_stuff.then(proc { |value| }, proc { |reason| p reason })
83
+ EM.run do
84
+ failing_stuff.then(proc { |value| }, proc { |reason| p reason })
85
+ end
81
86
  ```
82
87
 
83
88
  ### Waiting for fulfillment/rejection
@@ -88,6 +93,7 @@ re-raises the reason. Using `#sync` requires you to implement `#wait`. You could
88
93
  for example cooperatively schedule fibers waiting for different promises:
89
94
 
90
95
  ```ruby
96
+ require 'fiber'
91
97
  require 'promise'
92
98
  require 'eventmachine'
93
99
 
@@ -107,25 +113,29 @@ class MyPromise < Promise
107
113
  end
108
114
  end
109
115
 
110
- promise = MyPromise.new
111
- Fiber.new { p promise.sync }.resume
112
- promise.fulfill
116
+ EM.run do
117
+ promise = MyPromise.new
118
+ Fiber.new { p promise.sync }.resume
119
+ promise.fulfill
120
+ end
113
121
  ```
114
122
 
115
123
  Or have the rejection reason re-raised from `#sync`:
116
124
 
117
125
  ```ruby
118
- promise = MyPromise.new
126
+ EM.run do
127
+ promise = MyPromise.new
119
128
 
120
- Fiber.new do
121
- begin
122
- promise.sync
123
- rescue MyError
124
- p $!
125
- end
126
- end.resume
129
+ Fiber.new do
130
+ begin
131
+ promise.sync
132
+ rescue
133
+ p $!
134
+ end
135
+ end.resume
127
136
 
128
- promise.reject(MyError.new)
137
+ promise.reject('reason')
138
+ end
129
139
  ```
130
140
 
131
141
  ### Chaining promises
data/Rakefile CHANGED
@@ -1,7 +1,21 @@
1
1
  # encoding: utf-8
2
2
 
3
- task :default => 'ci:metrics'
3
+ if Gem.ruby_version >= Gem::Version.new('2.1')
4
+ require 'devtools'
5
+ Devtools.init_rake_tasks
4
6
 
5
- # Added by devtools
6
- require 'devtools'
7
- Devtools.init_rake_tasks
7
+ tasks = %w[
8
+ metrics:coverage
9
+ metrics:yardstick:verify
10
+ metrics:rubocop
11
+ metrics:flog
12
+ metrics:reek
13
+ spec:integration
14
+ ]
15
+ tasks << 'metrics:mutant' if RUBY_ENGINE == 'ruby'
16
+ task :default => tasks
17
+ else
18
+ require 'rspec/core/rake_task'
19
+ RSpec::Core::RakeTask.new(:spec)
20
+ task :default => :spec
21
+ end
data/config/devtools.yml CHANGED
@@ -1,2 +1,2 @@
1
1
  ---
2
- unit_test_timeout: 0.1
2
+ unit_test_timeout: 5.0
data/config/flay.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  ---
2
- threshold: 10
3
- total_score: 44
2
+ threshold: 9
3
+ total_score: 43
data/config/reek.yml CHANGED
@@ -12,6 +12,7 @@ ControlParameter:
12
12
  enabled: true
13
13
  exclude:
14
14
  - "Promise#reject"
15
+ - "Promise#dispatch"
15
16
  DataClump:
16
17
  enabled: true
17
18
  exclude: []
@@ -63,8 +64,9 @@ TooManyMethods:
63
64
  TooManyStatements:
64
65
  enabled: true
65
66
  exclude:
67
+ - initialize
66
68
  - each
67
- max_statements: 4
69
+ max_statements: 5
68
70
  UncommunicativeMethodName:
69
71
  enabled: true
70
72
  exclude: []
data/config/rubocop.yml CHANGED
@@ -1,17 +1,20 @@
1
1
  AllCops:
2
- Includes:
2
+ Include:
3
3
  - '**/*.rake'
4
4
  - 'Gemfile'
5
5
  - 'Gemfile.devtools'
6
- Excludes:
6
+ Exclude:
7
7
  - '**/vendor/**'
8
8
  - '**/benchmarks/**'
9
9
 
10
10
  # Avoid parameter lists longer than five parameters.
11
11
  ParameterLists:
12
- Max: 3
12
+ Max: 4
13
13
  CountKeywordArgs: true
14
- Enabled: false
14
+
15
+ MethodLength:
16
+ CountComments: false
17
+ Max: 10
15
18
 
16
19
  # Avoid more than `Max` levels of nesting.
17
20
  BlockNesting:
@@ -25,6 +28,15 @@ CollectionMethods:
25
28
  find: 'detect'
26
29
  find_all: 'select'
27
30
 
31
+ # Do not force public/protected/private keyword to be indented at the same
32
+ # level as the def keyword. My personal preference is to outdent these keywords
33
+ # because I think when scanning code it makes it easier to identify the
34
+ # sections of code and visually separate them. When the keyword is at the same
35
+ # level I think it sort of blends in with the def keywords and makes it harder
36
+ # to scan the code and see where the sections are.
37
+ AccessModifierIndentation:
38
+ Enabled: false
39
+
28
40
  # Limit line length
29
41
  LineLength:
30
42
  Max: 79
@@ -52,3 +64,35 @@ TrivialAccessors:
52
64
  SignalException:
53
65
  # Valid values are: semantic, only_raise and only_fail
54
66
  EnforcedStyle: only_raise
67
+
68
+ # Do not prefer do/end over {} for multiline blocks
69
+ BlockDelimiters:
70
+ Enabled: false
71
+
72
+ # Allow empty lines around body
73
+ EmptyLinesAroundBlockBody:
74
+ Enabled: false
75
+
76
+ # Prefer String#% over Kernel#sprintf
77
+ FormatString:
78
+ Enabled: false
79
+
80
+ # Use square brackets for literal Array objects
81
+ PercentLiteralDelimiters:
82
+ PreferredDelimiters:
83
+ '%': ()
84
+ '%i': '[]'
85
+ '%q': ()
86
+ '%Q': ()
87
+ '%r': '{}'
88
+ '%s': ()
89
+ '%w': '[]'
90
+ '%W': '[]'
91
+ '%x': ()
92
+
93
+ # buggy in rubocop-0.21.0, fixed in 0.23.0
94
+ LineEndConcatenation:
95
+ Enabled: false
96
+
97
+ GuardClause:
98
+ Enabled: false
data/lib/promise.rb CHANGED
@@ -4,6 +4,7 @@ require 'promise/version'
4
4
 
5
5
  require 'promise/callback'
6
6
  require 'promise/progress'
7
+ require 'promise/group'
7
8
 
8
9
  class Promise
9
10
  Error = Class.new(RuntimeError)
@@ -12,26 +13,35 @@ class Promise
12
13
 
13
14
  attr_reader :state, :value, :reason, :backtrace
14
15
 
16
+ def self.resolve(obj)
17
+ return obj if obj.instance_of?(self)
18
+ new.tap { |promise| promise.fulfill(obj) }
19
+ end
20
+
21
+ def self.all(enumerable)
22
+ Group.new(new, enumerable).promise
23
+ end
24
+
15
25
  def initialize
16
26
  @state = :pending
17
27
  @callbacks = []
18
28
  end
19
29
 
20
30
  def pending?
21
- @state == :pending
31
+ state.equal?(:pending)
22
32
  end
23
33
 
24
34
  def fulfilled?
25
- @state == :fulfilled
35
+ state.equal?(:fulfilled)
26
36
  end
27
37
 
28
38
  def rejected?
29
- @state == :rejected
39
+ state.equal?(:rejected)
30
40
  end
31
41
 
32
42
  def then(on_fulfill = nil, on_reject = nil, &block)
33
43
  on_fulfill ||= block
34
- next_promise = Promise.new
44
+ next_promise = self.class.new
35
45
 
36
46
  add_callback { Callback.new(self, on_fulfill, on_reject, next_promise) }
37
47
  next_promise
@@ -4,7 +4,8 @@ class Promise
4
4
  class Callback
5
5
  def initialize(promise, on_fulfill, on_reject, next_promise)
6
6
  @promise = promise
7
- @on_fulfill, @on_reject = on_fulfill, on_reject
7
+ @on_fulfill = on_fulfill
8
+ @on_reject = on_reject
8
9
  @next_promise = next_promise
9
10
  end
10
11
 
@@ -0,0 +1,51 @@
1
+ class Promise
2
+ class Group
3
+ attr_reader :promise
4
+
5
+ def initialize(result_promise, inputs)
6
+ @promise = result_promise
7
+ @inputs = inputs
8
+ @remaining = count_promises
9
+ if @remaining.zero?
10
+ promise.fulfill(inputs)
11
+ else
12
+ chain_inputs
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def chain_inputs
19
+ on_fulfill = method(:on_fulfill)
20
+ on_reject = promise.method(:reject)
21
+ each_promise do |input_promise|
22
+ input_promise.then(on_fulfill, on_reject)
23
+ end
24
+ end
25
+
26
+ def on_fulfill(_result)
27
+ @remaining -= 1
28
+ if @remaining.zero?
29
+ result = @inputs.map { |obj| promise?(obj) ? obj.value : obj }
30
+ promise.fulfill(result)
31
+ end
32
+ end
33
+
34
+ def promise?(obj)
35
+ obj.instance_of?(Promise)
36
+ end
37
+
38
+ def count_promises
39
+ count = 0
40
+ each_promise { count += 1 }
41
+ count
42
+ end
43
+
44
+ def each_promise
45
+ @inputs.each do |obj|
46
+ yield obj if promise?(obj)
47
+ end
48
+ end
49
+ end
50
+ private_constant :Group
51
+ end
@@ -3,9 +3,9 @@
3
3
  class Promise
4
4
  module Progress
5
5
  def on_progress(&block)
6
- @on_progress ||= []
7
- @on_progress << block if block_given?
8
- @on_progress
6
+ (@on_progress ||= []).tap do |callbacks|
7
+ callbacks << block if block_given?
8
+ end
9
9
  end
10
10
 
11
11
  def progress(status)
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  class Promise
4
- VERSION = '0.6.1'
4
+ VERSION = '0.7.0.rc1'
5
5
  end
data/spec/spec_helper.rb CHANGED
@@ -18,6 +18,8 @@ if ENV['COVERAGE'] == 'true'
18
18
  end
19
19
 
20
20
  require 'promise'
21
+ require_relative 'support/delayed_promise'
21
22
 
22
23
  require 'awesome_print'
23
- require 'devtools/spec_helper'
24
+ require 'devtools/spec_helper' if Gem.ruby_version >= Gem::Version.new('2.1')
25
+ require 'rspec/its'
@@ -0,0 +1,22 @@
1
+ class DelayedPromise < Promise
2
+ BrokenPromise = Class.new(StandardError)
3
+
4
+ class << self
5
+ def deferred
6
+ @deferred ||= []
7
+ end
8
+
9
+ def call_deferred
10
+ deferred.shift.call until deferred.empty?
11
+ end
12
+ end
13
+
14
+ def wait
15
+ DelayedPromise.call_deferred
16
+ raise BrokenPromise if pending?
17
+ end
18
+
19
+ def defer(&block)
20
+ DelayedPromise.deferred << block
21
+ end
22
+ end
@@ -44,7 +44,7 @@ describe Promise do
44
44
  end
45
45
 
46
46
  it 'freezes the value' do
47
- pending 'Dropped in 74da6e9'
47
+ skip 'Dropped in 74da6e9'
48
48
  end
49
49
  end
50
50
 
@@ -64,7 +64,7 @@ describe Promise do
64
64
  end
65
65
 
66
66
  it 'freezes the reason' do
67
- pending 'Dropped in 74da6e9'
67
+ skip 'Dropped in 74da6e9'
68
68
  end
69
69
  end
70
70
 
@@ -170,7 +170,16 @@ describe Promise do
170
170
 
171
171
  describe '3.2.4' do
172
172
  it 'returns before on_fulfill or on_reject is called' do
173
- pending 'To be implemented by application code'
173
+ called = false
174
+ p1 = DelayedPromise.new
175
+ p2 = p1.then { called = true }
176
+
177
+ p1.fulfill(42)
178
+
179
+ expect(called).to eq(false)
180
+ DelayedPromise.call_deferred
181
+ expect(called).to eq(true)
182
+ expect(p2).to be_fulfilled
174
183
  end
175
184
  end
176
185
 
@@ -328,83 +337,161 @@ describe Promise do
328
337
  end
329
338
  end
330
339
 
331
- describe '#progress' do
332
- let(:status) { double('status') }
340
+ describe 'extras' do
341
+ describe '#progress' do
342
+ let(:status) { double('status') }
333
343
 
334
- it 'calls the callbacks in the order of calls to #on_progress' do
335
- order = []
336
- block = proc do |i, stat|
337
- order << i
338
- expect(stat).to eq(status)
344
+ it 'calls the callbacks in the order of calls to #on_progress' do
345
+ order = []
346
+ block = proc do |i, stat|
347
+ order << i
348
+ expect(stat).to eq(status)
349
+ end
350
+
351
+ subject.on_progress(&block.curry[1])
352
+ subject.on_progress(&block.curry[2])
353
+ subject.on_progress(&block.curry[3])
354
+ subject.progress(status)
355
+
356
+ expect(order).to eq([1, 2, 3])
339
357
  end
340
358
 
341
- subject.on_progress(&block.curry[1])
342
- subject.on_progress(&block.curry[2])
343
- subject.on_progress(&block.curry[3])
344
- subject.progress(status)
359
+ it 'does not call back unless pending' do
360
+ called = false
361
+ subject.on_progress { |_| called = true }
362
+ subject.fulfill(value)
345
363
 
346
- expect(order).to eq([1, 2, 3])
364
+ subject.progress(status)
365
+ expect(called).to eq(false)
366
+ end
347
367
  end
348
368
 
349
- it 'does not call back unless pending' do
350
- called = false
351
- subject.on_progress { |_| called = true }
352
- subject.fulfill(value)
369
+ describe '#fulfill' do
370
+ it 'does not return anything' do
371
+ expect(subject.fulfill(nil)).to eq(nil)
372
+ end
353
373
 
354
- subject.progress(status)
355
- expect(called).to eq(false)
356
- end
357
- end
374
+ it 'does not require a value' do
375
+ subject.fulfill
376
+ expect(subject.value).to be(nil)
377
+ end
358
378
 
359
- describe '#fulfill' do
360
- it 'does not return anything' do
361
- expect(subject.fulfill(nil)).to eq(nil)
379
+ it 'sets the backtrace' do
380
+ subject.fulfill
381
+ expect(subject.backtrace.join)
382
+ .to include(__FILE__ + ':' + (__LINE__ - 2).to_s)
383
+ end
362
384
  end
363
385
 
364
- it 'does not require a value' do
365
- subject.fulfill
366
- expect(subject.value).to be(nil)
367
- end
386
+ describe '#reject' do
387
+ it 'does not return anything' do
388
+ expect(subject.reject(nil)).to eq(nil)
389
+ end
368
390
 
369
- it 'sets the backtrace' do
370
- subject.fulfill
371
- expect(subject.backtrace.join)
372
- .to include(__FILE__ + ':' + (__LINE__ - 2).to_s)
373
- end
374
- end
391
+ it 'does not require a reason' do
392
+ subject.reject
393
+ expect(subject.reason).to be(Promise::Error)
394
+ end
375
395
 
376
- describe '#reject' do
377
- it 'does not return anything' do
378
- expect(subject.reject(nil)).to eq(nil)
396
+ it 'sets the backtrace' do
397
+ subject.reject
398
+ expect(subject.backtrace.join)
399
+ .to include(__FILE__ + ':' + (__LINE__ - 2).to_s)
400
+ end
379
401
  end
380
402
 
381
- it 'does not require a reason' do
382
- subject.reject
383
- expect(subject.reason).to be(Promise::Error)
384
- end
403
+ describe '#sync' do
404
+ it 'waits for fulfillment' do
405
+ allow(subject).to receive(:wait) { subject.fulfill(value) }
406
+ expect(subject.sync).to be(value)
407
+ end
385
408
 
386
- it 'sets the backtrace' do
387
- subject.reject
388
- expect(subject.backtrace.join)
389
- .to include(__FILE__ + ':' + (__LINE__ - 2).to_s)
390
- end
391
- end
409
+ it 'waits for rejection' do
410
+ allow(subject).to receive(:wait) { subject.reject(reason) }
411
+ expect { subject.sync }.to raise_error(reason)
412
+ end
392
413
 
393
- describe '#sync' do
394
- it 'waits for fulfillment' do
395
- allow(subject).to receive(:wait) { subject.fulfill(value) }
396
- expect(subject.sync).to be(value)
414
+ it 'waits if pending' do
415
+ subject.fulfill(value)
416
+ expect(subject).not_to receive(:wait)
417
+ expect(subject.sync).to be(value)
418
+ end
397
419
  end
398
420
 
399
- it 'waits for rejection' do
400
- allow(subject).to receive(:wait) { subject.reject(reason) }
401
- expect { subject.sync }.to raise_error(reason)
421
+ describe '.resolve' do
422
+ it 'returns a fulfilled promise from a non-promise' do
423
+ promise = Promise.resolve(123)
424
+ expect(promise.fulfilled?).to eq(true)
425
+ expect(promise.value).to eq(123)
426
+ end
427
+
428
+ it 'assumes the state of a given promise' do
429
+ promise = Promise.new
430
+ new_promise = Promise.resolve(promise)
431
+ expect(new_promise.pending?).to eq(true)
432
+ promise.fulfill(42)
433
+ expect(new_promise.fulfilled?).to eq(true)
434
+ expect(new_promise.value).to eq(42)
435
+ end
402
436
  end
403
437
 
404
- it 'waits if pending' do
405
- subject.fulfill(value)
406
- expect(subject).not_to receive(:wait)
407
- expect(subject.sync).to be(value)
438
+ describe '.all' do
439
+ it 'returns a fulfilled promise for an array with no promises' do
440
+ obj = Object.new
441
+ promise = Promise.all([1, 'b', obj])
442
+ expect(promise.fulfilled?).to eq(true)
443
+ expect(promise.value).to eq([1, 'b', obj])
444
+ end
445
+
446
+ it 'fulfills the result when all args are fulfilled' do
447
+ p1 = Promise.new
448
+ p2 = Promise.new
449
+
450
+ result = Promise.all([p1, p2, 3])
451
+
452
+ expect(result).to be_pending
453
+ p2.fulfill('b')
454
+ expect(result).to be_pending
455
+ p1.fulfill(:a)
456
+ expect(result).to be_fulfilled
457
+ expect(result.value).to eq([:a, 'b', 3])
458
+ end
459
+
460
+ it 'leaves result pending if only the first input arg is fulfilled' do
461
+ p1 = Promise.new
462
+ p1.fulfill('a')
463
+ p2 = Promise.new
464
+
465
+ result = Promise.all([p1, p2])
466
+
467
+ expect(result).to be_pending
468
+ p2.fulfill(:b)
469
+ expect(result).to be_fulfilled
470
+ expect(result.value).to eq(['a', :b])
471
+ end
472
+
473
+ it 'rejects the result when any args is rejected' do
474
+ p1 = Promise.new
475
+ p2 = Promise.new
476
+ reason = RuntimeError.new('p1 failed')
477
+
478
+ result = Promise.all([p1, p2])
479
+
480
+ expect(result).to be_pending
481
+ p1.reject(reason)
482
+ expect(result).to be_rejected
483
+ expect(result.reason).to eq(reason)
484
+ end
485
+
486
+ it 'returns an instance of the class it is called on' do
487
+ p1 = Promise.new
488
+
489
+ result = DelayedPromise.all([p1, 2])
490
+
491
+ expect(result).to be_an_instance_of(DelayedPromise)
492
+ p1.fulfill(1.0)
493
+ expect(result.sync).to eq([1.0, 2])
494
+ end
408
495
  end
409
496
  end
410
497
  end
metadata CHANGED
@@ -1,30 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: promise.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
5
- prerelease:
4
+ version: 0.7.0.rc1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Lars Gierth
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-01-14 00:00:00.000000000 Z
11
+ date: 2016-02-09 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rspec
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  description: Promises/A+ for Ruby
@@ -34,12 +31,11 @@ executables: []
34
31
  extensions: []
35
32
  extra_rdoc_files: []
36
33
  files:
37
- - .gitignore
38
- - .rspec
39
- - .travis.yml
34
+ - ".gitignore"
35
+ - ".rspec"
36
+ - ".travis.yml"
40
37
  - CHANGELOG.md
41
38
  - Gemfile
42
- - Gemfile.devtools
43
39
  - README.md
44
40
  - Rakefile
45
41
  - UNLICENSE
@@ -52,37 +48,39 @@ files:
52
48
  - config/yardstick.yml
53
49
  - lib/promise.rb
54
50
  - lib/promise/callback.rb
51
+ - lib/promise/group.rb
55
52
  - lib/promise/progress.rb
56
53
  - lib/promise/version.rb
57
54
  - promise.rb.gemspec
58
- - spec/promise_spec.rb
59
55
  - spec/spec_helper.rb
56
+ - spec/support/delayed_promise.rb
57
+ - spec/unit/promise_spec.rb
60
58
  homepage: https://github.com/lgierth/promise
61
59
  licenses:
62
60
  - Public Domain
61
+ metadata: {}
63
62
  post_install_message:
64
63
  rdoc_options: []
65
64
  require_paths:
66
65
  - lib
67
66
  required_ruby_version: !ruby/object:Gem::Requirement
68
- none: false
69
67
  requirements:
70
- - - ! '>='
68
+ - - ">="
71
69
  - !ruby/object:Gem::Version
72
70
  version: '0'
73
71
  required_rubygems_version: !ruby/object:Gem::Requirement
74
- none: false
75
72
  requirements:
76
- - - ! '>='
73
+ - - ">"
77
74
  - !ruby/object:Gem::Version
78
- version: '0'
75
+ version: 1.3.1
79
76
  requirements: []
80
77
  rubyforge_project:
81
- rubygems_version: 1.8.23
78
+ rubygems_version: 2.2.5
82
79
  signing_key:
83
- specification_version: 3
80
+ specification_version: 4
84
81
  summary: Ruby implementation of the Promises/A+ spec
85
82
  test_files:
86
- - spec/promise_spec.rb
87
83
  - spec/spec_helper.rb
84
+ - spec/support/delayed_promise.rb
85
+ - spec/unit/promise_spec.rb
88
86
  has_rdoc:
data/Gemfile.devtools DELETED
@@ -1,69 +0,0 @@
1
- # encoding: utf-8
2
-
3
- group :development do
4
- gem 'rake', '~> 10.1.0'
5
- gem 'rspec', '~> 2.14.1'
6
- gem 'yard', '~> 0.8.7'
7
-
8
- platform :rbx do
9
- gem 'rubysl-singleton', '~> 2.0.0'
10
- end
11
- end
12
-
13
- group :yard do
14
- gem 'kramdown', '~> 1.3.0'
15
- end
16
-
17
- group :guard do
18
- gem 'guard', '~> 2.2.4'
19
- gem 'guard-bundler', '~> 2.0.0'
20
- gem 'guard-rspec', '~> 4.2.0'
21
- gem 'guard-rubocop', '~> 1.0.0'
22
-
23
- # file system change event handling
24
- gem 'listen', '~> 2.4.0'
25
- gem 'rb-fchange', '~> 0.0.6', require: false
26
- gem 'rb-fsevent', '~> 0.9.3', require: false
27
- gem 'rb-inotify', '~> 0.9.0', require: false
28
-
29
- # notification handling
30
- gem 'libnotify', '~> 0.8.0', require: false
31
- gem 'rb-notifu', '~> 0.0.4', require: false
32
- gem 'terminal-notifier-guard', '~> 1.5.3', require: false
33
- end
34
-
35
- group :metrics do
36
- gem 'coveralls', '~> 0.7.0'
37
- gem 'flay', '~> 2.4.0'
38
- gem 'flog', '~> 4.2.0'
39
- gem 'reek', '~> 1.3.2'
40
- gem 'rubocop', '~> 0.16.0'
41
- gem 'simplecov', '~> 0.8.2'
42
- gem 'yardstick', '~> 0.9.7', git: 'https://github.com/dkubb/yardstick.git'
43
-
44
- platforms :mri do
45
- gem 'mutant', '~> 0.3.4'
46
- end
47
-
48
- platforms :ruby_19, :ruby_20 do
49
- gem 'yard-spellcheck', '~> 0.1.5'
50
- end
51
-
52
- platform :rbx do
53
- gem 'json', '~> 1.8.1'
54
- gem 'racc', '~> 1.4.10'
55
- gem 'rubysl-logger', '~> 2.0.0'
56
- gem 'rubysl-open-uri', '~> 2.0.0'
57
- gem 'rubysl-prettyprint', '~> 2.0.2'
58
- end
59
- end
60
-
61
- group :benchmarks do
62
- gem 'rbench', '~> 0.2.3'
63
- end
64
-
65
- platform :jruby do
66
- group :jruby do
67
- gem 'jruby-openssl', '~> 0.8.5'
68
- end
69
- end