fear 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|