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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +105 -0
- data/.simplecov +2 -2
- data/.standard.yml +1 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +14 -2
- data/Gemfile.lock +84 -78
- data/LICENSE.txt +1 -1
- data/README.md +18 -70
- data/Rakefile +55 -142
- 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/examples/pattern_extracting.rb +2 -2
- data/examples/pattern_matching_number_in_words.rb +12 -12
- data/fear.gemspec +5 -21
- data/lib/fear/either/left_projection.rb +237 -0
- data/lib/fear/either/pattern_match.rb +49 -0
- data/lib/fear/either.rb +21 -12
- data/lib/fear/either_api.rb +2 -4
- data/lib/fear/empty_partial_function.rb +3 -3
- data/lib/fear/failure/pattern_match.rb +14 -0
- data/lib/fear/failure.rb +5 -5
- data/lib/fear/for.rb +1 -1
- data/lib/fear/for_api.rb +1 -3
- data/lib/fear/future.rb +6 -6
- data/lib/fear/future_api.rb +0 -5
- data/lib/fear/left/pattern_match.rb +15 -0
- data/lib/fear/left.rb +4 -4
- 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 +2 -6
- data/lib/fear/option_api.rb +1 -3
- data/lib/fear/partial_function/and_then.rb +2 -2
- data/lib/fear/partial_function/combined.rb +3 -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 +2 -4
- data/lib/fear/partial_function.rb +0 -9
- data/lib/fear/partial_function_class.rb +2 -2
- data/lib/fear/pattern_match.rb +5 -4
- data/lib/fear/pattern_matching_api.rb +1 -4
- data/lib/fear/right/pattern_match.rb +15 -0
- data/lib/fear/right.rb +4 -4
- data/lib/fear/right_biased.rb +2 -0
- data/lib/fear/some/pattern_match.rb +15 -0
- data/lib/fear/some.rb +3 -3
- data/lib/fear/success/pattern_match.rb +16 -0
- data/lib/fear/success.rb +5 -5
- data/lib/fear/try/pattern_match.rb +29 -0
- data/lib/fear/try.rb +3 -7
- data/lib/fear/try_api.rb +1 -3
- data/lib/fear/utils.rb +1 -1
- 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} +7 -7
- data/spec/fear/either_spec.rb +1 -1
- data/spec/fear/left_spec.rb +1 -1
- data/spec/fear/{option_pattern_match_spec.rb → option/pattern_match_spec.rb} +6 -6
- data/spec/fear/option_spec.rb +2 -2
- data/spec/fear/partial_function/any_spec.rb +3 -3
- data/spec/fear/partial_function/empty_spec.rb +2 -2
- data/spec/fear/partial_function_and_then_spec.rb +5 -5
- data/spec/fear/partial_function_composition_spec.rb +6 -6
- data/spec/fear/partial_function_or_else_spec.rb +13 -13
- data/spec/fear/partial_function_spec.rb +7 -7
- data/spec/fear/pattern_match_spec.rb +5 -5
- data/spec/fear/right_spec.rb +1 -1
- data/spec/fear/{try_pattern_match_spec.rb → try/try_pattern_match_spec.rb} +7 -7
- data/spec/fear/try_api_spec.rb +2 -2
- data/spec/fear/utils_spec.rb +3 -3
- data/spec/support/.keep +0 -0
- metadata +27 -296
- data/.github/workflows/rubocop.yml +0 -39
- data/.github/workflows/spec.yml +0 -43
- data/.rubocop.yml +0 -7
- data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +0 -11
- data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +0 -11
- data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +0 -11
- data/lib/dry/types/fear/option.rb +0 -125
- data/lib/dry/types/fear.rb +0 -8
- data/lib/fear/either_pattern_match.rb +0 -52
- data/lib/fear/failure_pattern_match.rb +0 -12
- data/lib/fear/left_pattern_match.rb +0 -11
- data/lib/fear/none_pattern_match.rb +0 -14
- data/lib/fear/option_pattern_match.rb +0 -50
- data/lib/fear/right_pattern_match.rb +0 -13
- data/lib/fear/some_pattern_match.rb +0 -13
- data/lib/fear/struct.rb +0 -237
- data/lib/fear/success_pattern_match.rb +0 -14
- data/lib/fear/try_pattern_match.rb +0 -32
- data/spec/dry/types/fear/option/constrained_spec.rb +0 -22
- data/spec/dry/types/fear/option/core_spec.rb +0 -77
- data/spec/dry/types/fear/option/default_spec.rb +0 -21
- data/spec/dry/types/fear/option/hash_spec.rb +0 -58
- data/spec/dry/types/fear/option/option_spec.rb +0 -97
- data/spec/struct_pattern_matching_spec.rb +0 -36
- data/spec/struct_spec.rb +0 -194
- data/spec/support/dry_types.rb +0 -6
data/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
|
-
|
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
|
-
|
63
|
+
iterations = 1_000
|
88
64
|
|
89
65
|
Benchmark.ips do |x|
|
90
66
|
x.report("Guard.new") do |n|
|
91
|
-
|
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
|
-
|
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
|
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
|
-
|
202
|
-
|
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
|
4
|
-
Fear
|
4
|
+
Dry 50.838k i/100ms
|
5
|
+
Fear 53.687T i/100ms
|
5
6
|
Calculating -------------------------------------
|
6
|
-
Dry
|
7
|
-
Fear
|
7
|
+
Dry 505.586k (± 1.3%) i/s - 2.542M in 5.028546s
|
8
|
+
Fear 38414118363278401536.000 (±35.1%) i/s - 129350402624716800000.000 in 4.237227s
|
8
9
|
|
9
10
|
Comparison:
|
10
|
-
Fear:
|
11
|
-
Dry:
|
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
|
4
|
-
Fear
|
4
|
+
Dry 156.108k i/100ms
|
5
|
+
Fear 398.884k i/100ms
|
5
6
|
Calculating -------------------------------------
|
6
|
-
Dry
|
7
|
-
Fear
|
7
|
+
Dry 1.561M (± 0.2%) i/s - 7.962M in 5.099636s
|
8
|
+
Fear 3.976M (± 0.5%) i/s - 19.944M in 5.016186s
|
8
9
|
|
9
10
|
Comparison:
|
10
|
-
Fear:
|
11
|
-
Dry:
|
11
|
+
Fear: 3976079.7 i/s
|
12
|
+
Dry: 1561199.0 i/s - 2.55x slower
|
data/benchmarks/factorial.txt
CHANGED
@@ -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
|
6
|
-
Fear
|
7
|
-
Qo 122.000 i/100ms
|
6
|
+
Proc 5.678k i/100ms
|
7
|
+
Fear 859.000 i/100ms
|
8
8
|
Calculating -------------------------------------
|
9
|
-
Proc
|
10
|
-
Fear
|
11
|
-
Qo 1.250k (± 4.8%) i/s - 6.344k in 5.090745s
|
9
|
+
Proc 56.634k (± 0.2%) i/s - 283.900k in 5.012921s
|
10
|
+
Fear 8.573k (± 0.5%) i/s - 42.950k in 5.009859s
|
12
11
|
|
13
12
|
Comparison:
|
14
|
-
Proc:
|
15
|
-
Fear:
|
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
|
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
|
@@ -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 = ["
|
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"
|
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
|
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
|
21
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.2")
|
23
22
|
|
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"
|
23
|
+
spec.add_runtime_dependency "zeitwerk"
|
40
24
|
end
|