numbers_in_words 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|