fear 2.0.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/spec.yml +1 -5
- data/CHANGELOG.md +8 -0
- data/Gemfile +14 -2
- data/Gemfile.lock +48 -61
- data/LICENSE.txt +1 -1
- data/README.md +18 -70
- data/Rakefile +32 -119
- data/benchmarks/dry_do_vs_fear_for.txt +7 -6
- data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +7 -6
- data/benchmarks/factorial.txt +7 -9
- data/benchmarks/fear_gaurd_and1_vs_new.txt +7 -6
- data/benchmarks/fear_gaurd_and2_vs_and.txt +8 -7
- data/benchmarks/fear_gaurd_and3_vs_and_and.txt +7 -6
- data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +7 -6
- data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +8 -10
- data/fear.gemspec +4 -19
- data/lib/fear/either/left_projection.rb +237 -0
- data/lib/fear/either/pattern_match.rb +49 -0
- data/lib/fear/either.rb +20 -11
- data/lib/fear/either_api.rb +2 -4
- data/lib/fear/empty_partial_function.rb +1 -1
- data/lib/fear/failure/pattern_match.rb +14 -0
- data/lib/fear/failure.rb +1 -1
- data/lib/fear/for_api.rb +0 -2
- data/lib/fear/future.rb +1 -1
- data/lib/fear/future_api.rb +0 -5
- data/lib/fear/left/pattern_match.rb +15 -0
- data/lib/fear/left.rb +1 -1
- data/lib/fear/none.rb +0 -87
- data/lib/fear/none_class/pattern_match.rb +16 -0
- data/lib/fear/none_class.rb +85 -0
- data/lib/fear/option/pattern_match.rb +47 -0
- data/lib/fear/option.rb +1 -5
- data/lib/fear/option_api.rb +1 -3
- data/lib/fear/partial_function/empty.rb +3 -5
- data/lib/fear/partial_function/guard.rb +0 -4
- data/lib/fear/partial_function/or_else.rb +0 -2
- data/lib/fear/partial_function.rb +0 -9
- data/lib/fear/partial_function_class.rb +1 -1
- data/lib/fear/pattern_match.rb +3 -2
- data/lib/fear/pattern_matching_api.rb +0 -3
- data/lib/fear/right/pattern_match.rb +15 -0
- data/lib/fear/right.rb +1 -1
- data/lib/fear/right_biased.rb +2 -0
- data/lib/fear/some/pattern_match.rb +15 -0
- data/lib/fear/some.rb +1 -1
- data/lib/fear/success/pattern_match.rb +16 -0
- data/lib/fear/success.rb +1 -1
- data/lib/fear/try/pattern_match.rb +29 -0
- data/lib/fear/try.rb +3 -7
- data/lib/fear/try_api.rb +0 -2
- data/lib/fear/version.rb +1 -1
- data/lib/fear.rb +3 -14
- data/spec/fear/awaitable_spec.rb +0 -2
- data/spec/fear/either/left_projection_spec.rb +289 -0
- data/spec/fear/{either_pattern_match_spec.rb → either/pattern_match_spec.rb} +1 -1
- data/spec/fear/{option_pattern_match_spec.rb → option/pattern_match_spec.rb} +1 -1
- data/spec/fear/partial_function/empty_spec.rb +1 -1
- data/spec/fear/{try_pattern_match_spec.rb → try/try_pattern_match_spec.rb} +1 -1
- data/spec/support/.keep +0 -0
- metadata +29 -255
- data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +0 -11
- data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +0 -11
- data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +0 -11
- data/lib/dry/types/fear/option.rb +0 -125
- data/lib/dry/types/fear.rb +0 -8
- data/lib/fear/either_pattern_match.rb +0 -52
- data/lib/fear/failure_pattern_match.rb +0 -12
- data/lib/fear/left_pattern_match.rb +0 -11
- data/lib/fear/none_pattern_match.rb +0 -14
- data/lib/fear/option_pattern_match.rb +0 -50
- data/lib/fear/right_pattern_match.rb +0 -13
- data/lib/fear/some_pattern_match.rb +0 -13
- data/lib/fear/struct.rb +0 -237
- data/lib/fear/success_pattern_match.rb +0 -14
- data/lib/fear/try_pattern_match.rb +0 -32
- data/spec/dry/types/fear/option/constrained_spec.rb +0 -22
- data/spec/dry/types/fear/option/core_spec.rb +0 -77
- data/spec/dry/types/fear/option/default_spec.rb +0 -21
- data/spec/dry/types/fear/option/hash_spec.rb +0 -58
- data/spec/dry/types/fear/option/option_spec.rb +0 -97
- data/spec/struct_pattern_matching_spec.rb +0 -36
- data/spec/struct_spec.rb +0 -194
- data/spec/support/dry_types.rb +0 -6
data/lib/fear/none.rb
CHANGED
@@ -1,94 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Fear
|
4
|
-
# @api private
|
5
|
-
class NoneClass
|
6
|
-
include Option
|
7
|
-
include RightBiased::Left
|
8
|
-
include NonePatternMatch.mixin
|
9
|
-
|
10
|
-
# @raise [NoSuchElementError]
|
11
|
-
def get
|
12
|
-
raise NoSuchElementError
|
13
|
-
end
|
14
|
-
|
15
|
-
# @return [nil]
|
16
|
-
def or_nil
|
17
|
-
nil
|
18
|
-
end
|
19
|
-
|
20
|
-
# @return [true]
|
21
|
-
def empty?
|
22
|
-
true
|
23
|
-
end
|
24
|
-
|
25
|
-
alias :blank? :empty?
|
26
|
-
|
27
|
-
# @return [false]
|
28
|
-
def present?
|
29
|
-
false
|
30
|
-
end
|
31
|
-
|
32
|
-
# @return [None]
|
33
|
-
def select(*)
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
|
-
# @return [None]
|
38
|
-
def reject(*)
|
39
|
-
self
|
40
|
-
end
|
41
|
-
|
42
|
-
# @return [String]
|
43
|
-
def inspect
|
44
|
-
"#<Fear::NoneClass>"
|
45
|
-
end
|
46
|
-
|
47
|
-
# @return [String]
|
48
|
-
alias to_s inspect
|
49
|
-
|
50
|
-
# @param other [Any]
|
51
|
-
# @return [Boolean]
|
52
|
-
def ==(other)
|
53
|
-
other.is_a?(NoneClass)
|
54
|
-
end
|
55
|
-
|
56
|
-
# @param other
|
57
|
-
# @return [Boolean]
|
58
|
-
def ===(other)
|
59
|
-
self == other
|
60
|
-
end
|
61
|
-
|
62
|
-
# @param other [Fear::Option]
|
63
|
-
# @return [Fear::Option]
|
64
|
-
def zip(other)
|
65
|
-
if other.is_a?(Option)
|
66
|
-
Fear.none
|
67
|
-
else
|
68
|
-
raise TypeError, "can't zip with #{other.class}"
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# @return [RightBiased::Left]
|
73
|
-
def filter_map
|
74
|
-
self
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
private_constant(:NoneClass)
|
79
|
-
|
80
4
|
# The only instance of NoneClass
|
81
|
-
# @api private
|
82
5
|
None = NoneClass.new.freeze
|
83
6
|
public_constant :None
|
84
|
-
|
85
|
-
class << NoneClass
|
86
|
-
def new
|
87
|
-
None
|
88
|
-
end
|
89
|
-
|
90
|
-
def inherited(*)
|
91
|
-
raise "you are not allowed to inherit from NoneClass, use Fear::None instead"
|
92
|
-
end
|
93
|
-
end
|
94
7
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
class NoneClass
|
5
|
+
# @api private
|
6
|
+
class PatternMatch < Option::PatternMatch
|
7
|
+
# @param conditions [<#==>]
|
8
|
+
# @return [Fear::OptionPatternMatch]
|
9
|
+
def some(*conditions)
|
10
|
+
self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private_constant :PatternMatch
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
# @api private
|
5
|
+
class NoneClass
|
6
|
+
include Option
|
7
|
+
include RightBiased::Left
|
8
|
+
include PatternMatch.mixin
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def inherited(*)
|
12
|
+
raise "you are not allowed to inherit from NoneClass, use Fear::None instead"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# @raise [NoSuchElementError]
|
17
|
+
def get
|
18
|
+
raise NoSuchElementError
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [nil]
|
22
|
+
def or_nil
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [true]
|
27
|
+
def empty?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
alias :blank? :empty?
|
32
|
+
|
33
|
+
# @return [false]
|
34
|
+
def present?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return [None]
|
39
|
+
def select(*)
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [None]
|
44
|
+
def reject(*)
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [String]
|
49
|
+
def inspect
|
50
|
+
"#<Fear::NoneClass>"
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [String]
|
54
|
+
alias to_s inspect
|
55
|
+
|
56
|
+
# @param other [Any]
|
57
|
+
# @return [Boolean]
|
58
|
+
def ==(other)
|
59
|
+
other.is_a?(NoneClass)
|
60
|
+
end
|
61
|
+
|
62
|
+
# @param other
|
63
|
+
# @return [Boolean]
|
64
|
+
def ===(other)
|
65
|
+
self == other
|
66
|
+
end
|
67
|
+
|
68
|
+
# @param other [Fear::Option]
|
69
|
+
# @return [Fear::Option]
|
70
|
+
def zip(other)
|
71
|
+
if other.is_a?(Option)
|
72
|
+
Fear.none
|
73
|
+
else
|
74
|
+
raise TypeError, "can't zip with #{other.class}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [RightBiased::Left]
|
79
|
+
def filter_map
|
80
|
+
self
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private_constant(:NoneClass)
|
85
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
module Option
|
5
|
+
# Option pattern matcher
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# pattern_match =
|
9
|
+
# Option::PatternMatch.new
|
10
|
+
# .some(Integer) { |x| x * 2 }
|
11
|
+
# .some(String) { |x| x.to_i * 2 }
|
12
|
+
# .none { 'NaN' }
|
13
|
+
# .else { 'error '}
|
14
|
+
#
|
15
|
+
# pattern_match.call(42) => 'NaN'
|
16
|
+
#
|
17
|
+
# @example the same matcher may be defined using block syntax
|
18
|
+
# Option::PatternMatch.new do |m|
|
19
|
+
# m.some(Integer) { |x| x * 2 }
|
20
|
+
# m.some(String) { |x| x.to_i * 2 }
|
21
|
+
# m.none { 'NaN' }
|
22
|
+
# m.else { 'error '}
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# @note it has two optimized subclasses +Fear::SomePatternMatch+ and +Fear::NonePatternMatch+
|
26
|
+
# @api private
|
27
|
+
class PatternMatch < Fear::PatternMatch
|
28
|
+
# Match against Some
|
29
|
+
#
|
30
|
+
# @param conditions [<#==>]
|
31
|
+
# @return [Fear::Option::PatternMatch]
|
32
|
+
def some(*conditions, &effect)
|
33
|
+
branch = Fear.case(Fear::Some, &:get).and_then(Fear.case(*conditions, &effect))
|
34
|
+
or_else(branch)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Match against None
|
38
|
+
#
|
39
|
+
# @param effect [Proc]
|
40
|
+
# @return [Fear::Option::PatternMatch]
|
41
|
+
def none(&effect)
|
42
|
+
branch = Fear.case(Fear::None, &effect)
|
43
|
+
or_else(branch)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/fear/option.rb
CHANGED
@@ -207,7 +207,7 @@ module Fear
|
|
207
207
|
# @yieldparam [OptionPatternMatch]
|
208
208
|
# @return [Fear::PartialFunction]
|
209
209
|
def matcher(&matcher)
|
210
|
-
|
210
|
+
Option::PatternMatch.new(&matcher)
|
211
211
|
end
|
212
212
|
|
213
213
|
def match(value, &block)
|
@@ -258,7 +258,3 @@ module Fear
|
|
258
258
|
end
|
259
259
|
end
|
260
260
|
end
|
261
|
-
|
262
|
-
require "fear/option_pattern_match"
|
263
|
-
require "fear/some"
|
264
|
-
require "fear/none"
|
data/lib/fear/option_api.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "fear/option"
|
4
|
-
|
5
3
|
module Fear
|
6
4
|
module OptionApi
|
7
5
|
# An +Option+ factory which creates +Some+ if the argument is
|
@@ -29,7 +27,7 @@ module Fear
|
|
29
27
|
Fear::None
|
30
28
|
end
|
31
29
|
|
32
|
-
# @param value [
|
30
|
+
# @param value [Object]
|
33
31
|
# @return [Fear::Some]
|
34
32
|
# @example
|
35
33
|
# Fear.some(17) #=> #<Fear::Some get=17>
|
@@ -1,12 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "fear/empty_partial_function"
|
4
|
-
|
5
3
|
module Fear
|
6
4
|
module PartialFunction
|
7
|
-
|
8
|
-
|
5
|
+
Empty = EmptyPartialFunction.new
|
6
|
+
Empty.freeze
|
9
7
|
|
10
|
-
public_constant :
|
8
|
+
public_constant :Empty
|
11
9
|
end
|
12
10
|
end
|
@@ -1,14 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "fear/partial_function/and_then"
|
4
|
-
require "fear/partial_function/any"
|
5
|
-
require "fear/partial_function/combined"
|
6
|
-
require "fear/partial_function/empty"
|
7
|
-
require "fear/partial_function/guard"
|
8
|
-
require "fear/partial_function/lifted"
|
9
|
-
require "fear/partial_function/or_else"
|
10
|
-
require "fear/partial_function_class"
|
11
|
-
|
12
3
|
module Fear
|
13
4
|
# A partial function is a unary function defined on subset of all possible inputs.
|
14
5
|
# The method +defined_at?+ allows to test dynamically if an arg is in
|
@@ -20,7 +20,7 @@ module Fear
|
|
20
20
|
# is contained in the function domain.
|
21
21
|
# @raise [MatchError] when this partial function is not defined.
|
22
22
|
def call(arg)
|
23
|
-
call_or_else(arg, &PartialFunction::
|
23
|
+
call_or_else(arg, &PartialFunction::Empty)
|
24
24
|
end
|
25
25
|
|
26
26
|
# @param arg [any]
|
data/lib/fear/pattern_match.rb
CHANGED
@@ -37,7 +37,7 @@ module Fear
|
|
37
37
|
|
38
38
|
# @return [Fear::PartialFunction]
|
39
39
|
def new
|
40
|
-
builder = __new__(PartialFunction::
|
40
|
+
builder = __new__(PartialFunction::Empty)
|
41
41
|
yield builder
|
42
42
|
builder.result
|
43
43
|
end
|
@@ -89,12 +89,13 @@ module Fear
|
|
89
89
|
#
|
90
90
|
# @param guards [<#===>]
|
91
91
|
# @param effect [Proc]
|
92
|
-
# @return [Fear::
|
92
|
+
# @return [Fear::PatternMatch]
|
93
93
|
# @see #or_else for details
|
94
94
|
def case(*guards, &effect)
|
95
95
|
or_else(Fear.case(*guards, &effect))
|
96
96
|
end
|
97
97
|
|
98
|
+
# @return [Fear::PatternMatch]
|
98
99
|
# @see Fear::PartialFunction#or_else
|
99
100
|
def or_else(other)
|
100
101
|
self.result = result.or_else(other)
|
data/lib/fear/right.rb
CHANGED
data/lib/fear/right_biased.rb
CHANGED
@@ -70,6 +70,7 @@ module Fear
|
|
70
70
|
yield(value)
|
71
71
|
self
|
72
72
|
end
|
73
|
+
alias apply each
|
73
74
|
|
74
75
|
# Maps the value using given block.
|
75
76
|
#
|
@@ -144,6 +145,7 @@ module Fear
|
|
144
145
|
def each
|
145
146
|
self
|
146
147
|
end
|
148
|
+
alias apply each
|
147
149
|
|
148
150
|
# Ignores the given block and return self.
|
149
151
|
#
|
data/lib/fear/some.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
class Success
|
5
|
+
# @api private
|
6
|
+
class PatternMatch < Try::PatternMatch
|
7
|
+
# @param conditions [<#==>]
|
8
|
+
# @return [Fear::TryPatternMatch]
|
9
|
+
def failure(*conditions)
|
10
|
+
self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private_constant :PatternMatch
|
15
|
+
end
|
16
|
+
end
|
data/lib/fear/success.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
module Try
|
5
|
+
# Try pattern matcher
|
6
|
+
#
|
7
|
+
# @note it has two optimized subclasses +Fear::Success::PatternMatch+ and +Fear::FailurePatternMatch+
|
8
|
+
# @api private
|
9
|
+
class PatternMatch < Fear::PatternMatch
|
10
|
+
# Match against +Fear::Success+
|
11
|
+
#
|
12
|
+
# @param conditions [<#==>]
|
13
|
+
# @return [Fear::Try::PatternMatch]
|
14
|
+
def success(*conditions, &effect)
|
15
|
+
branch = Fear.case(Fear::Success, &:get).and_then(Fear.case(*conditions, &effect))
|
16
|
+
or_else(branch)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Match against +Fear::Failure+
|
20
|
+
#
|
21
|
+
# @param conditions [<#==>]
|
22
|
+
# @return [Fear::Try::PatternMatch]
|
23
|
+
def failure(*conditions, &effect)
|
24
|
+
branch = Fear.case(Fear::Failure, &:exception).and_then(Fear.case(*conditions, &effect))
|
25
|
+
or_else(branch)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/fear/try.rb
CHANGED
@@ -231,7 +231,7 @@ module Fear
|
|
231
231
|
#
|
232
232
|
# @!method match(&matcher)
|
233
233
|
# Pattern match against this +Try+
|
234
|
-
# @yield matcher [Fear::
|
234
|
+
# @yield matcher [Fear::Try::PatternMatch]
|
235
235
|
# @example
|
236
236
|
# Fear.try { ... }.match do |m|
|
237
237
|
# m.success(Integer) do |x|
|
@@ -276,10 +276,10 @@ module Fear
|
|
276
276
|
# end
|
277
277
|
# matcher.call(try)
|
278
278
|
#
|
279
|
-
# @yieldparam [Fear::
|
279
|
+
# @yieldparam [Fear::Try::PatternMatch]
|
280
280
|
# @return [Fear::PartialFunction]
|
281
281
|
def matcher(&matcher)
|
282
|
-
|
282
|
+
Try::PatternMatch.new(&matcher)
|
283
283
|
end
|
284
284
|
end
|
285
285
|
|
@@ -317,7 +317,3 @@ module Fear
|
|
317
317
|
end
|
318
318
|
end
|
319
319
|
end
|
320
|
-
|
321
|
-
require "fear/try_pattern_match"
|
322
|
-
require "fear/success"
|
323
|
-
require "fear/failure"
|
data/lib/fear/try_api.rb
CHANGED
data/lib/fear/version.rb
CHANGED
data/lib/fear.rb
CHANGED
@@ -1,16 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
4
|
-
|
5
|
-
|
6
|
-
require "fear/unit"
|
7
|
-
require "fear/either_api"
|
8
|
-
require "fear/for_api"
|
9
|
-
require "fear/future_api"
|
10
|
-
require "fear/option_api"
|
11
|
-
require "fear/pattern_matching_api"
|
12
|
-
require "fear/try_api"
|
13
|
-
require "fear/version"
|
3
|
+
require "zeitwerk"
|
4
|
+
loader = Zeitwerk::Loader.for_gem
|
5
|
+
loader.setup
|
14
6
|
|
15
7
|
module Fear
|
16
8
|
Error = Class.new(StandardError)
|
@@ -25,9 +17,6 @@ module Fear
|
|
25
17
|
NoSuchElementError = Class.new(Error)
|
26
18
|
public_constant :NoSuchElementError
|
27
19
|
|
28
|
-
PatternSyntaxError = Class.new(Error)
|
29
|
-
public_constant :PatternSyntaxError
|
30
|
-
|
31
20
|
extend EitherApi
|
32
21
|
extend ForApi
|
33
22
|
extend FutureApi
|