fear 0.9.0 → 1.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 +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
|