numbers_in_words 0.4.1 → 0.5.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/.travis.yml +11 -3
- data/Gemfile +1 -0
- data/lib/numbers_in_words.rb +1 -0
- data/lib/numbers_in_words/exceptional_numbers.rb +0 -4
- data/lib/numbers_in_words/fraction.rb +6 -21
- data/lib/numbers_in_words/parsing/fraction_parsing.rb +34 -0
- data/lib/numbers_in_words/parsing/special.rb +67 -0
- data/lib/numbers_in_words/parsing/to_number.rb +5 -87
- data/lib/numbers_in_words/version.rb +1 -1
- data/numbers_in_words.gemspec +2 -1
- data/spec/fraction_spec.rb +105 -85
- data/spec/fractions_spec.rb +2 -2
- data/spec/non_monkey_patch_spec.rb +4 -4
- data/spec/number_parser_spec.rb +0 -32
- data/spec/numbers_in_words_spec.rb +10 -4
- data/spec/numerical_strings_spec.rb +2 -2
- data/spec/spec_helper.rb +21 -0
- data/spec/words_in_numbers_spec.rb +4 -2
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a69b94b2d308dbf461d439c03e57ab585f6bd14760fbe01fbfb72ab7c87bf49
|
4
|
+
data.tar.gz: e8eaf38c1c28fa6b6d6c055ad2e73a0a446f418f984314682c5cc22eda6a64a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a62e3d4ee01401dc3fd9ed1a694722fc4033954ea4c3e4ffc0f321f2c11777b91b465407873a80477986ef4c91d6bbc1aaa64dd6b0d9ab35ff45435d687b09a4
|
7
|
+
data.tar.gz: f068adee24754761e40e8b969fd432f478ec6c0d921e686594a33c29d06c4384644b2cb9a18a82c385e225e090c0a3db2fb379154d5885ced72523efb9f1776c
|
data/.travis.yml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
+
env:
|
2
|
+
global:
|
3
|
+
- CC_TEST_REPORTER_ID=9a548b48c1c0804d8fb9083ae8e9693a5d5197eb86e8cf1b63a89d18f33e0464
|
1
4
|
sudo: false
|
2
5
|
language: ruby
|
3
6
|
rvm:
|
4
|
-
- "2.
|
5
|
-
- "2.
|
6
|
-
|
7
|
+
- "2.6.6"
|
8
|
+
- "2.7.1"
|
9
|
+
before_script:
|
10
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
11
|
+
- chmod +x ./cc-test-reporter
|
12
|
+
- ./cc-test-reporter before-build
|
7
13
|
script: ./bin/spec
|
14
|
+
after_script:
|
15
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
data/Gemfile
CHANGED
data/lib/numbers_in_words.rb
CHANGED
@@ -18,12 +18,6 @@ module NumbersInWords
|
|
18
18
|
@attributes = attributes || NumbersInWords::ExceptionalNumbers::DEFINITIONS[denominator] || {}
|
19
19
|
end
|
20
20
|
|
21
|
-
def to_r
|
22
|
-
return 0.0 if denominator == Float::INFINITY
|
23
|
-
|
24
|
-
(numerator / denominator.to_f).rationalize(EPSILON)
|
25
|
-
end
|
26
|
-
|
27
21
|
def lookup_keys
|
28
22
|
key = in_words
|
29
23
|
key2 = strip_punctuation(key.split(' ')).join(' ')
|
@@ -36,13 +30,6 @@ module NumbersInWords
|
|
36
30
|
end
|
37
31
|
|
38
32
|
def in_words
|
39
|
-
if denominator == Float::INFINITY
|
40
|
-
# We've reached the limits of ruby's number system
|
41
|
-
# by the time we get to a googolplex (10 ** (10 ** 100))
|
42
|
-
# I suppose we could also call this an 'infinitieth'
|
43
|
-
return pluralize? ? 'googolplexths' : 'googolplexth'
|
44
|
-
end
|
45
|
-
|
46
33
|
NumbersInWords.in_words(numerator) + ' ' + fraction
|
47
34
|
end
|
48
35
|
|
@@ -51,6 +38,12 @@ module NumbersInWords
|
|
51
38
|
end
|
52
39
|
|
53
40
|
def fraction
|
41
|
+
if denominator == Float::INFINITY
|
42
|
+
# We've reached the limits of ruby's number system
|
43
|
+
# by the time we get to a googolplex (10 ** (10 ** 100))
|
44
|
+
return pluralize? ? 'infinitieths' : 'infinitieth'
|
45
|
+
end
|
46
|
+
|
54
47
|
pluralize? ? pluralized_fraction : singular_fraction
|
55
48
|
end
|
56
49
|
|
@@ -102,14 +95,6 @@ module NumbersInWords
|
|
102
95
|
end
|
103
96
|
end
|
104
97
|
|
105
|
-
def plural
|
106
|
-
exception && (fraction_plural || singular + 's') || ordinal_plural
|
107
|
-
end
|
108
|
-
|
109
|
-
def singular
|
110
|
-
(exception && exception[:singular]) || ordinal
|
111
|
-
end
|
112
|
-
|
113
98
|
def with_remainder(mod, join_word)
|
114
99
|
rest = denominator % mod
|
115
100
|
main = denominator - rest
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NumbersInWords
|
4
|
+
module FractionParsing
|
5
|
+
def fraction(text)
|
6
|
+
return unless possible_fraction?(text)
|
7
|
+
|
8
|
+
NumbersInWords.exceptional_numbers.lookup_fraction(text)
|
9
|
+
end
|
10
|
+
|
11
|
+
def strip_punctuation(text)
|
12
|
+
text = text.downcase.gsub(/[^a-z 0-9]/, ' ')
|
13
|
+
to_remove = true
|
14
|
+
|
15
|
+
to_remove = text.gsub! ' ', ' ' while to_remove
|
16
|
+
|
17
|
+
text
|
18
|
+
end
|
19
|
+
|
20
|
+
def possible_fraction?(text)
|
21
|
+
words = text.split(' ')
|
22
|
+
result = words & NumbersInWords.exceptional_numbers.fraction_names
|
23
|
+
result.length.positive?
|
24
|
+
end
|
25
|
+
|
26
|
+
def text_including_punctuation
|
27
|
+
to_s.strip
|
28
|
+
end
|
29
|
+
|
30
|
+
def text
|
31
|
+
strip_punctuation text_including_punctuation
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './fraction_parsing'
|
4
|
+
|
5
|
+
module NumbersInWords
|
6
|
+
class Special
|
7
|
+
extend Forwardable
|
8
|
+
def_delegator :that, :to_s
|
9
|
+
|
10
|
+
include FractionParsing
|
11
|
+
|
12
|
+
attr_reader :that, :only_compress
|
13
|
+
|
14
|
+
def initialize(that, only_compress)
|
15
|
+
@that = that
|
16
|
+
@only_compress = only_compress
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
float ||
|
21
|
+
negative ||
|
22
|
+
fraction(that) ||
|
23
|
+
mixed_words_and_digits ||
|
24
|
+
one
|
25
|
+
end
|
26
|
+
|
27
|
+
def float
|
28
|
+
text_including_punctuation.to_f if text =~ /^-?\d+(.\d+)?$/
|
29
|
+
end
|
30
|
+
|
31
|
+
def negative
|
32
|
+
stripped = strip_minus text
|
33
|
+
return unless stripped
|
34
|
+
|
35
|
+
stripped_n = NumbersInWords.in_numbers(stripped, only_compress: only_compress)
|
36
|
+
only_compress ? stripped_n.map { |k| k * -1 } : -1 * stripped_n
|
37
|
+
end
|
38
|
+
|
39
|
+
def mixed_words_and_digits
|
40
|
+
return unless numeric?(that)
|
41
|
+
|
42
|
+
in_words = that.split(' ').map { |word| numeric?(word) ? NumbersInWords.in_words(word) : word }.join(' ')
|
43
|
+
ToNumber.new(in_words, only_compress).call
|
44
|
+
end
|
45
|
+
|
46
|
+
def numeric?(word)
|
47
|
+
word.match(/\d+/)
|
48
|
+
end
|
49
|
+
|
50
|
+
def strip_minus(txt)
|
51
|
+
txt.gsub(/^minus/, '') if txt =~ /^minus/
|
52
|
+
end
|
53
|
+
|
54
|
+
def one
|
55
|
+
one = check_one text
|
56
|
+
|
57
|
+
return unless one
|
58
|
+
|
59
|
+
res = NumbersInWords.in_numbers(one[1])
|
60
|
+
only_compress ? [res] : res
|
61
|
+
end
|
62
|
+
|
63
|
+
def check_one(txt)
|
64
|
+
txt.match(/^one (#{POWERS_RX})$/)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,7 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative './special'
|
4
|
+
require_relative './fraction_parsing'
|
5
|
+
|
3
6
|
module NumbersInWords
|
4
7
|
class ToNumber
|
8
|
+
include FractionParsing
|
5
9
|
extend Forwardable
|
6
10
|
def_delegator :that, :to_s
|
7
11
|
|
@@ -19,65 +23,7 @@ module NumbersInWords
|
|
19
23
|
private
|
20
24
|
|
21
25
|
def special
|
22
|
-
|
23
|
-
negative ||
|
24
|
-
fraction(that) ||
|
25
|
-
mixed_words_and_digits ||
|
26
|
-
one ||
|
27
|
-
mixed
|
28
|
-
end
|
29
|
-
|
30
|
-
def float
|
31
|
-
return text_including_punctuation.to_f if text =~ /^-?\d+(.\d+)?$/
|
32
|
-
end
|
33
|
-
|
34
|
-
def text_including_punctuation
|
35
|
-
to_s.strip
|
36
|
-
end
|
37
|
-
|
38
|
-
def text
|
39
|
-
strip_punctuation text_including_punctuation
|
40
|
-
end
|
41
|
-
|
42
|
-
def negative
|
43
|
-
stripped = strip_minus text
|
44
|
-
return unless stripped
|
45
|
-
|
46
|
-
stripped_n = NumbersInWords.in_numbers(stripped, only_compress: only_compress)
|
47
|
-
only_compress ? stripped_n.map { |k| k * -1 } : -1 * stripped_n
|
48
|
-
end
|
49
|
-
|
50
|
-
def mixed_words_and_digits
|
51
|
-
return unless numeric?(that)
|
52
|
-
|
53
|
-
in_words = that.split(' ').map { |word| numeric?(word) ? NumbersInWords.in_words(word) : word }.join(' ')
|
54
|
-
self.class.new(in_words, only_compress).call
|
55
|
-
end
|
56
|
-
|
57
|
-
def numeric?(word)
|
58
|
-
word.match(/\d+/)
|
59
|
-
end
|
60
|
-
|
61
|
-
def strip_punctuation(text)
|
62
|
-
text = text.downcase.gsub(/[^a-z 0-9]/, ' ')
|
63
|
-
to_remove = true
|
64
|
-
|
65
|
-
to_remove = text.gsub! ' ', ' ' while to_remove
|
66
|
-
|
67
|
-
text
|
68
|
-
end
|
69
|
-
|
70
|
-
def one
|
71
|
-
one = check_one text
|
72
|
-
|
73
|
-
return unless one
|
74
|
-
|
75
|
-
res = NumbersInWords.in_numbers(one[1])
|
76
|
-
only_compress ? [res] : res
|
77
|
-
end
|
78
|
-
|
79
|
-
def mixed
|
80
|
-
check_mixed text
|
26
|
+
Special.new(that, only_compress).call
|
81
27
|
end
|
82
28
|
|
83
29
|
def decimal
|
@@ -107,18 +53,6 @@ module NumbersInWords
|
|
107
53
|
NumbersInWords.exceptional_number(text) || fraction(text) || power(text)
|
108
54
|
end
|
109
55
|
|
110
|
-
def fraction(text)
|
111
|
-
return unless possible_fraction?(text)
|
112
|
-
|
113
|
-
NumbersInWords.exceptional_numbers.lookup_fraction(text)
|
114
|
-
end
|
115
|
-
|
116
|
-
def possible_fraction?(text)
|
117
|
-
words = text.split(' ')
|
118
|
-
result = words & NumbersInWords.exceptional_numbers.fraction_names
|
119
|
-
result.length.positive?
|
120
|
-
end
|
121
|
-
|
122
56
|
def power(text)
|
123
57
|
power = NumbersInWords.power_of_ten(text)
|
124
58
|
|
@@ -136,22 +70,6 @@ module NumbersInWords
|
|
136
70
|
}
|
137
71
|
end
|
138
72
|
|
139
|
-
def check_mixed(txt)
|
140
|
-
mixed = txt.match(/^(-?\d+(.\d+)?) (#{POWERS_RX}s?)$/)
|
141
|
-
return unless mixed && mixed[1] && mixed[3]
|
142
|
-
|
143
|
-
matches = [mixed[1], mixed[3]].map { |m| NumbersInWords.in_numbers m }
|
144
|
-
matches.reduce(&:*)
|
145
|
-
end
|
146
|
-
|
147
|
-
def check_one(txt)
|
148
|
-
txt.match(/^one (#{POWERS_RX})$/)
|
149
|
-
end
|
150
|
-
|
151
|
-
def strip_minus(txt)
|
152
|
-
txt.gsub(/^minus/, '') if txt =~ /^minus/
|
153
|
-
end
|
154
|
-
|
155
73
|
def check_decimal(txt)
|
156
74
|
txt.match(/\spoint\s/)
|
157
75
|
end
|
data/numbers_in_words.gemspec
CHANGED
@@ -7,7 +7,8 @@ require 'numbers_in_words/version'
|
|
7
7
|
Gem::Specification.new do |gem|
|
8
8
|
gem.name = 'numbers_in_words'
|
9
9
|
gem.description = 'convert written numbers into Integers and vice-versa'
|
10
|
-
gem.summary = 'Example: NumbersInWords.in_words(123) # =>
|
10
|
+
gem.summary = 'Example: NumbersInWords.in_words(123) # => ' \
|
11
|
+
'"one hundred and twenty three", NumbersInWords.in_numbers("seventy-five point eight") # = > 75.8'
|
11
12
|
|
12
13
|
gem.version = NumbersInWords::VERSION
|
13
14
|
gem.authors = ['Mark Burns', 'Dimid Duchovny']
|
data/spec/fraction_spec.rb
CHANGED
@@ -1,131 +1,151 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
RSpec.describe NumbersInWords::Fraction do # rubocop: disable Metrics/BlockLength
|
4
|
+
subject do
|
5
|
+
described_class.new(numerator: numerator, denominator: denominator, attributes: attributes)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:numerator) { 1 }
|
9
|
+
|
10
|
+
context 'halves' do
|
11
|
+
let(:denominator) { 2 }
|
12
|
+
let(:attributes) do
|
13
|
+
{ number: 'two',
|
14
|
+
ordinal: 'second',
|
15
|
+
fraction: { singular: 'half', plural: 'halves' } }
|
7
16
|
end
|
8
17
|
|
9
|
-
|
18
|
+
it do
|
19
|
+
expect(subject.in_words).to eq 'one half'
|
20
|
+
end
|
10
21
|
|
11
|
-
context '
|
12
|
-
let(:
|
13
|
-
let(:attributes) do
|
14
|
-
{ number: 'two',
|
15
|
-
ordinal: 'second',
|
16
|
-
fraction: { singular: 'half', plural: 'halves' } }
|
17
|
-
end
|
22
|
+
context 'with plural' do
|
23
|
+
let(:numerator) { 2 }
|
18
24
|
|
19
25
|
it do
|
20
|
-
expect(subject.in_words).to eq '
|
26
|
+
expect(subject.in_words).to eq 'two halves'
|
21
27
|
end
|
28
|
+
end
|
29
|
+
end
|
22
30
|
|
23
|
-
|
24
|
-
|
31
|
+
context 'quarters' do
|
32
|
+
let(:denominator) { 4 }
|
33
|
+
let(:attributes) do
|
34
|
+
{
|
35
|
+
number: 'four',
|
36
|
+
ordinal: 'fourth',
|
37
|
+
fraction: { singular: 'quarter' }
|
38
|
+
}
|
39
|
+
end
|
25
40
|
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
41
|
+
it do
|
42
|
+
expect(subject.in_words).to eq 'one quarter'
|
30
43
|
end
|
44
|
+
end
|
31
45
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
ordinal: 'fourth',
|
38
|
-
fraction: { singular: 'quarter' }
|
39
|
-
}
|
40
|
-
end
|
46
|
+
context 'fifths' do
|
47
|
+
let(:denominator) { 5 }
|
48
|
+
let(:attributes) do
|
49
|
+
{ number: 'five', ordinal: 'fifth' }
|
50
|
+
end
|
41
51
|
|
42
|
-
|
43
|
-
|
44
|
-
end
|
52
|
+
it do
|
53
|
+
expect(subject.in_words).to eq 'one fifth'
|
45
54
|
end
|
55
|
+
end
|
46
56
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
{ number: 'five', ordinal: 'fifth' }
|
51
|
-
end
|
57
|
+
context 'sixths' do
|
58
|
+
let(:denominator) { 6 }
|
59
|
+
let(:attributes) { {} }
|
52
60
|
|
53
|
-
|
54
|
-
|
55
|
-
end
|
61
|
+
it do
|
62
|
+
expect(subject.in_words).to eq 'one sixth'
|
56
63
|
end
|
64
|
+
end
|
57
65
|
|
58
|
-
|
59
|
-
|
60
|
-
|
66
|
+
context 'nineteenths' do
|
67
|
+
let(:denominator) { 19 }
|
68
|
+
let(:attributes) { {} }
|
61
69
|
|
62
|
-
|
63
|
-
|
64
|
-
|
70
|
+
it do
|
71
|
+
expect(subject.in_words).to eq 'one nineteenth'
|
72
|
+
expect(subject.fraction).to eq 'nineteenth'
|
65
73
|
end
|
66
74
|
|
67
|
-
context '
|
68
|
-
let(:
|
69
|
-
let(:attributes) { {} }
|
75
|
+
context 'plural' do
|
76
|
+
let(:numerator) { 763 }
|
70
77
|
|
71
78
|
it do
|
72
|
-
expect(subject.in_words).to eq '
|
73
|
-
expect(subject.fraction).to eq 'nineteenth'
|
79
|
+
expect(subject.in_words).to eq 'seven hundred and sixty-three nineteenths'
|
74
80
|
end
|
81
|
+
end
|
82
|
+
end
|
75
83
|
|
76
|
-
|
77
|
-
|
84
|
+
context 'one hundred and seconds' do
|
85
|
+
let(:denominator) { 102 }
|
86
|
+
let(:attributes) { {} }
|
78
87
|
|
79
|
-
|
80
|
-
|
81
|
-
end
|
82
|
-
end
|
88
|
+
it do
|
89
|
+
expect(subject.in_words).to eq 'one one hundred and second'
|
83
90
|
end
|
91
|
+
end
|
84
92
|
|
85
|
-
|
86
|
-
|
87
|
-
|
93
|
+
context 'one hundred and sixth' do
|
94
|
+
let(:denominator) { 106 }
|
95
|
+
let(:attributes) { {} }
|
88
96
|
|
89
|
-
|
90
|
-
|
91
|
-
end
|
97
|
+
it do
|
98
|
+
expect(subject.in_words).to eq 'one one hundred and sixth'
|
92
99
|
end
|
100
|
+
end
|
93
101
|
|
94
|
-
|
95
|
-
|
96
|
-
|
102
|
+
context 'one hundred and nineteenth' do
|
103
|
+
let(:denominator) { 119 }
|
104
|
+
let(:attributes) { {} }
|
97
105
|
|
98
|
-
|
99
|
-
|
100
|
-
|
106
|
+
it do
|
107
|
+
expect(subject.ordinal).to eq 'one hundred and nineteenth'
|
108
|
+
expect(subject.in_words).to eq 'one one hundred and nineteenth'
|
101
109
|
end
|
110
|
+
end
|
102
111
|
|
103
|
-
|
104
|
-
|
105
|
-
|
112
|
+
context 'one thousandth' do
|
113
|
+
let(:denominator) { 1000 }
|
114
|
+
let(:attributes) { {} }
|
106
115
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
end
|
116
|
+
it do
|
117
|
+
expect(subject.ordinal).to eq 'one thousandth'
|
118
|
+
expect(subject.in_words).to eq 'one one thousandth'
|
111
119
|
end
|
112
120
|
|
113
|
-
context '
|
121
|
+
context 'plural' do
|
122
|
+
let(:numerator) { 2 }
|
114
123
|
let(:denominator) { 1000 }
|
115
|
-
let(:attributes) { {} }
|
116
124
|
|
117
125
|
it do
|
118
|
-
expect(subject.
|
119
|
-
expect(subject.in_words).to eq 'one one thousandth'
|
126
|
+
expect(subject.in_words).to eq 'two thousandths'
|
120
127
|
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'googolplexths' do
|
132
|
+
let(:denominator) { Kernel.silence_warnings { 10**(10**100) } }
|
121
133
|
|
122
|
-
|
123
|
-
|
124
|
-
|
134
|
+
let(:attributes) do
|
135
|
+
{ number: 'googolplex',
|
136
|
+
ordinal: 'googolplexth',
|
137
|
+
fraction: { singular: 'googolplexth', plural: 'googolplexths' } }
|
138
|
+
end
|
139
|
+
|
140
|
+
it do
|
141
|
+
expect(subject.in_words).to eq 'one infinitieth'
|
142
|
+
end
|
125
143
|
|
126
|
-
|
127
|
-
|
128
|
-
|
144
|
+
context 'with plural' do
|
145
|
+
let(:numerator) { 2 }
|
146
|
+
|
147
|
+
it do
|
148
|
+
expect(subject.in_words).to eq 'two infinitieths'
|
129
149
|
end
|
130
150
|
end
|
131
151
|
end
|
data/spec/fractions_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
describe NumbersInWords do
|
4
|
-
|
4
|
+
FRACTION_EXAMPLES = {
|
5
5
|
'half' => 0.5,
|
6
6
|
'a half' => 0.5,
|
7
7
|
'one half' => 0.5,
|
@@ -17,7 +17,7 @@ describe NumbersInWords do
|
|
17
17
|
'three ninety-sevenths' => 3 / 97.0
|
18
18
|
}.freeze
|
19
19
|
|
20
|
-
|
20
|
+
FRACTION_EXAMPLES.each do |string, float|
|
21
21
|
it "#{string} == #{float}" do
|
22
22
|
expect(string.in_numbers).to eql(float)
|
23
23
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe 'NumbersInWords' do
|
5
|
+
describe 'NumbersInWords' do # rubocop: disable Metrics/BlockLength
|
6
6
|
describe '.in_words' do
|
7
7
|
it do
|
8
8
|
expect(NumbersInWords.in_words(100)).to eq 'one hundred'
|
@@ -14,7 +14,7 @@ describe 'NumbersInWords' do
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
FRACTION_TO_WORDS = {
|
18
18
|
[1, 2] => 'one half',
|
19
19
|
[3, 2] => 'three halves',
|
20
20
|
[1, 3] => 'one third',
|
@@ -30,9 +30,9 @@ describe 'NumbersInWords' do
|
|
30
30
|
[13, 97] => 'thirteen ninety-sevenths'
|
31
31
|
}.freeze
|
32
32
|
|
33
|
-
|
33
|
+
FRACTION_TO_WORDS.each do |(numerator, denominator), string|
|
34
34
|
it "#{numerator}/#{denominator} == #{string}" do
|
35
|
-
expect(NumbersInWords.in_words(numerator.to_f / denominator
|
35
|
+
expect(NumbersInWords.in_words(numerator.to_f / denominator, fraction: true)).to eql(string)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
data/spec/number_parser_spec.rb
CHANGED
@@ -23,38 +23,6 @@ describe NumbersInWords::NumberParser do
|
|
23
23
|
it { expect(subject).to eq 1600 }
|
24
24
|
end
|
25
25
|
|
26
|
-
pending 'with fractions' do
|
27
|
-
context 'with only denominator' do
|
28
|
-
let(:number) { [0.5] }
|
29
|
-
it { expect(subject).to eq 0.5 }
|
30
|
-
end
|
31
|
-
|
32
|
-
context 'with numerator denominator' do
|
33
|
-
let(:number) { [1, 0.5] }
|
34
|
-
it { expect(subject).to eq 0.5 }
|
35
|
-
end
|
36
|
-
|
37
|
-
context 'with multiple denominator' do
|
38
|
-
let(:number) { [3, 0.5] }
|
39
|
-
it { expect(subject).to eq 1.5 }
|
40
|
-
end
|
41
|
-
|
42
|
-
context 'with tens denominator' do
|
43
|
-
let(:number) { [2, 3, 0.5] }
|
44
|
-
pending { expect(subject).to eq 21.5 }
|
45
|
-
end
|
46
|
-
|
47
|
-
context 'with invalid number' do
|
48
|
-
let(:number) { [2, 1, 0.5, 1] }
|
49
|
-
it { expect { subject }.to raise_error NumbersInWords::InvalidNumber }
|
50
|
-
end
|
51
|
-
|
52
|
-
context 'with numerator and denominator' do
|
53
|
-
let(:number) { [2, 0.5] }
|
54
|
-
it { expect(subject).to eq 1.0 }
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
26
|
context 'with hundreds' do
|
59
27
|
let(:number) { [2, 100, 45] }
|
60
28
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require './spec/spec_helper'
|
4
4
|
|
5
|
-
describe NumbersInWords do
|
5
|
+
describe NumbersInWords do # rubocop: disable Metrics/BlockLength
|
6
6
|
describe '.in_words' do
|
7
7
|
it do
|
8
8
|
expect(NumbersInWords.in_words(100)).to eq 'one hundred'
|
@@ -66,7 +66,8 @@ describe NumbersInWords do
|
|
66
66
|
it 'should handle a googol and larger' do
|
67
67
|
googol = 10**100
|
68
68
|
expect((googol + 1).in_words).to eq('one googol and one')
|
69
|
-
expect((42 * googol + 16_777_216).in_words)
|
69
|
+
expect((42 * googol + 16_777_216).in_words)
|
70
|
+
.to eq('forty-two googol sixteen million seven hundred and seventy-seven thousand two hundred and sixteen')
|
70
71
|
expect((42 * googol * googol).in_words).to eq('forty-two googol googol')
|
71
72
|
end
|
72
73
|
|
@@ -77,7 +78,10 @@ describe NumbersInWords do
|
|
77
78
|
expect(-15.in_words).to eq('minus fifteen')
|
78
79
|
expect(-100.in_words).to eq('minus one hundred')
|
79
80
|
expect((-1 * (10**100)).in_words).to eq('minus one googol')
|
80
|
-
|
81
|
+
|
82
|
+
expect(-123_456_789.in_words)
|
83
|
+
.to eq('minus one hundred and twenty-three million four hundred and ' \
|
84
|
+
'fifty-six thousand seven hundred and eighty-nine')
|
81
85
|
end
|
82
86
|
|
83
87
|
it 'should handle decimals' do
|
@@ -87,7 +91,9 @@ describe NumbersInWords do
|
|
87
91
|
expect(1.1.in_words).to match(/one point one/)
|
88
92
|
expect(1.2345678.in_words).to match(/one point two three four five six seven eight/)
|
89
93
|
expect(1000.2345678.in_words).to match(/one thousand point two three four five six seven eight/)
|
90
|
-
expect(12_345.2345678.in_words)
|
94
|
+
expect(12_345.2345678.in_words)
|
95
|
+
.to match(/twelve thousand three hundred and forty-five point two three four five six seven eight/)
|
96
|
+
|
91
97
|
expect((10**9 + 0.1).in_words).to match(/one billion point one/)
|
92
98
|
end
|
93
99
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
if ENV['CC_TEST_REPORTER_ID']
|
4
|
+
require 'simplecov'
|
5
|
+
SimpleCov.start
|
6
|
+
end
|
7
|
+
|
8
|
+
unless Kernel.method_defined?(:silence_warnings)
|
9
|
+
module Kernel
|
10
|
+
def silence_warnings
|
11
|
+
with_warnings(nil) { yield }
|
12
|
+
end
|
13
|
+
|
14
|
+
def with_warnings(flag)
|
15
|
+
old_verbose = $VERBOSE
|
16
|
+
$VERBOSE = flag
|
17
|
+
yield
|
18
|
+
ensure
|
19
|
+
$VERBOSE = old_verbose
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
3
24
|
require 'numbers_in_words'
|
4
25
|
require 'numbers_in_words/duck_punch'
|
5
26
|
require 'byebug'
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require './spec/spec_helper'
|
4
4
|
|
5
|
-
describe NumbersInWords::StringExtension do
|
5
|
+
describe NumbersInWords::StringExtension do # rubocop: disable Metrics/BlockLength
|
6
6
|
it 'should do the digits 0-10' do
|
7
7
|
expect('zero'.in_numbers).to eq(0)
|
8
8
|
expect('one'.in_numbers).to eq(1)
|
@@ -101,7 +101,7 @@ describe NumbersInWords::StringExtension do
|
|
101
101
|
expect("FIVE,,./';';';[] Million, three hundred and fifty-seVen Thousand".in_numbers).to eq(5_357_000)
|
102
102
|
end
|
103
103
|
|
104
|
-
it 'should handle decimal points' do
|
104
|
+
it 'should handle decimal points' do # rubocop: disable Metrics/BlockLength
|
105
105
|
expect('one point one'.in_numbers).to eq(1.1)
|
106
106
|
|
107
107
|
expect('zero point seven six five three four'.in_numbers).to eq(0.76534)
|
@@ -130,9 +130,11 @@ describe NumbersInWords::StringExtension do
|
|
130
130
|
eight nine five six four three two one eight nine five six seven eight
|
131
131
|
NUMBER
|
132
132
|
|
133
|
+
# rubocop: disable Metrics/LineLength
|
133
134
|
expect(long_number.in_numbers).to eq(
|
134
135
|
9_777_059_160_806_736_471_970_632_827_836_952_710_801_948_705_683_106_707_757_426_795_746_813_127_465_237_139_153_046_752_803_093_791.89564321895678
|
135
136
|
)
|
137
|
+
# rubocop: enable Metrics/LineLength
|
136
138
|
|
137
139
|
expect('seventy five point eight four three two seven six nine four five one eight'
|
138
140
|
.in_numbers).to eq(75.84327694518)
|
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
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Burns
|
@@ -64,11 +64,13 @@ files:
|
|
64
64
|
- lib/numbers_in_words/exceptional_numbers.rb
|
65
65
|
- lib/numbers_in_words/fraction.rb
|
66
66
|
- lib/numbers_in_words/number_group.rb
|
67
|
+
- lib/numbers_in_words/parsing/fraction_parsing.rb
|
67
68
|
- lib/numbers_in_words/parsing/number_parser.rb
|
68
69
|
- lib/numbers_in_words/parsing/pair_parsing.rb
|
69
70
|
- lib/numbers_in_words/parsing/parse_fractions.rb
|
70
71
|
- lib/numbers_in_words/parsing/parse_individual_number.rb
|
71
72
|
- lib/numbers_in_words/parsing/parse_status.rb
|
73
|
+
- lib/numbers_in_words/parsing/special.rb
|
72
74
|
- lib/numbers_in_words/parsing/to_number.rb
|
73
75
|
- lib/numbers_in_words/powers_of_ten.rb
|
74
76
|
- lib/numbers_in_words/to_word.rb
|