activesupport 6.1.4.1 → 7.0.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +325 -395
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_support/actionable_error.rb +1 -1
  6. data/lib/active_support/array_inquirer.rb +0 -2
  7. data/lib/active_support/backtrace_cleaner.rb +2 -2
  8. data/lib/active_support/benchmarkable.rb +2 -2
  9. data/lib/active_support/cache/file_store.rb +15 -9
  10. data/lib/active_support/cache/mem_cache_store.rb +148 -37
  11. data/lib/active_support/cache/memory_store.rb +24 -16
  12. data/lib/active_support/cache/null_store.rb +10 -2
  13. data/lib/active_support/cache/redis_cache_store.rb +68 -85
  14. data/lib/active_support/cache/strategy/local_cache.rb +38 -61
  15. data/lib/active_support/cache.rb +299 -147
  16. data/lib/active_support/callbacks.rb +184 -85
  17. data/lib/active_support/code_generator.rb +65 -0
  18. data/lib/active_support/concern.rb +5 -5
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  20. data/lib/active_support/concurrency/share_lock.rb +2 -2
  21. data/lib/active_support/configurable.rb +8 -5
  22. data/lib/active_support/configuration_file.rb +1 -1
  23. data/lib/active_support/core_ext/array/access.rb +1 -5
  24. data/lib/active_support/core_ext/array/conversions.rb +13 -12
  25. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  26. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  27. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  28. data/lib/active_support/core_ext/array.rb +1 -0
  29. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  30. data/lib/active_support/core_ext/class/subclasses.rb +25 -17
  31. data/lib/active_support/core_ext/date/blank.rb +1 -1
  32. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  33. data/lib/active_support/core_ext/date/conversions.rb +14 -14
  34. data/lib/active_support/core_ext/date/deprecated_conversions.rb +40 -0
  35. data/lib/active_support/core_ext/date.rb +1 -0
  36. data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
  37. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  38. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  39. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  40. data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
  41. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +36 -0
  42. data/lib/active_support/core_ext/date_time.rb +1 -0
  43. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  44. data/lib/active_support/core_ext/enumerable.rb +112 -38
  45. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  46. data/lib/active_support/core_ext/hash/conversions.rb +0 -1
  47. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  48. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  49. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  50. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  51. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  52. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  53. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  54. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  55. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  56. data/lib/active_support/core_ext/name_error.rb +2 -8
  57. data/lib/active_support/core_ext/numeric/conversions.rb +80 -77
  58. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  59. data/lib/active_support/core_ext/numeric.rb +1 -0
  60. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  61. data/lib/active_support/core_ext/object/blank.rb +2 -2
  62. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  63. data/lib/active_support/core_ext/object/duplicable.rb +15 -4
  64. data/lib/active_support/core_ext/object/json.rb +30 -25
  65. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  66. data/lib/active_support/core_ext/object/try.rb +20 -20
  67. data/lib/active_support/core_ext/object/with_options.rb +21 -2
  68. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  69. data/lib/active_support/core_ext/pathname.rb +3 -0
  70. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  71. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  72. data/lib/active_support/core_ext/range/deprecated_conversions.rb +36 -0
  73. data/lib/active_support/core_ext/range/each.rb +1 -1
  74. data/lib/active_support/core_ext/range/include_time_with_zone.rb +3 -26
  75. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  76. data/lib/active_support/core_ext/range.rb +1 -1
  77. data/lib/active_support/core_ext/securerandom.rb +1 -1
  78. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  79. data/lib/active_support/core_ext/string/filters.rb +1 -1
  80. data/lib/active_support/core_ext/string/inflections.rb +1 -5
  81. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  82. data/lib/active_support/core_ext/string/output_safety.rb +94 -38
  83. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  84. data/lib/active_support/core_ext/time/calculations.rb +13 -8
  85. data/lib/active_support/core_ext/time/conversions.rb +13 -12
  86. data/lib/active_support/core_ext/time/deprecated_conversions.rb +73 -0
  87. data/lib/active_support/core_ext/time/zones.rb +10 -26
  88. data/lib/active_support/core_ext/time.rb +1 -0
  89. data/lib/active_support/core_ext/uri.rb +3 -27
  90. data/lib/active_support/core_ext.rb +1 -0
  91. data/lib/active_support/current_attributes.rb +31 -14
  92. data/lib/active_support/dependencies/interlock.rb +10 -18
  93. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  94. data/lib/active_support/dependencies.rb +58 -788
  95. data/lib/active_support/deprecation/behaviors.rb +8 -5
  96. data/lib/active_support/deprecation/disallowed.rb +3 -3
  97. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  98. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  99. data/lib/active_support/deprecation.rb +2 -2
  100. data/lib/active_support/descendants_tracker.rb +174 -68
  101. data/lib/active_support/digest.rb +5 -3
  102. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  103. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  104. data/lib/active_support/duration.rb +81 -51
  105. data/lib/active_support/encrypted_configuration.rb +45 -3
  106. data/lib/active_support/encrypted_file.rb +21 -10
  107. data/lib/active_support/environment_inquirer.rb +1 -1
  108. data/lib/active_support/error_reporter.rb +117 -0
  109. data/lib/active_support/evented_file_update_checker.rb +20 -7
  110. data/lib/active_support/execution_context/test_helper.rb +13 -0
  111. data/lib/active_support/execution_context.rb +53 -0
  112. data/lib/active_support/execution_wrapper.rb +43 -21
  113. data/lib/active_support/executor/test_helper.rb +7 -0
  114. data/lib/active_support/fork_tracker.rb +19 -12
  115. data/lib/active_support/gem_version.rb +5 -5
  116. data/lib/active_support/hash_with_indifferent_access.rb +3 -1
  117. data/lib/active_support/html_safe_translation.rb +43 -0
  118. data/lib/active_support/i18n.rb +1 -0
  119. data/lib/active_support/i18n_railtie.rb +1 -1
  120. data/lib/active_support/inflector/inflections.rb +23 -7
  121. data/lib/active_support/inflector/methods.rb +29 -55
  122. data/lib/active_support/inflector/transliterate.rb +1 -1
  123. data/lib/active_support/isolated_execution_state.rb +72 -0
  124. data/lib/active_support/json/encoding.rb +3 -3
  125. data/lib/active_support/key_generator.rb +22 -5
  126. data/lib/active_support/lazy_load_hooks.rb +28 -4
  127. data/lib/active_support/locale/en.yml +1 -1
  128. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  129. data/lib/active_support/log_subscriber.rb +15 -5
  130. data/lib/active_support/logger_thread_safe_level.rb +4 -13
  131. data/lib/active_support/message_encryptor.rb +12 -6
  132. data/lib/active_support/message_verifier.rb +46 -14
  133. data/lib/active_support/messages/metadata.rb +2 -2
  134. data/lib/active_support/multibyte/chars.rb +10 -11
  135. data/lib/active_support/multibyte/unicode.rb +0 -12
  136. data/lib/active_support/multibyte.rb +1 -1
  137. data/lib/active_support/notifications/fanout.rb +91 -65
  138. data/lib/active_support/notifications/instrumenter.rb +32 -15
  139. data/lib/active_support/notifications.rb +23 -23
  140. data/lib/active_support/number_helper/number_converter.rb +1 -3
  141. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  142. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  143. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  144. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  145. data/lib/active_support/number_helper/rounding_helper.rb +1 -5
  146. data/lib/active_support/number_helper.rb +4 -5
  147. data/lib/active_support/option_merger.rb +10 -18
  148. data/lib/active_support/ordered_hash.rb +1 -1
  149. data/lib/active_support/ordered_options.rb +1 -1
  150. data/lib/active_support/parameter_filter.rb +20 -11
  151. data/lib/active_support/per_thread_registry.rb +5 -0
  152. data/lib/active_support/railtie.rb +69 -19
  153. data/lib/active_support/reloader.rb +1 -1
  154. data/lib/active_support/rescuable.rb +12 -12
  155. data/lib/active_support/ruby_features.rb +7 -0
  156. data/lib/active_support/secure_compare_rotator.rb +2 -2
  157. data/lib/active_support/string_inquirer.rb +0 -2
  158. data/lib/active_support/subscriber.rb +7 -18
  159. data/lib/active_support/tagged_logging.rb +2 -2
  160. data/lib/active_support/test_case.rb +13 -21
  161. data/lib/active_support/testing/assertions.rb +36 -6
  162. data/lib/active_support/testing/deprecation.rb +52 -1
  163. data/lib/active_support/testing/isolation.rb +30 -29
  164. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  165. data/lib/active_support/testing/parallelization/server.rb +4 -0
  166. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  167. data/lib/active_support/testing/parallelization.rb +4 -0
  168. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  169. data/lib/active_support/testing/stream.rb +3 -5
  170. data/lib/active_support/testing/tagged_logging.rb +1 -1
  171. data/lib/active_support/testing/time_helpers.rb +13 -2
  172. data/lib/active_support/time_with_zone.rb +43 -22
  173. data/lib/active_support/values/time_zone.rb +35 -14
  174. data/lib/active_support/version.rb +1 -1
  175. data/lib/active_support/xml_mini/jdom.rb +1 -1
  176. data/lib/active_support/xml_mini/libxml.rb +5 -5
  177. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  178. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  179. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  180. data/lib/active_support/xml_mini/rexml.rb +1 -1
  181. data/lib/active_support/xml_mini.rb +5 -4
  182. data/lib/active_support.rb +17 -1
  183. metadata +26 -23
  184. data/lib/active_support/core_ext/marshal.rb +0 -26
  185. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -3,32 +3,32 @@
3
3
  require "delegate"
4
4
 
5
5
  module ActiveSupport
6
- module Tryable #:nodoc:
7
- def try(method_name = nil, *args, &b)
8
- if method_name.nil? && block_given?
9
- if b.arity == 0
10
- instance_eval(&b)
6
+ module Tryable # :nodoc:
7
+ def try(*args, &block)
8
+ if args.empty? && block_given?
9
+ if block.arity == 0
10
+ instance_eval(&block)
11
11
  else
12
12
  yield self
13
13
  end
14
- elsif respond_to?(method_name)
15
- public_send(method_name, *args, &b)
14
+ elsif respond_to?(args.first)
15
+ public_send(*args, &block)
16
16
  end
17
17
  end
18
- ruby2_keywords(:try) if respond_to?(:ruby2_keywords, true)
18
+ ruby2_keywords(:try)
19
19
 
20
- def try!(method_name = nil, *args, &b)
21
- if method_name.nil? && block_given?
22
- if b.arity == 0
23
- instance_eval(&b)
20
+ def try!(*args, &block)
21
+ if args.empty? && block_given?
22
+ if block.arity == 0
23
+ instance_eval(&block)
24
24
  else
25
25
  yield self
26
26
  end
27
27
  else
28
- public_send(method_name, *args, &b)
28
+ public_send(*args, &block)
29
29
  end
30
30
  end
31
- ruby2_keywords(:try!) if respond_to?(:ruby2_keywords, true)
31
+ ruby2_keywords(:try!)
32
32
  end
33
33
  end
34
34
 
@@ -39,7 +39,7 @@ class Object
39
39
  # :method: try
40
40
  #
41
41
  # :call-seq:
42
- # try(*a, &b)
42
+ # try(*args, &block)
43
43
  #
44
44
  # Invokes the public method whose name goes as first argument just like
45
45
  # +public_send+ does, except that if the receiver does not respond to it the
@@ -104,7 +104,7 @@ class Object
104
104
  # :method: try!
105
105
  #
106
106
  # :call-seq:
107
- # try!(*a, &b)
107
+ # try!(*args, &block)
108
108
  #
109
109
  # Same as #try, but raises a +NoMethodError+ exception if the receiver is
110
110
  # not +nil+ and does not implement the tried method.
@@ -121,7 +121,7 @@ class Delegator
121
121
  # :method: try
122
122
  #
123
123
  # :call-seq:
124
- # try(a*, &b)
124
+ # try(*args, &block)
125
125
  #
126
126
  # See Object#try
127
127
 
@@ -129,7 +129,7 @@ class Delegator
129
129
  # :method: try!
130
130
  #
131
131
  # :call-seq:
132
- # try!(a*, &b)
132
+ # try!(*args, &block)
133
133
  #
134
134
  # See Object#try!
135
135
  end
@@ -145,14 +145,14 @@ class NilClass
145
145
  #
146
146
  # With +try+
147
147
  # @person.try(:children).try(:first).try(:name)
148
- def try(_method_name = nil, *)
148
+ def try(*)
149
149
  nil
150
150
  end
151
151
 
152
152
  # Calling +try!+ on +nil+ always returns +nil+.
153
153
  #
154
154
  # nil.try!(:name) # => nil
155
- def try!(_method_name = nil, *)
155
+ def try!(*)
156
156
  nil
157
157
  end
158
158
  end
@@ -64,7 +64,7 @@ class Object
64
64
  #
65
65
  # Hence the inherited default for +if+ key is ignored.
66
66
  #
67
- # NOTE: You cannot call class methods implicitly inside of with_options.
67
+ # NOTE: You cannot call class methods implicitly inside of +with_options+.
68
68
  # You can access these methods using the class name instead:
69
69
  #
70
70
  # class Phone < ActiveRecord::Base
@@ -75,8 +75,27 @@ class Object
75
75
  # end
76
76
  # end
77
77
  #
78
+ # When the block argument is omitted, the decorated Object instance is returned:
79
+ #
80
+ # module MyStyledHelpers
81
+ # def styled
82
+ # with_options style: "color: red;"
83
+ # end
84
+ # end
85
+ #
86
+ # styled.link_to "I'm red", "/"
87
+ # # => <a href="/" style="color: red;">I'm red</a>
88
+ #
89
+ # styled.button_tag "I'm red too!"
90
+ # # => <button style="color: red;">I'm red too!</button>
91
+ #
78
92
  def with_options(options, &block)
79
93
  option_merger = ActiveSupport::OptionMerger.new(self, options)
80
- block.arity.zero? ? option_merger.instance_eval(&block) : block.call(option_merger)
94
+
95
+ if block
96
+ block.arity.zero? ? option_merger.instance_eval(&block) : block.call(option_merger)
97
+ else
98
+ option_merger
99
+ end
81
100
  end
82
101
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Pathname
4
+ # Returns the receiver if the named file exists otherwise returns +nil+.
5
+ # <tt>pathname.existence</tt> is equivalent to
6
+ #
7
+ # pathname.exist? ? pathname : nil
8
+ #
9
+ # For example, something like
10
+ #
11
+ # content = pathname.read if pathname.exist?
12
+ #
13
+ # becomes
14
+ #
15
+ # content = pathname.existence&.read
16
+ #
17
+ # @return [Pathname]
18
+ def existence
19
+ self if exist?
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/pathname/existence"
@@ -51,31 +51,6 @@ module ActiveSupport
51
51
  super
52
52
  end
53
53
  end
54
-
55
- # Extends the default Range#cover? to support range comparisons.
56
- # (1..5).cover?(1..5) # => true
57
- # (1..5).cover?(2..3) # => true
58
- # (1..5).cover?(1...6) # => true
59
- # (1..5).cover?(2..6) # => false
60
- #
61
- # The native Range#cover? behavior is untouched.
62
- # ('a'..'f').cover?('c') # => true
63
- # (5..9).cover?(11) # => false
64
- #
65
- # The given range must be fully bounded, with both start and end.
66
- def cover?(value)
67
- if value.is_a?(::Range)
68
- is_backwards_op = value.exclude_end? ? :>= : :>
69
- return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
70
- # 1...10 covers 1..9 but it does not cover 1..10.
71
- # 1..10 covers 1...11 but it does not cover 1...12.
72
- operator = exclude_end? && !value.exclude_end? ? :< : :<=
73
- value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
74
- super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
75
- else
76
- super
77
- end
78
- end
79
54
  end
80
55
  end
81
56
 
@@ -7,34 +7,34 @@ module ActiveSupport
7
7
  case start
8
8
  when String then "BETWEEN '#{start}' AND '#{stop}'"
9
9
  else
10
- "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'"
10
+ "BETWEEN '#{start.to_fs(:db)}' AND '#{stop.to_fs(:db)}'"
11
11
  end
12
12
  end
13
13
  }
14
14
 
15
15
  # Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
16
16
  #
17
+ # This method is aliased to <tt>to_formatted_s</tt>.
18
+ #
17
19
  # range = (1..100) # => 1..100
18
20
  #
19
21
  # range.to_s # => "1..100"
20
- # range.to_s(:db) # => "BETWEEN '1' AND '100'"
22
+ # range.to_fs(:db) # => "BETWEEN '1' AND '100'"
21
23
  #
22
24
  # == Adding your own range formats to to_s
23
25
  # You can add your own formats to the Range::RANGE_FORMATS hash.
24
26
  # Use the format name as the hash key and a Proc instance.
25
27
  #
26
28
  # # config/initializers/range_formats.rb
27
- # Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
28
- def to_s(format = :default)
29
+ # Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_fs(:db)} and #{stop.to_fs(:db)}" }
30
+ def to_fs(format = :default)
29
31
  if formatter = RANGE_FORMATS[format]
30
32
  formatter.call(first, last)
31
33
  else
32
- super()
34
+ to_s
33
35
  end
34
36
  end
35
-
36
- alias_method :to_default_s, :to_s
37
- alias_method :to_formatted_s, :to_s
37
+ alias_method :to_formatted_s, :to_fs
38
38
  end
39
39
  end
40
40
 
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module DeprecatedRangeWithFormat # :nodoc:
5
+ NOT_SET = Object.new # :nodoc:
6
+ def to_s(format = NOT_SET)
7
+ if formatter = RangeWithFormat::RANGE_FORMATS[format]
8
+ ActiveSupport::Deprecation.warn(
9
+ "Range#to_s(#{format.inspect}) is deprecated. Please use Range#to_fs(#{format.inspect}) instead."
10
+ )
11
+ formatter.call(first, last)
12
+ elsif format == NOT_SET
13
+ if formatter = RangeWithFormat::RANGE_FORMATS[:default]
14
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
15
+ Using a :default format for Range#to_s is deprecated. Please use Range#to_fs instead. If you fixed all
16
+ places inside your application that you see this deprecation, you can set
17
+ `ENV['RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION']` to `"true"` in the `config/application.rb` file before
18
+ the `Bundler.require` call to fix all the callers outside of your application.
19
+ MSG
20
+ formatter.call(first, last)
21
+ else
22
+ super()
23
+ end
24
+ else
25
+ ActiveSupport::Deprecation.warn(
26
+ "Range#to_s(#{format.inspect}) is deprecated. Please use Range#to_fs(#{format.inspect}) instead."
27
+ )
28
+ super()
29
+ end
30
+ end
31
+ alias_method :to_default_s, :to_s
32
+ deprecate :to_default_s
33
+ end
34
+ end
35
+
36
+ Range.prepend(ActiveSupport::DeprecatedRangeWithFormat)
@@ -3,7 +3,7 @@
3
3
  require "active_support/time_with_zone"
4
4
 
5
5
  module ActiveSupport
6
- module EachTimeWithZone #:nodoc:
6
+ module EachTimeWithZone # :nodoc:
7
7
  def each(&block)
8
8
  ensure_iteration_allowed
9
9
  super
@@ -1,28 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/time_with_zone"
4
- require "active_support/deprecation"
5
-
6
- module ActiveSupport
7
- module IncludeTimeWithZone #:nodoc:
8
- # Extends the default Range#include? to support ActiveSupport::TimeWithZone.
9
- #
10
- # (1.hour.ago..1.hour.from_now).include?(Time.current) # => true
11
- #
12
- def include?(value)
13
- if self.begin.is_a?(TimeWithZone) || self.end.is_a?(TimeWithZone)
14
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
15
- Using `Range#include?` to check the inclusion of a value in
16
- a date time range is deprecated.
17
- It is recommended to use `Range#cover?` instead of `Range#include?` to
18
- check the inclusion of a value in a date time range.
19
- MSG
20
- cover?(value)
21
- else
22
- super
23
- end
24
- end
25
- end
26
- end
27
-
28
- Range.prepend(ActiveSupport::IncludeTimeWithZone)
3
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
4
+ `active_support/core_ext/range/include_time_with_zone` is deprecated and will be removed in Rails 7.1.
5
+ MSG
@@ -5,6 +5,6 @@ class Range
5
5
  # (1..5).overlaps?(4..6) # => true
6
6
  # (1..5).overlaps?(7..9) # => false
7
7
  def overlaps?(other)
8
- cover?(other.first) || other.cover?(first)
8
+ other.begin == self.begin || cover?(other.begin) || other.cover?(self.begin)
9
9
  end
10
10
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/range/conversions"
4
+ require "active_support/core_ext/range/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
4
5
  require "active_support/core_ext/range/compare_range"
5
- require "active_support/core_ext/range/include_time_with_zone"
6
6
  require "active_support/core_ext/range/overlaps"
7
7
  require "active_support/core_ext/range/each"
@@ -12,7 +12,7 @@ module SecureRandom
12
12
  #
13
13
  # If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
14
14
  #
15
- # The result may contain alphanumeric characters except 0, O, I and l.
15
+ # The result may contain alphanumeric characters except 0, O, I, and l.
16
16
  #
17
17
  # p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
18
18
  # p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
@@ -5,10 +5,10 @@ require "active_support/core_ext/time/calculations"
5
5
 
6
6
  class String
7
7
  # Converts a string to a Time value.
8
- # The +form+ can be either :utc or :local (default :local).
8
+ # The +form+ can be either +:utc+ or +:local+ (default +:local+).
9
9
  #
10
10
  # The time is parsed using Time.parse method.
11
- # If +form+ is :local, then the time is in the system timezone.
11
+ # If +form+ is +:local+, then the time is in the system timezone.
12
12
  # If the date part is missing then the current date is used and if
13
13
  # the time part is missing then it is assumed to be 00:00:00.
14
14
  #
@@ -106,7 +106,7 @@ class String
106
106
  self.class.new.tap do |cut|
107
107
  cut_at = truncate_at - omission.bytesize
108
108
 
109
- scan(/\X/) do |grapheme|
109
+ each_grapheme_cluster do |grapheme|
110
110
  if cut.bytesize + grapheme.bytesize <= cut_at
111
111
  cut << grapheme
112
112
  else
@@ -97,8 +97,6 @@ class String
97
97
  # 'active_record/errors'.camelize # => "ActiveRecord::Errors"
98
98
  # 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
99
99
  #
100
- # +camelize+ is also aliased as +camelcase+.
101
- #
102
100
  # See ActiveSupport::Inflector.camelize.
103
101
  def camelize(first_letter = :upper)
104
102
  case first_letter
@@ -124,8 +122,6 @@ class String
124
122
  # 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
125
123
  # 'string_ending_with_id'.titleize(keep_id_suffix: true) # => "String Ending With Id"
126
124
  #
127
- # +titleize+ is also aliased as +titlecase+.
128
- #
129
125
  # See ActiveSupport::Inflector.titleize.
130
126
  def titleize(keep_id_suffix: false)
131
127
  ActiveSupport::Inflector.titleize(self, keep_id_suffix: keep_id_suffix)
@@ -260,7 +256,7 @@ class String
260
256
  # 'author_id'.humanize # => "Author"
261
257
  # 'author_id'.humanize(capitalize: false) # => "author"
262
258
  # '_id'.humanize # => "Id"
263
- # 'author_id'.humanize(keep_id_suffix: true) # => "Author Id"
259
+ # 'author_id'.humanize(keep_id_suffix: true) # => "Author id"
264
260
  #
265
261
  # See ActiveSupport::Inflector.humanize.
266
262
  def humanize(capitalize: true, keep_id_suffix: false)
@@ -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
@@ -11,6 +11,14 @@ class ERB
11
11
  HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
12
12
  JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
13
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
+
14
22
  # A utility method for escaping HTML tag characters.
15
23
  # This method is also aliased as <tt>h</tt>.
16
24
  #
@@ -97,7 +105,7 @@ class ERB
97
105
  # WARNING: this helper only works with valid JSON. Using this on non-JSON values
98
106
  # will open up serious XSS vulnerabilities. For example, if you replace the
99
107
  # +current_user.to_json+ in the example above with user input instead, the browser
100
- # will happily eval() that string as JavaScript.
108
+ # will happily <tt>eval()</tt> that string as JavaScript.
101
109
  #
102
110
  # The escaping performed in this method is identical to those performed in the
103
111
  # Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
@@ -115,6 +123,26 @@ class ERB
115
123
  end
116
124
 
117
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
118
146
  end
119
147
  end
120
148
 
@@ -130,7 +158,7 @@ class Numeric
130
158
  end
131
159
  end
132
160
 
133
- module ActiveSupport #:nodoc:
161
+ module ActiveSupport # :nodoc:
134
162
  class SafeBuffer < String
135
163
  UNSAFE_STRING_METHODS = %w(
136
164
  capitalize chomp chop delete delete_prefix delete_suffix
@@ -143,7 +171,7 @@ module ActiveSupport #:nodoc:
143
171
  alias_method :original_concat, :concat
144
172
  private :original_concat
145
173
 
146
- # 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.
147
175
  class SafeConcatError < StandardError
148
176
  def initialize
149
177
  super "Could not concatenate to the buffer because it is not html safe."
@@ -184,27 +212,34 @@ module ActiveSupport #:nodoc:
184
212
  end
185
213
 
186
214
  def concat(value)
187
- super(html_escape_interpolated_argument(value))
215
+ unless value.nil?
216
+ super(implicit_html_escape_interpolated_argument(value))
217
+ end
218
+ self
188
219
  end
189
220
  alias << concat
190
221
 
222
+ def bytesplice(*args, value)
223
+ super(*args, implicit_html_escape_interpolated_argument(value))
224
+ end
225
+
191
226
  def insert(index, value)
192
- super(index, html_escape_interpolated_argument(value))
227
+ super(index, implicit_html_escape_interpolated_argument(value))
193
228
  end
194
229
 
195
230
  def prepend(value)
196
- super(html_escape_interpolated_argument(value))
231
+ super(implicit_html_escape_interpolated_argument(value))
197
232
  end
198
233
 
199
234
  def replace(value)
200
- super(html_escape_interpolated_argument(value))
235
+ super(implicit_html_escape_interpolated_argument(value))
201
236
  end
202
237
 
203
238
  def []=(*args)
204
239
  if args.length == 3
205
- super(args[0], args[1], html_escape_interpolated_argument(args[2]))
240
+ super(args[0], args[1], implicit_html_escape_interpolated_argument(args[2]))
206
241
  else
207
- super(args[0], html_escape_interpolated_argument(args[1]))
242
+ super(args[0], implicit_html_escape_interpolated_argument(args[1]))
208
243
  end
209
244
  end
210
245
 
@@ -222,9 +257,9 @@ module ActiveSupport #:nodoc:
222
257
  def %(args)
223
258
  case args
224
259
  when Hash
225
- escaped_args = args.transform_values { |arg| html_escape_interpolated_argument(arg) }
260
+ escaped_args = args.transform_values { |arg| explicit_html_escape_interpolated_argument(arg) }
226
261
  else
227
- escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
262
+ escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
228
263
  end
229
264
 
230
265
  self.class.new(super(escaped_args))
@@ -262,39 +297,60 @@ module ActiveSupport #:nodoc:
262
297
  end
263
298
 
264
299
  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
300
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
301
+ def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
302
+ if block # if block
303
+ to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
304
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
305
+ block.call(*params) # block.call(*params)
306
+ } # }
307
+ else # else
308
+ to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
309
+ end # end
310
+ end # end
311
+
312
+ def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
313
+ @html_safe = false # @html_safe = false
314
+ if block # if block
315
+ super(*args) { |*params| # super(*args) { |*params|
316
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
317
+ block.call(*params) # block.call(*params)
318
+ } # }
319
+ else # else
320
+ super # super
321
+ end # end
322
+ end # end
323
+ EOT
291
324
  end
292
325
 
293
326
  private
294
- def html_escape_interpolated_argument(arg)
327
+ def explicit_html_escape_interpolated_argument(arg)
295
328
  (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
296
329
  end
297
330
 
331
+ def implicit_html_escape_interpolated_argument(arg)
332
+ if !html_safe? || arg.html_safe?
333
+ arg
334
+ else
335
+ arg_string = begin
336
+ arg.to_str
337
+ rescue NoMethodError => error
338
+ if error.name == :to_str
339
+ str = arg.to_s
340
+ ActiveSupport::Deprecation.warn <<~MSG.squish
341
+ Implicit conversion of #{arg.class} into String by ActiveSupport::SafeBuffer
342
+ is deprecated and will be removed in Rails 7.1.
343
+ You must explicitly cast it to a String.
344
+ MSG
345
+ str
346
+ else
347
+ raise
348
+ end
349
+ end
350
+ CGI.escapeHTML(arg_string)
351
+ end
352
+ end
353
+
298
354
  def set_block_back_references(block, match_data)
299
355
  block.binding.eval("proc { |m| $~ = m }").call(match_data)
300
356
  rescue ArgumentError
@@ -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