omg-activesupport 8.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (289) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +86 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support/actionable_error.rb +50 -0
  6. data/lib/active_support/all.rb +5 -0
  7. data/lib/active_support/array_inquirer.rb +50 -0
  8. data/lib/active_support/backtrace_cleaner.rb +163 -0
  9. data/lib/active_support/benchmark.rb +21 -0
  10. data/lib/active_support/benchmarkable.rb +53 -0
  11. data/lib/active_support/broadcast_logger.rb +251 -0
  12. data/lib/active_support/builder.rb +8 -0
  13. data/lib/active_support/cache/coder.rb +153 -0
  14. data/lib/active_support/cache/entry.rb +134 -0
  15. data/lib/active_support/cache/file_store.rb +244 -0
  16. data/lib/active_support/cache/mem_cache_store.rb +290 -0
  17. data/lib/active_support/cache/memory_store.rb +262 -0
  18. data/lib/active_support/cache/null_store.rb +62 -0
  19. data/lib/active_support/cache/redis_cache_store.rb +492 -0
  20. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  21. data/lib/active_support/cache/strategy/local_cache.rb +201 -0
  22. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  23. data/lib/active_support/cache.rb +1104 -0
  24. data/lib/active_support/callbacks.rb +944 -0
  25. data/lib/active_support/class_attribute.rb +26 -0
  26. data/lib/active_support/code_generator.rb +79 -0
  27. data/lib/active_support/concern.rb +217 -0
  28. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +72 -0
  29. data/lib/active_support/concurrency/null_lock.rb +13 -0
  30. data/lib/active_support/concurrency/share_lock.rb +225 -0
  31. data/lib/active_support/configurable.rb +159 -0
  32. data/lib/active_support/configuration_file.rb +60 -0
  33. data/lib/active_support/core_ext/array/access.rb +100 -0
  34. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  35. data/lib/active_support/core_ext/array/extract.rb +21 -0
  36. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  37. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  38. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  39. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  40. data/lib/active_support/core_ext/array.rb +9 -0
  41. data/lib/active_support/core_ext/benchmark.rb +13 -0
  42. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  43. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  44. data/lib/active_support/core_ext/class/attribute.rb +122 -0
  45. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  46. data/lib/active_support/core_ext/class/subclasses.rb +24 -0
  47. data/lib/active_support/core_ext/class.rb +4 -0
  48. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  49. data/lib/active_support/core_ext/date/blank.rb +18 -0
  50. data/lib/active_support/core_ext/date/calculations.rb +161 -0
  51. data/lib/active_support/core_ext/date/conversions.rb +98 -0
  52. data/lib/active_support/core_ext/date/zones.rb +8 -0
  53. data/lib/active_support/core_ext/date.rb +7 -0
  54. data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
  55. data/lib/active_support/core_ext/date_and_time/compatibility.rb +58 -0
  56. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  57. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  58. data/lib/active_support/core_ext/date_time/blank.rb +18 -0
  59. data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
  60. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  61. data/lib/active_support/core_ext/date_time/conversions.rb +106 -0
  62. data/lib/active_support/core_ext/date_time.rb +7 -0
  63. data/lib/active_support/core_ext/digest/uuid.rb +76 -0
  64. data/lib/active_support/core_ext/digest.rb +3 -0
  65. data/lib/active_support/core_ext/enumerable.rb +267 -0
  66. data/lib/active_support/core_ext/erb/util.rb +201 -0
  67. data/lib/active_support/core_ext/file/atomic.rb +72 -0
  68. data/lib/active_support/core_ext/file.rb +3 -0
  69. data/lib/active_support/core_ext/hash/conversions.rb +262 -0
  70. data/lib/active_support/core_ext/hash/deep_merge.rb +42 -0
  71. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  72. data/lib/active_support/core_ext/hash/except.rb +12 -0
  73. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  74. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  75. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  76. data/lib/active_support/core_ext/hash/slice.rb +27 -0
  77. data/lib/active_support/core_ext/hash.rb +10 -0
  78. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  79. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  80. data/lib/active_support/core_ext/integer/time.rb +22 -0
  81. data/lib/active_support/core_ext/integer.rb +5 -0
  82. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  83. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  84. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  85. data/lib/active_support/core_ext/kernel.rb +5 -0
  86. data/lib/active_support/core_ext/load_error.rb +9 -0
  87. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  88. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  89. data/lib/active_support/core_ext/module/attr_internal.rb +49 -0
  90. data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
  91. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
  92. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  93. data/lib/active_support/core_ext/module/delegation.rb +225 -0
  94. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  95. data/lib/active_support/core_ext/module/introspection.rb +62 -0
  96. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  97. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  98. data/lib/active_support/core_ext/module.rb +13 -0
  99. data/lib/active_support/core_ext/name_error.rb +59 -0
  100. data/lib/active_support/core_ext/numeric/bytes.rb +75 -0
  101. data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
  102. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  103. data/lib/active_support/core_ext/numeric.rb +5 -0
  104. data/lib/active_support/core_ext/object/acts_like.rb +45 -0
  105. data/lib/active_support/core_ext/object/blank.rb +199 -0
  106. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  107. data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
  108. data/lib/active_support/core_ext/object/duplicable.rb +69 -0
  109. data/lib/active_support/core_ext/object/inclusion.rb +37 -0
  110. data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
  111. data/lib/active_support/core_ext/object/json.rb +260 -0
  112. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  113. data/lib/active_support/core_ext/object/to_query.rb +87 -0
  114. data/lib/active_support/core_ext/object/try.rb +158 -0
  115. data/lib/active_support/core_ext/object/with.rb +46 -0
  116. data/lib/active_support/core_ext/object/with_options.rb +101 -0
  117. data/lib/active_support/core_ext/object.rb +17 -0
  118. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  119. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  120. data/lib/active_support/core_ext/pathname.rb +4 -0
  121. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  122. data/lib/active_support/core_ext/range/conversions.rb +62 -0
  123. data/lib/active_support/core_ext/range/each.rb +24 -0
  124. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  125. data/lib/active_support/core_ext/range.rb +6 -0
  126. data/lib/active_support/core_ext/regexp.rb +14 -0
  127. data/lib/active_support/core_ext/securerandom.rb +41 -0
  128. data/lib/active_support/core_ext/string/access.rb +95 -0
  129. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  130. data/lib/active_support/core_ext/string/conversions.rb +60 -0
  131. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  132. data/lib/active_support/core_ext/string/filters.rb +151 -0
  133. data/lib/active_support/core_ext/string/indent.rb +45 -0
  134. data/lib/active_support/core_ext/string/inflections.rb +300 -0
  135. data/lib/active_support/core_ext/string/inquiry.rb +16 -0
  136. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  137. data/lib/active_support/core_ext/string/output_safety.rb +228 -0
  138. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  139. data/lib/active_support/core_ext/string/strip.rb +27 -0
  140. data/lib/active_support/core_ext/string/zones.rb +16 -0
  141. data/lib/active_support/core_ext/string.rb +15 -0
  142. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  143. data/lib/active_support/core_ext/symbol.rb +3 -0
  144. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  145. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  146. data/lib/active_support/core_ext/time/calculations.rb +386 -0
  147. data/lib/active_support/core_ext/time/compatibility.rb +32 -0
  148. data/lib/active_support/core_ext/time/conversions.rb +75 -0
  149. data/lib/active_support/core_ext/time/zones.rb +97 -0
  150. data/lib/active_support/core_ext/time.rb +7 -0
  151. data/lib/active_support/core_ext.rb +5 -0
  152. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  153. data/lib/active_support/current_attributes.rb +233 -0
  154. data/lib/active_support/deep_mergeable.rb +53 -0
  155. data/lib/active_support/delegation.rb +202 -0
  156. data/lib/active_support/dependencies/autoload.rb +72 -0
  157. data/lib/active_support/dependencies/interlock.rb +49 -0
  158. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  159. data/lib/active_support/dependencies.rb +98 -0
  160. data/lib/active_support/deprecation/behaviors.rb +148 -0
  161. data/lib/active_support/deprecation/constant_accessor.rb +74 -0
  162. data/lib/active_support/deprecation/deprecators.rb +104 -0
  163. data/lib/active_support/deprecation/disallowed.rb +54 -0
  164. data/lib/active_support/deprecation/method_wrappers.rb +68 -0
  165. data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
  166. data/lib/active_support/deprecation/reporting.rb +179 -0
  167. data/lib/active_support/deprecation.rb +81 -0
  168. data/lib/active_support/deprecator.rb +7 -0
  169. data/lib/active_support/descendants_tracker.rb +112 -0
  170. data/lib/active_support/digest.rb +22 -0
  171. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  172. data/lib/active_support/duration/iso8601_serializer.rb +64 -0
  173. data/lib/active_support/duration.rb +520 -0
  174. data/lib/active_support/encrypted_configuration.rb +126 -0
  175. data/lib/active_support/encrypted_file.rb +133 -0
  176. data/lib/active_support/environment_inquirer.rb +40 -0
  177. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  178. data/lib/active_support/error_reporter.rb +265 -0
  179. data/lib/active_support/evented_file_update_checker.rb +182 -0
  180. data/lib/active_support/execution_context/test_helper.rb +13 -0
  181. data/lib/active_support/execution_context.rb +53 -0
  182. data/lib/active_support/execution_wrapper.rb +150 -0
  183. data/lib/active_support/executor/test_helper.rb +7 -0
  184. data/lib/active_support/executor.rb +8 -0
  185. data/lib/active_support/file_update_checker.rb +164 -0
  186. data/lib/active_support/fork_tracker.rb +43 -0
  187. data/lib/active_support/gem_version.rb +17 -0
  188. data/lib/active_support/gzip.rb +40 -0
  189. data/lib/active_support/hash_with_indifferent_access.rb +445 -0
  190. data/lib/active_support/html_safe_translation.rb +56 -0
  191. data/lib/active_support/i18n.rb +17 -0
  192. data/lib/active_support/i18n_railtie.rb +138 -0
  193. data/lib/active_support/inflections.rb +72 -0
  194. data/lib/active_support/inflector/inflections.rb +273 -0
  195. data/lib/active_support/inflector/methods.rb +387 -0
  196. data/lib/active_support/inflector/transliterate.rb +149 -0
  197. data/lib/active_support/inflector.rb +9 -0
  198. data/lib/active_support/isolated_execution_state.rb +75 -0
  199. data/lib/active_support/json/decoding.rb +76 -0
  200. data/lib/active_support/json/encoding.rb +120 -0
  201. data/lib/active_support/json.rb +4 -0
  202. data/lib/active_support/key_generator.rb +66 -0
  203. data/lib/active_support/lazy_load_hooks.rb +107 -0
  204. data/lib/active_support/locale/en.rb +33 -0
  205. data/lib/active_support/locale/en.yml +141 -0
  206. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  207. data/lib/active_support/log_subscriber.rb +192 -0
  208. data/lib/active_support/logger.rb +55 -0
  209. data/lib/active_support/logger_silence.rb +21 -0
  210. data/lib/active_support/logger_thread_safe_level.rb +47 -0
  211. data/lib/active_support/message_encryptor.rb +374 -0
  212. data/lib/active_support/message_encryptors.rb +141 -0
  213. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  214. data/lib/active_support/message_pack/extensions.rb +305 -0
  215. data/lib/active_support/message_pack/serializer.rb +63 -0
  216. data/lib/active_support/message_pack.rb +50 -0
  217. data/lib/active_support/message_verifier.rb +368 -0
  218. data/lib/active_support/message_verifiers.rb +135 -0
  219. data/lib/active_support/messages/codec.rb +65 -0
  220. data/lib/active_support/messages/metadata.rb +146 -0
  221. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  222. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  223. data/lib/active_support/messages/rotator.rb +59 -0
  224. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  225. data/lib/active_support/multibyte/chars.rb +178 -0
  226. data/lib/active_support/multibyte/unicode.rb +42 -0
  227. data/lib/active_support/multibyte.rb +23 -0
  228. data/lib/active_support/notifications/fanout.rb +446 -0
  229. data/lib/active_support/notifications/instrumenter.rb +240 -0
  230. data/lib/active_support/notifications.rb +281 -0
  231. data/lib/active_support/number_helper/number_converter.rb +190 -0
  232. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  233. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  234. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  235. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  236. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  237. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  238. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  239. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  240. data/lib/active_support/number_helper.rb +479 -0
  241. data/lib/active_support/option_merger.rb +38 -0
  242. data/lib/active_support/ordered_hash.rb +50 -0
  243. data/lib/active_support/ordered_options.rb +147 -0
  244. data/lib/active_support/parameter_filter.rb +157 -0
  245. data/lib/active_support/proxy_object.rb +20 -0
  246. data/lib/active_support/rails.rb +26 -0
  247. data/lib/active_support/railtie.rb +161 -0
  248. data/lib/active_support/reloader.rb +138 -0
  249. data/lib/active_support/rescuable.rb +176 -0
  250. data/lib/active_support/secure_compare_rotator.rb +58 -0
  251. data/lib/active_support/security_utils.rb +38 -0
  252. data/lib/active_support/string_inquirer.rb +35 -0
  253. data/lib/active_support/subscriber.rb +146 -0
  254. data/lib/active_support/syntax_error_proxy.rb +60 -0
  255. data/lib/active_support/tagged_logging.rb +152 -0
  256. data/lib/active_support/test_case.rb +304 -0
  257. data/lib/active_support/testing/assertions.rb +332 -0
  258. data/lib/active_support/testing/autorun.rb +5 -0
  259. data/lib/active_support/testing/constant_lookup.rb +51 -0
  260. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  261. data/lib/active_support/testing/declarative.rb +28 -0
  262. data/lib/active_support/testing/deprecation.rb +82 -0
  263. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  264. data/lib/active_support/testing/file_fixtures.rb +38 -0
  265. data/lib/active_support/testing/isolation.rb +121 -0
  266. data/lib/active_support/testing/method_call_assertions.rb +69 -0
  267. data/lib/active_support/testing/parallelization/server.rb +85 -0
  268. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  269. data/lib/active_support/testing/parallelization.rb +55 -0
  270. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  271. data/lib/active_support/testing/setup_and_teardown.rb +57 -0
  272. data/lib/active_support/testing/stream.rb +41 -0
  273. data/lib/active_support/testing/strict_warnings.rb +43 -0
  274. data/lib/active_support/testing/tagged_logging.rb +27 -0
  275. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  276. data/lib/active_support/testing/time_helpers.rb +269 -0
  277. data/lib/active_support/time.rb +20 -0
  278. data/lib/active_support/time_with_zone.rb +609 -0
  279. data/lib/active_support/values/time_zone.rb +614 -0
  280. data/lib/active_support/version.rb +10 -0
  281. data/lib/active_support/xml_mini/jdom.rb +175 -0
  282. data/lib/active_support/xml_mini/libxml.rb +80 -0
  283. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  284. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  285. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  286. data/lib/active_support/xml_mini/rexml.rb +137 -0
  287. data/lib/active_support/xml_mini.rb +211 -0
  288. data/lib/active_support.rb +144 -0
  289. metadata +526 -0
@@ -0,0 +1,445 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/keys"
4
+ require "active_support/core_ext/hash/reverse_merge"
5
+ require "active_support/core_ext/hash/except"
6
+ require "active_support/core_ext/hash/slice"
7
+
8
+ module ActiveSupport
9
+ # = \Hash With Indifferent Access
10
+ #
11
+ # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
12
+ # to be the same.
13
+ #
14
+ # rgb = ActiveSupport::HashWithIndifferentAccess.new
15
+ #
16
+ # rgb[:black] = '#000000'
17
+ # rgb[:black] # => '#000000'
18
+ # rgb['black'] # => '#000000'
19
+ #
20
+ # rgb['white'] = '#FFFFFF'
21
+ # rgb[:white] # => '#FFFFFF'
22
+ # rgb['white'] # => '#FFFFFF'
23
+ #
24
+ # Internally symbols are mapped to strings when used as keys in the entire
25
+ # writing interface (calling <tt>[]=</tt>, <tt>merge</tt>, etc). This
26
+ # mapping belongs to the public interface. For example, given:
27
+ #
28
+ # hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
29
+ #
30
+ # You are guaranteed that the key is returned as a string:
31
+ #
32
+ # hash.keys # => ["a"]
33
+ #
34
+ # Technically other types of keys are accepted:
35
+ #
36
+ # hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
37
+ # hash[0] = 0
38
+ # hash # => {"a"=>1, 0=>0}
39
+ #
40
+ # but this class is intended for use cases where strings or symbols are the
41
+ # expected keys and it is convenient to understand both as the same. For
42
+ # example the +params+ hash in Ruby on \Rails.
43
+ #
44
+ # Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
45
+ #
46
+ # rgb = { black: '#000000', white: '#FFFFFF' }.with_indifferent_access
47
+ #
48
+ # which may be handy.
49
+ #
50
+ # To access this class outside of \Rails, require the core extension with:
51
+ #
52
+ # require "active_support/core_ext/hash/indifferent_access"
53
+ #
54
+ # which will, in turn, require this file.
55
+ class HashWithIndifferentAccess < Hash
56
+ # Returns +true+ so that <tt>Array#extract_options!</tt> finds members of
57
+ # this class.
58
+ def extractable_options?
59
+ true
60
+ end
61
+
62
+ def with_indifferent_access
63
+ dup
64
+ end
65
+
66
+ def nested_under_indifferent_access
67
+ self
68
+ end
69
+
70
+ def initialize(constructor = nil)
71
+ if constructor.respond_to?(:to_hash)
72
+ super()
73
+ update(constructor)
74
+
75
+ hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
76
+ self.default = hash.default if hash.default
77
+ self.default_proc = hash.default_proc if hash.default_proc
78
+ elsif constructor.nil?
79
+ super()
80
+ else
81
+ super(constructor)
82
+ end
83
+ end
84
+
85
+ def self.[](*args)
86
+ new.merge!(Hash[*args])
87
+ end
88
+
89
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
90
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
91
+
92
+ # Assigns a new value to the hash:
93
+ #
94
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
95
+ # hash[:key] = 'value'
96
+ #
97
+ # This value can be later fetched using either +:key+ or <tt>'key'</tt>.
98
+ def []=(key, value)
99
+ regular_writer(convert_key(key), convert_value(value, conversion: :assignment))
100
+ end
101
+
102
+ alias_method :store, :[]=
103
+
104
+ # Updates the receiver in-place, merging in the hashes passed as arguments:
105
+ #
106
+ # hash_1 = ActiveSupport::HashWithIndifferentAccess.new
107
+ # hash_1[:key] = 'value'
108
+ #
109
+ # hash_2 = ActiveSupport::HashWithIndifferentAccess.new
110
+ # hash_2[:key] = 'New Value!'
111
+ #
112
+ # hash_1.update(hash_2) # => {"key"=>"New Value!"}
113
+ #
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+.
119
+ # In either case the merge respects the semantics of indifferent access.
120
+ #
121
+ # If the argument is a regular hash with keys +:key+ and <tt>"key"</tt> only one
122
+ # of the values end up in the receiver, but which one is unspecified.
123
+ #
124
+ # When given a block, the value for duplicated keys will be determined
125
+ # by the result of invoking the block with the duplicated key, the value
126
+ # in the receiver, and the value in +other_hash+. The rules for duplicated
127
+ # keys follow the semantics of indifferent access:
128
+ #
129
+ # hash_1[:key] = 10
130
+ # hash_2['key'] = 12
131
+ # hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
132
+ def update(*other_hashes, &block)
133
+ if other_hashes.size == 1
134
+ update_with_single_argument(other_hashes.first, block)
135
+ else
136
+ other_hashes.each do |other_hash|
137
+ update_with_single_argument(other_hash, block)
138
+ end
139
+ end
140
+ self
141
+ end
142
+
143
+ alias_method :merge!, :update
144
+
145
+ # Checks the hash for a key matching the argument passed in:
146
+ #
147
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
148
+ # hash['key'] = 'value'
149
+ # hash.key?(:key) # => true
150
+ # hash.key?('key') # => true
151
+ def key?(key)
152
+ super(convert_key(key))
153
+ end
154
+
155
+ alias_method :include?, :key?
156
+ alias_method :has_key?, :key?
157
+ alias_method :member?, :key?
158
+
159
+ # Same as <tt>Hash#[]</tt> where the key passed as argument can be
160
+ # either a string or a symbol:
161
+ #
162
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
163
+ # counters[:foo] = 1
164
+ #
165
+ # counters['foo'] # => 1
166
+ # counters[:foo] # => 1
167
+ # counters[:zoo] # => nil
168
+ def [](key)
169
+ super(convert_key(key))
170
+ end
171
+
172
+ # Same as <tt>Hash#assoc</tt> where the key passed as argument can be
173
+ # either a string or a symbol:
174
+ #
175
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
176
+ # counters[:foo] = 1
177
+ #
178
+ # counters.assoc('foo') # => ["foo", 1]
179
+ # counters.assoc(:foo) # => ["foo", 1]
180
+ # counters.assoc(:zoo) # => nil
181
+ def assoc(key)
182
+ super(convert_key(key))
183
+ end
184
+
185
+ # Same as <tt>Hash#fetch</tt> where the key passed as argument can be
186
+ # either a string or a symbol:
187
+ #
188
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
189
+ # counters[:foo] = 1
190
+ #
191
+ # counters.fetch('foo') # => 1
192
+ # counters.fetch(:bar, 0) # => 0
193
+ # counters.fetch(:bar) { |key| 0 } # => 0
194
+ # counters.fetch(:zoo) # => KeyError: key not found: "zoo"
195
+ def fetch(key, *extras)
196
+ super(convert_key(key), *extras)
197
+ end
198
+
199
+ # Same as <tt>Hash#dig</tt> where the key passed as argument can be
200
+ # either a string or a symbol:
201
+ #
202
+ # counters = ActiveSupport::HashWithIndifferentAccess.new
203
+ # counters[:foo] = { bar: 1 }
204
+ #
205
+ # counters.dig('foo', 'bar') # => 1
206
+ # counters.dig(:foo, :bar) # => 1
207
+ # counters.dig(:zoo) # => nil
208
+ def dig(*args)
209
+ args[0] = convert_key(args[0]) if args.size > 0
210
+ super(*args)
211
+ end
212
+
213
+ # Same as <tt>Hash#default</tt> where the key passed as argument can be
214
+ # either a string or a symbol:
215
+ #
216
+ # hash = ActiveSupport::HashWithIndifferentAccess.new(1)
217
+ # hash.default # => 1
218
+ #
219
+ # hash = ActiveSupport::HashWithIndifferentAccess.new { |hash, key| key }
220
+ # hash.default # => nil
221
+ # hash.default('foo') # => 'foo'
222
+ # hash.default(:foo) # => 'foo'
223
+ def default(key = (no_key = true))
224
+ if no_key
225
+ super()
226
+ else
227
+ super(convert_key(key))
228
+ end
229
+ end
230
+
231
+ # Returns an array of the values at the specified indices:
232
+ #
233
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
234
+ # hash[:a] = 'x'
235
+ # hash[:b] = 'y'
236
+ # hash.values_at('a', 'b') # => ["x", "y"]
237
+ def values_at(*keys)
238
+ keys.map! { |key| convert_key(key) }
239
+ super
240
+ end
241
+
242
+ # Returns an array of the values at the specified indices, but also
243
+ # raises an exception when one of the keys can't be found.
244
+ #
245
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
246
+ # hash[:a] = 'x'
247
+ # hash[:b] = 'y'
248
+ # hash.fetch_values('a', 'b') # => ["x", "y"]
249
+ # hash.fetch_values('a', 'c') { |key| 'z' } # => ["x", "z"]
250
+ # hash.fetch_values('a', 'c') # => KeyError: key not found: "c"
251
+ def fetch_values(*indices, &block)
252
+ indices.map! { |key| convert_key(key) }
253
+ super
254
+ end
255
+
256
+ # Returns a shallow copy of the hash.
257
+ #
258
+ # hash = ActiveSupport::HashWithIndifferentAccess.new({ a: { b: 'b' } })
259
+ # dup = hash.dup
260
+ # dup[:a][:c] = 'c'
261
+ #
262
+ # hash[:a][:c] # => "c"
263
+ # dup[:a][:c] # => "c"
264
+ def dup
265
+ self.class.new(self).tap do |new_hash|
266
+ set_defaults(new_hash)
267
+ end
268
+ end
269
+
270
+ # This method has the same semantics of +update+, except it does not
271
+ # modify the receiver but rather returns a new hash with indifferent
272
+ # access with the result of the merge.
273
+ def merge(*hashes, &block)
274
+ dup.update(*hashes, &block)
275
+ end
276
+
277
+ # Like +merge+ but the other way around: Merges the receiver into the
278
+ # argument and returns a new hash with indifferent access as result:
279
+ #
280
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
281
+ # hash['a'] = nil
282
+ # hash.reverse_merge(a: 0, b: 1) # => {"a"=>nil, "b"=>1}
283
+ def reverse_merge(other_hash)
284
+ super(self.class.new(other_hash))
285
+ end
286
+ alias_method :with_defaults, :reverse_merge
287
+
288
+ # Same semantics as +reverse_merge+ but modifies the receiver in-place.
289
+ def reverse_merge!(other_hash)
290
+ super(self.class.new(other_hash))
291
+ end
292
+ alias_method :with_defaults!, :reverse_merge!
293
+
294
+ # Replaces the contents of this hash with other_hash.
295
+ #
296
+ # h = { "a" => 100, "b" => 200 }
297
+ # h.replace({ "c" => 300, "d" => 400 }) # => {"c"=>300, "d"=>400}
298
+ def replace(other_hash)
299
+ super(self.class.new(other_hash))
300
+ end
301
+
302
+ # Removes the specified key from the hash.
303
+ def delete(key)
304
+ super(convert_key(key))
305
+ end
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
311
+ def except(*keys)
312
+ dup.except!(*keys)
313
+ end
314
+ alias_method :without, :except
315
+
316
+ def stringify_keys!; self end
317
+ def deep_stringify_keys!; self end
318
+ def stringify_keys; dup end
319
+ def deep_stringify_keys; dup end
320
+ undef :symbolize_keys!
321
+ undef :deep_symbolize_keys!
322
+ def symbolize_keys; to_hash.symbolize_keys! end
323
+ alias_method :to_options, :symbolize_keys
324
+ def deep_symbolize_keys; to_hash.deep_symbolize_keys! end
325
+ def to_options!; self end
326
+
327
+ def select(*args, &block)
328
+ return to_enum(:select) unless block_given?
329
+ dup.tap { |hash| hash.select!(*args, &block) }
330
+ end
331
+
332
+ def reject(*args, &block)
333
+ return to_enum(:reject) unless block_given?
334
+ dup.tap { |hash| hash.reject!(*args, &block) }
335
+ end
336
+
337
+ def transform_values(&block)
338
+ return to_enum(:transform_values) unless block_given?
339
+ dup.tap { |hash| hash.transform_values!(&block) }
340
+ end
341
+
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) }
347
+ end
348
+
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) }
360
+ end
361
+
362
+ self
363
+ end
364
+
365
+ def slice(*keys)
366
+ keys.map! { |key| convert_key(key) }
367
+ self.class.new(super)
368
+ end
369
+
370
+ def slice!(*keys)
371
+ keys.map! { |key| convert_key(key) }
372
+ super
373
+ end
374
+
375
+ def compact
376
+ dup.tap(&:compact!)
377
+ end
378
+
379
+ # Convert to a regular hash with string keys.
380
+ def to_hash
381
+ copy = Hash[self]
382
+ copy.transform_values! { |v| convert_value_to_hash(v) }
383
+ set_defaults(copy)
384
+ copy
385
+ end
386
+
387
+ def to_proc
388
+ proc { |key| self[key] }
389
+ end
390
+
391
+ private
392
+ def convert_key(key)
393
+ Symbol === key ? key.name : key
394
+ end
395
+
396
+ def convert_value(value, conversion: nil)
397
+ if value.is_a? Hash
398
+ value.nested_under_indifferent_access
399
+ elsif value.is_a?(Array)
400
+ if conversion != :assignment || value.frozen?
401
+ value = value.dup
402
+ end
403
+ value.map! { |e| convert_value(e, conversion: conversion) }
404
+ else
405
+ value
406
+ end
407
+ end
408
+
409
+ def convert_value_to_hash(value)
410
+ if value.is_a? Hash
411
+ value.to_hash
412
+ elsif value.is_a?(Array)
413
+ value.map { |e| convert_value_to_hash(e) }
414
+ else
415
+ value
416
+ end
417
+ end
418
+
419
+
420
+ def set_defaults(target)
421
+ if default_proc
422
+ target.default_proc = default_proc.dup
423
+ else
424
+ target.default = default
425
+ end
426
+ end
427
+
428
+ def update_with_single_argument(other_hash, block)
429
+ if other_hash.is_a? HashWithIndifferentAccess
430
+ regular_update(other_hash, &block)
431
+ else
432
+ other_hash.to_hash.each_pair do |key, value|
433
+ if block && key?(key)
434
+ value = block.call(convert_key(key), self[key], value)
435
+ end
436
+ regular_writer(convert_key(key), convert_value(value))
437
+ end
438
+ end
439
+ end
440
+ end
441
+ end
442
+
443
+ # :stopdoc:
444
+
445
+ HashWithIndifferentAccess = ActiveSupport::HashWithIndifferentAccess
@@ -0,0 +1,56 @@
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
+
13
+ exception_handler = ->(*args) do
14
+ exception = true
15
+ I18n.exception_handler.call(*args)
16
+ end
17
+
18
+ translation = I18n.translate(key, **html_safe_options, exception_handler: exception_handler)
19
+
20
+ if exception
21
+ translation
22
+ else
23
+ html_safe_translation(translation)
24
+ end
25
+ else
26
+ I18n.translate(key, **options)
27
+ end
28
+ end
29
+
30
+ def html_safe_translation_key?(key)
31
+ /(?:_|\b)html\z/.match?(key)
32
+ end
33
+
34
+ private
35
+ def html_escape_translation_options(options)
36
+ options.each do |name, value|
37
+ unless i18n_option?(name) || (name == :count && value.is_a?(Numeric))
38
+ options[name] = ERB::Util.html_escape(value.to_s)
39
+ end
40
+ end
41
+ end
42
+
43
+ def i18n_option?(name)
44
+ (@i18n_option_names ||= I18n::RESERVED_KEYS.to_set).include?(name)
45
+ end
46
+
47
+
48
+ def html_safe_translation(translation)
49
+ if translation.respond_to?(:map)
50
+ translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
51
+ else
52
+ translation.respond_to?(:html_safe) ? translation.html_safe : translation
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/deep_merge"
4
+ require "active_support/core_ext/hash/except"
5
+ require "active_support/core_ext/hash/slice"
6
+ begin
7
+ require "i18n"
8
+ require "i18n/backend/fallbacks"
9
+ rescue LoadError => e
10
+ warn "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
11
+ raise e
12
+ end
13
+ require "active_support/lazy_load_hooks"
14
+
15
+ ActiveSupport.run_load_hooks(:i18n)
16
+ I18n.load_path << File.expand_path("locale/en.yml", __dir__)
17
+ I18n.load_path << File.expand_path("locale/en.rb", __dir__)
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+ require "active_support/core_ext/array/wrap"
5
+
6
+ # :enddoc:
7
+
8
+ module I18n
9
+ class Railtie < Rails::Railtie
10
+ config.i18n = ActiveSupport::OrderedOptions.new
11
+ config.i18n.railties_load_path = []
12
+ config.i18n.load_path = []
13
+ config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
14
+
15
+ config.eager_load_namespaces << I18n
16
+
17
+ # Set the i18n configuration after initialization since a lot of
18
+ # configuration is still usually done in application initializers.
19
+ config.after_initialize do |app|
20
+ I18n::Railtie.initialize_i18n(app)
21
+ end
22
+
23
+ # Trigger i18n config before any eager loading has happened
24
+ # so it's ready if any classes require it when eager loaded.
25
+ config.before_eager_load do |app|
26
+ I18n::Railtie.initialize_i18n(app)
27
+ end
28
+
29
+ @i18n_inited = false
30
+
31
+ # Setup i18n configuration.
32
+ def self.initialize_i18n(app)
33
+ return if @i18n_inited
34
+
35
+ fallbacks = app.config.i18n.delete(:fallbacks)
36
+
37
+ # Avoid issues with setting the default_locale by disabling available locales
38
+ # check while configuring.
39
+ enforce_available_locales = app.config.i18n.delete(:enforce_available_locales)
40
+ enforce_available_locales = I18n.enforce_available_locales if enforce_available_locales.nil?
41
+ I18n.enforce_available_locales = false
42
+
43
+ reloadable_paths = []
44
+ app.config.i18n.each do |setting, value|
45
+ case setting
46
+ when :railties_load_path
47
+ reloadable_paths = value
48
+ app.config.i18n.load_path.unshift(*value.flat_map(&:existent))
49
+ when :load_path
50
+ I18n.load_path += value
51
+ when :raise_on_missing_translations
52
+ strict = value == :strict
53
+ setup_raise_on_missing_translations_config(app, strict)
54
+ else
55
+ I18n.public_send("#{setting}=", value)
56
+ end
57
+ end
58
+
59
+ init_fallbacks(fallbacks) if fallbacks && validate_fallbacks(fallbacks)
60
+
61
+ # Restore available locales check so it will take place from now on.
62
+ I18n.enforce_available_locales = enforce_available_locales
63
+
64
+ if app.config.reloading_enabled?
65
+ directories = watched_dirs_with_extensions(reloadable_paths)
66
+ root_load_paths = I18n.load_path.select { |path| path.start_with?(Rails.root.to_s) }
67
+ reloader = app.config.file_watcher.new(root_load_paths, directories) do
68
+ I18n.load_path.delete_if { |p| p.start_with?(Rails.root.to_s) && !File.exist?(p) }
69
+ I18n.load_path |= reloadable_paths.flat_map(&:existent)
70
+ end
71
+
72
+ app.reloaders << reloader
73
+ app.reloader.to_run do
74
+ reloader.execute_if_updated { require_unload_lock! }
75
+ end
76
+ reloader.execute
77
+ end
78
+
79
+ @i18n_inited = true
80
+ end
81
+
82
+ def self.setup_raise_on_missing_translations_config(app, strict)
83
+ ActiveSupport.on_load(:action_view) do
84
+ ActionView::Helpers::TranslationHelper.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
85
+ end
86
+
87
+ ActiveSupport.on_load(:active_model_translation) do
88
+ ActiveModel::Translation.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations if strict
89
+ end
90
+
91
+ if app.config.i18n.raise_on_missing_translations &&
92
+ I18n.exception_handler.is_a?(I18n::ExceptionHandler) # Only override the i18n gem's default exception handler.
93
+
94
+ I18n.exception_handler = ->(exception, *) {
95
+ exception = exception.to_exception if exception.is_a?(I18n::MissingTranslation)
96
+ raise exception
97
+ }
98
+ end
99
+ end
100
+
101
+ def self.include_fallbacks_module
102
+ I18n.backend.class.include(I18n::Backend::Fallbacks)
103
+ end
104
+
105
+ def self.init_fallbacks(fallbacks)
106
+ include_fallbacks_module
107
+
108
+ args = \
109
+ case fallbacks
110
+ when ActiveSupport::OrderedOptions
111
+ [*(fallbacks[:defaults] || []) << fallbacks[:map]].compact
112
+ when Hash, Array
113
+ Array.wrap(fallbacks)
114
+ else # TrueClass
115
+ [I18n.default_locale]
116
+ end
117
+
118
+ I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
119
+ end
120
+
121
+ def self.validate_fallbacks(fallbacks)
122
+ case fallbacks
123
+ when ActiveSupport::OrderedOptions
124
+ !fallbacks.empty?
125
+ when TrueClass, Array, Hash
126
+ true
127
+ else
128
+ raise "Unexpected fallback type #{fallbacks.inspect}"
129
+ end
130
+ end
131
+
132
+ def self.watched_dirs_with_extensions(paths)
133
+ paths.each_with_object({}) do |path, result|
134
+ result[path.absolute_current] = path.extensions
135
+ end
136
+ end
137
+ end
138
+ end