num2words 0.1.3 → 0.1.5

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: 83b33cb28c58663786a3033b2aefceb7e0478d49d40b1db5b1bee5bc63f0198b
4
- data.tar.gz: 5293c916f1a5ad2726662cb5973033b23fa5f9b703920b2b4be21f293d47d67e
3
+ metadata.gz: 7fbb8e0f384b3baf9ca9081c7d2c2095817d883b55796d48196f0bfd5a111fcc
4
+ data.tar.gz: 1dd172a547a50ac707b78cb626e1ae81b0af1a631e7313b30a48afe414dc5d26
5
5
  SHA512:
6
- metadata.gz: c498c97a62099658e43c6d29159b9c6fc5c8d3113e19fdc0fe774966dbacce7084d8e0e5293e1a9b1b9cad5b0441af1ae35efe1922441a19196fd49f0d771756
7
- data.tar.gz: 53ceaa5a779dd1e7c3e8308d4f21dcafe2a3cde1a775ddb68fb7497be605d551497ee22350c3309feb4f21c648ff9546761c427ff5839ae43e0c01f073febc08
6
+ metadata.gz: 73b3f95666700ff9ad74b73c47f207becb76541d185dd0bdee98cbc89b2b33921a7b97651c844bc83029706cc52a84fde1cac98da8151bff8cfa1f77867cd1c2
7
+ data.tar.gz: 9008411287c518ecbc87c16426e9eaa9aebdb4f526a044a84a135df1c698cde43a16841cd9397faa97a890a3d1326df0945437a2b9112b608454e258f41b8f5f
data/CHANGELOG.md CHANGED
@@ -15,6 +15,56 @@
15
15
 
16
16
  ---
17
17
 
18
+ ## [0.1.5] - 2025-08-22
19
+ ### Added
20
+ - Расширение `Time#to_words`, возможность преобразовать строки с временем
21
+ ```ruby
22
+ "14:35:42".to_words(:ru)
23
+ # => "четырнадцать часов тридцать пять минут сорок две секунды"
24
+ ```
25
+ - Добавлен параметр `short: true` для `time` и `datetime`
26
+ Возвращает краткий вариант записи для time (`HH:MM`)
27
+ ```ruby
28
+ "14:35:42".to_words(:ru, short: true)
29
+ # => "четырнадцать часов тридцать пять минут"
30
+ ```
31
+ Возвращает краткий вариант записи для datetime на выбор - дата или время
32
+ ```ruby
33
+ "2024-08-21 14:35:42".to_words(:ru, :time)
34
+ # => "двадцать первого августа две тысячи двадцать четвёртого года"
35
+ ```
36
+ - Поддержка перевода времени в разных форматах:
37
+ - `:hours_only` — только часы
38
+ - `:hours_minutes` — часы и минуты
39
+ - `:hours_minutes_seconds` — часы, минуты и секунды
40
+
41
+ ## [0.1.4] - 2025-08-21
42
+ ### Added
43
+ - Расширение `String#to_words`, возможность преобразовать строки с датами
44
+ ```ruby
45
+ "21.08.2025".to_words(:ru)
46
+ # => "двадцать первое августа две тысячи двадцать пятого года"
47
+
48
+ "21.08.2025".to_words(:en)
49
+ # => "the twenty-first of August, two thousand twenty five"
50
+ ```
51
+ - Расширение `Date#to_words`, добавлена возможность преобразовывать объекты Date и DateTime
52
+ ```ruby
53
+ Date.new(2025, 8, 21).to_words(:ru)
54
+ # => "двадцать первого августа две тысячи двадцать пятого года"
55
+
56
+ Date.new(2025, 8, 21).to_words(:en)
57
+ # => "the twenty-first of August, two thousand twenty-five"
58
+ ```
59
+ - Поддержка параметра `format: :nominative`, можно получать даты в именительном падеже.
60
+ ```ruby
61
+ Date.new(2025, 8, 21).to_words(:ru, format: :nominative)
62
+ # => "двадцать первое августа две тысячи двадцать пятый год"
63
+
64
+ "19.07.2012".to_words(:ru, format: :nominative)
65
+ # => "девятнадцатое июля две тысячи двенадцатый год"
66
+ ```
67
+
18
68
  ## [0.1.3] – 2025-08-20
19
69
  ### Added
20
70
  - Параметр **`word_case:`** для методов `to_words`, `to_currency` со значениями:
data/README.md CHANGED
@@ -6,17 +6,20 @@
6
6
 
7
7
  ## ✨ Основные возможности
8
8
 
9
- - Поддержка **современных локалей** (включая русский и английский) через YAML-файлы `config/locales/*.yml`.
10
- - Удобные методы:
11
- - `Num2words.to_words(123)`
12
- - `Num2words.to_currency(12.34)`
13
- - Расширение `Integer` и `Float`:
14
- - `123.to_words(:en)`
15
- - `12.5.to_currency(locale: :ru)`
16
- - Короткая запись локали (символом): `123.to_words(:en)`
17
- - Lazy‑загрузка локалей (`lib/num2words/locales.rb`).
18
- - Унифицированный `Converter`, делегирующий логику нужной локали.
19
- - Разряды чисел и валюты настраиваются через I18n YAML.
9
+ - Поддержка **чисел, времени, дат и валют**:
10
+ - `Integer` → `123.to_words(:ru)` → `"сто двадцать три"`
11
+ - `Float` → `12.5.to_words(:en)` → `"twelve and five tenths"`
12
+ - `Time / DateTime` → `"2024-08-21 14:35:42".to_words(:ru, :time)` → `"четырнадцать часов тридцать пять минут сорок две секунды"`
13
+ - `Float.to_currency` `12.5.to_currency(:ru)` `"двенадцать рублей пятьдесят копеек"`
14
+ - Кастомизация вывода:
15
+ - Краткая форма (`short: true`)`"четырнадцать часов тридцать пять минут"`
16
+ - Форматы времени (`:hours_only`, `:hours_minutes`, `:hours_minutes_seconds`)
17
+ - Выбор локали: `:ru`, `:en` (из коробки), легко расширить YAML-файлами
18
+ - Расширение **Integer**, **Float**, **Date**, **Time**, **DateTime** удобными методами.
19
+ - Локали инициализируются только при обращении к ним (`lazy loading`) через `lib/num2words/locales.rb`.
20
+ - Унифицированный `Converter`, делегирующий работу нужной локали.
21
+ - Настраиваемые правила разрядов чисел и валют через I18n YAML.
22
+
20
23
 
21
24
  ---
22
25
 
@@ -40,21 +43,64 @@ gem install num2words
40
43
 
41
44
  ```ruby
42
45
  require "num2words"
46
+ ```
47
+
48
+ ### 🔢 Числа
49
+ ```ruby
50
+ # Integer
51
+ 123.to_words(:ru) # => "сто двадцать три"
52
+ 123.to_words(:en) # => "one hundred twenty three"
53
+
54
+ # Float
55
+ 45.67.to_words(:ru) # => "сорок пять целых шестьдесят семь сотых"
56
+ 45.67.to_words(:en) # => "forty five and sixty seven hundredths"
57
+ ```
43
58
 
44
- # По умолчанию используется I18n.locale или fallback :ru
45
- Num2words.to_words(21) # => "двадцать один"
46
- Num2words.to_currency(21.05) # => "двадцать один рубль пять копеек"
59
+ ### 💰 Валюта
60
+ ```ruby
61
+ 21.05.to_currency(:ru) # => "двадцать один рубль пять копеек"
62
+ 12.5.to_currency(:en) # => "twelve dollars fifty cents"
63
+ ```
47
64
 
48
- # Short-style:
49
- 123.to_words # "сто двадцать три"
50
- 123.to_words(:en) # "one hundred twenty three"
51
- 123.to_words(locale: :en) # "one hundred twenty three"
65
+ ### 📅 Дата
66
+ ```ruby
67
+ "2024-08-21".to_words(:ru, :date)
68
+ # => "двадцать первое августа две тысячи двадцать четвертого года"
52
69
 
53
- # Валюта:
54
- 12.5.to_currency(:en) # "twelve rubles fifty kopeks"
55
- 12.5.to_currency(locale: :ru) # "двенадцать рублей пятьдесят копеек"
70
+ "2024-08-21".to_words(:en, :date)
71
+ # => "the twenty-first of August, two thousand twenty four"
56
72
  ```
57
73
 
74
+ ### ⏰ Время
75
+ ```ruby
76
+ "14:35:42".to_words(:ru, :time)
77
+ # => "четырнадцать часов тридцать пять минут сорок две секунды"
78
+
79
+ "14:35:42".to_words(:ru, :time, short: true) # или короткая запись: "14:35:42".to_words(:ru, :time, true)
80
+ # => "четырнадцать часов тридцать пять минут"
81
+
82
+ "14:35:42".to_words(:en, :time)
83
+ # => "fourteen hours thirty five minutes forty two seconds"
84
+ ```
85
+
86
+ ### 🕓 Дата и время
87
+
88
+ ```ruby
89
+ "2024-08-21 14:35:42".to_words(:ru)
90
+ # => "двадцать первого августа две тысячи двадцать четвёртого года, четырнадцать часов тридцать пять минут сорок две секунды"
91
+
92
+ "2024-08-21 14:35:42".to_words(:en)
93
+ # => "the twenty-first of August, two thousand twenty four at fourteen hours thirty five minutes forty two seconds"
94
+ ```
95
+
96
+ ### ⚙️ Опции
97
+
98
+ - `locale: :ru | :en` — язык (по умолчанию берётся I18n.locale или :ru).
99
+ - `:date, :time, :datetime` — формат преобразования для строк.
100
+ - `short: true` — краткая форма для даты/времени.
101
+ - `Num2words.to_words(number, locale: :en)` — универсальный способ вызова без расширения базовых классов.
102
+ - `Num2words.to_currency(number)` — преобразование число в валюту.
103
+
58
104
  ### Консоль 💻
59
105
 
60
106
  Num2words поддерживает интерактивную консоль для быстрого тестирования.
@@ -138,6 +184,20 @@ bin/console
138
184
  - YAML-файл: `config/locales/xx.yml`
139
185
  - Обёртка: `lib/num2words/locales/xx.rb`
140
186
 
187
+ ### 🌍 Поддержка локалей (ru / en)
188
+
189
+ | Возможность | ru | en |
190
+ | ----------------------------- | --------- | ---------- |
191
+ | 🔢 Числа (Integer) | ✔ | ✔ |
192
+ | 🔢 Числа (Float) | ✔ | ✔ |
193
+ | 💰 Валюта | ✔ (рубли) | ✔ (rubles) |
194
+ | 💰 Валюта (short) | ✖ | ✖ |
195
+ | 💱 Выбор валюты (USD/EUR/…) | ✖ | ✖ |
196
+ | 📅 Дата | ✔ | ✔ |
197
+ | ⏰ Время | ✔ | ✔ |
198
+ | 🕓 Дата и время | ✔ | ✔ |
199
+ | 📝 Краткая форма даты/времени | ✔ | ✔ |
200
+
141
201
  ---
142
202
 
143
203
  ## 🧪 Тестирование
@@ -149,8 +209,10 @@ bundle exec rspec
149
209
  ## 📌 Roadmap
150
210
 
151
211
  - [x] 🇬🇧 Поддержка английского языка
152
- - [ ] 💵 Поддержка других валют (USD, EUR)
153
- - [ ] 🔠 Опция выбора регистра (строчные/Прописные)
212
+ - [x] 🔠 Опция выбора регистра (строчные/Прописные)
213
+ - [x] Краткая форма даты/времени
214
+ - [ ] 💵 Поддержка других валют (USD, EUR и т.д)
215
+ - [ ] 💰 Краткая форма валюты
154
216
 
155
217
  ---
156
218
 
@@ -39,3 +39,27 @@ en:
39
39
  10000000: ["ten-millionth", "ten-millionths", "ten-millionths"]
40
40
  100000000: ["hundred-millionth", "hundred-millionths", "hundred-millionths"]
41
41
  1000000000: ["billionth", "billionths", "billionths"]
42
+
43
+ numbers:
44
+ ordinals:
45
+ default:
46
+ masculine: ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth",
47
+ "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth" ,"fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth",
48
+ "twentieth", "twenty-first", "twenty-second", "twenty-third", "twenty-fourth", "twenty-fifth", "twenty-sixth", "twenty-seventh", "twenty-eighth", "twenty-ninth",
49
+ "thirtieth","thirty-first"]
50
+ datetime:
51
+ template: "%{date} at %{time}"
52
+ date:
53
+ template:
54
+ default: "the %{day} of %{month}, %{year}"
55
+ months:
56
+ default: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]
57
+ time:
58
+ template:
59
+ hours_only: "%{hours}"
60
+ hours_minutes: "%{hours} %{minutes}"
61
+ hours_minutes_seconds: "%{hours} %{minutes} %{seconds}"
62
+ words:
63
+ hour: ["hour", "hours", "hours"]
64
+ minute: ["minute", "minutes", "minutes"]
65
+ second: ["second", "seconds", "seconds"]
@@ -34,3 +34,43 @@ ru:
34
34
  10000000: ["десятимиллионная", "десятимиллионные", "десятимиллионных"]
35
35
  100000000: ["стомиллионная", "стомиллионные", "стомиллионных"]
36
36
  1000000000: ["миллиардная", "миллиардные", "миллиардных"]
37
+
38
+ numbers:
39
+ ordinals:
40
+ nominative:
41
+ masculine: ["первый", "второй", "третий", "четвёртый", "пятый", "шестой", "седьмой", "восьмой", "девятый", "десятый",
42
+ "одиннадцатый", "двенадцатый", "тринадцатый", "четырнадцатый", "пятнадцатый", "шестнадцатый", "семнадцатый", "восемнадцатый", "девятнадцатый",
43
+ "двадцатый", "двадцать первый", "двадцать второй", "двадцать третий", "двадцать четвёртый", "двадцать пятый", "двадцать шестой", "двадцать седьмой", "двадцать восьмой", "двадцать девятый",
44
+ "тридцатый", "тридцать первый"]
45
+ feminine: ["первая", "вторая", "третья", "четвёртая", "пятая", "шестая", "седьмая", "восьмая", "девятая",
46
+ "десятая", "одиннадцатая", "двенадцатая", "тринадцатая", "четырнадцатая", "пятнадцатая", "шестнадцатая", "семнадцатая", "восемнадцатая", "девятнадцатая",
47
+ "двадцатая", "двадцать первая", "двадцать вторая", "двадцать третья", "двадцать четвёртая", "двадцать пятая", "двадцать шестая", "двадцать седьмая", "двадцать восьмая", "двадцать девятая",
48
+ "тридцатая", "тридцать первая"]
49
+ neuter: ["первое", "второе", "третье", "четвёртое", "пятое", "шестое", "седьмое", "восьмое", "девятое",
50
+ "десятое", "одиннадцатое", "двенадцатое", "тринадцатое", "четырнадцатое", "пятнадцатое", "шестнадцатое", "семнадцатое", "восемнадцатое", "девятнадцатое",
51
+ "двадцатое", "двадцать первое", "двадцать второе", "двадцать третье", "двадцать четвёртое", "двадцать пятое", "двадцать шестое", "двадцать седьмое", "двадцать восьмое", "двадцать девятое",
52
+ "тридцатое", "тридцать первое"]
53
+ default:
54
+ masculine: ["первого", "второго", "третьего", "четвёртого", "пятого", "шестого", "седьмого", "восьмого", "девятого",
55
+ "десятого", "одиннадцатого", "двенадцатого", "тринадцатого", "четырнадцатого", "пятнадцатого", "шестнадцатого", "семнадцатого", "восемнадцатого", "девятнадцатого",
56
+ "двадцатого", "двадцать первого", "двадцать второго", "двадцать третьего", "двадцать четвёртого", "двадцать пятого", "двадцать шестого", "двадцать седьмого", "двадцать восьмого", "двадцать девятого",
57
+ "тридцатого", "тридцать первого"]
58
+
59
+ datetime:
60
+ template: "%{date}, %{time}"
61
+ date:
62
+ template:
63
+ default: "%{day} %{month} %{year} года"
64
+ nominative: "%{day} %{month} %{year} год"
65
+ months:
66
+ default: [ "января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря" ]
67
+ nominative: [ "января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря" ]
68
+ time:
69
+ template:
70
+ hours_only: "%{hours}"
71
+ hours_minutes: "%{hours} %{minutes}"
72
+ hours_minutes_seconds: "%{hours} %{minutes} %{seconds}"
73
+ words:
74
+ hour: ["час", "часа", "часов"]
75
+ minute: ["минута", "минуты", "минут"]
76
+ second: ["секунда", "секунды", "секунд"]
@@ -1,21 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "date"
4
+ require "time"
5
+
3
6
  module Num2words
4
7
  class Converter
5
8
  class << self
6
9
  def to_words(number, *args, **opts)
7
- locale = args.first.is_a?(Symbol) ? args.first : opts[:locale] || I18n.default_locale
8
- feminine = opts[:feminine] || false
9
- style = opts[:style] || :fraction
10
- word_case = opts[:word_case] || :downcase
10
+ locale = args[0].is_a?(Symbol) ? args[0] : opts[:locale] || I18n.default_locale
11
+ type_only = args[1].is_a?(Symbol) ? args[1] : opts[:only]
12
+ type_short = args[2].is_a?(TrueClass) || args[2].is_a?(FalseClass) ? args[2] : opts[:short] || false
13
+
14
+ feminine = opts[:feminine] || false
15
+ style = opts[:style] || :fraction
16
+ word_case = opts[:word_case] || :default
17
+ date_format = opts[:format] || :default
18
+
11
19
  locale_data = Locales[locale]
12
20
 
13
- result = if number.is_a?(Float)
14
- to_words_fractional(number, locale, feminine, locale_data, style: style)
15
- else
16
- to_words_integer(number, locale, feminine, locale_data)
21
+ result = case detect_type(number)
22
+ when :float then to_words_fractional(number, locale, feminine, locale_data, style: style)
23
+ when :integer then to_words_integer(number, locale, feminine, locale_data)
24
+ when :datetime then to_words_datetime(number, locale, locale_data, format: date_format, only: type_only, short: type_short)
25
+ when :date then to_words_date(number, locale, locale_data, format: date_format)
26
+ when :time then to_words_time(number, locale, locale_data, short: type_short)
27
+ else nil
17
28
  end
18
29
 
30
+ raise ArgumentError, "Unsupported input type: #{number.inspect}" if result.nil?
31
+
19
32
  apply_case(result, word_case)
20
33
  end
21
34
 
@@ -41,6 +54,7 @@ module Num2words
41
54
  private
42
55
 
43
56
  def pluralize(number, singular, few, plural)
57
+ number = number.abs
44
58
  return plural if (11..14).include?(number % 100)
45
59
 
46
60
  case number % 10
@@ -123,6 +137,107 @@ module Num2words
123
137
  words.join(" ")
124
138
  end
125
139
 
140
+ def to_words_date(date, locale, locale_data, format: :default)
141
+ date = Date.parse(date.to_s) unless date.is_a?(Date)
142
+
143
+ day, month, year = [date.day, date.month, date.year]
144
+
145
+ return date.strftime("%d.%m.%Y") if format == :short
146
+
147
+ months = locale_data::DATE[:months][format] || locale_data::DATE[:months][:default]
148
+ template = locale_data::DATE_TEMPLATE[format] || locale_data::DATE_TEMPLATE[:default]
149
+
150
+ raise ArgumentError, "Months not found for locale #{locale}" unless months
151
+ raise ArgumentError, "Template not found for locale #{locale}" unless template
152
+
153
+ day_words = to_words_ordinal(day, locale, format, locale_data, gender: :neuter)
154
+ month_words = months[month - 1]
155
+ year_words = to_words_ordinal(year, locale, format, locale_data)
156
+
157
+ template % { day: day_words, month: month_words, year: year_words }
158
+ end
159
+
160
+ def to_words_ordinal(value, locale, format, locale_data, gender: :masculine)
161
+ ordinals = locale_data::ORDINALS[format] rescue nil
162
+ raise ArgumentError, "Ordinals not found for locale #{locale}, format #{format}" unless ordinals
163
+
164
+ gender_data = ordinals[gender] || ordinals[:masculine]
165
+ raise ArgumentError, "Gender #{gender} not found for locale #{locale}, format #{format}" unless gender_data
166
+
167
+ return gender_data[value - 1] if gender_data[value]
168
+
169
+ if value > 31
170
+ thousands = (value / 100) * 100
171
+ last_two = value % 100
172
+
173
+ base_year = to_words_integer(thousands, locale, false, locale_data)
174
+ last_ordinal = gender_data[last_two - 1] || to_words_integer(last_two, locale, false, locale_data)
175
+ last_ordinal = to_words_integer(last_two, locale, false, locale_data) if locale == :en
176
+
177
+ return [base_year, last_ordinal].join(" ")
178
+ end
179
+
180
+ to_words_integer(value, locale, false, locale_data)
181
+ end
182
+
183
+ def to_words_time(time, locale, locale_data, format: :default, short: false)
184
+ time = Time.parse(time) if time.is_a?(String)
185
+
186
+ return time.strftime("%H:%M") if format == :short
187
+
188
+ words = locale_data::TIME[:words]
189
+ template = locale_data::TIME_TEMPLATE
190
+
191
+ hours = [
192
+ to_words_integer(time.hour, locale, false, locale_data),
193
+ pluralize(time.hour, *words[:hour])
194
+ ].join(" ")
195
+ minutes = [
196
+ to_words_integer(time.min, locale, true, locale_data),
197
+ pluralize(time.min, *words[:minute])
198
+ ].join(" ")
199
+ seconds = [
200
+ to_words_integer(time.sec, locale, true, locale_data),
201
+ pluralize(time.sec, *words[:second])
202
+ ].join(" ")
203
+
204
+ format = if short
205
+ time.min.zero? && time.sec.zero? ? :hours_only : :hours_minutes
206
+ else
207
+ format
208
+ end
209
+
210
+ case format
211
+ when :hours_only
212
+ template[:hours_only] % { hours: hours }
213
+ when :hours_minutes
214
+ template[:hours_minutes] % { hours: hours, minutes: minutes }
215
+ when :hours_minutes_seconds, :default
216
+ template[:hours_minutes_seconds] % { hours: hours, minutes: minutes, seconds: seconds }
217
+ else
218
+ raise ArgumentError, "Unsupported time format: #{format}"
219
+ end
220
+ end
221
+
222
+
223
+ def to_words_datetime(datetime, locale, locale_data, format: :default, only: nil, short: false)
224
+ datetime = DateTime.parse(datetime) if datetime.is_a?(String)
225
+
226
+ date_format = short && only == :date ? :short : format
227
+ time_format = short && only == :time ? :short : :default
228
+
229
+ date_part = to_words_date(datetime.to_date, locale, locale_data, format: date_format)
230
+ time_part = to_words_time(datetime.to_time, locale, locale_data, format: time_format, short: short)
231
+
232
+ return date_part if only == :date
233
+ return time_part if only == :time
234
+
235
+ return "#{date_part}, #{time_part}" if short
236
+
237
+ template = locale_data::DATETIME_TEMPLATE
238
+ template % { date: date_part, time: time_part }
239
+ end
240
+
126
241
  def apply_case(text, word_case)
127
242
  case word_case
128
243
  when :upper then text.upcase
@@ -132,6 +247,35 @@ module Num2words
132
247
  else text
133
248
  end
134
249
  end
250
+
251
+ def detect_type(value)
252
+ case value
253
+ when Integer then :integer
254
+ when Float then :float
255
+ when Date then :date
256
+ when Time then :time
257
+ when DateTime then :datetime
258
+ when String
259
+ return :integer if value.match?(/\A-?\d+\z/)
260
+ return :float if value.match?(/\A-?\d+\.\d+\z/)
261
+ return :time if value.match?(/\A\d{1,2}:\d{2}(:\d{2})?\z/)
262
+
263
+ # Форматы даты
264
+ return :date if value.match?(/\A\d{1,2}[.\-]\d{1,2}[.\-]\d{2,4}\z/)
265
+ return :date if value.match?(/\A\d{4}-\d{2}-\d{2}\z/)
266
+ return :datetime if value.match?(/\A\d{1,2}[.\-]\d{1,2}[.\-]\d{2,4}\s+\d{1,2}:\d{2}(:\d{2})?\z/)
267
+ return :datetime if value.match?(/\A\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(:\d{2})?([.,]\d+)?(Z|[+\-]\d{2}:?\d{2})?\z/)
268
+
269
+ begin
270
+ date_time = DateTime.parse(value)
271
+ (date_time.hour != 0 || date_time.min != 0 || date_time.sec != 0) ? :datetime : :date
272
+ rescue ArgumentError
273
+ :string
274
+ end
275
+ else
276
+ :unknown
277
+ end
278
+ end
135
279
  end
136
280
  end
137
281
  end
@@ -19,3 +19,27 @@ class Float
19
19
  Num2words::Converter.to_currency(self, *args, **opts)
20
20
  end
21
21
  end
22
+
23
+ class String
24
+ def to_words(*args, **opts)
25
+ Num2words::Converter.to_words(self, *args, **opts)
26
+ end
27
+ end
28
+
29
+ class Date
30
+ def to_words(*args, **opts)
31
+ Num2words::Converter.to_words(self.strftime("%d.%m.%Y"), *args, **opts)
32
+ end
33
+ end
34
+
35
+ class Time
36
+ def to_words(*args, **opts)
37
+ Num2words::Converter.to_words(self.strftime("%H:%M:%S"), *args, **opts)
38
+ end
39
+ end
40
+
41
+ class DateTime
42
+ def to_words(*args, **opts)
43
+ Num2words::Converter.to_words(self.strftime("%d.%m.%Y %H:%M:%S"), *args, **opts)
44
+ end
45
+ end
@@ -15,6 +15,14 @@ module Num2words
15
15
 
16
16
  FRACTIONS = I18n.t("num2words.fractions", locale: :en)
17
17
  GRAMMAR = I18n.t("num2words.grammar", locale: :en)
18
+
19
+ DATE = I18n.t("num2words.date", locale: :en)
20
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :en)
21
+ TIME = I18n.t("num2words.time", locale: :en)
22
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :en)
23
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :en)
24
+
25
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :en)
18
26
  end
19
27
 
20
28
  register :en, EN
@@ -15,6 +15,14 @@ module Num2words
15
15
 
16
16
  FRACTIONS = I18n.t("num2words.fractions", locale: :ru)
17
17
  GRAMMAR = I18n.t("num2words.grammar", locale: :ru)
18
+
19
+ DATE = I18n.t("num2words.date", locale: :ru)
20
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :ru)
21
+ TIME = I18n.t("num2words.time", locale: :ru)
22
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :ru)
23
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :ru)
24
+
25
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :ru)
18
26
  end
19
27
 
20
28
  register :ru, RU
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Num2words
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.5"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: num2words
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Fedotov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-08-20 00:00:00.000000000 Z
11
+ date: 2025-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n