monad-oxide 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 +7 -0
- data/lib/err_spec.rb +300 -0
- data/lib/ok_spec.rb +347 -0
- data/lib/result_spec.rb +30 -0
- metadata +77 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 504855112b6ed7faeb0c45305ed117f1e9950af5cbba9739680e493633ce0b84
|
4
|
+
data.tar.gz: 79491d6d8191a267e64a1fe55f00ef6899d49496a654d9458382b09d40f76f7a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3c186a75ca88ae69c1d6fa2e17ad7f7963177a8e6aa28aecf6457c2b549aa4a6ac6c6acb6161b017f0e58d8367f5728bcac032a8e34a82caeadf5ef9d3824e37
|
7
|
+
data.tar.gz: e36391798ab39c82c941b463688cbca7eee416d8d720d7be0eeb428d336b4456ab236fe666b8d80db15a42f1068d3c0466dcc6d24e4b30678edc799e303e6f3f
|
data/lib/err_spec.rb
ADDED
@@ -0,0 +1,300 @@
|
|
1
|
+
require 'monad-oxide'
|
2
|
+
require 'ok'
|
3
|
+
require 'err'
|
4
|
+
|
5
|
+
describe MonadOxide::Err do
|
6
|
+
|
7
|
+
# The constructor tests (MonadOxide::Err.new()) are exactly the same as the
|
8
|
+
# helper (MonadOxide.err()).
|
9
|
+
ctor_tests = ->(ctor) {
|
10
|
+
it 'raises a TypeError if not provided an Exception' do
|
11
|
+
expect { ctor.call('foo') }.to raise_error(TypeError)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'establishes a backtrace for unraised Exceptions' do
|
15
|
+
expect(
|
16
|
+
ctor.call(StandardError.new('foo'))
|
17
|
+
.unwrap_err()
|
18
|
+
.backtrace()
|
19
|
+
).not_to(be_nil())
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'retains backtraces for raised Exceptions' do
|
23
|
+
begin
|
24
|
+
raise StandardError.new('foo')
|
25
|
+
rescue => e
|
26
|
+
expect(
|
27
|
+
ctor.call(e)
|
28
|
+
.unwrap_err()
|
29
|
+
.backtrace()
|
30
|
+
).to(be(e.backtrace()))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
}
|
34
|
+
|
35
|
+
context '#initialize' do
|
36
|
+
ctor_tests.call(MonadOxide::Err.method(:new))
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'MonadOxide.err' do
|
40
|
+
ctor_tests.call(MonadOxide.method(:err))
|
41
|
+
end
|
42
|
+
|
43
|
+
context '#and_then' do
|
44
|
+
|
45
|
+
context 'with blocks' do
|
46
|
+
it 'does nothing with the block' do
|
47
|
+
effected = 'unset'
|
48
|
+
MonadOxide.err(StandardError.new('foo'))
|
49
|
+
.and_then() {|s| effected = "effect: #{s}"}
|
50
|
+
expect(effected).not_to(eq('effect: foo'))
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'does not change the underlying data' do
|
54
|
+
expect(
|
55
|
+
MonadOxide.err(StandardError.new('foo'))
|
56
|
+
.and_then() { 'bar' }
|
57
|
+
.unwrap_err()
|
58
|
+
.message()
|
59
|
+
).to(eq('foo'))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'with Procs' do
|
64
|
+
it 'does nothing with the function' do
|
65
|
+
effected = 'unset'
|
66
|
+
MonadOxide.err(StandardError.new('foo'))
|
67
|
+
.and_then(->(s) { effected = "effect: #{s}"})
|
68
|
+
expect(effected).not_to(eq('effect: foo'))
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'does not change the underlying data' do
|
72
|
+
expect(
|
73
|
+
MonadOxide.err(StandardError.new('foo'))
|
74
|
+
.and_then(->(_) { 'bar' })
|
75
|
+
.unwrap_err()
|
76
|
+
.message()
|
77
|
+
).to(eq('foo'))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
context '#inspect_err' do
|
85
|
+
context 'with blocks' do
|
86
|
+
it 'applies the data to the block provided' do
|
87
|
+
effected = 'unset'
|
88
|
+
MonadOxide.err(StandardError.new('foo'))
|
89
|
+
.inspect_err(->(s) { effected = "effect: #{s}"})
|
90
|
+
expect(effected).to(eq('effect: foo'))
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'does not change the underlying data' do
|
94
|
+
expect(
|
95
|
+
MonadOxide.err(StandardError.new('foo'))
|
96
|
+
.inspect_err() {|_| 'bar' }
|
97
|
+
.unwrap_err()
|
98
|
+
.message()
|
99
|
+
).to(eq('foo'))
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'returns an Err with the error from the block' do
|
103
|
+
expect(
|
104
|
+
MonadOxide.err(StandardError.new('foo'))
|
105
|
+
.inspect_err() {|_| raise StandardError.new('flagrant') }
|
106
|
+
.unwrap_err()
|
107
|
+
.message()
|
108
|
+
).to(eq('flagrant'))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'with Procs' do
|
113
|
+
it 'applies the data to the function provided' do
|
114
|
+
effected = 'unset'
|
115
|
+
MonadOxide.err(StandardError.new('foo'))
|
116
|
+
.inspect_err(->(s) { effected = "effect: #{s}"})
|
117
|
+
expect(effected).to(eq('effect: foo'))
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'does not change the underlying data' do
|
121
|
+
expect(
|
122
|
+
MonadOxide.err(StandardError.new('foo'))
|
123
|
+
.inspect_err(->(_) { 'bar' })
|
124
|
+
.unwrap_err()
|
125
|
+
.message()
|
126
|
+
).to(eq('foo'))
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'returns an Err with the error from the function' do
|
130
|
+
expect(
|
131
|
+
MonadOxide.err(StandardError.new('foo'))
|
132
|
+
.inspect_err(->(_) { raise StandardError.new('flagrant') })
|
133
|
+
.unwrap_err()
|
134
|
+
.message()
|
135
|
+
).to(eq('flagrant'))
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context '#inspect_ok' do
|
141
|
+
context 'with blocks' do
|
142
|
+
it 'does nothing with the block' do
|
143
|
+
effected = 'unset'
|
144
|
+
MonadOxide.err(StandardError.new('foo'))
|
145
|
+
.inspect_ok() {|s| effected = "effect: #{s}"}
|
146
|
+
expect(effected).not_to(eq('effect: foo'))
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'does not change the underlying data' do
|
150
|
+
expect(
|
151
|
+
MonadOxide.err(StandardError.new('foo'))
|
152
|
+
.inspect_ok() { 'bar' }
|
153
|
+
.unwrap_err()
|
154
|
+
.message()
|
155
|
+
).to(eq('foo'))
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'with Procs' do
|
160
|
+
it 'does nothing with the function' do
|
161
|
+
effected = 'unset'
|
162
|
+
MonadOxide.err(StandardError.new('foo'))
|
163
|
+
.inspect_ok(->(s) { effected = "effect: #{s}"})
|
164
|
+
expect(effected).not_to(eq('effect: foo'))
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'does not change the underlying data' do
|
168
|
+
expect(
|
169
|
+
MonadOxide.err(StandardError.new('foo'))
|
170
|
+
.inspect_ok(->(_) { 'bar' })
|
171
|
+
.unwrap_err()
|
172
|
+
.message()
|
173
|
+
).to(eq('foo'))
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
context '#map' do
|
180
|
+
context 'with blocks' do
|
181
|
+
it 'does nothing with the block' do
|
182
|
+
effected = 'unset'
|
183
|
+
MonadOxide.err(StandardError.new('foo'))
|
184
|
+
.map() {|s| effected = "effect: #{s}"}
|
185
|
+
expect(effected).not_to(eq('effect: foo'))
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'does not change the underlying data' do
|
189
|
+
expect(
|
190
|
+
MonadOxide.err(StandardError.new('foo'))
|
191
|
+
.map() { 'bar' }
|
192
|
+
.unwrap_err()
|
193
|
+
.message()
|
194
|
+
).to(eq('foo'))
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context 'with Procs' do
|
199
|
+
it 'does nothing with the function' do
|
200
|
+
effected = 'unset'
|
201
|
+
MonadOxide.err(StandardError.new('foo'))
|
202
|
+
.map(->(s) { effected = "effect: #{s}"})
|
203
|
+
expect(effected).not_to(eq('effect: foo'))
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'does not change the underlying data' do
|
207
|
+
expect(
|
208
|
+
MonadOxide.err(StandardError.new('foo'))
|
209
|
+
.map(->(_) { 'bar' })
|
210
|
+
.unwrap_err()
|
211
|
+
.message()
|
212
|
+
).to(eq('foo'))
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
context '#map_err' do
|
218
|
+
context 'with blocks' do
|
219
|
+
it 'returns an Err if an error is raised in the block' do
|
220
|
+
expect(
|
221
|
+
MonadOxide.err(StandardError.new('foo'))
|
222
|
+
.map_err() {|_| raise StandardError.new('bar') }
|
223
|
+
.unwrap_err()
|
224
|
+
.message()
|
225
|
+
).to(eq('bar'))
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'returns a new Err' do
|
229
|
+
expect(
|
230
|
+
MonadOxide.err(StandardError.new('foo'))
|
231
|
+
.map_err() {|_| StandardErr.new('bar') }
|
232
|
+
.class()
|
233
|
+
).to(be(MonadOxide::Err))
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'applies the block to the data for the new Ok' do
|
237
|
+
expect(
|
238
|
+
MonadOxide.err(StandardError.new('foo'))
|
239
|
+
.map_err() {|e| StandardError.new(e.message() + 'bar') }
|
240
|
+
.unwrap_err()
|
241
|
+
.message()
|
242
|
+
).to(eq('foobar'))
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'requires the mapped value is an Exception still' do
|
246
|
+
expect(
|
247
|
+
MonadOxide.err(StandardError.new('foo'))
|
248
|
+
.map_err() {|_| 'bar'}
|
249
|
+
.unwrap_err()
|
250
|
+
.class()
|
251
|
+
).to(be(TypeError))
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
context 'with Procs' do
|
256
|
+
it 'returns an Err if an error is raised in the function' do
|
257
|
+
expect(
|
258
|
+
MonadOxide.err(StandardError.new('foo'))
|
259
|
+
.map_err(->(_) { raise StandardError.new })
|
260
|
+
.unwrap_err()
|
261
|
+
.class()
|
262
|
+
).to(be(StandardError))
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'applies the function to the data for the new Ok' do
|
266
|
+
expect(
|
267
|
+
MonadOxide.err(StandardError.new('foo'))
|
268
|
+
.map_err(->(e) { StandardError.new(e.message() + 'bar') })
|
269
|
+
.unwrap_err()
|
270
|
+
.message()
|
271
|
+
).to(eq('foobar'))
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'requires the mapped value is an Exception still' do
|
275
|
+
expect(
|
276
|
+
MonadOxide.err(StandardError.new('foo'))
|
277
|
+
.map_err(->(_) { 'bar' })
|
278
|
+
.unwrap_err()
|
279
|
+
.class()
|
280
|
+
).to(be(TypeError))
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context '#unwrap' do
|
286
|
+
it 'raises an UnwrapError' do
|
287
|
+
expect {
|
288
|
+
MonadOxide.err(StandardError.new('foo')).unwrap()
|
289
|
+
}.to(raise_error(MonadOxide::UnwrapError))
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
context '#unwrap_err' do
|
294
|
+
it 'provides the underlying value' do
|
295
|
+
expect(
|
296
|
+
MonadOxide.err(StandardError.new('foo')).unwrap_err().message(),
|
297
|
+
).to(eq('foo'))
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
data/lib/ok_spec.rb
ADDED
@@ -0,0 +1,347 @@
|
|
1
|
+
require 'monad-oxide'
|
2
|
+
require 'ok'
|
3
|
+
require 'err'
|
4
|
+
|
5
|
+
describe MonadOxide::Ok do
|
6
|
+
|
7
|
+
context '#and_then' do
|
8
|
+
|
9
|
+
context 'with blocks' do
|
10
|
+
it 'passes the data from the Ok to the block' do
|
11
|
+
expect(
|
12
|
+
MonadOxide.ok('foo')
|
13
|
+
.and_then() {|s| MonadOxide.ok(s + 'bar') }
|
14
|
+
.unwrap()
|
15
|
+
).to(eq('foobar'))
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'converts to an Err if the block raises an error' do
|
19
|
+
expect(
|
20
|
+
MonadOxide.ok('foo')
|
21
|
+
.and_then() {|_| raise StandardError.new('flagrant') }
|
22
|
+
.class
|
23
|
+
).to(be(MonadOxide::Err))
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'converts to an Err if the block returns a non-Result' do
|
27
|
+
expect(
|
28
|
+
MonadOxide.ok('foo')
|
29
|
+
.and_then() {|_| 'bar' }
|
30
|
+
.class()
|
31
|
+
).to(be(MonadOxide::Err))
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'provides a ResultReturnExpectedError in the Err for non-Result returns' do
|
35
|
+
expect(
|
36
|
+
MonadOxide.ok('foo')
|
37
|
+
.and_then() {|_| 'bar' }
|
38
|
+
.unwrap_err()
|
39
|
+
.class()
|
40
|
+
).to(be(MonadOxide::ResultReturnExpectedError))
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'returns the same Ok returned by the block' do
|
44
|
+
expect(
|
45
|
+
MonadOxide.ok('foo')
|
46
|
+
.and_then() {|_| MonadOxide.ok('bar') }
|
47
|
+
.unwrap()
|
48
|
+
).to(eq('bar'))
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'returns the same Err returned by the block' do
|
52
|
+
expect(
|
53
|
+
MonadOxide.ok('foo')
|
54
|
+
.and_then() {|_| MonadOxide.err(StandardError.new()) }
|
55
|
+
.unwrap_err()
|
56
|
+
.class()
|
57
|
+
).to(be(StandardError))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with Procs' do
|
62
|
+
it 'passes the data from the Ok to the function' do
|
63
|
+
expect(
|
64
|
+
MonadOxide.ok('foo')
|
65
|
+
.and_then(->(s) { MonadOxide.ok(s + 'bar') })
|
66
|
+
.unwrap()
|
67
|
+
).to(eq('foobar'))
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'converts to an Err if the function raises an error' do
|
71
|
+
expect(
|
72
|
+
MonadOxide.ok('foo')
|
73
|
+
.and_then(->(_) { raise StandardError.new('flagrant') })
|
74
|
+
.class
|
75
|
+
).to(be(MonadOxide::Err))
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'converts to an Err if the function returns a non-Result' do
|
79
|
+
expect(
|
80
|
+
MonadOxide.ok('foo')
|
81
|
+
.and_then(->(_) { 'bar' })
|
82
|
+
.class()
|
83
|
+
).to(be(MonadOxide::Err))
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'provides a ResultReturnExpectedError in the Err for non-Result returns' do
|
87
|
+
expect(
|
88
|
+
MonadOxide.ok('foo')
|
89
|
+
.and_then(->(_) { 'bar' })
|
90
|
+
.unwrap_err()
|
91
|
+
.class()
|
92
|
+
).to(be(MonadOxide::ResultReturnExpectedError))
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'returns the same Ok returned by the function' do
|
96
|
+
expect(
|
97
|
+
MonadOxide.ok('foo')
|
98
|
+
.and_then(->(_) { MonadOxide.ok('bar') })
|
99
|
+
.unwrap()
|
100
|
+
).to(eq('bar'))
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'returns the same Err returned by the function' do
|
104
|
+
expect(
|
105
|
+
MonadOxide.ok('foo')
|
106
|
+
.and_then(->(_) { MonadOxide.err(StandardError.new()) })
|
107
|
+
.unwrap_err()
|
108
|
+
.class()
|
109
|
+
).to(be(StandardError))
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
context '#map' do
|
117
|
+
context 'with blocks' do
|
118
|
+
it 'returns an Err if an error is raised in the block' do
|
119
|
+
expect(
|
120
|
+
MonadOxide.ok('foo')
|
121
|
+
.map() {|_| raise StandardError.new('bar') }
|
122
|
+
.unwrap_err()
|
123
|
+
.class()
|
124
|
+
).to(be(StandardError))
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'returns a new Ok' do
|
128
|
+
expect(
|
129
|
+
MonadOxide.ok('foo')
|
130
|
+
.map() {|_| 'bar' }
|
131
|
+
.class()
|
132
|
+
).to(be(MonadOxide::Ok))
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'applies the block to the data for the new Ok' do
|
136
|
+
expect(
|
137
|
+
MonadOxide.ok('foo')
|
138
|
+
.map() {|s| s + 'bar' }
|
139
|
+
.unwrap()
|
140
|
+
).to(eq('foobar'))
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'allows nesting of Ok' do
|
144
|
+
expect(
|
145
|
+
MonadOxide.ok('foo')
|
146
|
+
.map() {|s| MonadOxide.ok(s) }
|
147
|
+
.unwrap()
|
148
|
+
.class()
|
149
|
+
).to(be(MonadOxide::Ok))
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'allows nesting of Err' do
|
153
|
+
expect(
|
154
|
+
MonadOxide.ok('foo')
|
155
|
+
.map() {|_| MonadOxide.err(StandardError.new('bar')) }
|
156
|
+
.unwrap()
|
157
|
+
.class()
|
158
|
+
).to(be(MonadOxide::Err))
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'with Procs' do
|
163
|
+
it 'returns an Err if an error is raised in the function' do
|
164
|
+
expect(
|
165
|
+
MonadOxide.ok('foo')
|
166
|
+
.map(->(_) { raise StandardError.new })
|
167
|
+
.unwrap_err()
|
168
|
+
.class()
|
169
|
+
).to(be(StandardError))
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'returns a new Ok' do
|
173
|
+
expect(
|
174
|
+
MonadOxide.ok('foo')
|
175
|
+
.map(->(_) { 'bar' })
|
176
|
+
.class()
|
177
|
+
).to(be(MonadOxide::Ok))
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'applies the function to the data for the new Ok' do
|
181
|
+
expect(
|
182
|
+
MonadOxide.ok('foo')
|
183
|
+
.map(->(s) { s + 'bar' })
|
184
|
+
.unwrap()
|
185
|
+
).to(eq('foobar'))
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'allows nesting of Ok' do
|
189
|
+
expect(
|
190
|
+
MonadOxide.ok('foo')
|
191
|
+
.map(->(s) { MonadOxide.ok(s) })
|
192
|
+
.unwrap()
|
193
|
+
.class()
|
194
|
+
).to(be(MonadOxide::Ok))
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'allows nesting of Err' do
|
198
|
+
expect(
|
199
|
+
MonadOxide.ok('foo')
|
200
|
+
.map(->(_) { MonadOxide.err(StandardError.new()) })
|
201
|
+
.unwrap()
|
202
|
+
.class()
|
203
|
+
).to(be(MonadOxide::Err))
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context '#map_err' do
|
209
|
+
context 'with blocks' do
|
210
|
+
it 'does nothing with the block' do
|
211
|
+
effected = 'unset'
|
212
|
+
MonadOxide.ok('foo')
|
213
|
+
.map_err() {|s| effected = "effect: #{s}"}
|
214
|
+
expect(effected).not_to(eq('effect: foo'))
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'does not change the underlying data' do
|
218
|
+
expect(
|
219
|
+
MonadOxide.ok('foo')
|
220
|
+
.map_err() { 'bar' }
|
221
|
+
.unwrap()
|
222
|
+
).to(eq('foo'))
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
context 'with Procs' do
|
227
|
+
it 'does nothing with the function' do
|
228
|
+
effected = 'unset'
|
229
|
+
MonadOxide.ok('foo')
|
230
|
+
.map_err(->(s) { effected = "effect: #{s}"})
|
231
|
+
expect(effected).not_to(eq('effect: foo'))
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'does not change the underlying data' do
|
235
|
+
expect(
|
236
|
+
MonadOxide.ok('foo')
|
237
|
+
.map_err(->(_) { 'bar' })
|
238
|
+
.unwrap()
|
239
|
+
).to(eq('foo'))
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context '#inspect_err' do
|
245
|
+
context 'with blocks' do
|
246
|
+
it 'does nothing with the block' do
|
247
|
+
effected = 'unset'
|
248
|
+
MonadOxide.ok('foo')
|
249
|
+
.inspect_err() {|s| effected = "effect: #{s}"}
|
250
|
+
expect(effected).not_to(eq('effect: foo'))
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'does not change the underlying data' do
|
254
|
+
expect(
|
255
|
+
MonadOxide.ok('foo')
|
256
|
+
.inspect_err() { 'bar' }
|
257
|
+
.unwrap()
|
258
|
+
).to(eq('foo'))
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
context 'with Procs' do
|
263
|
+
it 'does nothing with the function' do
|
264
|
+
effected = 'unset'
|
265
|
+
MonadOxide.ok('foo')
|
266
|
+
.inspect_err(->(s) { effected = "effect: #{s}"})
|
267
|
+
expect(effected).not_to(eq('effect: foo'))
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'does not change the underlying data' do
|
271
|
+
expect(
|
272
|
+
MonadOxide.ok('foo')
|
273
|
+
.inspect_err(->(_) { 'bar' })
|
274
|
+
.unwrap()
|
275
|
+
).to(eq('foo'))
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
context '#inspect_ok' do
|
281
|
+
context 'with blocks' do
|
282
|
+
it 'applies the data to the block provided' do
|
283
|
+
effected = 'unset'
|
284
|
+
MonadOxide.ok('foo')
|
285
|
+
.inspect_ok(->(s) { effected = "effect: #{s}"})
|
286
|
+
expect(effected).to(eq('effect: foo'))
|
287
|
+
end
|
288
|
+
|
289
|
+
it 'does not change the underlying data' do
|
290
|
+
expect(
|
291
|
+
MonadOxide.ok('foo')
|
292
|
+
.inspect_ok() {|_| 'bar' }
|
293
|
+
.unwrap()
|
294
|
+
).to(eq('foo'))
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'returns an Err with the error from the block' do
|
298
|
+
expect(
|
299
|
+
MonadOxide.ok('foo')
|
300
|
+
.inspect_ok() {|_| raise StandardError.new('flagrant') }
|
301
|
+
.unwrap_err()
|
302
|
+
.class()
|
303
|
+
).to(be(StandardError))
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context 'with Procs' do
|
308
|
+
it 'applies the data to the function provided' do
|
309
|
+
effected = 'unset'
|
310
|
+
MonadOxide.ok('foo')
|
311
|
+
.inspect_ok(->(s) { effected = "effect: #{s}"})
|
312
|
+
expect(effected).to(eq('effect: foo'))
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'does not change the underlying data' do
|
316
|
+
expect(
|
317
|
+
MonadOxide.ok('foo')
|
318
|
+
.inspect_ok(->(_) { 'bar' })
|
319
|
+
.unwrap()
|
320
|
+
).to(eq('foo'))
|
321
|
+
end
|
322
|
+
|
323
|
+
it 'returns an Err with the error from the function' do
|
324
|
+
expect(
|
325
|
+
MonadOxide.ok('foo')
|
326
|
+
.inspect_ok(->(_) { raise StandardError.new('flagrant') })
|
327
|
+
.unwrap_err()
|
328
|
+
.class()
|
329
|
+
).to(be(StandardError))
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
context '#unwrap' do
|
335
|
+
it 'provides the underlying value' do
|
336
|
+
expect(MonadOxide.ok('foo').unwrap()).to(eq('foo'))
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
context '#unwrap_err' do
|
341
|
+
it 'raises an UnwrapError' do
|
342
|
+
expect {
|
343
|
+
MonadOxide.ok('foo').unwrap_err()
|
344
|
+
}.to(raise_error(MonadOxide::UnwrapError))
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
data/lib/result_spec.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'monad-oxide'
|
2
|
+
require 'result'
|
3
|
+
|
4
|
+
describe MonadOxide::Result do
|
5
|
+
context '#initialize' do
|
6
|
+
it 'is protected from external consumption' do
|
7
|
+
expect { MonadOxide::Result.new('hi') }.to(raise_exception(NoMethodError))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context '#flatten' do
|
12
|
+
it 'returns itself when the Result is already flat' do
|
13
|
+
r = MonadOxide.ok('flat')
|
14
|
+
expect(r.flatten()).to(be(r))
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'returns the inner result' do
|
18
|
+
inner = MonadOxide.ok('inner')
|
19
|
+
outer = MonadOxide.ok(inner)
|
20
|
+
expect(outer.flatten()).to(be(inner))
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns the innermost result regardless of nesting' do
|
24
|
+
innermost = MonadOxide.ok('innermost')
|
25
|
+
inner = MonadOxide.ok(innermost)
|
26
|
+
outer = MonadOxide.ok(inner)
|
27
|
+
expect(outer.flatten()).to(be(innermost))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: monad-oxide
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Logan Barnett
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-07-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
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
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: |
|
42
|
+
Monad-Oxide is a port of Rust's built-in monads from std, such as Result and
|
43
|
+
Option. This enables better reasoning about error handling and possibly missing
|
44
|
+
data.
|
45
|
+
email:
|
46
|
+
executables: []
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- lib/err_spec.rb
|
51
|
+
- lib/ok_spec.rb
|
52
|
+
- lib/result_spec.rb
|
53
|
+
homepage:
|
54
|
+
licenses:
|
55
|
+
- Apache-2.0
|
56
|
+
- MIT
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 2.7.0
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubygems_version: 3.1.6
|
74
|
+
signing_key:
|
75
|
+
specification_version: 4
|
76
|
+
summary: Ruby port of Rust's Result and Option.
|
77
|
+
test_files: []
|