numbers_in_words 0.2.0 → 0.3.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 +7 -0
- data/.codeclimate.yml +12 -0
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.rubocop.yml +1171 -0
- data/.travis.yml +7 -0
- data/Gemfile +1 -0
- data/README.md +34 -47
- data/bin/spec +2 -0
- data/lib/numbers_in_words.rb +9 -0
- data/lib/numbers_in_words/duck_punch.rb +2 -2
- data/lib/numbers_in_words/english/language_writer_english.rb +10 -8
- data/lib/numbers_in_words/number_parser.rb +1 -1
- data/lib/numbers_in_words/version.rb +1 -1
- data/numbers_in_words.gemspec +1 -2
- data/spec/language_writer_spec.rb +6 -6
- data/spec/non_monkey_patch_spec.rb +26 -0
- data/spec/number_group_spec.rb +7 -7
- data/spec/numbers_in_words_spec.rb +65 -38
- data/spec/spec_helper.rb +4 -0
- data/spec/words_in_numbers_spec.rb +72 -71
- metadata +29 -50
- data/Gemfile.lock +0 -39
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,14 @@
|
|
1
|
+
[](https://travis-ci.org/markburns/numbers_in_words)
|
2
|
+
[](https://gemnasium.com/markburns/numbers_in_words)
|
3
|
+
[](https://codeclimate.com/github/markburns/numbers_in_words)
|
4
|
+
[](https://rubygems.org/gems/numbers_in_words)
|
5
|
+
[](http://markburns.mit-license.org)
|
6
|
+
[](https://github.com/badges/badgerbadgerbadger)
|
7
|
+
|
1
8
|
Installation
|
2
9
|
============
|
3
10
|
|
4
|
-
```
|
11
|
+
```ruby
|
5
12
|
gem 'numbers_in_words'
|
6
13
|
|
7
14
|
require 'numbers_in_words'
|
@@ -11,32 +18,24 @@ require 'numbers_in_words/duck_punch' #see why later
|
|
11
18
|
This project was created for a test for a job interview. I haven't really used
|
12
19
|
it myself, but I saw it mentioned somewhere so I thought I'd tidy it up a bit.
|
13
20
|
|
14
|
-
|
15
|
-
|
16
|
-
You've got one of:
|
21
|
+
Usage
|
22
|
+
=========
|
17
23
|
|
18
|
-
```
|
19
|
-
|
20
|
-
NoMethodError: undefined method `in_numbers' for "123":String
|
21
|
-
```
|
24
|
+
```ruby
|
25
|
+
require 'numbers_in_words'
|
22
26
|
|
23
|
-
|
24
|
-
|
27
|
+
NumbersInWords.in_words(112)
|
28
|
+
#=> one hundred and twelve
|
25
29
|
|
26
|
-
|
27
|
-
|
28
|
-
with:
|
30
|
+
NumbersInWords.in_numbers(112)
|
31
|
+
#=>10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
require 'numbers_in_words/duck_punch'
|
33
|
+
NumbersInWords.in_numbers("Seventy million, five-hundred and fifty six thousand point eight nine three")
|
34
|
+
#=> 70556000.893
|
33
35
|
```
|
34
36
|
|
35
|
-
Plus it now only adds a single `#in_words` method to `Numeric` and an `#in_numbers`
|
36
|
-
method to `String` instead of a whole bunch of them.
|
37
37
|
|
38
|
-
|
39
|
-
=========
|
38
|
+
Monkey patch version
|
40
39
|
|
41
40
|
```ruby
|
42
41
|
require 'numbers_in_words'
|
@@ -51,42 +50,30 @@ require 'numbers_in_words/duck_punch'
|
|
51
50
|
#=> 70556000.893
|
52
51
|
```
|
53
52
|
|
54
|
-
---------------
|
55
|
-
|
56
|
-
Whilst creating this project I realized that in English:
|
57
|
-
|
58
|
-
* Numbers are grouped in groups of threes
|
59
|
-
* Numbers less than 1,000 are grouped by hundreds and then by tens
|
60
|
-
* There are specific rules for when we put an "and" in between numbers
|
61
53
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
as the key and the multiplier as the value. E.g:
|
54
|
+
NoMethodError `in_words` or `in_numbers`
|
55
|
+
----------
|
56
|
+
I'm going to hopefully preempt some support queries by predicting this will happen:
|
66
57
|
|
67
|
-
|
68
|
-
31245.groups_of(3)
|
69
|
-
#=> {0=>245,3=>31} #i.e. 31 thousands, and 245 ones
|
58
|
+
You've got one of:
|
70
59
|
|
71
|
-
|
72
|
-
|
60
|
+
```
|
61
|
+
NoMethodError: undefined method `in_words' for 123:Fixnum
|
62
|
+
NoMethodError: undefined method `in_numbers' for "123":String
|
73
63
|
```
|
74
64
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
Example of usage:
|
65
|
+
Previous versions of this gem duckpunched Fixnum and String with a whole bunch
|
66
|
+
of methods. This gem will now only add methods if you specifically tell it to
|
67
|
+
with:
|
79
68
|
|
80
69
|
```ruby
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
70
|
+
require 'numbers_in_words'
|
71
|
+
require 'numbers_in_words/duck_punch'
|
72
|
+
```
|
85
73
|
|
86
|
-
|
87
|
-
|
74
|
+
Plus it now only adds a single `#in_words` method to `Numeric` and an `#in_numbers`
|
75
|
+
method to `String` instead of a whole bunch of them.
|
88
76
|
|
89
|
-
```
|
90
77
|
|
91
78
|
Future plans
|
92
79
|
============
|
data/bin/spec
ADDED
data/lib/numbers_in_words.rb
CHANGED
@@ -16,9 +16,18 @@ module NumbersInWords
|
|
16
16
|
|
17
17
|
class << self
|
18
18
|
attr_writer :language
|
19
|
+
|
19
20
|
def language
|
20
21
|
@language ||= "English"
|
21
22
|
end
|
23
|
+
|
24
|
+
def in_words(i, language=NumbersInWords.language)
|
25
|
+
NumbersInWords::ToWord.new(i, language).in_words
|
26
|
+
end
|
27
|
+
|
28
|
+
def in_numbers(s, language=NumbersInWords.language)
|
29
|
+
NumbersInWords::ToNumber.new(s, language).in_numbers
|
30
|
+
end
|
22
31
|
end
|
23
32
|
end
|
24
33
|
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module NumbersInWords
|
2
2
|
def in_words language=NumbersInWords.language
|
3
|
-
NumbersInWords
|
3
|
+
NumbersInWords.in_words(self, language)
|
4
4
|
end
|
5
5
|
end
|
6
6
|
|
7
7
|
module WordsInNumbers
|
8
8
|
def in_numbers language=NumbersInWords.language
|
9
|
-
NumbersInWords
|
9
|
+
NumbersInWords.in_numbers(self, language)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -9,7 +9,7 @@ module NumbersInWords
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def negative
|
12
|
-
"minus " + (-@that)
|
12
|
+
"minus " + NumbersInWords.in_words(-@that)
|
13
13
|
end
|
14
14
|
|
15
15
|
def in_words
|
@@ -33,13 +33,12 @@ module NumbersInWords
|
|
33
33
|
|
34
34
|
digit = number - tens #write the digits
|
35
35
|
|
36
|
-
output << " " +
|
36
|
+
output << " " + NumbersInWords.in_words(digit) unless digit==0
|
37
37
|
else
|
38
38
|
output << write() #longer numbers
|
39
39
|
end
|
40
40
|
|
41
41
|
output.strip
|
42
|
-
|
43
42
|
end
|
44
43
|
|
45
44
|
def handle_exception
|
@@ -67,24 +66,27 @@ module NumbersInWords
|
|
67
66
|
def decimals
|
68
67
|
int, decimals = NumberGroup.new(@that).split_decimals
|
69
68
|
if int
|
70
|
-
out =
|
69
|
+
out = NumbersInWords.in_words(int) + " point "
|
71
70
|
decimals.each do |decimal|
|
72
|
-
out << decimal.to_i
|
71
|
+
out << NumbersInWords.in_words(decimal.to_i) + " "
|
73
72
|
end
|
74
73
|
out.strip
|
75
74
|
end
|
76
75
|
end
|
77
76
|
|
78
77
|
private
|
78
|
+
|
79
79
|
def write_googols
|
80
80
|
googols, remainder = NumberGroup.new(@that).split_googols
|
81
81
|
output = ""
|
82
|
-
|
82
|
+
|
83
|
+
output << " " + NumbersInWords.in_words(googols) + " googol"
|
83
84
|
if remainder > 0
|
84
85
|
prefix = " "
|
85
86
|
prefix << "and " if remainder < 100
|
86
|
-
output << prefix +
|
87
|
+
output << prefix + NumbersInWords.in_words(remainder)
|
87
88
|
end
|
89
|
+
|
88
90
|
output
|
89
91
|
end
|
90
92
|
|
@@ -96,7 +98,7 @@ module NumbersInWords
|
|
96
98
|
prefix = " "
|
97
99
|
#no and between thousands and hundreds
|
98
100
|
prefix << "and " if power == 0 and digits < 100
|
99
|
-
output << prefix +
|
101
|
+
output << prefix + NumbersInWords.in_words(digits)
|
100
102
|
output << prefix + name unless power == 0
|
101
103
|
end
|
102
104
|
end
|
data/numbers_in_words.gemspec
CHANGED
@@ -14,8 +14,7 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.homepage = "http://github.com/markburns/numbers_in_words"
|
15
15
|
|
16
16
|
gem.add_dependency "activesupport"
|
17
|
-
gem.add_development_dependency "rspec"
|
18
|
-
gem.add_development_dependency "debugger"
|
17
|
+
gem.add_development_dependency "rspec", "~> 3.4.0"
|
19
18
|
|
20
19
|
gem.files = `git ls-files`.split($/)
|
21
20
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
@@ -7,13 +7,13 @@ describe NumbersInWords::English::LanguageWriterEnglish do
|
|
7
7
|
@writer.group_words(3) do |power, name, digits|
|
8
8
|
case count
|
9
9
|
when 0
|
10
|
-
power.
|
11
|
-
name.
|
12
|
-
digits.
|
10
|
+
expect(power).to eq(3)
|
11
|
+
expect(name).to eq("thousand")
|
12
|
+
expect(digits).to eq(2)
|
13
13
|
when 1
|
14
|
-
power.
|
15
|
-
name.
|
16
|
-
digits.
|
14
|
+
expect(power).to eq(0)
|
15
|
+
expect(name).to eq("one")
|
16
|
+
expect(digits).to eq(111)
|
17
17
|
end
|
18
18
|
count += 1
|
19
19
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'numbers_in_words'
|
2
|
+
|
3
|
+
describe "NumbersInWords" do
|
4
|
+
describe ".in_words" do
|
5
|
+
it do
|
6
|
+
expect(NumbersInWords.in_words(100)).to eq "one hundred"
|
7
|
+
expect(NumbersInWords.in_words(-100)).to eq "minus one hundred"
|
8
|
+
expect(NumbersInWords.in_words(24)).to eq "twenty four"
|
9
|
+
expect(NumbersInWords.in_words(1.2)).to eq "one point two"
|
10
|
+
expect(NumbersInWords.in_words(100*10**100)).to eq "one hundred googol"
|
11
|
+
expect(NumbersInWords.in_words(30 + 100*10**100)).to eq "one hundred googol and thirty"
|
12
|
+
end
|
13
|
+
|
14
|
+
pending "This should be implemented" do
|
15
|
+
expect(NumbersInWords.in_words(100*10**100)).to eq "one hundred googols"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".in_numbers" do
|
20
|
+
it do
|
21
|
+
expect(NumbersInWords.in_numbers("one hundred")).to eq 100
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
data/spec/number_group_spec.rb
CHANGED
@@ -4,13 +4,13 @@ describe NumbersInWords::NumberGroup do
|
|
4
4
|
it "should split into group of three digit numbers" do
|
5
5
|
g = Numeric::NumberGroup
|
6
6
|
|
7
|
-
g.groups_of(1 ,3 ).
|
8
|
-
g.groups_of(12 ,3 ).
|
9
|
-
g.groups_of(123 ,3 ).
|
10
|
-
g.groups_of(1111 ,3 ).
|
11
|
-
g.groups_of(87654 ,3 ).
|
12
|
-
g.groups_of(1_234_567 ,3 ).
|
13
|
-
g.groups_of(123_456_789_101_112 ,3 ).
|
7
|
+
expect(g.groups_of(1 ,3 )).to eq({0=>1 })
|
8
|
+
expect(g.groups_of(12 ,3 )).to eq({0=>12 })
|
9
|
+
expect(g.groups_of(123 ,3 )).to eq({0=>123 })
|
10
|
+
expect(g.groups_of(1111 ,3 )).to eq({3=>1 , 0=>111 })
|
11
|
+
expect(g.groups_of(87654 ,3 )).to eq({3=>87 , 0=>654 })
|
12
|
+
expect(g.groups_of(1_234_567 ,3 )).to eq({6=>1 , 3=>234 , 0=>567 })
|
13
|
+
expect(g.groups_of(123_456_789_101_112 ,3 )).to eq({12=>123 , 9=>456 , 6=>789 , 3=>101 , 0=>112 })
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -1,79 +1,106 @@
|
|
1
1
|
require './spec/spec_helper'
|
2
2
|
|
3
3
|
describe NumbersInWords do
|
4
|
+
describe ".language" do
|
5
|
+
after do
|
6
|
+
NumbersInWords.instance_variable_set(:"@language", nil)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "has a default value" do
|
10
|
+
expect(NumbersInWords.language).to eq "English"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "can be set" do
|
14
|
+
NumbersInWords.language = "some language"
|
15
|
+
expect(NumbersInWords.language).to eq "some language"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".in_words" do
|
20
|
+
it do
|
21
|
+
expect(NumbersInWords.in_words(100)).to eq "one hundred"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe ".in_numbers" do
|
26
|
+
it do
|
27
|
+
expect(NumbersInWords.in_numbers("one hundred")).to eq 100
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
4
31
|
it "should print the digits 0-9 correctly" do
|
5
32
|
numbers = %w[zero one two three four five six seven eight nine]
|
6
33
|
|
7
|
-
10.times { |i| i.in_words.
|
34
|
+
10.times { |i| expect(i.in_words).to eq(numbers[i]) }
|
8
35
|
end
|
9
36
|
|
10
37
|
it "should print the digits 11-19 correctly" do
|
11
38
|
words = %w[eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen]
|
12
39
|
numbers = [11,12,13,14,15,16,17,18,19]
|
13
40
|
numbers.each_with_index do |number, index|
|
14
|
-
number.in_words.
|
41
|
+
expect(number.in_words).to eq(words[index])
|
15
42
|
|
16
43
|
end
|
17
44
|
end
|
18
45
|
|
19
46
|
it "should handle two digit numbers" do
|
20
|
-
21.in_words.
|
47
|
+
expect(21.in_words). to eq("twenty one")
|
21
48
|
end
|
22
49
|
|
23
50
|
it "should handle three digit numbers" do
|
24
|
-
113.in_words.
|
25
|
-
299.in_words.
|
26
|
-
300.in_words.
|
27
|
-
101.in_words.
|
51
|
+
expect(113.in_words). to eq("one hundred and thirteen")
|
52
|
+
expect(299.in_words). to eq("two hundred and ninety nine")
|
53
|
+
expect(300.in_words). to eq("three hundred")
|
54
|
+
expect(101.in_words). to eq("one hundred and one")
|
28
55
|
end
|
29
56
|
|
30
57
|
it "should print out some random examples correctly" do
|
31
|
-
2999 .in_words.
|
32
|
-
99999 .in_words.
|
33
|
-
999999 .in_words.
|
34
|
-
123456 .in_words.
|
35
|
-
17054 .in_words.
|
36
|
-
11004 .in_words.
|
37
|
-
470154 .in_words.
|
38
|
-
417155 .in_words.
|
39
|
-
999999 .in_words.
|
40
|
-
1000000 .in_words.
|
41
|
-
1000001 .in_words.
|
42
|
-
112 .in_words.
|
58
|
+
expect(2999 .in_words). to eq("two thousand nine hundred and ninety nine")
|
59
|
+
expect(99999 .in_words). to eq("ninety nine thousand nine hundred and ninety nine")
|
60
|
+
expect(999999 .in_words). to eq("nine hundred and ninety nine thousand nine hundred and ninety nine")
|
61
|
+
expect(123456 .in_words). to eq("one hundred and twenty three thousand four hundred and fifty six")
|
62
|
+
expect(17054 .in_words). to eq("seventeen thousand and fifty four")
|
63
|
+
expect(11004 .in_words). to eq("eleven thousand and four")
|
64
|
+
expect(470154 .in_words). to eq("four hundred and seventy thousand one hundred and fifty four")
|
65
|
+
expect(417155 .in_words). to eq("four hundred and seventeen thousand one hundred and fifty five")
|
66
|
+
expect(999999 .in_words). to eq("nine hundred and ninety nine thousand nine hundred and ninety nine")
|
67
|
+
expect(1000000 .in_words). to eq("one million")
|
68
|
+
expect(1000001 .in_words). to eq("one million and one")
|
69
|
+
expect(112 .in_words). to eq("one hundred and twelve")
|
43
70
|
end
|
44
71
|
|
45
72
|
it "should handle edge cases" do
|
46
|
-
1000001 .in_words.
|
47
|
-
(10*10**12 + 10**6 +1) .in_words.
|
48
|
-
(10**75) .in_words.
|
49
|
-
10001001 .in_words.
|
73
|
+
expect(1000001 .in_words). to eq("one million and one")
|
74
|
+
expect((10*10**12 + 10**6 +1) .in_words). to eq("ten trillion one million and one")
|
75
|
+
expect((10**75) .in_words). to eq("one quattuorvigintillion")
|
76
|
+
expect(10001001 .in_words). to eq("ten million one thousand and one")
|
50
77
|
end
|
51
78
|
|
52
79
|
it "should handle a googol and larger" do
|
53
80
|
n=10**100
|
54
|
-
(10**100 + 1) .in_words.
|
55
|
-
(42*10**100 + 16777216).in_words.
|
56
|
-
(42* 10**100 * 10**100).in_words.
|
81
|
+
expect((10**100 + 1) .in_words). to eq("one googol and one")
|
82
|
+
expect((42*10**100 + 16777216).in_words). to eq("forty two googol sixteen million seven hundred and seventy seven thousand two hundred and sixteen")
|
83
|
+
expect((42* 10**100 * 10**100).in_words). to eq("forty two googol googol")
|
57
84
|
end
|
58
85
|
|
59
86
|
it "should handle negative numbers" do
|
60
|
-
-1 .in_words.
|
61
|
-
-9 .in_words.
|
62
|
-
-10 .in_words.
|
63
|
-
-15 .in_words.
|
64
|
-
-100 .in_words.
|
65
|
-
(-1*(10**100)).in_words.
|
66
|
-
-123456789 .in_words.
|
87
|
+
expect(-1 .in_words).to eq("minus one")
|
88
|
+
expect(-9 .in_words).to eq("minus nine")
|
89
|
+
expect(-10 .in_words).to eq("minus ten")
|
90
|
+
expect(-15 .in_words).to eq("minus fifteen")
|
91
|
+
expect(-100 .in_words).to eq("minus one hundred")
|
92
|
+
expect((-1*(10**100)).in_words).to eq("minus one googol")
|
93
|
+
expect(-123456789 .in_words).to eq("minus one hundred and twenty three million four hundred and fifty six thousand seven hundred and eighty nine")
|
67
94
|
end
|
68
95
|
|
69
96
|
it "should handle decimals" do
|
70
97
|
#because of lack of absolute accuracy with floats
|
71
98
|
#the output won't be exactly as you might expect
|
72
99
|
#so we will match rather than find equivalents
|
73
|
-
1.1 .in_words.
|
74
|
-
1.2345678 .in_words.
|
75
|
-
1000.2345678 .in_words.
|
76
|
-
12345.2345678.in_words.
|
77
|
-
(10**9 + 0.1).in_words.
|
100
|
+
expect(1.1 .in_words).to match(/one point one/)
|
101
|
+
expect(1.2345678 .in_words).to match(/one point two three four five six seven eight/)
|
102
|
+
expect(1000.2345678 .in_words).to match(/one thousand point two three four five six seven eight/)
|
103
|
+
expect(12345.2345678.in_words).to match(/twelve thousand three hundred and forty five point two three four five six seven eight/)
|
104
|
+
expect((10**9 + 0.1).in_words).to match(/one billion point one/)
|
78
105
|
end
|
79
106
|
end
|