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
@@ -1,152 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "erb"
4
- require "active_support/core_ext/kernel/singleton_class"
5
- require "active_support/core_ext/module/redefine_method"
3
+ require "active_support/core_ext/erb/util"
6
4
  require "active_support/multibyte/unicode"
7
5
 
8
- class ERB
9
- module Util
10
- HTML_ESCAPE = { "&" => "&amp;", ">" => "&gt;", "<" => "&lt;", '"' => "&quot;", "'" => "&#39;" }
11
- JSON_ESCAPE = { "&" => '\u0026', ">" => '\u003e', "<" => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
12
- HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
13
- JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
14
-
15
- # Following XML requirements: https://www.w3.org/TR/REC-xml/#NT-Name
16
- TAG_NAME_START_REGEXP_SET = "@:A-Z_a-z\u{C0}-\u{D6}\u{D8}-\u{F6}\u{F8}-\u{2FF}\u{370}-\u{37D}\u{37F}-\u{1FFF}" \
17
- "\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \
18
- "\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}"
19
- TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}]/
20
- TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}]/
21
- TAG_NAME_REPLACEMENT_CHAR = "_"
22
-
23
- # A utility method for escaping HTML tag characters.
24
- # This method is also aliased as <tt>h</tt>.
25
- #
26
- # puts html_escape('is a > 0 & a < 10?')
27
- # # => is a &gt; 0 &amp; a &lt; 10?
28
- def html_escape(s)
29
- unwrapped_html_escape(s).html_safe
30
- end
31
-
32
- silence_redefinition_of_method :h
33
- alias h html_escape
34
-
35
- module_function :h
36
-
37
- singleton_class.silence_redefinition_of_method :html_escape
38
- module_function :html_escape
39
-
40
- # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
41
- # This method is not for public consumption! Seriously!
42
- def unwrapped_html_escape(s) # :nodoc:
43
- s = s.to_s
44
- if s.html_safe?
45
- s
46
- else
47
- CGI.escapeHTML(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
48
- end
49
- end
50
- module_function :unwrapped_html_escape
51
-
52
- # A utility method for escaping HTML without affecting existing escaped entities.
53
- #
54
- # html_escape_once('1 < 2 &amp; 3')
55
- # # => "1 &lt; 2 &amp; 3"
56
- #
57
- # html_escape_once('&lt;&lt; Accept & Checkout')
58
- # # => "&lt;&lt; Accept &amp; Checkout"
59
- def html_escape_once(s)
60
- result = ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
61
- s.html_safe? ? result.html_safe : result
62
- end
63
-
64
- module_function :html_escape_once
65
-
66
- # A utility method for escaping HTML entities in JSON strings. Specifically, the
67
- # &, > and < characters are replaced with their equivalent unicode escaped form -
68
- # \u0026, \u003e, and \u003c. The Unicode sequences \u2028 and \u2029 are also
69
- # escaped as they are treated as newline characters in some JavaScript engines.
70
- # These sequences have identical meaning as the original characters inside the
71
- # context of a JSON string, so assuming the input is a valid and well-formed
72
- # JSON value, the output will have equivalent meaning when parsed:
73
- #
74
- # json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
75
- # # => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
76
- #
77
- # json_escape(json)
78
- # # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
79
- #
80
- # JSON.parse(json) == JSON.parse(json_escape(json))
81
- # # => true
82
- #
83
- # The intended use case for this method is to escape JSON strings before including
84
- # them inside a script tag to avoid XSS vulnerability:
85
- #
86
- # <script>
87
- # var currentUser = <%= raw json_escape(current_user.to_json) %>;
88
- # </script>
89
- #
90
- # It is necessary to +raw+ the result of +json_escape+, so that quotation marks
91
- # don't get converted to <tt>&quot;</tt> entities. +json_escape+ doesn't
92
- # automatically flag the result as HTML safe, since the raw value is unsafe to
93
- # use inside HTML attributes.
94
- #
95
- # If your JSON is being used downstream for insertion into the DOM, be aware of
96
- # whether or not it is being inserted via +html()+. Most jQuery plugins do this.
97
- # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
98
- # content returned by your JSON.
99
- #
100
- # If you need to output JSON elsewhere in your HTML, you can just do something
101
- # like this, as any unsafe characters (including quotation marks) will be
102
- # automatically escaped for you:
103
- #
104
- # <div data-user-info="<%= current_user.to_json %>">...</div>
105
- #
106
- # WARNING: this helper only works with valid JSON. Using this on non-JSON values
107
- # will open up serious XSS vulnerabilities. For example, if you replace the
108
- # +current_user.to_json+ in the example above with user input instead, the browser
109
- # will happily eval() that string as JavaScript.
110
- #
111
- # The escaping performed in this method is identical to those performed in the
112
- # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
113
- # set to true. Because this transformation is idempotent, this helper can be
114
- # applied even if +ActiveSupport.escape_html_entities_in_json+ is already true.
115
- #
116
- # Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+
117
- # is enabled, or if you are unsure where your JSON string originated from, it
118
- # is recommended that you always apply this helper (other libraries, such as the
119
- # JSON gem, do not provide this kind of protection by default; also some gems
120
- # might override +to_json+ to bypass Active Support's encoder).
121
- def json_escape(s)
122
- result = s.to_s.gsub(JSON_ESCAPE_REGEXP, JSON_ESCAPE)
123
- s.html_safe? ? result.html_safe : result
124
- end
125
-
126
- module_function :json_escape
127
-
128
- # A utility method for escaping XML names of tags and names of attributes.
129
- #
130
- # xml_name_escape('1 < 2 & 3')
131
- # # => "1___2___3"
132
- #
133
- # It follows the requirements of the specification: https://www.w3.org/TR/REC-xml/#NT-Name
134
- def xml_name_escape(name)
135
- name = name.to_s
136
- return "" if name.blank?
137
-
138
- starting_char = name[0].gsub(TAG_NAME_START_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
139
-
140
- return starting_char if name.size == 1
141
-
142
- following_chars = name[1..-1].gsub(TAG_NAME_FOLLOWING_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
143
-
144
- starting_char + following_chars
145
- end
146
- module_function :xml_name_escape
147
- end
148
- end
149
-
150
6
  class Object
151
7
  def html_safe?
152
8
  false
@@ -159,11 +15,11 @@ class Numeric
159
15
  end
160
16
  end
161
17
 
162
- module ActiveSupport #:nodoc:
18
+ module ActiveSupport # :nodoc:
163
19
  class SafeBuffer < String
164
20
  UNSAFE_STRING_METHODS = %w(
165
21
  capitalize chomp chop delete delete_prefix delete_suffix
166
- downcase lstrip next reverse rstrip scrub slice squeeze strip
22
+ downcase lstrip next reverse rstrip scrub squeeze strip
167
23
  succ swapcase tr tr_s unicode_normalize upcase
168
24
  )
169
25
 
@@ -172,10 +28,10 @@ module ActiveSupport #:nodoc:
172
28
  alias_method :original_concat, :concat
173
29
  private :original_concat
174
30
 
175
- # Raised when <tt>ActiveSupport::SafeBuffer#safe_concat</tt> is called on unsafe buffers.
31
+ # Raised when ActiveSupport::SafeBuffer#safe_concat is called on unsafe buffers.
176
32
  class SafeConcatError < StandardError
177
33
  def initialize
178
- super "Could not concatenate to the buffer because it is not html safe."
34
+ super "Could not concatenate to the buffer because it is not HTML safe."
179
35
  end
180
36
  end
181
37
 
@@ -185,13 +41,26 @@ module ActiveSupport #:nodoc:
185
41
 
186
42
  return unless new_string
187
43
 
188
- new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
189
- new_safe_buffer.instance_variable_set :@html_safe, true
190
- new_safe_buffer
44
+ string_into_safe_buffer(new_string, true)
191
45
  else
192
46
  to_str[*args]
193
47
  end
194
48
  end
49
+ alias_method :slice, :[]
50
+
51
+ def slice!(*args)
52
+ new_string = super
53
+
54
+ return new_string if !html_safe? || new_string.nil?
55
+
56
+ string_into_safe_buffer(new_string, true)
57
+ end
58
+
59
+ def chr
60
+ return super unless html_safe?
61
+
62
+ string_into_safe_buffer(super, true)
63
+ end
195
64
 
196
65
  def safe_concat(value)
197
66
  raise SafeConcatError unless html_safe?
@@ -208,32 +77,42 @@ module ActiveSupport #:nodoc:
208
77
  @html_safe = other.html_safe?
209
78
  end
210
79
 
211
- def clone_empty
80
+ def clone_empty # :nodoc:
81
+ ActiveSupport.deprecator.warn <<~EOM
82
+ ActiveSupport::SafeBuffer#clone_empty is deprecated and will be removed in Rails 7.2.
83
+ EOM
212
84
  self[0, 0]
213
85
  end
214
86
 
215
87
  def concat(value)
216
- super(html_escape_interpolated_argument(value))
88
+ unless value.nil?
89
+ super(implicit_html_escape_interpolated_argument(value))
90
+ end
91
+ self
217
92
  end
218
93
  alias << concat
219
94
 
95
+ def bytesplice(*args, value)
96
+ super(*args, implicit_html_escape_interpolated_argument(value))
97
+ end
98
+
220
99
  def insert(index, value)
221
- super(index, html_escape_interpolated_argument(value))
100
+ super(index, implicit_html_escape_interpolated_argument(value))
222
101
  end
223
102
 
224
103
  def prepend(value)
225
- super(html_escape_interpolated_argument(value))
104
+ super(implicit_html_escape_interpolated_argument(value))
226
105
  end
227
106
 
228
107
  def replace(value)
229
- super(html_escape_interpolated_argument(value))
108
+ super(implicit_html_escape_interpolated_argument(value))
230
109
  end
231
110
 
232
- def []=(*args)
233
- if args.count == 3
234
- super(args[0], args[1], html_escape_interpolated_argument(args[2]))
111
+ def []=(arg1, arg2, arg3 = nil)
112
+ if arg3
113
+ super(arg1, arg2, implicit_html_escape_interpolated_argument(arg3))
235
114
  else
236
- super(args[0], html_escape_interpolated_argument(args[1]))
115
+ super(arg1, implicit_html_escape_interpolated_argument(arg2))
237
116
  end
238
117
  end
239
118
 
@@ -241,7 +120,7 @@ module ActiveSupport #:nodoc:
241
120
  dup.concat(other)
242
121
  end
243
122
 
244
- def *(*)
123
+ def *(_)
245
124
  new_string = super
246
125
  new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
247
126
  new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
@@ -251,17 +130,17 @@ module ActiveSupport #:nodoc:
251
130
  def %(args)
252
131
  case args
253
132
  when Hash
254
- escaped_args = Hash[args.map { |k, arg| [k, html_escape_interpolated_argument(arg)] }]
133
+ escaped_args = args.transform_values { |arg| explicit_html_escape_interpolated_argument(arg) }
255
134
  else
256
- escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
135
+ escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
257
136
  end
258
137
 
259
138
  self.class.new(super(escaped_args))
260
139
  end
261
140
 
262
- def html_safe?
263
- defined?(@html_safe) && @html_safe
264
- end
141
+ attr_reader :html_safe
142
+ alias_method :html_safe?, :html_safe
143
+ remove_method :html_safe
265
144
 
266
145
  def to_s
267
146
  self
@@ -291,44 +170,56 @@ module ActiveSupport #:nodoc:
291
170
  end
292
171
 
293
172
  UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
294
- if unsafe_method.respond_to?(unsafe_method)
295
- class_eval <<-EOT, __FILE__, __LINE__ + 1
296
- def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
297
- if block # if block
298
- to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
299
- set_block_back_references(block, $~) # set_block_back_references(block, $~)
300
- block.call(*params) # block.call(*params)
301
- } # }
302
- else # else
303
- to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
304
- end # end
305
- end # end
306
-
307
- def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
308
- @html_safe = false # @html_safe = false
309
- if block # if block
310
- super(*args) { |*params| # super(*args) { |*params|
311
- set_block_back_references(block, $~) # set_block_back_references(block, $~)
312
- block.call(*params) # block.call(*params)
313
- } # }
314
- else # else
315
- super # super
316
- end # end
317
- end # end
318
- EOT
319
- end
173
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
174
+ def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
175
+ if block # if block
176
+ to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
177
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
178
+ block.call(*params) # block.call(*params)
179
+ } # }
180
+ else # else
181
+ to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
182
+ end # end
183
+ end # end
184
+
185
+ def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
186
+ @html_safe = false # @html_safe = false
187
+ if block # if block
188
+ super(*args) { |*params| # super(*args) { |*params|
189
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
190
+ block.call(*params) # block.call(*params)
191
+ } # }
192
+ else # else
193
+ super # super
194
+ end # end
195
+ end # end
196
+ EOT
320
197
  end
321
198
 
322
199
  private
323
- def html_escape_interpolated_argument(arg)
200
+ def explicit_html_escape_interpolated_argument(arg)
324
201
  (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
325
202
  end
326
203
 
204
+ def implicit_html_escape_interpolated_argument(arg)
205
+ if !html_safe? || arg.html_safe?
206
+ arg
207
+ else
208
+ CGI.escapeHTML(arg.to_str)
209
+ end
210
+ end
211
+
327
212
  def set_block_back_references(block, match_data)
328
213
  block.binding.eval("proc { |m| $~ = m }").call(match_data)
329
214
  rescue ArgumentError
330
215
  # Can't create binding from C level Proc
331
216
  end
217
+
218
+ def string_into_safe_buffer(new_string, is_html_safe)
219
+ new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
220
+ new_safe_buffer.instance_variable_set :@html_safe, is_html_safe
221
+ new_safe_buffer
222
+ end
332
223
  end
333
224
  end
334
225
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class String
4
- alias_method :starts_with?, :start_with?
5
- alias_method :ends_with?, :end_with?
4
+ alias :starts_with? :start_with?
5
+ alias :ends_with? :end_with?
6
6
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Symbol
4
+ alias :starts_with? :start_with?
5
+ alias :ends_with? :end_with?
6
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/symbol/starts_ends_with"
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Thread::Backtrace::Location # :nodoc:
4
+ if defined?(ErrorHighlight) && Gem::Version.new(ErrorHighlight::VERSION) >= Gem::Version.new("0.4.0")
5
+ def spot(ex)
6
+ ErrorHighlight.spot(ex, backtrace_location: self)
7
+ end
8
+ else
9
+ def spot(ex)
10
+ end
11
+ end
12
+ end
@@ -6,6 +6,7 @@ require "active_support/time_with_zone"
6
6
  require "active_support/core_ext/time/zones"
7
7
  require "active_support/core_ext/date_and_time/calculations"
8
8
  require "active_support/core_ext/date/calculations"
9
+ require "active_support/core_ext/module/remove_method"
9
10
 
10
11
  class Time
11
12
  include DateAndTime::Calculations
@@ -41,8 +42,8 @@ class Time
41
42
 
42
43
  # Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime
43
44
  # instances can be used when called with a single argument
44
- def at_with_coercion(*args)
45
- return at_without_coercion(*args) if args.size != 1
45
+ def at_with_coercion(*args, **kwargs)
46
+ return at_without_coercion(*args, **kwargs) if args.size != 1 || !kwargs.empty?
46
47
 
47
48
  # Time.at can be called with a time or numerical value
48
49
  time_or_number = args.first
@@ -107,11 +108,26 @@ class Time
107
108
  subsec
108
109
  end
109
110
 
111
+ unless Time.method_defined?(:floor)
112
+ def floor(precision = 0)
113
+ change(nsec: 0) + subsec.floor(precision)
114
+ end
115
+ end
116
+
117
+ # Restricted Ruby version due to a bug in `Time#ceil`
118
+ # See https://bugs.ruby-lang.org/issues/17025 for more details
119
+ if RUBY_VERSION <= "2.8"
120
+ remove_possible_method :ceil
121
+ def ceil(precision = 0)
122
+ change(nsec: 0) + subsec.ceil(precision)
123
+ end
124
+ end
125
+
110
126
  # Returns a new Time where one or more of the elements have been changed according
111
127
  # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
112
128
  # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
113
- # the hour is passed, then minute, sec, usec and nsec is set to 0. If the hour
114
- # and minute is passed, then sec, usec and nsec is set to 0. The +options+ parameter
129
+ # the hour is passed, then minute, sec, usec, and nsec is set to 0. If the hour
130
+ # and minute is passed, then sec, usec, and nsec is set to 0. The +options+ parameter
115
131
  # takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
116
132
  # <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>,
117
133
  # <tt>:offset</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
@@ -143,8 +159,26 @@ class Time
143
159
  ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
144
160
  elsif utc?
145
161
  ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
162
+ elsif zone&.respond_to?(:utc_to_local)
163
+ new_time = ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
164
+
165
+ # When there are two occurrences of a nominal time due to DST ending,
166
+ # `Time.new` chooses the first chronological occurrence (the one with a
167
+ # larger UTC offset). However, for `change`, we want to choose the
168
+ # occurrence that matches this time's UTC offset.
169
+ #
170
+ # If the new time's UTC offset is larger than this time's UTC offset, the
171
+ # new time might be a first chronological occurrence. So we add the offset
172
+ # difference to fast-forward the new time, and check if the result has the
173
+ # desired UTC offset (i.e. is the second chronological occurrence).
174
+ offset_difference = new_time.utc_offset - utc_offset
175
+ if offset_difference > 0 && (new_time_2 = new_time + offset_difference).utc_offset == utc_offset
176
+ new_time_2
177
+ else
178
+ new_time
179
+ end
146
180
  elsif zone
147
- ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec)
181
+ ::Time.local(new_sec, new_min, new_hour, new_day, new_month, new_year, nil, nil, isdst, nil)
148
182
  else
149
183
  ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
150
184
  end
@@ -161,6 +195,10 @@ class Time
161
195
  # Time.new(2015, 8, 1, 14, 35, 0).advance(hours: 1) # => 2015-08-01 15:35:00 -0700
162
196
  # Time.new(2015, 8, 1, 14, 35, 0).advance(days: 1) # => 2015-08-02 14:35:00 -0700
163
197
  # Time.new(2015, 8, 1, 14, 35, 0).advance(weeks: 1) # => 2015-08-08 14:35:00 -0700
198
+ #
199
+ # Just like Date#advance, increments are applied in order of time units from
200
+ # largest to smallest. This order can affect the result around the end of a
201
+ # month.
164
202
  def advance(options)
165
203
  unless options[:weeks].nil?
166
204
  options[:weeks], partial_weeks = options[:weeks].divmod(1)
@@ -259,7 +297,7 @@ class Time
259
297
  end
260
298
  alias :at_end_of_minute :end_of_minute
261
299
 
262
- def plus_with_duration(other) #:nodoc:
300
+ def plus_with_duration(other) # :nodoc:
263
301
  if ActiveSupport::Duration === other
264
302
  other.since(self)
265
303
  else
@@ -269,7 +307,7 @@ class Time
269
307
  alias_method :plus_without_duration, :+
270
308
  alias_method :+, :plus_with_duration
271
309
 
272
- def minus_with_duration(other) #:nodoc:
310
+ def minus_with_duration(other) # :nodoc:
273
311
  if ActiveSupport::Duration === other
274
312
  other.until(self)
275
313
  else
@@ -287,7 +325,7 @@ class Time
287
325
  other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other)
288
326
  end
289
327
  alias_method :minus_without_coercion, :-
290
- alias_method :-, :minus_with_coercion
328
+ alias_method :-, :minus_with_coercion # rubocop:disable Lint/DuplicateMethods
291
329
 
292
330
  # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
293
331
  # can be chronologically compared with a Time
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "time"
3
4
  require "active_support/inflector/methods"
4
5
  require "active_support/values/time_zone"
5
6
 
6
7
  class Time
7
8
  DATE_FORMATS = {
8
9
  db: "%Y-%m-%d %H:%M:%S",
10
+ inspect: "%Y-%m-%d %H:%M:%S.%9N %z",
9
11
  number: "%Y%m%d%H%M%S",
10
12
  nsec: "%Y%m%d%H%M%S%9N",
11
13
  usec: "%Y%m%d%H%M%S%6N",
@@ -25,22 +27,22 @@ class Time
25
27
 
26
28
  # Converts to a formatted string. See DATE_FORMATS for built-in formats.
27
29
  #
28
- # This method is aliased to <tt>to_s</tt>.
30
+ # This method is aliased to <tt>to_formatted_s</tt>.
29
31
  #
30
32
  # time = Time.now # => 2007-01-18 06:10:17 -06:00
31
33
  #
34
+ # time.to_fs(:time) # => "06:10"
32
35
  # time.to_formatted_s(:time) # => "06:10"
33
- # time.to_s(:time) # => "06:10"
34
36
  #
35
- # time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
36
- # time.to_formatted_s(:number) # => "20070118061017"
37
- # time.to_formatted_s(:short) # => "18 Jan 06:10"
38
- # time.to_formatted_s(:long) # => "January 18, 2007 06:10"
39
- # time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10"
40
- # time.to_formatted_s(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
41
- # time.to_formatted_s(:iso8601) # => "2007-01-18T06:10:17-06:00"
37
+ # time.to_fs(:db) # => "2007-01-18 06:10:17"
38
+ # time.to_fs(:number) # => "20070118061017"
39
+ # time.to_fs(:short) # => "18 Jan 06:10"
40
+ # time.to_fs(:long) # => "January 18, 2007 06:10"
41
+ # time.to_fs(:long_ordinal) # => "January 18th, 2007 06:10"
42
+ # time.to_fs(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
43
+ # time.to_fs(:iso8601) # => "2007-01-18T06:10:17-06:00"
42
44
  #
43
- # == Adding your own time formats to +to_formatted_s+
45
+ # == Adding your own time formats to +to_fs+
44
46
  # You can add your own formats to the Time::DATE_FORMATS hash.
45
47
  # Use the format name as the hash key and either a strftime string
46
48
  # or Proc instance that takes a time argument as the value.
@@ -48,15 +50,16 @@ class Time
48
50
  # # config/initializers/time_formats.rb
49
51
  # Time::DATE_FORMATS[:month_and_year] = '%B %Y'
50
52
  # Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
51
- def to_formatted_s(format = :default)
53
+ def to_fs(format = :default)
52
54
  if formatter = DATE_FORMATS[format]
53
55
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
54
56
  else
55
- to_default_s
57
+ to_s
56
58
  end
57
59
  end
60
+ alias_method :to_formatted_s, :to_fs
58
61
  alias_method :to_default_s, :to_s
59
- alias_method :to_s, :to_formatted_s
62
+ deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
60
63
 
61
64
  # Returns a formatted string of the offset from UTC, or an alternative
62
65
  # string if the time zone is already UTC.
@@ -12,17 +12,17 @@ class Time
12
12
  # Returns the TimeZone for the current request, if this has been set (via Time.zone=).
13
13
  # If <tt>Time.zone</tt> has not been set for the current request, returns the TimeZone specified in <tt>config.time_zone</tt>.
14
14
  def zone
15
- Thread.current[:time_zone] || zone_default
15
+ ::ActiveSupport::IsolatedExecutionState[:time_zone] || zone_default
16
16
  end
17
17
 
18
18
  # Sets <tt>Time.zone</tt> to a TimeZone object for the current request/thread.
19
19
  #
20
20
  # This method accepts any of the following:
21
21
  #
22
- # * A Rails TimeZone object.
23
- # * An identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", <tt>-5.hours</tt>).
24
- # * A TZInfo::Timezone object.
25
- # * An identifier for a TZInfo::Timezone object (e.g., "America/New_York").
22
+ # * A \Rails TimeZone object.
23
+ # * An identifier for a \Rails TimeZone object (e.g., "Eastern Time (US & Canada)", <tt>-5.hours</tt>).
24
+ # * A +TZInfo::Timezone+ object.
25
+ # * An identifier for a +TZInfo::Timezone+ object (e.g., "America/New_York").
26
26
  #
27
27
  # Here's an example of how you might set <tt>Time.zone</tt> on a per request basis and reset it when the request is done.
28
28
  # <tt>current_user.time_zone</tt> just needs to return a string identifying the user's preferred time zone:
@@ -39,7 +39,7 @@ class Time
39
39
  # end
40
40
  # end
41
41
  def zone=(time_zone)
42
- Thread.current[:time_zone] = find_zone!(time_zone)
42
+ ::ActiveSupport::IsolatedExecutionState[:time_zone] = find_zone!(time_zone)
43
43
  end
44
44
 
45
45
  # Allows override of <tt>Time.zone</tt> locally inside supplied block;
@@ -49,13 +49,12 @@ class Time
49
49
  # around_action :set_time_zone
50
50
  #
51
51
  # private
52
- #
53
- # def set_time_zone
54
- # Time.use_zone(current_user.timezone) { yield }
55
- # end
52
+ # def set_time_zone
53
+ # Time.use_zone(current_user.timezone) { yield }
54
+ # end
56
55
  # end
57
56
  #
58
- # NOTE: This won't affect any <tt>ActiveSupport::TimeWithZone</tt>
57
+ # NOTE: This won't affect any ActiveSupport::TimeWithZone
59
58
  # objects that have already been created, e.g. any model timestamp
60
59
  # attributes that have been read before the block will remain in
61
60
  # the application's default timezone.
@@ -80,24 +79,9 @@ class Time
80
79
  # Time.find_zone! false # => false
81
80
  # Time.find_zone! "NOT-A-TIMEZONE" # => ArgumentError: Invalid Timezone: NOT-A-TIMEZONE
82
81
  def find_zone!(time_zone)
83
- if !time_zone || time_zone.is_a?(ActiveSupport::TimeZone)
84
- time_zone
85
- else
86
- # Look up the timezone based on the identifier (unless we've been
87
- # passed a TZInfo::Timezone)
88
- unless time_zone.respond_to?(:period_for_local)
89
- time_zone = ActiveSupport::TimeZone[time_zone] || TZInfo::Timezone.get(time_zone)
90
- end
82
+ return time_zone unless time_zone
91
83
 
92
- # Return if a TimeZone instance, or wrap in a TimeZone instance if a TZInfo::Timezone
93
- if time_zone.is_a?(ActiveSupport::TimeZone)
94
- time_zone
95
- else
96
- ActiveSupport::TimeZone.create(time_zone.name, nil, time_zone)
97
- end
98
- end
99
- rescue TZInfo::InvalidTimezoneIdentifier
100
- raise ArgumentError, "Invalid Timezone: #{time_zone}"
84
+ ActiveSupport::TimeZone[time_zone] || raise(ArgumentError, "Invalid Timezone: #{time_zone}")
101
85
  end
102
86
 
103
87
  # Returns a TimeZone instance matching the time zone provided.