fear 2.0.1 → 3.0.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.
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