activesupport 6.0.3.7 → 7.0.0

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 (204) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +220 -533
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support/actionable_error.rb +1 -1
  6. data/lib/active_support/array_inquirer.rb +2 -2
  7. data/lib/active_support/backtrace_cleaner.rb +3 -3
  8. data/lib/active_support/benchmarkable.rb +3 -3
  9. data/lib/active_support/cache/file_store.rb +18 -11
  10. data/lib/active_support/cache/mem_cache_store.rb +143 -37
  11. data/lib/active_support/cache/memory_store.rb +56 -28
  12. data/lib/active_support/cache/null_store.rb +10 -2
  13. data/lib/active_support/cache/redis_cache_store.rb +63 -88
  14. data/lib/active_support/cache/strategy/local_cache.rb +46 -57
  15. data/lib/active_support/cache.rb +273 -82
  16. data/lib/active_support/callbacks.rb +226 -118
  17. data/lib/active_support/code_generator.rb +65 -0
  18. data/lib/active_support/concern.rb +49 -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 +9 -6
  22. data/lib/active_support/configuration_file.rb +51 -0
  23. data/lib/active_support/core_ext/array/access.rb +1 -5
  24. data/lib/active_support/core_ext/array/conversions.rb +9 -7
  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.rb +1 -0
  28. data/lib/active_support/core_ext/benchmark.rb +2 -2
  29. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  30. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  31. data/lib/active_support/core_ext/class/subclasses.rb +21 -40
  32. data/lib/active_support/core_ext/date/blank.rb +1 -1
  33. data/lib/active_support/core_ext/date/calculations.rb +4 -4
  34. data/lib/active_support/core_ext/date/conversions.rb +5 -4
  35. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  36. data/lib/active_support/core_ext/date.rb +1 -0
  37. data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
  38. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  39. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  40. data/lib/active_support/core_ext/date_time/conversions.rb +5 -5
  41. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -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 +139 -15
  45. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  46. data/lib/active_support/core_ext/hash/conversions.rb +2 -2
  47. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  48. data/lib/active_support/core_ext/hash/except.rb +1 -1
  49. data/lib/active_support/core_ext/hash/keys.rb +2 -2
  50. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  51. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  52. data/lib/active_support/core_ext/load_error.rb +1 -1
  53. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  54. data/lib/active_support/core_ext/module/attribute_accessors.rb +25 -29
  55. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +26 -13
  56. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  57. data/lib/active_support/core_ext/module/delegation.rb +40 -36
  58. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  59. data/lib/active_support/core_ext/name_error.rb +23 -2
  60. data/lib/active_support/core_ext/numeric/conversions.rb +79 -72
  61. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  62. data/lib/active_support/core_ext/numeric.rb +1 -0
  63. data/lib/active_support/core_ext/object/blank.rb +2 -2
  64. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  65. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  66. data/lib/active_support/core_ext/object/json.rb +42 -26
  67. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  68. data/lib/active_support/core_ext/object/try.rb +20 -20
  69. data/lib/active_support/core_ext/object/with_options.rb +20 -1
  70. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  71. data/lib/active_support/core_ext/pathname.rb +3 -0
  72. data/lib/active_support/core_ext/range/compare_range.rb +6 -25
  73. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  74. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  75. data/lib/active_support/core_ext/range/each.rb +1 -1
  76. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
  77. data/lib/active_support/core_ext/range.rb +1 -1
  78. data/lib/active_support/core_ext/regexp.rb +8 -1
  79. data/lib/active_support/core_ext/string/access.rb +5 -24
  80. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  81. data/lib/active_support/core_ext/string/filters.rb +1 -1
  82. data/lib/active_support/core_ext/string/inflections.rb +39 -5
  83. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  84. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  85. data/lib/active_support/core_ext/string/output_safety.rb +69 -45
  86. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  87. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  88. data/lib/active_support/core_ext/symbol.rb +3 -0
  89. data/lib/active_support/core_ext/time/calculations.rb +26 -6
  90. data/lib/active_support/core_ext/time/conversions.rb +6 -3
  91. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  92. data/lib/active_support/core_ext/time/zones.rb +4 -19
  93. data/lib/active_support/core_ext/time.rb +1 -0
  94. data/lib/active_support/core_ext/uri.rb +3 -23
  95. data/lib/active_support/core_ext.rb +2 -1
  96. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  97. data/lib/active_support/current_attributes.rb +39 -16
  98. data/lib/active_support/dependencies/interlock.rb +10 -18
  99. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  100. data/lib/active_support/dependencies.rb +58 -764
  101. data/lib/active_support/deprecation/behaviors.rb +19 -3
  102. data/lib/active_support/deprecation/disallowed.rb +56 -0
  103. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  104. data/lib/active_support/deprecation/method_wrappers.rb +6 -5
  105. data/lib/active_support/deprecation/proxy_wrappers.rb +4 -4
  106. data/lib/active_support/deprecation/reporting.rb +50 -7
  107. data/lib/active_support/deprecation.rb +6 -1
  108. data/lib/active_support/descendants_tracker.rb +177 -64
  109. data/lib/active_support/digest.rb +5 -3
  110. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  111. data/lib/active_support/duration/iso8601_serializer.rb +24 -10
  112. data/lib/active_support/duration.rb +134 -55
  113. data/lib/active_support/encrypted_configuration.rb +11 -1
  114. data/lib/active_support/encrypted_file.rb +20 -3
  115. data/lib/active_support/environment_inquirer.rb +20 -0
  116. data/lib/active_support/error_reporter.rb +117 -0
  117. data/lib/active_support/evented_file_update_checker.rb +70 -134
  118. data/lib/active_support/execution_context/test_helper.rb +13 -0
  119. data/lib/active_support/execution_context.rb +53 -0
  120. data/lib/active_support/execution_wrapper.rb +30 -4
  121. data/lib/active_support/executor/test_helper.rb +7 -0
  122. data/lib/active_support/fork_tracker.rb +71 -0
  123. data/lib/active_support/gem_version.rb +3 -3
  124. data/lib/active_support/hash_with_indifferent_access.rb +51 -25
  125. data/lib/active_support/html_safe_translation.rb +43 -0
  126. data/lib/active_support/i18n.rb +1 -0
  127. data/lib/active_support/i18n_railtie.rb +14 -19
  128. data/lib/active_support/inflector/inflections.rb +24 -9
  129. data/lib/active_support/inflector/methods.rb +29 -49
  130. data/lib/active_support/inflector/transliterate.rb +4 -4
  131. data/lib/active_support/isolated_execution_state.rb +56 -0
  132. data/lib/active_support/json/decoding.rb +4 -4
  133. data/lib/active_support/json/encoding.rb +8 -4
  134. data/lib/active_support/key_generator.rb +19 -2
  135. data/lib/active_support/locale/en.yml +8 -4
  136. data/lib/active_support/log_subscriber.rb +21 -3
  137. data/lib/active_support/logger.rb +1 -1
  138. data/lib/active_support/logger_silence.rb +2 -26
  139. data/lib/active_support/logger_thread_safe_level.rb +34 -21
  140. data/lib/active_support/message_encryptor.rb +12 -10
  141. data/lib/active_support/message_verifier.rb +50 -18
  142. data/lib/active_support/messages/metadata.rb +11 -3
  143. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  144. data/lib/active_support/messages/rotator.rb +6 -5
  145. data/lib/active_support/multibyte/chars.rb +13 -52
  146. data/lib/active_support/multibyte/unicode.rb +1 -87
  147. data/lib/active_support/multibyte.rb +1 -1
  148. data/lib/active_support/notifications/fanout.rb +110 -69
  149. data/lib/active_support/notifications/instrumenter.rb +37 -29
  150. data/lib/active_support/notifications.rb +47 -26
  151. data/lib/active_support/number_helper/number_converter.rb +2 -4
  152. data/lib/active_support/number_helper/number_to_currency_converter.rb +10 -9
  153. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  154. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  155. data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
  156. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  157. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  158. data/lib/active_support/number_helper/rounding_helper.rb +12 -32
  159. data/lib/active_support/number_helper.rb +29 -16
  160. data/lib/active_support/option_merger.rb +9 -16
  161. data/lib/active_support/ordered_hash.rb +1 -1
  162. data/lib/active_support/ordered_options.rb +8 -2
  163. data/lib/active_support/parameter_filter.rb +21 -11
  164. data/lib/active_support/per_thread_registry.rb +6 -1
  165. data/lib/active_support/rails.rb +1 -4
  166. data/lib/active_support/railtie.rb +77 -5
  167. data/lib/active_support/rescuable.rb +6 -6
  168. data/lib/active_support/ruby_features.rb +7 -0
  169. data/lib/active_support/secure_compare_rotator.rb +51 -0
  170. data/lib/active_support/security_utils.rb +19 -12
  171. data/lib/active_support/string_inquirer.rb +2 -2
  172. data/lib/active_support/subscriber.rb +19 -25
  173. data/lib/active_support/tagged_logging.rb +31 -6
  174. data/lib/active_support/test_case.rb +9 -21
  175. data/lib/active_support/testing/assertions.rb +49 -12
  176. data/lib/active_support/testing/deprecation.rb +52 -1
  177. data/lib/active_support/testing/isolation.rb +2 -2
  178. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  179. data/lib/active_support/testing/parallelization/server.rb +82 -0
  180. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  181. data/lib/active_support/testing/parallelization.rb +16 -95
  182. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  183. data/lib/active_support/testing/stream.rb +3 -5
  184. data/lib/active_support/testing/tagged_logging.rb +1 -1
  185. data/lib/active_support/testing/time_helpers.rb +53 -5
  186. data/lib/active_support/time_with_zone.rb +120 -55
  187. data/lib/active_support/values/time_zone.rb +49 -18
  188. data/lib/active_support/xml_mini/jdom.rb +1 -1
  189. data/lib/active_support/xml_mini/libxml.rb +5 -5
  190. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  191. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  192. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  193. data/lib/active_support/xml_mini/rexml.rb +9 -2
  194. data/lib/active_support/xml_mini.rb +5 -4
  195. data/lib/active_support.rb +29 -1
  196. metadata +46 -45
  197. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  198. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  199. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  200. data/lib/active_support/core_ext/marshal.rb +0 -24
  201. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  202. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  203. data/lib/active_support/core_ext/range/include_range.rb +0 -9
  204. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -43,7 +43,7 @@ class Hash
43
43
  def deep_dup
44
44
  hash = dup
45
45
  each_pair do |key, value|
46
- if key.frozen? && ::String === key
46
+ if ::String === key || ::Symbol === key
47
47
  hash[key] = value.deep_dup
48
48
  else
49
49
  hash.delete(key)
@@ -47,3 +47,14 @@ class UnboundMethod
47
47
  false
48
48
  end
49
49
  end
50
+
51
+ require "singleton"
52
+
53
+ module Singleton
54
+ # Singleton instances are not duplicable:
55
+ #
56
+ # Class.new.include(Singleton).instance.dup # TypeError (can't dup instance of singleton
57
+ def duplicable?
58
+ false
59
+ end
60
+ end
@@ -3,6 +3,7 @@
3
3
  # Hack to load json gem first so we can overwrite its to_json.
4
4
  require "json"
5
5
  require "bigdecimal"
6
+ require "ipaddr"
6
7
  require "uri/generic"
7
8
  require "pathname"
8
9
  require "active_support/core_ext/big_decimal/conversions" # for #to_s
@@ -18,8 +19,7 @@ require "active_support/core_ext/date/conversions"
18
19
  # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting
19
20
  # their default behavior. That said, we need to define the basic to_json method in all of them,
20
21
  # otherwise they will always use to_json gem implementation, which is backwards incompatible in
21
- # several cases (for instance, the JSON implementation for Hash does not work) with inheritance
22
- # and consequently classes as ActiveSupport::OrderedHash cannot be serialized to json.
22
+ # several cases (for instance, the JSON implementation for Hash does not work) with inheritance.
23
23
  #
24
24
  # On the other hand, we should avoid conflict with ::JSON.{generate,dump}(obj). Unfortunately, the
25
25
  # JSON gem's encoder relies on its own to_json implementation to encode objects. Since it always
@@ -45,12 +45,18 @@ module ActiveSupport
45
45
  end
46
46
  end
47
47
 
48
- [Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].reverse_each do |klass|
48
+ [Enumerable, Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass].reverse_each do |klass|
49
49
  klass.prepend(ActiveSupport::ToJsonWithActiveSupportEncoder)
50
50
  end
51
51
 
52
+ class Module
53
+ def as_json(options = nil) # :nodoc:
54
+ name
55
+ end
56
+ end
57
+
52
58
  class Object
53
- def as_json(options = nil) #:nodoc:
59
+ def as_json(options = nil) # :nodoc:
54
60
  if respond_to?(:to_hash)
55
61
  to_hash.as_json(options)
56
62
  else
@@ -59,44 +65,44 @@ class Object
59
65
  end
60
66
  end
61
67
 
62
- class Struct #:nodoc:
68
+ class Struct # :nodoc:
63
69
  def as_json(options = nil)
64
70
  Hash[members.zip(values)].as_json(options)
65
71
  end
66
72
  end
67
73
 
68
74
  class TrueClass
69
- def as_json(options = nil) #:nodoc:
75
+ def as_json(options = nil) # :nodoc:
70
76
  self
71
77
  end
72
78
  end
73
79
 
74
80
  class FalseClass
75
- def as_json(options = nil) #:nodoc:
81
+ def as_json(options = nil) # :nodoc:
76
82
  self
77
83
  end
78
84
  end
79
85
 
80
86
  class NilClass
81
- def as_json(options = nil) #:nodoc:
87
+ def as_json(options = nil) # :nodoc:
82
88
  self
83
89
  end
84
90
  end
85
91
 
86
92
  class String
87
- def as_json(options = nil) #:nodoc:
93
+ def as_json(options = nil) # :nodoc:
88
94
  self
89
95
  end
90
96
  end
91
97
 
92
98
  class Symbol
93
- def as_json(options = nil) #:nodoc:
99
+ def as_json(options = nil) # :nodoc:
94
100
  to_s
95
101
  end
96
102
  end
97
103
 
98
104
  class Numeric
99
- def as_json(options = nil) #:nodoc:
105
+ def as_json(options = nil) # :nodoc:
100
106
  self
101
107
  end
102
108
  end
@@ -104,7 +110,7 @@ end
104
110
  class Float
105
111
  # Encoding Infinity or NaN to JSON should return "null". The default returns
106
112
  # "Infinity" or "NaN" which are not valid JSON.
107
- def as_json(options = nil) #:nodoc:
113
+ def as_json(options = nil) # :nodoc:
108
114
  finite? ? self : nil
109
115
  end
110
116
  end
@@ -119,43 +125,43 @@ class BigDecimal
119
125
  # if the other end knows by contract that the data is supposed to be a
120
126
  # BigDecimal, it still has the chance to post-process the string and get the
121
127
  # real value.
122
- def as_json(options = nil) #:nodoc:
128
+ def as_json(options = nil) # :nodoc:
123
129
  finite? ? to_s : nil
124
130
  end
125
131
  end
126
132
 
127
133
  class Regexp
128
- def as_json(options = nil) #:nodoc:
134
+ def as_json(options = nil) # :nodoc:
129
135
  to_s
130
136
  end
131
137
  end
132
138
 
133
139
  module Enumerable
134
- def as_json(options = nil) #:nodoc:
140
+ def as_json(options = nil) # :nodoc:
135
141
  to_a.as_json(options)
136
142
  end
137
143
  end
138
144
 
139
145
  class IO
140
- def as_json(options = nil) #:nodoc:
146
+ def as_json(options = nil) # :nodoc:
141
147
  to_s
142
148
  end
143
149
  end
144
150
 
145
151
  class Range
146
- def as_json(options = nil) #:nodoc:
152
+ def as_json(options = nil) # :nodoc:
147
153
  to_s
148
154
  end
149
155
  end
150
156
 
151
157
  class Array
152
- def as_json(options = nil) #:nodoc:
158
+ def as_json(options = nil) # :nodoc:
153
159
  map { |v| options ? v.as_json(options.dup) : v.as_json }
154
160
  end
155
161
  end
156
162
 
157
163
  class Hash
158
- def as_json(options = nil) #:nodoc:
164
+ def as_json(options = nil) # :nodoc:
159
165
  # create a subset of the hash by applying :only or :except
160
166
  subset = if options
161
167
  if attrs = options[:only]
@@ -169,12 +175,16 @@ class Hash
169
175
  self
170
176
  end
171
177
 
172
- Hash[subset.map { |k, v| [k.to_s, options ? v.as_json(options.dup) : v.as_json] }]
178
+ result = {}
179
+ subset.each do |k, v|
180
+ result[k.to_s] = options ? v.as_json(options.dup) : v.as_json
181
+ end
182
+ result
173
183
  end
174
184
  end
175
185
 
176
186
  class Time
177
- def as_json(options = nil) #:nodoc:
187
+ def as_json(options = nil) # :nodoc:
178
188
  if ActiveSupport::JSON::Encoding.use_standard_json_time_format
179
189
  xmlschema(ActiveSupport::JSON::Encoding.time_precision)
180
190
  else
@@ -184,7 +194,7 @@ class Time
184
194
  end
185
195
 
186
196
  class Date
187
- def as_json(options = nil) #:nodoc:
197
+ def as_json(options = nil) # :nodoc:
188
198
  if ActiveSupport::JSON::Encoding.use_standard_json_time_format
189
199
  strftime("%Y-%m-%d")
190
200
  else
@@ -194,7 +204,7 @@ class Date
194
204
  end
195
205
 
196
206
  class DateTime
197
- def as_json(options = nil) #:nodoc:
207
+ def as_json(options = nil) # :nodoc:
198
208
  if ActiveSupport::JSON::Encoding.use_standard_json_time_format
199
209
  xmlschema(ActiveSupport::JSON::Encoding.time_precision)
200
210
  else
@@ -203,19 +213,25 @@ class DateTime
203
213
  end
204
214
  end
205
215
 
206
- class URI::Generic #:nodoc:
216
+ class URI::Generic # :nodoc:
217
+ def as_json(options = nil)
218
+ to_s
219
+ end
220
+ end
221
+
222
+ class Pathname # :nodoc:
207
223
  def as_json(options = nil)
208
224
  to_s
209
225
  end
210
226
  end
211
227
 
212
- class Pathname #:nodoc:
228
+ class IPAddr # :nodoc:
213
229
  def as_json(options = nil)
214
230
  to_s
215
231
  end
216
232
  end
217
233
 
218
- class Process::Status #:nodoc:
234
+ class Process::Status # :nodoc:
219
235
  def as_json(options = nil)
220
236
  { exitstatus: exitstatus, pid: pid }
221
237
  end
@@ -75,11 +75,11 @@ class Hash
75
75
  #
76
76
  # This method is also aliased as +to_param+.
77
77
  def to_query(namespace = nil)
78
- query = collect do |key, value|
78
+ query = filter_map do |key, value|
79
79
  unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
80
80
  value.to_query(namespace ? "#{namespace}[#{key}]" : key)
81
81
  end
82
- end.compact
82
+ end
83
83
 
84
84
  query.sort! unless namespace.to_s.include?("[]")
85
85
  query.join("&")
@@ -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, *args)
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, *args)
155
+ def try!(*)
156
156
  nil
157
157
  end
158
158
  end
@@ -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"
@@ -15,11 +15,13 @@ module ActiveSupport
15
15
  # The given range must be fully bounded, with both start and end.
16
16
  def ===(value)
17
17
  if value.is_a?(::Range)
18
+ is_backwards_op = value.exclude_end? ? :>= : :>
19
+ return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
18
20
  # 1...10 includes 1..9 but it does not include 1..10.
19
21
  # 1..10 includes 1...11 but it does not include 1...12.
20
22
  operator = exclude_end? && !value.exclude_end? ? :< : :<=
21
23
  value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
22
- super(value.first) && (self.end.nil? || value_max.send(operator, last))
24
+ super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
23
25
  else
24
26
  super
25
27
  end
@@ -38,34 +40,13 @@ module ActiveSupport
38
40
  # The given range must be fully bounded, with both start and end.
39
41
  def include?(value)
40
42
  if value.is_a?(::Range)
43
+ is_backwards_op = value.exclude_end? ? :>= : :>
44
+ return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
41
45
  # 1...10 includes 1..9 but it does not include 1..10.
42
46
  # 1..10 includes 1...11 but it does not include 1...12.
43
47
  operator = exclude_end? && !value.exclude_end? ? :< : :<=
44
48
  value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
45
- super(value.first) && (self.end.nil? || value_max.send(operator, last))
46
- else
47
- super
48
- end
49
- end
50
-
51
- # Extends the default Range#cover? to support range comparisons.
52
- # (1..5).cover?(1..5) # => true
53
- # (1..5).cover?(2..3) # => true
54
- # (1..5).cover?(1...6) # => true
55
- # (1..5).cover?(2..6) # => false
56
- #
57
- # The native Range#cover? behavior is untouched.
58
- # ('a'..'f').cover?('c') # => true
59
- # (5..9).cover?(11) # => false
60
- #
61
- # The given range must be fully bounded, with both start and end.
62
- def cover?(value)
63
- if value.is_a?(::Range)
64
- # 1...10 covers 1..9 but it does not cover 1..10.
65
- # 1..10 covers 1...11 but it does not cover 1...12.
66
- operator = exclude_end? && !value.exclude_end? ? :< : :<=
67
- value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
68
- super(value.first) && (self.end.nil? || value_max.send(operator, last))
49
+ super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
69
50
  else
70
51
  super
71
52
  end
@@ -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_formatted_s(:db)}' AND '#{stop.to_formatted_s(: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_fs</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_formatted_s(: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_formatted_s(:db)} and #{stop.to_formatted_s(:db)}" }
30
+ def to_formatted_s(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_fs, :to_formatted_s
38
38
  end
39
39
  end
40
40
 
@@ -0,0 +1,26 @@
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_formatted_s(#{format.inspect}) instead."
10
+ )
11
+ formatter.call(first, last)
12
+ elsif format == NOT_SET
13
+ super()
14
+ else
15
+ ActiveSupport::Deprecation.warn(
16
+ "Range#to_s(#{format.inspect}) is deprecated. Please use Range#to_formatted_s(#{format.inspect}) instead."
17
+ )
18
+ super()
19
+ end
20
+ end
21
+ alias_method :to_default_s, :to_s
22
+ deprecate :to_default_s
23
+ end
24
+ end
25
+
26
+ 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,23 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/time_with_zone"
4
-
5
- module ActiveSupport
6
- module IncludeTimeWithZone #:nodoc:
7
- # Extends the default Range#include? to support ActiveSupport::TimeWithZone.
8
- #
9
- # (1.hour.ago..1.hour.from_now).include?(Time.current) # => true
10
- #
11
- def include?(value)
12
- if self.begin.is_a?(TimeWithZone)
13
- cover?(value)
14
- elsif self.end.is_a?(TimeWithZone)
15
- cover?(value)
16
- else
17
- super
18
- end
19
- end
20
- end
21
- end
3
+ # frozen_string_literal: true
22
4
 
23
- Range.prepend(ActiveSupport::IncludeTimeWithZone)
5
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
6
+ `active_support/core_ext/range/include_time_with_zone` is deprecated and will be removed in Rails 7.1.
7
+ MSG
@@ -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"
@@ -1,6 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Regexp #:nodoc:
3
+ class Regexp
4
+ # Returns +true+ if the regexp has the multiline flag set.
5
+ #
6
+ # (/./).multiline? # => false
7
+ # (/./m).multiline? # => true
8
+ #
9
+ # Regexp.new(".").multiline? # => false
10
+ # Regexp.new(".", Regexp::MULTILINE).multiline? # => true
4
11
  def multiline?
5
12
  options & MULTILINE == MULTILINE
6
13
  end
@@ -44,7 +44,7 @@ class String
44
44
  # str.from(0).to(-1) # => "hello"
45
45
  # str.from(1).to(-2) # => "ell"
46
46
  def from(position)
47
- self[position..-1]
47
+ self[position, length]
48
48
  end
49
49
 
50
50
  # Returns a substring from the beginning of the string to the given position.
@@ -61,7 +61,8 @@ class String
61
61
  # str.from(0).to(-1) # => "hello"
62
62
  # str.from(1).to(-2) # => "ell"
63
63
  def to(position)
64
- self[0..position]
64
+ position += size if position < 0
65
+ self[0, position + 1] || +""
65
66
  end
66
67
 
67
68
  # Returns the first character. If a limit is supplied, returns a substring
@@ -75,17 +76,7 @@ class String
75
76
  # str.first(0) # => ""
76
77
  # str.first(6) # => "hello"
77
78
  def first(limit = 1)
78
- ActiveSupport::Deprecation.warn(
79
- "Calling String#first with a negative integer limit " \
80
- "will raise an ArgumentError in Rails 6.1."
81
- ) if limit < 0
82
- if limit == 0
83
- ""
84
- elsif limit >= size
85
- dup
86
- else
87
- to(limit - 1)
88
- end
79
+ self[0, limit] || raise(ArgumentError, "negative limit")
89
80
  end
90
81
 
91
82
  # Returns the last character of the string. If a limit is supplied, returns a substring
@@ -99,16 +90,6 @@ class String
99
90
  # str.last(0) # => ""
100
91
  # str.last(6) # => "hello"
101
92
  def last(limit = 1)
102
- ActiveSupport::Deprecation.warn(
103
- "Calling String#last with a negative integer limit " \
104
- "will raise an ArgumentError in Rails 6.1."
105
- ) if limit < 0
106
- if limit == 0
107
- ""
108
- elsif limit >= size
109
- dup
110
- else
111
- from(-limit)
112
- end
93
+ self[[length - limit, 0].max, limit] || raise(ArgumentError, "negative limit")
113
94
  end
114
95
  end
@@ -18,6 +18,7 @@ class String
18
18
  # "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 +0100
19
19
  # "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 06:12:00 UTC
20
20
  # "12/13/2012".to_time # => ArgumentError: argument out of range
21
+ # "1604326192".to_time # => ArgumentError: argument out of range
21
22
  def to_time(form = :local)
22
23
  parts = Date._parse(self, false)
23
24
  used_keys = %i(year mon mday hour min sec sec_fraction offset)
@@ -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