fear 1.0.0 → 2.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.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +27 -0
- data/.github/workflows/rubocop.yml +39 -0
- data/.github/workflows/spec.yml +42 -0
- data/.rubocop.yml +4 -60
- data/.simplecov +17 -0
- data/CHANGELOG.md +29 -1
- data/Gemfile +5 -5
- data/Gemfile.lock +86 -50
- data/README.md +240 -209
- data/Rakefile +72 -65
- data/examples/pattern_extracting.rb +10 -8
- data/examples/pattern_matching_binary_tree_set.rb +7 -2
- data/examples/pattern_matching_number_in_words.rb +48 -42
- data/fear.gemspec +33 -34
- data/lib/dry/types/fear/option.rb +125 -0
- data/lib/dry/types/fear.rb +8 -0
- data/lib/fear/await.rb +33 -0
- data/lib/fear/awaitable.rb +28 -0
- data/lib/fear/either.rb +15 -4
- data/lib/fear/either_api.rb +4 -0
- data/lib/fear/either_pattern_match.rb +9 -5
- data/lib/fear/empty_partial_function.rb +3 -1
- data/lib/fear/failure.rb +7 -7
- data/lib/fear/failure_pattern_match.rb +4 -0
- data/lib/fear/for.rb +4 -2
- data/lib/fear/for_api.rb +5 -1
- data/lib/fear/future.rb +157 -82
- data/lib/fear/future_api.rb +17 -4
- data/lib/fear/left.rb +3 -9
- data/lib/fear/left_pattern_match.rb +2 -0
- data/lib/fear/none.rb +28 -10
- data/lib/fear/none_pattern_match.rb +2 -0
- data/lib/fear/option.rb +30 -2
- data/lib/fear/option_api.rb +4 -0
- data/lib/fear/option_pattern_match.rb +8 -3
- data/lib/fear/partial_function/and_then.rb +4 -2
- data/lib/fear/partial_function/any.rb +2 -0
- data/lib/fear/partial_function/combined.rb +3 -1
- data/lib/fear/partial_function/empty.rb +6 -0
- data/lib/fear/partial_function/guard/and.rb +2 -0
- data/lib/fear/partial_function/guard/and3.rb +2 -0
- data/lib/fear/partial_function/guard/or.rb +2 -0
- data/lib/fear/partial_function/guard.rb +8 -6
- data/lib/fear/partial_function/lifted.rb +2 -0
- data/lib/fear/partial_function/or_else.rb +5 -1
- data/lib/fear/partial_function.rb +18 -9
- data/lib/fear/partial_function_class.rb +3 -1
- data/lib/fear/pattern_match.rb +3 -11
- data/lib/fear/pattern_matching_api.rb +6 -28
- data/lib/fear/promise.rb +7 -5
- data/lib/fear/right.rb +3 -9
- data/lib/fear/right_biased.rb +5 -3
- data/lib/fear/right_pattern_match.rb +4 -0
- data/lib/fear/some.rb +35 -8
- data/lib/fear/some_pattern_match.rb +2 -0
- data/lib/fear/struct.rb +237 -0
- data/lib/fear/success.rb +7 -8
- data/lib/fear/success_pattern_match.rb +4 -0
- data/lib/fear/try.rb +8 -2
- data/lib/fear/try_api.rb +4 -0
- data/lib/fear/try_pattern_match.rb +9 -5
- data/lib/fear/unit.rb +6 -2
- data/lib/fear/utils.rb +14 -2
- data/lib/fear/version.rb +4 -1
- data/lib/fear.rb +26 -44
- data/spec/dry/types/fear/option/constrained_spec.rb +22 -0
- data/spec/dry/types/fear/option/core_spec.rb +77 -0
- data/spec/dry/types/fear/option/default_spec.rb +21 -0
- data/spec/dry/types/fear/option/hash_spec.rb +58 -0
- data/spec/dry/types/fear/option/option_spec.rb +97 -0
- data/spec/fear/awaitable_spec.rb +19 -0
- data/spec/fear/done_spec.rb +7 -5
- data/spec/fear/either/mixin_spec.rb +4 -2
- data/spec/fear/either_pattern_match_spec.rb +10 -8
- data/spec/fear/either_pattern_matching_spec.rb +28 -0
- data/spec/fear/either_spec.rb +26 -0
- data/spec/fear/failure_spec.rb +57 -70
- data/spec/fear/for/mixin_spec.rb +15 -0
- data/spec/fear/for_spec.rb +19 -17
- data/spec/fear/future_spec.rb +477 -237
- data/spec/fear/guard_spec.rb +136 -24
- data/spec/fear/left_spec.rb +57 -70
- data/spec/fear/none_spec.rb +39 -43
- data/spec/fear/option/mixin_spec.rb +9 -7
- data/spec/fear/option_pattern_match_spec.rb +10 -8
- data/spec/fear/option_pattern_matching_spec.rb +34 -0
- data/spec/fear/option_spec.rb +142 -0
- data/spec/fear/partial_function/any_spec.rb +25 -0
- data/spec/fear/partial_function/empty_spec.rb +12 -10
- data/spec/fear/partial_function_and_then_spec.rb +39 -37
- data/spec/fear/partial_function_composition_spec.rb +46 -44
- data/spec/fear/partial_function_or_else_spec.rb +92 -90
- data/spec/fear/partial_function_spec.rb +91 -61
- data/spec/fear/pattern_match_spec.rb +19 -51
- data/spec/fear/pattern_matching_api_spec.rb +31 -0
- data/spec/fear/promise_spec.rb +23 -23
- data/spec/fear/right_biased/left.rb +28 -26
- data/spec/fear/right_biased/right.rb +51 -49
- data/spec/fear/right_spec.rb +48 -68
- data/spec/fear/some_spec.rb +30 -40
- data/spec/fear/success_spec.rb +40 -60
- data/spec/fear/try/mixin_spec.rb +19 -3
- data/spec/fear/try_api_spec.rb +23 -0
- data/spec/fear/try_pattern_match_spec.rb +10 -8
- data/spec/fear/try_pattern_matching_spec.rb +34 -0
- data/spec/fear/utils_spec.rb +16 -14
- data/spec/spec_helper.rb +13 -7
- data/spec/struct_pattern_matching_spec.rb +36 -0
- data/spec/struct_spec.rb +194 -0
- data/spec/support/dry_types.rb +6 -0
- metadata +128 -87
- data/.travis.yml +0 -13
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +0 -8
- data/lib/fear/extractor/any_matcher.rb +0 -15
- data/lib/fear/extractor/array_head_matcher.rb +0 -34
- data/lib/fear/extractor/array_matcher.rb +0 -38
- data/lib/fear/extractor/array_splat_matcher.rb +0 -14
- data/lib/fear/extractor/empty_list_matcher.rb +0 -18
- data/lib/fear/extractor/extractor_matcher.rb +0 -42
- data/lib/fear/extractor/grammar.rb +0 -201
- data/lib/fear/extractor/grammar.treetop +0 -129
- data/lib/fear/extractor/identifier_matcher.rb +0 -16
- data/lib/fear/extractor/matcher/and.rb +0 -36
- data/lib/fear/extractor/matcher.rb +0 -54
- data/lib/fear/extractor/named_array_splat_matcher.rb +0 -15
- data/lib/fear/extractor/pattern.rb +0 -55
- data/lib/fear/extractor/typed_identifier_matcher.rb +0 -24
- data/lib/fear/extractor/value_matcher.rb +0 -17
- data/lib/fear/extractor.rb +0 -108
- data/lib/fear/extractor_api.rb +0 -33
- data/spec/fear/extractor/array_matcher_spec.rb +0 -228
- data/spec/fear/extractor/extractor_matcher_spec.rb +0 -151
- data/spec/fear/extractor/grammar_array_spec.rb +0 -23
- data/spec/fear/extractor/identified_matcher_spec.rb +0 -47
- data/spec/fear/extractor/identifier_matcher_spec.rb +0 -66
- data/spec/fear/extractor/pattern_spec.rb +0 -32
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +0 -62
- data/spec/fear/extractor/value_matcher_number_spec.rb +0 -77
- data/spec/fear/extractor/value_matcher_string_spec.rb +0 -86
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +0 -69
- data/spec/fear/extractor_api_spec.rb +0 -113
- data/spec/fear/extractor_spec.rb +0 -59
data/Rakefile
CHANGED
@@ -1,28 +1,30 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "benchmark/ips"
|
5
|
+
require_relative "lib/fear"
|
4
6
|
|
5
7
|
namespace :perf do
|
6
8
|
# Contains benchmarking against Dry-rb
|
7
9
|
namespace :dry do
|
8
10
|
task :some_fmap_vs_fear_some_map do
|
9
|
-
require
|
11
|
+
require "dry/monads/maybe"
|
10
12
|
|
11
13
|
dry = Dry::Monads::Some.new(42)
|
12
14
|
fear = Fear.some(42)
|
13
15
|
|
14
16
|
Benchmark.ips do |x|
|
15
|
-
x.report(
|
17
|
+
x.report("Dry") { dry.fmap(&:itself) }
|
16
18
|
|
17
|
-
x.report(
|
19
|
+
x.report("Fear") { fear.map(&:itself) }
|
18
20
|
|
19
21
|
x.compare!
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
25
|
task :do_vs_fear_for do
|
24
|
-
require
|
25
|
-
require
|
26
|
+
require "dry/monads/maybe"
|
27
|
+
require "dry/monads/do"
|
26
28
|
|
27
29
|
class Operation
|
28
30
|
include Dry::Monads::Maybe::Mixin
|
@@ -42,9 +44,9 @@ namespace :perf do
|
|
42
44
|
op = Operation.new
|
43
45
|
|
44
46
|
Benchmark.ips do |x|
|
45
|
-
x.report(
|
47
|
+
x.report("Dry") { op.() }
|
46
48
|
|
47
|
-
x.report(
|
49
|
+
x.report("Fear") do |_n|
|
48
50
|
Fear.for(Fear.some(1), Fear.some(2)) do |one, two|
|
49
51
|
one + two
|
50
52
|
end
|
@@ -58,21 +60,21 @@ namespace :perf do
|
|
58
60
|
# Contains internal benchmarking to if optimization works
|
59
61
|
namespace :fear do
|
60
62
|
task :fear_pattern_extracting_with_vs_without_cache do
|
61
|
-
some = Fear.some([:err,
|
63
|
+
some = Fear.some([:err, "not found"])
|
62
64
|
|
63
65
|
class WOCache < Fear::Extractor::Pattern
|
64
66
|
def initialize(pattern)
|
65
67
|
@matcher = compile_pattern_without_cache(pattern)
|
66
68
|
end
|
67
69
|
end
|
68
|
-
pattern =
|
70
|
+
pattern = "Fear::Some([:err, code])"
|
69
71
|
|
70
72
|
Benchmark.ips do |x|
|
71
|
-
x.report(
|
73
|
+
x.report("With cache") do |_n|
|
72
74
|
Fear::Extractor::Pattern.new(pattern).extracted_arguments(some)
|
73
75
|
end
|
74
76
|
|
75
|
-
x.report(
|
77
|
+
x.report("Without cache") do |_n|
|
76
78
|
WOCache.new(pattern).extracted_arguments(some)
|
77
79
|
end
|
78
80
|
|
@@ -85,11 +87,11 @@ namespace :perf do
|
|
85
87
|
condition = Integer
|
86
88
|
|
87
89
|
Benchmark.ips do |x|
|
88
|
-
x.report(
|
90
|
+
x.report("Guard.new") do |n|
|
89
91
|
Fear::PartialFunction::Guard.new(condition) === n
|
90
92
|
end
|
91
93
|
|
92
|
-
x.report(
|
94
|
+
x.report("Guard.and1") do |n|
|
93
95
|
Fear::PartialFunction::Guard.and1(condition) === n
|
94
96
|
end
|
95
97
|
|
@@ -105,11 +107,11 @@ namespace :perf do
|
|
105
107
|
and_and = Fear::PartialFunction::Guard.new(first).and(Fear::PartialFunction::Guard.new(second))
|
106
108
|
|
107
109
|
Benchmark.ips do |x|
|
108
|
-
x.report(
|
110
|
+
x.report("and2") do |n|
|
109
111
|
and2 === n
|
110
112
|
end
|
111
113
|
|
112
|
-
x.report(
|
114
|
+
x.report("Guard#and") do |n|
|
113
115
|
and_and === n
|
114
116
|
end
|
115
117
|
|
@@ -120,7 +122,7 @@ namespace :perf do
|
|
120
122
|
task :and3_vs_and_and do
|
121
123
|
first = Integer
|
122
124
|
second = ->(x) { x > 2 }
|
123
|
-
third = ->(x) {
|
125
|
+
third = ->(x) { x < 10 }
|
124
126
|
|
125
127
|
and3 = Fear::PartialFunction::Guard.and3(first, second, third)
|
126
128
|
|
@@ -129,11 +131,11 @@ namespace :perf do
|
|
129
131
|
.and(Fear::PartialFunction::Guard.new(third))
|
130
132
|
|
131
133
|
Benchmark.ips do |x|
|
132
|
-
x.report(
|
134
|
+
x.report("Guard.and3") do |n|
|
133
135
|
and3 === n
|
134
136
|
end
|
135
137
|
|
136
|
-
x.report(
|
138
|
+
x.report("Guard#and") do |n|
|
137
139
|
and_and_and === n
|
138
140
|
end
|
139
141
|
|
@@ -149,15 +151,15 @@ namespace :perf do
|
|
149
151
|
end
|
150
152
|
|
151
153
|
Benchmark.ips do |x|
|
152
|
-
x.report(
|
154
|
+
x.report("construction") do
|
153
155
|
Fear::PatternMatch.new do |m|
|
154
156
|
m.case(Integer) { |y| y * 2 }
|
155
157
|
m.case(String) { |y| y.to_i(10) * 2 }
|
156
158
|
end
|
157
159
|
end
|
158
160
|
|
159
|
-
x.report(
|
160
|
-
matcher.
|
161
|
+
x.report("execution") do
|
162
|
+
matcher.(42)
|
161
163
|
end
|
162
164
|
|
163
165
|
x.compare!
|
@@ -166,23 +168,29 @@ namespace :perf do
|
|
166
168
|
end
|
167
169
|
|
168
170
|
namespace :pattern_matching do
|
169
|
-
require
|
170
|
-
require
|
171
|
+
require "qo"
|
172
|
+
require "dry/matcher"
|
171
173
|
|
172
|
-
task :
|
173
|
-
|
174
|
-
user = User.new(42, 'Jane')
|
174
|
+
task :option_match_vs_native_pattern_match do
|
175
|
+
some = Fear.some(42)
|
175
176
|
|
176
177
|
Benchmark.ips do |x|
|
177
|
-
x.report(
|
178
|
-
|
179
|
-
|
178
|
+
x.report("case ... in ...") do
|
179
|
+
case some
|
180
|
+
in Fear::Some(41 => x)
|
181
|
+
x
|
182
|
+
in Fear::Some(42 => x)
|
183
|
+
x
|
184
|
+
in Fear::Some(43 => x)
|
185
|
+
x
|
180
186
|
end
|
181
187
|
end
|
182
188
|
|
183
|
-
x.report(
|
184
|
-
|
185
|
-
m.
|
189
|
+
x.report("Option.match") do
|
190
|
+
some.match do |m|
|
191
|
+
m.some(41, &:itself)
|
192
|
+
m.some(42, &:itself)
|
193
|
+
m.some(45, &:itself)
|
186
194
|
end
|
187
195
|
end
|
188
196
|
|
@@ -198,25 +206,24 @@ namespace :perf do
|
|
198
206
|
end
|
199
207
|
end
|
200
208
|
|
201
|
-
SuccessBranch = Qo.create_branch(name:
|
202
|
-
FailureBranch = Qo.create_branch(name:
|
209
|
+
SuccessBranch = Qo.create_branch(name: "success", precondition: Fear::Success, extractor: :get)
|
210
|
+
FailureBranch = Qo.create_branch(name: "failure", precondition: Fear::Failure, extractor: :exception)
|
203
211
|
|
204
212
|
PatternMatch = Qo.create_pattern_match(
|
205
|
-
branches: [SuccessBranch,
|
206
|
-
FailureBranch],
|
213
|
+
branches: [SuccessBranch, FailureBranch],
|
207
214
|
).prepend(ExhaustivePatternMatch)
|
208
215
|
|
209
216
|
Fear::Success.include(PatternMatch.mixin(as: :qo_match))
|
210
217
|
|
211
218
|
success_case = Dry::Matcher::Case.new(
|
212
|
-
match:
|
219
|
+
match: ->(try, *pattern) {
|
213
220
|
try.is_a?(Fear::Success) && pattern.all? { |p| p === try.get }
|
214
221
|
},
|
215
222
|
resolve: ->(try) { try.get },
|
216
223
|
)
|
217
224
|
|
218
225
|
failure_case = Dry::Matcher::Case.new(
|
219
|
-
match:
|
226
|
+
match: ->(try, *pattern) {
|
220
227
|
try.is_a?(Fear::Failure) && pattern.all? { |p| p === try.exception }
|
221
228
|
},
|
222
229
|
resolve: ->(value) { value.exception },
|
@@ -228,27 +235,27 @@ namespace :perf do
|
|
228
235
|
success = Fear::Success.new(4)
|
229
236
|
|
230
237
|
Benchmark.ips do |x|
|
231
|
-
x.report(
|
238
|
+
x.report("Qo") do
|
232
239
|
success.qo_match do |m|
|
233
240
|
m.failure(&:itself)
|
234
241
|
m.success(Integer, ->(y) { y % 5 == 0 }, &:itself)
|
235
|
-
m.success {
|
242
|
+
m.success { "else" }
|
236
243
|
end
|
237
244
|
end
|
238
245
|
|
239
|
-
x.report(
|
246
|
+
x.report("Fear") do
|
240
247
|
success.match do |m|
|
241
248
|
m.failure(&:itself)
|
242
249
|
m.success(Integer, ->(y) { y % 5 == 0 }, &:itself)
|
243
|
-
m.success {
|
250
|
+
m.success { "else" }
|
244
251
|
end
|
245
252
|
end
|
246
253
|
|
247
|
-
x.report(
|
248
|
-
matcher.
|
254
|
+
x.report("Dr::Matcher") do
|
255
|
+
matcher.(success) do |m|
|
249
256
|
m.failure(&:itself)
|
250
257
|
m.success(Integer, ->(y) { y % 5 == 0 }, &:itself)
|
251
|
-
m.success {
|
258
|
+
m.success { "else" }
|
252
259
|
end
|
253
260
|
end
|
254
261
|
|
@@ -264,8 +271,8 @@ namespace :perf do
|
|
264
271
|
end
|
265
272
|
end
|
266
273
|
|
267
|
-
SuccessBranch = Qo.create_branch(name:
|
268
|
-
FailureBranch = Qo.create_branch(name:
|
274
|
+
SuccessBranch = Qo.create_branch(name: "success", precondition: Fear::Success, extractor: :get)
|
275
|
+
FailureBranch = Qo.create_branch(name: "failure", precondition: Fear::Failure, extractor: :exception)
|
269
276
|
|
270
277
|
QoPatternMatch = Qo.create_pattern_match(
|
271
278
|
branches: [SuccessBranch, FailureBranch],
|
@@ -278,22 +285,22 @@ namespace :perf do
|
|
278
285
|
qo_matcher = QoPatternMatch.new do |m|
|
279
286
|
m.success(1, &:itself)
|
280
287
|
m.success(4, &:itself)
|
281
|
-
m.failure {
|
288
|
+
m.failure { "failure" }
|
282
289
|
end
|
283
290
|
|
284
291
|
fear_matcher = Fear::TryPatternMatch.new do |m|
|
285
292
|
m.success(1, &:itself)
|
286
293
|
m.success(4, &:itself)
|
287
|
-
m.failure {
|
294
|
+
m.failure { "failure" }
|
288
295
|
end
|
289
296
|
|
290
297
|
Benchmark.ips do |x|
|
291
|
-
x.report(
|
292
|
-
qo_matcher.
|
298
|
+
x.report("Qo") do
|
299
|
+
qo_matcher.(success)
|
293
300
|
end
|
294
301
|
|
295
|
-
x.report(
|
296
|
-
fear_matcher.
|
302
|
+
x.report("Fear") do
|
303
|
+
fear_matcher.(success)
|
297
304
|
end
|
298
305
|
|
299
306
|
x.compare!
|
@@ -305,33 +312,33 @@ namespace :perf do
|
|
305
312
|
if n <= 1
|
306
313
|
1
|
307
314
|
else
|
308
|
-
n * factorial_proc.
|
315
|
+
n * factorial_proc.(n - 1)
|
309
316
|
end
|
310
317
|
end
|
311
318
|
|
312
319
|
factorial_pm = Fear.matcher do |m|
|
313
320
|
m.case(1, &:itself)
|
314
321
|
m.case(0, &:itself)
|
315
|
-
m.else { |n| n * factorial_pm.
|
322
|
+
m.else { |n| n * factorial_pm.(n - 1) }
|
316
323
|
end
|
317
324
|
|
318
325
|
factorial_qo = Qo.match do |m|
|
319
326
|
m.when(1, &:itself)
|
320
327
|
m.when(0, &:itself)
|
321
|
-
m.else { |n| n * factorial_qo.
|
328
|
+
m.else { |n| n * factorial_qo.(n - 1) }
|
322
329
|
end
|
323
330
|
|
324
331
|
Benchmark.ips do |x|
|
325
|
-
x.report(
|
326
|
-
factorial_proc.
|
332
|
+
x.report("Proc") do
|
333
|
+
factorial_proc.(100)
|
327
334
|
end
|
328
335
|
|
329
|
-
x.report(
|
330
|
-
factorial_pm.
|
336
|
+
x.report("Fear") do
|
337
|
+
factorial_pm.(100)
|
331
338
|
end
|
332
339
|
|
333
|
-
x.report(
|
334
|
-
factorial_qo.
|
340
|
+
x.report("Qo") do
|
341
|
+
factorial_qo.(100)
|
335
342
|
end
|
336
343
|
|
337
344
|
x.compare!
|
@@ -1,15 +1,17 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear"
|
2
4
|
|
3
5
|
User = Struct.new(:id, :name, :admin)
|
4
6
|
|
5
|
-
matcher =
|
6
|
-
|
7
|
+
matcher = proc do |value|
|
8
|
+
case value
|
9
|
+
in User(admin: true, name:)
|
7
10
|
puts "Hi #{name}, you are welcome"
|
8
|
-
|
9
|
-
|
10
|
-
puts 'Only admins allowed here'
|
11
|
+
in User(admin: false)
|
12
|
+
puts "Only admins are allowed here"
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
14
|
-
matcher.
|
15
|
-
matcher.
|
16
|
+
matcher.(User.new(1, "Jane", true))
|
17
|
+
matcher.(User.new(1, "John", false))
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear"
|
2
4
|
|
3
5
|
# @example Usage
|
4
6
|
# set = BinaryTreeSet.new
|
@@ -10,8 +12,11 @@ require 'fear'
|
|
10
12
|
#
|
11
13
|
class BinaryTreeSet
|
12
14
|
Position = Module.new
|
15
|
+
private_constant(:Position)
|
13
16
|
Right = Module.new.include(Position)
|
17
|
+
private_constant(:Right)
|
14
18
|
Left = Module.new.include(Position)
|
19
|
+
private_constant(:Left)
|
15
20
|
|
16
21
|
def initialize(elem = 0, removed: true)
|
17
22
|
@elem = elem
|
@@ -87,7 +92,7 @@ class BinaryTreeSet
|
|
87
92
|
# @param position [Position]
|
88
93
|
# @return [Fear::Option<BinaryTreeSet>]
|
89
94
|
private def leaf(position)
|
90
|
-
if subtrees.
|
95
|
+
if subtrees.has_key?(position)
|
91
96
|
Fear.some(subtrees[position])
|
92
97
|
else
|
93
98
|
Fear.none
|
@@ -1,54 +1,60 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear"
|
2
4
|
|
3
5
|
class ToWords
|
6
|
+
NUMBERS = {
|
7
|
+
0 => "zero",
|
8
|
+
1 => "one",
|
9
|
+
2 => "two",
|
10
|
+
3 => "three",
|
11
|
+
4 => "four",
|
12
|
+
5 => "five",
|
13
|
+
6 => "six",
|
14
|
+
7 => "seven",
|
15
|
+
8 => "eight",
|
16
|
+
9 => "nine",
|
17
|
+
10 => "ten",
|
18
|
+
11 => "eleven",
|
19
|
+
12 => "twelve",
|
20
|
+
13 => "thirteen",
|
21
|
+
14 => "fourteen",
|
22
|
+
15 => "fifteen",
|
23
|
+
16 => "sixteen",
|
24
|
+
17 => "seventeen",
|
25
|
+
18 => "eighteen",
|
26
|
+
19 => "nineteen",
|
27
|
+
20 => "twenty",
|
28
|
+
30 => "thirty",
|
29
|
+
40 => "forty",
|
30
|
+
50 => "fifty",
|
31
|
+
60 => "sixty",
|
32
|
+
70 => "seventy",
|
33
|
+
80 => "eighty",
|
34
|
+
90 => "ninety",
|
35
|
+
}.freeze
|
36
|
+
private_constant :NUMBERS
|
37
|
+
|
4
38
|
CONVERTER = Fear.matcher do |m|
|
5
|
-
|
6
|
-
0 => 'zero',
|
7
|
-
1 => 'one',
|
8
|
-
2 => 'two',
|
9
|
-
3 => 'three',
|
10
|
-
4 => 'four',
|
11
|
-
5 => 'five',
|
12
|
-
6 => 'six',
|
13
|
-
7 => 'seven',
|
14
|
-
8 => 'eight',
|
15
|
-
9 => 'nine',
|
16
|
-
10 => 'ten',
|
17
|
-
11 => 'eleven',
|
18
|
-
12 => 'twelve',
|
19
|
-
13 => 'thirteen',
|
20
|
-
14 => 'fourteen',
|
21
|
-
15 => 'fifteen',
|
22
|
-
16 => 'sixteen',
|
23
|
-
17 => 'seventeen',
|
24
|
-
18 => 'eighteen',
|
25
|
-
19 => 'nineteen',
|
26
|
-
20 => 'twenty',
|
27
|
-
30 => 'thirty',
|
28
|
-
40 => 'forty',
|
29
|
-
50 => 'fifty',
|
30
|
-
60 => 'sixty',
|
31
|
-
70 => 'seventy',
|
32
|
-
80 => 'eighty',
|
33
|
-
90 => 'ninety',
|
34
|
-
}.each_pair do |number, in_words|
|
39
|
+
NUMBERS.each_pair do |number, in_words|
|
35
40
|
m.case(number) { in_words }
|
36
41
|
end
|
37
|
-
m.case(->(n) { n < 0 }) { |n| "minus #{CONVERTER.
|
38
|
-
m.case(->(n) { n < 100 }) { |n| "#{CONVERTER.
|
39
|
-
m.case(->(n) { n < 200 }) { |n| "one hundred #{CONVERTER.
|
40
|
-
m.case(->(n) { n < 1_000 }) { |n| "#{CONVERTER.
|
41
|
-
m.case(->(n) { n < 2_000 }) { |n| "one thousand #{CONVERTER.
|
42
|
-
m.case(->(n) { n < 1_000_000 }) { |n| "#{CONVERTER.
|
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)}" }
|
43
48
|
m.else { |n| raise "#{n} too big " }
|
44
49
|
end
|
50
|
+
private_constant :CONVERTER
|
45
51
|
|
46
52
|
def self.call(number)
|
47
|
-
Fear.case(Integer, &:itself).and_then(CONVERTER).
|
53
|
+
Fear.case(Integer, &:itself).and_then(CONVERTER).(number)
|
48
54
|
end
|
49
55
|
end
|
50
56
|
|
51
|
-
ToWords.
|
52
|
-
ToWords.
|
53
|
-
ToWords.
|
54
|
-
ToWords.
|
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'
|
data/fear.gemspec
CHANGED
@@ -1,41 +1,40 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
2
4
|
|
3
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
6
|
|
5
|
-
require
|
7
|
+
require "fear/version"
|
6
8
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name
|
8
|
-
spec.version
|
9
|
-
spec.authors
|
10
|
-
spec.email
|
11
|
-
spec.summary
|
12
|
-
spec.description
|
13
|
-
spec.homepage
|
14
|
-
spec.license
|
15
|
-
|
16
|
-
spec.files = `git ls-files -z`.split("\x0")
|
17
|
-
spec.executables = spec.files.grep(%r{^bin\/}) { |f| File.basename(f) }
|
18
|
-
spec.test_files = spec.files.grep(%r{^spec\/})
|
19
|
-
spec.require_paths = ['lib']
|
20
|
-
|
21
|
-
spec.post_install_message = <<-MSG
|
22
|
-
Fear v0.11.0 introduces backwards-incompatible changes.
|
23
|
-
Please see https://github.com/bolshakov/fear/blob/master/CHANGELOG.md#0110 for details.
|
24
|
-
Successfully installed fear-#{Fear::VERSION}
|
25
|
-
MSG
|
9
|
+
spec.name = "fear"
|
10
|
+
spec.version = Fear::VERSION
|
11
|
+
spec.authors = ["Tema Bolshakov"]
|
12
|
+
spec.email = ["abolshakov@spbtv.com"]
|
13
|
+
spec.summary = "%q{Ruby port of some Scala's monads.}"
|
14
|
+
spec.description = "Ruby port of some Scala's monads."
|
15
|
+
spec.homepage = "https://github.com/bolshakov/fear"
|
16
|
+
spec.license = "MIT"
|
26
17
|
|
27
|
-
spec.
|
28
|
-
spec.
|
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\/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
|
29
23
|
|
30
|
-
spec.add_development_dependency
|
31
|
-
spec.add_development_dependency
|
32
|
-
spec.add_development_dependency
|
33
|
-
spec.add_development_dependency
|
34
|
-
spec.add_development_dependency
|
35
|
-
spec.add_development_dependency
|
36
|
-
spec.add_development_dependency
|
37
|
-
spec.add_development_dependency
|
38
|
-
spec.add_development_dependency
|
39
|
-
spec.add_development_dependency
|
40
|
-
spec.add_development_dependency
|
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"
|
41
40
|
end
|