fear 2.0.1 → 3.1.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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +105 -0
  3. data/.simplecov +2 -2
  4. data/.standard.yml +1 -0
  5. data/CHANGELOG.md +8 -0
  6. data/Gemfile +14 -2
  7. data/Gemfile.lock +84 -78
  8. data/LICENSE.txt +1 -1
  9. data/README.md +18 -70
  10. data/Rakefile +55 -142
  11. data/benchmarks/dry_do_vs_fear_for.txt +7 -6
  12. data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +7 -6
  13. data/benchmarks/factorial.txt +7 -9
  14. data/benchmarks/fear_gaurd_and1_vs_new.txt +7 -6
  15. data/benchmarks/fear_gaurd_and2_vs_and.txt +8 -7
  16. data/benchmarks/fear_gaurd_and3_vs_and_and.txt +7 -6
  17. data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +7 -6
  18. data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +8 -10
  19. data/examples/pattern_extracting.rb +2 -2
  20. data/examples/pattern_matching_number_in_words.rb +12 -12
  21. data/fear.gemspec +5 -21
  22. data/lib/fear/either/left_projection.rb +237 -0
  23. data/lib/fear/either/pattern_match.rb +49 -0
  24. data/lib/fear/either.rb +21 -12
  25. data/lib/fear/either_api.rb +2 -4
  26. data/lib/fear/empty_partial_function.rb +3 -3
  27. data/lib/fear/failure/pattern_match.rb +14 -0
  28. data/lib/fear/failure.rb +5 -5
  29. data/lib/fear/for.rb +1 -1
  30. data/lib/fear/for_api.rb +1 -3
  31. data/lib/fear/future.rb +6 -6
  32. data/lib/fear/future_api.rb +0 -5
  33. data/lib/fear/left/pattern_match.rb +15 -0
  34. data/lib/fear/left.rb +4 -4
  35. data/lib/fear/none.rb +0 -87
  36. data/lib/fear/none_class/pattern_match.rb +16 -0
  37. data/lib/fear/none_class.rb +85 -0
  38. data/lib/fear/option/pattern_match.rb +47 -0
  39. data/lib/fear/option.rb +2 -6
  40. data/lib/fear/option_api.rb +1 -3
  41. data/lib/fear/partial_function/and_then.rb +2 -2
  42. data/lib/fear/partial_function/combined.rb +3 -3
  43. data/lib/fear/partial_function/empty.rb +3 -5
  44. data/lib/fear/partial_function/guard.rb +0 -4
  45. data/lib/fear/partial_function/or_else.rb +2 -4
  46. data/lib/fear/partial_function.rb +0 -9
  47. data/lib/fear/partial_function_class.rb +2 -2
  48. data/lib/fear/pattern_match.rb +5 -4
  49. data/lib/fear/pattern_matching_api.rb +1 -4
  50. data/lib/fear/right/pattern_match.rb +15 -0
  51. data/lib/fear/right.rb +4 -4
  52. data/lib/fear/right_biased.rb +2 -0
  53. data/lib/fear/some/pattern_match.rb +15 -0
  54. data/lib/fear/some.rb +3 -3
  55. data/lib/fear/success/pattern_match.rb +16 -0
  56. data/lib/fear/success.rb +5 -5
  57. data/lib/fear/try/pattern_match.rb +29 -0
  58. data/lib/fear/try.rb +3 -7
  59. data/lib/fear/try_api.rb +1 -3
  60. data/lib/fear/utils.rb +1 -1
  61. data/lib/fear/version.rb +1 -1
  62. data/lib/fear.rb +3 -14
  63. data/spec/fear/awaitable_spec.rb +0 -2
  64. data/spec/fear/either/left_projection_spec.rb +289 -0
  65. data/spec/fear/{either_pattern_match_spec.rb → either/pattern_match_spec.rb} +7 -7
  66. data/spec/fear/either_spec.rb +1 -1
  67. data/spec/fear/left_spec.rb +1 -1
  68. data/spec/fear/{option_pattern_match_spec.rb → option/pattern_match_spec.rb} +6 -6
  69. data/spec/fear/option_spec.rb +2 -2
  70. data/spec/fear/partial_function/any_spec.rb +3 -3
  71. data/spec/fear/partial_function/empty_spec.rb +2 -2
  72. data/spec/fear/partial_function_and_then_spec.rb +5 -5
  73. data/spec/fear/partial_function_composition_spec.rb +6 -6
  74. data/spec/fear/partial_function_or_else_spec.rb +13 -13
  75. data/spec/fear/partial_function_spec.rb +7 -7
  76. data/spec/fear/pattern_match_spec.rb +5 -5
  77. data/spec/fear/right_spec.rb +1 -1
  78. data/spec/fear/{try_pattern_match_spec.rb → try/try_pattern_match_spec.rb} +7 -7
  79. data/spec/fear/try_api_spec.rb +2 -2
  80. data/spec/fear/utils_spec.rb +3 -3
  81. data/spec/support/.keep +0 -0
  82. metadata +27 -296
  83. data/.github/workflows/rubocop.yml +0 -39
  84. data/.github/workflows/spec.yml +0 -43
  85. data/.rubocop.yml +0 -7
  86. data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +0 -11
  87. data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +0 -11
  88. data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +0 -11
  89. data/lib/dry/types/fear/option.rb +0 -125
  90. data/lib/dry/types/fear.rb +0 -8
  91. data/lib/fear/either_pattern_match.rb +0 -52
  92. data/lib/fear/failure_pattern_match.rb +0 -12
  93. data/lib/fear/left_pattern_match.rb +0 -11
  94. data/lib/fear/none_pattern_match.rb +0 -14
  95. data/lib/fear/option_pattern_match.rb +0 -50
  96. data/lib/fear/right_pattern_match.rb +0 -13
  97. data/lib/fear/some_pattern_match.rb +0 -13
  98. data/lib/fear/struct.rb +0 -237
  99. data/lib/fear/success_pattern_match.rb +0 -14
  100. data/lib/fear/try_pattern_match.rb +0 -32
  101. data/spec/dry/types/fear/option/constrained_spec.rb +0 -22
  102. data/spec/dry/types/fear/option/core_spec.rb +0 -77
  103. data/spec/dry/types/fear/option/default_spec.rb +0 -21
  104. data/spec/dry/types/fear/option/hash_spec.rb +0 -58
  105. data/spec/dry/types/fear/option/option_spec.rb +0 -97
  106. data/spec/struct_pattern_matching_spec.rb +0 -36
  107. data/spec/struct_spec.rb +0 -194
  108. data/spec/support/dry_types.rb +0 -6
data/Rakefile CHANGED
@@ -2,15 +2,30 @@
2
2
 
3
3
  require "bundler/gem_tasks"
4
4
  require "benchmark/ips"
5
+ require "dry/monads"
5
6
  require_relative "lib/fear"
6
7
 
8
+ include Dry::Monads[:maybe]
9
+
10
+ class Operation
11
+ include Dry::Monads::Do.for(:call)
12
+
13
+ def call
14
+ m1 = Some(1)
15
+ m2 = Some(2)
16
+
17
+ one = yield m1
18
+ two = yield m2
19
+
20
+ Some(one + two)
21
+ end
22
+ end
23
+
7
24
  namespace :perf do
8
25
  # Contains benchmarking against Dry-rb
9
26
  namespace :dry do
10
27
  task :some_fmap_vs_fear_some_map do
11
- require "dry/monads/maybe"
12
-
13
- dry = Dry::Monads::Some.new(42)
28
+ dry = Some(42)
14
29
  fear = Fear.some(42)
15
30
 
16
31
  Benchmark.ips do |x|
@@ -23,28 +38,12 @@ namespace :perf do
23
38
  end
24
39
 
25
40
  task :do_vs_fear_for do
26
- require "dry/monads/maybe"
27
41
  require "dry/monads/do"
28
42
 
29
- class Operation
30
- include Dry::Monads::Maybe::Mixin
31
- include Dry::Monads::Do.for(:call)
32
-
33
- def call
34
- m1 = Some(1)
35
- m2 = Some(2)
36
-
37
- one = yield m1
38
- two = yield m2
39
-
40
- Some(one + two)
41
- end
42
- end
43
-
44
43
  op = Operation.new
45
44
 
46
45
  Benchmark.ips do |x|
47
- x.report("Dry") { op.() }
46
+ x.report("Dry") { op.call }
48
47
 
49
48
  x.report("Fear") do |_n|
50
49
  Fear.for(Fear.some(1), Fear.some(2)) do |one, two|
@@ -59,40 +58,21 @@ namespace :perf do
59
58
 
60
59
  # Contains internal benchmarking to if optimization works
61
60
  namespace :fear do
62
- task :fear_pattern_extracting_with_vs_without_cache do
63
- some = Fear.some([:err, "not found"])
64
-
65
- class WOCache < Fear::Extractor::Pattern
66
- def initialize(pattern)
67
- @matcher = compile_pattern_without_cache(pattern)
68
- end
69
- end
70
- pattern = "Fear::Some([:err, code])"
71
-
72
- Benchmark.ips do |x|
73
- x.report("With cache") do |_n|
74
- Fear::Extractor::Pattern.new(pattern).extracted_arguments(some)
75
- end
76
-
77
- x.report("Without cache") do |_n|
78
- WOCache.new(pattern).extracted_arguments(some)
79
- end
80
-
81
- x.compare!
82
- end
83
- end
84
-
85
61
  namespace :guard do
86
62
  task :and1_vs_new do
87
- condition = Integer
63
+ iterations = 1_000
88
64
 
89
65
  Benchmark.ips do |x|
90
66
  x.report("Guard.new") do |n|
91
- Fear::PartialFunction::Guard.new(condition) === n
67
+ iterations.times do
68
+ Fear::PartialFunction::Guard.new(Integer) === n
69
+ end
92
70
  end
93
71
 
94
72
  x.report("Guard.and1") do |n|
95
- Fear::PartialFunction::Guard.and1(condition) === n
73
+ iterations.times do
74
+ Fear::PartialFunction::Guard.and1(Integer) === n
75
+ end
96
76
  end
97
77
 
98
78
  x.compare!
@@ -100,6 +80,7 @@ namespace :perf do
100
80
  end
101
81
 
102
82
  task :and2_vs_and do
83
+ iterations = 1_000
103
84
  first = Integer
104
85
  second = ->(x) { x > 2 }
105
86
 
@@ -108,11 +89,11 @@ namespace :perf do
108
89
 
109
90
  Benchmark.ips do |x|
110
91
  x.report("and2") do |n|
111
- and2 === n
92
+ iterations.times { and2 === n }
112
93
  end
113
94
 
114
95
  x.report("Guard#and") do |n|
115
- and_and === n
96
+ iterations.times { and_and === n }
116
97
  end
117
98
 
118
99
  x.compare!
@@ -120,6 +101,7 @@ namespace :perf do
120
101
  end
121
102
 
122
103
  task :and3_vs_and_and do
104
+ iterations = 1_000
123
105
  first = Integer
124
106
  second = ->(x) { x > 2 }
125
107
  third = ->(x) { x < 10 }
@@ -132,11 +114,11 @@ namespace :perf do
132
114
 
133
115
  Benchmark.ips do |x|
134
116
  x.report("Guard.and3") do |n|
135
- and3 === n
117
+ iterations.times { and3 === n }
136
118
  end
137
119
 
138
120
  x.report("Guard#and") do |n|
139
- and_and_and === n
121
+ iterations.times { and_and_and === n }
140
122
  end
141
123
 
142
124
  x.compare!
@@ -159,22 +141,23 @@ namespace :perf do
159
141
  end
160
142
 
161
143
  x.report("execution") do
162
- matcher.(42)
144
+ matcher.call(42)
163
145
  end
164
146
 
165
147
  x.compare!
166
148
  end
167
149
  end
168
- end
169
-
170
- namespace :pattern_matching do
171
- require "qo"
172
- require "dry/matcher"
173
150
 
174
151
  task :option_match_vs_native_pattern_match do
175
152
  some = Fear.some(42)
176
153
 
177
154
  Benchmark.ips do |x|
155
+ matcher = Fear::Option.matcher do |m|
156
+ m.some(41, &:itself)
157
+ m.some(42, &:itself)
158
+ m.some(45, &:itself)
159
+ end
160
+
178
161
  x.report("case ... in ...") do
179
162
  case some
180
163
  in Fear::Some(41 => x)
@@ -186,7 +169,7 @@ namespace :perf do
186
169
  end
187
170
  end
188
171
 
189
- x.report("Option.match") do
172
+ x.report("Option#match") do
190
173
  some.match do |m|
191
174
  m.some(41, &:itself)
192
175
  m.some(42, &:itself)
@@ -194,39 +177,31 @@ namespace :perf do
194
177
  end
195
178
  end
196
179
 
180
+ x.report("Option#matcher") do
181
+ matcher.call(some)
182
+ end
183
+
197
184
  x.compare!
198
185
  end
199
186
  end
187
+ end
200
188
 
201
- task :dry_vs_qo_vs_fear_try do
202
- module ExhaustivePatternMatch
203
- def initialize(*)
204
- super
205
- @default ||= self.else { raise Fear::MatchError }
206
- end
207
- end
208
-
209
- SuccessBranch = Qo.create_branch(name: "success", precondition: Fear::Success, extractor: :get)
210
- FailureBranch = Qo.create_branch(name: "failure", precondition: Fear::Failure, extractor: :exception)
211
-
212
- PatternMatch = Qo.create_pattern_match(
213
- branches: [SuccessBranch, FailureBranch],
214
- ).prepend(ExhaustivePatternMatch)
215
-
216
- Fear::Success.include(PatternMatch.mixin(as: :qo_match))
189
+ namespace :pattern_matching do
190
+ require "dry/matcher"
217
191
 
192
+ task :dry_vs_fear_try do
218
193
  success_case = Dry::Matcher::Case.new(
219
194
  match: ->(try, *pattern) {
220
195
  try.is_a?(Fear::Success) && pattern.all? { |p| p === try.get }
221
196
  },
222
- resolve: ->(try) { try.get },
197
+ resolve: ->(try) { try.get }
223
198
  )
224
199
 
225
200
  failure_case = Dry::Matcher::Case.new(
226
201
  match: ->(try, *pattern) {
227
202
  try.is_a?(Fear::Failure) && pattern.all? { |p| p === try.exception }
228
203
  },
229
- resolve: ->(value) { value.exception },
204
+ resolve: ->(value) { value.exception }
230
205
  )
231
206
 
232
207
  # Build the matcher
@@ -235,14 +210,6 @@ namespace :perf do
235
210
  success = Fear::Success.new(4)
236
211
 
237
212
  Benchmark.ips do |x|
238
- x.report("Qo") do
239
- success.qo_match do |m|
240
- m.failure(&:itself)
241
- m.success(Integer, ->(y) { y % 5 == 0 }, &:itself)
242
- m.success { "else" }
243
- end
244
- end
245
-
246
213
  x.report("Fear") do
247
214
  success.match do |m|
248
215
  m.failure(&:itself)
@@ -252,7 +219,7 @@ namespace :perf do
252
219
  end
253
220
 
254
221
  x.report("Dr::Matcher") do
255
- matcher.(success) do |m|
222
+ matcher.call(success) do |m|
256
223
  m.failure(&:itself)
257
224
  m.success(Integer, ->(y) { y % 5 == 0 }, &:itself)
258
225
  m.success { "else" }
@@ -263,82 +230,28 @@ namespace :perf do
263
230
  end
264
231
  end
265
232
 
266
- task :qo_vs_fear_try_execution do
267
- module ExhaustivePatternMatch
268
- def initialize(*)
269
- super
270
- @default ||= self.else { raise Fear::MatchError }
271
- end
272
- end
273
-
274
- SuccessBranch = Qo.create_branch(name: "success", precondition: Fear::Success, extractor: :get)
275
- FailureBranch = Qo.create_branch(name: "failure", precondition: Fear::Failure, extractor: :exception)
276
-
277
- QoPatternMatch = Qo.create_pattern_match(
278
- branches: [SuccessBranch, FailureBranch],
279
- ).prepend(ExhaustivePatternMatch)
280
-
281
- Fear::Success.include(QoPatternMatch.mixin(as: :qo_match))
282
-
283
- success = Fear::Success.new(4)
284
-
285
- qo_matcher = QoPatternMatch.new do |m|
286
- m.success(1, &:itself)
287
- m.success(4, &:itself)
288
- m.failure { "failure" }
289
- end
290
-
291
- fear_matcher = Fear::TryPatternMatch.new do |m|
292
- m.success(1, &:itself)
293
- m.success(4, &:itself)
294
- m.failure { "failure" }
295
- end
296
-
297
- Benchmark.ips do |x|
298
- x.report("Qo") do
299
- qo_matcher.(success)
300
- end
301
-
302
- x.report("Fear") do
303
- fear_matcher.(success)
304
- end
305
-
306
- x.compare!
307
- end
308
- end
309
-
310
233
  task :factorial do
311
234
  factorial_proc = proc do |n|
312
235
  if n <= 1
313
236
  1
314
237
  else
315
- n * factorial_proc.(n - 1)
238
+ n * factorial_proc.call(n - 1)
316
239
  end
317
240
  end
318
241
 
319
242
  factorial_pm = Fear.matcher do |m|
320
243
  m.case(1, &:itself)
321
244
  m.case(0, &:itself)
322
- m.else { |n| n * factorial_pm.(n - 1) }
323
- end
324
-
325
- factorial_qo = Qo.match do |m|
326
- m.when(1, &:itself)
327
- m.when(0, &:itself)
328
- m.else { |n| n * factorial_qo.(n - 1) }
245
+ m.else { |n| n * factorial_pm.call(n - 1) }
329
246
  end
330
247
 
331
248
  Benchmark.ips do |x|
332
249
  x.report("Proc") do
333
- factorial_proc.(100)
250
+ factorial_proc.call(100)
334
251
  end
335
252
 
336
253
  x.report("Fear") do
337
- factorial_pm.(100)
338
- end
339
-
340
- x.report("Qo") do
341
- factorial_qo.(100)
254
+ factorial_pm.call(100)
342
255
  end
343
256
 
344
257
  x.compare!
@@ -1,11 +1,12 @@
1
1
  > bundle exec rake perf:dry:do_vs_fear_for
2
+ ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
2
3
  Warming up --------------------------------------
3
- Dry 31.375k i/100ms
4
- Fear 24.131k i/100ms
4
+ Dry 50.838k i/100ms
5
+ Fear 53.687T i/100ms
5
6
  Calculating -------------------------------------
6
- Dry 360.990k2.7%) i/s - 1.820M in 5.045364s
7
- Fear 7.212B27.2%) i/s - 27.210B in 4.656760s
7
+ Dry 505.586k1.3%) i/s - 2.542M in 5.028546s
8
+ Fear 38414118363278401536.00035.1%) i/s - 129350402624716800000.000 in 4.237227s
8
9
 
9
10
  Comparison:
10
- Fear: 7212177713.5 i/s
11
- Dry: 360989.8 i/s - 19978.90x slower
11
+ Fear: 38414118363278401536.0 i/s
12
+ Dry: 505586.3 i/s - 75979343079241.66x slower
@@ -1,11 +1,12 @@
1
1
  > bundle exec rake perf:dry:some_fmap_vs_fear_some_map
2
+ ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
2
3
  Warming up --------------------------------------
3
- Dry 68.154k i/100ms
4
- Fear 151.093k i/100ms
4
+ Dry 156.108k i/100ms
5
+ Fear 398.884k i/100ms
5
6
  Calculating -------------------------------------
6
- Dry 884.315k4.1%) i/s - 4.430M in 5.018931s
7
- Fear 2.481M4.1%) i/s - 12.390M in 5.003728s
7
+ Dry 1.561M0.2%) i/s - 7.962M in 5.099636s
8
+ Fear 3.976M0.5%) i/s - 19.944M in 5.016186s
8
9
 
9
10
  Comparison:
10
- Fear: 2480589.0 i/s
11
- Dry: 884315.1 i/s - 2.81x slower
11
+ Fear: 3976079.7 i/s
12
+ Dry: 1561199.0 i/s - 2.55x slower
@@ -1,16 +1,14 @@
1
1
  # Depends on `n`, for 100!:
2
2
 
3
3
  > bundle exec rake perf:pattern_matching:factorial
4
+ ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]
4
5
  Warming up --------------------------------------
5
- Proc 2.395k i/100ms
6
- Fear 312.000 i/100ms
7
- Qo 122.000 i/100ms
6
+ Proc 5.678k i/100ms
7
+ Fear 859.000 i/100ms
8
8
  Calculating -------------------------------------
9
- Proc 26.620k (± 2.9%) i/s - 134.120k in 5.042738s
10
- Fear 3.219k4.1%) i/s - 16.224k in 5.049215s
11
- Qo 1.250k (± 4.8%) i/s - 6.344k in 5.090745s
9
+ Proc 56.634k0.2%) i/s - 283.900k in 5.012921s
10
+ Fear 8.573k0.5%) i/s - 42.950k in 5.009859s
12
11
 
13
12
  Comparison:
14
- Proc: 26620.3 i/s
15
- Fear: 3219.4 i/s - 8.27x slower
16
- Qo: 1249.6 i/s - 21.30x slower
13
+ Proc: 56633.8 i/s
14
+ Fear: 8573.3 i/s - 6.61x slower
@@ -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
@@ -13,5 +13,5 @@ matcher = proc do |value|
13
13
  end
14
14
  end
15
15
 
16
- matcher.(User.new(1, "Jane", true))
17
- matcher.(User.new(1, "John", false))
16
+ matcher.call(User.new(1, "Jane", true))
17
+ matcher.call(User.new(1, "John", false))
@@ -31,7 +31,7 @@ class ToWords
31
31
  60 => "sixty",
32
32
  70 => "seventy",
33
33
  80 => "eighty",
34
- 90 => "ninety",
34
+ 90 => "ninety"
35
35
  }.freeze
36
36
  private_constant :NUMBERS
37
37
 
@@ -39,22 +39,22 @@ class ToWords
39
39
  NUMBERS.each_pair do |number, in_words|
40
40
  m.case(number) { in_words }
41
41
  end
42
- m.case(->(n) { n < 0 }) { |n| "minus #{CONVERTER.(-n)}" }
43
- m.case(->(n) { n < 100 }) { |n| "#{CONVERTER.((n / 10) * 10)}-#{CONVERTER.(n % 10)}" }
44
- m.case(->(n) { n < 200 }) { |n| "one hundred #{CONVERTER.(n % 100)}" }
45
- m.case(->(n) { n < 1_000 }) { |n| "#{CONVERTER.(n / 100)} hundreds #{CONVERTER.(n % 100)}" }
46
- m.case(->(n) { n < 2_000 }) { |n| "one thousand #{CONVERTER.(n % 1000)}" }
47
- m.case(->(n) { n < 1_000_000 }) { |n| "#{CONVERTER.(n / 1_000)} thousands #{CONVERTER.(n % 1_000)}" }
42
+ m.case(->(n) { n < 0 }) { |n| "minus #{CONVERTER.call(-n)}" }
43
+ m.case(->(n) { n < 100 }) { |n| "#{CONVERTER.call((n / 10) * 10)}-#{CONVERTER.call(n % 10)}" }
44
+ m.case(->(n) { n < 200 }) { |n| "one hundred #{CONVERTER.call(n % 100)}" }
45
+ m.case(->(n) { n < 1_000 }) { |n| "#{CONVERTER.call(n / 100)} hundreds #{CONVERTER.call(n % 100)}" }
46
+ m.case(->(n) { n < 2_000 }) { |n| "one thousand #{CONVERTER.call(n % 1000)}" }
47
+ m.case(->(n) { n < 1_000_000 }) { |n| "#{CONVERTER.call(n / 1_000)} thousands #{CONVERTER.call(n % 1_000)}" }
48
48
  m.else { |n| raise "#{n} too big " }
49
49
  end
50
50
  private_constant :CONVERTER
51
51
 
52
52
  def self.call(number)
53
- Fear.case(Integer, &:itself).and_then(CONVERTER).(number)
53
+ Fear.case(Integer, &:itself).and_then(CONVERTER).call(number)
54
54
  end
55
55
  end
56
56
 
57
- ToWords.(99) #=> 'ninety-nine'
58
- ToWords.(133) #=> 'one hundred thirty-three
59
- ToWords.(777) #=> 'seven hundreds seventy-seven'
60
- ToWords.(254_555) #=> 'two hundreds fifty-four thousands five hundreds fifty-five'
57
+ ToWords.call(99) #=> 'ninety-nine'
58
+ ToWords.call(133) #=> 'one hundred thirty-three
59
+ ToWords.call(777) #=> 'seven hundreds seventy-seven'
60
+ ToWords.call(254_555) #=> 'two hundreds fifty-four thousands five hundreds fifty-five'
data/fear.gemspec CHANGED
@@ -8,33 +8,17 @@ 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"
16
16
  spec.license = "MIT"
17
17
 
18
18
  spec.files = `git ls-files -z`.split("\x0")
19
- spec.executables = spec.files.grep(%r{^bin\/}) { |f| File.basename(f) }
20
- spec.test_files = spec.files.grep(%r{^spec\/})
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
20
  spec.require_paths = ["lib"]
22
- spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
21
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.2")
23
22
 
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"
23
+ spec.add_runtime_dependency "zeitwerk"
40
24
  end