rpromise 0.0.5 → 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.
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