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
@@ -1,13 +1,14 @@
|
|
1
1
|
# It verifies that optimization for Partial Functions with only one guard actually works.
|
2
2
|
|
3
3
|
> bundle exec rake perf:fear:guard:and1_vs_new
|
4
|
+
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
|
4
5
|
Warming up --------------------------------------
|
5
|
-
Guard.new
|
6
|
-
Guard.and1
|
6
|
+
Guard.new 571.139B i/100ms
|
7
|
+
Guard.and1 1.884T i/100ms
|
7
8
|
Calculating -------------------------------------
|
8
|
-
Guard.new
|
9
|
-
Guard.and1
|
9
|
+
Guard.new 2.927Q (±10.3%) i/s - 14.393Q in 4.993407s
|
10
|
+
Guard.and1 32.583Q (± 2.2%) i/s - 162.090Q in 4.977493s
|
10
11
|
|
11
12
|
Comparison:
|
12
|
-
Guard.and1:
|
13
|
-
Guard.new:
|
13
|
+
Guard.and1: 32583184202679384.0 i/s
|
14
|
+
Guard.new: 2927179441726049.0 i/s - 11.13x slower
|
@@ -1,13 +1,14 @@
|
|
1
1
|
# It verifies that optimization for Partial Functions with two guards actually works.
|
2
2
|
|
3
|
-
> bundle exec rake perf:fear:guard:
|
3
|
+
> bundle exec rake perf:fear:guard:and2_vs_and
|
4
|
+
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
|
4
5
|
Warming up --------------------------------------
|
5
|
-
and2
|
6
|
-
Guard#and
|
6
|
+
and2 807.325B i/100ms
|
7
|
+
Guard#and 692.737B i/100ms
|
7
8
|
Calculating -------------------------------------
|
8
|
-
and2
|
9
|
-
Guard#and
|
9
|
+
and2 6.011Q (± 2.4%) i/s - 29.972Q in 4.989608s
|
10
|
+
Guard#and 4.443Q (± 2.1%) i/s - 22.168Q in 4.991463s
|
10
11
|
|
11
12
|
Comparison:
|
12
|
-
and2:
|
13
|
-
Guard#and:
|
13
|
+
and2: 6011198087717350.0 i/s
|
14
|
+
Guard#and: 4443444774459918.5 i/s - 1.35x slower
|
@@ -1,13 +1,14 @@
|
|
1
1
|
# It verifies that optimization for Partial Functions with three guards actually works.
|
2
2
|
|
3
3
|
> bundle exec rake perf:fear:guard:and3_vs_and_and
|
4
|
+
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
|
4
5
|
Warming up --------------------------------------
|
5
|
-
Guard.and3
|
6
|
-
Guard#and
|
6
|
+
Guard.and3 580.401B i/100ms
|
7
|
+
Guard#and 350.896B i/100ms
|
7
8
|
Calculating -------------------------------------
|
8
|
-
Guard.and3
|
9
|
-
Guard#and
|
9
|
+
Guard.and3 3.152Q (± 1.3%) i/s - 15.736Q in 4.993183s
|
10
|
+
Guard#and 1.132Q (± 1.7%) i/s - 5.653Q in 4.996181s
|
10
11
|
|
11
12
|
Comparison:
|
12
|
-
Guard.and3:
|
13
|
-
Guard#and:
|
13
|
+
Guard.and3: 3152131160662449.0 i/s
|
14
|
+
Guard#and: 1131877273526757.5 i/s - 2.78x slower
|
@@ -1,13 +1,14 @@
|
|
1
1
|
# So, it's better to avoid building pattern match in runtime
|
2
2
|
|
3
3
|
> bundle exec rake perf:fear:pattern_matching_construction_vs_execution
|
4
|
+
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
|
4
5
|
Warming up --------------------------------------
|
5
|
-
construction
|
6
|
-
execution
|
6
|
+
construction 53.068k i/100ms
|
7
|
+
execution 280.541k i/100ms
|
7
8
|
Calculating -------------------------------------
|
8
|
-
construction
|
9
|
-
execution
|
9
|
+
construction 537.049k (± 0.2%) i/s - 2.706M in 5.039544s
|
10
|
+
execution 2.799M (± 0.4%) i/s - 14.027M in 5.011175s
|
10
11
|
|
11
12
|
Comparison:
|
12
|
-
execution:
|
13
|
-
construction:
|
13
|
+
execution: 2799195.6 i/s
|
14
|
+
construction: 537049.0 i/s - 5.21x slower
|
@@ -1,14 +1,12 @@
|
|
1
|
-
> bundle exec rake perf:pattern_matching:
|
1
|
+
> bundle exec rake perf:pattern_matching:dry_vs_fear_try
|
2
|
+
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
|
2
3
|
Warming up --------------------------------------
|
3
|
-
|
4
|
-
|
5
|
-
Dr::Matcher 13.079k i/100ms
|
4
|
+
Fear 18.527k i/100ms
|
5
|
+
Dr::Matcher 40.145k i/100ms
|
6
6
|
Calculating -------------------------------------
|
7
|
-
|
8
|
-
|
9
|
-
Dr::Matcher 166.700k (± 3.0%) i/s - 837.056k in 5.026408s
|
7
|
+
Fear 187.617k (± 0.4%) i/s - 944.877k in 5.036258s
|
8
|
+
Dr::Matcher 395.181k (± 1.9%) i/s - 2.007M in 5.081136s
|
10
9
|
|
11
10
|
Comparison:
|
12
|
-
Dr::Matcher:
|
13
|
-
Fear:
|
14
|
-
Qo: 38871.9 i/s - 4.29x slower
|
11
|
+
Dr::Matcher: 395181.1 i/s
|
12
|
+
Fear: 187617.3 i/s - 2.11x slower
|
data/fear.gemspec
CHANGED
@@ -8,8 +8,8 @@ require "fear/version"
|
|
8
8
|
Gem::Specification.new do |spec|
|
9
9
|
spec.name = "fear"
|
10
10
|
spec.version = Fear::VERSION
|
11
|
-
spec.authors = ["
|
12
|
-
spec.email = ["
|
11
|
+
spec.authors = ["Tëma Bolshakov"]
|
12
|
+
spec.email = ["tema@bolshakov.dev"]
|
13
13
|
spec.summary = "%q{Ruby port of some Scala's monads.}"
|
14
14
|
spec.description = "Ruby port of some Scala's monads."
|
15
15
|
spec.homepage = "https://github.com/bolshakov/fear"
|
@@ -19,22 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^bin\/}) { |f| File.basename(f) }
|
20
20
|
spec.test_files = spec.files.grep(%r{^spec\/})
|
21
21
|
spec.require_paths = ["lib"]
|
22
|
-
spec.required_ruby_version = Gem::Requirement.new(">=
|
22
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.1")
|
23
23
|
|
24
|
-
spec.
|
25
|
-
spec.add_development_dependency "bundler"
|
26
|
-
spec.add_development_dependency "concurrent-ruby"
|
27
|
-
spec.add_development_dependency "dry-matcher"
|
28
|
-
spec.add_development_dependency "dry-monads"
|
29
|
-
spec.add_development_dependency "qo"
|
30
|
-
spec.add_development_dependency "rake", "~> 13.0"
|
31
|
-
spec.add_development_dependency "rspec", "~> 3.1"
|
32
|
-
spec.add_development_dependency "rubocop-rspec", "1.34.0"
|
33
|
-
spec.add_development_dependency "rubocop", "1.32.0"
|
34
|
-
spec.add_development_dependency "ruby_coding_standard"
|
35
|
-
spec.add_development_dependency "yard"
|
36
|
-
spec.add_development_dependency "dry-types"
|
37
|
-
spec.add_development_dependency "fear-rspec"
|
38
|
-
spec.add_development_dependency "simplecov"
|
39
|
-
spec.add_development_dependency "simplecov-lcov"
|
24
|
+
spec.add_runtime_dependency "zeitwerk"
|
40
25
|
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
module Either
|
5
|
+
# Projects an `Either` into a `Left`.
|
6
|
+
# @see Fear::Either#left
|
7
|
+
#
|
8
|
+
class LeftProjection
|
9
|
+
prepend Fear::RightBiased::Interface
|
10
|
+
|
11
|
+
# @!attribute either
|
12
|
+
# @return [Fear::Either]
|
13
|
+
attr_reader :either
|
14
|
+
protected :either
|
15
|
+
|
16
|
+
# @param either [Fear::Either]
|
17
|
+
def initialize(either)
|
18
|
+
@either = either
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns +true+ if +Fear::Left+ has an element that is equal
|
22
|
+
# (as determined by +==+) to +other_value+, +false+ otherwise.
|
23
|
+
# @param [Object]
|
24
|
+
# @return [Boolean]
|
25
|
+
# @example
|
26
|
+
# Fear.left(17).left.include?(17) #=> true
|
27
|
+
# Fear.left(17).left.include?(7) #=> false
|
28
|
+
# Fear.right('undefined').left.include?(17) #=> false
|
29
|
+
#
|
30
|
+
def include?(other_value)
|
31
|
+
case either
|
32
|
+
in Fear::Left(x)
|
33
|
+
x == other_value
|
34
|
+
in Fear::Right
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the value from this +Fear::Left+ or evaluates the given
|
40
|
+
# default argument if this is a +Fear::Right+.
|
41
|
+
#
|
42
|
+
# @overload get_or_else(&default)
|
43
|
+
# @yieldreturn [Object]
|
44
|
+
# @return [Object]
|
45
|
+
# @example
|
46
|
+
# Fear.right(42).left.get_or_else { 24/2 } #=> 12
|
47
|
+
# Fear.left('undefined').left.get_or_else { 24/2 } #=> 'undefined'
|
48
|
+
#
|
49
|
+
# @overload get_or_else(default)
|
50
|
+
# @return [Object]
|
51
|
+
# @example
|
52
|
+
# Fear.right(42).left.get_or_else(12) #=> 12
|
53
|
+
# Fear.left('undefined').left.get_or_else(12) #=> 'undefined'
|
54
|
+
def get_or_else(*args)
|
55
|
+
case either
|
56
|
+
in Fear::Left(value)
|
57
|
+
value
|
58
|
+
in Fear::Right
|
59
|
+
args.fetch(0) { yield }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Performs the given block if this is a +Fear::Left+.
|
64
|
+
#
|
65
|
+
# @yieldparam [Object] value
|
66
|
+
# @yieldreturn [void]
|
67
|
+
# @return [Fear::Either] itself
|
68
|
+
# @example
|
69
|
+
# Fear.right(17).left.each do |value|
|
70
|
+
# puts value
|
71
|
+
# end #=> does nothing
|
72
|
+
#
|
73
|
+
# Fear.left('undefined').left.each do |value|
|
74
|
+
# puts value
|
75
|
+
# end #=> prints "nothing"
|
76
|
+
def each
|
77
|
+
case either
|
78
|
+
in Fear::Left(value)
|
79
|
+
yield(value)
|
80
|
+
either
|
81
|
+
in Fear::Right
|
82
|
+
either
|
83
|
+
end
|
84
|
+
end
|
85
|
+
alias apply each
|
86
|
+
|
87
|
+
# Maps the block argument through +Fear::Left+.
|
88
|
+
#
|
89
|
+
# @yieldparam [Object] value
|
90
|
+
# @yieldreturn [Fear::Either]
|
91
|
+
# @example
|
92
|
+
# Fear.left(42).left.map { _1/2 } #=> Fear.left(24)
|
93
|
+
# Fear.right(42).left.map { _1/2 } #=> Fear.right(42)
|
94
|
+
#
|
95
|
+
def map
|
96
|
+
case either
|
97
|
+
in Fear::Left(value)
|
98
|
+
Fear.left(yield(value))
|
99
|
+
in Fear::Right
|
100
|
+
either
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns the given block applied to the value from this +Fear::Left+
|
105
|
+
# or returns this if this is a +Fear::Right+.
|
106
|
+
#
|
107
|
+
# @yieldparam [Object] value
|
108
|
+
# @yieldreturn [Fear::Either]
|
109
|
+
# @return [Fear::Either]
|
110
|
+
#
|
111
|
+
# @example
|
112
|
+
# Fear.left(12).left.flat_map { Fear.left(_1 * 2) } #=> Fear.left(24)
|
113
|
+
# Fear.left(12).left.flat_map { Fear.right(_1 * 2) } #=> Fear.right(24)
|
114
|
+
# Fear.right(12).left.flat_map { Fear.left(_1 * 2) } #=> Fear.right(12)
|
115
|
+
#
|
116
|
+
def flat_map
|
117
|
+
case either
|
118
|
+
in Fear::Left(value)
|
119
|
+
yield(value)
|
120
|
+
in Fear::Right
|
121
|
+
either
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns an +Fear::Some+ containing the +Fear::Left+ value or a +Fear::None+ if
|
126
|
+
# this is a +Fear::Right+.
|
127
|
+
# @return [Fear::Option]
|
128
|
+
# @example
|
129
|
+
# Fear.left(42).left.to_option #=> Fear.some(42)
|
130
|
+
# Fear.right(42).left.to_option #=> Fear.none
|
131
|
+
#
|
132
|
+
def to_option
|
133
|
+
case either
|
134
|
+
in Fear::Left(value)
|
135
|
+
Fear.some(value)
|
136
|
+
in Fear::Right
|
137
|
+
Fear.none
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns an array containing the +Fear::Left+ value or an empty array if
|
142
|
+
# this is a +Fear::Right+.
|
143
|
+
#
|
144
|
+
# @return [Array]
|
145
|
+
# @example
|
146
|
+
# Fear.left(42).left.to_a #=> [42]
|
147
|
+
# Fear.right(42).left.to_a #=> []
|
148
|
+
#
|
149
|
+
def to_a
|
150
|
+
case either
|
151
|
+
in Fear::Left(value)
|
152
|
+
[value]
|
153
|
+
in Fear::Right
|
154
|
+
[]
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns +false+ if +Fear::Right+ or returns the result of the
|
159
|
+
# application of the given predicate to the +Fear::Light+ value.
|
160
|
+
#
|
161
|
+
# @yieldparam [Object] value
|
162
|
+
# @yieldreturn [Boolean]
|
163
|
+
# @return [Boolean]
|
164
|
+
# @example
|
165
|
+
# Fear.left(12).left.any? { |v| v > 10 } #=> true
|
166
|
+
# Fear.left(7).left.any? { |v| v > 10 } #=> false
|
167
|
+
# Fear.right(12).left.any? { |v| v > 10 } #=> false
|
168
|
+
#
|
169
|
+
def any?(&predicate)
|
170
|
+
case either
|
171
|
+
in Fear::Left(value)
|
172
|
+
predicate.(value)
|
173
|
+
in Fear::Right
|
174
|
+
false
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Returns +Fear::Right+ of value if the given predicate
|
179
|
+
# does not hold for the left value, otherwise, returns +Fear::Left+.
|
180
|
+
#
|
181
|
+
# @yieldparam value [Object]
|
182
|
+
# @yieldreturn [Boolean]
|
183
|
+
# @return [Fear::Either]
|
184
|
+
# @example
|
185
|
+
# Fear.left(12).left.select(&:even?) #=> Fear.left(12)
|
186
|
+
# Fear.left(7).left.select(&:even?) #=> Fear.right(7)
|
187
|
+
# Fear.right(12).left.select(&:even?) #=> Fear.right(12)
|
188
|
+
# Fear.right(7).left.select(&:even?) #=> Fear.right(7)
|
189
|
+
#
|
190
|
+
def select(&predicate)
|
191
|
+
case either
|
192
|
+
in Fear::Right
|
193
|
+
either
|
194
|
+
in Fear::Left(value) if predicate.(value)
|
195
|
+
either
|
196
|
+
in Fear::Left
|
197
|
+
either.swap
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# Returns +Fear::None+ if this is a +Fear::Right+ or if the given predicate
|
202
|
+
# does not hold for the left value, otherwise, returns a +Fear::Left+.
|
203
|
+
#
|
204
|
+
# @yieldparam value [Object]
|
205
|
+
# @yieldreturn [Boolean]
|
206
|
+
# @return [Fear::Option<Fear::Either>]
|
207
|
+
# @example
|
208
|
+
# Fear.left(12).left.find(&:even?) #=> #<Fear::Some value=#<Fear::Left value=12>>
|
209
|
+
# Fear.left(7).left.find(&:even?) #=> #<Fear::None>
|
210
|
+
# Fear.right(12).left.find(&:even) #=> #<Fear::None>
|
211
|
+
#
|
212
|
+
def find(&predicate)
|
213
|
+
case either
|
214
|
+
in Fear::Left(value) if predicate.(value)
|
215
|
+
Fear.some(either)
|
216
|
+
in Fear::Either
|
217
|
+
Fear.none
|
218
|
+
end
|
219
|
+
end
|
220
|
+
alias detect find
|
221
|
+
|
222
|
+
# @param other [Object]
|
223
|
+
# @return [Boolean]
|
224
|
+
def ==(other)
|
225
|
+
other.is_a?(self.class) && other.either == either
|
226
|
+
end
|
227
|
+
|
228
|
+
private def left_class
|
229
|
+
Fear::Right
|
230
|
+
end
|
231
|
+
|
232
|
+
private def right_class
|
233
|
+
Fear::Left
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
module Either
|
5
|
+
# Either pattern matcher
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# pattern_match =
|
9
|
+
# EitherPatternMatch.new
|
10
|
+
# .right(Integer, ->(x) { x > 2 }) { |x| x * 2 }
|
11
|
+
# .right(String) { |x| x.to_i * 2 }
|
12
|
+
# .left(String) { :err }
|
13
|
+
# .else { 'error '}
|
14
|
+
#
|
15
|
+
# pattern_match.call(42) => 'NaN'
|
16
|
+
#
|
17
|
+
# @example the same matcher may be defined using block syntax
|
18
|
+
# EitherPatternMatch.new do |m|
|
19
|
+
# m.right(Integer, ->(x) { x > 2 }) { |x| x * 2 }
|
20
|
+
# m.right(String) { |x| x.to_i * 2 }
|
21
|
+
# m.left(String) { :err }
|
22
|
+
# m.else { 'error '}
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# @note it has two optimized subclasses +Fear::Left::PatternMatch+ and +Fear::Right::PatternMatch+
|
26
|
+
# @api private
|
27
|
+
class PatternMatch < Fear::PatternMatch
|
28
|
+
# Match against +Fear::Right+
|
29
|
+
#
|
30
|
+
# @param conditions [<#==>]
|
31
|
+
# @return [Fear::Either::PatternMatch]
|
32
|
+
def right(*conditions, &effect)
|
33
|
+
branch = Fear.case(Fear::Right, &:right_value).and_then(Fear.case(*conditions, &effect))
|
34
|
+
or_else(branch)
|
35
|
+
end
|
36
|
+
alias success right
|
37
|
+
|
38
|
+
# Match against +Fear::Left+
|
39
|
+
#
|
40
|
+
# @param conditions [<#==>]
|
41
|
+
# @return [Fear::Either::PatternMatch]
|
42
|
+
def left(*conditions, &effect)
|
43
|
+
branch = Fear.case(Fear::Left, &:left_value).and_then(Fear.case(*conditions, &effect))
|
44
|
+
or_else(branch)
|
45
|
+
end
|
46
|
+
alias failure left
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/fear/either.rb
CHANGED
@@ -116,9 +116,9 @@ module Fear
|
|
116
116
|
# @yieldreturn [Boolean]
|
117
117
|
# @return [Boolean]
|
118
118
|
# @example
|
119
|
-
# Fear.right(12).any?
|
120
|
-
# Fear.right(7).any?
|
121
|
-
# Fear.left('undefined').any?
|
119
|
+
# Fear.right(12).any? { |v| v > 10 } #=> true
|
120
|
+
# Fear.right(7).any? { |v| v > 10 } #=> false
|
121
|
+
# Fear.left('undefined').any? { |v| v > 10 } #=> false
|
122
122
|
#
|
123
123
|
# -----
|
124
124
|
#
|
@@ -177,7 +177,7 @@ module Fear
|
|
177
177
|
#
|
178
178
|
# @!method swap
|
179
179
|
# If this is a +Left+, then return the left value in +Right+ or vice versa.
|
180
|
-
# @return [Either]
|
180
|
+
# @return [Fear::Either]
|
181
181
|
# @example
|
182
182
|
# Fear.left('left').swap #=> Fear.right('left')
|
183
183
|
# Fear.right('right').swap #=> Fear.left('left')
|
@@ -226,7 +226,7 @@ module Fear
|
|
226
226
|
#
|
227
227
|
# @!method match(&matcher)
|
228
228
|
# Pattern match against this +Either+
|
229
|
-
# @yield matcher [Fear::
|
229
|
+
# @yield matcher [Fear::Either::PatternMatch]
|
230
230
|
# @example
|
231
231
|
# either.match do |m|
|
232
232
|
# m.right(Integer) do |x|
|
@@ -280,6 +280,19 @@ module Fear
|
|
280
280
|
[value]
|
281
281
|
end
|
282
282
|
|
283
|
+
# Projects this +Fear::Either+ as a +Fear::Left+.
|
284
|
+
# This allows performing right-biased operation of the left
|
285
|
+
# side of the +Fear::Either+.
|
286
|
+
#
|
287
|
+
# @example
|
288
|
+
# Fear.left(42).left.map(&:succ) #=> Fear.left(43)
|
289
|
+
# Fear.right(42).left.map(&:succ) #=> Fear.left(42)
|
290
|
+
#
|
291
|
+
# @return [Fear::LeftProjection]
|
292
|
+
def left
|
293
|
+
LeftProjection.new(self)
|
294
|
+
end
|
295
|
+
|
283
296
|
class << self
|
284
297
|
# Build pattern matcher to be used later, despite off
|
285
298
|
# +Either#match+ method, id doesn't apply matcher immanently,
|
@@ -296,10 +309,10 @@ module Fear
|
|
296
309
|
# end
|
297
310
|
# matcher.call(Fear.right(42))
|
298
311
|
#
|
299
|
-
# @yieldparam [Fear::
|
312
|
+
# @yieldparam [Fear::Either::PatternMatch]
|
300
313
|
# @return [Fear::PartialFunction]
|
301
314
|
def matcher(&matcher)
|
302
|
-
|
315
|
+
Either::PatternMatch.new(&matcher)
|
303
316
|
end
|
304
317
|
end
|
305
318
|
|
@@ -331,7 +344,3 @@ module Fear
|
|
331
344
|
end
|
332
345
|
end
|
333
346
|
end
|
334
|
-
|
335
|
-
require "fear/either_pattern_match"
|
336
|
-
require "fear/left"
|
337
|
-
require "fear/right"
|
data/lib/fear/either_api.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "fear/either"
|
4
|
-
|
5
3
|
module Fear
|
6
4
|
module EitherApi
|
7
|
-
# @param value [
|
5
|
+
# @param value [Object]
|
8
6
|
# @return [Fear::Left]
|
9
7
|
# @example
|
10
8
|
# Fear.left(42) #=> #<Fear::Left value=42>
|
@@ -13,7 +11,7 @@ module Fear
|
|
13
11
|
Fear::Left.new(value)
|
14
12
|
end
|
15
13
|
|
16
|
-
# @param value [
|
14
|
+
# @param value [Object]
|
17
15
|
# @return [Fear::Right]
|
18
16
|
# @example
|
19
17
|
# Fear.right(42) #=> #<Fear::Right value=42>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Fear
|
4
|
-
# Use singleton version of EmptyPartialFunction -- PartialFunction::
|
4
|
+
# Use singleton version of EmptyPartialFunction -- PartialFunction::Empty
|
5
5
|
# @api private
|
6
6
|
class EmptyPartialFunction
|
7
7
|
include PartialFunction
|
data/lib/fear/failure.rb
CHANGED
data/lib/fear/for_api.rb
CHANGED
data/lib/fear/future.rb
CHANGED
@@ -170,7 +170,7 @@ module Fear
|
|
170
170
|
#
|
171
171
|
# If the future has already been completed,
|
172
172
|
# this will either be applied immediately or be scheduled asynchronously.
|
173
|
-
# @yieldparam [Fear::
|
173
|
+
# @yieldparam [Fear::Try::PatternMatch]
|
174
174
|
# @return [self]
|
175
175
|
#
|
176
176
|
# @example
|
data/lib/fear/future_api.rb
CHANGED
@@ -6,11 +6,6 @@ rescue LoadError
|
|
6
6
|
puts "You must add 'concurrent-ruby' to your Gemfile in order to use Fear::Future"
|
7
7
|
end
|
8
8
|
|
9
|
-
require "fear/awaitable"
|
10
|
-
require "fear/await"
|
11
|
-
require "fear/future"
|
12
|
-
require "fear/promise"
|
13
|
-
|
14
9
|
module Fear
|
15
10
|
# rubocop: disable Layout/LineLength
|
16
11
|
module FutureApi
|