activesupport 6.0.6.1 → 7.1.3.2

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.
Files changed (245) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +865 -438
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -6
  5. data/lib/active_support/actionable_error.rb +4 -2
  6. data/lib/active_support/array_inquirer.rb +4 -2
  7. data/lib/active_support/backtrace_cleaner.rb +30 -10
  8. data/lib/active_support/benchmarkable.rb +4 -3
  9. data/lib/active_support/broadcast_logger.rb +250 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +53 -20
  14. data/lib/active_support/cache/mem_cache_store.rb +208 -63
  15. data/lib/active_support/cache/memory_store.rb +120 -38
  16. data/lib/active_support/cache/null_store.rb +16 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +201 -208
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +73 -66
  20. data/lib/active_support/cache.rb +539 -261
  21. data/lib/active_support/callbacks.rb +273 -142
  22. data/lib/active_support/code_generator.rb +65 -0
  23. data/lib/active_support/concern.rb +53 -7
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/concurrency/share_lock.rb +2 -2
  27. data/lib/active_support/configurable.rb +19 -6
  28. data/lib/active_support/configuration_file.rb +51 -0
  29. data/lib/active_support/core_ext/array/access.rb +1 -5
  30. data/lib/active_support/core_ext/array/conversions.rb +15 -13
  31. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  32. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  33. data/lib/active_support/core_ext/benchmark.rb +2 -2
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  35. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  36. data/lib/active_support/core_ext/class/subclasses.rb +19 -29
  37. data/lib/active_support/core_ext/date/blank.rb +1 -1
  38. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  39. data/lib/active_support/core_ext/date/conversions.rb +18 -16
  40. data/lib/active_support/core_ext/date_and_time/calculations.rb +27 -4
  41. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  42. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  43. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  44. data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
  45. data/lib/active_support/core_ext/digest/uuid.rb +30 -13
  46. data/lib/active_support/core_ext/enumerable.rb +146 -72
  47. data/lib/active_support/core_ext/erb/util.rb +196 -0
  48. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  49. data/lib/active_support/core_ext/hash/conversions.rb +3 -4
  50. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  51. data/lib/active_support/core_ext/hash/deep_transform_values.rb +4 -4
  52. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  53. data/lib/active_support/core_ext/hash/keys.rb +5 -5
  54. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  55. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  56. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  57. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  58. data/lib/active_support/core_ext/load_error.rb +1 -1
  59. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  60. data/lib/active_support/core_ext/module/attribute_accessors.rb +31 -29
  61. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +51 -20
  62. data/lib/active_support/core_ext/module/concerning.rb +14 -8
  63. data/lib/active_support/core_ext/module/delegation.rb +75 -42
  64. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  65. data/lib/active_support/core_ext/module/introspection.rb +1 -26
  66. data/lib/active_support/core_ext/name_error.rb +23 -2
  67. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  68. data/lib/active_support/core_ext/numeric/conversions.rb +82 -73
  69. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  70. data/lib/active_support/core_ext/object/blank.rb +2 -2
  71. data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
  72. data/lib/active_support/core_ext/object/duplicable.rb +15 -4
  73. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  74. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  75. data/lib/active_support/core_ext/object/json.rb +52 -28
  76. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  77. data/lib/active_support/core_ext/object/try.rb +20 -20
  78. data/lib/active_support/core_ext/object/with.rb +44 -0
  79. data/lib/active_support/core_ext/object/with_options.rb +25 -6
  80. data/lib/active_support/core_ext/object.rb +1 -0
  81. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  82. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  83. data/lib/active_support/core_ext/pathname.rb +4 -0
  84. data/lib/active_support/core_ext/range/compare_range.rb +6 -25
  85. data/lib/active_support/core_ext/range/conversions.rb +34 -13
  86. data/lib/active_support/core_ext/range/each.rb +1 -1
  87. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  88. data/lib/active_support/core_ext/range.rb +1 -2
  89. data/lib/active_support/core_ext/regexp.rb +8 -1
  90. data/lib/active_support/core_ext/securerandom.rb +25 -13
  91. data/lib/active_support/core_ext/string/access.rb +5 -24
  92. data/lib/active_support/core_ext/string/conversions.rb +3 -2
  93. data/lib/active_support/core_ext/string/filters.rb +21 -15
  94. data/lib/active_support/core_ext/string/indent.rb +1 -1
  95. data/lib/active_support/core_ext/string/inflections.rb +51 -10
  96. data/lib/active_support/core_ext/string/inquiry.rb +2 -1
  97. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  98. data/lib/active_support/core_ext/string/output_safety.rb +85 -194
  99. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  100. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  101. data/lib/active_support/core_ext/symbol.rb +3 -0
  102. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  103. data/lib/active_support/core_ext/time/calculations.rb +46 -8
  104. data/lib/active_support/core_ext/time/conversions.rb +16 -13
  105. data/lib/active_support/core_ext/time/zones.rb +12 -28
  106. data/lib/active_support/core_ext.rb +2 -1
  107. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  108. data/lib/active_support/current_attributes.rb +54 -22
  109. data/lib/active_support/deep_mergeable.rb +53 -0
  110. data/lib/active_support/dependencies/autoload.rb +17 -12
  111. data/lib/active_support/dependencies/interlock.rb +10 -18
  112. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  113. data/lib/active_support/dependencies.rb +58 -769
  114. data/lib/active_support/deprecation/behaviors.rb +77 -38
  115. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  116. data/lib/active_support/deprecation/deprecators.rb +104 -0
  117. data/lib/active_support/deprecation/disallowed.rb +54 -0
  118. data/lib/active_support/deprecation/instance_delegator.rb +31 -5
  119. data/lib/active_support/deprecation/method_wrappers.rb +12 -28
  120. data/lib/active_support/deprecation/proxy_wrappers.rb +40 -25
  121. data/lib/active_support/deprecation/reporting.rb +76 -16
  122. data/lib/active_support/deprecation.rb +36 -4
  123. data/lib/active_support/deprecator.rb +7 -0
  124. data/lib/active_support/descendants_tracker.rb +150 -68
  125. data/lib/active_support/digest.rb +5 -3
  126. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  127. data/lib/active_support/duration/iso8601_serializer.rb +24 -12
  128. data/lib/active_support/duration.rb +136 -56
  129. data/lib/active_support/encrypted_configuration.rb +72 -9
  130. data/lib/active_support/encrypted_file.rb +46 -13
  131. data/lib/active_support/environment_inquirer.rb +40 -0
  132. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  133. data/lib/active_support/error_reporter.rb +203 -0
  134. data/lib/active_support/evented_file_update_checker.rb +86 -137
  135. data/lib/active_support/execution_context/test_helper.rb +13 -0
  136. data/lib/active_support/execution_context.rb +53 -0
  137. data/lib/active_support/execution_wrapper.rb +31 -12
  138. data/lib/active_support/executor/test_helper.rb +7 -0
  139. data/lib/active_support/file_update_checker.rb +4 -2
  140. data/lib/active_support/fork_tracker.rb +79 -0
  141. data/lib/active_support/gem_version.rb +5 -5
  142. data/lib/active_support/gzip.rb +2 -0
  143. data/lib/active_support/hash_with_indifferent_access.rb +86 -42
  144. data/lib/active_support/html_safe_translation.rb +53 -0
  145. data/lib/active_support/i18n.rb +2 -1
  146. data/lib/active_support/i18n_railtie.rb +29 -27
  147. data/lib/active_support/inflector/inflections.rb +26 -9
  148. data/lib/active_support/inflector/methods.rb +54 -64
  149. data/lib/active_support/inflector/transliterate.rb +7 -5
  150. data/lib/active_support/isolated_execution_state.rb +76 -0
  151. data/lib/active_support/json/decoding.rb +6 -5
  152. data/lib/active_support/json/encoding.rb +31 -45
  153. data/lib/active_support/key_generator.rb +32 -7
  154. data/lib/active_support/lazy_load_hooks.rb +33 -7
  155. data/lib/active_support/locale/en.yml +10 -4
  156. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  157. data/lib/active_support/log_subscriber.rb +101 -32
  158. data/lib/active_support/logger.rb +9 -60
  159. data/lib/active_support/logger_silence.rb +2 -26
  160. data/lib/active_support/logger_thread_safe_level.rb +24 -25
  161. data/lib/active_support/message_encryptor.rb +205 -58
  162. data/lib/active_support/message_encryptors.rb +141 -0
  163. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  164. data/lib/active_support/message_pack/extensions.rb +292 -0
  165. data/lib/active_support/message_pack/serializer.rb +63 -0
  166. data/lib/active_support/message_pack.rb +50 -0
  167. data/lib/active_support/message_verifier.rb +237 -86
  168. data/lib/active_support/message_verifiers.rb +135 -0
  169. data/lib/active_support/messages/codec.rb +65 -0
  170. data/lib/active_support/messages/metadata.rb +112 -46
  171. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  172. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  173. data/lib/active_support/messages/rotator.rb +35 -32
  174. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  175. data/lib/active_support/multibyte/chars.rb +15 -52
  176. data/lib/active_support/multibyte/unicode.rb +8 -122
  177. data/lib/active_support/multibyte.rb +1 -1
  178. data/lib/active_support/notifications/fanout.rb +310 -105
  179. data/lib/active_support/notifications/instrumenter.rb +113 -48
  180. data/lib/active_support/notifications.rb +56 -29
  181. data/lib/active_support/number_helper/number_converter.rb +15 -8
  182. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  183. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  184. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  185. data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -5
  186. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  187. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  188. data/lib/active_support/number_helper/rounding_helper.rb +12 -32
  189. data/lib/active_support/number_helper.rb +379 -304
  190. data/lib/active_support/option_merger.rb +11 -18
  191. data/lib/active_support/ordered_hash.rb +4 -4
  192. data/lib/active_support/ordered_options.rb +23 -3
  193. data/lib/active_support/parameter_filter.rb +104 -75
  194. data/lib/active_support/proxy_object.rb +2 -0
  195. data/lib/active_support/rails.rb +1 -4
  196. data/lib/active_support/railtie.rb +90 -6
  197. data/lib/active_support/reloader.rb +12 -4
  198. data/lib/active_support/rescuable.rb +18 -16
  199. data/lib/active_support/ruby_features.rb +7 -0
  200. data/lib/active_support/secure_compare_rotator.rb +58 -0
  201. data/lib/active_support/security_utils.rb +19 -12
  202. data/lib/active_support/string_inquirer.rb +5 -3
  203. data/lib/active_support/subscriber.rb +23 -47
  204. data/lib/active_support/syntax_error_proxy.rb +70 -0
  205. data/lib/active_support/tagged_logging.rb +84 -23
  206. data/lib/active_support/test_case.rb +166 -27
  207. data/lib/active_support/testing/assertions.rb +73 -20
  208. data/lib/active_support/testing/autorun.rb +0 -2
  209. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  210. data/lib/active_support/testing/deprecation.rb +53 -2
  211. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  212. data/lib/active_support/testing/isolation.rb +30 -29
  213. data/lib/active_support/testing/method_call_assertions.rb +24 -11
  214. data/lib/active_support/testing/parallelization/server.rb +82 -0
  215. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  216. data/lib/active_support/testing/parallelization.rb +16 -95
  217. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  218. data/lib/active_support/testing/stream.rb +4 -6
  219. data/lib/active_support/testing/strict_warnings.rb +39 -0
  220. data/lib/active_support/testing/tagged_logging.rb +1 -1
  221. data/lib/active_support/testing/time_helpers.rb +89 -19
  222. data/lib/active_support/time_with_zone.rb +105 -70
  223. data/lib/active_support/values/time_zone.rb +59 -26
  224. data/lib/active_support/version.rb +1 -1
  225. data/lib/active_support/xml_mini/jdom.rb +4 -11
  226. data/lib/active_support/xml_mini/libxml.rb +5 -5
  227. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  228. data/lib/active_support/xml_mini/nokogiri.rb +5 -5
  229. data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
  230. data/lib/active_support/xml_mini/rexml.rb +9 -2
  231. data/lib/active_support/xml_mini.rb +7 -6
  232. data/lib/active_support.rb +40 -1
  233. metadata +127 -40
  234. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  235. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  236. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  237. data/lib/active_support/core_ext/marshal.rb +0 -24
  238. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  239. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  240. data/lib/active_support/core_ext/range/include_range.rb +0 -9
  241. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -23
  242. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  243. data/lib/active_support/core_ext/uri.rb +0 -25
  244. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
  245. data/lib/active_support/per_thread_registry.rb +0 -60
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module ForkTracker # :nodoc:
5
+ module ModernCoreExt
6
+ def _fork
7
+ pid = super
8
+ if pid == 0
9
+ ForkTracker.after_fork_callback
10
+ end
11
+ pid
12
+ end
13
+ end
14
+
15
+ module CoreExt
16
+ def fork(...)
17
+ if block_given?
18
+ super do
19
+ ForkTracker.check!
20
+ yield
21
+ end
22
+ else
23
+ unless pid = super
24
+ ForkTracker.check!
25
+ end
26
+ pid
27
+ end
28
+ end
29
+ end
30
+
31
+ module CoreExtPrivate
32
+ include CoreExt
33
+ private :fork
34
+ end
35
+
36
+ @pid = Process.pid
37
+ @callbacks = []
38
+
39
+ class << self
40
+ def after_fork_callback
41
+ new_pid = Process.pid
42
+ if @pid != new_pid
43
+ @callbacks.each(&:call)
44
+ @pid = new_pid
45
+ end
46
+ end
47
+
48
+ if Process.respond_to?(:_fork) # Ruby 3.1+
49
+ def check!
50
+ # We trust the `_fork` callback
51
+ end
52
+ else
53
+ alias_method :check!, :after_fork_callback
54
+ end
55
+
56
+ def hook!
57
+ if Process.respond_to?(:_fork) # Ruby 3.1+
58
+ ::Process.singleton_class.prepend(ModernCoreExt)
59
+ elsif Process.respond_to?(:fork)
60
+ ::Object.prepend(CoreExtPrivate) if RUBY_VERSION < "3.0"
61
+ ::Kernel.prepend(CoreExtPrivate)
62
+ ::Kernel.singleton_class.prepend(CoreExt)
63
+ ::Process.singleton_class.prepend(CoreExt)
64
+ end
65
+ end
66
+
67
+ def after_fork(&block)
68
+ @callbacks << block
69
+ block
70
+ end
71
+
72
+ def unregister(callback)
73
+ @callbacks.delete(callback)
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ ActiveSupport::ForkTracker.hook!
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
- # Returns the version of the currently loaded Active Support as a <tt>Gem::Version</tt>.
4
+ # Returns the currently loaded version of Active Support as a +Gem::Version+.
5
5
  def self.gem_version
6
6
  Gem::Version.new VERSION::STRING
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 6
11
- MINOR = 0
12
- TINY = 6
13
- PRE = "1"
10
+ MAJOR = 7
11
+ MINOR = 1
12
+ TINY = 3
13
+ PRE = "2"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -4,6 +4,8 @@ require "zlib"
4
4
  require "stringio"
5
5
 
6
6
  module ActiveSupport
7
+ # = Active Support \Gzip
8
+ #
7
9
  # A convenient wrapper for the zlib standard library that allows
8
10
  # compression/decompression of strings with gzip.
9
11
  #
@@ -3,8 +3,11 @@
3
3
  require "active_support/core_ext/hash/keys"
4
4
  require "active_support/core_ext/hash/reverse_merge"
5
5
  require "active_support/core_ext/hash/except"
6
+ require "active_support/core_ext/hash/slice"
6
7
 
7
8
  module ActiveSupport
9
+ # = \Hash With Indifferent Access
10
+ #
8
11
  # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
9
12
  # to be the same.
10
13
  #
@@ -36,7 +39,7 @@ module ActiveSupport
36
39
  #
37
40
  # but this class is intended for use cases where strings or symbols are the
38
41
  # expected keys and it is convenient to understand both as the same. For
39
- # example the +params+ hash in Ruby on Rails.
42
+ # example the +params+ hash in Ruby on \Rails.
40
43
  #
41
44
  # Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
42
45
  #
@@ -44,7 +47,7 @@ module ActiveSupport
44
47
  #
45
48
  # which may be handy.
46
49
  #
47
- # To access this class outside of Rails, require the core extension with:
50
+ # To access this class outside of \Rails, require the core extension with:
48
51
  #
49
52
  # require "active_support/core_ext/hash/indifferent_access"
50
53
  #
@@ -64,14 +67,16 @@ module ActiveSupport
64
67
  self
65
68
  end
66
69
 
67
- def initialize(constructor = {})
70
+ def initialize(constructor = nil)
68
71
  if constructor.respond_to?(:to_hash)
69
72
  super()
70
73
  update(constructor)
71
74
 
72
- hash = constructor.to_hash
75
+ hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
73
76
  self.default = hash.default if hash.default
74
77
  self.default_proc = hash.default_proc if hash.default_proc
78
+ elsif constructor.nil?
79
+ super()
75
80
  else
76
81
  super(constructor)
77
82
  end
@@ -91,12 +96,12 @@ module ActiveSupport
91
96
  #
92
97
  # This value can be later fetched using either +:key+ or <tt>'key'</tt>.
93
98
  def []=(key, value)
94
- regular_writer(convert_key(key), convert_value(value, for: :assignment))
99
+ regular_writer(convert_key(key), convert_value(value, conversion: :assignment))
95
100
  end
96
101
 
97
102
  alias_method :store, :[]=
98
103
 
99
- # Updates the receiver in-place, merging in the hash passed as argument:
104
+ # Updates the receiver in-place, merging in the hashes passed as arguments:
100
105
  #
101
106
  # hash_1 = ActiveSupport::HashWithIndifferentAccess.new
102
107
  # hash_1[:key] = 'value'
@@ -106,11 +111,14 @@ module ActiveSupport
106
111
  #
107
112
  # hash_1.update(hash_2) # => {"key"=>"New Value!"}
108
113
  #
109
- # The argument can be either an
110
- # <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
114
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
115
+ # hash.update({ "a" => 1 }, { "b" => 2 }) # => { "a" => 1, "b" => 2 }
116
+ #
117
+ # The arguments can be either an
118
+ # +ActiveSupport::HashWithIndifferentAccess+ or a regular +Hash+.
111
119
  # In either case the merge respects the semantics of indifferent access.
112
120
  #
113
- # If the argument is a regular hash with keys +:key+ and +"key"+ only one
121
+ # If the argument is a regular hash with keys +:key+ and <tt>"key"</tt> only one
114
122
  # of the values end up in the receiver, but which one is unspecified.
115
123
  #
116
124
  # When given a block, the value for duplicated keys will be determined
@@ -121,18 +129,15 @@ module ActiveSupport
121
129
  # hash_1[:key] = 10
122
130
  # hash_2['key'] = 12
123
131
  # hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
124
- def update(other_hash)
125
- if other_hash.is_a? HashWithIndifferentAccess
126
- super(other_hash)
132
+ def update(*other_hashes, &block)
133
+ if other_hashes.size == 1
134
+ update_with_single_argument(other_hashes.first, block)
127
135
  else
128
- other_hash.to_hash.each_pair do |key, value|
129
- if block_given? && key?(key)
130
- value = yield(convert_key(key), self[key], value)
131
- end
132
- regular_writer(convert_key(key), convert_value(value))
136
+ other_hashes.each do |other_hash|
137
+ update_with_single_argument(other_hash, block)
133
138
  end
134
- self
135
139
  end
140
+ self
136
141
  end
137
142
 
138
143
  alias_method :merge!, :update
@@ -215,8 +220,12 @@ module ActiveSupport
215
220
  # hash.default # => nil
216
221
  # hash.default('foo') # => 'foo'
217
222
  # hash.default(:foo) # => 'foo'
218
- def default(*args)
219
- super(*args.map { |arg| convert_key(arg) })
223
+ def default(key = (no_key = true))
224
+ if no_key
225
+ super()
226
+ else
227
+ super(convert_key(key))
228
+ end
220
229
  end
221
230
 
222
231
  # Returns an array of the values at the specified indices:
@@ -226,7 +235,8 @@ module ActiveSupport
226
235
  # hash[:b] = 'y'
227
236
  # hash.values_at('a', 'b') # => ["x", "y"]
228
237
  def values_at(*keys)
229
- super(*keys.map { |key| convert_key(key) })
238
+ keys.map! { |key| convert_key(key) }
239
+ super
230
240
  end
231
241
 
232
242
  # Returns an array of the values at the specified indices, but also
@@ -239,7 +249,8 @@ module ActiveSupport
239
249
  # hash.fetch_values('a', 'c') { |key| 'z' } # => ["x", "z"]
240
250
  # hash.fetch_values('a', 'c') # => KeyError: key not found: "c"
241
251
  def fetch_values(*indices, &block)
242
- super(*indices.map { |key| convert_key(key) }, &block)
252
+ indices.map! { |key| convert_key(key) }
253
+ super
243
254
  end
244
255
 
245
256
  # Returns a shallow copy of the hash.
@@ -259,8 +270,8 @@ module ActiveSupport
259
270
  # This method has the same semantics of +update+, except it does not
260
271
  # modify the receiver but rather returns a new hash with indifferent
261
272
  # access with the result of the merge.
262
- def merge(hash, &block)
263
- dup.update(hash, &block)
273
+ def merge(*hashes, &block)
274
+ dup.update(*hashes, &block)
264
275
  end
265
276
 
266
277
  # Like +merge+ but the other way around: Merges the receiver into the
@@ -293,8 +304,12 @@ module ActiveSupport
293
304
  super(convert_key(key))
294
305
  end
295
306
 
307
+ # Returns a hash with indifferent access that includes everything except given keys.
308
+ # hash = { a: "x", b: "y", c: 10 }.with_indifferent_access
309
+ # hash.except(:a, "b") # => {c: 10}.with_indifferent_access
310
+ # hash # => { a: "x", b: "y", c: 10 }.with_indifferent_access
296
311
  def except(*keys)
297
- slice(*self.keys - keys.map { |key| convert_key(key) })
312
+ dup.except!(*keys)
298
313
  end
299
314
  alias_method :without, :except
300
315
 
@@ -319,21 +334,31 @@ module ActiveSupport
319
334
  dup.tap { |hash| hash.reject!(*args, &block) }
320
335
  end
321
336
 
322
- def transform_values(*args, &block)
337
+ def transform_values(&block)
323
338
  return to_enum(:transform_values) unless block_given?
324
- dup.tap { |hash| hash.transform_values!(*args, &block) }
339
+ dup.tap { |hash| hash.transform_values!(&block) }
325
340
  end
326
341
 
327
- def transform_keys(*args, &block)
328
- return to_enum(:transform_keys) unless block_given?
329
- dup.tap { |hash| hash.transform_keys!(*args, &block) }
342
+ NOT_GIVEN = Object.new # :nodoc:
343
+
344
+ def transform_keys(hash = NOT_GIVEN, &block)
345
+ return to_enum(:transform_keys) if NOT_GIVEN.equal?(hash) && !block_given?
346
+ dup.tap { |h| h.transform_keys!(hash, &block) }
330
347
  end
331
348
 
332
- def transform_keys!
333
- return enum_for(:transform_keys!) { size } unless block_given?
334
- keys.each do |key|
335
- self[yield(key)] = delete(key)
349
+ def transform_keys!(hash = NOT_GIVEN, &block)
350
+ return to_enum(:transform_keys!) if NOT_GIVEN.equal?(hash) && !block_given?
351
+
352
+ if hash.nil?
353
+ super
354
+ elsif NOT_GIVEN.equal?(hash)
355
+ keys.each { |key| self[yield(key)] = delete(key) }
356
+ elsif block_given?
357
+ keys.each { |key| self[hash[key] || yield(key)] = delete(key) }
358
+ else
359
+ keys.each { |key| self[hash[key] || key] = delete(key) }
336
360
  end
361
+
337
362
  self
338
363
  end
339
364
 
@@ -357,40 +382,59 @@ module ActiveSupport
357
382
  set_defaults(_new_hash)
358
383
 
359
384
  each do |key, value|
360
- _new_hash[key] = convert_value(value, for: :to_hash)
385
+ _new_hash[key] = convert_value(value, conversion: :to_hash)
361
386
  end
362
387
  _new_hash
363
388
  end
364
389
 
365
390
  private
366
- def convert_key(key) # :doc:
367
- key.kind_of?(Symbol) ? key.to_s : key
391
+ if Symbol.method_defined?(:name)
392
+ def convert_key(key)
393
+ key.kind_of?(Symbol) ? key.name : key
394
+ end
395
+ else
396
+ def convert_key(key)
397
+ key.kind_of?(Symbol) ? key.to_s : key
398
+ end
368
399
  end
369
400
 
370
- def convert_value(value, options = {}) # :doc:
401
+ def convert_value(value, conversion: nil)
371
402
  if value.is_a? Hash
372
- if options[:for] == :to_hash
403
+ if conversion == :to_hash
373
404
  value.to_hash
374
405
  else
375
406
  value.nested_under_indifferent_access
376
407
  end
377
408
  elsif value.is_a?(Array)
378
- if options[:for] != :assignment || value.frozen?
409
+ if conversion != :assignment || value.frozen?
379
410
  value = value.dup
380
411
  end
381
- value.map! { |e| convert_value(e, options) }
412
+ value.map! { |e| convert_value(e, conversion: conversion) }
382
413
  else
383
414
  value
384
415
  end
385
416
  end
386
417
 
387
- def set_defaults(target) # :doc:
418
+ def set_defaults(target)
388
419
  if default_proc
389
420
  target.default_proc = default_proc.dup
390
421
  else
391
422
  target.default = default
392
423
  end
393
424
  end
425
+
426
+ def update_with_single_argument(other_hash, block)
427
+ if other_hash.is_a? HashWithIndifferentAccess
428
+ regular_update(other_hash, &block)
429
+ else
430
+ other_hash.to_hash.each_pair do |key, value|
431
+ if block && key?(key)
432
+ value = block.call(convert_key(key), self[key], value)
433
+ end
434
+ regular_writer(convert_key(key), convert_value(value))
435
+ end
436
+ end
437
+ end
394
438
  end
395
439
  end
396
440
 
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module HtmlSafeTranslation # :nodoc:
5
+ extend self
6
+
7
+ def translate(key, **options)
8
+ if html_safe_translation_key?(key)
9
+ html_safe_options = html_escape_translation_options(options)
10
+
11
+ exception = false
12
+ exception_handler = ->(*args) do
13
+ exception = true
14
+ I18n.exception_handler.call(*args)
15
+ end
16
+ translation = I18n.translate(key, **html_safe_options, exception_handler: exception_handler)
17
+ if exception
18
+ translation
19
+ else
20
+ html_safe_translation(translation)
21
+ end
22
+ else
23
+ I18n.translate(key, **options)
24
+ end
25
+ end
26
+
27
+ private
28
+ def html_safe_translation_key?(key)
29
+ /(?:_|\b)html\z/.match?(key)
30
+ end
31
+
32
+ def html_escape_translation_options(options)
33
+ options.each do |name, value|
34
+ unless i18n_option?(name) || (name == :count && value.is_a?(Numeric))
35
+ options[name] = ERB::Util.html_escape(value.to_s)
36
+ end
37
+ end
38
+ end
39
+
40
+ def i18n_option?(name)
41
+ (@i18n_option_names ||= I18n::RESERVED_KEYS.to_set).include?(name)
42
+ end
43
+
44
+
45
+ def html_safe_translation(translation)
46
+ if translation.respond_to?(:map)
47
+ translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
48
+ else
49
+ translation.respond_to?(:html_safe) ? translation.html_safe : translation
50
+ end
51
+ end
52
+ end
53
+ end
@@ -5,8 +5,9 @@ require "active_support/core_ext/hash/except"
5
5
  require "active_support/core_ext/hash/slice"
6
6
  begin
7
7
  require "i18n"
8
+ require "i18n/backend/fallbacks"
8
9
  rescue LoadError => e
9
- $stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
10
+ warn "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
10
11
  raise e
11
12
  end
12
13
  require "active_support/lazy_load_hooks"
@@ -12,9 +12,7 @@ module I18n
12
12
  config.i18n.load_path = []
13
13
  config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
14
14
 
15
- if I18n.respond_to?(:eager_load!)
16
- config.eager_load_namespaces << I18n
17
- end
15
+ config.eager_load_namespaces << I18n
18
16
 
19
17
  # Set the i18n configuration after initialization since a lot of
20
18
  # configuration is still usually done in application initializers.
@@ -50,8 +48,10 @@ module I18n
50
48
  app.config.i18n.load_path.unshift(*value.flat_map(&:existent))
51
49
  when :load_path
52
50
  I18n.load_path += value
51
+ when :raise_on_missing_translations
52
+ setup_raise_on_missing_translations_config(app)
53
53
  else
54
- I18n.send("#{setting}=", value)
54
+ I18n.public_send("#{setting}=", value)
55
55
  end
56
56
  end
57
57
 
@@ -60,21 +60,36 @@ module I18n
60
60
  # Restore available locales check so it will take place from now on.
61
61
  I18n.enforce_available_locales = enforce_available_locales
62
62
 
63
- directories = watched_dirs_with_extensions(reloadable_paths)
64
- reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
65
- I18n.load_path.keep_if { |p| File.exist?(p) }
66
- I18n.load_path |= reloadable_paths.flat_map(&:existent)
63
+ if app.config.reloading_enabled?
64
+ directories = watched_dirs_with_extensions(reloadable_paths)
65
+ reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
66
+ I18n.load_path.keep_if { |p| File.exist?(p) }
67
+ I18n.load_path |= reloadable_paths.flat_map(&:existent)
68
+ end
67
69
 
68
- I18n.reload!
70
+ app.reloaders << reloader
71
+ app.reloader.to_run do
72
+ reloader.execute_if_updated { require_unload_lock! }
73
+ end
74
+ reloader.execute
69
75
  end
70
76
 
71
- app.reloaders << reloader
72
- app.reloader.to_run do
73
- reloader.execute_if_updated { require_unload_lock! }
77
+ @i18n_inited = true
78
+ end
79
+
80
+ def self.setup_raise_on_missing_translations_config(app)
81
+ ActiveSupport.on_load(:action_view) do
82
+ ActionView::Helpers::TranslationHelper.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
74
83
  end
75
- reloader.execute
76
84
 
77
- @i18n_inited = true
85
+ if app.config.i18n.raise_on_missing_translations &&
86
+ I18n.exception_handler.is_a?(I18n::ExceptionHandler) # Only override the i18n gem's default exception handler.
87
+
88
+ I18n.exception_handler = ->(exception, *) {
89
+ exception = exception.to_exception if exception.is_a?(I18n::MissingTranslation)
90
+ raise exception
91
+ }
92
+ end
78
93
  end
79
94
 
80
95
  def self.include_fallbacks_module
@@ -94,19 +109,6 @@ module I18n
94
109
  [I18n.default_locale]
95
110
  end
96
111
 
97
- if args.empty? || args.first.is_a?(Hash)
98
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
99
- Using I18n fallbacks with an empty `defaults` sets the defaults to
100
- include the `default_locale`. This behavior will change in Rails 6.1.
101
- If you desire the default locale to be included in the defaults, please
102
- explicitly configure it with `config.i18n.fallbacks.defaults =
103
- [I18n.default_locale]` or `config.i18n.fallbacks = [I18n.default_locale,
104
- {...}]`. If you want to opt-in to the new behavior, use
105
- `config.i18n.fallbacks.defaults = [nil, {...}]`.
106
- MSG
107
- args.unshift I18n.default_locale
108
- end
109
-
110
112
  I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
111
113
  end
112
114
 
@@ -2,12 +2,13 @@
2
2
 
3
3
  require "concurrent/map"
4
4
  require "active_support/i18n"
5
- require "active_support/deprecation"
6
5
 
7
6
  module ActiveSupport
8
7
  module Inflector
9
8
  extend self
10
9
 
10
+ # = Active Support \Inflections
11
+ #
11
12
  # A singleton instance of this class is yielded by Inflector.inflections,
12
13
  # which can then be used to specify additional inflection rules. If passed
13
14
  # an optional locale, rules for other languages can be specified. The
@@ -17,13 +18,13 @@ module ActiveSupport
17
18
  # inflect.plural /^(ox)$/i, '\1\2en'
18
19
  # inflect.singular /^(ox)en/i, '\1'
19
20
  #
20
- # inflect.irregular 'octopus', 'octopi'
21
+ # inflect.irregular 'cactus', 'cacti'
21
22
  #
22
23
  # inflect.uncountable 'equipment'
23
24
  # end
24
25
  #
25
26
  # New rules are added at the top. So in the example above, the irregular
26
- # rule for octopus will now be the first of the pluralization and
27
+ # rule for cactus will now be the first of the pluralization and
27
28
  # singularization rules that is runs. This guarantees that your rules run
28
29
  # before any of the rules that may already have been loaded.
29
30
  class Inflections
@@ -65,6 +66,13 @@ module ActiveSupport
65
66
  @__instance__[locale] ||= new
66
67
  end
67
68
 
69
+ def self.instance_or_fallback(locale)
70
+ I18n.fallbacks[locale].each do |k|
71
+ return @__instance__[k] if @__instance__.key?(k)
72
+ end
73
+ instance(locale)
74
+ end
75
+
68
76
  attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms
69
77
 
70
78
  attr_reader :acronyms_camelize_regex, :acronyms_underscore_regex # :nodoc:
@@ -77,7 +85,7 @@ module ActiveSupport
77
85
  # Private, for the test suite.
78
86
  def initialize_dup(orig) # :nodoc:
79
87
  %w(plurals singulars uncountables humans acronyms).each do |scope|
80
- instance_variable_set("@#{scope}", orig.send(scope).dup)
88
+ instance_variable_set("@#{scope}", orig.public_send(scope).dup)
81
89
  end
82
90
  define_acronym_regex_patterns
83
91
  end
@@ -161,7 +169,7 @@ module ActiveSupport
161
169
  # regular expressions. You simply pass the irregular in singular and
162
170
  # plural form.
163
171
  #
164
- # irregular 'octopus', 'octopi'
172
+ # irregular 'cactus', 'cacti'
165
173
  # irregular 'person', 'people'
166
174
  def irregular(singular, plural)
167
175
  @uncountables.delete(singular)
@@ -216,15 +224,24 @@ module ActiveSupport
216
224
  # Clears the loaded inflections within a given scope (default is
217
225
  # <tt>:all</tt>). Give the scope as a symbol of the inflection type, the
218
226
  # options are: <tt>:plurals</tt>, <tt>:singulars</tt>, <tt>:uncountables</tt>,
219
- # <tt>:humans</tt>.
227
+ # <tt>:humans</tt>, <tt>:acronyms</tt>.
220
228
  #
221
229
  # clear :all
222
230
  # clear :plurals
223
231
  def clear(scope = :all)
224
232
  case scope
225
233
  when :all
226
- @plurals, @singulars, @uncountables, @humans = [], [], Uncountables.new, []
227
- else
234
+ clear(:acronyms)
235
+ clear(:plurals)
236
+ clear(:singulars)
237
+ clear(:uncountables)
238
+ clear(:humans)
239
+ when :acronyms
240
+ @acronyms = {}
241
+ define_acronym_regex_patterns
242
+ when :uncountables
243
+ @uncountables = Uncountables.new
244
+ when :plurals, :singulars, :humans
228
245
  instance_variable_set "@#{scope}", []
229
246
  end
230
247
  end
@@ -249,7 +266,7 @@ module ActiveSupport
249
266
  if block_given?
250
267
  yield Inflections.instance(locale)
251
268
  else
252
- Inflections.instance(locale)
269
+ Inflections.instance_or_fallback(locale)
253
270
  end
254
271
  end
255
272
  end