fear 0.1.0 → 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/.yardopts +1 -0
- data/README.md +8 -0
- data/fear.gemspec +1 -1
- data/lib/fear/either.rb +192 -97
- data/lib/fear/failure.rb +15 -7
- data/lib/fear/for.rb +22 -7
- data/lib/fear/left.rb +21 -20
- data/lib/fear/none.rb +15 -6
- data/lib/fear/option.rb +123 -40
- data/lib/fear/right.rb +25 -20
- data/lib/fear/right_biased.rb +5 -9
- data/lib/fear/some.rb +13 -8
- data/lib/fear/success.rb +16 -11
- data/lib/fear/try.rb +203 -66
- data/lib/fear/utils.rb +1 -0
- data/lib/fear/version.rb +1 -1
- data/spec/fear/failure_spec.rb +7 -1
- data/spec/fear/left_spec.rb +12 -2
- data/spec/fear/none_spec.rb +10 -7
- data/spec/fear/option_spec.rb +7 -24
- data/spec/fear/right_spec.rb +16 -2
- data/spec/fear/some_spec.rb +11 -7
- data/spec/fear/success_spec.rb +5 -0
- metadata +4 -3
data/lib/fear/option.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
module Fear
|
2
|
-
# Represents optional values. Instances of
|
3
|
-
# are either an instance of
|
2
|
+
# Represents optional values. Instances of +Option+
|
3
|
+
# are either an instance of +Some+ or the object +None+.
|
4
4
|
#
|
5
|
-
# @example The most idiomatic way to use an
|
5
|
+
# @example The most idiomatic way to use an +Option+ instance is to treat it as a collection
|
6
6
|
# name = Option(params[:name])
|
7
7
|
# upper = name.map(&:strip).select { |n| n.length != 0 }.map(&:upcase)
|
8
8
|
# puts upper.get_or_else('')
|
9
9
|
#
|
10
|
-
# This allows for sophisticated chaining of
|
10
|
+
# This allows for sophisticated chaining of +Option+ values without
|
11
11
|
# having to check for the existence of a value.
|
12
12
|
#
|
13
|
-
# @example A less-idiomatic way to use
|
13
|
+
# @example A less-idiomatic way to use +Option+ values is via pattern matching
|
14
14
|
# name = Option(params[:name])
|
15
15
|
# case name
|
16
16
|
# when Some
|
@@ -27,61 +27,144 @@ module Fear
|
|
27
27
|
# puts name.strip.upcase
|
28
28
|
# end
|
29
29
|
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
30
|
+
# @!method get_or_else(*args)
|
31
|
+
# Returns the value from this +Some+ or evaluates the given
|
32
|
+
# default argument if this is a +None+.
|
33
|
+
# @overload get_or_else(&default)
|
34
|
+
# @yieldreturn [any]
|
35
|
+
# @return [any]
|
36
|
+
# @example
|
37
|
+
# Some(42).get_or_else { 24/2 } #=> 42
|
38
|
+
# None().get_or_else { 24/2 } #=> 12
|
39
|
+
# @overload get_or_else(default)
|
40
|
+
# @return [any]
|
41
|
+
# @example
|
42
|
+
# Some(42).get_or_else(12) #=> 42
|
43
|
+
# None().get_or_else(12) #=> 12
|
34
44
|
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
45
|
+
# @!method include?(other_value)
|
46
|
+
# Returns +true+ if it has an element that is equal
|
47
|
+
# (as determined by +==+) to +other_value+, +false+ otherwise.
|
48
|
+
# @param [any]
|
49
|
+
# @return [Boolean]
|
50
|
+
# @example
|
51
|
+
# Some(17).include?(17) #=> true
|
52
|
+
# Some(17).include?(7) #=> false
|
53
|
+
# None().include?(17) #=> false
|
38
54
|
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
55
|
+
# @!method each(&block)
|
56
|
+
# Performs the given block if this is a +Some+.
|
57
|
+
# @yieldparam [any] value
|
58
|
+
# @yieldreturn [void]
|
59
|
+
# @return [Option] itself
|
60
|
+
# @example
|
61
|
+
# Some(17).each do |value|
|
62
|
+
# puts value
|
63
|
+
# end #=> prints 17
|
43
64
|
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
65
|
+
# None().each do |value|
|
66
|
+
# puts value
|
67
|
+
# end #=> does nothing
|
68
|
+
#
|
69
|
+
# @!method map(&block)
|
70
|
+
# Maps the given block to the value from this +Some+ or
|
71
|
+
# returns this if this is a +None+
|
72
|
+
# @yieldparam [any] value
|
73
|
+
# @yieldreturn [any]
|
74
|
+
# @example
|
75
|
+
# Some(42).map { |v| v/2 } #=> Some(21)
|
76
|
+
# None().map { |v| v/2 } #=> None()
|
77
|
+
#
|
78
|
+
# @!method flat_map(&block)
|
79
|
+
# Returns the given block applied to the value from this +Some+
|
80
|
+
# or returns this if this is a +None+
|
81
|
+
# @yieldparam [any] value
|
82
|
+
# @yieldreturn [Option]
|
83
|
+
# @return [Option]
|
84
|
+
# @example
|
85
|
+
# Some(42).flat_map { |v| Some(v/2) } #=> Some(21)
|
86
|
+
# None().flat_map { |v| Some(v/2) } #=> None()
|
87
|
+
#
|
88
|
+
# @!method to_a
|
89
|
+
# Returns an +Array+ containing the +Some+ value or an
|
90
|
+
# empty +Array+ if this is a +None+
|
91
|
+
# @return [Array]
|
92
|
+
# @example
|
93
|
+
# Some(42).to_a #=> [21]
|
94
|
+
# None().to_a #=> []
|
95
|
+
#
|
96
|
+
# @!method any?(&predicate)
|
97
|
+
# Returns +false+ if +None+ or returns the result of the
|
98
|
+
# application of the given predicate to the +Some+ value.
|
99
|
+
# @yieldparam [any] value
|
100
|
+
# @yieldreturn [Boolean]
|
101
|
+
# @return [Boolean]
|
102
|
+
# @example
|
103
|
+
# Some(12).any?( |v| v > 10) #=> true
|
104
|
+
# Some(7).any?( |v| v > 10) #=> false
|
105
|
+
# None().any?( |v| v > 10) #=> false
|
106
|
+
#
|
107
|
+
# @!method select(&predicate)
|
108
|
+
# Returns self if it is nonempty and applying the predicate to this
|
109
|
+
# +Option+'s value returns +true+. Otherwise, return +None+.
|
110
|
+
# @yieldparam [any] value
|
111
|
+
# @yieldreturn [Boolean]
|
112
|
+
# @return [Option]
|
113
|
+
# @example
|
114
|
+
# Some(42).select { |v| v > 40 } #=> Success(21)
|
115
|
+
# Some(42).select { |v| v < 40 } #=> None()
|
116
|
+
# None().select { |v| v < 40 } #=> None()
|
117
|
+
#
|
118
|
+
# @!method reject(&predicate)
|
119
|
+
# Returns +Some+ if applying the predicate to this
|
120
|
+
# +Option+'s value returns +false+. Otherwise, return +None+.
|
121
|
+
# @yieldparam [any] value
|
122
|
+
# @yieldreturn [Boolean]
|
123
|
+
# @return [Option]
|
124
|
+
# @example
|
125
|
+
# Some(42).reject { |v| v > 40 } #=> None
|
126
|
+
# Some(42).reject { |v| v < 40 } #=> Some(42)
|
127
|
+
# None().reject { |v| v < 40 } #=> None
|
128
|
+
#
|
129
|
+
# @!method get
|
130
|
+
# @return [any] the +Option+'s value.
|
131
|
+
# @raise [NoSuchElementError] if the option is empty.
|
132
|
+
#
|
133
|
+
# @!method empty?
|
134
|
+
# Returns +true+ if the +Option+ is +None+, +false+ otherwise.
|
135
|
+
# @return [Boolean]
|
136
|
+
# @example
|
137
|
+
# Some(42).empty? #=> false
|
138
|
+
# None().empty? #=> true
|
48
139
|
#
|
49
140
|
# @see https://github.com/scala/scala/blob/2.11.x/src/library/scala/Option.scala
|
50
141
|
#
|
51
142
|
module Option
|
143
|
+
# @private
|
52
144
|
def left_class
|
53
145
|
None
|
54
146
|
end
|
55
147
|
|
148
|
+
# @private
|
56
149
|
def right_class
|
57
150
|
Some
|
58
151
|
end
|
59
152
|
|
60
|
-
#
|
61
|
-
# false otherwise.
|
62
|
-
#
|
63
|
-
def empty?
|
64
|
-
is_a?(None)
|
65
|
-
end
|
66
|
-
|
67
|
-
# Returns the option's value if it is nonempty,
|
68
|
-
# or `nil` if it is empty. Useful for unwrapping
|
69
|
-
# option's value.
|
70
|
-
#
|
71
|
-
# @return [Object, nil] the option's value if it is
|
72
|
-
# nonempty or `nil` if it is empty
|
73
|
-
#
|
153
|
+
# Include this mixin to access convenient factory methods.
|
74
154
|
# @example
|
75
|
-
# Option
|
76
|
-
#
|
155
|
+
# include Fear::Option::Mixin
|
156
|
+
#
|
157
|
+
# Option(17) #=> #<Fear::Some value=17>
|
158
|
+
# Option(nil) #=> #<Fear::None>
|
159
|
+
# Some(17) #=> #<Fear::Some value=17>
|
160
|
+
# None() #=> #<Fear::None>
|
77
161
|
#
|
78
|
-
def or_nil
|
79
|
-
get_or_else { nil }
|
80
|
-
end
|
81
|
-
|
82
162
|
module Mixin
|
163
|
+
# An +Option+ factory which creates +Some+ if the argument is
|
164
|
+
# not +nil+, and +None+ if it is +nil+.
|
83
165
|
# @param value [any]
|
84
166
|
# @return [Some, None]
|
167
|
+
#
|
85
168
|
def Option(value)
|
86
169
|
if value.nil?
|
87
170
|
None()
|
data/lib/fear/right.rb
CHANGED
@@ -3,13 +3,21 @@ module Fear
|
|
3
3
|
include Either
|
4
4
|
include RightBiased::Right
|
5
5
|
|
6
|
-
#
|
7
|
-
|
8
|
-
|
6
|
+
# @return [true]
|
7
|
+
def right?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
alias success? right?
|
11
|
+
|
12
|
+
# @return [false]
|
13
|
+
def left?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
alias failure? left?
|
17
|
+
|
9
18
|
# @param default [Proc, any]
|
10
19
|
# @return [Either]
|
11
|
-
|
12
|
-
def select(default)
|
20
|
+
def select_or_else(default)
|
13
21
|
if yield(value)
|
14
22
|
self
|
15
23
|
else
|
@@ -17,38 +25,35 @@ module Fear
|
|
17
25
|
end
|
18
26
|
end
|
19
27
|
|
28
|
+
# @return [Either]
|
29
|
+
def select
|
30
|
+
if yield(value)
|
31
|
+
self
|
32
|
+
else
|
33
|
+
Left.new(value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
20
37
|
# @return [Left] value in `Left`
|
21
38
|
def swap
|
22
39
|
Left.new(value)
|
23
40
|
end
|
24
41
|
|
25
|
-
# @param reduce_right [Proc]
|
26
|
-
# @return [any]
|
27
|
-
#
|
42
|
+
# @param reduce_right [Proc]
|
43
|
+
# @return [any]
|
28
44
|
def reduce(_, reduce_right)
|
29
45
|
reduce_right.call(value)
|
30
46
|
end
|
31
47
|
|
32
|
-
# Joins an `Either` through `Right`.
|
33
|
-
#
|
34
|
-
# This method requires that the right side of this `Either` is itself an
|
35
|
-
# Either type.
|
36
|
-
#
|
37
|
-
# This method, and `join_left`, are analogous to `Option#flatten`
|
38
|
-
#
|
39
48
|
# @return [Either]
|
40
|
-
# @raise [TypeError]
|
41
|
-
#
|
49
|
+
# @raise [TypeError]
|
42
50
|
def join_right
|
43
51
|
value.tap do |v|
|
44
52
|
Utils.assert_type!(v, Either)
|
45
53
|
end
|
46
54
|
end
|
47
55
|
|
48
|
-
# Joins an `Either` through `Left`.
|
49
|
-
#
|
50
56
|
# @return [self]
|
51
|
-
#
|
52
57
|
def join_left
|
53
58
|
self
|
54
59
|
end
|
data/lib/fear/right_biased.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module Fear
|
2
|
+
# @private
|
2
3
|
module RightBiased
|
3
4
|
# Performs necessary interface and type checks.
|
4
5
|
#
|
@@ -31,11 +32,11 @@ module Fear
|
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
34
|
-
#
|
35
|
+
# @overload get_or_else(default)
|
35
36
|
# @param default [any]
|
36
37
|
# @return [any] the `#value`.
|
37
38
|
#
|
38
|
-
#
|
39
|
+
# @overload get_or_else(&default)
|
39
40
|
# @return [any] the `#value`.
|
40
41
|
#
|
41
42
|
def get_or_else(*_args)
|
@@ -43,17 +44,12 @@ module Fear
|
|
43
44
|
end
|
44
45
|
|
45
46
|
# @param [any]
|
46
|
-
# @return [Boolean]
|
47
|
-
# (as determined by `==`) to `other_value`, `false` otherwise.
|
48
|
-
#
|
47
|
+
# @return [Boolean]
|
49
48
|
def include?(other_value)
|
50
49
|
value == other_value
|
51
50
|
end
|
52
51
|
|
53
|
-
# Executes the given side-effecting block.
|
54
|
-
#
|
55
52
|
# @return [self]
|
56
|
-
#
|
57
53
|
def each
|
58
54
|
yield(value)
|
59
55
|
self
|
@@ -98,7 +94,7 @@ module Fear
|
|
98
94
|
# @param default [any]
|
99
95
|
# @return [any] default value
|
100
96
|
#
|
101
|
-
# @!method get_or_else
|
97
|
+
# @!method get_or_else(&default)
|
102
98
|
# @return [any] result of evaluating a block.
|
103
99
|
#
|
104
100
|
def get_or_else(*args)
|
data/lib/fear/some.rb
CHANGED
@@ -11,15 +11,22 @@ module Fear
|
|
11
11
|
@value = value
|
12
12
|
end
|
13
13
|
|
14
|
-
# @return
|
14
|
+
# @return [any]
|
15
15
|
def get
|
16
16
|
@value
|
17
17
|
end
|
18
18
|
|
19
|
-
# @return [
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
# @return [any]
|
20
|
+
def or_nil
|
21
|
+
@value
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [false]
|
25
|
+
def empty?
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Option]
|
23
30
|
def select
|
24
31
|
if yield(value)
|
25
32
|
self
|
@@ -28,9 +35,7 @@ module Fear
|
|
28
35
|
end
|
29
36
|
end
|
30
37
|
|
31
|
-
# @return [Option]
|
32
|
-
# option's value returns false. Otherwise, return `None`.
|
33
|
-
#
|
38
|
+
# @return [Option]
|
34
39
|
def reject
|
35
40
|
if yield(value)
|
36
41
|
None.new
|
data/lib/fear/success.rb
CHANGED
@@ -7,27 +7,32 @@ module Fear
|
|
7
7
|
attr_reader :value
|
8
8
|
protected :value
|
9
9
|
|
10
|
+
# @param [any]
|
10
11
|
def initialize(value)
|
11
12
|
@value = value
|
12
13
|
end
|
13
14
|
|
15
|
+
# @return [any]
|
14
16
|
def get
|
15
17
|
@value
|
16
18
|
end
|
17
19
|
|
20
|
+
# @return [Boolean]
|
18
21
|
def success?
|
19
22
|
true
|
20
23
|
end
|
21
24
|
|
22
|
-
# @return [
|
25
|
+
# @return [false]
|
26
|
+
def failure?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Success]
|
23
31
|
def or_else
|
24
32
|
self
|
25
33
|
end
|
26
34
|
|
27
|
-
# Transforms a nested `Try`, ie, a `Success` of `Success``,
|
28
|
-
# into an un-nested `Try`, ie, a `Success`.
|
29
35
|
# @return [Try]
|
30
|
-
#
|
31
36
|
def flatten
|
32
37
|
if value.is_a?(Try)
|
33
38
|
value.flatten
|
@@ -36,12 +41,9 @@ module Fear
|
|
36
41
|
end
|
37
42
|
end
|
38
43
|
|
39
|
-
# Converts this to a `Failure` if the predicate
|
40
|
-
# is not satisfied.
|
41
44
|
# @yieldparam [any] value
|
42
45
|
# @yieldreturn [Boolean]
|
43
46
|
# @return [Try]
|
44
|
-
#
|
45
47
|
def select
|
46
48
|
if yield(value)
|
47
49
|
self
|
@@ -52,14 +54,12 @@ module Fear
|
|
52
54
|
Failure.new(error)
|
53
55
|
end
|
54
56
|
|
55
|
-
# @return [Success]
|
56
|
-
#
|
57
|
+
# @return [Success]
|
57
58
|
def recover_with
|
58
59
|
self
|
59
60
|
end
|
60
61
|
|
61
|
-
# @return [Success]
|
62
|
-
#
|
62
|
+
# @return [Success]
|
63
63
|
def recover
|
64
64
|
self
|
65
65
|
end
|
@@ -77,5 +77,10 @@ module Fear
|
|
77
77
|
rescue => error
|
78
78
|
Failure.new(error)
|
79
79
|
end
|
80
|
+
|
81
|
+
# @return [Right]
|
82
|
+
def to_either
|
83
|
+
Right.new(value)
|
84
|
+
end
|
80
85
|
end
|
81
86
|
end
|