easy_to_dictate_numbers 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 780e66635c5b14977a37fbd6136d0f818aceab29d48753184e1e5b0285502a61
4
- data.tar.gz: 81a6072f1e4f44c34babb9288e7a3c0250763a1f22e49f67a9fbe1fb89dea852
3
+ metadata.gz: aad1aad5f6f04f1c1788f38a5b5698a247198f1fedb8a811c997128bef520344
4
+ data.tar.gz: 79192439f74c5525eb578dff92542a78231c8237e4a37bb48e52bea13137f68f
5
5
  SHA512:
6
- metadata.gz: b36b50433deb8b0778bc81ccc1a08a55b4cf202c60af927a88858eed1b9e90611e4e4f0081ba8f079a168f87ff58107ecdc15bf65894a78036982d8f2f20fafc
7
- data.tar.gz: 90f026f4a7f1df4ea53d18625b0632925b2f46e31c0353c906e97b332f8360cf9faa0ab21c2be7721943022c668c638258114ceb5ceda9fe6c68e5643f8ca491
6
+ metadata.gz: 3903d276514862a8c8a8f870109b2ab6e7be5e7ae1e6b664f4aca5c129654d11a2503c0254e8dc516cbd04a99ba6ecd6ecd326f5913b2ee6c9a6b928401a9431
7
+ data.tar.gz: 037e26765bba96e29941dce83e4abdaab9a7a86ea30324ae8f6bbce9769fba2bbab323b95ca8f31b3ccc97432e2ed9d3d7fb44bb41cbddd41aad59e92b35291f
data/.rubocop.yml CHANGED
@@ -1,3 +1,9 @@
1
+
2
+ require:
3
+ - rubocop-performance
4
+ - rubocop-rspec
5
+ - rubocop-rake
6
+
1
7
  AllCops:
2
8
  TargetRubyVersion: 2.6
3
9
 
@@ -8,4 +14,337 @@ Style/Documentation:
8
14
  Enabled: false
9
15
 
10
16
  Metrics/BlockLength:
11
- Enabled: false
17
+ Enabled: false
18
+
19
+ Gemspec/DeprecatedAttributeAssignment: # new in 1.30
20
+ Enabled: true
21
+ Gemspec/DevelopmentDependencies: # new in 1.44
22
+ Enabled: true
23
+ Gemspec/RequireMFA: # new in 1.23
24
+ Enabled: true
25
+ Layout/LineContinuationLeadingSpace: # new in 1.31
26
+ Enabled: true
27
+ Layout/LineContinuationSpacing: # new in 1.31
28
+ Enabled: true
29
+ Layout/LineEndStringConcatenationIndentation: # new in 1.18
30
+ Enabled: true
31
+ Layout/SpaceBeforeBrackets: # new in 1.7
32
+ Enabled: true
33
+ Lint/AmbiguousAssignment: # new in 1.7
34
+ Enabled: true
35
+ Lint/AmbiguousOperatorPrecedence: # new in 1.21
36
+ Enabled: true
37
+ Lint/AmbiguousRange: # new in 1.19
38
+ Enabled: true
39
+ Lint/ConstantOverwrittenInRescue: # new in 1.31
40
+ Enabled: true
41
+ Lint/DeprecatedConstants: # new in 1.8
42
+ Enabled: true
43
+ Lint/DuplicateBranch: # new in 1.3
44
+ Enabled: true
45
+ Lint/DuplicateMagicComment: # new in 1.37
46
+ Enabled: true
47
+ Lint/DuplicateMatchPattern: # new in 1.50
48
+ Enabled: true
49
+ Lint/DuplicateRegexpCharacterClassElement: # new in 1.1
50
+ Enabled: true
51
+ Lint/EmptyBlock: # new in 1.1
52
+ Enabled: true
53
+ Lint/EmptyClass: # new in 1.3
54
+ Enabled: true
55
+ Lint/EmptyInPattern: # new in 1.16
56
+ Enabled: true
57
+ Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21
58
+ Enabled: true
59
+ Lint/LambdaWithoutLiteralBlock: # new in 1.8
60
+ Enabled: true
61
+ Lint/LiteralAssignmentInCondition: # new in 1.58
62
+ Enabled: true
63
+ Lint/MixedCaseRange: # new in 1.53
64
+ Enabled: true
65
+ Lint/NoReturnInBeginEndBlocks: # new in 1.2
66
+ Enabled: true
67
+ Lint/NonAtomicFileOperation: # new in 1.31
68
+ Enabled: true
69
+ Lint/NumberedParameterAssignment: # new in 1.9
70
+ Enabled: true
71
+ Lint/OrAssignmentToConstant: # new in 1.9
72
+ Enabled: true
73
+ Lint/RedundantDirGlobSort: # new in 1.8
74
+ Enabled: true
75
+ Lint/RedundantRegexpQuantifiers: # new in 1.53
76
+ Enabled: true
77
+ Lint/RefinementImportMethods: # new in 1.27
78
+ Enabled: true
79
+ Lint/RequireRangeParentheses: # new in 1.32
80
+ Enabled: true
81
+ Lint/RequireRelativeSelfPath: # new in 1.22
82
+ Enabled: true
83
+ Lint/SymbolConversion: # new in 1.9
84
+ Enabled: true
85
+ Lint/ToEnumArguments: # new in 1.1
86
+ Enabled: true
87
+ Lint/TripleQuotes: # new in 1.9
88
+ Enabled: true
89
+ Lint/UnexpectedBlockArity: # new in 1.5
90
+ Enabled: true
91
+ Lint/UnmodifiedReduceAccumulator: # new in 1.1
92
+ Enabled: true
93
+ Lint/UselessRescue: # new in 1.43
94
+ Enabled: true
95
+ Lint/UselessRuby2Keywords: # new in 1.23
96
+ Enabled: true
97
+ Metrics/CollectionLiteralLength: # new in 1.47
98
+ Enabled: true
99
+ Naming/BlockForwarding: # new in 1.24
100
+ Enabled: true
101
+ Security/CompoundHash: # new in 1.28
102
+ Enabled: true
103
+ Security/IoMethods: # new in 1.22
104
+ Enabled: true
105
+ Style/ArgumentsForwarding: # new in 1.1
106
+ Enabled: true
107
+ Style/ArrayIntersect: # new in 1.40
108
+ Enabled: true
109
+ Style/CollectionCompact: # new in 1.2
110
+ Enabled: true
111
+ Style/ComparableClamp: # new in 1.44
112
+ Enabled: true
113
+ Style/ConcatArrayLiterals: # new in 1.41
114
+ Enabled: true
115
+ Style/DataInheritance: # new in 1.49
116
+ Enabled: true
117
+ Style/DirEmpty: # new in 1.48
118
+ Enabled: true
119
+ Style/DocumentDynamicEvalDefinition: # new in 1.1
120
+ Enabled: true
121
+ Style/EmptyHeredoc: # new in 1.32
122
+ Enabled: true
123
+ Style/EndlessMethod: # new in 1.8
124
+ Enabled: true
125
+ Style/EnvHome: # new in 1.29
126
+ Enabled: true
127
+ Style/ExactRegexpMatch: # new in 1.51
128
+ Enabled: true
129
+ Style/FetchEnvVar: # new in 1.28
130
+ Enabled: true
131
+ Style/FileEmpty: # new in 1.48
132
+ Enabled: true
133
+ Style/FileRead: # new in 1.24
134
+ Enabled: true
135
+ Style/FileWrite: # new in 1.24
136
+ Enabled: true
137
+ Style/HashConversion: # new in 1.10
138
+ Enabled: true
139
+ Style/HashExcept: # new in 1.7
140
+ Enabled: true
141
+ Style/IfWithBooleanLiteralBranches: # new in 1.9
142
+ Enabled: true
143
+ Style/InPatternThen: # new in 1.16
144
+ Enabled: true
145
+ Style/MagicCommentFormat: # new in 1.35
146
+ Enabled: true
147
+ Style/MapCompactWithConditionalBlock: # new in 1.30
148
+ Enabled: true
149
+ Style/MapToHash: # new in 1.24
150
+ Enabled: true
151
+ Style/MapToSet: # new in 1.42
152
+ Enabled: true
153
+ Style/MinMaxComparison: # new in 1.42
154
+ Enabled: true
155
+ Style/MultilineInPatternThen: # new in 1.16
156
+ Enabled: true
157
+ Style/NegatedIfElseCondition: # new in 1.2
158
+ Enabled: true
159
+ Style/NestedFileDirname: # new in 1.26
160
+ Enabled: true
161
+ Style/NilLambda: # new in 1.3
162
+ Enabled: true
163
+ Style/NumberedParameters: # new in 1.22
164
+ Enabled: true
165
+ Style/NumberedParametersLimit: # new in 1.22
166
+ Enabled: true
167
+ Style/ObjectThen: # new in 1.28
168
+ Enabled: true
169
+ Style/OpenStructUse: # new in 1.23
170
+ Enabled: true
171
+ Style/OperatorMethodCall: # new in 1.37
172
+ Enabled: true
173
+ Style/QuotedSymbols: # new in 1.16
174
+ Enabled: true
175
+ Style/RedundantArgument: # new in 1.4
176
+ Enabled: true
177
+ Style/RedundantArrayConstructor: # new in 1.52
178
+ Enabled: true
179
+ Style/RedundantConstantBase: # new in 1.40
180
+ Enabled: true
181
+ Style/RedundantCurrentDirectoryInPath: # new in 1.53
182
+ Enabled: true
183
+ Style/RedundantDoubleSplatHashBraces: # new in 1.41
184
+ Enabled: true
185
+ Style/RedundantEach: # new in 1.38
186
+ Enabled: true
187
+ Style/RedundantFilterChain: # new in 1.52
188
+ Enabled: true
189
+ Style/RedundantHeredocDelimiterQuotes: # new in 1.45
190
+ Enabled: true
191
+ Style/RedundantInitialize: # new in 1.27
192
+ Enabled: true
193
+ Style/RedundantLineContinuation: # new in 1.49
194
+ Enabled: true
195
+ Style/RedundantRegexpArgument: # new in 1.53
196
+ Enabled: true
197
+ Style/RedundantRegexpConstructor: # new in 1.52
198
+ Enabled: true
199
+ Style/RedundantSelfAssignmentBranch: # new in 1.19
200
+ Enabled: true
201
+ Style/RedundantStringEscape: # new in 1.37
202
+ Enabled: true
203
+ Style/ReturnNilInPredicateMethodDefinition: # new in 1.53
204
+ Enabled: true
205
+ Style/SelectByRegexp: # new in 1.22
206
+ Enabled: true
207
+ Style/SingleLineDoEndBlock: # new in 1.57
208
+ Enabled: true
209
+ Style/StringChars: # new in 1.12
210
+ Enabled: true
211
+ Style/SuperWithArgsParentheses: # new in 1.58
212
+ Enabled: true
213
+ Style/SwapValues: # new in 1.1
214
+ Enabled: true
215
+ Style/YAMLFileRead: # new in 1.53
216
+ Enabled: true
217
+ Capybara/ClickLinkOrButtonStyle: # new in 2.19
218
+ Enabled: true
219
+ Capybara/MatchStyle: # new in 2.17
220
+ Enabled: true
221
+ Capybara/NegationMatcher: # new in 2.14
222
+ Enabled: true
223
+ Capybara/RedundantWithinFind: # new in 2.20
224
+ Enabled: true
225
+ Capybara/SpecificActions: # new in 2.14
226
+ Enabled: true
227
+ Capybara/SpecificFinders: # new in 2.13
228
+ Enabled: true
229
+ Capybara/SpecificMatcher: # new in 2.12
230
+ Enabled: true
231
+ Capybara/RSpec/HaveSelector: # new in 2.19
232
+ Enabled: true
233
+ Capybara/RSpec/PredicateMatcher: # new in 2.19
234
+ Enabled: true
235
+ FactoryBot/AssociationStyle: # new in 2.23
236
+ Enabled: true
237
+ FactoryBot/ConsistentParenthesesStyle: # new in 2.14
238
+ Enabled: true
239
+ FactoryBot/ExcessiveCreateList: # new in 2.25
240
+ Enabled: true
241
+ FactoryBot/FactoryAssociationWithStrategy: # new in 2.23
242
+ Enabled: true
243
+ FactoryBot/FactoryNameStyle: # new in 2.16
244
+ Enabled: true
245
+ FactoryBot/IdSequence: # new in 2.24
246
+ Enabled: true
247
+ FactoryBot/RedundantFactoryOption: # new in 2.23
248
+ Enabled: true
249
+ FactoryBot/SyntaxMethods: # new in 2.7
250
+ Enabled: true
251
+ RSpec/BeEmpty: # new in 2.20
252
+ Enabled: true
253
+ RSpec/BeEq: # new in 2.9.0
254
+ Enabled: true
255
+ RSpec/BeNil: # new in 2.9.0
256
+ Enabled: true
257
+ RSpec/ChangeByZero: # new in 2.11
258
+ Enabled: true
259
+ RSpec/ContainExactly: # new in 2.19
260
+ Enabled: true
261
+ RSpec/DuplicatedMetadata: # new in 2.16
262
+ Enabled: true
263
+ RSpec/EmptyMetadata: # new in 2.24
264
+ Enabled: true
265
+ RSpec/Eq: # new in 2.24
266
+ Enabled: true
267
+ RSpec/ExcessiveDocstringSpacing: # new in 2.5
268
+ Enabled: true
269
+ RSpec/IdenticalEqualityAssertion: # new in 2.4
270
+ Enabled: true
271
+ RSpec/IndexedLet: # new in 2.20
272
+ Enabled: true
273
+ RSpec/MatchArray: # new in 2.19
274
+ Enabled: true
275
+ RSpec/MetadataStyle: # new in 2.24
276
+ Enabled: true
277
+ RSpec/NoExpectationExample: # new in 2.13
278
+ Enabled: true
279
+ RSpec/PendingWithoutReason: # new in 2.16
280
+ Enabled: true
281
+ RSpec/ReceiveMessages: # new in 2.23
282
+ Enabled: true
283
+ RSpec/RedundantAround: # new in 2.19
284
+ Enabled: true
285
+ RSpec/RedundantPredicateMatcher: # new in 2.26
286
+ Enabled: true
287
+ RSpec/RemoveConst: # new in 2.26
288
+ Enabled: true
289
+ RSpec/SkipBlockInsideExample: # new in 2.19
290
+ Enabled: true
291
+ RSpec/SortMetadata: # new in 2.14
292
+ Enabled: true
293
+ RSpec/SpecFilePathFormat: # new in 2.24
294
+ Enabled: true
295
+ RSpec/SpecFilePathSuffix: # new in 2.24
296
+ Enabled: true
297
+ RSpec/SubjectDeclaration: # new in 2.5
298
+ Enabled: true
299
+ RSpec/VerifiedDoubleReference: # new in 2.10.0
300
+ Enabled: true
301
+ RSpec/Rails/AvoidSetupHook: # new in 2.4
302
+ Enabled: true
303
+ RSpec/Rails/HaveHttpStatus: # new in 2.12
304
+ Enabled: true
305
+ RSpec/Rails/InferredSpecType: # new in 2.14
306
+ Enabled: true
307
+ RSpec/Rails/MinitestAssertions: # new in 2.17
308
+ Enabled: true
309
+ RSpec/Rails/NegationBeValid: # new in 2.23
310
+ Enabled: true
311
+ RSpec/Rails/TravelAround: # new in 2.19
312
+ Enabled: true
313
+ Performance/AncestorsInclude: # new in 1.7
314
+ Enabled: true
315
+ Performance/BigDecimalWithNumericArgument: # new in 1.7
316
+ Enabled: true
317
+ Performance/BlockGivenWithExplicitBlock: # new in 1.9
318
+ Enabled: true
319
+ Performance/CollectionLiteralInLoop: # new in 1.8
320
+ Enabled: true
321
+ Performance/ConcurrentMonotonicTime: # new in 1.12
322
+ Enabled: true
323
+ Performance/ConstantRegexp: # new in 1.9
324
+ Enabled: true
325
+ Performance/MapCompact: # new in 1.11
326
+ Enabled: true
327
+ Performance/MapMethodChain: # new in 1.19
328
+ Enabled: true
329
+ Performance/MethodObjectAsBlock: # new in 1.9
330
+ Enabled: true
331
+ Performance/RedundantEqualityComparisonBlock: # new in 1.10
332
+ Enabled: true
333
+ Performance/RedundantSortBlock: # new in 1.7
334
+ Enabled: true
335
+ Performance/RedundantSplitRegexpArgument: # new in 1.10
336
+ Enabled: true
337
+ Performance/RedundantStringChars: # new in 1.7
338
+ Enabled: true
339
+ Performance/ReverseFirst: # new in 1.7
340
+ Enabled: true
341
+ Performance/SortReverse: # new in 1.7
342
+ Enabled: true
343
+ Performance/Squeeze: # new in 1.7
344
+ Enabled: true
345
+ Performance/StringIdentifierArgument: # new in 1.13
346
+ Enabled: true
347
+ Performance/StringInclude: # new in 1.7
348
+ Enabled: true
349
+ Performance/Sum: # new in 1.8
350
+ Enabled: true
data/CHANGELOG.md CHANGED
@@ -18,4 +18,10 @@
18
18
  - 100 -> one hundred
19
19
  - 1000 -> one thousand
20
20
  - 2334 -> twenty three thirty four
21
- - Extended string with `to_dictable_number`
21
+ - Extended string with `to_dictable_number`
22
+ - Add support for leading zeroes
23
+
24
+ ## [0.1.4] - 2024-01-14
25
+
26
+ - Refactor to use instance methods to avoid exposing so many
27
+ - Added rubocop and fixed all errors
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # EasyToDictateNumbers
2
2
 
3
- EasyToDictateNumbers is a Ruby gem that allows for easy conversion of numbers into their word representations. This gem is useful in scenarios where numbers need to be communicated clearly, such as in telephone conversations or when dictating information.
3
+ GitHub Copilot: EasyToDictateNumbers is an opinionated Ruby gem designed to convert numbers into their spoken equivalents. This gem is particularly useful in situations where precise verbal communication of numbers is required, such as during phone calls or dictation. It makes certain decisions about the "best" way to pronounce numbers, which may be subject to debate.
4
4
 
5
5
  ## Installation
6
6
 
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
 
11
11
  spec.summary = 'Transform numbers into words to dictate them easily.'
12
12
  spec.description = 'Transform numbers into words to dictate them easily.' \
13
- "For example 1234 becomes twelve thirty four and 123456 becomes 'one two three, four five six'"
13
+ "For example 1234 becomes twelve thirty four and 123456 becomes 'one two three, four five six'"
14
14
  spec.homepage = 'https://github.com/matismasters/easy_to_dictate_numbers'
15
15
  spec.required_ruby_version = '>= 2.6.0'
16
16
 
@@ -36,4 +36,5 @@ Gem::Specification.new do |spec|
36
36
 
37
37
  # For more information and examples about making a new gem, check out our
38
38
  # guide at: https://bundler.io/guides/creating_gem.html
39
+ spec.metadata['rubygems_mfa_required'] = 'true'
39
40
  end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EasyToDictateNumbers
4
+ class DictableNumber
5
+ attr_reader :number_to_dictate, :dictable_number_in_words
6
+
7
+ ONES = %w[zero one two three four five six seven eight nine].freeze
8
+ TEENS = %w[ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen].freeze
9
+ TENS = %w[twenty thirty forty fifty sixty seventy eighty ninety].freeze
10
+
11
+ def initialize(number_to_dictate)
12
+ @number_to_dictate = number_to_dictate.to_s
13
+ validate_number(@number_to_dictate)
14
+ end
15
+
16
+ def to_dictable
17
+ @to_dictable ||= number_to_words
18
+ end
19
+
20
+ private
21
+
22
+ def number_to_words
23
+ number_as_string = @number_to_dictate
24
+
25
+ leading_zeroes_words = leading_zeroes_to_words(number_as_string)
26
+
27
+ number_without_leading_zeroes = number_without_leading_zeroes(number_as_string)
28
+ number_without_leading_zeroes_words = number_without_leading_zeroes_to_words(number_without_leading_zeroes)
29
+
30
+ [leading_zeroes_words, number_without_leading_zeroes_words].reject(&:empty?).join(' ')
31
+ end
32
+
33
+ def validate_number(number_as_string)
34
+ raise NonNumberCharactersPresent if number_as_string.match?(/[^0-9]/)
35
+ end
36
+
37
+ def number_without_leading_zeroes_to_words(number_as_string)
38
+ case number_as_string.length
39
+ when 1 then one_digit_number_to_words(number_as_string)
40
+ when 2 then two_digit_number_to_words(number_as_string)
41
+ when 3 then three_digit_number_to_words(number_as_string)
42
+ when 4 then four_digit_number_to_words(number_as_string)
43
+ else large_number_to_words(number_as_string)
44
+ end
45
+ end
46
+
47
+ def repeat_zeroes(number_of_zeroes)
48
+ Array.new(number_of_zeroes) { ONES[0] }.join(' ')
49
+ end
50
+
51
+ def leading_zeroes_to_words(number_as_string)
52
+ leading_zeroes = number_as_string.match(/^0+/).to_s
53
+ return '' if leading_zeroes.empty?
54
+
55
+ repeat_zeroes(leading_zeroes.length)
56
+ end
57
+
58
+ def number_without_leading_zeroes(number_as_string)
59
+ number_as_string.sub(/^0+/, '')
60
+ end
61
+
62
+ def single_thousands_to_words(number_as_string)
63
+ number = number_as_string.to_i / 1000
64
+
65
+ [one_digit_number_to_words(number), 'thousand'].join(' ')
66
+ end
67
+
68
+ def one_digit_number_to_words(number_as_string)
69
+ number = number_as_string.to_i
70
+ return repeat_zeroes(1) if number.zero?
71
+
72
+ ONES[number]
73
+ end
74
+
75
+ def two_digit_number_to_words(number_as_string)
76
+ number = number_as_string.to_i
77
+
78
+ return repeat_zeroes(2) if number.zero?
79
+ return TEENS[number - 10] if number < 20
80
+
81
+ div, mod = number.divmod(10)
82
+ TENS[div - 2] + (mod.zero? ? '' : " #{ONES[mod]}")
83
+ end
84
+
85
+ def three_digit_number_to_words(number_as_string)
86
+ number = number_as_string.to_i
87
+ return repeat_zeroes(3) if number.zero?
88
+
89
+ first_digit, remainder = number.divmod(100)
90
+ words = [ONES[first_digit]]
91
+ words << (remainder.zero? ? 'hundred' : two_digit_number_to_words(remainder))
92
+ words.join(' ')
93
+ end
94
+
95
+ def four_digit_number_to_words(number_as_string)
96
+ number = number_as_string.to_i
97
+
98
+ return repeat_zeroes(4) if number.zero?
99
+ return single_thousands_to_words(number_as_string) if (number % 1000).zero?
100
+
101
+ high_pair = number_as_string[0..1]
102
+ low_pair = number_as_string[2..3]
103
+
104
+ [
105
+ two_digit_number_to_words(high_pair),
106
+ low_pair.to_i.zero? ? 'hundred' : two_digit_number_to_words(low_pair)
107
+ ].join(' ')
108
+ end
109
+
110
+ def large_number_to_words(number_as_string)
111
+ number_as_string.chars.map { |digit| ONES[digit.to_i] }.each_slice(3).map { |digit| digit.join(' ') }.join(', ')
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EasyToDictateNumbers
4
+ class Error < StandardError; end
5
+
6
+ class NonNumberCharactersPresent < StandardError
7
+ def initialize
8
+ super('Non-number characters present')
9
+ end
10
+ end
11
+ end
@@ -2,12 +2,12 @@
2
2
 
3
3
  class Integer
4
4
  def to_dictable
5
- EasyToDictateNumbers::NumberToDictable.number_to_words(self)
5
+ EasyToDictateNumbers::DictableNumber.new(self).to_dictable
6
6
  end
7
7
  end
8
8
 
9
9
  class String
10
10
  def to_dictable_number
11
- EasyToDictateNumbers::NumberToDictable.number_to_words(self)
11
+ EasyToDictateNumbers::DictableNumber.new(self).to_dictable
12
12
  end
13
13
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EasyToDictateNumbers
4
- VERSION = '0.1.3'
4
+ VERSION = '0.1.4'
5
5
  end
@@ -3,4 +3,5 @@
3
3
  # lib/easy_to_dictate_numbers.rb
4
4
  require_relative 'easy_to_dictate_numbers/version'
5
5
  require_relative 'easy_to_dictate_numbers/extend_primitives'
6
- require_relative 'easy_to_dictate_numbers/easy_to_dictate_numbers'
6
+ require_relative 'easy_to_dictate_numbers/exceptions'
7
+ require_relative 'easy_to_dictate_numbers/dictable_number'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy_to_dictate_numbers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matias Verges
@@ -26,7 +26,8 @@ files:
26
26
  - Rakefile
27
27
  - easy_to_dictate_numbers.gemspec
28
28
  - lib/easy_to_dictate_numbers.rb
29
- - lib/easy_to_dictate_numbers/easy_to_dictate_numbers.rb
29
+ - lib/easy_to_dictate_numbers/dictable_number.rb
30
+ - lib/easy_to_dictate_numbers/exceptions.rb
30
31
  - lib/easy_to_dictate_numbers/extend_primitives.rb
31
32
  - lib/easy_to_dictate_numbers/version.rb
32
33
  - sig/easy_to_dictate_numbers.rbs
@@ -37,6 +38,7 @@ metadata:
37
38
  homepage_uri: https://github.com/matismasters/easy_to_dictate_numbers
38
39
  source_code_uri: https://github.com/matismasters/easy_to_dictate_numbers
39
40
  changelog_uri: https://github.com/matismasters/easy_to_dictate_numbers/blob/main/CHANGELOG.md
41
+ rubygems_mfa_required: 'true'
40
42
  post_install_message:
41
43
  rdoc_options: []
42
44
  require_paths:
@@ -1,110 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module EasyToDictateNumbers
4
- class Error < StandardError; end
5
-
6
- class NonNumberCharactersPresent < StandardError
7
- def initialize
8
- super('Non-number characters present')
9
- end
10
- end
11
-
12
- class NumberToDictable
13
- ONES = %w[zero one two three four five six seven eight nine].freeze
14
- TEENS = %w[ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen].freeze
15
- TENS = %w[twenty thirty forty fifty sixty seventy eighty ninety].freeze
16
-
17
- class << self
18
- def number_to_words(number_to_dictate)
19
- number_as_string = number_to_dictate.to_s
20
- validate_number(number_as_string)
21
-
22
- leading_zeroes_words = leading_zeroes_to_words(number_as_string)
23
-
24
- number_without_leading_zeroes = number_without_leading_zeroes(number_as_string)
25
- number_without_leading_zeroes_words = number_without_leading_zeroes_to_words(number_without_leading_zeroes)
26
-
27
- [leading_zeroes_words, number_without_leading_zeroes_words].reject(&:empty?).join(' ')
28
- end
29
-
30
- def validate_number(number_as_string)
31
- raise NonNumberCharactersPresent if number_as_string.match?(/[^0-9]/)
32
- end
33
-
34
- def number_without_leading_zeroes_to_words(number_as_string)
35
- case number_as_string.length
36
- when 1 then one_digit_number_to_words(number_as_string)
37
- when 2 then two_digit_number_to_words(number_as_string)
38
- when 3 then three_digit_number_to_words(number_as_string)
39
- when 4 then four_digit_number_to_words(number_as_string)
40
- else large_number_to_words(number_as_string)
41
- end
42
- end
43
-
44
- def repeat_zeroes(number_of_zeroes)
45
- number_of_zeroes.times.map { ONES[0] }.join(' ')
46
- end
47
-
48
- def leading_zeroes_to_words(number_as_string)
49
- leading_zeroes = number_as_string.match(/^0+/).to_s
50
- leading_zeroes.empty? ? '' : repeat_zeroes(leading_zeroes.length)
51
- end
52
-
53
- def number_without_leading_zeroes(number_as_string)
54
- number_as_string.sub(/^0+/, '')
55
- end
56
-
57
- def single_thousands_to_words(number_as_string)
58
- number = number_as_string.to_i / 1000
59
-
60
- [one_digit_number_to_words(number), 'thousand'].join(' ')
61
- end
62
-
63
- def one_digit_number_to_words(number_as_string)
64
- number = number_as_string.to_i
65
- return repeat_zeroes(1) if number.zero?
66
-
67
- ONES[number]
68
- end
69
-
70
- def two_digit_number_to_words(number_as_string)
71
- number = number_as_string.to_i
72
-
73
- return repeat_zeroes(2) if number.zero?
74
- return TEENS[number - 10] if number < 20
75
-
76
- div, mod = number.divmod(10)
77
- TENS[div - 2] + (mod.zero? ? '' : " #{ONES[mod]}")
78
- end
79
-
80
- def three_digit_number_to_words(number_as_string)
81
- number = number_as_string.to_i
82
- return repeat_zeroes(3) if number.zero?
83
-
84
- first_digit, remainder = number.divmod(100)
85
- words = [ONES[first_digit]]
86
- words << (remainder.zero? ? 'hundred' : two_digit_number_to_words(remainder))
87
- words.join(' ')
88
- end
89
-
90
- def four_digit_number_to_words(number_as_string)
91
- number = number_as_string.to_i
92
-
93
- return repeat_zeroes(4) if number.zero?
94
- return single_thousands_to_words(number_as_string) if (number % 1000).zero?
95
-
96
- high_pair = number_as_string[0..1]
97
- low_pair = number_as_string[2..3]
98
-
99
- [
100
- two_digit_number_to_words(high_pair),
101
- low_pair.to_i.zero? ? 'hundred' : two_digit_number_to_words(low_pair)
102
- ].join(' ')
103
- end
104
-
105
- def large_number_to_words(number_as_string)
106
- number_as_string.chars.map { |digit| ONES[digit.to_i] }.each_slice(3).map { |digit| digit.join(' ') }.join(', ')
107
- end
108
- end
109
- end
110
- end