tater 2.0.2 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tater.rb +163 -196
  3. data/test/tater_test.rb +29 -14
  4. metadata +21 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb7166fcdf9b548f8837e4411bfe5d83712f202e1de27c299fa0e5694b50bc2b
4
- data.tar.gz: ab3f53e56fa8538f39ce59ba9f2e42496e5bea116a880fc26e23ad2091e5e93c
3
+ metadata.gz: 866326a5050b49de428a273e71709fe84f1a4e2e82c5325fef634fcea8282878
4
+ data.tar.gz: af9bdb6c35c928886bf3f50779447e88a9a4f4ce7c36222bb3f5bb762ec2f59a
5
5
  SHA512:
6
- metadata.gz: ceb821ff34a086711feb0df9e21a7aa4c7891a3e84fc52a9cf62d5972462c6ab0a5f81eef2ab820ef95df7211dda82e2a56299a1ced017e468c50358b6e537db
7
- data.tar.gz: 2ad3f4c078bb63e39b5650254f92cb3859c39c73f4eaf2dfae18320e60712bf2c632e42c38770c39a456ee62f13fbf6262e1fef527846c17c53d7ebd859fa6de
6
+ metadata.gz: fb353520b23e2235ee49899e84460f5667a6767c38019ce38e19eb823fe181eba3d7cecc9a4f72a907c77afc279a94994ab505073e29861169cb064b1f56bf32
7
+ data.tar.gz: b6ff46ec8d5f33f44bae20a3996aa9e77bd1a101a6f841e1a35c7af74fca33353817974a2414739734095f6a3315898bec0edd2726eef18ec78feae28edee58d
data/lib/tater.rb CHANGED
@@ -1,97 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
  require 'bigdecimal'
3
+ require 'date'
4
+ require 'time'
3
5
  require 'yaml'
6
+ require 'tater/utils'
7
+ require 'tater/hash' unless Hash.method_defined?(:except)
4
8
 
5
9
  # Tater is a internationalization (i18n) and localization (l10n) library
6
10
  # designed for speed and simplicity.
7
11
  class Tater
8
12
  class MissingLocalizationFormat < ArgumentError; end
9
-
10
13
  class UnLocalizableObject < ArgumentError; end
11
14
 
12
- module Utils # :nodoc:
13
- # Merge all the way down.
14
- #
15
- # @param to [Hash]
16
- # The target Hash to merge into.
17
- # @param from [Hash]
18
- # The Hash to copy values from.
19
- # @return [Hash]
20
- def self.deep_merge(to, from)
21
- to.merge(from) do |_key, left, right|
22
- if left.is_a?(Hash) && right.is_a?(Hash)
23
- Utils.deep_merge(left, right)
24
- else
25
- right
26
- end
27
- end
28
- end
29
-
30
- # Transform keys all the way down.
31
- #
32
- # @param hash [Hash]
33
- # The Hash to stringify keys for.
34
- # @return [Hash]
35
- def self.deep_stringify_keys(hash)
36
- hash.transform_keys(&:to_s).transform_values do |value|
37
- if value.is_a?(Hash)
38
- Utils.deep_stringify_keys(value)
39
- else
40
- value
41
- end
42
- end
43
- end
44
-
45
- # Freeze all the way down.
46
- #
47
- # @param hash [Hash]
48
- # @return [Hash]
49
- def self.deep_freeze(hash)
50
- hash.transform_keys(&:freeze).transform_values do |value|
51
- if value.is_a?(Hash)
52
- Utils.deep_freeze(value)
53
- else
54
- value.freeze
55
- end
56
- end.freeze
57
- end
58
-
59
- # Try to interpolate these things, if one of them is a string.
60
- #
61
- # @param string [String]
62
- # The target string to interpolate into.
63
- # @param options [Hash]
64
- # The values to interpolate into the target string.
65
- #
66
- # @return [String]
67
- def self.interpolate(string, options = HASH)
68
- return string unless string.is_a?(String)
69
- return string if options.empty?
70
-
71
- format(string, options)
72
- end
73
-
74
- # Convert a Numeric to a string, particularly formatting BigDecimals to a
75
- # Float-like string representation.
76
- #
77
- # @param numeric [Numeric]
78
- #
79
- # @return [String]
80
- def self.string_from_numeric(numeric)
81
- if numeric.is_a?(BigDecimal)
82
- numeric.to_s('F')
83
- else
84
- numeric.to_s
85
- end
86
- end
87
- end
88
-
89
15
  DEFAULT = 'default'
90
16
  DELIMITING_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/.freeze
91
17
  HASH = {}.freeze
92
18
  SEPARATOR = '.'
93
19
  SUBSTITUTION_REGEX = /%(|\^)[aAbBpP]/.freeze
94
20
 
21
+ # Needed for Ruby < 3.
22
+ using HashExcept unless Hash.method_defined?(:except)
23
+
95
24
  # @return [String]
96
25
  attr_reader :locale
97
26
 
@@ -107,7 +36,6 @@ class Tater
107
36
  # @param path [String]
108
37
  # A path to search for YAML or Ruby files to load messages from.
109
38
  def initialize(cascade: false, locale: nil, messages: nil, path: nil)
110
- @cache = {}
111
39
  @cascade = cascade
112
40
  @locale = locale
113
41
  @messages = {}
@@ -153,7 +81,7 @@ class Tater
153
81
  end
154
82
 
155
83
  Dir.glob(File.join(path, '**', '*.rb')).each do |file|
156
- @messages = Utils.deep_merge(@messages, Utils.deep_stringify_keys(eval(IO.read(file), binding, file))) # rubocop:disable Security/Eval
84
+ @messages = Utils.deep_merge(@messages, Utils.deep_stringify_keys(eval(File.read(file), binding, file))) # rubocop:disable Security/Eval
157
85
  end
158
86
  end
159
87
 
@@ -165,8 +93,10 @@ class Tater
165
93
 
166
94
  # Not only does this clear our cache but it establishes the basic structure
167
95
  # that we rely on in other methods.
96
+ @cache = {}
97
+
168
98
  @messages.each_key do |key|
169
- @cache[key] = { true => {}, false => {} }
99
+ @cache[key] = { false => {}, true => {} }
170
100
  end
171
101
  end
172
102
 
@@ -190,9 +120,9 @@ class Tater
190
120
  # @option options [String] :locale
191
121
  # The locale to use in lieu of the current default.
192
122
  # @option options [String] :delimiter
193
- # The delimiter to use when localizing numberic values.
123
+ # The delimiter to use when localizing numeric values.
194
124
  # @option options [String] :separator
195
- # The separator to use when localizing numberic values.
125
+ # The separator to use when localizing numeric values.
196
126
  # @option options [String] :two_words_connector
197
127
  # The string used to join two array elements together e.g. " and ".
198
128
  # @option options [String] :words_connector
@@ -208,109 +138,57 @@ class Tater
208
138
  when String
209
139
  object
210
140
  when Numeric
211
- delimiter = options[:delimiter] || lookup('numeric.delimiter', locale: options[:locale])
212
- separator = options[:separator] || lookup('numeric.separator', locale: options[:locale])
213
- precision = options[:precision] || 2
214
-
215
- raise(MissingLocalizationFormat, "Numeric localization delimiter ('numeric.delimiter') missing or not passed as option :delimiter") unless delimiter
216
- raise(MissingLocalizationFormat, "Numeric localization separator ('numeric.separator') missing or not passed as option :separator") unless separator
217
-
218
- # Break the number up into integer and fraction parts.
219
- integer = Utils.string_from_numeric(object)
220
- integer, fraction = integer.split('.') unless object.is_a?(Integer)
221
-
222
- if integer.length > 3
223
- integer.gsub!(DELIMITING_REGEX) do |number|
224
- "#{ number }#{ delimiter }"
225
- end
226
- end
227
-
228
- if precision.zero? || fraction.nil?
229
- integer
230
- else
231
- "#{ integer }#{ separator }#{ fraction.ljust(precision, '0').slice(0, precision) }"
232
- end
141
+ localize_numeric(object, options)
233
142
  when Date, Time, DateTime
234
- format = lookup("#{ object.class.to_s.downcase }.formats.#{ options[:format] || DEFAULT }", locale: options[:locale]) || options[:format] || DEFAULT
235
-
236
- # Heavily cribbed from I18n, many thanks to the people who sorted this out
237
- # before I worked on this library.
238
- format = format.gsub(SUBSTITUTION_REGEX) do |match|
239
- case match
240
- when '%a' then lookup('date.abbreviated_days', locale: options[:locale])[object.wday]
241
- when '%^a' then lookup('date.abbreviated_days', locale: options[:locale])[object.wday].upcase
242
- when '%A' then lookup('date.days', locale: options[:locale])[object.wday]
243
- when '%^A' then lookup('date.days', locale: options[:locale])[object.wday].upcase
244
- when '%b' then lookup('date.abbreviated_months', locale: options[:locale])[object.mon - 1]
245
- when '%^b' then lookup('date.abbreviated_months', locale: options[:locale])[object.mon - 1].upcase
246
- when '%B' then lookup('date.months', locale: options[:locale])[object.mon - 1]
247
- when '%^B' then lookup('date.months', locale: options[:locale])[object.mon - 1].upcase
248
- when '%p' then lookup("time.#{ object.hour < 12 ? 'am' : 'pm' }", locale: options[:locale]).upcase if object.respond_to?(:hour) # rubocop:disable Metrics/BlockNesting
249
- when '%P' then lookup("time.#{ object.hour < 12 ? 'am' : 'pm' }", locale: options[:locale]).downcase if object.respond_to?(:hour) # rubocop:disable Metrics/BlockNesting
250
- end
251
- end
252
-
253
- object.strftime(format)
143
+ localize_datetime(object, options)
254
144
  when Array
255
- case object.length
256
- when 0
257
- ''
258
- when 1
259
- object[0]
260
- when 2
261
- two_words_connector = options[:two_words_connector] || lookup('array.two_words_connector', locale: options[:locale])
262
-
263
- raise(MissingLocalizationFormat, "Sentence localization connector ('array.two_words_connector') missing or not passed as option :two_words_connector") unless two_words_connector
264
-
265
- "#{ object[0] }#{ two_words_connector }#{ object[1] }"
266
- else
267
- last_word_connector = options[:last_word_connector] || lookup('array.last_word_connector', locale: options[:locale])
268
- words_connector = options[:words_connector] || lookup('array.words_connector', locale: options[:locale])
269
-
270
- raise(MissingLocalizationFormat, "Sentence localization connector ('array.last_word_connector') missing or not passed as option :last_word_connector") unless last_word_connector
271
- raise(MissingLocalizationFormat, "Sentence localization connector ('array.words_connector') missing or not passed as option :words_connector") unless words_connector
272
-
273
- "#{ object[0...-1].join(words_connector) }#{ last_word_connector }#{ object[-1] }"
274
- end
145
+ localize_array(object, options)
275
146
  else
276
147
  raise(UnLocalizableObject, "The object class #{ object.class } cannot be localized by Tater.")
277
148
  end
278
149
  end
279
- alias l localize
280
150
 
281
151
  # Lookup a key in the messages hash, using the current locale or an override.
282
152
  #
153
+ # @example Using the default locale, look up a key's value.
154
+ # i18n = Tater.new(locale: 'en', messages: { 'en' => { 'greeting' => { 'world' => 'Hello, world!' } } })
155
+ # i18n.lookup('greeting.world') # => "Hello, world!"
156
+ #
283
157
  # @param key [String]
158
+ # The period-separated key path to look for within our messages.
284
159
  # @param locale [String]
285
- # A locale to use instead of our current one.
160
+ # A locale to use instead of our current one, if any.
286
161
  # @param cascade [Boolean]
287
162
  # A boolean to forcibly set the cascade option for this lookup.
288
163
  #
289
164
  # @return
290
165
  # Basically anything that can be stored in your messages Hash.
291
166
  def lookup(key, locale: nil, cascade: nil)
292
- locale = locale.nil? ? @locale : locale
293
- cascade = cascade.nil? ? @cascade : cascade
167
+ locale =
168
+ if locale.nil?
169
+ @locale
170
+ else
171
+ locale.to_s
172
+ end
294
173
 
295
- cached(key, locale, cascade) || begin
296
- return nil unless @messages.key?(locale.to_s)
174
+ cascade = @cascade if cascade.nil?
297
175
 
298
- path = key.split(SEPARATOR).prepend(locale).map(&:to_s)
176
+ @cache[locale][cascade][key] ||= begin
177
+ path = key.split(SEPARATOR)
299
178
 
300
- message =
301
- if cascade
302
- while path.length >= 2
303
- attempt = @messages.dig(*path)
304
-
305
- break attempt unless attempt.nil?
179
+ message = @messages[locale].dig(*path)
306
180
 
181
+ if message.nil? && cascade
182
+ message =
183
+ while path.length > 1
307
184
  path.delete_at(path.length - 2)
185
+ attempt = @messages[locale].dig(*path)
186
+
187
+ break attempt unless attempt.nil?
308
188
  end
309
- else
310
- @messages.dig(*path)
311
- end
189
+ end
312
190
 
313
- cache(key, locale, cascade, message)
191
+ message
314
192
  end
315
193
  end
316
194
 
@@ -373,51 +251,140 @@ class Tater
373
251
  # The translated and interpreted string, if found, or any data at the
374
252
  # defined key.
375
253
  def translate(key, options = HASH)
376
- message =
377
- if options.key?(:locales)
378
- options[:locales].append(@locale) if @locale && !options[:locales].include?(@locale)
254
+ if options.empty?
255
+ message = lookup(key)
379
256
 
380
- options[:locales].find do |accept|
381
- found = lookup(key, locale: accept, cascade: options[:cascade])
382
-
383
- break found unless found.nil?
384
- end
257
+ if message.is_a?(Proc) # rubocop:disable Style/CaseLikeIf
258
+ message.call(key)
259
+ elsif message.is_a?(String)
260
+ message
385
261
  else
386
- lookup(key, locale: options[:locale], cascade: options[:cascade])
262
+ "Tater lookup failed: #{ locale }.#{ key }"
387
263
  end
264
+ else
265
+ message =
266
+ if options.key?(:locales)
267
+ options[:locales].append(@locale) if @locale && !options[:locales].include?(@locale)
388
268
 
389
- # Call procs that should return a string.
390
- message = message.call(key, options) if message.is_a?(Proc)
269
+ options[:locales].find do |accept|
270
+ found = lookup(key, locale: accept, cascade: options[:cascade])
391
271
 
392
- Utils.interpolate(message, options) || options[:default] || "Tater lookup failed: #{ options[:locale] || options[:locales] || locale }.#{ key }"
272
+ break found unless found.nil?
273
+ end
274
+ else
275
+ lookup(key, locale: options[:locale], cascade: options[:cascade])
276
+ end
277
+
278
+ if message.is_a?(Proc) # rubocop:disable Style/CaseLikeIf
279
+ message.call(key, options.except(:cascade, :default, :locale, :locales))
280
+ elsif message.is_a?(String)
281
+ Utils.interpolate(message, options.except(:cascade, :default, :locale, :locales))
282
+ else
283
+ options[:default] || "Tater lookup failed: #{ options[:locale] || options[:locales] || locale }.#{ key }"
284
+ end
285
+ end
393
286
  end
394
- alias t translate
395
287
 
396
288
  private
397
289
 
398
- # @param key [String]
399
- # The cache key, often in the form "something.nested.like.this"
400
- # @param locale [String]
401
- # The locale to store the value for.
402
- # @param cascade [Boolean]
403
- # Was this a cascading lookup?
404
- # @param message [String]
405
- # The message being cached, often a String.
290
+ # Localize an Array object.
291
+ #
292
+ # @param object [Array<String>]
293
+ # The array to localize.
294
+ # @param options [Hash]
295
+ # Options to configure localization.
296
+ # @return [String]
297
+ # The localize array string.
298
+ def localize_array(object, options)
299
+ case object.length
300
+ when 0
301
+ ''
302
+ when 1
303
+ object[0]
304
+ when 2
305
+ two_words_connector = options[:two_words_connector] || lookup('array.two_words_connector', locale: options[:locale])
306
+
307
+ raise(MissingLocalizationFormat, "Sentence localization connector ('array.two_words_connector') missing or not passed as option :two_words_connector") unless two_words_connector
308
+
309
+ "#{ object[0] }#{ two_words_connector }#{ object[1] }"
310
+ else
311
+ last_word_connector = options[:last_word_connector] || lookup('array.last_word_connector', locale: options[:locale])
312
+ words_connector = options[:words_connector] || lookup('array.words_connector', locale: options[:locale])
313
+
314
+ raise(MissingLocalizationFormat, "Sentence localization connector ('array.last_word_connector') missing or not passed as option :last_word_connector") unless last_word_connector
315
+ raise(MissingLocalizationFormat, "Sentence localization connector ('array.words_connector') missing or not passed as option :words_connector") unless words_connector
316
+
317
+ "#{ object[0...-1].join(words_connector) }#{ last_word_connector }#{ object[-1] }"
318
+ end
319
+ end
320
+
321
+ # Localize a Date, DateTime, or Time object.
322
+ #
323
+ # @param object [Date, DateTime, Time]
324
+ # The date-ish object to localize.
325
+ # @param options [Hash]
326
+ # Options to configure localization.
406
327
  # @return [String]
407
- # Whatever value is being cached, often a String.
408
- def cache(key, locale, cascade, message)
409
- @cache[locale][cascade][key] = message
328
+ # The localized date string.
329
+ def localize_datetime(object, options)
330
+ frmt = options[:format] || DEFAULT
331
+ loc = options[:locale]
332
+ format = lookup("#{ object.class.to_s.downcase }.formats.#{ frmt }", locale: loc) || frmt
333
+
334
+ # Heavily cribbed from I18n, many thanks to the people who sorted this out
335
+ # before I worked on this library.
336
+ format = format.gsub(SUBSTITUTION_REGEX) do |match|
337
+ case match
338
+ when '%a' then lookup('date.abbreviated_days', locale: loc)[object.wday]
339
+ when '%^a' then lookup('date.abbreviated_days', locale: loc)[object.wday].upcase
340
+ when '%A' then lookup('date.days', locale: loc)[object.wday]
341
+ when '%^A' then lookup('date.days', locale: loc)[object.wday].upcase
342
+ when '%b' then lookup('date.abbreviated_months', locale: loc)[object.mon - 1]
343
+ when '%^b' then lookup('date.abbreviated_months', locale: loc)[object.mon - 1].upcase
344
+ when '%B' then lookup('date.months', locale: loc)[object.mon - 1]
345
+ when '%^B' then lookup('date.months', locale: loc)[object.mon - 1].upcase
346
+ when '%p' then lookup("time.#{ object.hour < 12 ? 'am' : 'pm' }", locale: loc).upcase if object.respond_to?(:hour)
347
+ when '%P' then lookup("time.#{ object.hour < 12 ? 'am' : 'pm' }", locale: loc).downcase if object.respond_to?(:hour)
348
+ end
349
+ end
350
+
351
+ if format.include?('%')
352
+ object.strftime(format)
353
+ else
354
+ format
355
+ end
410
356
  end
411
357
 
412
- # @param key [String]
413
- # The cache key, often in the form "something.nested.like.this"
414
- # @param locale [String]
415
- # The locale to store the value for.
416
- # @param cascade [Boolean]
417
- # Was this a cascading lookup?
418
- # @return [String, nil]
419
- # The cached message or nil.
420
- def cached(key, locale, cascade)
421
- @cache.dig(locale, cascade, key)
358
+ # Localize a Numeric object.
359
+ #
360
+ # @param object [Array<String>, Date, Time, DateTime, Numeric]
361
+ # The object to localize.
362
+ # @param options [Hash]
363
+ # Options to configure localization.
364
+ # @return [String]
365
+ # The localized numeric string.
366
+ def localize_numeric(object, options)
367
+ delimiter = options[:delimiter] || lookup('numeric.delimiter', locale: options[:locale])
368
+ separator = options[:separator] || lookup('numeric.separator', locale: options[:locale])
369
+ precision = options[:precision] || 2
370
+
371
+ raise(MissingLocalizationFormat, "Numeric localization delimiter ('numeric.delimiter') missing or not passed as option :delimiter") unless delimiter
372
+ raise(MissingLocalizationFormat, "Numeric localization separator ('numeric.separator') missing or not passed as option :separator") unless separator
373
+
374
+ # Break the number up into integer and fraction parts.
375
+ integer = Utils.string_from_numeric(object)
376
+ integer, fraction = integer.split('.') unless object.is_a?(Integer)
377
+
378
+ if object >= 1_000
379
+ integer.gsub!(DELIMITING_REGEX) do |number|
380
+ "#{ number }#{ delimiter }"
381
+ end
382
+ end
383
+
384
+ if precision.zero? || fraction.nil?
385
+ integer
386
+ else
387
+ "#{ integer }#{ separator }#{ fraction.ljust(precision, '0').slice(0, precision) }"
388
+ end
422
389
  end
423
390
  end
data/test/tater_test.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
- require_relative '../lib/tater'
3
- require 'minitest/autorun'
2
+ $LOAD_PATH.unshift File.expand_path('lib', __dir__)
3
+
4
4
  require 'date'
5
+ require 'minitest/autorun'
6
+ require 'tater'
5
7
 
6
8
  describe Tater do
7
9
  describe Tater::Utils do
@@ -59,6 +61,20 @@ describe Tater do
59
61
  assert_equal '1.0', Tater::Utils.string_from_numeric(BigDecimal('1'))
60
62
  end
61
63
  end
64
+
65
+ describe '#interpolation_string?' do
66
+ def is?(arg)
67
+ Tater::Utils.interpolation_string?(arg)
68
+ end
69
+
70
+ it 'checks whether a string contains interpolation placeholders' do
71
+ assert is?('Hey %{there}!')
72
+ assert is?('Hey %<there>s!')
73
+ refute is?('Nah, this is fine')
74
+ refute is?("<b>HTML shouldn't count")
75
+ refute is?("A single % shouldn't count")
76
+ end
77
+ end
62
78
  end
63
79
 
64
80
  describe '#available?' do
@@ -141,6 +157,10 @@ describe Tater do
141
157
  assert_nil i18n.lookup('nope')
142
158
  end
143
159
 
160
+ it 'returns arbitrary data at keys' do
161
+ assert_equal({ 'key' => 'This key is deeper' }, i18n.lookup('deep'))
162
+ end
163
+
144
164
  it 'cascades' do
145
165
  assert_equal 'Delicious', i18n.lookup('cascade.nope.tacos', cascade: true)
146
166
  assert_equal 'Whoaa', i18n.lookup('cascade.another.nope.crazy', cascade: true)
@@ -162,8 +182,8 @@ describe Tater do
162
182
  assert_equal 'This key is deeper', i18n.translate('deep.key')
163
183
  end
164
184
 
165
- it 'returns a hash for nested keys' do
166
- assert_equal({ 'key' => 'This key is deeper' }, i18n.translate('deep'))
185
+ it 'does not return a hash for nested keys' do
186
+ assert_equal 'Tater lookup failed: en.deep', i18n.translate('deep')
167
187
  end
168
188
 
169
189
  it 'interpolates additional variables' do
@@ -180,10 +200,6 @@ describe Tater do
180
200
  assert_equal 'Tater lookup failed: en.nope', i18n.translate('nope')
181
201
  end
182
202
 
183
- it 'is aliased as t' do
184
- assert_equal 'This is a title', i18n.t('title')
185
- end
186
-
187
203
  it 'cascades lookups' do
188
204
  assert_equal 'Tater lookup failed: en.cascade.another.nope.crazy', i18n.translate('cascade.another.nope.crazy', cascade: false)
189
205
  assert_equal 'Tater lookup failed: en.cascade.nope.tacos', i18n.translate('cascade.nope.tacos')
@@ -201,9 +217,12 @@ describe Tater do
201
217
  assert_equal 'Tater lookup failed: ["fr", "en"].neither', i18n.translate('neither', locales: %w[fr en])
202
218
  end
203
219
 
204
- it 'finds Ruby files as well' do
220
+ it 'finds Ruby files' do
205
221
  assert_equal 'Hey ruby!', i18n.translate('ruby')
206
- assert_equal 'Hey options!', i18n.translate('options', options: 'options')
222
+ end
223
+
224
+ it 'does not interpolate messages returned by procs' do
225
+ assert_equal 'Hey %{options}!', i18n.translate('options', options: 'options')
207
226
  end
208
227
  end
209
228
 
@@ -314,10 +333,6 @@ describe Tater do
314
333
  end
315
334
  end
316
335
 
317
- it 'is aliased l' do
318
- assert_equal '1970/1/1', i18n.l(Date.new(1970, 1, 1))
319
- end
320
-
321
336
  describe 'month, day, and AM/PM names' do
322
337
  let :i18n do
323
338
  Tater.new(path: File.expand_path('test/fixtures'), locale: 'fr')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tater
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Lecklider
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-21 00:00:00.000000000 Z
11
+ date: 2021-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-packaging
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: rubocop-performance
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -128,8 +142,9 @@ licenses:
128
142
  - MIT
129
143
  metadata:
130
144
  bug_tracker_uri: https://github.com/evanleck/tater/issues
145
+ rubygems_mfa_required: 'true'
131
146
  source_code_uri: https://github.com/evanleck/tater
132
- post_install_message:
147
+ post_install_message:
133
148
  rdoc_options: []
134
149
  require_paths:
135
150
  - lib
@@ -144,8 +159,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
144
159
  - !ruby/object:Gem::Version
145
160
  version: '2.0'
146
161
  requirements: []
147
- rubygems_version: 3.2.15
148
- signing_key:
162
+ rubygems_version: 3.2.32
163
+ signing_key:
149
164
  specification_version: 4
150
165
  summary: Minimal internationalization and localization library.
151
166
  test_files: