numbers_in_words 0.4.0 → 0.4.1
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 +5 -5
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.rubocop.yml +35 -1148
- data/.travis.yml +4 -4
- data/Gemfile +3 -1
- data/README.md +5 -43
- data/Rakefile +3 -1
- data/lib/numbers_in_words.rb +43 -19
- data/lib/numbers_in_words/duck_punch.rb +12 -8
- data/lib/numbers_in_words/exceptional_numbers.rb +119 -0
- data/lib/numbers_in_words/fraction.rb +151 -0
- data/lib/numbers_in_words/number_group.rb +34 -21
- data/lib/numbers_in_words/parsing/number_parser.rb +98 -0
- data/lib/numbers_in_words/parsing/pair_parsing.rb +64 -0
- data/lib/numbers_in_words/parsing/parse_fractions.rb +45 -0
- data/lib/numbers_in_words/parsing/parse_individual_number.rb +68 -0
- data/lib/numbers_in_words/parsing/parse_status.rb +17 -0
- data/lib/numbers_in_words/parsing/to_number.rb +159 -0
- data/lib/numbers_in_words/powers_of_ten.rb +49 -0
- data/lib/numbers_in_words/to_word.rb +78 -13
- data/lib/numbers_in_words/version.rb +3 -1
- data/lib/numbers_in_words/writer.rb +69 -0
- data/numbers_in_words.gemspec +14 -13
- data/spec/exceptional_numbers_spec.rb +26 -0
- data/spec/fraction_spec.rb +132 -0
- data/spec/fractions_spec.rb +31 -0
- data/spec/non_monkey_patch_spec.rb +39 -20
- data/spec/number_group_spec.rb +12 -12
- data/spec/number_parser_spec.rb +63 -0
- data/spec/numbers_in_words_spec.rb +56 -69
- data/spec/numerical_strings_spec.rb +28 -12
- data/spec/spec_helper.rb +2 -4
- data/spec/to_word_spec.rb +18 -0
- data/spec/words_in_numbers_spec.rb +130 -125
- data/spec/writer_spec.rb +26 -0
- data/spec/years_spec.rb +23 -13
- metadata +40 -25
- data/lib/numbers_in_words/english/constants.rb +0 -124
- data/lib/numbers_in_words/english/language_writer_english.rb +0 -116
- data/lib/numbers_in_words/language_writer.rb +0 -30
- data/lib/numbers_in_words/number_parser.rb +0 -135
- data/lib/numbers_in_words/to_number.rb +0 -88
- data/spec/language_writer_spec.rb +0 -23
data/spec/writer_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe NumbersInWords::Writer do
|
4
|
+
let(:number) { 2_111 }
|
5
|
+
let(:writer) { described_class.new(number) }
|
6
|
+
|
7
|
+
it 'should display numbers grouped' do
|
8
|
+
count = 0
|
9
|
+
|
10
|
+
writer.group_words(3) do |power, name, digits|
|
11
|
+
case count
|
12
|
+
when 0
|
13
|
+
expect(power).to eq(3)
|
14
|
+
expect(name).to eq('thousand')
|
15
|
+
expect(digits).to eq(2)
|
16
|
+
when 1
|
17
|
+
expect(power).to eq(0)
|
18
|
+
expect(name).to eq('one')
|
19
|
+
expect(digits).to eq(111)
|
20
|
+
end
|
21
|
+
count += 1
|
22
|
+
end
|
23
|
+
|
24
|
+
expect(count).to eq 2
|
25
|
+
end
|
26
|
+
end
|
data/spec/years_spec.rb
CHANGED
@@ -1,17 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require './spec/spec_helper'
|
2
4
|
|
3
|
-
describe
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
5
|
+
describe NumbersInWords::NumericExtension do
|
6
|
+
YEARS = {
|
7
|
+
'thirteen hundred' => 13_00,
|
8
|
+
'twenty-two hundred' => 22_00,
|
9
|
+
'twenty-two hundred and five' => 22_05,
|
10
|
+
'fifteen sixteen seventeen' => 151_617,
|
11
|
+
'forty-nine ninety-eight forty-seven seventy-nine' => 49_984_779,
|
12
|
+
'one fifty' => 150,
|
13
|
+
'two fifty' => 250,
|
14
|
+
'three fifty' => 350,
|
15
|
+
'one point fifty-six fifty-seven' => 1.5657,
|
16
|
+
'one three forty-seven' => 1347,
|
17
|
+
'one three five-point forty-seven' => 135.47,
|
18
|
+
'one ten sixty-three' => 11_063,
|
19
|
+
'one nineteen ten oh five' => 1_191_005
|
20
|
+
}.freeze
|
16
21
|
|
22
|
+
YEARS.each do |k, v|
|
23
|
+
it do
|
24
|
+
expect(k.in_numbers).to eql(v)
|
25
|
+
end
|
26
|
+
end
|
17
27
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: numbers_in_words
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Burns
|
@@ -9,37 +9,37 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2020-08-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: rspec
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - "
|
18
|
+
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version:
|
21
|
-
type: :
|
20
|
+
version: 3.4.0
|
21
|
+
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - "
|
25
|
+
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version:
|
27
|
+
version: 3.4.0
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: rubocop
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - "
|
32
|
+
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
34
|
+
version: '0'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - "
|
39
|
+
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
42
|
-
description:
|
41
|
+
version: '0'
|
42
|
+
description: convert written numbers into Integers and vice-versa
|
43
43
|
email:
|
44
44
|
- markthedeveloper@gmail.com
|
45
45
|
- dimidd@gmail.com
|
@@ -54,28 +54,39 @@ files:
|
|
54
54
|
- ".rubocop.yml"
|
55
55
|
- ".travis.yml"
|
56
56
|
- Gemfile
|
57
|
+
- Gemfile.lock
|
57
58
|
- LICENSE.txt
|
58
59
|
- README.md
|
59
60
|
- Rakefile
|
60
61
|
- bin/spec
|
61
62
|
- lib/numbers_in_words.rb
|
62
63
|
- lib/numbers_in_words/duck_punch.rb
|
63
|
-
- lib/numbers_in_words/
|
64
|
-
- lib/numbers_in_words/
|
65
|
-
- lib/numbers_in_words/language_writer.rb
|
64
|
+
- lib/numbers_in_words/exceptional_numbers.rb
|
65
|
+
- lib/numbers_in_words/fraction.rb
|
66
66
|
- lib/numbers_in_words/number_group.rb
|
67
|
-
- lib/numbers_in_words/number_parser.rb
|
68
|
-
- lib/numbers_in_words/
|
67
|
+
- lib/numbers_in_words/parsing/number_parser.rb
|
68
|
+
- lib/numbers_in_words/parsing/pair_parsing.rb
|
69
|
+
- lib/numbers_in_words/parsing/parse_fractions.rb
|
70
|
+
- lib/numbers_in_words/parsing/parse_individual_number.rb
|
71
|
+
- lib/numbers_in_words/parsing/parse_status.rb
|
72
|
+
- lib/numbers_in_words/parsing/to_number.rb
|
73
|
+
- lib/numbers_in_words/powers_of_ten.rb
|
69
74
|
- lib/numbers_in_words/to_word.rb
|
70
75
|
- lib/numbers_in_words/version.rb
|
76
|
+
- lib/numbers_in_words/writer.rb
|
71
77
|
- numbers_in_words.gemspec
|
72
|
-
- spec/
|
78
|
+
- spec/exceptional_numbers_spec.rb
|
79
|
+
- spec/fraction_spec.rb
|
80
|
+
- spec/fractions_spec.rb
|
73
81
|
- spec/non_monkey_patch_spec.rb
|
74
82
|
- spec/number_group_spec.rb
|
83
|
+
- spec/number_parser_spec.rb
|
75
84
|
- spec/numbers_in_words_spec.rb
|
76
85
|
- spec/numerical_strings_spec.rb
|
77
86
|
- spec/spec_helper.rb
|
87
|
+
- spec/to_word_spec.rb
|
78
88
|
- spec/words_in_numbers_spec.rb
|
89
|
+
- spec/writer_spec.rb
|
79
90
|
- spec/years_spec.rb
|
80
91
|
homepage: http://github.com/markburns/numbers_in_words
|
81
92
|
licenses: []
|
@@ -95,18 +106,22 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
106
|
- !ruby/object:Gem::Version
|
96
107
|
version: '0'
|
97
108
|
requirements: []
|
98
|
-
|
99
|
-
rubygems_version: 2.4.5
|
109
|
+
rubygems_version: 3.0.3
|
100
110
|
signing_key:
|
101
111
|
specification_version: 4
|
102
|
-
summary: 'Example:
|
103
|
-
point eight"
|
112
|
+
summary: 'Example: NumbersInWords.in_words(123) # => "one hundred and twenty three",
|
113
|
+
NumbersInWords.in_numbers("seventy-five point eight") # = > 75.8'
|
104
114
|
test_files:
|
105
|
-
- spec/
|
115
|
+
- spec/exceptional_numbers_spec.rb
|
116
|
+
- spec/fraction_spec.rb
|
117
|
+
- spec/fractions_spec.rb
|
106
118
|
- spec/non_monkey_patch_spec.rb
|
107
119
|
- spec/number_group_spec.rb
|
120
|
+
- spec/number_parser_spec.rb
|
108
121
|
- spec/numbers_in_words_spec.rb
|
109
122
|
- spec/numerical_strings_spec.rb
|
110
123
|
- spec/spec_helper.rb
|
124
|
+
- spec/to_word_spec.rb
|
111
125
|
- spec/words_in_numbers_spec.rb
|
126
|
+
- spec/writer_spec.rb
|
112
127
|
- spec/years_spec.rb
|
@@ -1,124 +0,0 @@
|
|
1
|
-
module NumbersInWords
|
2
|
-
module English
|
3
|
-
|
4
|
-
def self.canonize(w)
|
5
|
-
aliases = {
|
6
|
-
"oh" => "zero"
|
7
|
-
}
|
8
|
-
canon = aliases[w]
|
9
|
-
return canon ? canon : w
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.exceptions
|
13
|
-
{
|
14
|
-
0 => "zero",
|
15
|
-
1 => "one",
|
16
|
-
2 => "two",
|
17
|
-
3 => "three",
|
18
|
-
4 => "four",
|
19
|
-
5 => "five",
|
20
|
-
6 => "six",
|
21
|
-
7 => "seven",
|
22
|
-
8 => "eight",
|
23
|
-
9 => "nine",
|
24
|
-
|
25
|
-
10 => "ten",
|
26
|
-
11 => "eleven",
|
27
|
-
12 => "twelve",
|
28
|
-
|
29
|
-
13 => "thirteen",
|
30
|
-
14 => "fourteen",
|
31
|
-
15 => "fifteen",
|
32
|
-
16 => "sixteen" ,
|
33
|
-
17 => "seventeen",
|
34
|
-
18 => "eighteen",
|
35
|
-
19 => "nineteen",
|
36
|
-
|
37
|
-
20 => "twenty",
|
38
|
-
30 => "thirty",
|
39
|
-
40 => "forty",
|
40
|
-
50 => "fifty",
|
41
|
-
60 => "sixty",
|
42
|
-
70 => "seventy",
|
43
|
-
80 => "eighty",
|
44
|
-
90 => "ninety"
|
45
|
-
}
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.swap_keys hsh
|
49
|
-
hsh.inject({}){|h,(k,v)| h[v]=k; h}
|
50
|
-
end
|
51
|
-
|
52
|
-
def self.powers_of_ten
|
53
|
-
{
|
54
|
-
0 => "one",
|
55
|
-
1 => "ten",
|
56
|
-
2 => "hundred",
|
57
|
-
3 => "thousand",
|
58
|
-
6 => "million",
|
59
|
-
9 => "billion",
|
60
|
-
12 => "trillion",
|
61
|
-
15 => "quadrillion",
|
62
|
-
18 => "quintillion",
|
63
|
-
21 => "sextillion",
|
64
|
-
24 => "septillion",
|
65
|
-
27 => "octillion",
|
66
|
-
30 => "nonillion",
|
67
|
-
33 => "decillion",
|
68
|
-
36 => "undecillion",
|
69
|
-
39 => "duodecillion",
|
70
|
-
42 => "tredecillion",
|
71
|
-
45 => "quattuordecillion",
|
72
|
-
48 => "quindecillion",
|
73
|
-
51 => "sexdecillion",
|
74
|
-
54 => "septendecillion",
|
75
|
-
57 => "octodecillion",
|
76
|
-
60 => "novemdecillion",
|
77
|
-
63 => "vigintillion",
|
78
|
-
66 => "unvigintillion",
|
79
|
-
69 => "duovigintillion",
|
80
|
-
72 => "trevigintillion",
|
81
|
-
75 => "quattuorvigintillion",
|
82
|
-
78 => "quinvigintillion",
|
83
|
-
81 => "sexvigintillion",
|
84
|
-
84 => "septenvigintillion",
|
85
|
-
87 => "octovigintillion",
|
86
|
-
90 => "novemvigintillion",
|
87
|
-
93 => "trigintillion",
|
88
|
-
96 => "untrigintillion",
|
89
|
-
99 => "duotrigintillion",
|
90
|
-
100 => "googol"
|
91
|
-
}
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.exceptions_to_i
|
95
|
-
swap_keys exceptions
|
96
|
-
end
|
97
|
-
|
98
|
-
def self.powers_of_ten_to_i
|
99
|
-
swap_keys powers_of_ten
|
100
|
-
end
|
101
|
-
|
102
|
-
POWERS_RX = Regexp.union(powers_of_ten.values[1..-1])
|
103
|
-
|
104
|
-
def self.check_mixed(txt)
|
105
|
-
mixed = txt.match /^(-?\d+(.\d+)?) (#{POWERS_RX}s?)$/
|
106
|
-
if mixed && mixed[1] && mixed[3]
|
107
|
-
matches = [mixed[1], mixed[3]].map{ |m| NumbersInWords.in_numbers m }
|
108
|
-
return matches.reduce(&:*)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def self.check_one(txt)
|
113
|
-
one = txt.match /^one (#{POWERS_RX})$/
|
114
|
-
end
|
115
|
-
|
116
|
-
def self.strip_minus(txt)
|
117
|
-
stripped = txt.gsub(/^minus/, "") if txt =~ /^minus/
|
118
|
-
end
|
119
|
-
|
120
|
-
def self.check_decimal(txt)
|
121
|
-
txt.match(/\spoint\s/)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
@@ -1,116 +0,0 @@
|
|
1
|
-
module NumbersInWords
|
2
|
-
module English
|
3
|
-
class LanguageWriterEnglish < LanguageWriter
|
4
|
-
delegate :to_i, to: :that
|
5
|
-
|
6
|
-
def initialize that
|
7
|
-
super that
|
8
|
-
@language = "English"
|
9
|
-
end
|
10
|
-
|
11
|
-
def negative
|
12
|
-
"minus " + NumbersInWords.in_words(-@that)
|
13
|
-
end
|
14
|
-
|
15
|
-
def in_words
|
16
|
-
v = handle_exception
|
17
|
-
return v if v
|
18
|
-
|
19
|
-
in_decimals = decimals
|
20
|
-
return in_decimals if in_decimals
|
21
|
-
|
22
|
-
number = to_i
|
23
|
-
|
24
|
-
return negative() if number < 0
|
25
|
-
|
26
|
-
output = if number.to_s.length == 2 #20-99
|
27
|
-
handle_tens(number)
|
28
|
-
else
|
29
|
-
write() #longer numbers
|
30
|
-
end
|
31
|
-
|
32
|
-
output.strip
|
33
|
-
end
|
34
|
-
|
35
|
-
def handle_tens(number)
|
36
|
-
output = ""
|
37
|
-
|
38
|
-
tens = (number/10).round*10 #write the tens
|
39
|
-
|
40
|
-
output << exceptions[tens] # e.g. eighty
|
41
|
-
|
42
|
-
digit = number - tens #write the digits
|
43
|
-
|
44
|
-
unless digit == 0
|
45
|
-
output << " " + NumbersInWords.in_words(digit)
|
46
|
-
end
|
47
|
-
|
48
|
-
output
|
49
|
-
end
|
50
|
-
|
51
|
-
def handle_exception
|
52
|
-
exceptions[@that] if @that.is_a?(Integer) and exceptions[@that]
|
53
|
-
end
|
54
|
-
|
55
|
-
|
56
|
-
def write
|
57
|
-
length = @that.to_s.length
|
58
|
-
output =
|
59
|
-
if length == 3
|
60
|
-
#e.g. 113 splits into "one hundred" and "thirteen"
|
61
|
-
write_groups(2)
|
62
|
-
|
63
|
-
#more than one hundred less than one googol
|
64
|
-
elsif length < LENGTH_OF_GOOGOL
|
65
|
-
write_groups(3)
|
66
|
-
|
67
|
-
elsif length >= LENGTH_OF_GOOGOL
|
68
|
-
write_googols
|
69
|
-
end
|
70
|
-
output.strip
|
71
|
-
end
|
72
|
-
|
73
|
-
def decimals
|
74
|
-
int, decimals = NumberGroup.new(@that).split_decimals
|
75
|
-
if int
|
76
|
-
out = NumbersInWords.in_words(int) + " point "
|
77
|
-
decimals.each do |decimal|
|
78
|
-
out << NumbersInWords.in_words(decimal.to_i) + " "
|
79
|
-
end
|
80
|
-
out.strip
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
def write_googols
|
87
|
-
googols, remainder = NumberGroup.new(@that).split_googols
|
88
|
-
output = ""
|
89
|
-
|
90
|
-
output << " " + NumbersInWords.in_words(googols) + " googol"
|
91
|
-
if remainder > 0
|
92
|
-
prefix = " "
|
93
|
-
prefix << "and " if remainder < 100
|
94
|
-
output << prefix + NumbersInWords.in_words(remainder)
|
95
|
-
end
|
96
|
-
|
97
|
-
output
|
98
|
-
end
|
99
|
-
|
100
|
-
def write_groups group
|
101
|
-
#e.g. 113 splits into "one hundred" and "thirteen"
|
102
|
-
output = ""
|
103
|
-
group_words(group) do |power, name, digits|
|
104
|
-
if digits > 0
|
105
|
-
prefix = " "
|
106
|
-
#no and between thousands and hundreds
|
107
|
-
prefix << "and " if power == 0 and digits < 100
|
108
|
-
output << prefix + NumbersInWords.in_words(digits)
|
109
|
-
output << prefix + name unless power == 0
|
110
|
-
end
|
111
|
-
end
|
112
|
-
output
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module NumbersInWords
|
2
|
-
class LanguageWriter
|
3
|
-
attr_reader :that
|
4
|
-
delegate :exceptions, :powers_of_ten, to: :language
|
5
|
-
|
6
|
-
def initialize that
|
7
|
-
@that = that
|
8
|
-
end
|
9
|
-
|
10
|
-
def language
|
11
|
-
if @language.is_a? Module
|
12
|
-
@language
|
13
|
-
else
|
14
|
-
@language = NumbersInWords.const_get(@language)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def group_words size
|
19
|
-
#1000 and over Numbers are split into groups of three
|
20
|
-
groups = NumberGroup.groups_of @that, size
|
21
|
-
powers = groups.keys.sort.reverse #put in descending order
|
22
|
-
|
23
|
-
powers.each do |power|
|
24
|
-
name = powers_of_ten[power]
|
25
|
-
digits = groups[power]
|
26
|
-
yield power, name, digits
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|