activesupport 5.2.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +362 -333
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/array_inquirer.rb +4 -2
  7. data/lib/active_support/backtrace_cleaner.rb +29 -3
  8. data/lib/active_support/benchmarkable.rb +1 -1
  9. data/lib/active_support/cache/file_store.rb +33 -33
  10. data/lib/active_support/cache/mem_cache_store.rb +31 -29
  11. data/lib/active_support/cache/memory_store.rb +59 -33
  12. data/lib/active_support/cache/null_store.rb +8 -3
  13. data/lib/active_support/cache/redis_cache_store.rb +84 -45
  14. data/lib/active_support/cache/strategy/local_cache.rb +41 -26
  15. data/lib/active_support/cache.rb +174 -113
  16. data/lib/active_support/callbacks.rb +81 -64
  17. data/lib/active_support/concern.rb +76 -5
  18. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  19. data/lib/active_support/concurrency/share_lock.rb +0 -1
  20. data/lib/active_support/configurable.rb +10 -14
  21. data/lib/active_support/configuration_file.rb +46 -0
  22. data/lib/active_support/core_ext/array/access.rb +18 -6
  23. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  24. data/lib/active_support/core_ext/array/extract.rb +21 -0
  25. data/lib/active_support/core_ext/array.rb +1 -1
  26. data/lib/active_support/core_ext/benchmark.rb +2 -2
  27. data/lib/active_support/core_ext/class/attribute.rb +32 -47
  28. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  29. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  30. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  31. data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
  32. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  33. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  34. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  35. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  36. data/lib/active_support/core_ext/digest.rb +3 -0
  37. data/lib/active_support/core_ext/enumerable.rb +171 -70
  38. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  39. data/lib/active_support/core_ext/hash/conversions.rb +3 -3
  40. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  41. data/lib/active_support/core_ext/hash/except.rb +2 -2
  42. data/lib/active_support/core_ext/hash/keys.rb +1 -30
  43. data/lib/active_support/core_ext/hash/slice.rb +6 -27
  44. data/lib/active_support/core_ext/hash.rb +1 -2
  45. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  46. data/lib/active_support/core_ext/kernel.rb +0 -1
  47. data/lib/active_support/core_ext/load_error.rb +1 -1
  48. data/lib/active_support/core_ext/marshal.rb +2 -0
  49. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  50. data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
  51. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
  52. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  53. data/lib/active_support/core_ext/module/delegation.rb +76 -33
  54. data/lib/active_support/core_ext/module/introspection.rb +16 -15
  55. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  56. data/lib/active_support/core_ext/module.rb +0 -1
  57. data/lib/active_support/core_ext/name_error.rb +29 -2
  58. data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
  59. data/lib/active_support/core_ext/numeric.rb +0 -1
  60. data/lib/active_support/core_ext/object/blank.rb +1 -2
  61. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  62. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  63. data/lib/active_support/core_ext/object/json.rb +7 -2
  64. data/lib/active_support/core_ext/object/to_query.rb +5 -2
  65. data/lib/active_support/core_ext/object/try.rb +17 -7
  66. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  67. data/lib/active_support/core_ext/range/compare_range.rb +82 -0
  68. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  69. data/lib/active_support/core_ext/range/each.rb +0 -1
  70. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  71. data/lib/active_support/core_ext/range.rb +1 -1
  72. data/lib/active_support/core_ext/regexp.rb +8 -5
  73. data/lib/active_support/core_ext/securerandom.rb +23 -3
  74. data/lib/active_support/core_ext/string/access.rb +5 -16
  75. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  76. data/lib/active_support/core_ext/string/filters.rb +42 -1
  77. data/lib/active_support/core_ext/string/inflections.rb +45 -6
  78. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  79. data/lib/active_support/core_ext/string/multibyte.rb +6 -5
  80. data/lib/active_support/core_ext/string/output_safety.rb +69 -12
  81. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  82. data/lib/active_support/core_ext/string/strip.rb +3 -1
  83. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  84. data/lib/active_support/core_ext/symbol.rb +3 -0
  85. data/lib/active_support/core_ext/time/calculations.rb +50 -3
  86. data/lib/active_support/core_ext/time/conversions.rb +1 -0
  87. data/lib/active_support/core_ext/uri.rb +7 -5
  88. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  89. data/lib/active_support/current_attributes.rb +15 -2
  90. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  91. data/lib/active_support/dependencies.rb +118 -35
  92. data/lib/active_support/deprecation/behaviors.rb +20 -3
  93. data/lib/active_support/deprecation/disallowed.rb +56 -0
  94. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  95. data/lib/active_support/deprecation/method_wrappers.rb +21 -13
  96. data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
  97. data/lib/active_support/deprecation/reporting.rb +51 -8
  98. data/lib/active_support/deprecation.rb +6 -1
  99. data/lib/active_support/descendants_tracker.rb +59 -9
  100. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  101. data/lib/active_support/duration/iso8601_serializer.rb +18 -14
  102. data/lib/active_support/duration.rb +90 -38
  103. data/lib/active_support/encrypted_configuration.rb +1 -5
  104. data/lib/active_support/encrypted_file.rb +23 -5
  105. data/lib/active_support/environment_inquirer.rb +20 -0
  106. data/lib/active_support/evented_file_update_checker.rb +82 -117
  107. data/lib/active_support/execution_wrapper.rb +1 -0
  108. data/lib/active_support/file_update_checker.rb +0 -1
  109. data/lib/active_support/fork_tracker.rb +62 -0
  110. data/lib/active_support/gem_version.rb +2 -2
  111. data/lib/active_support/hash_with_indifferent_access.rb +78 -41
  112. data/lib/active_support/i18n.rb +1 -0
  113. data/lib/active_support/i18n_railtie.rb +16 -5
  114. data/lib/active_support/inflector/inflections.rb +2 -7
  115. data/lib/active_support/inflector/methods.rb +50 -57
  116. data/lib/active_support/inflector/transliterate.rb +47 -18
  117. data/lib/active_support/json/decoding.rb +25 -26
  118. data/lib/active_support/json/encoding.rb +11 -3
  119. data/lib/active_support/key_generator.rb +1 -33
  120. data/lib/active_support/lazy_load_hooks.rb +5 -2
  121. data/lib/active_support/locale/en.rb +33 -0
  122. data/lib/active_support/locale/en.yml +7 -3
  123. data/lib/active_support/log_subscriber.rb +39 -9
  124. data/lib/active_support/logger.rb +2 -17
  125. data/lib/active_support/logger_silence.rb +11 -19
  126. data/lib/active_support/logger_thread_safe_level.rb +52 -7
  127. data/lib/active_support/message_encryptor.rb +8 -13
  128. data/lib/active_support/message_verifier.rb +10 -10
  129. data/lib/active_support/messages/metadata.rb +11 -2
  130. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  131. data/lib/active_support/messages/rotator.rb +10 -9
  132. data/lib/active_support/multibyte/chars.rb +10 -68
  133. data/lib/active_support/multibyte/unicode.rb +15 -327
  134. data/lib/active_support/notifications/fanout.rb +116 -16
  135. data/lib/active_support/notifications/instrumenter.rb +71 -9
  136. data/lib/active_support/notifications.rb +72 -8
  137. data/lib/active_support/number_helper/number_converter.rb +5 -6
  138. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
  139. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  140. data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
  141. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
  142. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  143. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  144. data/lib/active_support/number_helper/number_to_rounded_converter.rb +8 -7
  145. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  146. data/lib/active_support/number_helper.rb +38 -12
  147. data/lib/active_support/option_merger.rb +22 -3
  148. data/lib/active_support/ordered_hash.rb +1 -1
  149. data/lib/active_support/ordered_options.rb +13 -3
  150. data/lib/active_support/parameter_filter.rb +133 -0
  151. data/lib/active_support/per_thread_registry.rb +1 -1
  152. data/lib/active_support/rails.rb +1 -10
  153. data/lib/active_support/railtie.rb +23 -1
  154. data/lib/active_support/reloader.rb +4 -5
  155. data/lib/active_support/secure_compare_rotator.rb +51 -0
  156. data/lib/active_support/security_utils.rb +19 -12
  157. data/lib/active_support/string_inquirer.rb +4 -3
  158. data/lib/active_support/subscriber.rb +72 -24
  159. data/lib/active_support/tagged_logging.rb +42 -8
  160. data/lib/active_support/test_case.rb +92 -1
  161. data/lib/active_support/testing/assertions.rb +30 -9
  162. data/lib/active_support/testing/deprecation.rb +0 -1
  163. data/lib/active_support/testing/file_fixtures.rb +2 -0
  164. data/lib/active_support/testing/isolation.rb +2 -2
  165. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  166. data/lib/active_support/testing/parallelization/server.rb +78 -0
  167. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  168. data/lib/active_support/testing/parallelization.rb +51 -0
  169. data/lib/active_support/testing/setup_and_teardown.rb +5 -9
  170. data/lib/active_support/testing/stream.rb +1 -2
  171. data/lib/active_support/testing/time_helpers.rb +47 -12
  172. data/lib/active_support/time_with_zone.rb +81 -47
  173. data/lib/active_support/values/time_zone.rb +34 -18
  174. data/lib/active_support/xml_mini/jdom.rb +2 -3
  175. data/lib/active_support/xml_mini/libxml.rb +2 -2
  176. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  177. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  178. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  179. data/lib/active_support/xml_mini/rexml.rb +10 -3
  180. data/lib/active_support/xml_mini.rb +2 -10
  181. data/lib/active_support.rb +14 -1
  182. metadata +57 -30
  183. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
  184. data/lib/active_support/core_ext/hash/compact.rb +0 -29
  185. data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
  186. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  187. data/lib/active_support/core_ext/module/reachable.rb +0 -11
  188. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
  189. data/lib/active_support/core_ext/range/include_range.rb +0 -25
  190. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module ForkTracker # :nodoc:
5
+ module CoreExt
6
+ def fork(*)
7
+ if block_given?
8
+ super do
9
+ ForkTracker.check!
10
+ yield
11
+ end
12
+ else
13
+ unless pid = super
14
+ ForkTracker.check!
15
+ end
16
+ pid
17
+ end
18
+ end
19
+ end
20
+
21
+ module CoreExtPrivate
22
+ include CoreExt
23
+
24
+ private
25
+ def fork(*)
26
+ super
27
+ end
28
+ end
29
+
30
+ @pid = Process.pid
31
+ @callbacks = []
32
+
33
+ class << self
34
+ def check!
35
+ if @pid != Process.pid
36
+ @callbacks.each(&:call)
37
+ @pid = Process.pid
38
+ end
39
+ end
40
+
41
+ def hook!
42
+ if Process.respond_to?(:fork)
43
+ ::Object.prepend(CoreExtPrivate)
44
+ ::Kernel.prepend(CoreExtPrivate)
45
+ ::Kernel.singleton_class.prepend(CoreExt)
46
+ ::Process.singleton_class.prepend(CoreExt)
47
+ end
48
+ end
49
+
50
+ def after_fork(&block)
51
+ @callbacks << block
52
+ block
53
+ end
54
+
55
+ def unregister(callback)
56
+ @callbacks.delete(callback)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ ActiveSupport::ForkTracker.hook!
@@ -7,8 +7,8 @@ module ActiveSupport
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 5
11
- MINOR = 2
10
+ MAJOR = 6
11
+ MINOR = 1
12
12
  TINY = 0
13
13
  PRE = nil
14
14
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "active_support/core_ext/hash/keys"
4
4
  require "active_support/core_ext/hash/reverse_merge"
5
+ require "active_support/core_ext/hash/except"
5
6
 
6
7
  module ActiveSupport
7
8
  # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
@@ -68,7 +69,7 @@ module ActiveSupport
68
69
  super()
69
70
  update(constructor)
70
71
 
71
- hash = constructor.to_hash
72
+ hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
72
73
  self.default = hash.default if hash.default
73
74
  self.default_proc = hash.default_proc if hash.default_proc
74
75
  else
@@ -90,12 +91,12 @@ module ActiveSupport
90
91
  #
91
92
  # This value can be later fetched using either +:key+ or <tt>'key'</tt>.
92
93
  def []=(key, value)
93
- regular_writer(convert_key(key), convert_value(value, for: :assignment))
94
+ regular_writer(convert_key(key), convert_value(value, conversion: :assignment))
94
95
  end
95
96
 
96
97
  alias_method :store, :[]=
97
98
 
98
- # Updates the receiver in-place, merging in the hash passed as argument:
99
+ # Updates the receiver in-place, merging in the hashes passed as arguments:
99
100
  #
100
101
  # hash_1 = ActiveSupport::HashWithIndifferentAccess.new
101
102
  # hash_1[:key] = 'value'
@@ -105,7 +106,10 @@ module ActiveSupport
105
106
  #
106
107
  # hash_1.update(hash_2) # => {"key"=>"New Value!"}
107
108
  #
108
- # The argument can be either an
109
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
110
+ # hash.update({ "a" => 1 }, { "b" => 2 }) # => { "a" => 1, "b" => 2 }
111
+ #
112
+ # The arguments can be either an
109
113
  # <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
110
114
  # In either case the merge respects the semantics of indifferent access.
111
115
  #
@@ -120,18 +124,15 @@ module ActiveSupport
120
124
  # hash_1[:key] = 10
121
125
  # hash_2['key'] = 12
122
126
  # hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
123
- def update(other_hash)
124
- if other_hash.is_a? HashWithIndifferentAccess
125
- super(other_hash)
127
+ def update(*other_hashes, &block)
128
+ if other_hashes.size == 1
129
+ update_with_single_argument(other_hashes.first, block)
126
130
  else
127
- other_hash.to_hash.each_pair do |key, value|
128
- if block_given? && key?(key)
129
- value = yield(convert_key(key), self[key], value)
130
- end
131
- regular_writer(convert_key(key), convert_value(value))
131
+ other_hashes.each do |other_hash|
132
+ update_with_single_argument(other_hash, block)
132
133
  end
133
- self
134
134
  end
135
+ self
135
136
  end
136
137
 
137
138
  alias_method :merge!, :update
@@ -163,6 +164,19 @@ module ActiveSupport
163
164
  super(convert_key(key))
164
165
  end
165
166
 
167
+ # Same as <tt>Hash#assoc</tt> where the key passed as argument can be
168
+ # either a string or a symbol:
169
+ #
170
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
171
+ # counters[:foo] = 1
172
+ #
173
+ # counters.assoc('foo') # => ["foo", 1]
174
+ # counters.assoc(:foo) # => ["foo", 1]
175
+ # counters.assoc(:zoo) # => nil
176
+ def assoc(key)
177
+ super(convert_key(key))
178
+ end
179
+
166
180
  # Same as <tt>Hash#fetch</tt> where the key passed as argument can be
167
181
  # either a string or a symbol:
168
182
  #
@@ -177,20 +191,18 @@ module ActiveSupport
177
191
  super(convert_key(key), *extras)
178
192
  end
179
193
 
180
- if Hash.new.respond_to?(:dig)
181
- # Same as <tt>Hash#dig</tt> where the key passed as argument can be
182
- # either a string or a symbol:
183
- #
184
- # counters = ActiveSupport::HashWithIndifferentAccess.new
185
- # counters[:foo] = { bar: 1 }
186
- #
187
- # counters.dig('foo', 'bar') # => 1
188
- # counters.dig(:foo, :bar) # => 1
189
- # counters.dig(:zoo) # => nil
190
- def dig(*args)
191
- args[0] = convert_key(args[0]) if args.size > 0
192
- super(*args)
193
- end
194
+ # Same as <tt>Hash#dig</tt> where the key passed as argument can be
195
+ # either a string or a symbol:
196
+ #
197
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
198
+ # counters[:foo] = { bar: 1 }
199
+ #
200
+ # counters.dig('foo', 'bar') # => 1
201
+ # counters.dig(:foo, :bar) # => 1
202
+ # counters.dig(:zoo) # => nil
203
+ def dig(*args)
204
+ args[0] = convert_key(args[0]) if args.size > 0
205
+ super(*args)
194
206
  end
195
207
 
196
208
  # Same as <tt>Hash#default</tt> where the key passed as argument can be
@@ -213,8 +225,8 @@ module ActiveSupport
213
225
  # hash[:a] = 'x'
214
226
  # hash[:b] = 'y'
215
227
  # hash.values_at('a', 'b') # => ["x", "y"]
216
- def values_at(*indices)
217
- indices.collect { |key| self[convert_key(key)] }
228
+ def values_at(*keys)
229
+ super(*keys.map { |key| convert_key(key) })
218
230
  end
219
231
 
220
232
  # Returns an array of the values at the specified indices, but also
@@ -227,8 +239,8 @@ module ActiveSupport
227
239
  # hash.fetch_values('a', 'c') { |key| 'z' } # => ["x", "z"]
228
240
  # hash.fetch_values('a', 'c') # => KeyError: key not found: "c"
229
241
  def fetch_values(*indices, &block)
230
- indices.collect { |key| fetch(key, &block) }
231
- end if Hash.method_defined?(:fetch_values)
242
+ super(*indices.map { |key| convert_key(key) }, &block)
243
+ end
232
244
 
233
245
  # Returns a shallow copy of the hash.
234
246
  #
@@ -247,8 +259,8 @@ module ActiveSupport
247
259
  # This method has the same semantics of +update+, except it does not
248
260
  # modify the receiver but rather returns a new hash with indifferent
249
261
  # access with the result of the merge.
250
- def merge(hash, &block)
251
- dup.update(hash, &block)
262
+ def merge(*hashes, &block)
263
+ dup.update(*hashes, &block)
252
264
  end
253
265
 
254
266
  # Like +merge+ but the other way around: Merges the receiver into the
@@ -281,6 +293,11 @@ module ActiveSupport
281
293
  super(convert_key(key))
282
294
  end
283
295
 
296
+ def except(*keys)
297
+ slice(*self.keys - keys.map { |key| convert_key(key) })
298
+ end
299
+ alias_method :without, :except
300
+
284
301
  def stringify_keys!; self end
285
302
  def deep_stringify_keys!; self end
286
303
  def stringify_keys; dup end
@@ -288,6 +305,7 @@ module ActiveSupport
288
305
  undef :symbolize_keys!
289
306
  undef :deep_symbolize_keys!
290
307
  def symbolize_keys; to_hash.symbolize_keys! end
308
+ alias_method :to_options, :symbolize_keys
291
309
  def deep_symbolize_keys; to_hash.deep_symbolize_keys! end
292
310
  def to_options!; self end
293
311
 
@@ -339,40 +357,59 @@ module ActiveSupport
339
357
  set_defaults(_new_hash)
340
358
 
341
359
  each do |key, value|
342
- _new_hash[key] = convert_value(value, for: :to_hash)
360
+ _new_hash[key] = convert_value(value, conversion: :to_hash)
343
361
  end
344
362
  _new_hash
345
363
  end
346
364
 
347
365
  private
348
- def convert_key(key) # :doc:
349
- key.kind_of?(Symbol) ? key.to_s : key
366
+ if Symbol.method_defined?(:name)
367
+ def convert_key(key)
368
+ key.kind_of?(Symbol) ? key.name : key
369
+ end
370
+ else
371
+ def convert_key(key)
372
+ key.kind_of?(Symbol) ? key.to_s : key
373
+ end
350
374
  end
351
375
 
352
- def convert_value(value, options = {}) # :doc:
376
+ def convert_value(value, conversion: nil)
353
377
  if value.is_a? Hash
354
- if options[:for] == :to_hash
378
+ if conversion == :to_hash
355
379
  value.to_hash
356
380
  else
357
381
  value.nested_under_indifferent_access
358
382
  end
359
383
  elsif value.is_a?(Array)
360
- if options[:for] != :assignment || value.frozen?
384
+ if conversion != :assignment || value.frozen?
361
385
  value = value.dup
362
386
  end
363
- value.map! { |e| convert_value(e, options) }
387
+ value.map! { |e| convert_value(e, conversion: conversion) }
364
388
  else
365
389
  value
366
390
  end
367
391
  end
368
392
 
369
- def set_defaults(target) # :doc:
393
+ def set_defaults(target)
370
394
  if default_proc
371
395
  target.default_proc = default_proc.dup
372
396
  else
373
397
  target.default = default
374
398
  end
375
399
  end
400
+
401
+ def update_with_single_argument(other_hash, block)
402
+ if other_hash.is_a? HashWithIndifferentAccess
403
+ regular_update(other_hash, &block)
404
+ else
405
+ other_hash.to_hash.each_pair do |key, value|
406
+ if block && key?(key)
407
+ value = block.call(convert_key(key), self[key], value)
408
+ end
409
+ regular_writer(convert_key(key), convert_value(value))
410
+ end
411
+ end
412
+ end
376
413
  end
377
414
  end
378
415
 
@@ -13,3 +13,4 @@ require "active_support/lazy_load_hooks"
13
13
 
14
14
  ActiveSupport.run_load_hooks(:i18n)
15
15
  I18n.load_path << File.expand_path("locale/en.yml", __dir__)
16
+ I18n.load_path << File.expand_path("locale/en.rb", __dir__)
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support"
4
- require "active_support/file_update_checker"
5
4
  require "active_support/core_ext/array/wrap"
6
5
 
7
6
  # :enddoc:
@@ -13,6 +12,8 @@ module I18n
13
12
  config.i18n.load_path = []
14
13
  config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
15
14
 
15
+ config.eager_load_namespaces << I18n
16
+
16
17
  # Set the i18n configuration after initialization since a lot of
17
18
  # configuration is still usually done in application initializers.
18
19
  config.after_initialize do |app|
@@ -47,8 +48,10 @@ module I18n
47
48
  app.config.i18n.load_path.unshift(*value.flat_map(&:existent))
48
49
  when :load_path
49
50
  I18n.load_path += value
51
+ when :raise_on_missing_translations
52
+ forward_raise_on_missing_translations_config(app)
50
53
  else
51
- I18n.send("#{setting}=", value)
54
+ I18n.public_send("#{setting}=", value)
52
55
  end
53
56
  end
54
57
 
@@ -61,8 +64,6 @@ module I18n
61
64
  reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
62
65
  I18n.load_path.keep_if { |p| File.exist?(p) }
63
66
  I18n.load_path |= reloadable_paths.flat_map(&:existent)
64
-
65
- I18n.reload!
66
67
  end
67
68
 
68
69
  app.reloaders << reloader
@@ -74,6 +75,16 @@ module I18n
74
75
  @i18n_inited = true
75
76
  end
76
77
 
78
+ def self.forward_raise_on_missing_translations_config(app)
79
+ ActiveSupport.on_load(:action_view) do
80
+ self.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
81
+ end
82
+
83
+ ActiveSupport.on_load(:action_controller) do
84
+ AbstractController::Translation.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
85
+ end
86
+ end
87
+
77
88
  def self.include_fallbacks_module
78
89
  I18n.backend.class.include(I18n::Backend::Fallbacks)
79
90
  end
@@ -88,7 +99,7 @@ module I18n
88
99
  when Hash, Array
89
100
  Array.wrap(fallbacks)
90
101
  else # TrueClass
91
- []
102
+ [I18n.default_locale]
92
103
  end
93
104
 
94
105
  I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
@@ -1,10 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "concurrent/map"
4
- require "active_support/core_ext/array/prepend_and_append"
5
- require "active_support/core_ext/regexp"
6
4
  require "active_support/i18n"
7
- require "active_support/deprecation"
8
5
 
9
6
  module ActiveSupport
10
7
  module Inflector
@@ -67,8 +64,7 @@ module ActiveSupport
67
64
  @__instance__[locale] ||= new
68
65
  end
69
66
 
70
- attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms, :acronym_regex
71
- deprecate :acronym_regex
67
+ attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms
72
68
 
73
69
  attr_reader :acronyms_camelize_regex, :acronyms_underscore_regex # :nodoc:
74
70
 
@@ -80,7 +76,7 @@ module ActiveSupport
80
76
  # Private, for the test suite.
81
77
  def initialize_dup(orig) # :nodoc:
82
78
  %w(plurals singulars uncountables humans acronyms).each do |scope|
83
- instance_variable_set("@#{scope}", orig.send(scope).dup)
79
+ instance_variable_set("@#{scope}", orig.public_send(scope).dup)
84
80
  end
85
81
  define_acronym_regex_patterns
86
82
  end
@@ -233,7 +229,6 @@ module ActiveSupport
233
229
  end
234
230
 
235
231
  private
236
-
237
232
  def define_acronym_regex_patterns
238
233
  @acronym_regex = @acronyms.empty? ? /(?=a)b/ : /#{@acronyms.values.join("|")}/
239
234
  @acronyms_camelize_regex = /^(?:#{@acronym_regex}(?=\b|[A-Z_])|\w)/
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/inflections"
4
- require "active_support/core_ext/regexp"
4
+ require "active_support/core_ext/object/blank"
5
5
 
6
6
  module ActiveSupport
7
7
  # The Inflector transforms words from singular to plural, class names to table
@@ -74,7 +74,7 @@ module ActiveSupport
74
74
  string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase }
75
75
  end
76
76
  string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
77
- string.gsub!("/".freeze, "::".freeze)
77
+ string.gsub!("/", "::")
78
78
  string
79
79
  end
80
80
 
@@ -91,11 +91,11 @@ module ActiveSupport
91
91
  # camelize(underscore('SSLError')) # => "SslError"
92
92
  def underscore(camel_cased_word)
93
93
  return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
94
- word = camel_cased_word.to_s.gsub("::".freeze, "/".freeze)
95
- word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_'.freeze }#{$2.downcase}" }
96
- word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
97
- word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
98
- word.tr!("-".freeze, "_".freeze)
94
+ word = camel_cased_word.to_s.gsub("::", "/")
95
+ word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
96
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
97
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
98
+ word.tr!("-", "_")
99
99
  word.downcase!
100
100
  word
101
101
  end
@@ -131,11 +131,11 @@ module ActiveSupport
131
131
 
132
132
  inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
133
133
 
134
- result.sub!(/\A_+/, "".freeze)
134
+ result.sub!(/\A_+/, "")
135
135
  unless keep_id_suffix
136
- result.sub!(/_id\z/, "".freeze)
136
+ result.delete_suffix!("_id")
137
137
  end
138
- result.tr!("_".freeze, " ".freeze)
138
+ result.tr!("_", " ")
139
139
 
140
140
  result.gsub!(/([a-z\d]*)/i) do |match|
141
141
  "#{inflections.acronyms[match.downcase] || match.downcase}"
@@ -173,7 +173,7 @@ module ActiveSupport
173
173
  # titleize('raiders_of_the_lost_ark') # => "Raiders Of The Lost Ark"
174
174
  # titleize('string_ending_with_id', keep_id_suffix: true) # => "String Ending With Id"
175
175
  def titleize(word, keep_id_suffix: false)
176
- humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`])[a-z]/) do |match|
176
+ humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`()])[a-z]/) do |match|
177
177
  match.capitalize
178
178
  end
179
179
  end
@@ -197,17 +197,17 @@ module ActiveSupport
197
197
  #
198
198
  # Singular names are not handled correctly:
199
199
  #
200
- # classify('calculus') # => "Calculus"
200
+ # classify('calculus') # => "Calculu"
201
201
  def classify(table_name)
202
202
  # strip out any leading schema name
203
- camelize(singularize(table_name.to_s.sub(/.*\./, "".freeze)))
203
+ camelize(singularize(table_name.to_s.sub(/.*\./, "")))
204
204
  end
205
205
 
206
206
  # Replaces underscores with dashes in the string.
207
207
  #
208
208
  # dasherize('puni_puni') # => "puni-puni"
209
209
  def dasherize(underscored_word)
210
- underscored_word.tr("_".freeze, "-".freeze)
210
+ underscored_word.tr("_", "-")
211
211
  end
212
212
 
213
213
  # Removes the module part from the expression in the string.
@@ -270,32 +270,36 @@ module ActiveSupport
270
270
  # NameError is raised when the name is not in CamelCase or the constant is
271
271
  # unknown.
272
272
  def constantize(camel_cased_word)
273
- names = camel_cased_word.split("::".freeze)
274
-
275
- # Trigger a built-in NameError exception including the ill-formed constant in the message.
276
- Object.const_get(camel_cased_word) if names.empty?
277
-
278
- # Remove the first blank element in case of '::ClassName' notation.
279
- names.shift if names.size > 1 && names.first.empty?
280
-
281
- names.inject(Object) do |constant, name|
282
- if constant == Object
283
- constant.const_get(name)
284
- else
285
- candidate = constant.const_get(name)
286
- next candidate if constant.const_defined?(name, false)
287
- next candidate unless Object.const_defined?(name)
288
-
289
- # Go down the ancestors to check if it is owned directly. The check
290
- # stops when we reach Object or the end of ancestors tree.
291
- constant = constant.ancestors.inject(constant) do |const, ancestor|
292
- break const if ancestor == Object
293
- break ancestor if ancestor.const_defined?(name, false)
294
- const
273
+ if camel_cased_word.blank? || !camel_cased_word.include?("::")
274
+ Object.const_get(camel_cased_word)
275
+ else
276
+ names = camel_cased_word.split("::")
277
+
278
+ # Trigger a built-in NameError exception including the ill-formed constant in the message.
279
+ Object.const_get(camel_cased_word) if names.empty?
280
+
281
+ # Remove the first blank element in case of '::ClassName' notation.
282
+ names.shift if names.size > 1 && names.first.empty?
283
+
284
+ names.inject(Object) do |constant, name|
285
+ if constant == Object
286
+ constant.const_get(name)
287
+ else
288
+ candidate = constant.const_get(name)
289
+ next candidate if constant.const_defined?(name, false)
290
+ next candidate unless Object.const_defined?(name)
291
+
292
+ # Go down the ancestors to check if it is owned directly. The check
293
+ # stops when we reach Object or the end of ancestors tree.
294
+ constant = constant.ancestors.inject(constant) do |const, ancestor|
295
+ break const if ancestor == Object
296
+ break ancestor if ancestor.const_defined?(name, false)
297
+ const
298
+ end
299
+
300
+ # owner is in Object, so raise
301
+ constant.const_get(name, false)
295
302
  end
296
-
297
- # owner is in Object, so raise
298
- constant.const_get(name, false)
299
303
  end
300
304
  end
301
305
  end
@@ -327,8 +331,9 @@ module ActiveSupport
327
331
  rescue NameError => e
328
332
  raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) ||
329
333
  e.name.to_s == camel_cased_word.to_s)
330
- rescue ArgumentError => e
331
- raise unless /not missing constant #{const_regexp(camel_cased_word)}!$/.match?(e.message)
334
+ rescue LoadError => e
335
+ message = e.respond_to?(:original_message) ? e.original_message : e.message
336
+ raise unless /Unable to autoload constant #{const_regexp(camel_cased_word)}/.match?(message)
332
337
  end
333
338
 
334
339
  # Returns the suffix that should be added to a number to denote the position
@@ -341,18 +346,7 @@ module ActiveSupport
341
346
  # ordinal(-11) # => "th"
342
347
  # ordinal(-1021) # => "st"
343
348
  def ordinal(number)
344
- abs_number = number.to_i.abs
345
-
346
- if (11..13).include?(abs_number % 100)
347
- "th"
348
- else
349
- case abs_number % 10
350
- when 1; "st"
351
- when 2; "nd"
352
- when 3; "rd"
353
- else "th"
354
- end
355
- end
349
+ I18n.translate("number.nth.ordinals", number: number)
356
350
  end
357
351
 
358
352
  # Turns a number into an ordinal string used to denote the position in an
@@ -365,24 +359,23 @@ module ActiveSupport
365
359
  # ordinalize(-11) # => "-11th"
366
360
  # ordinalize(-1021) # => "-1021st"
367
361
  def ordinalize(number)
368
- "#{number}#{ordinal(number)}"
362
+ I18n.translate("number.nth.ordinalized", number: number)
369
363
  end
370
364
 
371
365
  private
372
-
373
366
  # Mounts a regular expression, returned as a string to ease interpolation,
374
367
  # that will match part by part the given constant.
375
368
  #
376
369
  # const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?"
377
370
  # const_regexp("::") # => "::"
378
371
  def const_regexp(camel_cased_word)
379
- parts = camel_cased_word.split("::".freeze)
372
+ parts = camel_cased_word.split("::")
380
373
 
381
374
  return Regexp.escape(camel_cased_word) if parts.blank?
382
375
 
383
376
  last = parts.pop
384
377
 
385
- parts.reverse.inject(last) do |acc, part|
378
+ parts.reverse!.inject(last) do |acc, part|
386
379
  part.empty? ? acc : "#{part}(::#{acc})?"
387
380
  end
388
381
  end