promise.rb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MDc3Mjc3N2NjZGNlYzFjOGFkMGNmNTRmZTI3ZDYwZjJkMWYzMTM4YQ==
5
+ data.tar.gz: !binary |-
6
+ MTE2NTg0ZGZhZDNhNjMwZjgzOWRhODFlMjU0MjhjOTdjOGQ1NzExZg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ M2Q4ODVmZGUyZjRkNjhkOTJiMTM2Y2E5YTAzZDkwMjQ1OTQ1ODkyNDYzN2Zj
10
+ ZjA3ZjI5MzBlNDQ4NjljMDliMjlhMzFiMGVhYWU3NjQwOTgyMGZlYWVkMTYz
11
+ YTY0MjQxOTk4Y2RmMjJiN2M1YzU3NDEzNGYyYjA4NGZjMzkxMzc=
12
+ data.tar.gz: !binary |-
13
+ OGFlMjE0YzRhYTIwYzczODI4YThlNDE3YjQ3MDQ2NWFlOWQ5YjAzNjBkMjY5
14
+ ZDNlMWU2OGFhNDFjZGQ1MDE5YjY1MmY4NmIwNTI0YzY0MDFmMTI2YzE1Yjg4
15
+ ZThlOWM2Y2QyMGFhOTg3M2FiMjRiMDk3MmYwMTQyOTBlYzEzNmE=
@@ -0,0 +1,9 @@
1
+ .project
2
+ .bundle
3
+ .rvmrc
4
+ Gemfile.lock
5
+ pkg/
6
+ *.rbc
7
+ .yardoc/
8
+ doc/
9
+ coverage/
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --order rand
2
+ --color
3
+ --format Fuubar
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ before_script: git checkout master
5
+ script: bundle exec rake ci -t
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ ruby '1.9.3'
6
+
7
+ gemspec
8
+
9
+ gem 'devtools', git: 'https://github.com/lgierth/devtools.git',
10
+ ref: 'branch-detection2'
11
+ gem 'fuubar', git: 'https://github.com/lgierth/fuubar.git',
12
+ ref: 'static-percentage'
13
+ gem 'awesome_print'
14
+
15
+ # Added by devtools
16
+ eval_gemfile 'Gemfile.devtools'
@@ -0,0 +1,55 @@
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
+ end
8
+
9
+ group :yard do
10
+ gem 'kramdown', '~> 1.2.0'
11
+ end
12
+
13
+ group :guard do
14
+ gem 'guard', '~> 1.8.1'
15
+ gem 'guard-bundler', '~> 1.0.0'
16
+ gem 'guard-rspec', '~> 3.0.2'
17
+ gem 'guard-rubocop', '~> 0.2.0'
18
+ gem 'guard-mutant', '~> 0.0.1'
19
+
20
+ # file system change event handling
21
+ gem 'listen', '~> 1.3.0'
22
+ gem 'rb-fchange', '~> 0.0.6', require: false
23
+ gem 'rb-fsevent', '~> 0.9.3', require: false
24
+ gem 'rb-inotify', '~> 0.9.0', require: false
25
+
26
+ # notification handling
27
+ gem 'libnotify', '~> 0.8.0', require: false
28
+ gem 'rb-notifu', '~> 0.0.4', require: false
29
+ gem 'terminal-notifier-guard', '~> 1.5.3', require: false
30
+ end
31
+
32
+ group :metrics do
33
+ gem 'coveralls', '~> 0.6.7'
34
+ gem 'flay', '~> 2.4.0'
35
+ gem 'flog', '~> 4.1.1'
36
+ gem 'reek', '~> 1.3.2'
37
+ gem 'rubocop', '~> 0.12.0'
38
+ gem 'simplecov', '~> 0.7.1'
39
+ gem 'yardstick', '~> 0.9.7', git: 'https://github.com/dkubb/yardstick.git'
40
+
41
+ platforms :ruby_19, :ruby_20 do
42
+ gem 'mutant', git: 'https://github.com/mbj/mutant.git'
43
+ gem 'yard-spellcheck', '~> 0.1.5'
44
+ end
45
+ end
46
+
47
+ group :benchmarks do
48
+ gem 'rbench', '~> 0.2.3'
49
+ end
50
+
51
+ platform :jruby do
52
+ group :jruby do
53
+ gem 'jruby-openssl', '~> 0.8.5'
54
+ end
55
+ end
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>
@@ -0,0 +1,4 @@
1
+ promise
2
+ =======
3
+
4
+ Promises/A+ for Ruby
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ # Added by devtools
6
+ require 'devtools'
7
+ Devtools.init_rake_tasks
@@ -0,0 +1,2 @@
1
+ ---
2
+ unit_test_timeout: 0.1
@@ -0,0 +1,3 @@
1
+ ---
2
+ threshold: 12
3
+ total_score: 49
@@ -0,0 +1,2 @@
1
+ ---
2
+ threshold: 7.7
@@ -0,0 +1,3 @@
1
+ ---
2
+ name: promise
3
+ namespace: Promise
@@ -0,0 +1,103 @@
1
+ ---
2
+ Attribute:
3
+ enabled: false
4
+ exclude: []
5
+ BooleanParameter:
6
+ enabled: true
7
+ exclude: []
8
+ ClassVariable:
9
+ enabled: true
10
+ exclude: []
11
+ ControlParameter:
12
+ enabled: true
13
+ exclude: []
14
+ DataClump:
15
+ enabled: true
16
+ exclude: []
17
+ max_copies: 2
18
+ min_clump_size: 2
19
+ DuplicateMethodCall:
20
+ enabled: true
21
+ exclude: []
22
+ max_calls: 1
23
+ allow_calls: []
24
+ FeatureEnvy:
25
+ enabled: false
26
+ exclude: []
27
+ IrresponsibleModule:
28
+ enabled: false
29
+ exclude: []
30
+ LongParameterList:
31
+ enabled: true
32
+ exclude: []
33
+ max_params: 2
34
+ overrides:
35
+ initialize:
36
+ max_params: 3
37
+ LongYieldList:
38
+ enabled: true
39
+ exclude: []
40
+ max_params: 2
41
+ NestedIterators:
42
+ enabled: true
43
+ exclude: []
44
+ max_allowed_nesting: 1
45
+ ignore_iterators: []
46
+ NilCheck:
47
+ enabled: true
48
+ exclude: []
49
+ RepeatedConditional:
50
+ enabled: true
51
+ exclude: []
52
+ max_ifs: 2
53
+ TooManyInstanceVariables:
54
+ enabled: true
55
+ exclude: []
56
+ max_instance_variables: 6
57
+ TooManyMethods:
58
+ enabled: true
59
+ exclude: []
60
+ max_methods: 11
61
+ TooManyStatements:
62
+ enabled: true
63
+ exclude:
64
+ - each
65
+ max_statements: 4
66
+ UncommunicativeMethodName:
67
+ enabled: true
68
+ exclude: []
69
+ reject:
70
+ - !ruby/regexp /^[a-z]$/
71
+ - !ruby/regexp /[0-9]$/
72
+ - !ruby/regexp /[A-Z]/
73
+ accept: []
74
+ UncommunicativeModuleName:
75
+ enabled: true
76
+ exclude: []
77
+ reject:
78
+ - !ruby/regexp /^.$/
79
+ - !ruby/regexp /[0-9]$/
80
+ accept: []
81
+ UncommunicativeParameterName:
82
+ enabled: true
83
+ exclude: []
84
+ reject:
85
+ - !ruby/regexp /^.$/
86
+ - !ruby/regexp /[0-9]$/
87
+ - !ruby/regexp /[A-Z]/
88
+ accept: []
89
+ UncommunicativeVariableName:
90
+ enabled: true
91
+ exclude: []
92
+ reject:
93
+ - !ruby/regexp /^.$/
94
+ - !ruby/regexp /[0-9]$/
95
+ - !ruby/regexp /[A-Z]/
96
+ accept: []
97
+ UnusedParameters:
98
+ enabled: true
99
+ exclude: []
100
+ UtilityFunction:
101
+ enabled: false
102
+ exclude: []
103
+ max_helper_calls: 0
@@ -0,0 +1,58 @@
1
+ AllCops:
2
+ Includes:
3
+ - '**/*.rake'
4
+ - 'Gemfile'
5
+ - 'Gemfile.devtools'
6
+ Excludes:
7
+ - '**/vendor/**'
8
+ - '**/benchmarks/**'
9
+
10
+ # Avoid parameter lists longer than five parameters.
11
+ ParameterLists:
12
+ Max: 3
13
+ CountKeywordArgs: true
14
+
15
+ # Avoid more than `Max` levels of nesting.
16
+ BlockNesting:
17
+ Max: 3
18
+
19
+ # Align with the style guide.
20
+ CollectionMethods:
21
+ PreferredMethods:
22
+ collect: 'map'
23
+ inject: 'reduce'
24
+ find: 'detect'
25
+ find_all: 'select'
26
+
27
+ # Do not force public/protected/private keyword to be indented at the same
28
+ # level as the def keyword. My personal preference is to outdent these keywords
29
+ # because I think when scanning code it makes it easier to identify the
30
+ # sections of code and visually separate them. When the keyword is at the same
31
+ # level I think it sort of blends in with the def keywords and makes it harder
32
+ # to scan the code and see where the sections are.
33
+ AccessControl:
34
+ Enabled: false
35
+
36
+ # Limit line length
37
+ LineLength:
38
+ Max: 79
39
+
40
+ # Disable documentation checking until a class needs to be documented once
41
+ Documentation:
42
+ Enabled: false
43
+
44
+ # Do not favor modifier if/unless usage when you have a single-line body
45
+ IfUnlessModifier:
46
+ Enabled: false
47
+
48
+ # Allow case equality operator (in limited use within the specs)
49
+ CaseEquality:
50
+ Enabled: false
51
+
52
+ # Constants do not always have to use SCREAMING_SNAKE_CASE
53
+ ConstantName:
54
+ Enabled: false
55
+
56
+ # Not all trivial readers/writers can be defined with attr_* methods
57
+ TrivialAccessors:
58
+ Enabled: false
@@ -0,0 +1,2 @@
1
+ ---
2
+ threshold: 100
@@ -0,0 +1,80 @@
1
+ # encoding: utf-8
2
+
3
+ require 'promise/version'
4
+
5
+ require 'promise/callback'
6
+ require 'promise/progress'
7
+
8
+ class Promise
9
+ attr_reader :state, :value, :reason
10
+
11
+ def initialize
12
+ @state = :pending
13
+ @on_fulfill = []
14
+ @on_reject = []
15
+ end
16
+
17
+ def pending?
18
+ @state == :pending
19
+ end
20
+
21
+ def fulfilled?
22
+ @state == :fulfilled
23
+ end
24
+
25
+ def rejected?
26
+ @state == :rejected
27
+ end
28
+
29
+ def then(on_fulfill = nil, on_reject = nil)
30
+ next_promise = add_callbacks(on_fulfill, on_reject)
31
+
32
+ maybe_dispatch(@on_fulfill.last, @on_reject.last)
33
+ next_promise
34
+ end
35
+
36
+ def fulfill(value)
37
+ dispatch(@on_fulfill, value) do
38
+ @state = :fulfilled
39
+ @value = value
40
+ end
41
+ end
42
+
43
+ def reject(reason)
44
+ dispatch(@on_reject, reason) do
45
+ @state = :rejected
46
+ @reason = reason
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def add_callbacks(on_fulfill, on_reject)
53
+ next_promise = self.class.new
54
+ @on_fulfill << FulfillCallback.new(on_fulfill, next_promise)
55
+ @on_reject << RejectCallback.new(on_reject, next_promise)
56
+ next_promise
57
+ end
58
+
59
+ def dispatch(callbacks, arg)
60
+ if pending?
61
+ yield
62
+ arg.freeze
63
+ callbacks.each { |callback| defer(callback, arg) }
64
+ end
65
+ end
66
+
67
+ def maybe_dispatch(fulfill_callback, reject_callback)
68
+ if fulfilled?
69
+ defer(fulfill_callback, value)
70
+ end
71
+
72
+ if rejected?
73
+ defer(reject_callback, reason)
74
+ end
75
+ end
76
+
77
+ def defer(callback, arg)
78
+ callback.dispatch(arg)
79
+ end
80
+ end
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ class Promise
4
+ class Callback
5
+ def initialize(block, next_promise)
6
+ @block = block
7
+ @next_promise = next_promise
8
+ end
9
+
10
+ private
11
+
12
+ def execute(value)
13
+ @block.call(value)
14
+ rescue => error
15
+ @next_promise.reject(error)
16
+ end
17
+
18
+ def handle_result(result)
19
+ if Promise === result
20
+ assume_state(result)
21
+ else
22
+ @next_promise.fulfill(result)
23
+ end
24
+ end
25
+
26
+ def assume_state(returned_promise)
27
+ on_fulfill = @next_promise.method(:fulfill)
28
+ on_reject = @next_promise.method(:reject)
29
+
30
+ returned_promise.then(on_fulfill, on_reject)
31
+ end
32
+ end
33
+
34
+ class FulfillCallback < Callback
35
+ def dispatch(value)
36
+ if @block
37
+ result = execute(value)
38
+ handle_result(result)
39
+ else
40
+ handle_result(value)
41
+ end
42
+ end
43
+ end
44
+
45
+ class RejectCallback < Callback
46
+ def dispatch(reason)
47
+ if @block
48
+ result = execute(reason)
49
+ handle_result(result)
50
+ else
51
+ @next_promise.reject(reason)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+
3
+ class Promise
4
+ module Progress
5
+ def on_progress(block)
6
+ (@on_progress ||= []) << block
7
+ end
8
+
9
+ def progress(status)
10
+ if pending? && @on_progress
11
+ @on_progress.each { |block| block.call(status) }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ class Promise
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'promise/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'promise.rb'
9
+ spec.version = Promise::VERSION
10
+ spec.authors = ['Lars Gierth']
11
+ spec.email = ['lars.gierth@gmail.com']
12
+ spec.description = %q{Promises/A+ for Ruby}
13
+ spec.summary = %q{Promises/A+ for Ruby}
14
+ spec.homepage = 'https://github.com/lgierth/promise'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.test_files = spec.files.grep(%r{^spec/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'rspec'
22
+ end
@@ -0,0 +1,331 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Promise do
6
+ subject { Promise.new }
7
+
8
+ let(:value) { double('value') }
9
+ let(:other_value) { double('other_value') }
10
+ let(:reason) { double('reason') }
11
+ let(:other_reason) { double('other_reason') }
12
+
13
+ describe '#state' do
14
+ describe '3.1.1 pending' do
15
+ it 'transitions to fulfilled' do
16
+ subject.fulfill(value)
17
+ expect(subject.state).to eq(:fulfilled)
18
+ end
19
+
20
+ it 'transitions to rejected' do
21
+ subject.reject(reason)
22
+ expect(subject.state).to eq(:rejected)
23
+ end
24
+ end
25
+
26
+ describe '3.1.2 fulfilled' do
27
+ it 'does not transition to other states' do
28
+ subject.fulfill(value)
29
+ subject.reject(reason)
30
+ expect(subject.state).to eq(:fulfilled)
31
+ end
32
+
33
+ it 'has an immutable value' do
34
+ subject.fulfill(value)
35
+ expect(subject.value).to eq(value)
36
+
37
+ subject.fulfill(other_value)
38
+ expect(subject.value).to eq(value)
39
+
40
+ expect(subject.value).to be_frozen
41
+ end
42
+ end
43
+
44
+ describe '3.1.3 rejected' do
45
+ it 'does not transition to other states' do
46
+ subject.reject(reason)
47
+ subject.fulfill(value)
48
+ expect(subject.state).to eq(:rejected)
49
+ end
50
+
51
+ it 'has an immutable reason' do
52
+ subject.reject(reason)
53
+ expect(subject.reason).to eq(reason)
54
+
55
+ subject.reject(other_reason)
56
+ expect(subject.reason).to eq(reason)
57
+
58
+ expect(subject.reason).to be_frozen
59
+ end
60
+ end
61
+ end
62
+
63
+ describe '#then' do
64
+ describe '3.2.1 on_fulfill' do
65
+ it 'is optional' do
66
+ subject.then
67
+ subject.fulfill(value)
68
+ end
69
+ end
70
+
71
+ describe '3.2.1 on_reject' do
72
+ it 'is optional' do
73
+ subject.then(proc { |_| })
74
+ subject.reject(reason)
75
+ end
76
+ end
77
+
78
+ describe '3.2.2 on_fulfill' do
79
+ it 'is called after promise is fulfilled' do
80
+ state = nil
81
+ subject.then(proc { |_| state = subject.state })
82
+
83
+ subject.fulfill(value)
84
+ expect(state).to eq(:fulfilled)
85
+ end
86
+
87
+ it 'is called with fulfillment value' do
88
+ result = nil
89
+ subject.then(proc { |val| result = val })
90
+
91
+ subject.fulfill(value)
92
+ expect(result).to eq(value)
93
+ end
94
+
95
+ it 'is called not more than once' do
96
+ called = 0
97
+ subject.then(proc { |_| called += 1 })
98
+
99
+ subject.fulfill(value)
100
+ subject.fulfill(value)
101
+ expect(called).to eq(1)
102
+ end
103
+
104
+ it 'is not called if on_reject has been called' do
105
+ called = false
106
+ subject.then(proc { |_| called = true })
107
+
108
+ subject.reject(reason)
109
+ expect(called).to eq(false)
110
+ end
111
+ end
112
+
113
+ describe '3.2.3 on_reject' do
114
+ it 'is called after promise is rejected' do
115
+ state = nil
116
+ subject.then(nil, proc { |_| state = subject.state })
117
+
118
+ subject.reject(reason)
119
+ expect(state).to eq(:rejected)
120
+ end
121
+
122
+ it 'is called with rejection reason' do
123
+ result = nil
124
+ subject.then(nil, proc { |reas| result = reas })
125
+
126
+ subject.reject(reason)
127
+ expect(result).to eq(reason)
128
+ end
129
+
130
+ it 'is called not more than once' do
131
+ called = 0
132
+ subject.then(nil, proc { |_| called += 1 })
133
+
134
+ subject.reject(reason)
135
+ subject.reject(reason)
136
+ expect(called).to eq(1)
137
+ end
138
+
139
+ it 'is not called if on_fulfill has been called' do
140
+ called = false
141
+ subject.then(nil, proc { |_| called = true })
142
+
143
+ subject.fulfill(value)
144
+ expect(called).to eq(false)
145
+ end
146
+ end
147
+
148
+ describe '3.2.4' do
149
+ it 'returns before on_fulfill or on_reject is called' do
150
+ pending
151
+ end
152
+ end
153
+
154
+ describe '3.2.5' do
155
+ it 'calls multiple on_fulfill callbacks in order of definition' do
156
+ order = []
157
+ on_fulfill = proc do |i, val|
158
+ order << i
159
+ expect(val).to eq(value)
160
+ end
161
+
162
+ subject.then(on_fulfill.curry[1])
163
+ subject.then(on_fulfill.curry[2])
164
+
165
+ subject.fulfill(value)
166
+ subject.then(on_fulfill.curry[3])
167
+
168
+ expect(order).to eq([1, 2, 3])
169
+ end
170
+
171
+ it 'calls multiple on_reject callbacks in order of definition' do
172
+ order = []
173
+ on_reject = proc do |i, reas|
174
+ order << i
175
+ expect(reas).to eq(reason)
176
+ end
177
+
178
+ subject.then(nil, on_reject.curry[1])
179
+ subject.then(nil, on_reject.curry[2])
180
+
181
+ subject.reject(reason)
182
+ subject.then(nil, on_reject.curry[3])
183
+
184
+ expect(order).to eq([1, 2, 3])
185
+ end
186
+ end
187
+
188
+ describe '3.2.6' do
189
+ let(:error) { StandardError.new }
190
+ let(:returned_promise) { Promise.new }
191
+
192
+ it 'returns promise2' do
193
+ expect(subject.then).to be_a(Promise)
194
+ expect(subject.then).not_to eq(subject)
195
+ end
196
+
197
+ it 'fulfills promise2 with value returned by on_fulfill' do
198
+ promise2 = subject.then(proc { |_| other_value })
199
+ subject.fulfill(value)
200
+
201
+ expect(promise2).to be_fulfilled
202
+ expect(promise2.value).to eq(other_value)
203
+ end
204
+
205
+ it 'fulfills promise2 with value returned by on_reject' do
206
+ promise2 = subject.then(nil, proc { |_| other_value })
207
+ subject.reject(reason)
208
+
209
+ expect(promise2).to be_fulfilled
210
+ expect(promise2.value).to eq(other_value)
211
+ end
212
+
213
+ it 'rejects promise2 with error raised by on_fulfill' do
214
+ promise2 = subject.then(proc { |_| raise error })
215
+ subject.fulfill(value)
216
+
217
+ expect(promise2).to be_rejected
218
+ expect(promise2.reason).to eq(error)
219
+ end
220
+
221
+ it 'rejects promise2 with error raised by on_reject' do
222
+ promise2 = subject.then(nil, proc { |_| raise error })
223
+ subject.reject(reason)
224
+
225
+ expect(promise2).to be_rejected
226
+ expect(promise2.reason).to eq(error)
227
+ end
228
+
229
+ describe 'on_fulfill returns promise' do
230
+ it 'makes promise2 assume fulfilled state of returned promise' do
231
+ promise2 = subject.then(proc { |_| returned_promise })
232
+
233
+ subject.fulfill(value)
234
+ expect(promise2).to be_pending
235
+
236
+ returned_promise.fulfill(other_value)
237
+ expect(promise2).to be_fulfilled
238
+ expect(promise2.value).to eq(other_value)
239
+ end
240
+
241
+ it 'makes promise2 assume rejected state of returned promise' do
242
+ promise2 = subject.then(proc { |_| returned_promise })
243
+
244
+ subject.fulfill(value)
245
+ expect(promise2).to be_pending
246
+
247
+ returned_promise.reject(other_reason)
248
+ expect(promise2).to be_rejected
249
+ expect(promise2.reason).to eq(other_reason)
250
+ end
251
+ end
252
+
253
+ describe 'on_reject returns promise' do
254
+ it 'makes promise2 assume fulfilled state of returned promise' do
255
+ promise2 = subject.then(nil, proc { |_| returned_promise })
256
+
257
+ subject.reject(reason)
258
+ expect(promise2).to be_pending
259
+
260
+ returned_promise.fulfill(other_value)
261
+ expect(promise2).to be_fulfilled
262
+ expect(promise2.value).to eq(other_value)
263
+ end
264
+
265
+ it 'makes promise2 assume rejected state of returned promise' do
266
+ promise2 = subject.then(nil, proc { |_| returned_promise })
267
+
268
+ subject.reject(reason)
269
+ expect(promise2).to be_pending
270
+
271
+ returned_promise.reject(other_reason)
272
+ expect(promise2).to be_rejected
273
+ expect(promise2.reason).to eq(other_reason)
274
+ end
275
+ end
276
+
277
+ describe 'without on_fulfill' do
278
+ it 'fulfill promise2 with fulfillment value' do
279
+ promise2 = subject.then
280
+ subject.fulfill(value)
281
+
282
+ expect(promise2).to be_fulfilled
283
+ expect(promise2.value).to eq(value)
284
+ end
285
+ end
286
+
287
+ describe 'without on_reject' do
288
+ it 'rejects promise2 with rejection reason' do
289
+ promise2 = subject.then
290
+ subject.reject(reason)
291
+
292
+ expect(promise2).to be_rejected
293
+ expect(promise2.reason).to eq(reason)
294
+ end
295
+ end
296
+ end
297
+ end
298
+
299
+ describe '#progress' do
300
+ let(:klass) do
301
+ Class.new(Promise) { include Promise::Progress }
302
+ end
303
+ let(:subject) { klass.new }
304
+
305
+ let(:status) { double('status') }
306
+
307
+ it 'calls the callbacks in the order of calls to #on_progress' do
308
+ order = []
309
+ block = proc do |i, stat|
310
+ order << i
311
+ expect(stat).to eq(status)
312
+ end
313
+
314
+ subject.on_progress(block.curry[1])
315
+ subject.on_progress(block.curry[2])
316
+ subject.on_progress(block.curry[3])
317
+ subject.progress(status)
318
+
319
+ expect(order).to eq([1, 2, 3])
320
+ end
321
+
322
+ it 'does not call back unless pending' do
323
+ called = false
324
+ subject.on_progress(proc { |_| called = true })
325
+ subject.fulfill(value)
326
+
327
+ subject.progress(status)
328
+ expect(called).to eq(false)
329
+ end
330
+ end
331
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ if ENV['COVERAGE'] == 'true'
4
+ require 'simplecov'
5
+ require 'coveralls'
6
+
7
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
8
+ SimpleCov::Formatter::HTMLFormatter,
9
+ Coveralls::SimpleCov::Formatter
10
+ ]
11
+
12
+ SimpleCov.start do
13
+ command_name 'spec:unit'
14
+
15
+ add_filter 'config'
16
+ add_filter 'spec'
17
+ end
18
+ end
19
+
20
+ require 'promise'
21
+
22
+ require 'awesome_print'
23
+ require 'devtools/spec_helper'
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: promise.rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Lars Gierth
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Promises/A+ for Ruby
28
+ email:
29
+ - lars.gierth@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - .gitignore
35
+ - .rspec
36
+ - .travis.yml
37
+ - Gemfile
38
+ - Gemfile.devtools
39
+ - LICENSE
40
+ - README.md
41
+ - Rakefile
42
+ - config/devtools.yml
43
+ - config/flay.yml
44
+ - config/flog.yml
45
+ - config/mutant.yml
46
+ - config/reek.yml
47
+ - config/rubocop.yml
48
+ - config/yardstick.yml
49
+ - lib/promise.rb
50
+ - lib/promise/callback.rb
51
+ - lib/promise/progress.rb
52
+ - lib/promise/version.rb
53
+ - promise.rb.gemspec
54
+ - spec/promise_spec.rb
55
+ - spec/spec_helper.rb
56
+ homepage: https://github.com/lgierth/promise
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 2.1.1
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Promises/A+ for Ruby
80
+ test_files:
81
+ - spec/promise_spec.rb
82
+ - spec/spec_helper.rb
83
+ has_rdoc: