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.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +27 -0
  3. data/.github/workflows/rubocop.yml +39 -0
  4. data/.github/workflows/spec.yml +42 -0
  5. data/.rubocop.yml +4 -60
  6. data/.simplecov +17 -0
  7. data/CHANGELOG.md +29 -1
  8. data/Gemfile +5 -5
  9. data/Gemfile.lock +86 -50
  10. data/README.md +240 -209
  11. data/Rakefile +72 -65
  12. data/examples/pattern_extracting.rb +10 -8
  13. data/examples/pattern_matching_binary_tree_set.rb +7 -2
  14. data/examples/pattern_matching_number_in_words.rb +48 -42
  15. data/fear.gemspec +33 -34
  16. data/lib/dry/types/fear/option.rb +125 -0
  17. data/lib/dry/types/fear.rb +8 -0
  18. data/lib/fear/await.rb +33 -0
  19. data/lib/fear/awaitable.rb +28 -0
  20. data/lib/fear/either.rb +15 -4
  21. data/lib/fear/either_api.rb +4 -0
  22. data/lib/fear/either_pattern_match.rb +9 -5
  23. data/lib/fear/empty_partial_function.rb +3 -1
  24. data/lib/fear/failure.rb +7 -7
  25. data/lib/fear/failure_pattern_match.rb +4 -0
  26. data/lib/fear/for.rb +4 -2
  27. data/lib/fear/for_api.rb +5 -1
  28. data/lib/fear/future.rb +157 -82
  29. data/lib/fear/future_api.rb +17 -4
  30. data/lib/fear/left.rb +3 -9
  31. data/lib/fear/left_pattern_match.rb +2 -0
  32. data/lib/fear/none.rb +28 -10
  33. data/lib/fear/none_pattern_match.rb +2 -0
  34. data/lib/fear/option.rb +30 -2
  35. data/lib/fear/option_api.rb +4 -0
  36. data/lib/fear/option_pattern_match.rb +8 -3
  37. data/lib/fear/partial_function/and_then.rb +4 -2
  38. data/lib/fear/partial_function/any.rb +2 -0
  39. data/lib/fear/partial_function/combined.rb +3 -1
  40. data/lib/fear/partial_function/empty.rb +6 -0
  41. data/lib/fear/partial_function/guard/and.rb +2 -0
  42. data/lib/fear/partial_function/guard/and3.rb +2 -0
  43. data/lib/fear/partial_function/guard/or.rb +2 -0
  44. data/lib/fear/partial_function/guard.rb +8 -6
  45. data/lib/fear/partial_function/lifted.rb +2 -0
  46. data/lib/fear/partial_function/or_else.rb +5 -1
  47. data/lib/fear/partial_function.rb +18 -9
  48. data/lib/fear/partial_function_class.rb +3 -1
  49. data/lib/fear/pattern_match.rb +3 -11
  50. data/lib/fear/pattern_matching_api.rb +6 -28
  51. data/lib/fear/promise.rb +7 -5
  52. data/lib/fear/right.rb +3 -9
  53. data/lib/fear/right_biased.rb +5 -3
  54. data/lib/fear/right_pattern_match.rb +4 -0
  55. data/lib/fear/some.rb +35 -8
  56. data/lib/fear/some_pattern_match.rb +2 -0
  57. data/lib/fear/struct.rb +237 -0
  58. data/lib/fear/success.rb +7 -8
  59. data/lib/fear/success_pattern_match.rb +4 -0
  60. data/lib/fear/try.rb +8 -2
  61. data/lib/fear/try_api.rb +4 -0
  62. data/lib/fear/try_pattern_match.rb +9 -5
  63. data/lib/fear/unit.rb +6 -2
  64. data/lib/fear/utils.rb +14 -2
  65. data/lib/fear/version.rb +4 -1
  66. data/lib/fear.rb +26 -44
  67. data/spec/dry/types/fear/option/constrained_spec.rb +22 -0
  68. data/spec/dry/types/fear/option/core_spec.rb +77 -0
  69. data/spec/dry/types/fear/option/default_spec.rb +21 -0
  70. data/spec/dry/types/fear/option/hash_spec.rb +58 -0
  71. data/spec/dry/types/fear/option/option_spec.rb +97 -0
  72. data/spec/fear/awaitable_spec.rb +19 -0
  73. data/spec/fear/done_spec.rb +7 -5
  74. data/spec/fear/either/mixin_spec.rb +4 -2
  75. data/spec/fear/either_pattern_match_spec.rb +10 -8
  76. data/spec/fear/either_pattern_matching_spec.rb +28 -0
  77. data/spec/fear/either_spec.rb +26 -0
  78. data/spec/fear/failure_spec.rb +57 -70
  79. data/spec/fear/for/mixin_spec.rb +15 -0
  80. data/spec/fear/for_spec.rb +19 -17
  81. data/spec/fear/future_spec.rb +477 -237
  82. data/spec/fear/guard_spec.rb +136 -24
  83. data/spec/fear/left_spec.rb +57 -70
  84. data/spec/fear/none_spec.rb +39 -43
  85. data/spec/fear/option/mixin_spec.rb +9 -7
  86. data/spec/fear/option_pattern_match_spec.rb +10 -8
  87. data/spec/fear/option_pattern_matching_spec.rb +34 -0
  88. data/spec/fear/option_spec.rb +142 -0
  89. data/spec/fear/partial_function/any_spec.rb +25 -0
  90. data/spec/fear/partial_function/empty_spec.rb +12 -10
  91. data/spec/fear/partial_function_and_then_spec.rb +39 -37
  92. data/spec/fear/partial_function_composition_spec.rb +46 -44
  93. data/spec/fear/partial_function_or_else_spec.rb +92 -90
  94. data/spec/fear/partial_function_spec.rb +91 -61
  95. data/spec/fear/pattern_match_spec.rb +19 -51
  96. data/spec/fear/pattern_matching_api_spec.rb +31 -0
  97. data/spec/fear/promise_spec.rb +23 -23
  98. data/spec/fear/right_biased/left.rb +28 -26
  99. data/spec/fear/right_biased/right.rb +51 -49
  100. data/spec/fear/right_spec.rb +48 -68
  101. data/spec/fear/some_spec.rb +30 -40
  102. data/spec/fear/success_spec.rb +40 -60
  103. data/spec/fear/try/mixin_spec.rb +19 -3
  104. data/spec/fear/try_api_spec.rb +23 -0
  105. data/spec/fear/try_pattern_match_spec.rb +10 -8
  106. data/spec/fear/try_pattern_matching_spec.rb +34 -0
  107. data/spec/fear/utils_spec.rb +16 -14
  108. data/spec/spec_helper.rb +13 -7
  109. data/spec/struct_pattern_matching_spec.rb +36 -0
  110. data/spec/struct_spec.rb +194 -0
  111. data/spec/support/dry_types.rb +6 -0
  112. metadata +128 -87
  113. data/.travis.yml +0 -13
  114. data/lib/fear/extractor/anonymous_array_splat_matcher.rb +0 -8
  115. data/lib/fear/extractor/any_matcher.rb +0 -15
  116. data/lib/fear/extractor/array_head_matcher.rb +0 -34
  117. data/lib/fear/extractor/array_matcher.rb +0 -38
  118. data/lib/fear/extractor/array_splat_matcher.rb +0 -14
  119. data/lib/fear/extractor/empty_list_matcher.rb +0 -18
  120. data/lib/fear/extractor/extractor_matcher.rb +0 -42
  121. data/lib/fear/extractor/grammar.rb +0 -201
  122. data/lib/fear/extractor/grammar.treetop +0 -129
  123. data/lib/fear/extractor/identifier_matcher.rb +0 -16
  124. data/lib/fear/extractor/matcher/and.rb +0 -36
  125. data/lib/fear/extractor/matcher.rb +0 -54
  126. data/lib/fear/extractor/named_array_splat_matcher.rb +0 -15
  127. data/lib/fear/extractor/pattern.rb +0 -55
  128. data/lib/fear/extractor/typed_identifier_matcher.rb +0 -24
  129. data/lib/fear/extractor/value_matcher.rb +0 -17
  130. data/lib/fear/extractor.rb +0 -108
  131. data/lib/fear/extractor_api.rb +0 -33
  132. data/spec/fear/extractor/array_matcher_spec.rb +0 -228
  133. data/spec/fear/extractor/extractor_matcher_spec.rb +0 -151
  134. data/spec/fear/extractor/grammar_array_spec.rb +0 -23
  135. data/spec/fear/extractor/identified_matcher_spec.rb +0 -47
  136. data/spec/fear/extractor/identifier_matcher_spec.rb +0 -66
  137. data/spec/fear/extractor/pattern_spec.rb +0 -32
  138. data/spec/fear/extractor/typed_identifier_matcher_spec.rb +0 -62
  139. data/spec/fear/extractor/value_matcher_number_spec.rb +0 -77
  140. data/spec/fear/extractor/value_matcher_string_spec.rb +0 -86
  141. data/spec/fear/extractor/value_matcher_symbol_spec.rb +0 -69
  142. data/spec/fear/extractor_api_spec.rb +0 -113
  143. data/spec/fear/extractor_spec.rb +0 -59
data/Rakefile CHANGED
@@ -1,28 +1,30 @@
1
- require 'bundler/gem_tasks'
2
- require 'benchmark/ips'
3
- require_relative 'lib/fear'
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 'dry/monads/maybe'
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('Dry') { dry.fmap(&:itself) }
17
+ x.report("Dry") { dry.fmap(&:itself) }
16
18
 
17
- x.report('Fear') { fear.map(&:itself) }
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 'dry/monads/maybe'
25
- require 'dry/monads/do'
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('Dry') { op.call }
47
+ x.report("Dry") { op.() }
46
48
 
47
- x.report('Fear') do |_n|
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, 'not found'])
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 = 'Fear::Some([:err, code])'
70
+ pattern = "Fear::Some([:err, code])"
69
71
 
70
72
  Benchmark.ips do |x|
71
- x.report('With cache') do |_n|
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('Without cache') do |_n|
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('Guard.new') do |n|
90
+ x.report("Guard.new") do |n|
89
91
  Fear::PartialFunction::Guard.new(condition) === n
90
92
  end
91
93
 
92
- x.report('Guard.and1') do |n|
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('and2') do |n|
110
+ x.report("and2") do |n|
109
111
  and2 === n
110
112
  end
111
113
 
112
- x.report('Guard#and') do |n|
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) { x < 10 }
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('Guard.and3') do |n|
134
+ x.report("Guard.and3") do |n|
133
135
  and3 === n
134
136
  end
135
137
 
136
- x.report('Guard#and') do |n|
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('construction') do
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('execution') do
160
- matcher.call(42)
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 'qo'
170
- require 'dry/matcher'
171
+ require "qo"
172
+ require "dry/matcher"
171
173
 
172
- task :qo_vs_fear_pattern_extraction do
173
- User = Struct.new(:id, :name)
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('Qo') do
178
- Qo.case(user, destructure: true) do |m|
179
- m.when(User) { |id, name| [id, name] }
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('Fear') do
184
- Fear.match(user) do |m|
185
- m.xcase('User(id, name)') { |id:, name:| [id, name] }
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: 'success', precondition: Fear::Success, extractor: :get)
202
- FailureBranch = Qo.create_branch(name: 'failure', precondition: Fear::Failure, extractor: :exception)
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: lambda { |try, *pattern|
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: lambda { |try, *pattern|
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('Qo') do
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 { 'else' }
242
+ m.success { "else" }
236
243
  end
237
244
  end
238
245
 
239
- x.report('Fear') do
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 { 'else' }
250
+ m.success { "else" }
244
251
  end
245
252
  end
246
253
 
247
- x.report('Dr::Matcher') do
248
- matcher.call(success) do |m|
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 { 'else' }
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: 'success', precondition: Fear::Success, extractor: :get)
268
- FailureBranch = Qo.create_branch(name: 'failure', precondition: Fear::Failure, extractor: :exception)
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 { '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 { 'failure' }
294
+ m.failure { "failure" }
288
295
  end
289
296
 
290
297
  Benchmark.ips do |x|
291
- x.report('Qo') do
292
- qo_matcher.call(success)
298
+ x.report("Qo") do
299
+ qo_matcher.(success)
293
300
  end
294
301
 
295
- x.report('Fear') do
296
- fear_matcher.call(success)
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.call(n - 1)
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.call(n - 1) }
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.call(n - 1) }
328
+ m.else { |n| n * factorial_qo.(n - 1) }
322
329
  end
323
330
 
324
331
  Benchmark.ips do |x|
325
- x.report('Proc') do
326
- factorial_proc.call(100)
332
+ x.report("Proc") do
333
+ factorial_proc.(100)
327
334
  end
328
335
 
329
- x.report('Fear') do
330
- factorial_pm.call(100)
336
+ x.report("Fear") do
337
+ factorial_pm.(100)
331
338
  end
332
339
 
333
- x.report('Qo') do
334
- factorial_qo.call(100)
340
+ x.report("Qo") do
341
+ factorial_qo.(100)
335
342
  end
336
343
 
337
344
  x.compare!
@@ -1,15 +1,17 @@
1
- require 'fear'
1
+ # frozen_string_literal: true
2
+
3
+ require "fear"
2
4
 
3
5
  User = Struct.new(:id, :name, :admin)
4
6
 
5
- matcher = Fear.matcher do |m|
6
- m.xcase('User(_, name, true)') do |name:|
7
+ matcher = proc do |value|
8
+ case value
9
+ in User(admin: true, name:)
7
10
  puts "Hi #{name}, you are welcome"
8
- end
9
- m.xcase('User(_, _, false)') do
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.call User.new(1, 'Jane', true)
15
- matcher.call User.new(1, 'John', false)
16
+ matcher.(User.new(1, "Jane", true))
17
+ matcher.(User.new(1, "John", false))
@@ -1,4 +1,6 @@
1
- require 'fear'
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.key?(position)
95
+ if subtrees.has_key?(position)
91
96
  Fear.some(subtrees[position])
92
97
  else
93
98
  Fear.none
@@ -1,54 +1,60 @@
1
- require 'fear'
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.call(-n)}" }
38
- m.case(->(n) { n < 100 }) { |n| "#{CONVERTER.call((n / 10) * 10)}-#{CONVERTER.call(n % 10)}" }
39
- m.case(->(n) { n < 200 }) { |n| "one hundred #{CONVERTER.call(n % 100)}" }
40
- m.case(->(n) { n < 1_000 }) { |n| "#{CONVERTER.call(n / 100)} hundreds #{CONVERTER.call(n % 100)}" }
41
- m.case(->(n) { n < 2_000 }) { |n| "one thousand #{CONVERTER.call(n % 1000)}" }
42
- m.case(->(n) { n < 1_000_000 }) { |n| "#{CONVERTER.call(n / 1_000)} thousands #{CONVERTER.call(n % 1_000)}" }
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).call(number)
53
+ Fear.case(Integer, &:itself).and_then(CONVERTER).(number)
48
54
  end
49
55
  end
50
56
 
51
- ToWords.call(99) #=> 'ninety-nine'
52
- ToWords.call(133) #=> 'one hundred thirty-three
53
- ToWords.call(777) #=> 'seven hundreds seventy-seven'
54
- ToWords.call(254_555) #=> 'two hundreds fifty-four thousands five hundreds fifty-five'
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
- lib = File.expand_path('lib', __dir__)
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 'fear/version'
7
+ require "fear/version"
6
8
  Gem::Specification.new do |spec|
7
- spec.name = 'fear'
8
- spec.version = Fear::VERSION
9
- spec.authors = ['Tema Bolshakov']
10
- spec.email = ['abolshakov@spbtv.com']
11
- spec.summary = "%q{Ruby port of some Scala's monads.}"
12
- spec.description = "Ruby port of some Scala's monads."
13
- spec.homepage = 'https://github.com/bolshakov/fear'
14
- spec.license = 'MIT'
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.add_runtime_dependency 'lru_redux'
28
- spec.add_runtime_dependency 'treetop'
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 'benchmark-ips'
31
- spec.add_development_dependency 'bundler'
32
- spec.add_development_dependency 'concurrent-ruby'
33
- spec.add_development_dependency 'dry-matcher'
34
- spec.add_development_dependency 'dry-monads'
35
- spec.add_development_dependency 'qo'
36
- spec.add_development_dependency 'rake', '~> 10.0'
37
- spec.add_development_dependency 'rspec', '~> 3.1'
38
- spec.add_development_dependency 'rubocop', '0.65.0'
39
- spec.add_development_dependency 'rubocop-rspec', '1.32.0'
40
- spec.add_development_dependency 'yard'
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