rpromise 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1262691501de1334a31235ac093581f219d4cc44
4
- data.tar.gz: d9557239fef9c4d00dd102b48b9f4cc0cb02de26
3
+ metadata.gz: f827fadaed28b188d96a603fd46c933e06f52e6f
4
+ data.tar.gz: b76fde2e1c6388e4ca470e4eb8a0a28f779fa9cd
5
5
  SHA512:
6
- metadata.gz: 3b1e40b5e717eaaf25c8baf8f22c627f75d24e8651a6192a892ac8e39378101e8db0e77c4fc3bc1b37164aec58512f3c03cfa4e455fe0311553fb5150b11241c
7
- data.tar.gz: 612ef5ff492f18d43591b95aaaddd81c9b1e5bf9e60546dd5659da0cb3040adab5b9da1a4fde069cff66cbe6230e6c32e456fc1b2ff75d359d04af327d3b7e12
6
+ metadata.gz: b8b692957a78f776851bb84e5071304b7dd4a9666a9d8b44dd5254e336e7be3ebd82344ac60d98029961ca2cbcbe205ae97e04517d657a9a2c197a65f0e449cc
7
+ data.tar.gz: e968d06a23ee237efa58935cb4e5b80130c86821c52f2ab1f2cd2055f2fa8c8e87b4103e798eea821eaea5971eedb24d1e11f68f33312d7b9244c0293ed7fd4b
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Rpromise
2
2
 
3
3
  [![Build Status](https://travis-ci.org/samuelmolinari/rpromise.svg?branch=master)](https://travis-ci.org/samuelmolinari/rpromise)
4
+ [![Gem Version](https://badge.fury.io/rb/rpromise.svg)](http://badge.fury.io/rb/rpromise)
5
+ [![Code Climate](https://codeclimate.com/github/samuelmolinari/rpromise/badges/gpa.svg)](https://codeclimate.com/github/samuelmolinari/rpromise)
6
+ [![Test Coverage](https://codeclimate.com/github/samuelmolinari/rpromise/badges/coverage.svg)](https://codeclimate.com/github/samuelmolinari/rpromise)
4
7
 
5
8
  ## Installation
6
9
 
@@ -18,50 +21,120 @@ Or install it yourself as:
18
21
 
19
22
  ## Usage
20
23
 
24
+ ### Create a promise
25
+
21
26
  ```ruby
22
27
 
23
28
  class Task
24
29
 
25
30
  def async
26
- return ::Rpromise.new do |resolve, reject|
27
- Thread.new do
28
- sleep(1)
29
- value = Random.rand * 10
30
-
31
- if value > 5
32
- resolve.call(value)
33
- else
34
- reject.call('Oh boy, what have you done')
35
- end
31
+ ::Rpromise.new do |resolve, reject|
32
+ sleep(1)
33
+ value = Random.rand * 10
34
+
35
+ if value > 5
36
+ resolve.call(value)
37
+ else
38
+ reject.call('Oh boy, what have you done')
36
39
  end
37
40
  end
38
41
  end
39
42
 
40
43
  end
41
44
 
42
- on_resolve = lambda do |value|
45
+ ```
43
46
 
44
- puts value
47
+ ### Callbacks
45
48
 
46
- return ::Rpromise.new do |resolve, reject|
47
- Thread.new do
48
- sleep(1)
49
- # Do an async task
50
- resolve.call(value + 10)
51
- end
52
- end
49
+ #### Using method
50
+
51
+ You can use existing methods as callbacks:
52
+
53
+ ```ruby
54
+ def on_resolve(value)
55
+ # Do something with the returned value from the promise
53
56
  end
54
57
 
55
- on_reject = lambda do |error|
56
- puts error
58
+ Task.new.async.then(method(:on_resolve))
59
+ ```
60
+
61
+ #### Using proc
62
+
63
+ You can use ``Proc`` as a callback
64
+
65
+ ```ruby
66
+ Task.new.async.then(Proc.new do |value|
67
+ # Do something
68
+ end)
69
+ ```
70
+
71
+ #### Using lambda
72
+
73
+ You can use ``lambda`` as a callback
74
+
75
+ ```ruby
76
+ Task.new.async.then(lambda do |value|
77
+ # Do something
78
+ end)
79
+ ```
80
+
81
+ ### Chained promises
82
+
83
+ ```ruby
84
+ Rpromise.new do |resolve, reject|
85
+
86
+ resolve.call(5)
87
+
88
+ end.then(lambda do |value|
89
+
90
+ # value == 5
91
+ value + 10
92
+
93
+ end).then(lambda do |value|
94
+
95
+ # value == 15
96
+ Rpromise.new do |resolve, reject|
97
+ resolve.call(value / 5)
98
+ end
99
+
100
+ end).then(lambda do |value|
101
+
102
+ # value == 3
103
+
104
+ end)
105
+ ```
106
+
107
+ #### Error handling
108
+
109
+ You can handle errors raised during the async task by passing a callback block as second argument
110
+
111
+ ```ruby
112
+ p = Rpromise.new do |resolve, reject|
113
+ raise 'Oopss'
57
114
  end
58
115
 
59
- Task.new.async
60
- .then(on_resolve, on_reject)
61
- .then(Proc.new do |value_plus_10|
62
- puts value_plus_10 # Returned value from the previous ``then`` promise resolved value
63
- end)
116
+ p.then(nil, lambda do |err|
117
+ err.message # => "Oopss"
118
+ end)
119
+ ```
120
+
121
+ or you can handle the exceptions yourself by making use of the reject callback
122
+
123
+ ```ruby
124
+ p = Rpromise.new do |resolve, reject|
125
+ begin
126
+ method_that_could_raise_an_exception()
127
+ resolve('Everything went ok')
128
+ rescue Exception => e
129
+ reject.call('Oh dear, what have I done?!')
130
+ end
131
+ end
64
132
 
133
+ p.then(lambda do |message|
134
+ # Called if the promise executed without exceptions
135
+ end, lambda do |err|
136
+ # Called if the promise has raised an exception
137
+ end)
65
138
  ```
66
139
 
67
140
  ## Contributing
@@ -1,3 +1,3 @@
1
1
  class Rpromise
2
- VERSION = "0.0.5"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/rpromise.rb CHANGED
@@ -9,12 +9,18 @@ class Rpromise
9
9
 
10
10
  Handler = Struct.new(:on_resolved, :on_rejected, :resolve, :reject)
11
11
 
12
- attr_reader :state
12
+ attr_reader :state, :thread
13
13
 
14
14
  def initialize()
15
15
  @state = State::PENDING
16
16
  @defered = nil
17
- yield(method(:resolve!), method(:reject!),self)
17
+ @thread = Thread.new do
18
+ begin
19
+ yield(method(:resolve!), method(:reject!))
20
+ rescue Exception => e
21
+ reject!(e)
22
+ end
23
+ end
18
24
  rescue Exception => e
19
25
  reject!(e)
20
26
  end
@@ -23,9 +29,9 @@ class Rpromise
23
29
  raise ArgumentError unless is_valid_block?(on_resolved)
24
30
  raise ArgumentError unless is_valid_block?(on_rejected)
25
31
  return self if on_resolved.nil? && on_rejected.nil?
26
- return ::Rpromise.new do |resolve, reject, promise|
32
+ return ::Rpromise.new do |resolve, reject|
27
33
  handler = Handler.new(on_resolved, on_rejected, resolve, reject)
28
- self.handle(handler)
34
+ handle(handler)
29
35
  end
30
36
  end
31
37
 
@@ -53,9 +59,6 @@ class Rpromise
53
59
  unless @defered.nil?
54
60
  handle(@defered)
55
61
  end
56
-
57
- rescue
58
- reject!(nil)
59
62
  end
60
63
 
61
64
  def reject!(value = nil)
@@ -92,7 +95,5 @@ class Rpromise
92
95
  output = callback.call(@value)
93
96
  handler.resolve.call(output) unless handler.resolve.nil?
94
97
  end
95
- rescue
96
- handler.reject.call(nil) unless handler.reject.nil?
97
98
  end
98
99
  end
data/rpromise.gemspec CHANGED
@@ -23,4 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "rspec"
24
24
  spec.add_development_dependency "guard"
25
25
  spec.add_development_dependency "guard-rspec"
26
+ spec.add_development_dependency "codeclimate-test-reporter"
26
27
  end
@@ -12,30 +12,27 @@ describe ::Rpromise do
12
12
 
13
13
  describe '#initialize' do
14
14
  it 'uses the resolve! method as callback' do
15
- t = nil
15
+ lock = true
16
16
  p = described_class.new do |resolve, reject|
17
- t = Thread.new do
18
- resolve.call('hi')
19
- end
17
+ resolve.call('hi')
18
+ lock = false
20
19
  end
21
- t.join
20
+ loop { break unless lock }
22
21
  expect(p).to be_resolved
23
22
  end
24
23
 
25
24
  it 'uses the reject! method as callback' do
26
- t = nil
25
+ lock = true
27
26
  p = described_class.new do |resolve, reject|
28
- t = Thread.new do
29
- reject.call('hi')
30
- end
27
+ reject.call('hi')
28
+ lock = false
31
29
  end
32
- t.join
30
+ loop { break unless lock }
33
31
  expect(p).to be_rejected
34
32
  end
35
33
  end
36
34
 
37
35
  describe '#then' do
38
-
39
36
  it 'returns a new promise' do
40
37
  expect(promise.then).to be_kind_of described_class
41
38
  end
@@ -58,158 +55,112 @@ describe ::Rpromise do
58
55
  let(:value2) { Random.rand + value }
59
56
  let(:value3) { Random.rand + value + value2 }
60
57
 
61
- context 'with async task' do
62
- before(:each) do
63
- @thread = nil
64
- @promise = described_class.new do |resolve, reject|
65
- @thread = Thread.new do
66
- sleep(0.5)
67
- resolve.call(value)
68
- end
69
- end
58
+ before(:each) do
59
+ @promise = described_class.new do |resolve, reject|
60
+ resolve.call(value)
70
61
  end
62
+ end
71
63
 
72
- it 'returns the resolved value' do
73
- lambda_value = nil
74
- @promise.then(lambda do |v|
75
- lambda_value = v
64
+ it 'returns the resolved value' do
65
+ lambda_value = nil
66
+ lock = true
67
+ @promise.then(lambda do |v|
68
+ lambda_value = v
69
+ lock = false
70
+ end)
71
+ loop { break unless lock }
72
+ expect(@promise).to be_resolved
73
+ expect(lambda_value).to eq value
74
+ end
75
+
76
+ context 'when multiple then are chained together' do
77
+ it 'passes its returned value to the next then' do
78
+ lambda_value_1 = nil
79
+ lambda_value_2 = nil
80
+ lambda_value_3 = nil
81
+ lock = true
82
+ @promise.then(lambda do |v1|
83
+ lambda_value_1 = v1
84
+ return value2
85
+ end).then(lambda do |v2|
86
+ lambda_value_2 = v2
87
+ return value3
88
+ end).then(lambda do |v3|
89
+ lambda_value_3 = v3
90
+ lock = false
76
91
  end)
77
- expect(lambda_value).to be_nil
78
- expect(@promise).to be_pending
79
- @thread.join
80
- expect(@promise).to be_resolved
81
- expect(lambda_value).to eq value
82
- end
83
- context 'when multiple then are chained together' do
84
- it 'passes its returned value to the next then' do
85
- lambda_value_1 = nil
86
- lambda_value_2 = nil
87
- lambda_value_3 = nil
88
- @promise.then(lambda do |v1|
89
- lambda_value_1 = v1
90
- return value2
91
- end).then(lambda do |v2|
92
- lambda_value_2 = v2
93
- return value3
94
- end).then(lambda do |v3|
95
- lambda_value_3 = v3
96
- end)
97
- @thread.join
98
- expect(lambda_value_1).to eq value
99
- expect(lambda_value_2).to eq value2
100
- expect(lambda_value_3).to eq value3
101
- end
102
- end
103
- context 'when then resolve callback returns a promise' do
104
- it 'uses the next then as handler' do
105
- thread2 = nil
106
- lambda_value = nil
107
- lock = true
108
- @promise.then(lambda do |v|
109
- return described_class.new do |resolve, reject|
110
- thread2 = Thread.new do
111
- sleep(0)
112
- resolve.call('Hello world!')
113
- end
114
- end
115
- end).then(lambda do |hello_world|
116
- lambda_value = hello_world
117
- lock = false
118
- end)
119
- loop { break unless lock }
120
- expect(lambda_value).to eq 'Hello world!'
121
- end
122
- end
123
- context 'when no callback is passed' do
124
- it 'passes original returned value to the next then' do
125
- lambda_value = nil
126
- @promise.then.then(lambda do |v|
127
- lambda_value = v
128
- end)
129
- @thread.join
130
- expect(lambda_value).to eq value
131
- end
92
+ loop { break unless lock }
93
+ expect(lambda_value_1).to eq value
94
+ expect(lambda_value_2).to eq value2
95
+ expect(lambda_value_3).to eq value3
132
96
  end
133
97
  end
134
98
 
135
- context 'with non-async task' do
136
- let(:promise) do
137
- described_class.new do |resolve, reject|
138
- resolve.call(value)
139
- end
99
+ context 'when then resolve callback returns a promise' do
100
+ it 'uses the next then as handler' do
101
+ thread2 = nil
102
+ lambda_value = nil
103
+ lock = true
104
+ @promise.then(lambda do |v|
105
+ return described_class.new do |resolve, reject|
106
+ thread2 = Thread.new do
107
+ resolve.call('Hello world!')
108
+ end
109
+ end
110
+ end).then(lambda do |hello_world|
111
+ lambda_value = hello_world
112
+ lock = false
113
+ end)
114
+ loop { break unless lock }
115
+ expect(lambda_value).to eq 'Hello world!'
140
116
  end
117
+ end
141
118
 
142
- it 'returns the resolved value' do
119
+ context 'when no callback is passed' do
120
+ it 'passes original returned value to the next then' do
143
121
  lambda_value = nil
144
- promise.then(lambda do |v|
122
+ lock = true
123
+ @promise.then.then(lambda do |v|
145
124
  lambda_value = v
125
+ lock = false
146
126
  end)
147
- expect(lambda_value).to be value
148
- end
149
-
150
- context 'when multiple then are chained together' do
151
- it 'passes its returned value to the next then' do
152
- lambda_value_1 = nil
153
- lambda_value_2 = nil
154
- lambda_value_3 = nil
155
- promise.then(lambda do |v1|
156
- lambda_value_1 = v1
157
- return value2
158
- end).then(lambda do |v2|
159
- lambda_value_2 = v2
160
- return value3
161
- end).then(lambda do |v3|
162
- lambda_value_3 = v3
163
- end)
164
- expect(lambda_value_1).to eq value
165
- expect(lambda_value_2).to eq value2
166
- expect(lambda_value_3).to eq value3
167
- end
168
- end
169
-
170
- context 'when no callback is passed' do
171
- it 'does not raise any error' do
172
- expect { promise.then }.not_to raise_error
173
- end
174
-
175
- it 'passes original returned value to the next then' do
176
- lambda_value = nil
177
- promise.then.then(lambda do |v|
178
- lambda_value = v
179
- end)
180
- expect(lambda_value).to eq value
181
- end
127
+ loop { break unless lock }
128
+ expect(lambda_value).to eq value
182
129
  end
183
130
  end
184
131
  end
185
132
 
186
133
  context 'when promise is rejected' do
187
- context 'with non-async task' do
188
- let(:error) { Random.rand }
189
- let(:promise) do
190
- described_class.new do |resolve, reject|
191
- reject.call(error)
192
- end
134
+ let(:error) { Random.rand }
135
+ it 'returns exception' do
136
+ lambda_error = nil
137
+ lock = true
138
+ p = described_class.new do |resolve, reject|
139
+ reject.call(error)
193
140
  end
194
- it 'returns exception' do
195
- lambda_error = nil
196
- promise.then(nil, lambda do |e|
197
- lambda_error = e
198
- end)
199
- expect(lambda_error).to eq error
200
- end
201
- it 'handles raised exceptions within the promise' do
202
- lambda_error = nil
203
- promise = described_class.new do |resolve, reject|
204
- raise 'Oops'
205
- end
206
- promise.then(nil, lambda do |e|
207
- lambda_error = e
208
- end)
209
- expect(lambda_error).to be_kind_of RuntimeError
210
- expect(lambda_error.message).to eq 'Oops'
141
+ p.then(nil, lambda do |e|
142
+ lambda_error = e
143
+ lock = false
144
+ end)
145
+ loop { break unless lock }
146
+ expect(lambda_error).to eq error
147
+ end
148
+ it 'handles raised exceptions within the promise' do
149
+ lambda_error = nil
150
+ lock = true
151
+ p = described_class.new do |resolve, reject|
152
+ raise 'Oops'
211
153
  end
154
+ p.then(nil, lambda do |e|
155
+ lambda_error = e
156
+ lock = false
157
+ end)
158
+ loop { break unless lock }
159
+ expect(lambda_error).to be_kind_of RuntimeError
160
+ expect(lambda_error.message).to eq 'Oops'
212
161
  end
162
+ xit 'handles raised exceptions within resolve!'
163
+ xit 'handles raised exceptions within handle!'
213
164
  end
214
165
  end
215
166
 
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
3
+
1
4
  require 'rpromise'
2
5
 
3
6
  RSpec.configure do |config|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rpromise
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Molinari
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-13 00:00:00.000000000 Z
11
+ date: 2014-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: codeclimate-test-reporter
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description: Handle async method easily
84
98
  email:
85
99
  - samuel@molinari.me