activesupport 5.1.7 → 7.0.4.1

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

Potentially problematic release.


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

Files changed (279) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +259 -585
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -5
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +2 -0
  7. data/lib/active_support/array_inquirer.rb +4 -2
  8. data/lib/active_support/backtrace_cleaner.rb +33 -5
  9. data/lib/active_support/benchmarkable.rb +5 -3
  10. data/lib/active_support/builder.rb +2 -0
  11. data/lib/active_support/cache/file_store.rb +50 -43
  12. data/lib/active_support/cache/mem_cache_store.rb +194 -67
  13. data/lib/active_support/cache/memory_store.rb +70 -34
  14. data/lib/active_support/cache/null_store.rb +18 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +474 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +73 -50
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  18. data/lib/active_support/cache.rb +556 -220
  19. data/lib/active_support/callbacks.rb +264 -159
  20. data/lib/active_support/code_generator.rb +65 -0
  21. data/lib/active_support/concern.rb +81 -8
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +16 -0
  23. data/lib/active_support/concurrency/share_lock.rb +4 -3
  24. data/lib/active_support/configurable.rb +17 -16
  25. data/lib/active_support/configuration_file.rb +51 -0
  26. data/lib/active_support/core_ext/array/access.rb +18 -8
  27. data/lib/active_support/core_ext/array/conversions.rb +20 -17
  28. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +8 -6
  32. data/lib/active_support/core_ext/array/inquiry.rb +4 -2
  33. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  34. data/lib/active_support/core_ext/array.rb +4 -1
  35. data/lib/active_support/core_ext/benchmark.rb +4 -2
  36. data/lib/active_support/core_ext/big_decimal/conversions.rb +3 -1
  37. data/lib/active_support/core_ext/big_decimal.rb +2 -0
  38. data/lib/active_support/core_ext/class/attribute.rb +50 -47
  39. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
  40. data/lib/active_support/core_ext/class/subclasses.rb +10 -24
  41. data/lib/active_support/core_ext/class.rb +2 -0
  42. data/lib/active_support/core_ext/date/acts_like.rb +2 -0
  43. data/lib/active_support/core_ext/date/blank.rb +3 -1
  44. data/lib/active_support/core_ext/date/calculations.rb +17 -14
  45. data/lib/active_support/core_ext/date/conversions.rb +24 -22
  46. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  47. data/lib/active_support/core_ext/date/zones.rb +2 -0
  48. data/lib/active_support/core_ext/date.rb +3 -0
  49. data/lib/active_support/core_ext/date_and_time/calculations.rb +65 -41
  50. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
  51. data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +3 -1
  54. data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
  56. data/lib/active_support/core_ext/date_time/conversions.rb +15 -14
  57. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  58. data/lib/active_support/core_ext/date_time.rb +3 -0
  59. data/lib/active_support/core_ext/digest/uuid.rb +42 -14
  60. data/lib/active_support/core_ext/digest.rb +3 -0
  61. data/lib/active_support/core_ext/enumerable.rb +244 -72
  62. data/lib/active_support/core_ext/file/atomic.rb +6 -2
  63. data/lib/active_support/core_ext/file.rb +2 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +7 -6
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +4 -2
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
  69. data/lib/active_support/core_ext/hash/keys.rb +4 -31
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  71. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  72. data/lib/active_support/core_ext/hash.rb +3 -2
  73. data/lib/active_support/core_ext/integer/inflections.rb +2 -0
  74. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  75. data/lib/active_support/core_ext/integer/time.rb +7 -14
  76. data/lib/active_support/core_ext/integer.rb +2 -0
  77. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  78. data/lib/active_support/core_ext/kernel/reporting.rb +6 -4
  79. data/lib/active_support/core_ext/kernel/singleton_class.rb +3 -1
  80. data/lib/active_support/core_ext/kernel.rb +2 -1
  81. data/lib/active_support/core_ext/load_error.rb +3 -8
  82. data/lib/active_support/core_ext/module/aliasing.rb +2 -0
  83. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  84. data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
  85. data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -56
  86. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +36 -27
  87. data/lib/active_support/core_ext/module/concerning.rb +15 -10
  88. data/lib/active_support/core_ext/module/delegation.rb +97 -58
  89. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  90. data/lib/active_support/core_ext/module/introspection.rb +18 -15
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  93. data/lib/active_support/core_ext/module.rb +3 -1
  94. data/lib/active_support/core_ext/name_error.rb +30 -2
  95. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +134 -129
  97. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +7 -15
  99. data/lib/active_support/core_ext/numeric.rb +3 -1
  100. data/lib/active_support/core_ext/object/acts_like.rb +41 -6
  101. data/lib/active_support/core_ext/object/blank.rb +15 -5
  102. data/lib/active_support/core_ext/object/conversions.rb +2 -0
  103. data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
  104. data/lib/active_support/core_ext/object/duplicable.rb +16 -110
  105. data/lib/active_support/core_ext/object/inclusion.rb +2 -0
  106. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  107. data/lib/active_support/core_ext/object/json.rb +51 -26
  108. data/lib/active_support/core_ext/object/to_param.rb +2 -0
  109. data/lib/active_support/core_ext/object/to_query.rb +4 -2
  110. data/lib/active_support/core_ext/object/try.rb +26 -14
  111. data/lib/active_support/core_ext/object/with_options.rb +24 -3
  112. data/lib/active_support/core_ext/object.rb +2 -0
  113. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  114. data/lib/active_support/core_ext/pathname.rb +3 -0
  115. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  116. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  117. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  118. data/lib/active_support/core_ext/range/each.rb +6 -3
  119. data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
  120. data/lib/active_support/core_ext/range/overlaps.rb +3 -1
  121. data/lib/active_support/core_ext/range.rb +4 -1
  122. data/lib/active_support/core_ext/regexp.rb +10 -5
  123. data/lib/active_support/core_ext/securerandom.rb +25 -3
  124. data/lib/active_support/core_ext/string/access.rb +7 -16
  125. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  126. data/lib/active_support/core_ext/string/conversions.rb +5 -2
  127. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  128. data/lib/active_support/core_ext/string/filters.rb +44 -1
  129. data/lib/active_support/core_ext/string/indent.rb +2 -0
  130. data/lib/active_support/core_ext/string/inflections.rb +69 -16
  131. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  132. data/lib/active_support/core_ext/string/multibyte.rb +9 -4
  133. data/lib/active_support/core_ext/string/output_safety.rb +135 -27
  134. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  135. data/lib/active_support/core_ext/string/strip.rb +5 -1
  136. data/lib/active_support/core_ext/string/zones.rb +2 -0
  137. data/lib/active_support/core_ext/string.rb +2 -0
  138. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  139. data/lib/active_support/core_ext/symbol.rb +3 -0
  140. data/lib/active_support/core_ext/time/acts_like.rb +2 -0
  141. data/lib/active_support/core_ext/time/calculations.rb +81 -24
  142. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  143. data/lib/active_support/core_ext/time/conversions.rb +17 -12
  144. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  145. data/lib/active_support/core_ext/time/zones.rb +12 -25
  146. data/lib/active_support/core_ext/time.rb +3 -0
  147. data/lib/active_support/core_ext/uri.rb +4 -23
  148. data/lib/active_support/core_ext.rb +4 -1
  149. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  150. data/lib/active_support/current_attributes.rb +226 -0
  151. data/lib/active_support/dependencies/autoload.rb +2 -0
  152. data/lib/active_support/dependencies/interlock.rb +12 -18
  153. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  154. data/lib/active_support/dependencies.rb +59 -715
  155. data/lib/active_support/deprecation/behaviors.rb +48 -13
  156. data/lib/active_support/deprecation/constant_accessor.rb +4 -2
  157. data/lib/active_support/deprecation/disallowed.rb +56 -0
  158. data/lib/active_support/deprecation/instance_delegator.rb +2 -1
  159. data/lib/active_support/deprecation/method_wrappers.rb +29 -21
  160. data/lib/active_support/deprecation/proxy_wrappers.rb +34 -8
  161. data/lib/active_support/deprecation/reporting.rb +54 -9
  162. data/lib/active_support/deprecation.rb +10 -3
  163. data/lib/active_support/descendants_tracker.rb +192 -34
  164. data/lib/active_support/digest.rb +22 -0
  165. data/lib/active_support/duration/iso8601_parser.rb +9 -9
  166. data/lib/active_support/duration/iso8601_serializer.rb +29 -15
  167. data/lib/active_support/duration.rb +158 -72
  168. data/lib/active_support/encrypted_configuration.rb +56 -0
  169. data/lib/active_support/encrypted_file.rb +129 -0
  170. data/lib/active_support/environment_inquirer.rb +20 -0
  171. data/lib/active_support/error_reporter.rb +117 -0
  172. data/lib/active_support/evented_file_update_checker.rb +87 -122
  173. data/lib/active_support/execution_context/test_helper.rb +13 -0
  174. data/lib/active_support/execution_context.rb +53 -0
  175. data/lib/active_support/execution_wrapper.rb +46 -21
  176. data/lib/active_support/executor/test_helper.rb +7 -0
  177. data/lib/active_support/executor.rb +2 -0
  178. data/lib/active_support/file_update_checker.rb +2 -1
  179. data/lib/active_support/fork_tracker.rb +71 -0
  180. data/lib/active_support/gem_version.rb +7 -5
  181. data/lib/active_support/gzip.rb +2 -0
  182. data/lib/active_support/hash_with_indifferent_access.rb +126 -42
  183. data/lib/active_support/html_safe_translation.rb +43 -0
  184. data/lib/active_support/i18n.rb +5 -1
  185. data/lib/active_support/i18n_railtie.rb +19 -14
  186. data/lib/active_support/inflections.rb +2 -0
  187. data/lib/active_support/inflector/inflections.rb +41 -14
  188. data/lib/active_support/inflector/methods.rb +73 -87
  189. data/lib/active_support/inflector/transliterate.rb +56 -18
  190. data/lib/active_support/inflector.rb +2 -0
  191. data/lib/active_support/isolated_execution_state.rb +72 -0
  192. data/lib/active_support/json/decoding.rb +27 -26
  193. data/lib/active_support/json/encoding.rb +16 -6
  194. data/lib/active_support/json.rb +2 -0
  195. data/lib/active_support/key_generator.rb +25 -38
  196. data/lib/active_support/lazy_load_hooks.rb +35 -6
  197. data/lib/active_support/locale/en.rb +33 -0
  198. data/lib/active_support/locale/en.yml +8 -4
  199. data/lib/active_support/log_subscriber/test_helper.rb +4 -2
  200. data/lib/active_support/log_subscriber.rb +54 -13
  201. data/lib/active_support/logger.rb +4 -17
  202. data/lib/active_support/logger_silence.rb +13 -20
  203. data/lib/active_support/logger_thread_safe_level.rb +48 -10
  204. data/lib/active_support/message_encryptor.rb +111 -37
  205. data/lib/active_support/message_verifier.rb +124 -21
  206. data/lib/active_support/messages/metadata.rb +80 -0
  207. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  208. data/lib/active_support/messages/rotator.rb +57 -0
  209. data/lib/active_support/multibyte/chars.rb +19 -76
  210. data/lib/active_support/multibyte/unicode.rb +9 -331
  211. data/lib/active_support/multibyte.rb +3 -1
  212. data/lib/active_support/notifications/fanout.rb +165 -37
  213. data/lib/active_support/notifications/instrumenter.rb +92 -11
  214. data/lib/active_support/notifications.rb +96 -30
  215. data/lib/active_support/number_helper/number_converter.rb +8 -9
  216. data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -12
  217. data/lib/active_support/number_helper/number_to_delimited_converter.rb +6 -3
  218. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -3
  219. data/lib/active_support/number_helper/number_to_human_size_converter.rb +7 -4
  220. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  221. data/lib/active_support/number_helper/number_to_phone_converter.rb +6 -3
  222. data/lib/active_support/number_helper/number_to_rounded_converter.rb +14 -27
  223. data/lib/active_support/number_helper/rounding_helper.rb +16 -34
  224. data/lib/active_support/number_helper.rb +38 -12
  225. data/lib/active_support/option_merger.rb +19 -6
  226. data/lib/active_support/ordered_hash.rb +4 -2
  227. data/lib/active_support/ordered_options.rb +18 -6
  228. data/lib/active_support/parameter_filter.rb +138 -0
  229. data/lib/active_support/per_thread_registry.rb +8 -1
  230. data/lib/active_support/proxy_object.rb +2 -0
  231. data/lib/active_support/rails.rb +3 -10
  232. data/lib/active_support/railtie.rb +112 -11
  233. data/lib/active_support/reloader.rb +12 -11
  234. data/lib/active_support/rescuable.rb +19 -18
  235. data/lib/active_support/ruby_features.rb +7 -0
  236. data/lib/active_support/secure_compare_rotator.rb +51 -0
  237. data/lib/active_support/security_utils.rb +26 -15
  238. data/lib/active_support/string_inquirer.rb +4 -3
  239. data/lib/active_support/subscriber.rb +81 -42
  240. data/lib/active_support/tagged_logging.rb +45 -9
  241. data/lib/active_support/test_case.rb +86 -2
  242. data/lib/active_support/testing/assertions.rb +89 -21
  243. data/lib/active_support/testing/autorun.rb +2 -0
  244. data/lib/active_support/testing/constant_lookup.rb +2 -0
  245. data/lib/active_support/testing/declarative.rb +2 -0
  246. data/lib/active_support/testing/deprecation.rb +54 -2
  247. data/lib/active_support/testing/file_fixtures.rb +4 -0
  248. data/lib/active_support/testing/isolation.rb +6 -4
  249. data/lib/active_support/testing/method_call_assertions.rb +34 -5
  250. data/lib/active_support/testing/parallelization/server.rb +82 -0
  251. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  252. data/lib/active_support/testing/parallelization.rb +55 -0
  253. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  254. data/lib/active_support/testing/setup_and_teardown.rb +12 -7
  255. data/lib/active_support/testing/stream.rb +6 -7
  256. data/lib/active_support/testing/tagged_logging.rb +3 -1
  257. data/lib/active_support/testing/time_helpers.rb +91 -15
  258. data/lib/active_support/time.rb +2 -0
  259. data/lib/active_support/time_with_zone.rb +168 -56
  260. data/lib/active_support/values/time_zone.rb +85 -37
  261. data/lib/active_support/version.rb +3 -1
  262. data/lib/active_support/xml_mini/jdom.rb +6 -5
  263. data/lib/active_support/xml_mini/libxml.rb +9 -7
  264. data/lib/active_support/xml_mini/libxmlsax.rb +7 -5
  265. data/lib/active_support/xml_mini/nokogiri.rb +8 -6
  266. data/lib/active_support/xml_mini/nokogirisax.rb +6 -4
  267. data/lib/active_support/xml_mini/rexml.rb +13 -4
  268. data/lib/active_support/xml_mini.rb +10 -15
  269. data/lib/active_support.rb +30 -9
  270. metadata +76 -35
  271. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  272. data/lib/active_support/core_ext/hash/compact.rb +0 -27
  273. data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
  274. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  275. data/lib/active_support/core_ext/marshal.rb +0 -22
  276. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  277. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  278. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  279. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "erb"
2
- require "active_support/core_ext/kernel/singleton_class"
4
+ require "active_support/core_ext/module/redefine_method"
3
5
  require "active_support/multibyte/unicode"
4
6
 
5
7
  class ERB
@@ -9,25 +11,29 @@ class ERB
9
11
  HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
10
12
  JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
11
13
 
14
+ # Following XML requirements: https://www.w3.org/TR/REC-xml/#NT-Name
15
+ 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}" \
16
+ "\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \
17
+ "\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}"
18
+ TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}]/
19
+ TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}]/
20
+ TAG_NAME_REPLACEMENT_CHAR = "_"
21
+
12
22
  # A utility method for escaping HTML tag characters.
13
23
  # This method is also aliased as <tt>h</tt>.
14
24
  #
15
- # In your ERB templates, use this method to escape any unsafe content. For example:
16
- # <%= h @person.name %>
17
- #
18
25
  # puts html_escape('is a > 0 & a < 10?')
19
26
  # # => is a &gt; 0 &amp; a &lt; 10?
20
27
  def html_escape(s)
21
28
  unwrapped_html_escape(s).html_safe
22
29
  end
23
30
 
24
- # Aliasing twice issues a warning "discarding old...". Remove first to avoid it.
25
- remove_method(:h)
31
+ silence_redefinition_of_method :h
26
32
  alias h html_escape
27
33
 
28
34
  module_function :h
29
35
 
30
- singleton_class.send(:remove_method, :html_escape)
36
+ singleton_class.silence_redefinition_of_method :html_escape
31
37
  module_function :html_escape
32
38
 
33
39
  # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
@@ -86,7 +92,7 @@ class ERB
86
92
  # use inside HTML attributes.
87
93
  #
88
94
  # If your JSON is being used downstream for insertion into the DOM, be aware of
89
- # whether or not it is being inserted via +html()+. Most jQuery plugins do this.
95
+ # whether or not it is being inserted via <tt>html()</tt>. Most jQuery plugins do this.
90
96
  # If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
91
97
  # content returned by your JSON.
92
98
  #
@@ -99,7 +105,7 @@ class ERB
99
105
  # WARNING: this helper only works with valid JSON. Using this on non-JSON values
100
106
  # will open up serious XSS vulnerabilities. For example, if you replace the
101
107
  # +current_user.to_json+ in the example above with user input instead, the browser
102
- # will happily eval() that string as JavaScript.
108
+ # will happily <tt>eval()</tt> that string as JavaScript.
103
109
  #
104
110
  # The escaping performed in this method is identical to those performed in the
105
111
  # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
@@ -117,6 +123,26 @@ class ERB
117
123
  end
118
124
 
119
125
  module_function :json_escape
126
+
127
+ # A utility method for escaping XML names of tags and names of attributes.
128
+ #
129
+ # xml_name_escape('1 < 2 & 3')
130
+ # # => "1___2___3"
131
+ #
132
+ # It follows the requirements of the specification: https://www.w3.org/TR/REC-xml/#NT-Name
133
+ def xml_name_escape(name)
134
+ name = name.to_s
135
+ return "" if name.blank?
136
+
137
+ starting_char = name[0].gsub(TAG_NAME_START_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
138
+
139
+ return starting_char if name.size == 1
140
+
141
+ following_chars = name[1..-1].gsub(TAG_NAME_FOLLOWING_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
142
+
143
+ starting_char + following_chars
144
+ end
145
+ module_function :xml_name_escape
120
146
  end
121
147
  end
122
148
 
@@ -132,17 +158,20 @@ class Numeric
132
158
  end
133
159
  end
134
160
 
135
- module ActiveSupport #:nodoc:
161
+ module ActiveSupport # :nodoc:
136
162
  class SafeBuffer < String
137
163
  UNSAFE_STRING_METHODS = %w(
138
- capitalize chomp chop delete downcase gsub lstrip next reverse rstrip
139
- slice squeeze strip sub succ swapcase tr tr_s upcase
164
+ capitalize chomp chop delete delete_prefix delete_suffix
165
+ downcase lstrip next reverse rstrip scrub slice squeeze strip
166
+ succ swapcase tr tr_s unicode_normalize upcase
140
167
  )
141
168
 
169
+ UNSAFE_STRING_METHODS_WITH_BACKREF = %w(gsub sub)
170
+
142
171
  alias_method :original_concat, :concat
143
172
  private :original_concat
144
173
 
145
- # Raised when <tt>ActiveSupport::SafeBuffer#safe_concat</tt> is called on unsafe buffers.
174
+ # Raised when ActiveSupport::SafeBuffer#safe_concat is called on unsafe buffers.
146
175
  class SafeConcatError < StandardError
147
176
  def initialize
148
177
  super "Could not concatenate to the buffer because it is not html safe."
@@ -150,15 +179,13 @@ module ActiveSupport #:nodoc:
150
179
  end
151
180
 
152
181
  def [](*args)
153
- if args.size < 2
154
- super
155
- elsif html_safe?
156
- new_safe_buffer = super
182
+ if html_safe?
183
+ new_string = super
157
184
 
158
- if new_safe_buffer
159
- new_safe_buffer.instance_variable_set :@html_safe, true
160
- end
185
+ return unless new_string
161
186
 
187
+ new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
188
+ new_safe_buffer.instance_variable_set :@html_safe, true
162
189
  new_safe_buffer
163
190
  else
164
191
  to_str[*args]
@@ -185,24 +212,50 @@ module ActiveSupport #:nodoc:
185
212
  end
186
213
 
187
214
  def concat(value)
188
- super(html_escape_interpolated_argument(value))
215
+ unless value.nil?
216
+ super(implicit_html_escape_interpolated_argument(value))
217
+ end
218
+ self
189
219
  end
190
220
  alias << concat
191
221
 
222
+ def insert(index, value)
223
+ super(index, implicit_html_escape_interpolated_argument(value))
224
+ end
225
+
192
226
  def prepend(value)
193
- super(html_escape_interpolated_argument(value))
227
+ super(implicit_html_escape_interpolated_argument(value))
228
+ end
229
+
230
+ def replace(value)
231
+ super(implicit_html_escape_interpolated_argument(value))
232
+ end
233
+
234
+ def []=(*args)
235
+ if args.length == 3
236
+ super(args[0], args[1], implicit_html_escape_interpolated_argument(args[2]))
237
+ else
238
+ super(args[0], implicit_html_escape_interpolated_argument(args[1]))
239
+ end
194
240
  end
195
241
 
196
242
  def +(other)
197
243
  dup.concat(other)
198
244
  end
199
245
 
246
+ def *(*)
247
+ new_string = super
248
+ new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
249
+ new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
250
+ new_safe_buffer
251
+ end
252
+
200
253
  def %(args)
201
254
  case args
202
255
  when Hash
203
- escaped_args = Hash[args.map { |k, arg| [k, html_escape_interpolated_argument(arg)] }]
256
+ escaped_args = args.transform_values { |arg| explicit_html_escape_interpolated_argument(arg) }
204
257
  else
205
- escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
258
+ escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
206
259
  end
207
260
 
208
261
  self.class.new(super(escaped_args))
@@ -239,11 +292,66 @@ module ActiveSupport #:nodoc:
239
292
  end
240
293
  end
241
294
 
242
- private
295
+ UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
296
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
297
+ def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
298
+ if block # if block
299
+ to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
300
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
301
+ block.call(*params) # block.call(*params)
302
+ } # }
303
+ else # else
304
+ to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
305
+ end # end
306
+ end # end
307
+
308
+ def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
309
+ @html_safe = false # @html_safe = false
310
+ if block # if block
311
+ super(*args) { |*params| # super(*args) { |*params|
312
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
313
+ block.call(*params) # block.call(*params)
314
+ } # }
315
+ else # else
316
+ super # super
317
+ end # end
318
+ end # end
319
+ EOT
320
+ end
243
321
 
244
- def html_escape_interpolated_argument(arg)
322
+ private
323
+ def explicit_html_escape_interpolated_argument(arg)
245
324
  (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
246
325
  end
326
+
327
+ def implicit_html_escape_interpolated_argument(arg)
328
+ if !html_safe? || arg.html_safe?
329
+ arg
330
+ else
331
+ arg_string = begin
332
+ arg.to_str
333
+ rescue NoMethodError => error
334
+ if error.name == :to_str
335
+ str = arg.to_s
336
+ ActiveSupport::Deprecation.warn <<~MSG.squish
337
+ Implicit conversion of #{arg.class} into String by ActiveSupport::SafeBuffer
338
+ is deprecated and will be removed in Rails 7.1.
339
+ You must explicitly cast it to a String.
340
+ MSG
341
+ str
342
+ else
343
+ raise
344
+ end
345
+ end
346
+ CGI.escapeHTML(arg_string)
347
+ end
348
+ end
349
+
350
+ def set_block_back_references(block, match_data)
351
+ block.binding.eval("proc { |m| $~ = m }").call(match_data)
352
+ rescue ArgumentError
353
+ # Can't create binding from C level Proc
354
+ end
247
355
  end
248
356
  end
249
357
 
@@ -251,7 +359,7 @@ class String
251
359
  # Marks a string as trusted safe. It will be inserted into HTML with no
252
360
  # additional escaping performed. It is your responsibility to ensure that the
253
361
  # string contains no malicious content. This method is equivalent to the
254
- # `raw` helper in views. It is recommended that you use `sanitize` instead of
362
+ # +raw+ helper in views. It is recommended that you use +sanitize+ instead of
255
363
  # this method. It should never be called on user input.
256
364
  def html_safe
257
365
  ActiveSupport::SafeBuffer.new(self)
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
- alias_method :starts_with?, :start_with?
3
- alias_method :ends_with?, :end_with?
4
+ alias :starts_with? :start_with?
5
+ alias :ends_with? :end_with?
4
6
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
4
  # Strips indentation in heredocs.
3
5
  #
@@ -18,6 +20,8 @@ class String
18
20
  # Technically, it looks for the least indented non-empty line
19
21
  # in the whole string, and removes that amount of leading whitespace.
20
22
  def strip_heredoc
21
- gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".freeze)
23
+ gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "").tap do |stripped|
24
+ stripped.freeze if frozen?
25
+ end
22
26
  end
23
27
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/string/conversions"
2
4
  require "active_support/core_ext/time/zones"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/string/conversions"
2
4
  require "active_support/core_ext/string/filters"
3
5
  require "active_support/core_ext/string/multibyte"
@@ -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"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/object/acts_like"
2
4
 
3
5
  class Time
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/duration"
2
4
  require "active_support/core_ext/time/conversions"
3
5
  require "active_support/time_with_zone"
4
6
  require "active_support/core_ext/time/zones"
5
7
  require "active_support/core_ext/date_and_time/calculations"
6
8
  require "active_support/core_ext/date/calculations"
9
+ require "active_support/core_ext/module/remove_method"
7
10
 
8
11
  class Time
9
12
  include DateAndTime::Calculations
@@ -39,13 +42,15 @@ class Time
39
42
 
40
43
  # Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime
41
44
  # instances can be used when called with a single argument
42
- def at_with_coercion(*args)
43
- 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?
44
47
 
45
48
  # Time.at can be called with a time or numerical value
46
49
  time_or_number = args.first
47
50
 
48
- if time_or_number.is_a?(ActiveSupport::TimeWithZone) || time_or_number.is_a?(DateTime)
51
+ if time_or_number.is_a?(ActiveSupport::TimeWithZone)
52
+ at_without_coercion(time_or_number.to_r).getlocal
53
+ elsif time_or_number.is_a?(DateTime)
49
54
  at_without_coercion(time_or_number.to_f).getlocal
50
55
  else
51
56
  at_without_coercion(time_or_number)
@@ -103,25 +108,41 @@ class Time
103
108
  subsec
104
109
  end
105
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
+
106
126
  # Returns a new Time where one or more of the elements have been changed according
107
127
  # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
108
128
  # <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
109
- # the hour is passed, then minute, sec, usec and nsec is set to 0. If the hour
110
- # and minute is passed, then sec, usec and nsec is set to 0. The +options+
111
- # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
112
- # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>
113
- # <tt>:nsec</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
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
+ # takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
132
+ # <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>,
133
+ # <tt>:offset</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
114
134
  #
115
135
  # Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0)
116
136
  # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0)
117
137
  # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => Time.new(1981, 8, 29, 0, 0, 0)
118
138
  def change(options)
119
- new_year = options.fetch(:year, year)
120
- new_month = options.fetch(:month, month)
121
- new_day = options.fetch(:day, day)
122
- new_hour = options.fetch(:hour, hour)
123
- new_min = options.fetch(:min, options[:hour] ? 0 : min)
124
- new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec)
139
+ new_year = options.fetch(:year, year)
140
+ new_month = options.fetch(:month, month)
141
+ new_day = options.fetch(:day, day)
142
+ new_hour = options.fetch(:hour, hour)
143
+ new_min = options.fetch(:min, options[:hour] ? 0 : min)
144
+ new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec)
145
+ new_offset = options.fetch(:offset, nil)
125
146
 
126
147
  if new_nsec = options[:nsec]
127
148
  raise ArgumentError, "Can't change both :nsec and :usec at the same time: #{options.inspect}" if options[:usec]
@@ -130,13 +151,20 @@ class Time
130
151
  new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
131
152
  end
132
153
 
133
- if utc?
134
- ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
154
+ raise ArgumentError, "argument out of range" if new_usec >= 1000000
155
+
156
+ new_sec += Rational(new_usec, 1000000)
157
+
158
+ if new_offset
159
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
160
+ elsif utc?
161
+ ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
162
+ elsif zone&.respond_to?(:utc_to_local)
163
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
135
164
  elsif zone
136
- ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
165
+ ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec)
137
166
  else
138
- raise ArgumentError, "argument out of range" if new_usec >= 1000000
139
- ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), utc_offset)
167
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
140
168
  end
141
169
  end
142
170
 
@@ -162,8 +190,7 @@ class Time
162
190
  options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
163
191
  end
164
192
 
165
- d = to_date.advance(options)
166
- d = d.gregorian if d.julian?
193
+ d = to_date.gregorian.advance(options)
167
194
  time_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
168
195
  seconds_to_advance = \
169
196
  options.fetch(:seconds, 0) +
@@ -250,7 +277,7 @@ class Time
250
277
  end
251
278
  alias :at_end_of_minute :end_of_minute
252
279
 
253
- def plus_with_duration(other) #:nodoc:
280
+ def plus_with_duration(other) # :nodoc:
254
281
  if ActiveSupport::Duration === other
255
282
  other.since(self)
256
283
  else
@@ -260,7 +287,7 @@ class Time
260
287
  alias_method :plus_without_duration, :+
261
288
  alias_method :+, :plus_with_duration
262
289
 
263
- def minus_with_duration(other) #:nodoc:
290
+ def minus_with_duration(other) # :nodoc:
264
291
  if ActiveSupport::Duration === other
265
292
  other.until(self)
266
293
  else
@@ -278,7 +305,7 @@ class Time
278
305
  other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other)
279
306
  end
280
307
  alias_method :minus_without_coercion, :-
281
- alias_method :-, :minus_with_coercion
308
+ alias_method :-, :minus_with_coercion # rubocop:disable Lint/DuplicateMethods
282
309
 
283
310
  # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
284
311
  # can be chronologically compared with a Time
@@ -304,4 +331,34 @@ class Time
304
331
  end
305
332
  alias_method :eql_without_coercion, :eql?
306
333
  alias_method :eql?, :eql_with_coercion
334
+
335
+ # Returns a new time the specified number of days ago.
336
+ def prev_day(days = 1)
337
+ advance(days: -days)
338
+ end
339
+
340
+ # Returns a new time the specified number of days in the future.
341
+ def next_day(days = 1)
342
+ advance(days: days)
343
+ end
344
+
345
+ # Returns a new time the specified number of months ago.
346
+ def prev_month(months = 1)
347
+ advance(months: -months)
348
+ end
349
+
350
+ # Returns a new time the specified number of months in the future.
351
+ def next_month(months = 1)
352
+ advance(months: months)
353
+ end
354
+
355
+ # Returns a new time the specified number of years ago.
356
+ def prev_year(years = 1)
357
+ advance(years: -years)
358
+ end
359
+
360
+ # Returns a new time the specified number of years in the future.
361
+ def next_year(years = 1)
362
+ advance(years: years)
363
+ end
307
364
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/date_and_time/compatibility"
2
- require "active_support/core_ext/module/remove_method"
4
+ require "active_support/core_ext/module/redefine_method"
3
5
 
4
6
  class Time
5
7
  include DateAndTime::Compatibility
6
8
 
7
- remove_possible_method :to_time
9
+ silence_redefinition_of_method :to_time
8
10
 
9
11
  # Either return +self+ or the time in the local system timezone depending
10
12
  # on the setting of +ActiveSupport.to_time_preserves_timezone+.
@@ -1,9 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
1
4
  require "active_support/inflector/methods"
2
5
  require "active_support/values/time_zone"
3
6
 
4
7
  class Time
5
8
  DATE_FORMATS = {
6
9
  db: "%Y-%m-%d %H:%M:%S",
10
+ inspect: "%Y-%m-%d %H:%M:%S.%9N %z",
7
11
  number: "%Y%m%d%H%M%S",
8
12
  nsec: "%Y%m%d%H%M%S%9N",
9
13
  usec: "%Y%m%d%H%M%S%6N",
@@ -23,22 +27,22 @@ class Time
23
27
 
24
28
  # Converts to a formatted string. See DATE_FORMATS for built-in formats.
25
29
  #
26
- # This method is aliased to <tt>to_s</tt>.
30
+ # This method is aliased to <tt>to_formatted_s</tt>.
27
31
  #
28
32
  # time = Time.now # => 2007-01-18 06:10:17 -06:00
29
33
  #
34
+ # time.to_fs(:time) # => "06:10"
30
35
  # time.to_formatted_s(:time) # => "06:10"
31
- # time.to_s(:time) # => "06:10"
32
36
  #
33
- # time.to_formatted_s(:db) # => "2007-01-18 06:10:17"
34
- # time.to_formatted_s(:number) # => "20070118061017"
35
- # time.to_formatted_s(:short) # => "18 Jan 06:10"
36
- # time.to_formatted_s(:long) # => "January 18, 2007 06:10"
37
- # time.to_formatted_s(:long_ordinal) # => "January 18th, 2007 06:10"
38
- # time.to_formatted_s(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
39
- # 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"
40
44
  #
41
- # == Adding your own time formats to +to_formatted_s+
45
+ # == Adding your own time formats to +to_fs+
42
46
  # You can add your own formats to the Time::DATE_FORMATS hash.
43
47
  # Use the format name as the hash key and either a strftime string
44
48
  # or Proc instance that takes a time argument as the value.
@@ -46,15 +50,16 @@ class Time
46
50
  # # config/initializers/time_formats.rb
47
51
  # Time::DATE_FORMATS[:month_and_year] = '%B %Y'
48
52
  # Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
49
- def to_formatted_s(format = :default)
53
+ def to_fs(format = :default)
50
54
  if formatter = DATE_FORMATS[format]
51
55
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
52
56
  else
57
+ # Change to `to_s` when deprecation is gone. Also deprecate `to_default_s`.
53
58
  to_default_s
54
59
  end
55
60
  end
61
+ alias_method :to_formatted_s, :to_fs
56
62
  alias_method :to_default_s, :to_s
57
- alias_method :to_s, :to_formatted_s
58
63
 
59
64
  # Returns a formatted string of the offset from UTC, or an alternative
60
65
  # string if the time zone is already UTC.
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+
5
+ class Time
6
+ NOT_SET = Object.new # :nodoc:
7
+ def to_s(format = NOT_SET) # :nodoc:
8
+ if formatter = DATE_FORMATS[format]
9
+ ActiveSupport::Deprecation.warn(
10
+ "Time#to_s(#{format.inspect}) is deprecated. Please use Time#to_fs(#{format.inspect}) instead."
11
+ )
12
+ formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
13
+ elsif format == NOT_SET
14
+ to_default_s
15
+ else
16
+ ActiveSupport::Deprecation.warn(
17
+ "Time#to_s(#{format.inspect}) is deprecated. Please use Time#to_fs(#{format.inspect}) instead."
18
+ )
19
+ to_default_s
20
+ end
21
+ end
22
+ end