fear 0.9.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/rubocop.yml +39 -0
- data/.github/workflows/spec.yml +42 -0
- data/.gitignore +0 -1
- data/.rubocop.yml +4 -12
- data/.simplecov +17 -0
- data/CHANGELOG.md +40 -0
- data/Gemfile +5 -2
- data/Gemfile.lock +130 -0
- data/LICENSE.txt +1 -1
- data/README.md +1293 -97
- data/Rakefile +369 -1
- data/benchmarks/README.md +1 -0
- data/benchmarks/dry_do_vs_fear_for.txt +11 -0
- data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +11 -0
- data/benchmarks/factorial.txt +16 -0
- data/benchmarks/fear_gaurd_and1_vs_new.txt +13 -0
- data/benchmarks/fear_gaurd_and2_vs_and.txt +13 -0
- data/benchmarks/fear_gaurd_and3_vs_and_and.txt +13 -0
- data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +11 -0
- data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +13 -0
- data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +14 -0
- data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +11 -0
- data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +11 -0
- data/examples/pattern_extracting.rb +17 -0
- data/examples/pattern_extracting_ruby2.7.rb +15 -0
- data/examples/pattern_matching_binary_tree_set.rb +101 -0
- data/examples/pattern_matching_number_in_words.rb +60 -0
- data/fear.gemspec +34 -23
- data/lib/dry/types/fear.rb +8 -0
- data/lib/dry/types/fear/option.rb +125 -0
- data/lib/fear.rb +65 -15
- data/lib/fear/await.rb +33 -0
- data/lib/fear/awaitable.rb +28 -0
- data/lib/fear/either.rb +131 -71
- data/lib/fear/either_api.rb +23 -0
- data/lib/fear/either_pattern_match.rb +53 -0
- data/lib/fear/empty_partial_function.rb +38 -0
- data/lib/fear/extractor.rb +112 -0
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +10 -0
- data/lib/fear/extractor/any_matcher.rb +17 -0
- data/lib/fear/extractor/array_head_matcher.rb +36 -0
- data/lib/fear/extractor/array_matcher.rb +40 -0
- data/lib/fear/extractor/array_splat_matcher.rb +16 -0
- data/lib/fear/extractor/empty_list_matcher.rb +20 -0
- data/lib/fear/extractor/extractor_matcher.rb +44 -0
- data/lib/fear/extractor/grammar.rb +203 -0
- data/lib/fear/extractor/grammar.treetop +129 -0
- data/lib/fear/extractor/identifier_matcher.rb +18 -0
- data/lib/fear/extractor/matcher.rb +53 -0
- data/lib/fear/extractor/matcher/and.rb +38 -0
- data/lib/fear/extractor/named_array_splat_matcher.rb +17 -0
- data/lib/fear/extractor/pattern.rb +58 -0
- data/lib/fear/extractor/typed_identifier_matcher.rb +26 -0
- data/lib/fear/extractor/value_matcher.rb +19 -0
- data/lib/fear/extractor_api.rb +35 -0
- data/lib/fear/failure.rb +46 -14
- data/lib/fear/failure_pattern_match.rb +10 -0
- data/lib/fear/for.rb +37 -95
- data/lib/fear/for_api.rb +68 -0
- data/lib/fear/future.rb +497 -0
- data/lib/fear/future_api.rb +21 -0
- data/lib/fear/left.rb +19 -2
- data/lib/fear/left_pattern_match.rb +11 -0
- data/lib/fear/none.rb +67 -3
- data/lib/fear/none_pattern_match.rb +14 -0
- data/lib/fear/option.rb +120 -56
- data/lib/fear/option_api.rb +40 -0
- data/lib/fear/option_pattern_match.rb +48 -0
- data/lib/fear/partial_function.rb +176 -0
- data/lib/fear/partial_function/and_then.rb +50 -0
- data/lib/fear/partial_function/any.rb +28 -0
- data/lib/fear/partial_function/combined.rb +53 -0
- data/lib/fear/partial_function/empty.rb +10 -0
- data/lib/fear/partial_function/guard.rb +80 -0
- data/lib/fear/partial_function/guard/and.rb +38 -0
- data/lib/fear/partial_function/guard/and3.rb +41 -0
- data/lib/fear/partial_function/guard/or.rb +38 -0
- data/lib/fear/partial_function/lifted.rb +23 -0
- data/lib/fear/partial_function/or_else.rb +64 -0
- data/lib/fear/partial_function_class.rb +38 -0
- data/lib/fear/pattern_match.rb +114 -0
- data/lib/fear/pattern_matching_api.rb +137 -0
- data/lib/fear/promise.rb +95 -0
- data/lib/fear/right.rb +20 -2
- data/lib/fear/right_biased.rb +6 -14
- data/lib/fear/right_pattern_match.rb +11 -0
- data/lib/fear/some.rb +55 -3
- data/lib/fear/some_pattern_match.rb +13 -0
- data/lib/fear/struct.rb +248 -0
- data/lib/fear/success.rb +35 -5
- data/lib/fear/success_pattern_match.rb +12 -0
- data/lib/fear/try.rb +136 -79
- data/lib/fear/try_api.rb +33 -0
- data/lib/fear/try_pattern_match.rb +33 -0
- data/lib/fear/unit.rb +32 -0
- data/lib/fear/utils.rb +39 -14
- data/lib/fear/version.rb +4 -1
- data/spec/dry/types/fear/option/constrained_spec.rb +22 -0
- data/spec/dry/types/fear/option/core_spec.rb +77 -0
- data/spec/dry/types/fear/option/default_spec.rb +21 -0
- data/spec/dry/types/fear/option/hash_spec.rb +58 -0
- data/spec/dry/types/fear/option/option_spec.rb +97 -0
- data/spec/fear/awaitable_spec.rb +17 -0
- data/spec/fear/done_spec.rb +8 -6
- data/spec/fear/either/mixin_spec.rb +17 -0
- data/spec/fear/either_pattern_match_spec.rb +37 -0
- data/spec/fear/either_pattern_matching_spec.rb +28 -0
- data/spec/fear/extractor/array_matcher_spec.rb +230 -0
- data/spec/fear/extractor/extractor_matcher_spec.rb +153 -0
- data/spec/fear/extractor/grammar_array_spec.rb +25 -0
- data/spec/fear/extractor/identified_matcher_spec.rb +49 -0
- data/spec/fear/extractor/identifier_matcher_spec.rb +68 -0
- data/spec/fear/extractor/pattern_spec.rb +34 -0
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +64 -0
- data/spec/fear/extractor/value_matcher_number_spec.rb +79 -0
- data/spec/fear/extractor/value_matcher_string_spec.rb +88 -0
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +71 -0
- data/spec/fear/extractor_api_spec.rb +115 -0
- data/spec/fear/extractor_spec.rb +61 -0
- data/spec/fear/failure_spec.rb +145 -45
- data/spec/fear/for_spec.rb +57 -67
- data/spec/fear/future_spec.rb +691 -0
- data/spec/fear/guard_spec.rb +103 -0
- data/spec/fear/left_spec.rb +112 -46
- data/spec/fear/none_spec.rb +114 -16
- data/spec/fear/option/mixin_spec.rb +39 -0
- data/spec/fear/option_pattern_match_spec.rb +35 -0
- data/spec/fear/option_pattern_matching_spec.rb +34 -0
- data/spec/fear/option_spec.rb +121 -8
- data/spec/fear/partial_function/empty_spec.rb +38 -0
- data/spec/fear/partial_function_and_then_spec.rb +147 -0
- data/spec/fear/partial_function_composition_spec.rb +82 -0
- data/spec/fear/partial_function_or_else_spec.rb +276 -0
- data/spec/fear/partial_function_spec.rb +239 -0
- data/spec/fear/pattern_match_spec.rb +93 -0
- data/spec/fear/pattern_matching_api_spec.rb +31 -0
- data/spec/fear/promise_spec.rb +96 -0
- data/spec/fear/right_biased/left.rb +29 -32
- data/spec/fear/right_biased/right.rb +51 -54
- data/spec/fear/right_spec.rb +109 -41
- data/spec/fear/some_spec.rb +80 -15
- data/spec/fear/success_spec.rb +99 -32
- data/spec/fear/try/mixin_spec.rb +19 -0
- data/spec/fear/try_pattern_match_spec.rb +37 -0
- data/spec/fear/try_pattern_matching_spec.rb +34 -0
- data/spec/fear/utils_spec.rb +16 -14
- data/spec/spec_helper.rb +13 -7
- data/spec/struct_pattern_matching_spec.rb +36 -0
- data/spec/struct_spec.rb +226 -0
- data/spec/support/dry_types.rb +6 -0
- metadata +320 -29
- data/.travis.yml +0 -9
- data/lib/fear/done.rb +0 -22
- data/lib/fear/for/evaluation_context.rb +0 -91
data/lib/fear/success.rb
CHANGED
@@ -1,8 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
class Success
|
3
5
|
include Try
|
4
|
-
include Dry::Equalizer(:value)
|
5
6
|
include RightBiased::Right
|
7
|
+
include SuccessPatternMatch.mixin
|
8
|
+
|
9
|
+
EXTRACTOR = proc do |try|
|
10
|
+
if Fear::Success === try
|
11
|
+
Fear.some([try.get])
|
12
|
+
else
|
13
|
+
Fear.none
|
14
|
+
end
|
15
|
+
end
|
16
|
+
public_constant :EXTRACTOR
|
6
17
|
|
7
18
|
attr_reader :value
|
8
19
|
protected :value
|
@@ -48,9 +59,9 @@ module Fear
|
|
48
59
|
if yield(value)
|
49
60
|
self
|
50
61
|
else
|
51
|
-
|
62
|
+
raise NoSuchElementError, "Predicate does not hold for `#{value}`"
|
52
63
|
end
|
53
|
-
rescue => error
|
64
|
+
rescue StandardError => error
|
54
65
|
Failure.new(error)
|
55
66
|
end
|
56
67
|
|
@@ -67,14 +78,14 @@ module Fear
|
|
67
78
|
# @return [Try]
|
68
79
|
def map
|
69
80
|
super
|
70
|
-
rescue => error
|
81
|
+
rescue StandardError => error
|
71
82
|
Failure.new(error)
|
72
83
|
end
|
73
84
|
|
74
85
|
# @return [Try]
|
75
86
|
def flat_map
|
76
87
|
super
|
77
|
-
rescue => error
|
88
|
+
rescue StandardError => error
|
78
89
|
Failure.new(error)
|
79
90
|
end
|
80
91
|
|
@@ -82,5 +93,24 @@ module Fear
|
|
82
93
|
def to_either
|
83
94
|
Right.new(value)
|
84
95
|
end
|
96
|
+
|
97
|
+
# @param other [Any]
|
98
|
+
# @return [Boolean]
|
99
|
+
def ==(other)
|
100
|
+
other.is_a?(Success) && value == other.value
|
101
|
+
end
|
102
|
+
|
103
|
+
# @return [String]
|
104
|
+
def inspect
|
105
|
+
"#<Fear::Success value=#{value.inspect}>"
|
106
|
+
end
|
107
|
+
|
108
|
+
# @return [String]
|
109
|
+
alias to_s inspect
|
110
|
+
|
111
|
+
# @return [<any>]
|
112
|
+
def deconstruct
|
113
|
+
[value]
|
114
|
+
end
|
85
115
|
end
|
86
116
|
end
|
data/lib/fear/try.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
# The +Try+ represents a computation that may either result
|
3
5
|
# in an exception, or return a successfully computed value. Instances of +Try+,
|
@@ -11,15 +13,23 @@ module Fear
|
|
11
13
|
# @example
|
12
14
|
# include Fear::Try::Mixin
|
13
15
|
#
|
14
|
-
# dividend =
|
15
|
-
# divisor =
|
16
|
+
# dividend = Fear.try { Integer(params[:dividend]) }
|
17
|
+
# divisor = Fear.try { Integer(params[:divisor]) }
|
16
18
|
# problem = dividend.flat_map { |x| divisor.map { |y| x / y } }
|
17
19
|
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
20
|
+
# problem.match |m|
|
21
|
+
# m.success do |result|
|
22
|
+
# puts "Result of #{dividend.get} / #{divisor.get} is: #{result}"
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# m.failure(ZeroDivisionError) do
|
26
|
+
# puts "Division by zero is not allowed"
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# m.failure do |exception|
|
30
|
+
# puts "You entered something wrong. Try again"
|
31
|
+
# puts "Info from the exception: #{exception.message}"
|
32
|
+
# end
|
23
33
|
# end
|
24
34
|
#
|
25
35
|
# An important property of +Try+ shown in the above example is its
|
@@ -45,13 +55,13 @@ module Fear
|
|
45
55
|
# @yieldreturn [any]
|
46
56
|
# @return [any]
|
47
57
|
# @example
|
48
|
-
#
|
49
|
-
#
|
58
|
+
# Fear.success(42).get_or_else { 24/2 } #=> 42
|
59
|
+
# Fear.failure(ArgumentError.new).get_or_else { 24/2 } #=> 12
|
50
60
|
# @overload get_or_else(default)
|
51
61
|
# @return [any]
|
52
62
|
# @example
|
53
|
-
#
|
54
|
-
#
|
63
|
+
# Fear.success(42).get_or_else(12) #=> 42
|
64
|
+
# Fear.failure(ArgumentError.new).get_or_else(12) #=> 12
|
55
65
|
#
|
56
66
|
# @!method include?(other_value)
|
57
67
|
# Returns +true+ if it has an element that is equal
|
@@ -59,9 +69,9 @@ module Fear
|
|
59
69
|
# @param [any]
|
60
70
|
# @return [Boolean]
|
61
71
|
# @example
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
72
|
+
# Fear.success(17).include?(17) #=> true
|
73
|
+
# Fear.success(17).include?(7) #=> false
|
74
|
+
# Fear.failure(ArgumentError.new).include?(17) #=> false
|
65
75
|
#
|
66
76
|
# @!method each(&block)
|
67
77
|
# Performs the given block if this is a +Success+.
|
@@ -70,11 +80,11 @@ module Fear
|
|
70
80
|
# @yieldreturn [void]
|
71
81
|
# @return [Try] itself
|
72
82
|
# @example
|
73
|
-
#
|
83
|
+
# Fear.success(17).each do |value|
|
74
84
|
# puts value
|
75
85
|
# end #=> prints 17
|
76
86
|
#
|
77
|
-
#
|
87
|
+
# Fear.failure(ArgumentError.new).each do |value|
|
78
88
|
# puts value
|
79
89
|
# end #=> does nothing
|
80
90
|
#
|
@@ -84,8 +94,8 @@ module Fear
|
|
84
94
|
# @yieldparam [any] value
|
85
95
|
# @yieldreturn [any]
|
86
96
|
# @example
|
87
|
-
#
|
88
|
-
#
|
97
|
+
# Fear.success(42).map { |v| v/2 } #=> Fear.success(21)
|
98
|
+
# Fear.failure(ArgumentError.new).map { |v| v/2 } #=> Fear.failure(ArgumentError.new)
|
89
99
|
#
|
90
100
|
# @!method flat_map(&block)
|
91
101
|
# Returns the given block applied to the value from this +Success+
|
@@ -94,26 +104,18 @@ module Fear
|
|
94
104
|
# @yieldreturn [Try]
|
95
105
|
# @return [Try]
|
96
106
|
# @example
|
97
|
-
#
|
98
|
-
# #=>
|
99
|
-
#
|
100
|
-
# #=>
|
101
|
-
#
|
102
|
-
# @!method to_a
|
103
|
-
# Returns an +Array+ containing the +Success+ value or an
|
104
|
-
# empty +Array+ if this is a +Failure+.
|
105
|
-
# @return [Array]
|
106
|
-
# @example
|
107
|
-
# Success(42).to_a #=> [21]
|
108
|
-
# Failure(ArgumentError.new).to_a #=> []
|
107
|
+
# Fear.success(42).flat_map { |v| Fear.success(v/2) }
|
108
|
+
# #=> Fear.success(21)
|
109
|
+
# Fear.failure(ArgumentError.new).flat_map { |v| Fear.success(v/2) }
|
110
|
+
# #=> Fear.failure(ArgumentError.new)
|
109
111
|
#
|
110
112
|
# @!method to_option
|
111
113
|
# Returns an +Some+ containing the +Success+ value or a +None+ if
|
112
114
|
# this is a +Failure+.
|
113
115
|
# @return [Option]
|
114
116
|
# @example
|
115
|
-
#
|
116
|
-
#
|
117
|
+
# Fear.success(42).to_option #=> Fear.some(21)
|
118
|
+
# Fear.failure(ArgumentError.new).to_option #=> Fear.none()
|
117
119
|
#
|
118
120
|
# @!method any?(&predicate)
|
119
121
|
# Returns +false+ if +Failure+ or returns the result of the
|
@@ -122,9 +124,9 @@ module Fear
|
|
122
124
|
# @yieldreturn [Boolean]
|
123
125
|
# @return [Boolean]
|
124
126
|
# @example
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
127
|
+
# Fear.success(12).any?( |v| v > 10) #=> true
|
128
|
+
# Fear.success(7).any?( |v| v > 10) #=> false
|
129
|
+
# Fear.failure(ArgumentError.new).any?( |v| v > 10) #=> false
|
128
130
|
#
|
129
131
|
# ---
|
130
132
|
#
|
@@ -141,26 +143,27 @@ module Fear
|
|
141
143
|
# if this is a +Failure+.
|
142
144
|
# @return [any]
|
143
145
|
# @example
|
144
|
-
#
|
145
|
-
#
|
146
|
+
# Fear.success(42).get #=> 42
|
147
|
+
# Fear.failure(ArgumentError.new).get #=> ArgumentError: ArgumentError
|
146
148
|
#
|
147
149
|
# @!method or_else(&alternative)
|
148
150
|
# Returns this +Try+ if it's a +Success+ or the given alternative if this is a +Failure+.
|
149
151
|
# @return [Try]
|
150
152
|
# @example
|
151
|
-
#
|
152
|
-
#
|
153
|
-
#
|
153
|
+
# Fear.success(42).or_else { Fear.success(-1) } #=> Fear.success(42)
|
154
|
+
# Fear.failure(ArgumentError.new).or_else { Fear.success(-1) } #=> Fear.success(-1)
|
155
|
+
# Fear.failure(ArgumentError.new).or_else { Fear.try { 1/0 } }
|
156
|
+
# #=> Fear.failure(ZeroDivisionError.new('divided by 0'))
|
154
157
|
#
|
155
158
|
# @!method flatten
|
156
159
|
# Transforms a nested +Try+, ie, a +Success+ of +Success+,
|
157
160
|
# into an un-nested +Try+, ie, a +Success+.
|
158
161
|
# @return [Try]
|
159
162
|
# @example
|
160
|
-
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
163
|
+
# Fear.success(42).flatten #=> Fear.success(42)
|
164
|
+
# Fear.success(Fear.success(42)).flatten #=> Fear.success(42)
|
165
|
+
# Fear.success(Fear.failure(ArgumentError.new)).flatten #=> Fear.failure(ArgumentError.new)
|
166
|
+
# Fear.failure(ArgumentError.new).flatten { -1 } #=> Fear.failure(ArgumentError.new)
|
164
167
|
#
|
165
168
|
# @!method select(&predicate)
|
166
169
|
# Converts this to a +Failure+ if the predicate is not satisfied.
|
@@ -168,47 +171,80 @@ module Fear
|
|
168
171
|
# @yieldreturn [Boolean]
|
169
172
|
# @return [Try]
|
170
173
|
# @example
|
171
|
-
#
|
172
|
-
# #=>
|
173
|
-
#
|
174
|
-
# #=>
|
175
|
-
#
|
176
|
-
# #=>
|
174
|
+
# Fear.success(42).select { |v| v > 40 }
|
175
|
+
# #=> Fear.success(21)
|
176
|
+
# Fear.success(42).select { |v| v < 40 }
|
177
|
+
# #=> Fear.failure(Fear::NoSuchElementError.new("Predicate does not hold for 42"))
|
178
|
+
# Fear.failure(ArgumentError.new).select { |v| v < 40 }
|
179
|
+
# #=> Fear.failure(ArgumentError.new)
|
177
180
|
#
|
178
181
|
# @!method recover_with(&block)
|
179
182
|
# Applies the given block to exception. This is like +flat_map+
|
180
183
|
# for the exception.
|
181
|
-
# @yieldparam [
|
182
|
-
# @yieldreturn [Try]
|
183
|
-
# @return [Try]
|
184
|
+
# @yieldparam [Fear::PatternMatch] matcher
|
185
|
+
# @yieldreturn [Fear::Try]
|
186
|
+
# @return [Fear::Try]
|
184
187
|
# @example
|
185
|
-
#
|
186
|
-
#
|
187
|
-
#
|
188
|
-
#
|
189
|
-
#
|
190
|
-
#
|
188
|
+
# Fear.success(42).recover_with do |m|
|
189
|
+
# m.case(ZeroDivisionError) { Fear.success(0) }
|
190
|
+
# end #=> Fear.success(42)
|
191
|
+
#
|
192
|
+
# Fear.failure(ArgumentError.new).recover_with do |m|
|
193
|
+
# m.case(ZeroDivisionError) { Fear.success(0) }
|
194
|
+
# m.case(ArgumentError) { |error| Fear.success(error.class.name) }
|
195
|
+
# end #=> Fear.success('ArgumentError')
|
196
|
+
#
|
197
|
+
# # If the block raises error, this new error returned as an result
|
198
|
+
#
|
199
|
+
# Fear.failure(ArgumentError.new).recover_with do |m|
|
200
|
+
# raise
|
201
|
+
# end #=> Fear.failure(RuntimeError)
|
191
202
|
#
|
192
203
|
# @!method recover(&block)
|
193
204
|
# Applies the given block to exception. This is like +map+ for the exception.
|
194
|
-
# @yieldparam [
|
205
|
+
# @yieldparam [Fear::PatternMatch] matcher
|
195
206
|
# @yieldreturn [any]
|
196
|
-
# @return [Try]
|
207
|
+
# @return [Fear::Try]
|
197
208
|
# @example #recover
|
198
|
-
#
|
199
|
-
#
|
200
|
-
#
|
201
|
-
#
|
202
|
-
#
|
203
|
-
#
|
209
|
+
# Fear.success(42).recover do |m|
|
210
|
+
# m.case(&:message)
|
211
|
+
# end #=> Fear.success(42)
|
212
|
+
#
|
213
|
+
# Fear.failure(ArgumentError.new).recover do |m|
|
214
|
+
# m.case(ZeroDivisionError) { 0 }
|
215
|
+
# m.case(&:message)
|
216
|
+
# end #=> Fear.success('ArgumentError')
|
217
|
+
#
|
218
|
+
# # If the block raises error, this new error returned as an result
|
219
|
+
#
|
220
|
+
# Fear.failure(ArgumentError.new).recover do |m|
|
221
|
+
# raise
|
222
|
+
# end #=> Fear.failure(RuntimeError)
|
204
223
|
#
|
205
224
|
# @!method to_either
|
206
225
|
# Returns +Left+ with exception if this is a +Failure+, otherwise
|
207
226
|
# returns +Right+ with +Success+ value.
|
208
227
|
# @return [Right<any>, Left<StandardError>]
|
209
228
|
# @example
|
210
|
-
#
|
211
|
-
#
|
229
|
+
# Fear.success(42).to_either #=> Fear.right(42)
|
230
|
+
# Fear.failure(ArgumentError.new).to_either #=> Fear.left(ArgumentError.new)
|
231
|
+
#
|
232
|
+
# @!method match(&matcher)
|
233
|
+
# Pattern match against this +Try+
|
234
|
+
# @yield matcher [Fear::TryPatternMatch]
|
235
|
+
# @example
|
236
|
+
# Fear.try { ... }.match do |m|
|
237
|
+
# m.success(Integer) do |x|
|
238
|
+
# x * 2
|
239
|
+
# end
|
240
|
+
#
|
241
|
+
# m.success(String) do |x|
|
242
|
+
# x.to_i * 2
|
243
|
+
# end
|
244
|
+
#
|
245
|
+
# m.failure(ZeroDivisionError) { 'not allowed to divide by 0' }
|
246
|
+
# m.else { 'something unexpected' }
|
247
|
+
# end
|
212
248
|
#
|
213
249
|
# @author based on Twitter's original implementation.
|
214
250
|
# @see https://github.com/scala/scala/blob/2.11.x/src/library/scala/util/Try.scala
|
@@ -224,38 +260,59 @@ module Fear
|
|
224
260
|
Success
|
225
261
|
end
|
226
262
|
|
263
|
+
class << self
|
264
|
+
# Build pattern matcher to be used later, despite off
|
265
|
+
# +Try#match+ method, id doesn't apply matcher immanently,
|
266
|
+
# but build it instead. Unusually in sake of efficiency it's better
|
267
|
+
# to statically build matcher and reuse it later.
|
268
|
+
#
|
269
|
+
# @example
|
270
|
+
# matcher =
|
271
|
+
# Try.matcher do |m|
|
272
|
+
# m.success(Integer, ->(x) { x > 2 }) { |x| x * 2 }
|
273
|
+
# m.success(String) { |x| x.to_i * 2 }
|
274
|
+
# m.failure(ActiveRecord::RecordNotFound) { :err }
|
275
|
+
# m.else { 'error '}
|
276
|
+
# end
|
277
|
+
# matcher.call(try)
|
278
|
+
#
|
279
|
+
# @yieldparam [Fear::TryPatternMatch]
|
280
|
+
# @return [Fear::PartialFunction]
|
281
|
+
def matcher(&matcher)
|
282
|
+
TryPatternMatch.new(&matcher)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
227
286
|
# Include this mixin to access convenient factory methods.
|
228
287
|
# @example
|
229
288
|
# include Fear::Try::Mixin
|
230
289
|
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
290
|
+
# Fear.try { 4/2 } #=> #<Fear::Success value=2>
|
291
|
+
# Fear.try { 4/0 } #=> #<Fear::Failure exception=#<ZeroDivisionError: divided by 0>>
|
292
|
+
# Fear.success(2) #=> #<Fear::Success value=2>
|
234
293
|
#
|
235
294
|
module Mixin
|
236
295
|
# Constructs a +Try+ using the block. This
|
237
|
-
# method
|
296
|
+
# method ensures any non-fatal exception is caught and a
|
238
297
|
# +Failure+ object is returned.
|
239
298
|
# @return [Try]
|
240
299
|
#
|
241
|
-
def Try
|
242
|
-
|
243
|
-
rescue => error
|
244
|
-
Failure.new(error)
|
300
|
+
def Try(&block)
|
301
|
+
Fear.try(&block)
|
245
302
|
end
|
246
303
|
|
247
304
|
# @param exception [StandardError]
|
248
305
|
# @return [Failure]
|
249
306
|
#
|
250
307
|
def Failure(exception)
|
251
|
-
|
308
|
+
Fear.failure(exception)
|
252
309
|
end
|
253
310
|
|
254
311
|
# @param value [any]
|
255
312
|
# @return [Success]
|
256
313
|
#
|
257
314
|
def Success(value)
|
258
|
-
|
315
|
+
Fear.success(value)
|
259
316
|
end
|
260
317
|
end
|
261
318
|
end
|
data/lib/fear/try_api.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
module TryApi
|
5
|
+
# Constructs a +Try+ using the block. This
|
6
|
+
# method ensures any non-fatal exception is caught and a
|
7
|
+
# +Failure+ object is returned.
|
8
|
+
# @return [Fear::Try]
|
9
|
+
# @example
|
10
|
+
# Fear.try { 4/0 } #=> #<Fear::Failure exception=#<ZeroDivisionError: divided by 0>>
|
11
|
+
# Fear.try { 4/2 } #=> #<Fear::Success value=2>
|
12
|
+
#
|
13
|
+
def try
|
14
|
+
success(yield)
|
15
|
+
rescue StandardError => error
|
16
|
+
failure(error)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param exception [StandardError]
|
20
|
+
# @return [Fear::Failure]
|
21
|
+
#
|
22
|
+
def failure(exception)
|
23
|
+
Fear::Failure.new(exception)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param value [any]
|
27
|
+
# @return [Fear::Success]
|
28
|
+
#
|
29
|
+
def success(value)
|
30
|
+
Fear::Success.new(value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|