divergent 0.1.4 → 0.2.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 +4 -4
- data/README.md +2 -2
- data/lib/divergent/maybe.rb +44 -52
- data/lib/divergent/monad.rb +17 -8
- data/lib/divergent/try.rb +19 -32
- data/lib/divergent/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f041ffcec9e7a3a5287941abf2e229cd6644229
|
4
|
+
data.tar.gz: 6ce3a0fe3cd1798cd1a96cf7f27a9e79f36fa871
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c19e6ec8931dc0d5a719c5ac5a6fd8603badd8672cab190106effac007230f9a281824b6dfd5c18ecd05d264ced8cf5be879565d2064d3131b8626820f0dd16
|
7
|
+
data.tar.gz: 0170760e83aed59e80d28b741b4adc7e947a222773292481956bd332907e7b8aeca0c16d11f741c64450fba7f46c4f3d8b7a9eaa574605e623207bff7572e22d
|
data/README.md
CHANGED
@@ -79,9 +79,9 @@ Try { 1 / 0 }.recover(ZeroDivisionError, &:message)
|
|
79
79
|
|
80
80
|
``` ruby
|
81
81
|
# provide default value
|
82
|
-
user = Maybe
|
82
|
+
user = Maybe(User.find('a_non_exist_id'))
|
83
83
|
user.get_or_else(default_user)
|
84
|
-
user.or_else(
|
84
|
+
user.or_else Maybe(User.find_by_name("username"))
|
85
85
|
|
86
86
|
# usage as a collection
|
87
87
|
user.each { |u| p u}
|
data/lib/divergent/maybe.rb
CHANGED
@@ -5,38 +5,23 @@ require_relative 'monad'
|
|
5
5
|
|
6
6
|
module Divergent
|
7
7
|
##
|
8
|
-
#
|
9
|
-
# are either an instance of Some or the object None.
|
8
|
+
# == Optional values.
|
10
9
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
10
|
+
# An instance of Some or the object None.
|
11
|
+
#
|
12
|
+
# The most idiomatic way to use an Maybe instance is to treat it
|
13
|
+
# as a collection or monad and use `map`, `fmap`, `filter`, or `each`.
|
14
14
|
class Maybe
|
15
15
|
include Monad
|
16
|
-
|
17
|
-
##
|
18
|
-
# An Maybe factory which return None.
|
19
|
-
# This always return the same None object.
|
20
|
-
#
|
21
|
-
# Example:
|
22
|
-
#
|
23
|
-
# ```
|
24
|
-
# Maybe.empty == Maybe.empty
|
25
|
-
# ```
|
26
|
-
def self.empty
|
27
|
-
None
|
28
|
-
end
|
29
|
-
|
30
16
|
##
|
31
17
|
# An factory which creates Some(v) if the argument is not nil,
|
32
18
|
# and None if it is nil.
|
33
19
|
#
|
34
20
|
# Examples:
|
35
21
|
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
# ```
|
22
|
+
# Maybe.unit(1) # => Some(1)
|
23
|
+
# Maybe.unit(nil) # => None
|
24
|
+
#
|
40
25
|
def self.unit(v)
|
41
26
|
if v.nil?
|
42
27
|
None
|
@@ -45,6 +30,20 @@ module Divergent
|
|
45
30
|
end
|
46
31
|
end
|
47
32
|
|
33
|
+
|
34
|
+
##
|
35
|
+
# An Maybe factory which return None.
|
36
|
+
#
|
37
|
+
# This always return the same None object.
|
38
|
+
#
|
39
|
+
# Example:
|
40
|
+
#
|
41
|
+
# Maybe.empty == Maybe.empty
|
42
|
+
#
|
43
|
+
def self.empty
|
44
|
+
None
|
45
|
+
end
|
46
|
+
|
48
47
|
##
|
49
48
|
# Returns the result of applying block to this Maybe value,
|
50
49
|
# if this value is not empty.
|
@@ -55,11 +54,10 @@ module Divergent
|
|
55
54
|
#
|
56
55
|
# Examples
|
57
56
|
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
# some_hash
|
61
|
-
#
|
62
|
-
# ```
|
57
|
+
# Maybe.unit(1).fmap { |v| Maybe.unit(v + 1) } # => Some(2)
|
58
|
+
# some_hash = {}
|
59
|
+
# Maybe.unit(:a).fmap { |v| Maybe.unit(some_hash[v]) } # => None
|
60
|
+
#
|
63
61
|
def fmap() # :yields: v
|
64
62
|
if empty?
|
65
63
|
None
|
@@ -120,11 +118,7 @@ module Divergent
|
|
120
118
|
# This is similar to +flat_map+ except here,
|
121
119
|
# block does not need to wrap its result in a maybe.
|
122
120
|
def map() # :yields: v
|
123
|
-
|
124
|
-
None
|
125
|
-
else
|
126
|
-
Maybe.unit(yield get)
|
127
|
-
end
|
121
|
+
fmap { |v| Maybe.unit(yield v) }
|
128
122
|
end
|
129
123
|
|
130
124
|
|
@@ -132,10 +126,8 @@ module Divergent
|
|
132
126
|
# Return this maybe if it is not empty and the predicate block evals to true.
|
133
127
|
# Otherwise, return None.
|
134
128
|
def filter() # :yields: v
|
135
|
-
|
136
|
-
|
137
|
-
else
|
138
|
-
None
|
129
|
+
fmap do |v|
|
130
|
+
yield(v) ? Maybe.unit(v) : None
|
139
131
|
end
|
140
132
|
end
|
141
133
|
|
@@ -144,11 +136,11 @@ module Divergent
|
|
144
136
|
#
|
145
137
|
# Examples:
|
146
138
|
#
|
147
|
-
#
|
148
|
-
#
|
149
|
-
#
|
150
|
-
#
|
151
|
-
#
|
139
|
+
#
|
140
|
+
# Maybe.unit(1).include?(1) #=> true
|
141
|
+
# Maybe.unit(1).include?(2) #=> false
|
142
|
+
# Maybe.empty.include?(1) #=> false
|
143
|
+
#
|
152
144
|
def include?(elem)
|
153
145
|
!empty? && get == elem
|
154
146
|
end
|
@@ -158,11 +150,11 @@ module Divergent
|
|
158
150
|
#
|
159
151
|
# Examples:
|
160
152
|
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
153
|
+
#
|
154
|
+
# Maybe.unit(1).any?{ |v| v == 1} #=> true
|
155
|
+
# Maybe.unit(1).any?{ |v| v == 2} #=> false
|
156
|
+
# Maybe.empty.any?{ |v| v == 1} #=> false
|
157
|
+
#
|
166
158
|
def any?() # :yields: v
|
167
159
|
!empty? && yield(get)
|
168
160
|
end
|
@@ -173,11 +165,11 @@ module Divergent
|
|
173
165
|
#
|
174
166
|
# Examples:
|
175
167
|
#
|
176
|
-
#
|
177
|
-
#
|
178
|
-
#
|
179
|
-
#
|
180
|
-
#
|
168
|
+
#
|
169
|
+
# Maybe.unit(1).all?{ |v| v == 1} #=> true
|
170
|
+
# Maybe.unit(1).all?{ |v| v == 2} #=> false
|
171
|
+
# Maybe.empty.all?{ |v| v == 1} #=> true
|
172
|
+
#
|
181
173
|
def all?() # :yields: v
|
182
174
|
empty? || yield(get)
|
183
175
|
end
|
data/lib/divergent/monad.rb
CHANGED
@@ -4,17 +4,26 @@ module Divergent
|
|
4
4
|
#
|
5
5
|
# Examples:
|
6
6
|
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
7
|
+
#
|
8
|
+
# Maybe.unit(1) # => Some(1)
|
9
|
+
# Maybe.unit(1).fmap { |v| v + 1 } => Some(2)
|
10
|
+
#
|
11
11
|
module Monad
|
12
|
-
|
13
|
-
|
12
|
+
module InstanceMethods
|
13
|
+
def fmap(&f)
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def unit(v)
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
14
22
|
end
|
15
23
|
|
16
|
-
def
|
17
|
-
|
24
|
+
def self.included(subclass)
|
25
|
+
subclass.extend ClassMethods
|
26
|
+
subclass.include InstanceMethods
|
18
27
|
end
|
19
28
|
end
|
20
29
|
end
|
data/lib/divergent/try.rb
CHANGED
@@ -15,8 +15,10 @@ module Divergent
|
|
15
15
|
# all of the places that an exception might occur.
|
16
16
|
module Try
|
17
17
|
include Monad
|
18
|
-
def self.unit(
|
19
|
-
Success.new(
|
18
|
+
def self.unit()
|
19
|
+
Success.new(yield)
|
20
|
+
rescue => e
|
21
|
+
Failure.new(e)
|
20
22
|
end
|
21
23
|
|
22
24
|
# Returns `true` if the `Try` is a `Failure`, `false` otherwise.
|
@@ -84,6 +86,7 @@ module Divergent
|
|
84
86
|
# otherwise returns this if this is a `Success`.
|
85
87
|
#
|
86
88
|
# Notes: block call should return an instance of Try.
|
89
|
+
# And, error raised from the block call will not rescued by it!
|
87
90
|
# This is like `fmap` for the exception.
|
88
91
|
def recover_with(&block)
|
89
92
|
raise NotImplementedError
|
@@ -93,6 +96,7 @@ module Divergent
|
|
93
96
|
# and leave other error case unrecoverd.
|
94
97
|
# If no class is given, recover it anyway.
|
95
98
|
# The error instance(if this is a Failure) will be passed into the block.
|
99
|
+
# And, error raised from the block call will not rescued by it!
|
96
100
|
# Otherwise returns this if this is a `Success`.
|
97
101
|
#
|
98
102
|
# This is like `fmap` for the exception.
|
@@ -156,25 +160,18 @@ module Divergent
|
|
156
160
|
end
|
157
161
|
|
158
162
|
def map()
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
Failure.new(e)
|
163
|
-
end
|
164
|
-
|
165
|
-
Success.new(t)
|
163
|
+
fmap do |v|
|
164
|
+
Try.unit { yield v }
|
165
|
+
end
|
166
166
|
end
|
167
167
|
|
168
168
|
def filter()
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
self
|
176
|
-
else
|
177
|
-
Failure.new(NoSuchElementError.new("Predicate does not hold for #{@value}"))
|
169
|
+
fmap do |v|
|
170
|
+
if yield(v)
|
171
|
+
self
|
172
|
+
else
|
173
|
+
Failure.new(NoSuchElementError.new("Predicate does not hold for #{v}"))
|
174
|
+
end
|
178
175
|
end
|
179
176
|
end
|
180
177
|
|
@@ -249,11 +246,7 @@ module Divergent
|
|
249
246
|
end
|
250
247
|
|
251
248
|
def recover_with()
|
252
|
-
|
253
|
-
yield(@error)
|
254
|
-
rescue => e
|
255
|
-
Failure.new(e)
|
256
|
-
end
|
249
|
+
yield(@error)
|
257
250
|
end
|
258
251
|
|
259
252
|
def recover(*errors)
|
@@ -264,12 +257,8 @@ module Divergent
|
|
264
257
|
|
265
258
|
raise 'no block given' unless block_given?
|
266
259
|
|
267
|
-
|
268
|
-
|
269
|
-
Success.new(t)
|
270
|
-
rescue => e
|
271
|
-
Failure.new(e)
|
272
|
-
end
|
260
|
+
t = yield(@error)
|
261
|
+
Success.new(t)
|
273
262
|
end
|
274
263
|
|
275
264
|
def failed
|
@@ -303,9 +292,7 @@ module Divergent
|
|
303
292
|
# method will ensure any StandardError is caught and a
|
304
293
|
# `Failure` object is returned.
|
305
294
|
def Try
|
306
|
-
|
307
|
-
rescue => e
|
308
|
-
Failure.new(e)
|
295
|
+
Try.unit { yield }
|
309
296
|
end
|
310
297
|
module_function :Try
|
311
298
|
end
|
data/lib/divergent/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: divergent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cao Jiafeng
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -109,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
109
|
version: '0'
|
110
110
|
requirements: []
|
111
111
|
rubyforge_project:
|
112
|
-
rubygems_version: 2.5.1
|
112
|
+
rubygems_version: 2.4.5.1
|
113
113
|
signing_key:
|
114
114
|
specification_version: 4
|
115
115
|
summary: a collection of monad implemented in ruby inspired by scala
|