promise.rb 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -3,11 +3,11 @@ rvm:
3
3
  - 1.9.3
4
4
  - 2.0.0
5
5
  - jruby-19mode
6
- - rbx-19mode
6
+ - rbx
7
7
  - ruby-head
8
8
  - jruby-head
9
9
  matrix:
10
10
  allow_failures:
11
11
  - rvm: ruby-head
12
12
  - rvm: jruby-head
13
- script: bundle exec rake ci:metrics -t
13
+ script: bundle exec rake -t metrics:coverage ci
data/Gemfile CHANGED
@@ -9,5 +9,12 @@ gem 'fuubar', git: 'https://github.com/lgierth/fuubar.git',
9
9
  ref: 'static-percentage'
10
10
  gem 'awesome_print'
11
11
 
12
+ platform :rbx do
13
+ gem 'rubysl', '~> 2.0'
14
+ gem 'rubysl-json', '~> 2.0'
15
+ gem 'rubinius', '~> 2.0'
16
+ gem 'racc'
17
+ end
18
+
12
19
  # Added by devtools
13
20
  eval_gemfile 'Gemfile.devtools'
data/README.md CHANGED
@@ -1,4 +1,90 @@
1
- promise
2
- =======
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)
3
2
 
4
- Promises/A+ for Ruby
3
+ Ruby implementation of the [Promises/A+ spec](http://promisesaplus.com/).
4
+ 100% mutation coverage, tested on 1.9, 2.0, Rubinius, and JRuby.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'promise.rb'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install promise.rb
19
+
20
+ ## Usage
21
+
22
+ promise.rb doesn't come with a way of scheduling callback dispatch.
23
+
24
+ ```ruby
25
+ require 'promise'
26
+
27
+ class MyPromise < Promise
28
+ def defer(callback, arg)
29
+ callback.dispatch(arg)
30
+ end
31
+ end
32
+ ```
33
+
34
+ The above scheduling mechanism violates the following section of the spec:
35
+
36
+ > onFulfilled or onRejected must not be called until the execution context
37
+ > stack contains only platform code.
38
+
39
+ Compliance can be achieved, for example, by running an event reactor like
40
+ EventMachine:
41
+
42
+ ```ruby
43
+ require 'promise'
44
+ require 'eventmachine'
45
+
46
+ class MyPromise < Promise
47
+ def defer(callback, arg)
48
+ EM.next_tick { callback.dispatch(arg) }
49
+ end
50
+ end
51
+ ```
52
+
53
+ Now you can create MyPromise objects, and fullfil (or reject) them, as well as
54
+ add callbacks to them:
55
+
56
+ ```ruby
57
+ def nonblocking_stuff
58
+ promise = MyPromise.new
59
+ EM.next_tick { promise.fulfill('value') }
60
+ promise
61
+ end
62
+
63
+ nonblocking_stuff.then { |value| p value }
64
+ nonblocking_stuff.then(proc { |value| p value })
65
+ ```
66
+
67
+ Rejection works similarly:
68
+
69
+ ```ruby
70
+ def failing_stuff
71
+ promise = MyPromise.new
72
+ EM.next_tick { promise.reject('reason') }
73
+ promise
74
+ end
75
+
76
+ failing_stuff.then(proc { |value| }, proc { |reason| p reason })
77
+ ```
78
+
79
+ ## License
80
+
81
+ Hatetepe is licensed under the [MIT License](http://opensource.org/licenses/MIT).
82
+ See LICENSE.txt for details.
83
+
84
+ ## Contributing
85
+
86
+ 1. Fork it
87
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
88
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
89
+ 4. Push to the branch (`git push origin my-new-feature`)
90
+ 5. Create new Pull Request
data/config/flay.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  ---
2
- threshold: 12
2
+ threshold: 14
3
3
  total_score: 49
data/config/reek.yml CHANGED
@@ -57,7 +57,7 @@ TooManyInstanceVariables:
57
57
  TooManyMethods:
58
58
  enabled: true
59
59
  exclude: []
60
- max_methods: 11
60
+ max_methods: 13
61
61
  TooManyStatements:
62
62
  enabled: true
63
63
  exclude:
data/lib/promise.rb CHANGED
@@ -34,14 +34,20 @@ class Promise
34
34
  next_promise
35
35
  end
36
36
 
37
- def fulfill(value)
37
+ def sync
38
+ wait if pending?
39
+ fail reason if rejected?
40
+ value
41
+ end
42
+
43
+ def fulfill(value = nil)
38
44
  dispatch(@on_fulfill, value) do
39
45
  @state = :fulfilled
40
46
  @value = value
41
47
  end
42
48
  end
43
49
 
44
- def reject(reason)
50
+ def reject(reason = nil)
45
51
  dispatch(@on_reject, reason) do
46
52
  @state = :rejected
47
53
  @reason = reason
@@ -61,7 +67,7 @@ class Promise
61
67
  if pending?
62
68
  yield
63
69
  arg.freeze
64
- callbacks.each { |callback| defer(callback, arg) }
70
+ callbacks.each { |callback| dispatch!(callback, arg) }
65
71
  end
66
72
 
67
73
  # Callback#assume_state uses #dispatch as returned_promise's on_fulfill
@@ -74,15 +80,19 @@ class Promise
74
80
 
75
81
  def maybe_dispatch(fulfill_callback, reject_callback)
76
82
  if fulfilled?
77
- defer(fulfill_callback, value)
83
+ dispatch!(fulfill_callback, value)
78
84
  end
79
85
 
80
86
  if rejected?
81
- defer(reject_callback, reason)
87
+ dispatch!(reject_callback, reason)
82
88
  end
83
89
  end
84
90
 
85
- def defer(callback, arg)
86
- callback.dispatch(arg)
91
+ def dispatch!(callback, arg)
92
+ defer { callback.dispatch(arg) }
93
+ end
94
+
95
+ def defer
96
+ yield
87
97
  end
88
98
  end
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  class Promise
4
- VERSION = '0.2.1'
4
+ VERSION = '0.3.0'
5
5
  end
data/spec/promise_spec.rb CHANGED
@@ -7,8 +7,12 @@ describe Promise do
7
7
 
8
8
  let(:value) { double('value') }
9
9
  let(:other_value) { double('other_value') }
10
- let(:reason) { double('reason') }
11
- let(:other_reason) { double('other_reason') }
10
+ let(:reason) do
11
+ StandardError.new('reason').tap { |ex| ex.set_backtrace(caller) }
12
+ end
13
+ let(:other_reason) do
14
+ StandardError.new('other_reason').tap { |ex| ex.set_backtrace(caller) }
15
+ end
12
16
 
13
17
  describe '3.1.1 pending' do
14
18
  it 'transitions to fulfilled' do
@@ -337,11 +341,39 @@ describe Promise do
337
341
  it 'does not return anything' do
338
342
  expect(subject.fulfill(nil)).to eq(nil)
339
343
  end
344
+
345
+ it 'does not require a value' do
346
+ subject.fulfill
347
+ expect(subject.value).to be(nil)
348
+ end
340
349
  end
341
350
 
342
351
  describe '#reject' do
343
352
  it 'does not return anything' do
344
353
  expect(subject.reject(nil)).to eq(nil)
345
354
  end
355
+
356
+ it 'does not require a reason' do
357
+ subject.reject
358
+ expect(subject.reason).to be(nil)
359
+ end
360
+ end
361
+
362
+ describe '#sync' do
363
+ it 'waits for fulfillment' do
364
+ allow(subject).to receive(:wait) { subject.fulfill(value) }
365
+ expect(subject.sync).to be(value)
366
+ end
367
+
368
+ it 'waits for rejection' do
369
+ allow(subject).to receive(:wait) { subject.reject(reason) }
370
+ expect { subject.sync }.to raise_error(reason)
371
+ end
372
+
373
+ it 'waits if pending' do
374
+ subject.fulfill(value)
375
+ expect(subject).not_to receive(:wait)
376
+ expect(subject.sync).to be(value)
377
+ end
346
378
  end
347
379
  end
metadata CHANGED
@@ -1,18 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: promise.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Lars Gierth
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2013-10-19 00:00:00.000000000 Z
12
+ date: 2013-12-07 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: rspec
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
19
  - - ! '>='
18
20
  - !ruby/object:Gem::Version
@@ -20,6 +22,7 @@ dependencies:
20
22
  type: :development
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
27
  - - ! '>='
25
28
  - !ruby/object:Gem::Version
@@ -56,26 +59,27 @@ files:
56
59
  homepage: https://github.com/lgierth/promise
57
60
  licenses:
58
61
  - MIT
59
- metadata: {}
60
62
  post_install_message:
61
63
  rdoc_options: []
62
64
  require_paths:
63
65
  - lib
64
66
  required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
65
68
  requirements:
66
69
  - - ! '>='
67
70
  - !ruby/object:Gem::Version
68
71
  version: '0'
69
72
  required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
70
74
  requirements:
71
75
  - - ! '>='
72
76
  - !ruby/object:Gem::Version
73
77
  version: '0'
74
78
  requirements: []
75
79
  rubyforge_project:
76
- rubygems_version: 2.1.5
80
+ rubygems_version: 1.8.23
77
81
  signing_key:
78
- specification_version: 4
82
+ specification_version: 3
79
83
  summary: Promises/A+ for Ruby
80
84
  test_files:
81
85
  - spec/promise_spec.rb
checksums.yaml DELETED
@@ -1,15 +0,0 @@
1
- ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NGFmYWVmYmRmNWEyMjkyYmMwY2Y0NjA2OWE1YzBjZTM2NTlkNzFmMA==
5
- data.tar.gz: !binary |-
6
- ODg2NzU0ZjFmZTZjY2YzODFlYzJiYzUwMWE1OGQ2NWE4MGVlYTM0ZQ==
7
- SHA512:
8
- metadata.gz: !binary |-
9
- NzA4MmZhMGJiNTliYWIxZjQ5NmY1YTc2NTE5ZTQzY2Y1MTEzNzEyZGVjY2Yy
10
- MjdkODk5ZGYxMjMwMjZiYjUzODdmZmY2YzIxNDk1M2Y3ZWQ1M2RkMjdhY2Jl
11
- MTRhNzY2M2E4NWExNjY1OTg3OTYzYmI2NzY0MzZlNDE3ZmI2YWY=
12
- data.tar.gz: !binary |-
13
- N2MxOTAzZWMzMmUyNGY4MTVhODEwZWYwODNhNmRkYmMwYjU1MWNjNTI3ZGQz
14
- MTZhZDliZWQyZWRjNmVkN2E4MDA5YzhhZjBmMDkxMTYxNTQzYTRkZWU3N2Ix
15
- MTgyZGMyZTNiMjJiMTczZDRmNTA4ZjEzMDE2MDZhMjc4YmI4ZWY=