kabal 0.3.5 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -2
- data/Gemfile +1 -0
- data/README.md +3 -1
- data/kabal.gemspec +1 -1
- data/lib/kabal.rb +24 -20
- data/lib/kabal/config.rb +1 -1
- data/lib/kabal/config/yaml_loader.rb +4 -2
- data/lib/kabal/errors.rb +7 -5
- data/lib/kabal/errors/error.rb +5 -5
- data/lib/kabal/errors/no_language_support_error.rb +1 -1
- data/lib/kabal/errors/no_support_for_fractional_numbers_on_current_language_error.rb +1 -1
- data/lib/kabal/errors/number_out_range_error.rb +1 -1
- data/lib/kabal/languages/deutsch.rb +4 -15
- data/lib/kabal/languages/deutsch/declinations.rb +4 -4
- data/lib/kabal/languages/deutsch/fractional_numbers.rb +1 -25
- data/lib/kabal/languages/deutsch/natural_numbers.rb +19 -17
- data/lib/kabal/languages/english.rb +4 -14
- data/lib/kabal/languages/english/fractional_numbers.rb +4 -28
- data/lib/kabal/languages/english/natural_numbers.rb +11 -25
- data/lib/kabal/languages/global/fractional_numbers.rb +40 -0
- data/lib/kabal/languages/global/natural_numbers.rb +20 -0
- data/lib/kabal/languages/language.rb +40 -15
- data/lib/kabal/languages/russian.rb +4 -17
- data/lib/kabal/languages/russian/declinations.rb +10 -12
- data/lib/kabal/languages/russian/fractional_numbers.rb +10 -21
- data/lib/kabal/languages/russian/natural_numbers.rb +23 -30
- data/lib/kabal/version.rb +1 -1
- data/test/lib/kabal_test.rb +14 -11
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: de5e475e931da2b5e708213ce699c0e69cdcb1c5
|
4
|
+
data.tar.gz: 8f37d26b3228d9b9471fff1397de6a1ed3dee356
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a75d13edce6e537158b6ab2d9be8a5bbd46db205b9d693e851777fb4bb13fbcf0c6d9448ee4cf78425ad5e715666accf37e16025b373733d7650ce1b9847ec3c
|
7
|
+
data.tar.gz: 61291e01e663a5b7a05daa5117df56b3fe0976681d61037ace697056f63d9e90d0bcc97770d21bbd2338b3891661e0375f39e8b303f2722548d010c40d8ecd87
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -7,9 +7,10 @@
|
|
7
7
|
[![endorse](https://api.coderwall.com/kalashnikovisme/endorsecount.png)](https://coderwall.com/kalashnikovisme)
|
8
8
|
[![Dependency Status](https://gemnasium.com/kalashnikovisme/kabal.svg)](https://gemnasium.com/kalashnikovisme/kabal)
|
9
9
|
[![Still MainTained](http://stillmaintained.com/kalashnikovisme/kabal.png)](http://stillmaintained.com/kalashnikovisme/kabal)
|
10
|
+
[![Code Climate](https://codeclimate.com/github/kalashnikovisme/kabal/badges/gpa.svg)](https://codeclimate.com/github/kalashnikovisme/kabal)
|
10
11
|
|
11
12
|
|
12
|
-
Kabal allows you to translate number into text.
|
13
|
+
Kabal allows you to translate number into text. See Demo on [http://kabal.herokuapp.com](http://kabal.herokuapp.com)
|
13
14
|
|
14
15
|
## Installation
|
15
16
|
|
@@ -51,6 +52,7 @@ Supported Languages:
|
|
51
52
|
* Negative Numbers
|
52
53
|
* Deutsch
|
53
54
|
* Natural Number { max 10 ** 24 }
|
55
|
+
* Fractional Numbers
|
54
56
|
* Negative Numbers
|
55
57
|
|
56
58
|
Interfaces:
|
data/kabal.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Pavel Kalashnikov"]
|
10
10
|
spec.email = ["kalashnikovisme@gmail.com"]
|
11
11
|
spec.summary = %q{Number To Text Helper}
|
12
|
-
spec.description = %q{Kabal allows you to translate numbers into text on languages: English, Russian, Deutsch}
|
12
|
+
spec.description = %q{Kabal allows you to translate numbers into text on languages: English, Russian, Deutsch. See demo on http://kabal.herokuapp.com}
|
13
13
|
spec.homepage = "https://github.com/kalashnikovisme/kabal"
|
14
14
|
spec.license = "MIT"
|
15
15
|
spec.required_ruby_version = '>= 2.0.0'
|
data/lib/kabal.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
autoload :Version,
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
autoload :Version, 'kabal/version'
|
2
|
+
require 'kabal/supported_languages'
|
3
|
+
require 'kabal/errors'
|
4
|
+
require 'kabal/config'
|
5
5
|
require 'yaml'
|
6
6
|
|
7
7
|
module Kabal
|
@@ -14,22 +14,22 @@ module Kabal
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def language=(language_to_set)
|
17
|
-
languages = Kabal::Config::YamlLoader.yaml_object
|
17
|
+
languages = Kabal::Config::YamlLoader.yaml_object 'languages'
|
18
18
|
if languages[language_to_set]
|
19
19
|
@language = language_to_set
|
20
20
|
else
|
21
|
-
|
21
|
+
fail NoLanguageSupportError.message
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
25
|
def to_text_in_language(number, language_at_once)
|
26
26
|
number = string_convert number
|
27
|
-
languages = Kabal::Config::YamlLoader.yaml_object
|
27
|
+
languages = Kabal::Config::YamlLoader.yaml_object 'languages'
|
28
28
|
if languages[language_at_once]
|
29
|
-
if number > maximum_for(language_at_once)
|
29
|
+
if number > maximum_for(language_at_once) || number < minimum_for(language_at_once)
|
30
30
|
NumberOutRangeError.message
|
31
31
|
else
|
32
|
-
obj = Object.const_get(
|
32
|
+
obj = Object.const_get(language_class_name(language_at_once)).new
|
33
33
|
obj.convert number
|
34
34
|
end
|
35
35
|
else
|
@@ -39,9 +39,9 @@ module Kabal
|
|
39
39
|
|
40
40
|
def to_text_in_language_by_index(number, language_at_once_index)
|
41
41
|
number = string_convert number
|
42
|
-
languages = Kabal::Config::YamlLoader.yaml_object(
|
42
|
+
languages = Kabal::Config::YamlLoader.yaml_object('languages').to_a
|
43
43
|
if languages[language_at_once_index]
|
44
|
-
obj = Object.const_get(
|
44
|
+
obj = Object.const_get(language_class_name(languages[language_at_once_index].first)).new
|
45
45
|
obj.convert number
|
46
46
|
else
|
47
47
|
NoLanguageSupportError.message
|
@@ -49,42 +49,42 @@ module Kabal
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def current_language
|
52
|
-
@language ||=
|
52
|
+
@language ||= 'English'
|
53
53
|
@language
|
54
54
|
end
|
55
55
|
|
56
56
|
def supported_languages
|
57
|
-
languages = Kabal::Config::YamlLoader.yaml_object
|
57
|
+
languages = Kabal::Config::YamlLoader.yaml_object 'languages'
|
58
58
|
languages.keys
|
59
59
|
end
|
60
60
|
|
61
61
|
def current_language_supports_natural?
|
62
|
-
obj = Object.const_get(
|
62
|
+
obj = Object.const_get(language_class_name(current_language)).new
|
63
63
|
obj.supports_natural?
|
64
64
|
end
|
65
65
|
|
66
66
|
def current_language_supports_fractional?
|
67
|
-
obj = Object.const_get(
|
67
|
+
obj = Object.const_get(language_class_name(current_language)).new
|
68
68
|
obj.supports_fractional?
|
69
69
|
end
|
70
70
|
|
71
71
|
def language_supports_negative?(language)
|
72
|
-
obj = Object.const_get(
|
72
|
+
obj = Object.const_get(language_class_name(language)).new
|
73
73
|
obj.supports_negative?
|
74
74
|
end
|
75
75
|
|
76
76
|
def language_supports_fractional?(language)
|
77
|
-
obj = Object.const_get(
|
77
|
+
obj = Object.const_get(language_class_name(language)).new
|
78
78
|
obj.supports_fractional?
|
79
79
|
end
|
80
80
|
|
81
81
|
def maximum_for(language)
|
82
|
-
obj = Object.const_get(
|
82
|
+
obj = Object.const_get(language_class_name(language)).new
|
83
83
|
obj.max_value
|
84
84
|
end
|
85
85
|
|
86
86
|
def minimum_for(language)
|
87
|
-
obj = Object.const_get(
|
87
|
+
obj = Object.const_get(language_class_name(language)).new
|
88
88
|
obj.min_value
|
89
89
|
end
|
90
90
|
|
@@ -103,6 +103,10 @@ module Kabal
|
|
103
103
|
end
|
104
104
|
|
105
105
|
def string_is_float?(number)
|
106
|
-
number.include?
|
106
|
+
number.include? '.'
|
107
|
+
end
|
108
|
+
|
109
|
+
def language_class_name(language)
|
110
|
+
'Kabal::' + language
|
107
111
|
end
|
108
112
|
end
|
data/lib/kabal/config.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
require 'active_support/core_ext/hash'
|
2
|
+
|
1
3
|
module Kabal
|
2
4
|
module Config
|
3
5
|
class YamlLoader
|
4
6
|
def self.gem_root
|
5
|
-
Gem::Specification.find_by_name(
|
7
|
+
Gem::Specification.find_by_name('kabal').gem_dir
|
6
8
|
end
|
7
9
|
|
8
10
|
def self.yaml_object(filename)
|
9
|
-
|
11
|
+
YAML.load_file(gem_root + '/yaml/' + filename + '.yml').with_indifferent_access
|
10
12
|
end
|
11
13
|
end
|
12
14
|
end
|
data/lib/kabal/errors.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
module Kabal
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
module Kabal
|
2
|
+
module Errors
|
3
|
+
require 'kabal/errors/no_language_support_error'
|
4
|
+
require 'kabal/errors/number_out_range_error'
|
5
|
+
require 'kabal/errors/no_support_for_fractional_numbers_on_current_language_error'
|
6
|
+
require 'kabal/errors/error'
|
7
|
+
end
|
6
8
|
end
|
data/lib/kabal/errors/error.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
require
|
1
|
+
require 'kabal/config'
|
2
2
|
|
3
3
|
module Kabal
|
4
4
|
module Errors
|
5
5
|
class Error < StandardError
|
6
|
-
@message =
|
7
|
-
@code =
|
6
|
+
@message = 'There is some error'
|
7
|
+
@code = 'Unknown error code'
|
8
8
|
|
9
9
|
def self.message
|
10
|
-
errors = Kabal::Config::YamlLoader.yaml_object
|
11
|
-
errors[
|
10
|
+
errors = Kabal::Config::YamlLoader.yaml_object 'errors'
|
11
|
+
errors[:errors][:messages][@code]
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -3,20 +3,9 @@ require 'kabal/languages/deutsch/natural_numbers'
|
|
3
3
|
require 'kabal/languages/deutsch/declinations'
|
4
4
|
require 'kabal/languages/deutsch/fractional_numbers'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def convert(number)
|
11
|
-
if need_minus? number
|
12
|
-
minus + " " + number_words(-number)
|
13
|
-
else
|
14
|
-
number_words number
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def number_words(number)
|
19
|
-
return natural_number_name number.round if natural? number
|
20
|
-
fractional_number_name number if fractional? number
|
6
|
+
module Kabal
|
7
|
+
class Deutsch < Kabal::Language
|
8
|
+
include Kabal::DeutschRules::NaturalNumbers
|
9
|
+
include Kabal::DeutschRules::FractionalNumbers
|
21
10
|
end
|
22
11
|
end
|
@@ -3,10 +3,10 @@ module Kabal
|
|
3
3
|
module Declinations
|
4
4
|
def self.name_with_declination(number_name, count)
|
5
5
|
if count != 1
|
6
|
-
if number_name[-1, 1] ==
|
7
|
-
return number_name +
|
8
|
-
elsif number_name[-1, 1] ==
|
9
|
-
return number_name +
|
6
|
+
if number_name[-1, 1] == 'n'
|
7
|
+
return number_name + 'en'
|
8
|
+
elsif number_name[-1, 1] == 'e'
|
9
|
+
return number_name + 'n'
|
10
10
|
end
|
11
11
|
end
|
12
12
|
number_name
|
@@ -2,7 +2,7 @@ module Kabal
|
|
2
2
|
module DeutschRules
|
3
3
|
module FractionalNumbers
|
4
4
|
def fractional_number_name(number)
|
5
|
-
whole_part_name(number) +
|
5
|
+
whole_part_name(number) + ' ' + dot + ' ' + fractional_part_name(number)
|
6
6
|
end
|
7
7
|
|
8
8
|
def whole_part_name(number)
|
@@ -10,33 +10,9 @@ module Kabal
|
|
10
10
|
natural_number_name(count)
|
11
11
|
end
|
12
12
|
|
13
|
-
def fractional_part_name(number)
|
14
|
-
name = ""
|
15
|
-
count_string = fractional_part_string(number).split('.')[1]
|
16
|
-
count = count_string.to_i
|
17
|
-
if count_string.size != count.to_s.size
|
18
|
-
(count_string.size - count.to_s.size).times do
|
19
|
-
name += names["single"][0] + " "
|
20
|
-
end
|
21
|
-
name + natural_number_name(count)
|
22
|
-
else
|
23
|
-
natural_number_name(count)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
13
|
def fractional_part_string(number)
|
28
14
|
"%.#{fractional_part_order(number)}f" % number
|
29
15
|
end
|
30
|
-
|
31
|
-
def fractional_part_order(number)
|
32
|
-
#FIXME find better way with whole 0 numbers
|
33
|
-
number_string = number.to_s
|
34
|
-
if number_string.include? "-"
|
35
|
-
number_string.split('-')[1].to_i
|
36
|
-
else
|
37
|
-
number_string.split('.')[1].length
|
38
|
-
end
|
39
|
-
end
|
40
16
|
end
|
41
17
|
end
|
42
18
|
end
|
@@ -1,35 +1,29 @@
|
|
1
1
|
module Kabal
|
2
2
|
module DeutschRules
|
3
3
|
module NaturalNumbers
|
4
|
-
def natural_number_name(number)
|
5
|
-
return single number if number >= 0 and number <= 19
|
6
|
-
return two_words number if number >= 0 and number <= 99
|
7
|
-
return three_words number if number >= 100 and number <= 999
|
8
|
-
ten_powers number if number >= 100
|
9
|
-
end
|
10
4
|
def single(number)
|
11
|
-
|
12
|
-
names["single"][number]
|
13
|
-
else
|
5
|
+
if @ein
|
14
6
|
@ein = false
|
15
|
-
names[
|
7
|
+
names[:single][number].chop
|
8
|
+
else
|
9
|
+
names[:single][number]
|
16
10
|
end
|
17
11
|
end
|
18
12
|
|
19
13
|
def two_words(number)
|
20
14
|
return single number if number <= 19
|
21
|
-
number_name = names[
|
15
|
+
number_name = names[:two_words][number / 10]
|
22
16
|
@ein = (number % 10 == 1)
|
23
|
-
number_name = single(number % 10) + names[
|
17
|
+
number_name = single(number % 10) + names[:and] + number_name if (number % 10 != 0)
|
24
18
|
number_name
|
25
19
|
end
|
26
20
|
|
27
21
|
def three_words(number)
|
28
22
|
return two_words number if number <= 99
|
29
23
|
@ein = (number / 100 == 1)
|
30
|
-
number_name = single(number / 100) + names[
|
24
|
+
number_name = single(number / 100) + names[:ten_powers][2]
|
31
25
|
number_name += two_words(number % 100) if (number % 100 >= 10)
|
32
|
-
number_name += single(number % 100) if number % 100 < 10
|
26
|
+
number_name += single(number % 100) if number % 100 < 10 && number % 100 != 0
|
33
27
|
number_name
|
34
28
|
end
|
35
29
|
|
@@ -37,7 +31,7 @@ module Kabal
|
|
37
31
|
less_thousands number if number_is_thousands? number
|
38
32
|
return @number_name if number_is_thousands? number
|
39
33
|
create_number_name number
|
40
|
-
ten_powers number % (10
|
34
|
+
ten_powers number % (10**number_order(number))
|
41
35
|
end
|
42
36
|
|
43
37
|
def create_number_name(number)
|
@@ -63,11 +57,19 @@ module Kabal
|
|
63
57
|
|
64
58
|
def words_to_add(number)
|
65
59
|
if millions_or_greater?(number)
|
66
|
-
|
60
|
+
number_with_space number
|
67
61
|
else
|
68
|
-
|
62
|
+
number_without_space number
|
69
63
|
end
|
70
64
|
end
|
65
|
+
|
66
|
+
def number_with_space(number)
|
67
|
+
@number_name = count_name(number) + ' ' + Declinations.name_with_declination(names[:ten_powers][number_order(number)], count(number)) + ' '
|
68
|
+
end
|
69
|
+
|
70
|
+
def number_without_space(number)
|
71
|
+
@number_name = count_name(number) + Declinations.name_with_declination(names[:ten_powers][number_order(number)], count(number))
|
72
|
+
end
|
71
73
|
end
|
72
74
|
end
|
73
75
|
end
|
@@ -2,19 +2,9 @@ require 'kabal/languages/language'
|
|
2
2
|
require 'kabal/languages/english/natural_numbers'
|
3
3
|
require 'kabal/languages/english/fractional_numbers'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
if need_minus? number
|
10
|
-
minus + " " + number_words(-number)
|
11
|
-
else
|
12
|
-
number_words number
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def number_words(number)
|
17
|
-
return natural_number_name number.round if natural? number
|
18
|
-
fractional_number_name number if fractional? number
|
5
|
+
module Kabal
|
6
|
+
class English < Kabal::Language
|
7
|
+
include Kabal::EnglishRules::NaturalNumbers
|
8
|
+
include Kabal::EnglishRules::FractionalNumbers
|
19
9
|
end
|
20
10
|
end
|
@@ -2,45 +2,21 @@ module Kabal
|
|
2
2
|
module EnglishRules
|
3
3
|
module FractionalNumbers
|
4
4
|
def fractional_number_name(number)
|
5
|
-
if whole_part_name(number) !=
|
6
|
-
whole_part_name(number) +
|
5
|
+
if whole_part_name(number) != ''
|
6
|
+
whole_part_name(number) + ' ' + dot + ' ' + fractional_part_name(number)
|
7
7
|
else
|
8
|
-
dot +
|
8
|
+
dot + ' ' + fractional_part_name(number)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
def whole_part_name(number)
|
13
13
|
count = number.floor
|
14
|
-
count != 0 ? natural_number_name(count) :
|
15
|
-
end
|
16
|
-
|
17
|
-
def fractional_part_name(number)
|
18
|
-
name = ""
|
19
|
-
count_string = fractional_part_string(number).to_s.split('.')[1]
|
20
|
-
count = count_string.to_i
|
21
|
-
if count_string.size != count.to_s.size
|
22
|
-
(count_string.size - count.to_s.size).times do
|
23
|
-
name += names["single"][0] + " "
|
24
|
-
end
|
25
|
-
name + natural_number_name(count)
|
26
|
-
else
|
27
|
-
natural_number_name(count)
|
28
|
-
end
|
14
|
+
count != 0 ? natural_number_name(count) : ''
|
29
15
|
end
|
30
16
|
|
31
17
|
def fractional_part_string(number)
|
32
18
|
"%.#{fractional_part_order(number)}f" % number
|
33
19
|
end
|
34
|
-
|
35
|
-
def fractional_part_order(number)
|
36
|
-
#FIXME find better way with whole 0 numbers
|
37
|
-
number_string = number.to_s
|
38
|
-
if number_string.include? "-"
|
39
|
-
number_string.split('-')[1].to_i
|
40
|
-
else
|
41
|
-
number_string.split('.')[1].length
|
42
|
-
end
|
43
|
-
end
|
44
20
|
end
|
45
21
|
end
|
46
22
|
end
|
@@ -1,28 +1,22 @@
|
|
1
1
|
module Kabal
|
2
2
|
module EnglishRules
|
3
3
|
module NaturalNumbers
|
4
|
-
def natural_number_name(number)
|
5
|
-
return single number if number >= 0 and number <= 19
|
6
|
-
return two_words number if number >= 0 and number <= 99
|
7
|
-
return three_words number if number >= 100 and number <= 999
|
8
|
-
ten_powers number if number >= 100
|
9
|
-
end
|
10
4
|
def single(number)
|
11
|
-
names[
|
5
|
+
names[:single][number]
|
12
6
|
end
|
13
7
|
|
14
8
|
def two_words(number)
|
15
9
|
return single number if number <= 19
|
16
|
-
number_name = names[
|
17
|
-
number_name +=
|
10
|
+
number_name = names[:two_words][number / 10]
|
11
|
+
number_name += ' ' + single(number % 10) if (number % 10 != 0)
|
18
12
|
number_name
|
19
13
|
end
|
20
14
|
|
21
15
|
def three_words(number)
|
22
16
|
return two_words number if number <= 99
|
23
|
-
number_name = single(number / 100) +
|
24
|
-
number_name +=
|
25
|
-
number_name +=
|
17
|
+
number_name = single(number / 100) + ' ' + names[:ten_powers][2]
|
18
|
+
number_name += ' ' + two_words(number % 100) if number % 100 >= 10
|
19
|
+
number_name += ' ' + names[:and] + ' ' + single(number % 100) if number % 100 < 10 && number % 100 != 0
|
26
20
|
number_name
|
27
21
|
end
|
28
22
|
|
@@ -30,25 +24,17 @@ module Kabal
|
|
30
24
|
less_thousands number if number_is_thousands? number
|
31
25
|
return @number_name if number_is_thousands? number
|
32
26
|
create_number_name number
|
33
|
-
ten_powers number % (10
|
34
|
-
end
|
35
|
-
|
36
|
-
def create_number_name(number)
|
37
|
-
if @number_name.nil?
|
38
|
-
@number_name = count_name(number) + " " + names["ten_powers"][number_order(number)]
|
39
|
-
elsif count(number) != 0
|
40
|
-
@number_name += " " + count_name(number) + " " + names["ten_powers"][number_order(number)]
|
41
|
-
end
|
27
|
+
ten_powers number % (10**number_order(number))
|
42
28
|
end
|
43
29
|
|
44
|
-
def
|
45
|
-
three_words
|
30
|
+
def count_name_with_order_name(number)
|
31
|
+
three_words(count(number)) + ' ' + names[:ten_powers][number_order(number)]
|
46
32
|
end
|
47
33
|
|
48
34
|
def less_thousands(number)
|
49
35
|
return if number == 0
|
50
|
-
@number_name +=
|
51
|
-
@number_name +=
|
36
|
+
@number_name += ' ' + names[:and] if number < 100
|
37
|
+
@number_name += ' ' + three_words(number % 1000) unless number == 0
|
52
38
|
end
|
53
39
|
end
|
54
40
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Kabal
|
2
|
+
module GlobalRules
|
3
|
+
module FractionalNumbers
|
4
|
+
def fractional_part_order(number)
|
5
|
+
number_string = number.to_s
|
6
|
+
if number_string.include? '-'
|
7
|
+
number_string.split('-')[1].to_i
|
8
|
+
else
|
9
|
+
number_string.split('.')[1].length
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def fractional_part_name(number)
|
14
|
+
@count_string = fractional_part_string(number).to_s.split('.')[1]
|
15
|
+
@count_int = @count_string.to_i
|
16
|
+
if there_zeros_before_fractional_part?
|
17
|
+
number_name_with_zeros + natural_number_name(@count_int)
|
18
|
+
else
|
19
|
+
natural_number_name @count_int
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def there_zeros_before_fractional_part?
|
24
|
+
@count_string.size != @count_int.to_s.size
|
25
|
+
end
|
26
|
+
|
27
|
+
def zeros_number
|
28
|
+
@count_string.size - @count_int.to_s.size
|
29
|
+
end
|
30
|
+
|
31
|
+
def number_name_with_zeros
|
32
|
+
name = ''
|
33
|
+
zeros_number.times do
|
34
|
+
name += names[:single][0] + ' '
|
35
|
+
end
|
36
|
+
name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Kabal
|
2
|
+
module GlobalRules
|
3
|
+
module NaturalNumbers
|
4
|
+
def natural_number_name(number)
|
5
|
+
return single number if number >= 0 && number <= 19
|
6
|
+
return two_words number if number >= 0 && number <= 99
|
7
|
+
return three_words number if number >= 100 && number <= 999
|
8
|
+
ten_powers number if number >= 100
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_number_name(number)
|
12
|
+
if @number_name.nil?
|
13
|
+
@number_name = count_name_with_order_name number
|
14
|
+
elsif count(number) != 0
|
15
|
+
@number_name += ' ' + count_name_with_order_name(number)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,8 +1,15 @@
|
|
1
|
+
require 'kabal/languages/global/fractional_numbers'
|
2
|
+
require 'kabal/languages/global/natural_numbers'
|
3
|
+
|
1
4
|
module Kabal
|
2
5
|
class Language
|
6
|
+
include Kabal::GlobalRules::NaturalNumbers
|
7
|
+
include Kabal::GlobalRules::FractionalNumbers
|
8
|
+
|
3
9
|
def initialize
|
4
10
|
@names = Kabal::Config::YamlLoader.yaml_object "languages/#{lang}"
|
5
|
-
|
11
|
+
support_file = Kabal::Config::YamlLoader.yaml_object('support')
|
12
|
+
@supports = support_file[:support][lang]
|
6
13
|
end
|
7
14
|
|
8
15
|
def convert(number)
|
@@ -13,22 +20,36 @@ module Kabal
|
|
13
20
|
end
|
14
21
|
end
|
15
22
|
|
23
|
+
def convert_number(number)
|
24
|
+
@number_name = nil
|
25
|
+
if need_minus? number
|
26
|
+
minus + ' ' + number_words(-number)
|
27
|
+
else
|
28
|
+
number_words number
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def number_words(number)
|
33
|
+
return natural_number_name number.round if natural? number
|
34
|
+
fractional_number_name number if fractional? number
|
35
|
+
end
|
36
|
+
|
16
37
|
def error(number)
|
17
38
|
if number_is_out_of_the_range? number
|
18
39
|
return Kabal::Errors::NumberOutRangeError.message
|
19
40
|
end
|
20
|
-
if
|
41
|
+
if (!supports_fractional?) && (number % 1 != 0)
|
21
42
|
Kabal::Errors::NoSupportForFractionalNumberOnCurrentLanguages.message
|
22
43
|
end
|
23
44
|
end
|
24
45
|
|
25
46
|
def lang
|
26
|
-
languages = Kabal::Config::YamlLoader.yaml_object
|
27
|
-
@lang = languages[self.to_s.split(
|
47
|
+
languages = Kabal::Config::YamlLoader.yaml_object 'languages'
|
48
|
+
@lang = languages[self.to_s.split(':')[-2]]
|
28
49
|
end
|
29
50
|
|
30
51
|
def supports_natural?
|
31
|
-
@supports[
|
52
|
+
@supports[:natural]
|
32
53
|
end
|
33
54
|
|
34
55
|
def supports_negative?
|
@@ -36,11 +57,11 @@ module Kabal
|
|
36
57
|
end
|
37
58
|
|
38
59
|
def min_value
|
39
|
-
eval @supports[
|
60
|
+
eval @supports[:natural][:min]
|
40
61
|
end
|
41
62
|
|
42
63
|
def max_value
|
43
|
-
eval @supports[
|
64
|
+
eval @supports[:natural][:max]
|
44
65
|
end
|
45
66
|
|
46
67
|
def names
|
@@ -48,15 +69,15 @@ module Kabal
|
|
48
69
|
end
|
49
70
|
|
50
71
|
def minus
|
51
|
-
names[
|
72
|
+
names[:minus]
|
52
73
|
end
|
53
74
|
|
54
75
|
def whole
|
55
|
-
names[
|
76
|
+
names[:whole]
|
56
77
|
end
|
57
78
|
|
58
79
|
def dot
|
59
|
-
names[
|
80
|
+
names[:dot]
|
60
81
|
end
|
61
82
|
|
62
83
|
def fractional?(number)
|
@@ -72,7 +93,7 @@ module Kabal
|
|
72
93
|
end
|
73
94
|
|
74
95
|
def number_is_google?(number)
|
75
|
-
count(number) == 10
|
96
|
+
count(number) == 10 && number_order(number) == 99
|
76
97
|
end
|
77
98
|
|
78
99
|
def number_order(number)
|
@@ -80,19 +101,23 @@ module Kabal
|
|
80
101
|
end
|
81
102
|
|
82
103
|
def count(number)
|
83
|
-
number / (10
|
104
|
+
number / (10**number_order(number))
|
84
105
|
end
|
85
106
|
|
86
107
|
def supports_fractional?
|
87
|
-
@supports[
|
108
|
+
@supports[:fractional]
|
88
109
|
end
|
89
110
|
|
90
111
|
def number_is_out_of_the_range?(number)
|
91
|
-
number >= max_value
|
112
|
+
number >= max_value || number <= min_value
|
113
|
+
end
|
114
|
+
|
115
|
+
def fractional_but_no_support_fractional?(number)
|
116
|
+
number % 1 != 0 && !supports_fractional?
|
92
117
|
end
|
93
118
|
|
94
119
|
def no_supports?(number)
|
95
|
-
(number
|
120
|
+
fractional_but_no_support_fractional?(number) || number_is_out_of_the_range?(number)
|
96
121
|
end
|
97
122
|
|
98
123
|
def need_minus?(number)
|
@@ -3,22 +3,9 @@ require 'kabal/languages/russian/declinations'
|
|
3
3
|
require 'kabal/languages/russian/natural_numbers'
|
4
4
|
require 'kabal/languages/russian/fractional_numbers'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def convert_number(number)
|
11
|
-
#FIXME find better way
|
12
|
-
@number_name = nil
|
13
|
-
if need_minus? number
|
14
|
-
minus + " " + number_words(-number)
|
15
|
-
else
|
16
|
-
number_words number
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def number_words(number)
|
21
|
-
return natural_number_name number.round if natural? number
|
22
|
-
fractional_number_name number if fractional? number
|
6
|
+
module Kabal
|
7
|
+
class Russian < Kabal::Language
|
8
|
+
include Kabal::RussianRules::NaturalNumbers
|
9
|
+
include Kabal::RussianRules::FractionalNumbers
|
23
10
|
end
|
24
11
|
end
|
@@ -2,32 +2,30 @@ module Kabal
|
|
2
2
|
module RussianRules
|
3
3
|
module Declinations
|
4
4
|
def self.name_with_declination(number_name, count)
|
5
|
-
|
6
|
-
#FIXME find another way to convert number from exp form
|
7
|
-
if count.to_s.include? "e"
|
5
|
+
if count.to_s.include? 'e'
|
8
6
|
count = count.to_s.split('.')[0].to_i
|
9
7
|
end
|
10
|
-
#FIXME add gem russian
|
11
|
-
if number_name[-1, 1] ==
|
8
|
+
# FIXME add gem russian
|
9
|
+
if number_name[-1, 1] == 'а'
|
12
10
|
return number_name if ends_with_one? count
|
13
|
-
return number_name[0..4] +
|
11
|
+
return number_name[0..4] + 'и' if end_with_two_or_three_of_four? count
|
14
12
|
number_name[0..4]
|
15
|
-
elsif number_name[-1, 1] ==
|
13
|
+
elsif number_name[-1, 1] == 'я'
|
16
14
|
return number_name if ends_with_one? count
|
17
|
-
number_name[0..-3] +
|
15
|
+
number_name[0..-3] + 'ых'
|
18
16
|
else
|
19
17
|
return number_name if ends_with_one? count
|
20
|
-
return number_name +
|
21
|
-
number_name +
|
18
|
+
return number_name + 'а' if end_with_two_or_three_of_four? count
|
19
|
+
number_name + 'ов'
|
22
20
|
end
|
23
21
|
end
|
24
22
|
|
25
23
|
def self.ends_with_one?(count)
|
26
|
-
count.to_s[-1] ==
|
24
|
+
count.to_s[-1] == '1' && (count % 100) / 10 != 1
|
27
25
|
end
|
28
26
|
|
29
27
|
def self.end_with_two_or_three_of_four?(count)
|
30
|
-
count.to_s[-1] ==
|
28
|
+
count.to_s[-1] == '2' || count.to_s[-1] == '3' || count.to_s[-1] == '4'
|
31
29
|
end
|
32
30
|
end
|
33
31
|
end
|
@@ -2,49 +2,38 @@ module Kabal
|
|
2
2
|
module RussianRules
|
3
3
|
module FractionalNumbers
|
4
4
|
def fractional_number_name(number)
|
5
|
-
whole_part_name(number) +
|
5
|
+
whole_part_name(number) + ' ' + fractional_part_name(number)
|
6
6
|
end
|
7
7
|
|
8
8
|
def fractional_part_name(number)
|
9
|
-
fractional_part = (number % 1).round(
|
10
|
-
fractional_order = ((fractional_part) * (10
|
11
|
-
feminine_natural_number_name(fractional_order, true) +
|
9
|
+
fractional_part = (number % 1).round(fractional_part_order(number))
|
10
|
+
fractional_order = ((fractional_part) * (10**fractional_part_order(number))).to_s.split('.')[0].to_i
|
11
|
+
feminine_natural_number_name(fractional_order, true) + ' ' + Declinations.name_with_declination(fractional_ten_powers_name(number), fractional_part)
|
12
12
|
end
|
13
13
|
|
14
14
|
def whole_part_name(number)
|
15
15
|
count = number.floor
|
16
|
-
feminine_natural_number_name(count) +
|
16
|
+
feminine_natural_number_name(count) + ' ' + Declinations.name_with_declination(whole, count)
|
17
17
|
end
|
18
18
|
|
19
19
|
def fractional_ten_powers_name(number)
|
20
|
-
ten_powers_name = ""
|
21
20
|
if need_pre_word? number
|
22
|
-
|
21
|
+
fractional_pre_word(number) + fractional_order_word(number)
|
23
22
|
else
|
24
|
-
|
23
|
+
names[:fractional_ten_powers][fractional_part_order(number)]
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
28
27
|
def fractional_order_word(number)
|
29
|
-
names[
|
28
|
+
names[:fractional_ten_powers][fractional_part_order(number) - (fractional_part_order(number) % 3)]
|
30
29
|
end
|
31
30
|
|
32
31
|
def fractional_pre_word(number)
|
33
|
-
names[
|
32
|
+
names[:fractional_pre_words][fractional_part_order(number) % 3]
|
34
33
|
end
|
35
34
|
|
36
35
|
def need_pre_word?(number)
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
def fractional_number_order(number)
|
41
|
-
#FIXME find better way with whole 0 numbers
|
42
|
-
number_string = number.to_s
|
43
|
-
if number_string.include? "-"
|
44
|
-
number_string.split('-')[1].to_i
|
45
|
-
else
|
46
|
-
number_string.split('.')[1].length
|
47
|
-
end
|
36
|
+
fractional_part_order(number) > 3 && fractional_part_order(number) % 3 != 0
|
48
37
|
end
|
49
38
|
end
|
50
39
|
end
|
@@ -2,74 +2,67 @@ module Kabal
|
|
2
2
|
module RussianRules
|
3
3
|
module NaturalNumbers
|
4
4
|
def feminine_natural_number_name(number, fractional_part = false)
|
5
|
+
@number_name = nil
|
5
6
|
@number = number
|
6
7
|
@feminine_name = !fractional_part
|
7
8
|
@fractional_part = fractional_part
|
8
9
|
natural_number_name number
|
9
10
|
end
|
10
11
|
|
11
|
-
def
|
12
|
-
#FIXME switch case next lines
|
13
|
-
return single(number, true) if number >= 0 and number <= 19
|
14
|
-
return two_words(number, true) if number >= 20 and number <= 99
|
15
|
-
return three_words(number, true) if number >= 100 and number <= 999
|
16
|
-
ten_powers(number) if number >= 1000
|
17
|
-
end
|
18
|
-
|
19
|
-
def single(number, this_is_end = false)
|
12
|
+
def single(number, this_is_end = true)
|
20
13
|
if @feminine_name
|
21
14
|
@feminine_name = false
|
22
|
-
return names[
|
15
|
+
return names[:single_feminine][count(number) % 10] if count_can_be_feminine? number
|
23
16
|
end
|
24
|
-
if @fractional_part
|
17
|
+
if @fractional_part && this_is_end
|
25
18
|
@fractional_part = false
|
26
|
-
return names[
|
19
|
+
return names[:single_feminine][count(number) % 10] if count_can_be_feminine? number
|
27
20
|
end
|
28
|
-
names[
|
21
|
+
names[:single][number]
|
29
22
|
end
|
30
23
|
|
31
|
-
def two_words(number, this_is_end =
|
24
|
+
def two_words(number, this_is_end = true)
|
32
25
|
return single(number, this_is_end) if number <= 19
|
33
|
-
number_name = names[
|
34
|
-
number_name +=
|
26
|
+
number_name = names[:two_words][number / 10]
|
27
|
+
number_name += ' ' + single(number % 10, this_is_end) if (number % 10 != 0)
|
35
28
|
number_name
|
36
29
|
end
|
37
30
|
|
38
|
-
def three_words(number, this_is_end =
|
31
|
+
def three_words(number, this_is_end = true)
|
39
32
|
return two_words(number, this_is_end) if number / 100 == 0
|
40
|
-
number_name = names[
|
41
|
-
return number_name +=
|
42
|
-
return number_name +=
|
33
|
+
number_name = names[:three_words][number / 100]
|
34
|
+
return number_name += ' ' + two_words(number % 100, this_is_end) if (number % 100 >= 20)
|
35
|
+
return number_name += ' ' + single(number % 100, this_is_end) if (number % 100 != 0)
|
43
36
|
number_name
|
44
37
|
end
|
45
38
|
|
46
39
|
def ten_powers(number)
|
47
|
-
return names[
|
40
|
+
return names[:ten_powers][100] if number_is_google? number
|
48
41
|
less_thousands number if number_is_thousands? number
|
49
42
|
return @number_name if number_is_thousands? number
|
50
43
|
create_number_name number
|
51
44
|
ten_powers(number % (10 ** number_order(number)))
|
52
45
|
end
|
53
46
|
|
54
|
-
def
|
55
|
-
|
56
|
-
@number_name = count_name(number) + " " + Declinations.name_with_declination(names["ten_powers"][number_order(number)], count(number))
|
57
|
-
elsif count(number) != 0
|
58
|
-
@number_name += " " + count_name(number) + " " + Declinations.name_with_declination(names["ten_powers"][number_order(number)], count(number))
|
59
|
-
end
|
47
|
+
def count_can_be_feminine?(number)
|
48
|
+
count(number) % 10 == 1 || count(number) % 10 == 2
|
60
49
|
end
|
61
50
|
|
62
51
|
def less_thousands(number)
|
63
|
-
@number_name +=
|
52
|
+
@number_name += ' ' + three_words(number % 1000) unless number == 0
|
64
53
|
end
|
65
54
|
|
66
55
|
def count_name(number)
|
67
|
-
if (number.to_s[-4] ==
|
56
|
+
if (number.to_s[-4] == '1' || number.to_s[-4] == '2') && count(number) && (count(number) % 100) / 10 != 1 && number_order(number) == 3
|
68
57
|
@feminine_name = true
|
69
58
|
else
|
70
59
|
@feminine_name = false
|
71
60
|
end
|
72
|
-
three_words count(number)
|
61
|
+
three_words count(number), false
|
62
|
+
end
|
63
|
+
|
64
|
+
def count_name_with_order_name(number)
|
65
|
+
count_name(number) + ' ' + Declinations.name_with_declination(names[:ten_powers][number_order(number)], count(number))
|
73
66
|
end
|
74
67
|
end
|
75
68
|
end
|
data/lib/kabal/version.rb
CHANGED
data/test/lib/kabal_test.rb
CHANGED
@@ -5,10 +5,11 @@ include Kabal
|
|
5
5
|
class KabalTest < TestCase
|
6
6
|
def test_language_init
|
7
7
|
Kabal.language = "Russian"
|
8
|
-
assert_equal Kabal.current_language
|
8
|
+
assert_equal "Russian", Kabal.current_language
|
9
9
|
end
|
10
10
|
|
11
11
|
def test_to_text
|
12
|
+
Kabal.language = "Russian"
|
12
13
|
assert_equal "сто двадцать пять миллиардов сто двадцать пять миллионов сто двадцать пять тысяч сто двадцать пять", Kabal.to_text(125125125125)
|
13
14
|
assert_equal "сто двадцать пять миллиардов сто двадцать пять миллионов сто двадцать пять тысяч сто двадцать пять", Kabal.to_text("125125125125")
|
14
15
|
end
|
@@ -57,15 +58,15 @@ class KabalTest < TestCase
|
|
57
58
|
end
|
58
59
|
|
59
60
|
def test_maximum_for_language
|
60
|
-
assert_equal Kabal.maximum_for("Russian")
|
61
|
-
assert_equal
|
62
|
-
assert_equal
|
61
|
+
assert_equal 10 ** 102, Kabal.maximum_for("Russian")
|
62
|
+
assert_equal (10 ** 66) - 1, Kabal.maximum_for("English")
|
63
|
+
assert_equal (10 ** 24) - 1, Kabal.maximum_for("Deutsch")
|
63
64
|
end
|
64
65
|
|
65
66
|
def test_minimum_for_language
|
66
|
-
assert_equal Kabal.minimum_for("Russian")
|
67
|
-
assert_equal
|
68
|
-
assert_equal
|
67
|
+
assert_equal -(10 ** 102), Kabal.minimum_for("Russian")
|
68
|
+
assert_equal -(10 ** 66) + 1, Kabal.minimum_for("English")
|
69
|
+
assert_equal -(10 ** 24) + 1, Kabal.minimum_for("Deutsch")
|
69
70
|
end
|
70
71
|
|
71
72
|
def test_minimum_and_maximum_convert_for_language
|
@@ -88,9 +89,11 @@ class KabalTest < TestCase
|
|
88
89
|
end
|
89
90
|
|
90
91
|
def test_bad_number_test
|
91
|
-
|
92
|
-
assert_equal Kabal.to_text("
|
93
|
-
assert_equal Kabal.to_text("
|
94
|
-
assert_equal
|
92
|
+
Kabal.language = "Russian"
|
93
|
+
assert_equal "сто десять квинтиллионов одна тысяча одиннадцать", Kabal.to_text("110000000000000001011")
|
94
|
+
assert_equal "одиннадцать квадраллионов одиннадцать", Kabal.to_text("11000000000000011")
|
95
|
+
assert_equal "сто двенадцать квинтиллиона двести двадцать три квадраллиона триста тридцать четыре триллиона четыреста сорок пять миллиардов пятьсот пятьдесят шесть миллионов шестьсот шестьдесят одна тысяча одиннадцать", Kabal.to_text("112223334445556661011")
|
96
|
+
assert_equal "девятьсот девять миллионов девяносто тысяч девятьсот девять целых одна тысяча двести тридцать четыре десятитысячных", Kabal.to_text("909090909.1234")
|
97
|
+
assert_equal "девятьсот девять миллионов девяносто тысяч девятьсот девять целых одна тысяча двести тридцать четыре десятитысячных", Kabal.to_text(909090909.1234)
|
95
98
|
end
|
96
99
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kabal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pavel Kalashnikov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
description: 'Kabal allows you to translate numbers into text on languages: English,
|
42
|
-
Russian, Deutsch'
|
42
|
+
Russian, Deutsch. See demo on http://kabal.herokuapp.com'
|
43
43
|
email:
|
44
44
|
- kalashnikovisme@gmail.com
|
45
45
|
executables: []
|
@@ -70,6 +70,8 @@ files:
|
|
70
70
|
- lib/kabal/languages/english.rb
|
71
71
|
- lib/kabal/languages/english/fractional_numbers.rb
|
72
72
|
- lib/kabal/languages/english/natural_numbers.rb
|
73
|
+
- lib/kabal/languages/global/fractional_numbers.rb
|
74
|
+
- lib/kabal/languages/global/natural_numbers.rb
|
73
75
|
- lib/kabal/languages/language.rb
|
74
76
|
- lib/kabal/languages/russian.rb
|
75
77
|
- lib/kabal/languages/russian/declinations.rb
|