ordinalize_full 3.0.0 → 3.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7174b3e018cd6b0f1b7b41a7d30fe3994726c81029d6c197e46184a58ed3e690
4
- data.tar.gz: d76be4c1a6205e4e5c62e4d32d776281cda48d120bf05d78778ccb3383d78ae8
3
+ metadata.gz: 141ca2978cba4542c3753808f1a4e7097c44b4c5d2baa6648a8a8f097c50e4d0
4
+ data.tar.gz: 1345bbea85ce31a8c67341003bad1ebe32695fbbb488d1d7528f36df1bd57b51
5
5
  SHA512:
6
- metadata.gz: a39b56d13c8026e98a2e08eec3fdc01152d60becd2942b1cb183bf56cf43524d1b5520e75cc9568948d371fc5e376ab61024c54d0ef903aa0a727b0ba0a184e1
7
- data.tar.gz: 672aed32b546b3346dd305008493d0665c83595ebb7b22f6ac9f1c20feffff0025928df0103fd8d12283da073e074a3ea8b4274ac60439b34f39add6c1e7222d
6
+ metadata.gz: d071d17ee79d77eb2254ab950867f27ed7a267ee3f26e108572ce85d9746e3433d2812cb0651e6a5b682617ae8da4dfa2e99da1f843d04a8f97005e9eed68b82
7
+ data.tar.gz: 7eafd8f37d55f00e8dba46ea12fc12ca8fd7ee99f18f6c54ec47d6cf0edd66a7b1949d1aae18bb92a124638b9765e57dee09a25a30c1e48e77cb829b6b143c08
data/.rubocop.yml CHANGED
@@ -6,32 +6,17 @@ AllCops:
6
6
  TargetRubyVersion: 3.0
7
7
  NewCops: enable
8
8
 
9
+ Gemspec/DevelopmentDependencies:
10
+ Enabled: false
11
+
9
12
  Metrics:
10
13
  Enabled: false
11
14
 
12
15
  Layout/AccessModifierIndentation:
13
16
  EnforcedStyle: outdent
14
17
 
15
- Layout/CaseIndentation:
16
- Enabled: false
17
-
18
- Layout/EndAlignment:
19
- Enabled: false
20
-
21
- Layout/EmptyLinesAroundArguments:
22
- Enabled: false
23
-
24
- Layout/LineLength:
25
- Enabled: false
26
-
27
18
  Style/Alias:
28
19
  EnforcedStyle: prefer_alias_method
29
20
 
30
- Style/Documentation:
31
- Enabled: false
32
-
33
21
  Style/StringLiterals:
34
22
  EnforcedStyle: double_quotes
35
-
36
- Style/SpecialGlobalVars:
37
- Enabled: false
data/README.md CHANGED
@@ -8,9 +8,8 @@ Like Rails' [ordinalize](http://api.rubyonrails.org/classes/ActiveSupport/Inflec
8
8
  Features:
9
9
 
10
10
  - i18n support
11
- - doesn't monkey-patch
11
+ - doesn't require monkey-patching
12
12
  - easy to integrate with Rails but doesn't require Rails
13
- - less than 50 lines of code
14
13
 
15
14
  ## Usage
16
15
 
@@ -49,6 +48,9 @@ MyIntegerLikeClass.new.ordinalize_in_full #=> "forty second"
49
48
 
50
49
  ## Limitations
51
50
 
52
- - only works up to 100 (for now)
51
+ - only works up to 100 for non-English languages
53
52
  - locales only available in English, French, Italian, Spanish, and Dutch (pull requests welcome!)
54
53
 
54
+ ## License
55
+
56
+ `SPDX-License-Identifier: MIT`
data/Rakefile CHANGED
@@ -10,11 +10,4 @@ end
10
10
  require "rubocop/rake_task"
11
11
  RuboCop::RakeTask.new
12
12
 
13
- require "cane/rake_task"
14
- Cane::RakeTask.new do |t|
15
- t.no_doc = true
16
- t.style_measure = 120
17
- t.abc_max = 20
18
- end
19
-
20
- task default: %i[spec rubocop cane]
13
+ task default: %i[spec rubocop]
@@ -1,102 +1,72 @@
1
1
  en:
2
- ordinalize_full:
3
- n_1: first
4
- n_2: second
5
- n_3: third
6
- n_4: fourth
7
- n_5: fifth
8
- n_6: sixth
9
- n_7: seventh
10
- n_8: eighth
11
- n_9: ninth
12
- n_10: tenth
13
- n_11: eleventh
14
- n_12: twelfth
15
- n_13: thirteenth
16
- n_14: fourteenth
17
- n_15: fifteenth
18
- n_16: sixteenth
19
- n_17: seventeenth
20
- n_18: eighteenth
21
- n_19: nineteenth
22
- n_20: twentieth
23
- n_21: twenty first
24
- n_22: twenty second
25
- n_23: twenty third
26
- n_24: twenty fourth
27
- n_25: twenty fifth
28
- n_26: twenty sixth
29
- n_27: twenty seventh
30
- n_28: twenty eighth
31
- n_29: twenty ninth
32
- n_30: thirtieth
33
- n_31: thirty first
34
- n_32: thirty second
35
- n_33: thirty third
36
- n_34: thirty fourth
37
- n_35: thirty fifth
38
- n_36: thirty sixth
39
- n_37: thirty seventh
40
- n_38: thirty eighth
41
- n_39: thirty ninth
42
- n_40: fortieth
43
- n_41: forty first
44
- n_42: forty second
45
- n_43: forty third
46
- n_44: forty fourth
47
- n_45: forty fifth
48
- n_46: forty sixth
49
- n_47: forty seventh
50
- n_48: forty eighth
51
- n_49: forty ninth
52
- n_50: fiftieth
53
- n_51: fifty first
54
- n_52: fifty second
55
- n_53: fifty third
56
- n_54: fifty fourth
57
- n_55: fifty fifth
58
- n_56: fifty sixth
59
- n_57: fifty seventh
60
- n_58: fifty eighth
61
- n_59: fifty ninth
62
- n_60: sixtieth
63
- n_61: sixty first
64
- n_62: sixty second
65
- n_63: sixty third
66
- n_64: sixty fourth
67
- n_65: sixty fifth
68
- n_66: sixty sixth
69
- n_67: sixty seventh
70
- n_68: sixty eighth
71
- n_69: sixty ninth
72
- n_70: seventieth
73
- n_71: seventy first
74
- n_72: seventy second
75
- n_73: seventy third
76
- n_74: seventy fourth
77
- n_75: seventy fifth
78
- n_76: seventy sixth
79
- n_77: seventy seventh
80
- n_78: seventy eighth
81
- n_79: seventy ninth
82
- n_80: eightieth
83
- n_81: eighty first
84
- n_82: eighty second
85
- n_83: eighty third
86
- n_84: eighty fourth
87
- n_85: eighty fifth
88
- n_86: eighty sixth
89
- n_87: eighty seventh
90
- n_88: eighty eighth
91
- n_89: eighty ninth
92
- n_90: ninetieth
93
- n_91: ninety first
94
- n_92: ninety second
95
- n_93: ninety third
96
- n_94: ninety fourth
97
- n_95: ninety fifth
98
- n_96: ninety sixth
99
- n_97: ninety seventh
100
- n_98: ninety eighth
101
- n_99: ninety ninth
102
- n_100: one hundredth
2
+ long_form:
3
+ negative: negative
4
+ simple:
5
+ ones:
6
+ n_0: zero
7
+ n_1: one
8
+ n_2: two
9
+ n_3: three
10
+ n_4: four
11
+ n_5: five
12
+ n_6: six
13
+ n_7: seven
14
+ n_8: eight
15
+ n_9: nine
16
+ n_10: ten
17
+ n_11: eleven
18
+ n_12: twelve
19
+ n_13: thirteen
20
+ n_14: fourteen
21
+ n_15: fifteen
22
+ n_16: sixteen
23
+ n_17: seventeen
24
+ n_18: eighteen
25
+ n_19: nineteen
26
+ tens:
27
+ n_2: twenty
28
+ n_3: thirty
29
+ n_4: forty
30
+ n_5: fifty
31
+ n_6: sixty
32
+ n_7: seventy
33
+ n_8: eighty
34
+ n_9: ninety
35
+ hundred: hundred
36
+ larger:
37
+ n_0: ""
38
+ n_1: thousand
39
+ n_2: million
40
+ n_3: billion
41
+ n_4: trillion
42
+ ordinal:
43
+ ones:
44
+ n_0: zeroth
45
+ n_1: first
46
+ n_2: second
47
+ n_3: third
48
+ n_4: fourth
49
+ n_5: fifth
50
+ n_6: sixth
51
+ n_7: seventh
52
+ n_8: eighth
53
+ n_9: ninth
54
+ n_10: tenth
55
+ n_11: eleventh
56
+ n_12: twelfth
57
+ n_13: thirteenth
58
+ n_14: fourteenth
59
+ n_15: fifteenth
60
+ n_16: sixteenth
61
+ n_17: seventeenth
62
+ n_18: eigthteenth
63
+ n_19: nineteenth
64
+ tens:
65
+ n_2: twentieth
66
+ n_3: thirtieth
67
+ n_4: fortieth
68
+ n_5: fiftieth
69
+ n_6: sixtieth
70
+ n_7: seventieth
71
+ n_8: eightieth
72
+ n_9: ninetieth
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "i18n"
4
4
 
5
+ # Main module
5
6
  module OrdinalizeFull
6
7
  I18n.load_path += Dir[File.join(__dir__, "ordinalize_full/locales/*.yml")]
7
8
 
@@ -35,7 +36,11 @@ module OrdinalizeFull
35
36
 
36
37
  value
37
38
  else
38
- I18n.t("ordinalize_full.n_#{self}", throw: true)
39
+ begin
40
+ integer_to_long_form_ordinal
41
+ rescue ArgumentError
42
+ I18n.t("ordinalize_full.n_#{self}", throw: true)
43
+ end
39
44
  end
40
45
  rescue ArgumentError
41
46
  raise NotImplementedError, "Unknown locale #{I18n.locale}"
@@ -47,40 +52,106 @@ private
47
52
 
48
53
  def ordinalize_in_short(gender: :masculine, plurality: :singular)
49
54
  abs_number = to_i.abs
50
- suffix = case I18n.locale
51
- when :en
52
- if (11..13).cover?(abs_number % 100)
53
- "th"
54
- else
55
- case abs_number % 10
56
- when 1 then "st"
57
- when 2 then "nd"
58
- when 3 then "rd"
59
- else "th"
55
+ suffix = \
56
+ case I18n.locale
57
+ when :en
58
+ if (11..13).cover?(abs_number % 100)
59
+ "th"
60
+ else
61
+ case abs_number % 10
62
+ when 1 then "st"
63
+ when 2 then "nd"
64
+ when 3 then "rd"
65
+ else "th"
66
+ end
67
+ end
68
+ when :fr
69
+ self == 1 ? "er" : "ème"
70
+ when :it
71
+ "°"
72
+ when :nl
73
+ [8, 1, 0].include?(self % 100) || self % 100 > 19 ? "ste" : "de"
74
+ when :es
75
+ value = ordinalize_in_full(gender: gender, plurality: plurality)
76
+
77
+ if value.end_with?("er")
78
+ ".ᵉʳ"
79
+ elsif value.end_with?("a")
80
+ ".ᵃ"
81
+ elsif value.end_with?("o")
82
+ ".ᵒ"
83
+ elsif value.end_with?("os")
84
+ ".ᵒˢ"
85
+ elsif value.end_with?("as")
86
+ ".ᵃˢ"
60
87
  end
61
88
  end
62
- when :fr
63
- self == 1 ? "er" : "ème"
64
- when :it
65
- "°"
66
- when :nl
67
- [8, 1, 0].include?(self % 100) || self % 100 > 19 ? "ste" : "de"
68
- when :es
69
- value = ordinalize_in_full(gender: gender, plurality: plurality)
70
-
71
- if value.end_with?("er")
72
- ".ᵉʳ"
73
- elsif value.end_with?("a")
74
- ".ᵃ"
75
- elsif value.end_with?("o")
76
- ".ᵒ"
77
- elsif value.end_with?("os")
78
- ".ᵒˢ"
79
- elsif value.end_with?("as")
80
- ".ᵃˢ"
89
+
90
+ [self, suffix].join
91
+ end
92
+
93
+ # Build the long form of a given number. In this context, it is used for every digit except the last two.
94
+ # @param number [Integer] - A number to write in long form
95
+ # @return [String] - The long form of a number
96
+ def number_to_word(number)
97
+ if number.zero?
98
+ I18n.t("long_form.simple.ones.n_0", throw: true)
99
+ elsif number < 20
100
+ I18n.t("long_form.simple.ones.n_#{number}", throw: true)
101
+ elsif number < 100
102
+ [
103
+ I18n.t("long_form.simple.tens.n_#{number / 10}", throw: true),
104
+ (number % 10).zero? ? "" : "-#{I18n.t("long_form.simple.ones.n_#{number % 10}", throw: true)}"
105
+ ].join
106
+ elsif number < 1000
107
+ [
108
+ I18n.t("long_form.simple.ones.n_#{number / 100}", throw: true),
109
+ " ",
110
+ I18n.t("long_form.simple.hundred", throw: true),
111
+ (number % 100).zero? ? "" : " and #{number_to_word(number % 100)}"
112
+ ].join
113
+ else
114
+ i = 0
115
+ meow = number
116
+ while meow >= 1000
117
+ meow /= 1000
118
+ i += 1
81
119
  end
120
+ the_one_tenth = number % ((10**(3 * i)))
121
+ [
122
+ number_to_word(meow),
123
+ " ",
124
+ i.positive? ? I18n.t("long_form.simple.larger.n_#{i}", throw: true) : "",
125
+ the_one_tenth.zero? ? "" : " #{number_to_word(the_one_tenth)}"
126
+ ].join
82
127
  end
128
+ end
83
129
 
84
- [self, suffix].join
130
+ # Builds the ordinalized version of a number. Specific to english. Really only the two least significant digits are
131
+ # ordinalized, and the rest are just in long format
132
+ # @param number [Integer] - A number to ordinalize in long form
133
+ # @return [String] - The long form of a number as an ordinal
134
+ def number_to_ordinal_word(number)
135
+ if number.zero?
136
+ I18n.t("long_form.ordinal.ones.n_0", throw: true)
137
+ elsif number < 20
138
+ I18n.t("long_form.ordinal.ones.n_#{number}", throw: true)
139
+ elsif number < 100 && (number % 10).zero?
140
+ I18n.t("long_form.ordinal.tens.n_#{number / 10}", throw: true)
141
+ elsif number < 100
142
+ "#{number_to_word(number - (number % 10))}-#{I18n.t("long_form.ordinal.ones.n_#{number % 10}", throw: true)}"
143
+ elsif number >= 100 && (number % 100).zero?
144
+ "#{number_to_word(number - (number % 100))}th"
145
+ else
146
+ "#{number_to_word(number - (number % 100))} and #{number_to_ordinal_word((number % 100))}"
147
+ end
148
+ end
149
+
150
+ # Builds the long form ordinal of an integer
151
+ # @return [String] - The long form ordinal of an integer (including negative)
152
+ def integer_to_long_form_ordinal
153
+ return "#{I18n.t('long_form.negative', throw: true)} #{number_to_ordinal_word(-self)}" if negative?
154
+
155
+ number_to_ordinal_word(self)
85
156
  end
86
157
  end
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "ordinalize_full"
8
- spec.version = "3.0.0"
8
+ spec.version = "3.1.0"
9
9
  spec.authors = ["Cédric Félizard"]
10
10
  spec.email = ["cedric@felizard.fr"]
11
11
  spec.summary = "Turns a number into an ordinal string such as first, second, third or 1st, 2nd, 3rd."
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = "https://github.com/infertux/ordinalize_full"
14
14
  spec.license = "MIT"
15
15
 
16
- spec.files = `git ls-files`.split($/)
16
+ spec.files = `git ls-files`.split($/) # rubocop:disable Style/SpecialGlobalVars
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.require_paths = ["lib"]
19
19
 
@@ -22,7 +22,6 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency "i18n", "~> 1.8"
23
23
 
24
24
  spec.add_development_dependency "bundler", ">= 1.5"
25
- spec.add_development_dependency "cane"
26
25
  spec.add_development_dependency "rake"
27
26
  spec.add_development_dependency "rspec", "~> 3"
28
27
  spec.add_development_dependency "rubocop"
@@ -8,10 +8,18 @@ describe OrdinalizeFull do
8
8
  before { I18n.locale = :en }
9
9
 
10
10
  specify { expect(1.ordinalize_in_full).to eq("first") }
11
- specify { expect(42.ordinalize_in_full).to eq("forty second") }
11
+ specify { expect(42.ordinalize_in_full).to eq("forty-second") }
12
+ specify { expect(2023.ordinalize_in_full).to eq("two thousand and twenty-third") }
13
+ specify { expect(2_147_483_647.ordinalize_in_full).to eq("two billion one hundred and forty-seven million four hundred and eighty-three thousand six hundred and forty-seventh") } # rubocop:disable Layout/LineLength
14
+
15
+ it "converts any number" do
16
+ 10.times do
17
+ expect { rand(1_000_000).ordinalize_in_full }.not_to raise_error
18
+ end
19
+ end
12
20
 
13
- it "raises with unknown numbers" do
14
- expect { 101.ordinalize_in_full }.to raise_error(NotImplementedError)
21
+ it "handles negatives too" do
22
+ expect(-273.ordinalize_in_full).to eq("negative two hundred and seventy-third")
15
23
  end
16
24
  end
17
25
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ordinalize_full
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cédric Félizard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-17 00:00:00.000000000 Z
11
+ date: 2023-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.5'
41
- - !ruby/object:Gem::Dependency
42
- name: cane
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: rake
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -167,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
153
  - !ruby/object:Gem::Version
168
154
  version: '0'
169
155
  requirements: []
170
- rubygems_version: 3.3.26
156
+ rubygems_version: 3.4.10
171
157
  signing_key:
172
158
  specification_version: 4
173
159
  summary: Turns a number into an ordinal string such as first, second, third or 1st,