deterministic 0.8.1 → 0.10.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.md +17 -0
  3. data/README.md +121 -153
  4. data/lib/deterministic/core_ext/object/result.rb +6 -0
  5. data/lib/deterministic/core_ext/{either.rb → result.rb} +2 -6
  6. data/lib/deterministic/monad.rb +3 -3
  7. data/lib/deterministic/result/chain.rb +27 -0
  8. data/lib/deterministic/result/failure.rb +5 -0
  9. data/lib/deterministic/{either → result}/match.rb +5 -5
  10. data/lib/deterministic/result/success.rb +5 -0
  11. data/lib/deterministic/{either.rb → result.rb} +29 -6
  12. data/lib/deterministic/version.rb +1 -1
  13. data/lib/deterministic.rb +5 -6
  14. data/spec/examples/bookings_spec.rb +3 -5
  15. data/spec/lib/deterministic/core_ext/object/either_spec.rb +3 -20
  16. data/spec/lib/deterministic/core_ext/result_spec.rb +22 -0
  17. data/spec/lib/deterministic/maybe_spec.rb +2 -0
  18. data/spec/lib/deterministic/monad_spec.rb +3 -3
  19. data/spec/lib/deterministic/result/chain_spec.rb +150 -0
  20. data/spec/lib/deterministic/{either → result}/failure_spec.rb +9 -6
  21. data/spec/lib/deterministic/{either → result}/match_spec.rb +5 -5
  22. data/spec/lib/deterministic/result/result_shared.rb +23 -0
  23. data/spec/lib/deterministic/{either → result}/success_spec.rb +10 -6
  24. data/spec/lib/deterministic/{either_spec.rb → result_spec.rb} +3 -3
  25. metadata +24 -27
  26. data/either.rb +0 -97
  27. data/lib/deterministic/core_ext/object/either.rb +0 -6
  28. data/lib/deterministic/either/attempt_all.rb +0 -50
  29. data/lib/deterministic/either/chain.rb +0 -22
  30. data/lib/deterministic/either/failure.rb +0 -22
  31. data/lib/deterministic/either/success.rb +0 -22
  32. data/spec/lib/deterministic/attempt_all_spec.rb +0 -115
  33. data/spec/lib/deterministic/core_ext/either_spec.rb +0 -50
  34. data/spec/lib/deterministic/either/chain_spec.rb +0 -80
  35. data/spec/lib/deterministic/either/either_shared.rb +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7e4df729f9e00305be8b4bfa828c627dd581ad07
4
- data.tar.gz: 0e1c862ea8004b24bbe65d1d86aa93946013fdad
3
+ metadata.gz: d6ccf85126958f17b98ac22932b29ed508584250
4
+ data.tar.gz: 689d36f2f3b71bcc6192129514a8ca14b2b32001
5
5
  SHA512:
6
- metadata.gz: bef331eed029917b69da1e1059b75f2d43a63ce00bac59f16e589e78de61349e57624f57bc84dac8b7011045043fae28f2fa74831b7d13fea07e2f9f90b805b9
7
- data.tar.gz: adb613df744063e6ac84bee504c2c050d70ace2add63a8b93978efbc128f84e78fee9e205c983f90de7025d7511591e802f3286a3573c314644673b640ad09b7
6
+ metadata.gz: c3c067aab6e1418a829a72505ad33f5822d3f7c749ece67aa903c306e7910ab2158cf5005f439d3dceffe032394f321109fc618c892b4324e85a2a469c8de6eb
7
+ data.tar.gz: 9500d35aedd9849fd2893534b6a220256ac71696b973e86978b4d714233a17a31acd017efdd55cd0dee18afdd25522ab05a0f357e2023819784067fecce687b4
data/HISTORY.md ADDED
@@ -0,0 +1,17 @@
1
+ ## v0.10.0
2
+ ** breaking changes **
3
+
4
+ - Remove `Either#<<`
5
+ - Rename `Either` to `Result`
6
+ - Add `Result#pipe` aka `Result#**`
7
+ - Add `Result#map` and `Result#map_err`
8
+
9
+ ## v0.9.0
10
+ ** breaking changes **
11
+
12
+ - Remove `Either.attempt_all` in favor of `Either#>>` and `Either#>=`
13
+ This greatly reduces the complexity and the code necessary.
14
+
15
+ ## 0.8.0 - v0.8.1
16
+
17
+ - Introduce `Either#>>` and `Either#>=`
data/README.md CHANGED
@@ -9,79 +9,153 @@ This is a spiritual successor of the [Monadic gem](http://github.com/pzol/monadi
9
9
 
10
10
  ## Usage
11
11
 
12
- ### Success & Failure
12
+ ### Result: Success & Failure
13
13
 
14
14
  ```ruby
15
- Success(1).to_s # => "1"
16
- Success(1) << Success(2) # => Success(2)
17
- Success(Success(1)) # => Success(1)
18
- Success(1).map { |v| v + 1} # => Success(2)
19
- Success({a:1}).to_json # => '{"Success": {"a":1}}'
20
-
21
- Failure(1).to_s # => "1"
22
- Failure(1) << Failure(2) # => Failure(1)
23
- Failure(Failure(1)) # => Failure(1)
24
- Failure(1).map { |v| v + 1} # => Failure(2)
25
- Failure({a:1}).to_json # => '{"Failure": {"a":1}}'
15
+ Success(1).to_s # => "1"
16
+ Success(Success(1)) # => Success(1)
17
+
18
+ Failure(1).to_s # => "1"
19
+ Failure(Failure(1)) # => Failure(1)
26
20
  ```
27
21
 
28
- Chaining successful actions
22
+ #### `fmap :: R a -> (a -> b) -> R b`
23
+
24
+ Maps a `Result` with the value `a` to the same `Result` with the value `b`.
29
25
 
30
26
  ```ruby
31
- Success(1).and Success(2) # => Success(2)
32
- Success(1).and_then { Success(2) } # => Success(2)
27
+ Success(1).fmap { |v| v + 1} # => Success(2)
28
+ Failure(1).fmap { |v| v - 1} # => Failure(0)
29
+ ```
33
30
 
34
- Success(1).or Success(2) # => Success(1)
35
- Success(1).or_else { Success(2) } # => Success(1)
31
+ #### `bind :: R a -> (a -> R b) -> R b`
32
+
33
+ Maps a `Result` with the value `a` to another `Result` with the value `b`.
34
+
35
+ ```ruby
36
+ Success(1).bind { |v| Failure(v + 1) } # => Failure(2)
37
+ Failure(1).fmap { |v| Success(v - 1) } # => Success(0)
38
+ ```
39
+
40
+ #### `map :: S a -> (a -> R b) -> R b`
41
+
42
+ Maps a `Success` with the value `a` to another `Result` with the value `b`. It works like `#bind` but only on `Success`.
43
+
44
+ ```ruby
45
+ Success(1).map { |n| n + 1 } # => Success(2)
46
+ Failure(0).map { |n| n + 1 } # => Failure(0)
47
+ ```
48
+
49
+ #### `map_err :: F a -> (a -> R b) -> R b`
50
+
51
+ Maps a `Failure` with the value `a` to another `Result` with the value `b`. It works like `#bind` but only on `Failure`.
52
+
53
+ ```ruby
54
+ Failure(1).map_err { |n| n + 1 } # => Success(2)
55
+ Success(0).map_err { |n| n + 1 } # => Success(0)
36
56
  ```
37
57
 
38
- Chaining failed actions
58
+ #### `try :: S a -> ( a -> R b) -> R b`
59
+
60
+ Just like `#map`, transforms `a` to another `Result`, but it will also catch raised exceptions and wrap them with a `Failure`.
61
+
62
+ ```ruby
63
+ Success(0).try { |n| raise "Error" } # => Failure(Error)
64
+ ```
65
+
66
+ #### `and :: S a -> R b -> R b`
67
+
68
+ Replaces `Success a` with `Result b`. If a `Failure` is passed as argument, it is ignored.
39
69
 
40
70
  ```ruby
71
+ Success(1).and Success(2) # => Success(2)
41
72
  Failure(1).and Success(2) # => Failure(1)
73
+ ```
74
+
75
+ #### `and_then :: S a -> (a -> R b) -> R b`
76
+
77
+ Replaces `Success a` with the result of the block. If a `Failure` is passed as argument, it is ignored.
78
+
79
+ ```ruby
80
+ Success(1).and_then { Success(2) } # => Success(2)
42
81
  Failure(1).and_then { Success(2) } # => Failure(1)
82
+ ```
83
+
84
+ #### `or :: F a -> R b -> R b`
85
+ Replaces `Failure a` with `Result`. If a `Failure` is passed as argument, it is ignored.
43
86
 
87
+ ```ruby
88
+ Success(1).or Success(2) # => Success(1)
44
89
  Failure(1).or Success(1) # => Success(1)
45
- Failure(1).or_else { |v| Success(v)} # => Success(1)
46
90
  ```
47
91
 
48
- The value or block result must always be a `Success` or `Failure`
92
+ #### `or_else :: F a -> (a -> R b) -> R b`
93
+
94
+ Replaces `Failure a` with the result of the block. If a `Success` is passed as argument, it is ignored.
95
+
96
+ ```ruby
97
+ Success(1).or_else { Success(2) } # => Success(1)
98
+ Failure(1).or_else { |n| Success(n)} # => Success(1)
99
+ ```
100
+
101
+ #### `pipe :: R a -> (R a -> b) -> R a`
102
+
103
+ Executes the block passed, but completely ignores its result. If an error is raised within the block it will **NOT** be catched.
104
+
105
+ ```ruby
106
+ Success(1).try { |n| log(n.value) } # => Success(1)
107
+ ```
108
+
109
+ The value or block result must always be a `Result` i.e. `Success` or `Failure`.
110
+
111
+ ### Result Chaining
49
112
 
50
- ### Either.chain
51
113
  You can easily chain the execution of several operations. Here we got some nice function composition.
52
114
  The method must be a unary function, i.e. it always takes one parameter - the context, which is passed from call to call.
53
115
 
116
+ The following aliases are defined
117
+
118
+ ```ruby
119
+ alias :>> :map
120
+ alias :>= :try
121
+ alias :** :pipe # the operator must be right associative
122
+ ```
123
+
124
+ This allows the composition of procs or lambdas and thus allow a clear definiton of a pipeline.
125
+
126
+ ```ruby
127
+ Success(params) >> validate >> build_request ** log >> send ** log >> build_response
128
+ ```
129
+
130
+ #### Complex Example in a Builder Class
131
+
54
132
  ```ruby
55
133
  class Foo
56
134
  include Deterministic
57
- alias :m :method
135
+ alias :m :method # method conveniently returns a Proc to a method
58
136
 
59
- def call
60
- setup >> m(:validate) >> m(:send)
137
+ def call(params)
138
+ Success(params) >> m(:validate) >> m(:send)
61
139
  end
62
140
 
63
- def setup
64
- Success(1)
65
- end
66
-
67
- def validate(ctx)
141
+ def validate(params)
68
142
  # do stuff
69
- Success(ctx + 1)
143
+ Success(validate_and_cleansed_params)
70
144
  end
71
145
 
72
- def send(ctx)
146
+ def send(clean_params)
73
147
  # do stuff
74
- Success(ctx + 1)
148
+ Success(result)
75
149
  end
76
150
  end
77
151
 
78
152
  Foo.new.call # Success(3)
79
153
  ```
80
154
 
81
- Chaining works with blocks (`#chain` is an alias for `#>>`)
155
+ Chaining works with blocks (`#map` is an alias for `#>>`)
82
156
 
83
157
  ```ruby
84
- Success(1).chain {|ctx| Success(ctx + 1)}
158
+ Success(1).map {|ctx| Success(ctx + 1)}
85
159
  ```
86
160
 
87
161
  it also works with lambdas
@@ -107,75 +181,21 @@ end
107
181
  Success(0) >> method(:works) >> method(:breaks) >> method(:never_executed) # Failure(2)
108
182
  ```
109
183
 
110
- `#chain` aka `#>>` will not catch any exceptions raised. If you want automatic exception handling, the `#try` aka `#>=` will catch an error and wrap it with a failure
184
+ `#map` aka `#>>` will not catch any exceptions raised. If you want automatic exception handling, the `#try` aka `#>=` will catch an error and wrap it with a failure
111
185
 
112
186
  ```ruby
113
187
  def error(ctx)
114
- raise "error #{1}"
188
+ raise "error #{ctx}"
115
189
  end
116
190
 
117
191
  Success(1) >= method(:error) # Failure(RuntimeError(error 1))
118
192
  ```
119
193
 
120
- ### Either.attempt_all
121
- The basic idea is to execute a chain of units of work and make sure all return either `Success` or `Failure`.
122
- This remains for compatibility reasons, personally I would use the `>>` chaining.
123
-
124
-
125
- ```ruby
126
- Either.attempt_all do
127
- try { 1 }
128
- try { |prev| prev + 1 }
129
- end # => Success(2)
130
- ```
131
- Take notice, that the result of of unit of work will be passed to the next one. So the result of prepare_somehing will be something in the second try.
132
-
133
- If any of the units of work in between fail, the rest will not be executed and the last `Failure` will be returned.
134
-
135
- ```ruby
136
- Either.attempt_all do
137
- try { 1 }
138
- try { raise "error" }
139
- try { 2 }
140
- end # => Failure(RuntimeError("error"))
141
- ```
142
-
143
- However, the real fun starts if you use it with your own context. You can use this as a state container (meh!) or to pass a dependency locator:
144
-
145
- ```ruby
146
- class Context
147
- attr_accessor :env, :settings
148
- def some_service
149
- end
150
- end
151
-
152
- # exemplary unit of work
153
- module LoadSettings
154
- def self.call(env)
155
- settings = load(env)
156
- settings.nil? ? Failure('could not load settings') : Success(settings)
157
- end
158
-
159
- def load(env)
160
- end
161
- end
162
-
163
- Either.attempt_all(context) do
164
- # this unit of work explicitly returns success or failure
165
- # no exceptions are catched and if they occur, well, they behave as expected
166
- # methods from the context can be accessed, the use of self for setters is necessary
167
- let { self.settings = LoadSettings.call(env) }
168
-
169
- # with #try all exceptions will be transformed into a Failure
170
- try { do_something }
171
- end
172
- ```
173
-
174
194
  ### Pattern matching
175
195
  Now that you have some result, you want to control flow by providing patterns.
176
196
  `#match` can match by
177
197
 
178
- * success, failure, either or any
198
+ * success, failure, result or any
179
199
  * values
180
200
  * lambdas
181
201
  * classes
@@ -184,7 +204,7 @@ Now that you have some result, you want to control flow by providing patterns.
184
204
  Success(1).match do
185
205
  success { |v| "success #{v}"}
186
206
  failure { |v| "failure #{v}"}
187
- either { |v| "either #{v}"}
207
+ result { |v| "result #{v}"}
188
208
  end # => "success 1"
189
209
  ```
190
210
  Note1: the inner value has been unwrapped!
@@ -217,18 +237,6 @@ Success([1, 2, 3]).match do
217
237
  end # => 1
218
238
  ```
219
239
 
220
- Combining `#attempt_all` and `#match` is the ultimate sophistication:
221
-
222
- ```ruby
223
- Either.attempt_all do
224
- try { 1 }
225
- try { |v| v + 1 }
226
- end.match do
227
- success(1) { |v| "We made it to step #{v}" }
228
- success(2) { |v| "The correct answer is #{v}"}
229
- end # => "The correct answer is 2"
230
- ```
231
-
232
240
  If no match was found a `NoMatchError` is raised, so make sure you always cover all possible outcomes.
233
241
 
234
242
  ```ruby
@@ -246,59 +254,19 @@ end # => "catch-all"
246
254
  ```
247
255
 
248
256
  ## core_ext
249
- You can use a core extension, to include Either in your own class or in Object, i.e. in all classes.
257
+ You can use a core extension, to include Result in your own class or in Object, i.e. in all classes.
250
258
 
251
- In a class, as a mixin
259
+ ## Result
252
260
 
253
261
  ```ruby
254
- require "deterministic/core_ext/either" # this includes Deterministic in the global namespace!
255
- class UnderTest
256
- include Deterministic::CoreExt::Either
257
- def test
258
- attempt_all do
259
- try { foo }
260
- end
261
- end
262
-
263
- def foo
264
- 1
265
- end
266
- end
262
+ require 'deterministic/core_ext/object/result'
267
263
 
268
- ut = UnderTest.new
269
- ut.test # => Success(1)
264
+ [1].success? # => false
265
+ Success(1).failure? # => false
266
+ Success(1).success? # => true
267
+ Failure(1).result? # => true
270
268
  ```
271
269
 
272
- To add it to all classes
273
-
274
- ```ruby
275
- require "deterministic/core_ext/object/either" # this includes Deterministic to Object
276
-
277
- class UnderTest
278
- def test
279
- attempt_all do
280
- try { foo }
281
- end
282
- end
283
-
284
- def foo
285
- 1
286
- end
287
- end
288
-
289
- ut = UnderTest.new
290
- ut.test # => Success(1)
291
- ```
292
-
293
- or use it on built-in classes
294
-
295
- ```ruby
296
- require "deterministic/core_ext/object/either"
297
- h = {a:1}
298
- h.attempt_all do
299
- try { |s| s[:a] + 1}
300
- end # => Success(2)
301
- ```
302
270
 
303
271
  ## Maybe
304
272
  The simplest NullObject wrapper there can be. It adds `#some?` and `#none?` to `Object` though.
@@ -307,7 +275,7 @@ The simplest NullObject wrapper there can be. It adds `#some?` and `#none?` to `
307
275
  require 'deterministic/maybe' # you need to do this explicitly
308
276
  Maybe(nil).foo # => None
309
277
  Maybe(nil).foo.bar # => None
310
- Mmaybe({a: 1})[:a] # => 1
278
+ Maybe({a: 1})[:a] # => 1
311
279
 
312
280
  Maybe(nil).none? # => true
313
281
  Maybe({}).none? # => false
@@ -332,7 +300,7 @@ null.foo # => NoMethodError
332
300
 
333
301
  ## Inspirations
334
302
  * My [Monadic gem](http://github.com/pzol/monadic) of course
335
- * `#attempt_all` was somewhat inspired by [An error monad in Clojure](http://brehaut.net/blog/2011/error_monads)
303
+ * `#attempt_all` was somewhat inspired by [An error monad in Clojure](http://brehaut.net/blog/2011/error_monads) (attempt all has now been removed)
336
304
  * [Pithyless' rumblings](https://gist.github.com/pithyless/2216519)
337
305
  * [either by rsslldnphy](https://github.com/rsslldnphy/either)
338
306
  * [Functors, Applicatives, And Monads In Pictures](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html)
@@ -0,0 +1,6 @@
1
+ require "deterministic/core_ext/result"
2
+
3
+ include Deterministic
4
+ class Object
5
+ include Deterministic::CoreExt::Result
6
+ end
@@ -2,7 +2,7 @@ include Deterministic
2
2
 
3
3
  module Deterministic
4
4
  module CoreExt
5
- module Either
5
+ module Result
6
6
  def success?
7
7
  self.is_a? Success
8
8
  end
@@ -11,13 +11,9 @@ module Deterministic
11
11
  self.is_a? Failure
12
12
  end
13
13
 
14
- def either?
14
+ def result?
15
15
  success? || failure?
16
16
  end
17
-
18
- def attempt_all(context=self, &block)
19
- Deterministic::Either::AttemptAll.new(context, &block).call(self)
20
- end
21
17
  end
22
18
  end
23
19
  end
@@ -16,17 +16,17 @@ module Deterministic
16
16
  # The functor: takes a function (a -> b) and applies it to the inner value of the monad (Ma),
17
17
  # boxes it back to the same monad (Mb)
18
18
  # fmap :: (a -> b) -> M a -> M b
19
- def map(proc=nil, &block)
19
+ def fmap(proc=nil, &block)
20
20
  result = (proc || block).call(value)
21
21
  self.class.new(result)
22
22
  end
23
23
 
24
24
  # The monad: takes a function which returns a monad (of the same type), applies the function
25
- # bind :: M a -> (a -> Mb) -> M b
25
+ # bind :: (a -> Mb) -> M a -> M b
26
26
  # the self.class, i.e. the containing monad is passed as a second (optional) arg to the function
27
27
  def bind(proc=nil, &block)
28
28
  (proc || block).call(value, self.class).tap do |result|
29
- raise NotMonadError, "Expected #{result.inspect} to be an Either" unless result.is_a? self.class
29
+ raise NotMonadError, "Expected #{result.inspect} to be an Result" unless result.is_a? self.class
30
30
  end
31
31
  end
32
32
  alias :'>>=' :bind
@@ -0,0 +1,27 @@
1
+ module Deterministic
2
+ class Result
3
+ module Chain
4
+ def map(proc=nil, &block)
5
+ return self if failure?
6
+ bind(proc || block)
7
+ end
8
+
9
+ alias :>> :map
10
+
11
+ def map_err(proc=nil, &block)
12
+ return self if success?
13
+ bind(proc || block)
14
+ end
15
+
16
+ def try(proc=nil, &block)
17
+ map(proc, &block)
18
+ rescue => err
19
+ Failure(err)
20
+ end
21
+
22
+ alias :>= :try
23
+
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,5 @@
1
+ module Deterministic
2
+ class Failure < Result
3
+ class << self; public :new; end
4
+ end
5
+ end
@@ -4,7 +4,7 @@ module Deterministic::PatternMatching
4
4
  context ||= block.binding.eval('self')
5
5
  match = Match.new(self, context)
6
6
  match.instance_eval &block
7
- match.result
7
+ match.call
8
8
  end
9
9
 
10
10
  class NoMatchError < StandardError; end
@@ -16,14 +16,14 @@ module Deterministic::PatternMatching
16
16
  @collection = []
17
17
  end
18
18
 
19
- def result
19
+ def call
20
20
  matcher = @collection.detect { |m| m.matches?(@container.value) }
21
- raise NoMatchError, "No could be made for #{@container}" if matcher.nil?
21
+ raise NoMatchError, "No match could be made for #{@container.inspect}" if matcher.nil?
22
22
  @context.instance_exec(@container.value, &matcher.block)
23
23
  end
24
24
 
25
- # TODO: Either specific DSL, will need to move it to Either, later on
26
- %w[Success Failure Either].each do |s|
25
+ # TODO: Result specific DSL, will need to move it to Result, later on
26
+ %w[Success Failure Result].each do |s|
27
27
  define_method s.downcase.to_sym do |value=nil, &block|
28
28
  klas = Module.const_get(s)
29
29
  push(klas, value, block)
@@ -0,0 +1,5 @@
1
+ module Deterministic
2
+ class Success < Result
3
+ class << self; public :new; end
4
+ end
5
+ end
@@ -1,13 +1,13 @@
1
1
  module Deterministic
2
2
  # Abstract parent of Success and Failure
3
- class Either
3
+ class Result
4
4
  include Monad
5
5
  include Deterministic::PatternMatching
6
6
  include Chain
7
7
 
8
8
  def bind(proc=nil, &block)
9
- (proc || block).call(value, self.class).tap do |result|
10
- raise NotMonadError, "Expected #{result.inspect} to be an Either" unless result.is_a? self.class.superclass
9
+ (proc || block).call(value).tap do |result|
10
+ raise NotMonadError, "Expected #{result.inspect} to be an Result" unless result.is_a? self.class.superclass
11
11
  end
12
12
  end
13
13
 
@@ -19,9 +19,33 @@ module Deterministic
19
19
  is_a? Failure
20
20
  end
21
21
 
22
- def <<(other)
22
+ def pipe(proc=nil, &block)
23
+ (proc || block).call(self)
24
+ self
25
+ end
26
+
27
+ alias :** :pipe
28
+
29
+ def and(other)
30
+ return self if failure?
31
+ raise NotMonadError, "Expected #{other.inspect} to be an Result" unless other.is_a? Result
32
+ other
33
+ end
34
+
35
+ def and_then(&block)
23
36
  return self if failure?
24
- return other if other.is_a? Either
37
+ bind(&block)
38
+ end
39
+
40
+ def or(other)
41
+ return self if success?
42
+ raise NotMonadError, "Expected #{other.inspect} to be an Result" unless other.is_a? Result
43
+ return other
44
+ end
45
+
46
+ def or_else(&block)
47
+ return self if success?
48
+ bind(&block)
25
49
  end
26
50
 
27
51
  # This is an abstract class, can't ever instantiate it directly
@@ -40,7 +64,6 @@ module Deterministic
40
64
  end
41
65
 
42
66
  module_function
43
-
44
67
  def Success(value)
45
68
  Success.new(value)
46
69
  end
@@ -1,3 +1,3 @@
1
1
  module Deterministic
2
- VERSION = "0.8.1"
2
+ VERSION = "0.10.0"
3
3
  end
data/lib/deterministic.rb CHANGED
@@ -5,10 +5,9 @@ warn "WARN: Deterministic is meant to run on Ruby 2+" if RUBY_VERSION.to_f < 2
5
5
  module Deterministic; end
6
6
 
7
7
  require 'deterministic/monad'
8
- require 'deterministic/either/match'
9
- require 'deterministic/either/chain'
10
- require 'deterministic/either'
11
- require 'deterministic/either/attempt_all'
12
- require 'deterministic/either/success'
13
- require 'deterministic/either/failure'
8
+ require 'deterministic/result/match'
9
+ require 'deterministic/result/chain'
10
+ require 'deterministic/result'
11
+ require 'deterministic/result/success'
12
+ require 'deterministic/result/failure'
14
13
  require 'deterministic/none'
@@ -33,10 +33,8 @@ module Examples
33
33
  end
34
34
 
35
35
  def call(dirty_params)
36
- result = Either.attempt_all(self) do
37
- try { parse_params(dirty_params) }
38
- let { |params| read_bookings(params) }
39
- end.match(world) do
36
+
37
+ ( parse_params(dirty_params) >> method(:read_bookings) ).match(world) do
40
38
  success(Array) { |bookings| booking_list(bookings) }
41
39
  success { |booking| booking(booking) }
42
40
  failure(:no_bookings) { empty_booking_list }
@@ -49,7 +47,7 @@ module Examples
49
47
  attr_reader :bookings_repo, :world
50
48
 
51
49
  def parse_params(dirty_params)
52
- dirty_params
50
+ Success(dirty_params)
53
51
  end
54
52
 
55
53
  def read_bookings(params)
@@ -1,28 +1,11 @@
1
1
  require "spec_helper"
2
- require "deterministic/core_ext/object/either"
2
+ require "deterministic/core_ext/object/result"
3
3
 
4
- describe Deterministic::CoreExt::Either, "object", isolate: true do
4
+ describe Deterministic::CoreExt::Result, "object", isolate: true do
5
5
  it "does something" do
6
6
  h = {a: 1}
7
7
  expect(h.success?).to be_falsey
8
8
  expect(h.failure?).to be_falsey
9
- expect(h.either?).to be_falsey
10
- end
11
-
12
- it "use attempt_all in an instance" do
13
- class UnderTest
14
- def test
15
- attempt_all do
16
- try { foo }
17
- end
18
- end
19
-
20
- def foo
21
- 1
22
- end
23
- end
24
-
25
- ut = UnderTest.new
26
- expect(ut.test).to eq Success(1)
9
+ expect(h.result?).to be_falsey
27
10
  end
28
11
  end