fear 2.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/spec.yml +1 -5
  3. data/CHANGELOG.md +8 -0
  4. data/Gemfile +14 -2
  5. data/Gemfile.lock +48 -61
  6. data/LICENSE.txt +1 -1
  7. data/README.md +18 -70
  8. data/Rakefile +32 -119
  9. data/benchmarks/dry_do_vs_fear_for.txt +7 -6
  10. data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +7 -6
  11. data/benchmarks/factorial.txt +7 -9
  12. data/benchmarks/fear_gaurd_and1_vs_new.txt +7 -6
  13. data/benchmarks/fear_gaurd_and2_vs_and.txt +8 -7
  14. data/benchmarks/fear_gaurd_and3_vs_and_and.txt +7 -6
  15. data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +7 -6
  16. data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +8 -10
  17. data/fear.gemspec +4 -19
  18. data/lib/fear/either/left_projection.rb +237 -0
  19. data/lib/fear/either/pattern_match.rb +49 -0
  20. data/lib/fear/either.rb +20 -11
  21. data/lib/fear/either_api.rb +2 -4
  22. data/lib/fear/empty_partial_function.rb +1 -1
  23. data/lib/fear/failure/pattern_match.rb +14 -0
  24. data/lib/fear/failure.rb +1 -1
  25. data/lib/fear/for_api.rb +0 -2
  26. data/lib/fear/future.rb +1 -1
  27. data/lib/fear/future_api.rb +0 -5
  28. data/lib/fear/left/pattern_match.rb +15 -0
  29. data/lib/fear/left.rb +1 -1
  30. data/lib/fear/none.rb +0 -87
  31. data/lib/fear/none_class/pattern_match.rb +16 -0
  32. data/lib/fear/none_class.rb +85 -0
  33. data/lib/fear/option/pattern_match.rb +47 -0
  34. data/lib/fear/option.rb +1 -5
  35. data/lib/fear/option_api.rb +1 -3
  36. data/lib/fear/partial_function/empty.rb +3 -5
  37. data/lib/fear/partial_function/guard.rb +0 -4
  38. data/lib/fear/partial_function/or_else.rb +0 -2
  39. data/lib/fear/partial_function.rb +0 -9
  40. data/lib/fear/partial_function_class.rb +1 -1
  41. data/lib/fear/pattern_match.rb +3 -2
  42. data/lib/fear/pattern_matching_api.rb +0 -3
  43. data/lib/fear/right/pattern_match.rb +15 -0
  44. data/lib/fear/right.rb +1 -1
  45. data/lib/fear/right_biased.rb +2 -0
  46. data/lib/fear/some/pattern_match.rb +15 -0
  47. data/lib/fear/some.rb +1 -1
  48. data/lib/fear/success/pattern_match.rb +16 -0
  49. data/lib/fear/success.rb +1 -1
  50. data/lib/fear/try/pattern_match.rb +29 -0
  51. data/lib/fear/try.rb +3 -7
  52. data/lib/fear/try_api.rb +0 -2
  53. data/lib/fear/version.rb +1 -1
  54. data/lib/fear.rb +3 -14
  55. data/spec/fear/awaitable_spec.rb +0 -2
  56. data/spec/fear/either/left_projection_spec.rb +289 -0
  57. data/spec/fear/{either_pattern_match_spec.rb → either/pattern_match_spec.rb} +1 -1
  58. data/spec/fear/{option_pattern_match_spec.rb → option/pattern_match_spec.rb} +1 -1
  59. data/spec/fear/partial_function/empty_spec.rb +1 -1
  60. data/spec/fear/{try_pattern_match_spec.rb → try/try_pattern_match_spec.rb} +1 -1
  61. data/spec/support/.keep +0 -0
  62. metadata +29 -255
  63. data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +0 -11
  64. data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +0 -11
  65. data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +0 -11
  66. data/lib/dry/types/fear/option.rb +0 -125
  67. data/lib/dry/types/fear.rb +0 -8
  68. data/lib/fear/either_pattern_match.rb +0 -52
  69. data/lib/fear/failure_pattern_match.rb +0 -12
  70. data/lib/fear/left_pattern_match.rb +0 -11
  71. data/lib/fear/none_pattern_match.rb +0 -14
  72. data/lib/fear/option_pattern_match.rb +0 -50
  73. data/lib/fear/right_pattern_match.rb +0 -13
  74. data/lib/fear/some_pattern_match.rb +0 -13
  75. data/lib/fear/struct.rb +0 -237
  76. data/lib/fear/success_pattern_match.rb +0 -14
  77. data/lib/fear/try_pattern_match.rb +0 -32
  78. data/spec/dry/types/fear/option/constrained_spec.rb +0 -22
  79. data/spec/dry/types/fear/option/core_spec.rb +0 -77
  80. data/spec/dry/types/fear/option/default_spec.rb +0 -21
  81. data/spec/dry/types/fear/option/hash_spec.rb +0 -58
  82. data/spec/dry/types/fear/option/option_spec.rb +0 -97
  83. data/spec/struct_pattern_matching_spec.rb +0 -36
  84. data/spec/struct_spec.rb +0 -194
  85. 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 173.019k i/100ms
6
- Guard.and1 268.379k i/100ms
6
+ Guard.new 571.139B i/100ms
7
+ Guard.and1 1.884T i/100ms
7
8
  Calculating -------------------------------------
8
- Guard.new 171.291B 8.4%) i/s - 561.437B
9
- Guard.and1 266.882B5.9%) i/s - 751.316B
9
+ Guard.new 2.927Q10.3%) i/s - 14.393Q in 4.993407s
10
+ Guard.and1 32.583Q2.2%) i/s - 162.090Q in 4.977493s
10
11
 
11
12
  Comparison:
12
- Guard.and1: 266881817299.6 i/s
13
- Guard.new: 171291386467.1 i/s - 1.56x slower
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:and2_vs_guard_and_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 224.836k i/100ms
6
- Guard#and 211.833k i/100ms
6
+ and2 807.325B i/100ms
7
+ Guard#and 692.737B i/100ms
7
8
  Calculating -------------------------------------
8
- and2 224.457B3.8%) i/s - 651.564B
9
- Guard#and 211.486B3.7%) i/s - 667.936B
9
+ and2 6.011Q2.4%) i/s - 29.972Q in 4.989608s
10
+ Guard#and 4.443Q2.1%) i/s - 22.168Q in 4.991463s
10
11
 
11
12
  Comparison:
12
- and2: 224457051906.8 i/s
13
- Guard#and: 211485786834.4 i/s - same-ish: difference falls within error
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 236.318k i/100ms
6
- Guard#and 170.369k i/100ms
6
+ Guard.and3 580.401B i/100ms
7
+ Guard#and 350.896B i/100ms
7
8
  Calculating -------------------------------------
8
- Guard.and3 235.992B (± 3.4%) i/s - 791.166B
9
- Guard#and 169.998B4.0%) i/s - 640.637B
9
+ Guard.and3 3.152Q1.3%) i/s - 15.736Q in 4.993183s
10
+ Guard#and 1.132Q1.7%) i/s - 5.653Q in 4.996181s
10
11
 
11
12
  Comparison:
12
- Guard.and3: 235992292688.6 i/s
13
- Guard#and: 169997755111.1 i/s - 1.39x slower
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 24.425k i/100ms
6
- execution 80.516k i/100ms
6
+ construction 53.068k i/100ms
7
+ execution 280.541k i/100ms
7
8
  Calculating -------------------------------------
8
- construction 267.887k4.9%) i/s - 1.343M in 5.029005s
9
- execution 1.085M2.6%) i/s - 5.475M in 5.049775s
9
+ construction 537.049k0.2%) i/s - 2.706M in 5.039544s
10
+ execution 2.799M0.4%) i/s - 14.027M in 5.011175s
10
11
 
11
12
  Comparison:
12
- execution: 1084968.2 i/s
13
- construction: 267886.6 i/s - 4.05x slower
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:dry_vs_qo_vs_fear_try
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
- Qo 2.958k i/100ms
4
- Fear 7.127k i/100ms
5
- Dr::Matcher 13.079k i/100ms
4
+ Fear 18.527k i/100ms
5
+ Dr::Matcher 40.145k i/100ms
6
6
  Calculating -------------------------------------
7
- Qo 38.872k3.1%) i/s - 195.228k in 5.027249s
8
- Fear 88.756k3.7%) i/s - 449.001k in 5.066471s
9
- Dr::Matcher 166.700k (± 3.0%) i/s - 837.056k in 5.026408s
7
+ Fear 187.617k0.4%) i/s - 944.877k in 5.036258s
8
+ Dr::Matcher 395.181k1.9%) i/s - 2.007M in 5.081136s
10
9
 
11
10
  Comparison:
12
- Dr::Matcher: 166699.7 i/s
13
- Fear: 88755.7 i/s - 1.88x slower
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 = ["Tema Bolshakov"]
12
- spec.email = ["abolshakov@spbtv.com"]
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(">= 2.6.0")
22
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.1")
23
23
 
24
- spec.add_development_dependency "benchmark-ips"
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?( |v| v > 10) #=> true
120
- # Fear.right(7).any?( |v| v > 10) #=> false
121
- # Fear.left('undefined').any?( |v| v > 10) #=> false
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::EitherPatternMatch]
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::EitherPatternMatch]
312
+ # @yieldparam [Fear::Either::PatternMatch]
300
313
  # @return [Fear::PartialFunction]
301
314
  def matcher(&matcher)
302
- EitherPatternMatch.new(&matcher)
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"
@@ -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 [any]
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 [any]
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::EMPTY
4
+ # Use singleton version of EmptyPartialFunction -- PartialFunction::Empty
5
5
  # @api private
6
6
  class EmptyPartialFunction
7
7
  include PartialFunction
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ class Failure
5
+ # @api private
6
+ class PatternMatch < Try::PatternMatch
7
+ def success(*_conditions)
8
+ self
9
+ end
10
+ end
11
+
12
+ private_constant :PatternMatch
13
+ end
14
+ end
data/lib/fear/failure.rb CHANGED
@@ -4,7 +4,7 @@ module Fear
4
4
  class Failure
5
5
  include Try
6
6
  include RightBiased::Left
7
- include FailurePatternMatch.mixin
7
+ include PatternMatch.mixin
8
8
 
9
9
  # @param [StandardError]
10
10
  def initialize(exception)
data/lib/fear/for_api.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fear/for"
4
-
5
3
  module Fear
6
4
  module ForApi
7
5
  # Syntactic sugar for composition of multiple monadic operations. It supports two such
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::TryPatternMatch]
173
+ # @yieldparam [Fear::Try::PatternMatch]
174
174
  # @return [self]
175
175
  #
176
176
  # @example
@@ -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
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ class Left
5
+ # @api private
6
+ class PatternMatch < Fear::Either::PatternMatch
7
+ def right(*)
8
+ self
9
+ end
10
+ alias success right
11
+ end
12
+
13
+ private_constant :PatternMatch
14
+ end
15
+ end
data/lib/fear/left.rb CHANGED
@@ -4,7 +4,7 @@ module Fear
4
4
  class Left
5
5
  include Either
6
6
  include RightBiased::Left
7
- include LeftPatternMatch.mixin
7
+ include PatternMatch.mixin
8
8
 
9
9
  # @api private
10
10
  def left_value