promise.rb 0.1.0

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.
@@ -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: