activesupport 6.1.0 → 7.1.5.1

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 (225) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1075 -325
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +4 -2
  6. data/lib/active_support/array_inquirer.rb +2 -2
  7. data/lib/active_support/backtrace_cleaner.rb +32 -7
  8. data/lib/active_support/benchmarkable.rb +3 -2
  9. data/lib/active_support/broadcast_logger.rb +251 -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 +201 -62
  15. data/lib/active_support/cache/memory_store.rb +86 -24
  16. data/lib/active_support/cache/null_store.rb +16 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +186 -193
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +63 -71
  20. data/lib/active_support/cache.rb +487 -249
  21. data/lib/active_support/callbacks.rb +227 -105
  22. data/lib/active_support/code_generator.rb +70 -0
  23. data/lib/active_support/concern.rb +9 -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 +18 -5
  28. data/lib/active_support/configuration_file.rb +7 -2
  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/big_decimal/conversions.rb +1 -1
  34. data/lib/active_support/core_ext/class/subclasses.rb +37 -26
  35. data/lib/active_support/core_ext/date/blank.rb +1 -1
  36. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  37. data/lib/active_support/core_ext/date/conversions.rb +16 -15
  38. data/lib/active_support/core_ext/date_and_time/calculations.rb +14 -4
  39. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  40. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  41. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  42. data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
  43. data/lib/active_support/core_ext/digest/uuid.rb +30 -13
  44. data/lib/active_support/core_ext/enumerable.rb +85 -83
  45. data/lib/active_support/core_ext/erb/util.rb +196 -0
  46. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  47. data/lib/active_support/core_ext/hash/conversions.rb +1 -2
  48. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  49. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  50. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  51. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  52. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  53. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  54. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  55. data/lib/active_support/core_ext/module/attribute_accessors.rb +8 -0
  56. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +49 -22
  57. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  58. data/lib/active_support/core_ext/module/delegation.rb +81 -43
  59. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  60. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  61. data/lib/active_support/core_ext/name_error.rb +2 -8
  62. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  63. data/lib/active_support/core_ext/numeric/conversions.rb +82 -77
  64. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  65. data/lib/active_support/core_ext/object/blank.rb +2 -2
  66. data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
  67. data/lib/active_support/core_ext/object/duplicable.rb +31 -11
  68. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  69. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  70. data/lib/active_support/core_ext/object/json.rb +49 -27
  71. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  72. data/lib/active_support/core_ext/object/try.rb +20 -20
  73. data/lib/active_support/core_ext/object/with.rb +44 -0
  74. data/lib/active_support/core_ext/object/with_options.rb +25 -6
  75. data/lib/active_support/core_ext/object.rb +1 -0
  76. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  77. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  78. data/lib/active_support/core_ext/pathname.rb +4 -0
  79. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  80. data/lib/active_support/core_ext/range/conversions.rb +34 -13
  81. data/lib/active_support/core_ext/range/each.rb +1 -1
  82. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  83. data/lib/active_support/core_ext/range.rb +1 -2
  84. data/lib/active_support/core_ext/securerandom.rb +25 -13
  85. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  86. data/lib/active_support/core_ext/string/filters.rb +21 -15
  87. data/lib/active_support/core_ext/string/indent.rb +1 -1
  88. data/lib/active_support/core_ext/string/inflections.rb +17 -10
  89. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  90. data/lib/active_support/core_ext/string/output_safety.rb +85 -165
  91. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  92. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  93. data/lib/active_support/core_ext/time/calculations.rb +30 -8
  94. data/lib/active_support/core_ext/time/conversions.rb +15 -13
  95. data/lib/active_support/core_ext/time/zones.rb +12 -28
  96. data/lib/active_support/core_ext.rb +2 -1
  97. data/lib/active_support/current_attributes.rb +47 -20
  98. data/lib/active_support/deep_mergeable.rb +53 -0
  99. data/lib/active_support/dependencies/autoload.rb +17 -12
  100. data/lib/active_support/dependencies/interlock.rb +10 -18
  101. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  102. data/lib/active_support/dependencies.rb +58 -788
  103. data/lib/active_support/deprecation/behaviors.rb +66 -40
  104. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  105. data/lib/active_support/deprecation/deprecators.rb +104 -0
  106. data/lib/active_support/deprecation/disallowed.rb +6 -8
  107. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  108. data/lib/active_support/deprecation/method_wrappers.rb +9 -26
  109. data/lib/active_support/deprecation/proxy_wrappers.rb +38 -23
  110. data/lib/active_support/deprecation/reporting.rb +43 -26
  111. data/lib/active_support/deprecation.rb +32 -5
  112. data/lib/active_support/deprecator.rb +7 -0
  113. data/lib/active_support/descendants_tracker.rb +150 -72
  114. data/lib/active_support/digest.rb +5 -3
  115. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  116. data/lib/active_support/duration/iso8601_serializer.rb +9 -3
  117. data/lib/active_support/duration.rb +83 -52
  118. data/lib/active_support/encrypted_configuration.rb +72 -9
  119. data/lib/active_support/encrypted_file.rb +29 -13
  120. data/lib/active_support/environment_inquirer.rb +23 -3
  121. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  122. data/lib/active_support/error_reporter.rb +203 -0
  123. data/lib/active_support/evented_file_update_checker.rb +20 -7
  124. data/lib/active_support/execution_context/test_helper.rb +13 -0
  125. data/lib/active_support/execution_context.rb +53 -0
  126. data/lib/active_support/execution_wrapper.rb +44 -22
  127. data/lib/active_support/executor/test_helper.rb +7 -0
  128. data/lib/active_support/file_update_checker.rb +4 -2
  129. data/lib/active_support/fork_tracker.rb +28 -11
  130. data/lib/active_support/gem_version.rb +4 -4
  131. data/lib/active_support/gzip.rb +2 -0
  132. data/lib/active_support/hash_with_indifferent_access.rb +44 -19
  133. data/lib/active_support/html_safe_translation.rb +53 -0
  134. data/lib/active_support/i18n.rb +2 -1
  135. data/lib/active_support/i18n_railtie.rb +21 -14
  136. data/lib/active_support/inflector/inflections.rb +25 -7
  137. data/lib/active_support/inflector/methods.rb +50 -64
  138. data/lib/active_support/inflector/transliterate.rb +4 -2
  139. data/lib/active_support/isolated_execution_state.rb +76 -0
  140. data/lib/active_support/json/decoding.rb +2 -1
  141. data/lib/active_support/json/encoding.rb +27 -45
  142. data/lib/active_support/key_generator.rb +31 -6
  143. data/lib/active_support/lazy_load_hooks.rb +33 -7
  144. data/lib/active_support/locale/en.yml +4 -2
  145. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  146. data/lib/active_support/log_subscriber.rb +97 -35
  147. data/lib/active_support/logger.rb +9 -60
  148. data/lib/active_support/logger_thread_safe_level.rb +11 -34
  149. data/lib/active_support/message_encryptor.rb +206 -56
  150. data/lib/active_support/message_encryptors.rb +141 -0
  151. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  152. data/lib/active_support/message_pack/extensions.rb +292 -0
  153. data/lib/active_support/message_pack/serializer.rb +63 -0
  154. data/lib/active_support/message_pack.rb +50 -0
  155. data/lib/active_support/message_verifier.rb +235 -84
  156. data/lib/active_support/message_verifiers.rb +135 -0
  157. data/lib/active_support/messages/codec.rb +65 -0
  158. data/lib/active_support/messages/metadata.rb +112 -46
  159. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  160. data/lib/active_support/messages/rotator.rb +34 -32
  161. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  162. data/lib/active_support/multibyte/chars.rb +12 -11
  163. data/lib/active_support/multibyte/unicode.rb +9 -49
  164. data/lib/active_support/multibyte.rb +1 -1
  165. data/lib/active_support/notifications/fanout.rb +304 -114
  166. data/lib/active_support/notifications/instrumenter.rb +117 -35
  167. data/lib/active_support/notifications.rb +25 -25
  168. data/lib/active_support/number_helper/number_converter.rb +14 -7
  169. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  170. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  171. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -4
  172. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  173. data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
  174. data/lib/active_support/number_helper/rounding_helper.rb +2 -6
  175. data/lib/active_support/number_helper.rb +379 -319
  176. data/lib/active_support/option_merger.rb +10 -18
  177. data/lib/active_support/ordered_hash.rb +4 -4
  178. data/lib/active_support/ordered_options.rb +15 -1
  179. data/lib/active_support/parameter_filter.rb +105 -81
  180. data/lib/active_support/proxy_object.rb +2 -0
  181. data/lib/active_support/railtie.rb +83 -21
  182. data/lib/active_support/reloader.rb +13 -5
  183. data/lib/active_support/rescuable.rb +18 -16
  184. data/lib/active_support/ruby_features.rb +7 -0
  185. data/lib/active_support/secure_compare_rotator.rb +18 -11
  186. data/lib/active_support/security_utils.rb +1 -1
  187. data/lib/active_support/string_inquirer.rb +3 -3
  188. data/lib/active_support/subscriber.rb +11 -40
  189. data/lib/active_support/syntax_error_proxy.rb +60 -0
  190. data/lib/active_support/tagged_logging.rb +65 -25
  191. data/lib/active_support/test_case.rb +166 -27
  192. data/lib/active_support/testing/assertions.rb +61 -15
  193. data/lib/active_support/testing/autorun.rb +0 -2
  194. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  195. data/lib/active_support/testing/deprecation.rb +53 -2
  196. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  197. data/lib/active_support/testing/isolation.rb +30 -29
  198. data/lib/active_support/testing/method_call_assertions.rb +24 -11
  199. data/lib/active_support/testing/parallelization/server.rb +4 -0
  200. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  201. data/lib/active_support/testing/parallelization.rb +4 -0
  202. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  203. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  204. data/lib/active_support/testing/stream.rb +4 -6
  205. data/lib/active_support/testing/strict_warnings.rb +39 -0
  206. data/lib/active_support/testing/tagged_logging.rb +1 -1
  207. data/lib/active_support/testing/time_helpers.rb +49 -16
  208. data/lib/active_support/time_with_zone.rb +39 -28
  209. data/lib/active_support/values/time_zone.rb +50 -18
  210. data/lib/active_support/version.rb +1 -1
  211. data/lib/active_support/xml_mini/jdom.rb +4 -11
  212. data/lib/active_support/xml_mini/libxml.rb +5 -5
  213. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  214. data/lib/active_support/xml_mini/nokogiri.rb +5 -5
  215. data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
  216. data/lib/active_support/xml_mini/rexml.rb +2 -2
  217. data/lib/active_support/xml_mini.rb +7 -6
  218. data/lib/active_support.rb +28 -1
  219. metadata +150 -18
  220. data/lib/active_support/core_ext/marshal.rb +0 -26
  221. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -28
  222. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  223. data/lib/active_support/core_ext/uri.rb +0 -29
  224. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
  225. data/lib/active_support/per_thread_registry.rb +0 -60
@@ -4,7 +4,7 @@ require "active_support/string_inquirer"
4
4
  require "active_support/environment_inquirer"
5
5
 
6
6
  class String
7
- # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class,
7
+ # Wraps the current string in the ActiveSupport::StringInquirer class,
8
8
  # which gives you a prettier way to test for equality.
9
9
  #
10
10
  # env = 'production'.inquiry
@@ -1,123 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "erb"
4
- require "active_support/core_ext/module/redefine_method"
3
+ require "active_support/core_ext/erb/util"
5
4
  require "active_support/multibyte/unicode"
6
5
 
7
- class ERB
8
- module Util
9
- HTML_ESCAPE = { "&" => "&amp;", ">" => "&gt;", "<" => "&lt;", '"' => "&quot;", "'" => "&#39;" }
10
- JSON_ESCAPE = { "&" => '\u0026', ">" => '\u003e', "<" => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
11
- HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
12
- JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
13
-
14
- # A utility method for escaping HTML tag characters.
15
- # This method is also aliased as <tt>h</tt>.
16
- #
17
- # puts html_escape('is a > 0 & a < 10?')
18
- # # => is a &gt; 0 &amp; a &lt; 10?
19
- def html_escape(s)
20
- unwrapped_html_escape(s).html_safe
21
- end
22
-
23
- silence_redefinition_of_method :h
24
- alias h html_escape
25
-
26
- module_function :h
27
-
28
- singleton_class.silence_redefinition_of_method :html_escape
29
- module_function :html_escape
30
-
31
- # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
32
- # This method is not for public consumption! Seriously!
33
- def unwrapped_html_escape(s) # :nodoc:
34
- s = s.to_s
35
- if s.html_safe?
36
- s
37
- else
38
- CGI.escapeHTML(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
39
- end
40
- end
41
- module_function :unwrapped_html_escape
42
-
43
- # A utility method for escaping HTML without affecting existing escaped entities.
44
- #
45
- # html_escape_once('1 < 2 &amp; 3')
46
- # # => "1 &lt; 2 &amp; 3"
47
- #
48
- # html_escape_once('&lt;&lt; Accept & Checkout')
49
- # # => "&lt;&lt; Accept &amp; Checkout"
50
- def html_escape_once(s)
51
- result = ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
52
- s.html_safe? ? result.html_safe : result
53
- end
54
-
55
- module_function :html_escape_once
56
-
57
- # A utility method for escaping HTML entities in JSON strings. Specifically, the
58
- # &, > and < characters are replaced with their equivalent unicode escaped form -
59
- # \u0026, \u003e, and \u003c. The Unicode sequences \u2028 and \u2029 are also
60
- # escaped as they are treated as newline characters in some JavaScript engines.
61
- # These sequences have identical meaning as the original characters inside the
62
- # context of a JSON string, so assuming the input is a valid and well-formed
63
- # JSON value, the output will have equivalent meaning when parsed:
64
- #
65
- # json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
66
- # # => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
67
- #
68
- # json_escape(json)
69
- # # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
70
- #
71
- # JSON.parse(json) == JSON.parse(json_escape(json))
72
- # # => true
73
- #
74
- # The intended use case for this method is to escape JSON strings before including
75
- # them inside a script tag to avoid XSS vulnerability:
76
- #
77
- # <script>
78
- # var currentUser = <%= raw json_escape(current_user.to_json) %>;
79
- # </script>
80
- #
81
- # It is necessary to +raw+ the result of +json_escape+, so that quotation marks
82
- # don't get converted to <tt>&quot;</tt> entities. +json_escape+ doesn't
83
- # automatically flag the result as HTML safe, since the raw value is unsafe to
84
- # use inside HTML attributes.
85
- #
86
- # If your JSON is being used downstream for insertion into the DOM, be aware of
87
- # whether or not it is being inserted via +html()+. Most jQuery plugins do this.
88
- # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
89
- # content returned by your JSON.
90
- #
91
- # If you need to output JSON elsewhere in your HTML, you can just do something
92
- # like this, as any unsafe characters (including quotation marks) will be
93
- # automatically escaped for you:
94
- #
95
- # <div data-user-info="<%= current_user.to_json %>">...</div>
96
- #
97
- # WARNING: this helper only works with valid JSON. Using this on non-JSON values
98
- # will open up serious XSS vulnerabilities. For example, if you replace the
99
- # +current_user.to_json+ in the example above with user input instead, the browser
100
- # will happily eval() that string as JavaScript.
101
- #
102
- # The escaping performed in this method is identical to those performed in the
103
- # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
104
- # set to true. Because this transformation is idempotent, this helper can be
105
- # applied even if +ActiveSupport.escape_html_entities_in_json+ is already true.
106
- #
107
- # Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+
108
- # is enabled, or if you are unsure where your JSON string originated from, it
109
- # is recommended that you always apply this helper (other libraries, such as the
110
- # JSON gem, do not provide this kind of protection by default; also some gems
111
- # might override +to_json+ to bypass Active Support's encoder).
112
- def json_escape(s)
113
- result = s.to_s.gsub(JSON_ESCAPE_REGEXP, JSON_ESCAPE)
114
- s.html_safe? ? result.html_safe : result
115
- end
116
-
117
- module_function :json_escape
118
- end
119
- end
120
-
121
6
  class Object
122
7
  def html_safe?
123
8
  false
@@ -130,11 +15,11 @@ class Numeric
130
15
  end
131
16
  end
132
17
 
133
- module ActiveSupport #:nodoc:
18
+ module ActiveSupport # :nodoc:
134
19
  class SafeBuffer < String
135
20
  UNSAFE_STRING_METHODS = %w(
136
21
  capitalize chomp chop delete delete_prefix delete_suffix
137
- downcase lstrip next reverse rstrip scrub slice squeeze strip
22
+ downcase lstrip next reverse rstrip scrub squeeze strip
138
23
  succ swapcase tr tr_s unicode_normalize upcase
139
24
  )
140
25
 
@@ -143,10 +28,10 @@ module ActiveSupport #:nodoc:
143
28
  alias_method :original_concat, :concat
144
29
  private :original_concat
145
30
 
146
- # 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.
147
32
  class SafeConcatError < StandardError
148
33
  def initialize
149
- 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."
150
35
  end
151
36
  end
152
37
 
@@ -156,13 +41,26 @@ module ActiveSupport #:nodoc:
156
41
 
157
42
  return unless new_string
158
43
 
159
- new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
160
- new_safe_buffer.instance_variable_set :@html_safe, true
161
- new_safe_buffer
44
+ string_into_safe_buffer(new_string, true)
162
45
  else
163
46
  to_str[*args]
164
47
  end
165
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
166
64
 
167
65
  def safe_concat(value)
168
66
  raise SafeConcatError unless html_safe?
@@ -179,32 +77,42 @@ module ActiveSupport #:nodoc:
179
77
  @html_safe = other.html_safe?
180
78
  end
181
79
 
182
- 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
183
84
  self[0, 0]
184
85
  end
185
86
 
186
87
  def concat(value)
187
- super(html_escape_interpolated_argument(value))
88
+ unless value.nil?
89
+ super(implicit_html_escape_interpolated_argument(value))
90
+ end
91
+ self
188
92
  end
189
93
  alias << concat
190
94
 
95
+ def bytesplice(*args, value)
96
+ super(*args, implicit_html_escape_interpolated_argument(value))
97
+ end
98
+
191
99
  def insert(index, value)
192
- super(index, html_escape_interpolated_argument(value))
100
+ super(index, implicit_html_escape_interpolated_argument(value))
193
101
  end
194
102
 
195
103
  def prepend(value)
196
- super(html_escape_interpolated_argument(value))
104
+ super(implicit_html_escape_interpolated_argument(value))
197
105
  end
198
106
 
199
107
  def replace(value)
200
- super(html_escape_interpolated_argument(value))
108
+ super(implicit_html_escape_interpolated_argument(value))
201
109
  end
202
110
 
203
- def []=(*args)
204
- if args.length == 3
205
- 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))
206
114
  else
207
- super(args[0], html_escape_interpolated_argument(args[1]))
115
+ super(arg1, implicit_html_escape_interpolated_argument(arg2))
208
116
  end
209
117
  end
210
118
 
@@ -212,7 +120,7 @@ module ActiveSupport #:nodoc:
212
120
  dup.concat(other)
213
121
  end
214
122
 
215
- def *(*)
123
+ def *(_)
216
124
  new_string = super
217
125
  new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
218
126
  new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
@@ -222,17 +130,17 @@ module ActiveSupport #:nodoc:
222
130
  def %(args)
223
131
  case args
224
132
  when Hash
225
- escaped_args = args.transform_values { |arg| html_escape_interpolated_argument(arg) }
133
+ escaped_args = args.transform_values { |arg| explicit_html_escape_interpolated_argument(arg) }
226
134
  else
227
- escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
135
+ escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
228
136
  end
229
137
 
230
138
  self.class.new(super(escaped_args))
231
139
  end
232
140
 
233
- def html_safe?
234
- defined?(@html_safe) && @html_safe
235
- end
141
+ attr_reader :html_safe
142
+ alias_method :html_safe?, :html_safe
143
+ remove_method :html_safe
236
144
 
237
145
  def to_s
238
146
  self
@@ -262,44 +170,56 @@ module ActiveSupport #:nodoc:
262
170
  end
263
171
 
264
172
  UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
265
- if unsafe_method.respond_to?(unsafe_method)
266
- class_eval <<-EOT, __FILE__, __LINE__ + 1
267
- def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
268
- if block # if block
269
- to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
270
- set_block_back_references(block, $~) # set_block_back_references(block, $~)
271
- block.call(*params) # block.call(*params)
272
- } # }
273
- else # else
274
- to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
275
- end # end
276
- end # end
277
-
278
- def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
279
- @html_safe = false # @html_safe = false
280
- if block # if block
281
- super(*args) { |*params| # super(*args) { |*params|
282
- set_block_back_references(block, $~) # set_block_back_references(block, $~)
283
- block.call(*params) # block.call(*params)
284
- } # }
285
- else # else
286
- super # super
287
- end # end
288
- end # end
289
- EOT
290
- 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
291
197
  end
292
198
 
293
199
  private
294
- def html_escape_interpolated_argument(arg)
200
+ def explicit_html_escape_interpolated_argument(arg)
295
201
  (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
296
202
  end
297
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
+
298
212
  def set_block_back_references(block, match_data)
299
213
  block.binding.eval("proc { |m| $~ = m }").call(match_data)
300
214
  rescue ArgumentError
301
215
  # Can't create binding from C level Proc
302
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
303
223
  end
304
224
  end
305
225
 
@@ -1,14 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Symbol
4
- def start_with?(*prefixes)
5
- to_s.start_with?(*prefixes)
6
- end unless method_defined?(:start_with?)
7
-
8
- def end_with?(*suffixes)
9
- to_s.end_with?(*suffixes)
10
- end unless method_defined?(:end_with?)
11
-
12
4
  alias :starts_with? :start_with?
13
5
  alias :ends_with? :end_with?
14
6
  end
@@ -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
@@ -42,8 +42,8 @@ class Time
42
42
 
43
43
  # Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime
44
44
  # instances can be used when called with a single argument
45
- def at_with_coercion(*args)
46
- 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?
47
47
 
48
48
  # Time.at can be called with a time or numerical value
49
49
  time_or_number = args.first
@@ -126,8 +126,8 @@ class Time
126
126
  # Returns a new Time where one or more of the elements have been changed according
127
127
  # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
128
128
  # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
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
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
131
131
  # takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
132
132
  # <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>,
133
133
  # <tt>:offset</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
@@ -159,8 +159,26 @@ class Time
159
159
  ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
160
160
  elsif utc?
161
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
162
180
  elsif zone
163
- ::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)
164
182
  else
165
183
  ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
166
184
  end
@@ -177,6 +195,10 @@ class Time
177
195
  # Time.new(2015, 8, 1, 14, 35, 0).advance(hours: 1) # => 2015-08-01 15:35:00 -0700
178
196
  # Time.new(2015, 8, 1, 14, 35, 0).advance(days: 1) # => 2015-08-02 14:35:00 -0700
179
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.
180
202
  def advance(options)
181
203
  unless options[:weeks].nil?
182
204
  options[:weeks], partial_weeks = options[:weeks].divmod(1)
@@ -275,7 +297,7 @@ class Time
275
297
  end
276
298
  alias :at_end_of_minute :end_of_minute
277
299
 
278
- def plus_with_duration(other) #:nodoc:
300
+ def plus_with_duration(other) # :nodoc:
279
301
  if ActiveSupport::Duration === other
280
302
  other.since(self)
281
303
  else
@@ -285,7 +307,7 @@ class Time
285
307
  alias_method :plus_without_duration, :+
286
308
  alias_method :+, :plus_with_duration
287
309
 
288
- def minus_with_duration(other) #:nodoc:
310
+ def minus_with_duration(other) # :nodoc:
289
311
  if ActiveSupport::Duration === other
290
312
  other.until(self)
291
313
  else
@@ -303,7 +325,7 @@ class Time
303
325
  other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other)
304
326
  end
305
327
  alias_method :minus_without_coercion, :-
306
- alias_method :-, :minus_with_coercion
328
+ alias_method :-, :minus_with_coercion # rubocop:disable Lint/DuplicateMethods
307
329
 
308
330
  # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
309
331
  # can be chronologically compared with a Time
@@ -1,5 +1,6 @@
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
 
@@ -26,22 +27,22 @@ class Time
26
27
 
27
28
  # Converts to a formatted string. See DATE_FORMATS for built-in formats.
28
29
  #
29
- # This method is aliased to <tt>to_s</tt>.
30
+ # This method is aliased to <tt>to_formatted_s</tt>.
30
31
  #
31
32
  # time = Time.now # => 2007-01-18 06:10:17 -06:00
32
33
  #
34
+ # time.to_fs(:time) # => "06:10"
33
35
  # time.to_formatted_s(:time) # => "06:10"
34
- # time.to_s(:time) # => "06:10"
35
36
  #
36
- # time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
37
- # time.to_formatted_s(:number) # => "20070118061017"
38
- # time.to_formatted_s(:short) # => "18 Jan 06:10"
39
- # time.to_formatted_s(:long) # => "January 18, 2007 06:10"
40
- # time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10"
41
- # time.to_formatted_s(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
42
- # 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"
43
44
  #
44
- # == Adding your own time formats to +to_formatted_s+
45
+ # == Adding your own time formats to +to_fs+
45
46
  # You can add your own formats to the Time::DATE_FORMATS hash.
46
47
  # Use the format name as the hash key and either a strftime string
47
48
  # or Proc instance that takes a time argument as the value.
@@ -49,15 +50,16 @@ class Time
49
50
  # # config/initializers/time_formats.rb
50
51
  # Time::DATE_FORMATS[:month_and_year] = '%B %Y'
51
52
  # Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
52
- def to_formatted_s(format = :default)
53
+ def to_fs(format = :default)
53
54
  if formatter = DATE_FORMATS[format]
54
55
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
55
56
  else
56
- to_default_s
57
+ to_s
57
58
  end
58
59
  end
60
+ alias_method :to_formatted_s, :to_fs
59
61
  alias_method :to_default_s, :to_s
60
- alias_method :to_s, :to_formatted_s
62
+ deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
61
63
 
62
64
  # Returns a formatted string of the offset from UTC, or an alternative
63
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.
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Dir.glob(File.expand_path("core_ext/*.rb", __dir__)).each do |path|
3
+ Dir.glob(File.expand_path("core_ext/*.rb", __dir__)).sort.each do |path|
4
+ next if path.end_with?("core_ext/uri.rb")
4
5
  require path
5
6
  end