numbers_in_words 0.2.0 → 0.5.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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +14 -0
  3. data/.gitignore +2 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +58 -0
  6. data/.travis.yml +15 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +50 -26
  9. data/README.md +20 -70
  10. data/Rakefile +3 -1
  11. data/bin/spec +2 -0
  12. data/lib/numbers_in_words.rb +49 -15
  13. data/lib/numbers_in_words/duck_punch.rb +12 -8
  14. data/lib/numbers_in_words/exceptional_numbers.rb +115 -0
  15. data/lib/numbers_in_words/fraction.rb +136 -0
  16. data/lib/numbers_in_words/number_group.rb +34 -25
  17. data/lib/numbers_in_words/parsing/fraction_parsing.rb +34 -0
  18. data/lib/numbers_in_words/parsing/number_parser.rb +98 -0
  19. data/lib/numbers_in_words/parsing/pair_parsing.rb +64 -0
  20. data/lib/numbers_in_words/parsing/parse_fractions.rb +45 -0
  21. data/lib/numbers_in_words/parsing/parse_individual_number.rb +68 -0
  22. data/lib/numbers_in_words/parsing/parse_status.rb +17 -0
  23. data/lib/numbers_in_words/parsing/special.rb +67 -0
  24. data/lib/numbers_in_words/parsing/to_number.rb +77 -0
  25. data/lib/numbers_in_words/powers_of_ten.rb +49 -0
  26. data/lib/numbers_in_words/to_word.rb +78 -13
  27. data/lib/numbers_in_words/version.rb +3 -1
  28. data/lib/numbers_in_words/writer.rb +69 -0
  29. data/numbers_in_words.gemspec +15 -14
  30. data/spec/exceptional_numbers_spec.rb +26 -0
  31. data/spec/fraction_spec.rb +152 -0
  32. data/spec/fractions_spec.rb +31 -0
  33. data/spec/non_monkey_patch_spec.rb +51 -0
  34. data/spec/number_group_spec.rb +12 -12
  35. data/spec/number_parser_spec.rb +31 -0
  36. data/spec/numbers_in_words_spec.rb +74 -54
  37. data/spec/numerical_strings_spec.rb +35 -0
  38. data/spec/spec_helper.rb +24 -0
  39. data/spec/to_word_spec.rb +18 -0
  40. data/spec/words_in_numbers_spec.rb +135 -117
  41. data/spec/writer_spec.rb +26 -0
  42. data/spec/years_spec.rb +27 -0
  43. metadata +61 -59
  44. data/lib/numbers_in_words/english/constants.rb +0 -93
  45. data/lib/numbers_in_words/english/language_writer_english.rb +0 -107
  46. data/lib/numbers_in_words/language_writer.rb +0 -31
  47. data/lib/numbers_in_words/number_parser.rb +0 -81
  48. data/lib/numbers_in_words/to_number.rb +0 -82
  49. data/spec/language_writer_spec.rb +0 -23
@@ -1,93 +0,0 @@
1
- module NumbersInWords
2
- module English
3
- def self.exceptions
4
- {
5
- 0 => "zero",
6
- 1 => "one",
7
- 2 => "two",
8
- 3 => "three",
9
- 4 => "four",
10
- 5 => "five",
11
- 6 => "six",
12
- 7 => "seven",
13
- 8 => "eight",
14
- 9 => "nine",
15
-
16
- 10 => "ten",
17
- 11 => "eleven",
18
- 12 => "twelve",
19
-
20
- 13 => "thirteen",
21
- 14 => "fourteen",
22
- 15 => "fifteen",
23
- 16 => "sixteen" ,
24
- 17 => "seventeen",
25
- 18 => "eighteen",
26
- 19 => "nineteen",
27
-
28
- 20 => "twenty",
29
- 30 => "thirty",
30
- 40 => "forty",
31
- 50 => "fifty",
32
- 60 => "sixty",
33
- 70 => "seventy",
34
- 80 => "eighty",
35
- 90 => "ninety"
36
- }
37
- end
38
-
39
- def self.swap_keys hsh
40
- hsh.inject({}){|h,(k,v)| h[v]=k; h}
41
- end
42
-
43
- def self.powers_of_ten
44
- {
45
- 0 => "one",
46
- 1 => "ten",
47
- 2 => "hundred",
48
- 3 => "thousand",
49
- 6 => "million",
50
- 9 => "billion",
51
- 12 => "trillion",
52
- 15 => "quadrillion",
53
- 18 => "quintillion",
54
- 21 => "sextillion",
55
- 24 => "septillion",
56
- 27 => "octillion",
57
- 30 => "nonillion",
58
- 33 => "decillion",
59
- 36 => "undecillion",
60
- 39 => "duodecillion",
61
- 42 => "tredecillion",
62
- 45 => "quattuordecillion",
63
- 48 => "quindecillion",
64
- 51 => "sexdecillion",
65
- 54 => "septendecillion",
66
- 57 => "octodecillion",
67
- 60 => "novemdecillion",
68
- 63 => "vigintillion",
69
- 66 => "unvigintillion",
70
- 69 => "duovigintillion",
71
- 72 => "trevigintillion",
72
- 75 => "quattuorvigintillion",
73
- 78 => "quinvigintillion",
74
- 81 => "sexvigintillion",
75
- 84 => "septenvigintillion",
76
- 87 => "octovigintillion",
77
- 90 => "novemvigintillion",
78
- 93 => "trigintillion",
79
- 96 => "untrigintillion",
80
- 99 => "duotrigintillion",
81
- 100 => "googol"
82
- }
83
- end
84
-
85
- def self.exceptions_to_i
86
- swap_keys exceptions
87
- end
88
-
89
- def self.powers_of_ten_to_i
90
- swap_keys powers_of_ten
91
- end
92
- end
93
- end
@@ -1,107 +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 " + (-@that).in_words
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
- length = number.to_s.length
27
- output = ""
28
-
29
- if length == 2 #20-99
30
- tens = (number/10).round*10 #write the tens
31
-
32
- output << exceptions[tens] # e.g. eighty
33
-
34
- digit = number - tens #write the digits
35
-
36
- output << " " + digit.in_words unless digit==0
37
- else
38
- output << write() #longer numbers
39
- end
40
-
41
- output.strip
42
-
43
- end
44
-
45
- def handle_exception
46
- exceptions[@that] if @that.is_a?(Integer) and exceptions[@that]
47
- end
48
-
49
-
50
- def write
51
- length = @that.to_s.length
52
- output =
53
- if length == 3
54
- #e.g. 113 splits into "one hundred" and "thirteen"
55
- write_groups(2)
56
-
57
- #more than one hundred less than one googol
58
- elsif length < LENGTH_OF_GOOGOL
59
- write_groups(3)
60
-
61
- elsif length >= LENGTH_OF_GOOGOL
62
- write_googols
63
- end
64
- output.strip
65
- end
66
-
67
- def decimals
68
- int, decimals = NumberGroup.new(@that).split_decimals
69
- if int
70
- out = int.in_words + " point "
71
- decimals.each do |decimal|
72
- out << decimal.to_i.in_words + " "
73
- end
74
- out.strip
75
- end
76
- end
77
-
78
- private
79
- def write_googols
80
- googols, remainder = NumberGroup.new(@that).split_googols
81
- output = ""
82
- output << " " + googols.in_words + " googol"
83
- if remainder > 0
84
- prefix = " "
85
- prefix << "and " if remainder < 100
86
- output << prefix + remainder.in_words
87
- end
88
- output
89
- end
90
-
91
- def write_groups group
92
- #e.g. 113 splits into "one hundred" and "thirteen"
93
- output = ""
94
- group_words(group) do |power, name, digits|
95
- if digits > 0
96
- prefix = " "
97
- #no and between thousands and hundreds
98
- prefix << "and " if power == 0 and digits < 100
99
- output << prefix + digits.in_words
100
- output << prefix + name unless power == 0
101
- end
102
- end
103
- output
104
- end
105
- end
106
- end
107
- end
@@ -1,31 +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
-
19
- def group_words size
20
- #1000 and over Numbers are split into groups of three
21
- groups = NumberGroup.groups_of @that, size
22
- powers = groups.keys.sort.reverse #put in descending order
23
-
24
- powers.each do |power|
25
- name = powers_of_ten[power]
26
- digits = groups[power]
27
- yield power, name, digits
28
- end
29
- end
30
- end
31
- end
@@ -1,81 +0,0 @@
1
- module NumbersInWords::NumberParser
2
- # Example: 364,895,457,898
3
- #three hundred and sixty four billion eight hundred and ninety five million
4
- #four hundred and fifty seven thousand eight hundred and ninety eight
5
- #
6
- #3 100 60 4 10^9, 8 100 90 5 10^6, 4 100 50 7 1000, 8 100 90 8
7
- # memory answer
8
- #x1. 3 add to memory because answer and memory are zero 3 0
9
- #x2. memory * 100 (because memory<100) 300 0
10
- #x3. 60 add to memory because memory > 60 360 0
11
- #x3. 4 add to memory because memory > 4 364 0
12
- #x4. multiply memory by 10^9 because memory < power of ten 364*10^9 0
13
- #x5. add memory to answer (and reset)memory > 8 (memory pow of ten > 2) 0 364*10^9
14
- #x6. 8 add to memory because not finished 8 ''
15
- #x7. multiply memory by 100 because memory < 100 800 ''
16
- #x8. add 90 to memory because memory > 90 890 ''
17
- #x9. add 5 to memory because memory > 5 895 ''
18
- #x10. multiply memory by 10^6 because memory < power of ten 895*10^6 ''
19
- #x11. add memory to answer (and reset) because memory power ten > 2 0 364895 * 10^6
20
- #x12. 4 add to memory because not finished 4 ''
21
- #x13. memory * 100 because memory < 100 400 ''
22
- #x14. memory + 50 because memory > 50 450 ''
23
- #x15. memory + 7 because memory > 7 457 ''
24
- #x16. memory * 1000 because memory < 1000 457000 ''
25
- #x17. add memory to answer (and reset)memory > 8 (memory pow of ten > 2) 0 364895457000
26
- #x18. 8 add to memory because not finished 8 ''
27
- #x19. memory * 100 because memory < 100 800 ''
28
- #x14. memory + 90 because memory > 90 890 ''
29
- #x15. memory + 8 because memory > 8 898 ''
30
- #16. finished so add memory to answer
31
-
32
- #Example
33
- #2001
34
- #two thousand and one
35
- #2 1000 1
36
- # memory answer
37
- #1. add 2 to memory because first 2 0
38
- #2. multiply memory by 1000 because memory < 1000 2000 0
39
- #3. add memory to answer,reset, because power of ten>2 0 2000
40
- #4. add 1 to memory 1 2000
41
- #5. finish - add memory to answer 0 2001
42
- def parse(integers)
43
- memory = 0
44
- answer = 0
45
- reset = true #reset each time memory is reset
46
- integers.each_with_index do |integer, index|
47
- if reset
48
- reset = false
49
- memory += integer
50
- else
51
- #x4. multiply memory by 10^9 because memory < power of ten
52
- if power_of_ten?(integer)
53
- if power_of_ten(integer)> 2
54
- memory *= integer
55
- #17. add memory to answer (and reset) (memory pow of ten > 2)
56
- answer += memory
57
- memory = 0
58
- reset = true
59
- end
60
- end
61
-
62
- if memory < integer
63
- memory *= integer
64
- else
65
- memory += integer
66
- end
67
- end
68
- end
69
- answer += memory
70
- end
71
-
72
- def power_of_ten integer
73
- Math.log10(integer)
74
- end
75
-
76
- def power_of_ten? integer
77
- power_of_ten(integer) == power_of_ten(integer).to_i
78
- end
79
-
80
- extend self
81
- end
@@ -1,82 +0,0 @@
1
- class NumbersInWords::ToNumber
2
- delegate :to_s, to: :that
3
- delegate :powers_of_ten_to_i, :exceptions_to_i, to: :language
4
- attr_reader :that, :language
5
-
6
- def initialize that, language=NumbersInWords.language
7
- @that = that
8
- @language = language
9
- end
10
-
11
- def language
12
- if @language.is_a? Module
13
- @language
14
- else
15
- @language = NumbersInWords.const_get(@language)
16
- end
17
- end
18
-
19
- def handle_negative text
20
- -1 * (text.gsub(/^minus /, "")).in_numbers if text =~ /^minus /
21
- end
22
-
23
- def in_numbers
24
- text = to_s
25
-
26
- text = strip_punctuation text
27
- i = handle_negative text
28
- return i if i
29
-
30
- h = handle_decimals text
31
- return h if h
32
-
33
- integers = word_array_to_integers text.split(" ")
34
-
35
- NumbersInWords::NumberParser.parse integers
36
- end
37
-
38
- def strip_punctuation text
39
- text = text.downcase.gsub(/[^a-z ]/, " ")
40
- to_remove = true
41
-
42
- to_remove = text.gsub! " ", " " while to_remove
43
-
44
- text
45
- end
46
-
47
- def handle_decimals text
48
- match = text.match(/\spoint\s/)
49
- if match
50
- integer = match.pre_match.in_numbers
51
-
52
- decimal = decimal_portion match.post_match
53
-
54
- integer + decimal
55
- end
56
- end
57
-
58
-
59
- def decimal_portion text
60
- words = text.split " "
61
- integers = word_array_to_integers words
62
- decimal = "0." + integers.join()
63
- decimal.to_f
64
- end
65
-
66
- #handles simple single word numbers
67
- #e.g. one, seven, twenty, eight, thousand etc
68
- def word_to_integer word
69
- text = word.to_s.chomp.strip
70
-
71
- exception = exceptions_to_i[text]
72
- return exception if exception
73
-
74
- power = powers_of_ten_to_i[text]
75
- return 10 ** power if power
76
- end
77
-
78
- def word_array_to_integers words
79
- words.map { |i| word_to_integer i }.compact
80
- end
81
- end
82
-
@@ -1,23 +0,0 @@
1
- require './spec/spec_helper'
2
-
3
- describe NumbersInWords::English::LanguageWriterEnglish do
4
- it "should display numbers grouped" do
5
- count = 0
6
- @writer = NumbersInWords::English::LanguageWriterEnglish.new(2111)
7
- @writer.group_words(3) do |power, name, digits|
8
- case count
9
- when 0
10
- power.should == 3
11
- name.should == "thousand"
12
- digits.should == 2
13
- when 1
14
- power.should == 0
15
- name.should == "one"
16
- digits.should == 111
17
- end
18
- count += 1
19
- end
20
- end
21
- end
22
-
23
-