activesupport 7.0.4 → 7.1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1076 -230
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -6
- data/lib/active_support/actionable_error.rb +3 -1
- data/lib/active_support/array_inquirer.rb +2 -0
- data/lib/active_support/backtrace_cleaner.rb +30 -5
- data/lib/active_support/benchmarkable.rb +1 -0
- data/lib/active_support/broadcast_logger.rb +251 -0
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +37 -10
- data/lib/active_support/cache/mem_cache_store.rb +100 -76
- data/lib/active_support/cache/memory_store.rb +78 -24
- data/lib/active_support/cache/null_store.rb +6 -0
- data/lib/active_support/cache/redis_cache_store.rb +153 -141
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +29 -14
- data/lib/active_support/cache.rb +333 -253
- data/lib/active_support/callbacks.rb +44 -21
- data/lib/active_support/code_generator.rb +15 -10
- data/lib/active_support/concern.rb +4 -2
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/configurable.rb +10 -0
- data/lib/active_support/core_ext/array/conversions.rb +2 -1
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/class/subclasses.rb +13 -10
- data/lib/active_support/core_ext/date/calculations.rb +15 -0
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date.rb +0 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +6 -2
- data/lib/active_support/core_ext/date_time.rb +0 -1
- data/lib/active_support/core_ext/digest/uuid.rb +1 -10
- data/lib/active_support/core_ext/enumerable.rb +8 -75
- data/lib/active_support/core_ext/erb/util.rb +196 -0
- data/lib/active_support/core_ext/hash/conversions.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +3 -3
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
- data/lib/active_support/core_ext/module/concerning.rb +6 -6
- data/lib/active_support/core_ext/module/delegation.rb +81 -37
- data/lib/active_support/core_ext/module/deprecation.rb +15 -12
- data/lib/active_support/core_ext/module/introspection.rb +0 -1
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +2 -0
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
- data/lib/active_support/core_ext/object/duplicable.rb +25 -16
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
- data/lib/active_support/core_ext/object/json.rb +16 -6
- data/lib/active_support/core_ext/object/to_query.rb +0 -2
- data/lib/active_support/core_ext/object/with.rb +44 -0
- data/lib/active_support/core_ext/object/with_options.rb +9 -9
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +16 -0
- data/lib/active_support/core_ext/pathname/existence.rb +2 -0
- data/lib/active_support/core_ext/pathname.rb +1 -0
- data/lib/active_support/core_ext/range/conversions.rb +28 -7
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +24 -12
- data/lib/active_support/core_ext/string/filters.rb +20 -14
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +16 -9
- data/lib/active_support/core_ext/string/output_safety.rb +42 -174
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +22 -2
- data/lib/active_support/core_ext/time/conversions.rb +2 -2
- data/lib/active_support/core_ext/time/zones.rb +7 -8
- data/lib/active_support/core_ext/time.rb +0 -1
- data/lib/active_support/current_attributes.rb +15 -6
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/dependencies/autoload.rb +17 -12
- data/lib/active_support/deprecation/behaviors.rb +65 -42
- data/lib/active_support/deprecation/constant_accessor.rb +5 -4
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +6 -8
- data/lib/active_support/deprecation/instance_delegator.rb +31 -4
- data/lib/active_support/deprecation/method_wrappers.rb +6 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
- data/lib/active_support/deprecation/reporting.rb +43 -26
- data/lib/active_support/deprecation.rb +32 -5
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +104 -132
- data/lib/active_support/duration/iso8601_serializer.rb +0 -2
- data/lib/active_support/duration.rb +2 -1
- data/lib/active_support/encrypted_configuration.rb +63 -11
- data/lib/active_support/encrypted_file.rb +16 -12
- data/lib/active_support/environment_inquirer.rb +22 -2
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +121 -35
- data/lib/active_support/evented_file_update_checker.rb +17 -2
- data/lib/active_support/execution_wrapper.rb +4 -4
- data/lib/active_support/file_update_checker.rb +4 -2
- data/lib/active_support/fork_tracker.rb +10 -2
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +35 -17
- data/lib/active_support/html_safe_translation.rb +16 -6
- data/lib/active_support/i18n.rb +1 -1
- data/lib/active_support/i18n_railtie.rb +20 -13
- data/lib/active_support/inflector/inflections.rb +2 -0
- data/lib/active_support/inflector/methods.rb +28 -18
- data/lib/active_support/inflector/transliterate.rb +3 -1
- data/lib/active_support/isolated_execution_state.rb +26 -22
- data/lib/active_support/json/decoding.rb +2 -1
- data/lib/active_support/json/encoding.rb +25 -43
- data/lib/active_support/key_generator.rb +9 -1
- data/lib/active_support/lazy_load_hooks.rb +7 -5
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber.rb +85 -33
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_thread_safe_level.rb +10 -24
- data/lib/active_support/message_encryptor.rb +197 -53
- data/lib/active_support/message_encryptors.rb +141 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +292 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +212 -93
- data/lib/active_support/message_verifiers.rb +135 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +111 -45
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +34 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +2 -0
- data/lib/active_support/multibyte/unicode.rb +9 -37
- data/lib/active_support/notifications/fanout.rb +245 -81
- data/lib/active_support/notifications/instrumenter.rb +87 -22
- data/lib/active_support/notifications.rb +3 -3
- data/lib/active_support/number_helper/number_converter.rb +14 -5
- data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
- data/lib/active_support/number_helper.rb +379 -317
- data/lib/active_support/ordered_hash.rb +3 -3
- data/lib/active_support/ordered_options.rb +14 -0
- data/lib/active_support/parameter_filter.rb +103 -84
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/railtie.rb +33 -21
- data/lib/active_support/reloader.rb +12 -4
- data/lib/active_support/rescuable.rb +2 -0
- data/lib/active_support/secure_compare_rotator.rb +16 -9
- data/lib/active_support/string_inquirer.rb +3 -1
- data/lib/active_support/subscriber.rb +9 -27
- data/lib/active_support/syntax_error_proxy.rb +60 -0
- data/lib/active_support/tagged_logging.rb +64 -24
- data/lib/active_support/test_case.rb +153 -6
- data/lib/active_support/testing/assertions.rb +26 -10
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +32 -0
- data/lib/active_support/testing/deprecation.rb +25 -25
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +29 -28
- data/lib/active_support/testing/method_call_assertions.rb +21 -8
- data/lib/active_support/testing/parallelize_executor.rb +8 -3
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/stream.rb +1 -1
- data/lib/active_support/testing/strict_warnings.rb +39 -0
- data/lib/active_support/testing/time_helpers.rb +37 -15
- data/lib/active_support/time_with_zone.rb +8 -37
- data/lib/active_support/values/time_zone.rb +18 -7
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +3 -10
- data/lib/active_support/xml_mini/nokogiri.rb +1 -1
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +2 -2
- data/lib/active_support.rb +14 -3
- metadata +148 -19
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -26
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -22
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -26
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -7
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -22
- data/lib/active_support/core_ext/uri.rb +0 -5
- data/lib/active_support/per_thread_registry.rb +0 -65
@@ -7,9 +7,9 @@ class Module
|
|
7
7
|
# option is not used.
|
8
8
|
class DelegationError < NoMethodError; end
|
9
9
|
|
10
|
-
RUBY_RESERVED_KEYWORDS = %w(alias and BEGIN begin break
|
11
|
-
else elsif END end ensure false for if in module next nil
|
12
|
-
return self super then true undef unless until when while yield)
|
10
|
+
RUBY_RESERVED_KEYWORDS = %w(__ENCODING__ __LINE__ __FILE__ alias and BEGIN begin break
|
11
|
+
case class def defined? do else elsif END end ensure false for if in module next nil
|
12
|
+
not or redo rescue retry return self super then true undef unless until when while yield)
|
13
13
|
DELEGATION_RESERVED_KEYWORDS = %w(_ arg args block)
|
14
14
|
DELEGATION_RESERVED_METHOD_NAMES = Set.new(
|
15
15
|
RUBY_RESERVED_KEYWORDS + DELEGATION_RESERVED_KEYWORDS
|
@@ -187,19 +187,49 @@ class Module
|
|
187
187
|
location = caller_locations(1, 1).first
|
188
188
|
file, line = location.path, location.lineno
|
189
189
|
|
190
|
-
|
191
|
-
|
190
|
+
receiver = to.to_s
|
191
|
+
receiver = "self.#{receiver}" if DELEGATION_RESERVED_METHOD_NAMES.include?(receiver)
|
192
192
|
|
193
193
|
method_def = []
|
194
194
|
method_names = []
|
195
195
|
|
196
|
-
|
196
|
+
method_def << "self.private" if private
|
197
|
+
|
198
|
+
methods.each do |method|
|
197
199
|
method_name = prefix ? "#{method_prefix}#{method}" : method
|
198
200
|
method_names << method_name.to_sym
|
199
201
|
|
200
202
|
# Attribute writer methods only accept one argument. Makes sure []=
|
201
203
|
# methods still accept two arguments.
|
202
|
-
definition =
|
204
|
+
definition = \
|
205
|
+
if /[^\]]=\z/.match?(method)
|
206
|
+
"arg"
|
207
|
+
else
|
208
|
+
method_object =
|
209
|
+
begin
|
210
|
+
if to.is_a?(Module)
|
211
|
+
to.method(method)
|
212
|
+
elsif receiver == "self.class"
|
213
|
+
method(method)
|
214
|
+
end
|
215
|
+
rescue NameError
|
216
|
+
# Do nothing. Fall back to `"..."`
|
217
|
+
end
|
218
|
+
|
219
|
+
if method_object
|
220
|
+
parameters = method_object.parameters
|
221
|
+
|
222
|
+
if (parameters.map(&:first) & [:opt, :rest, :keyreq, :key, :keyrest]).any?
|
223
|
+
"..."
|
224
|
+
else
|
225
|
+
defn = parameters.filter_map { |type, arg| arg if type == :req }
|
226
|
+
defn << "&block"
|
227
|
+
defn.join(", ")
|
228
|
+
end
|
229
|
+
else
|
230
|
+
"..."
|
231
|
+
end
|
232
|
+
end
|
203
233
|
|
204
234
|
# The following generated method calls the target exactly once, storing
|
205
235
|
# the returned value in a dummy variable.
|
@@ -213,7 +243,7 @@ class Module
|
|
213
243
|
|
214
244
|
method_def <<
|
215
245
|
"def #{method_name}(#{definition})" <<
|
216
|
-
" _ = #{
|
246
|
+
" _ = #{receiver}" <<
|
217
247
|
" if !_.nil? || nil.respond_to?(:#{method})" <<
|
218
248
|
" _.#{method}(#{definition})" <<
|
219
249
|
" end" <<
|
@@ -224,11 +254,11 @@ class Module
|
|
224
254
|
|
225
255
|
method_def <<
|
226
256
|
"def #{method_name}(#{definition})" <<
|
227
|
-
" _ = #{
|
257
|
+
" _ = #{receiver}" <<
|
228
258
|
" _.#{method}(#{definition})" <<
|
229
259
|
"rescue NoMethodError => e" <<
|
230
260
|
" if _.nil? && e.name == :#{method}" <<
|
231
|
-
%( raise DelegationError, "#{self}##{method_name} delegated to #{
|
261
|
+
%( raise DelegationError, "#{self}##{method_name} delegated to #{receiver}.#{method}, but #{receiver} is nil: \#{self.inspect}") <<
|
232
262
|
" else" <<
|
233
263
|
" raise" <<
|
234
264
|
" end" <<
|
@@ -236,7 +266,6 @@ class Module
|
|
236
266
|
end
|
237
267
|
end
|
238
268
|
module_eval(method_def.join(";"), file, line)
|
239
|
-
private(*method_names) if private
|
240
269
|
method_names
|
241
270
|
end
|
242
271
|
|
@@ -288,37 +317,52 @@ class Module
|
|
288
317
|
# of <tt>object</tt> add or remove instance variables.
|
289
318
|
def delegate_missing_to(target, allow_nil: nil)
|
290
319
|
target = target.to_s
|
291
|
-
target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
|
320
|
+
target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target) || target == "__target"
|
292
321
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
322
|
+
if allow_nil
|
323
|
+
module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
324
|
+
def respond_to_missing?(name, include_private = false)
|
325
|
+
# It may look like an oversight, but we deliberately do not pass
|
326
|
+
# +include_private+, because they do not get delegated.
|
297
327
|
|
298
|
-
|
299
|
-
|
300
|
-
|
328
|
+
return false if name == :marshal_dump || name == :_dump
|
329
|
+
#{target}.respond_to?(name) || super
|
330
|
+
end
|
301
331
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
332
|
+
def method_missing(method, *args, &block)
|
333
|
+
__target = #{target}
|
334
|
+
if __target.nil? && !nil.respond_to?(method)
|
335
|
+
nil
|
336
|
+
elsif __target.respond_to?(method)
|
337
|
+
__target.public_send(method, *args, &block)
|
338
|
+
else
|
307
339
|
super
|
308
|
-
rescue NoMethodError
|
309
|
-
if #{target}.nil?
|
310
|
-
if #{allow_nil == true}
|
311
|
-
nil
|
312
|
-
else
|
313
|
-
raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
|
314
|
-
end
|
315
|
-
else
|
316
|
-
raise
|
317
|
-
end
|
318
340
|
end
|
319
341
|
end
|
320
|
-
|
321
|
-
|
322
|
-
|
342
|
+
ruby2_keywords(:method_missing)
|
343
|
+
RUBY
|
344
|
+
else
|
345
|
+
module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
346
|
+
def respond_to_missing?(name, include_private = false)
|
347
|
+
# It may look like an oversight, but we deliberately do not pass
|
348
|
+
# +include_private+, because they do not get delegated.
|
349
|
+
|
350
|
+
return false if name == :marshal_dump || name == :_dump
|
351
|
+
#{target}.respond_to?(name) || super
|
352
|
+
end
|
353
|
+
|
354
|
+
def method_missing(method, *args, &block)
|
355
|
+
__target = #{target}
|
356
|
+
if __target.nil? && !nil.respond_to?(method)
|
357
|
+
raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
|
358
|
+
elsif __target.respond_to?(method)
|
359
|
+
__target.public_send(method, *args, &block)
|
360
|
+
else
|
361
|
+
super
|
362
|
+
end
|
363
|
+
end
|
364
|
+
ruby2_keywords(:method_missing)
|
365
|
+
RUBY
|
366
|
+
end
|
323
367
|
end
|
324
368
|
end
|
@@ -1,17 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Module
|
4
|
-
# deprecate :foo
|
5
|
-
# deprecate bar:
|
6
|
-
# deprecate :foo, :bar, baz: 'warning!', qux: 'gone!'
|
4
|
+
# deprecate :foo, deprecator: MyLib.deprecator
|
5
|
+
# deprecate :foo, bar: "warning!", deprecator: MyLib.deprecator
|
7
6
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# deprecate :foo, bar: "warning!", deprecator: MyLib::Deprecator.new
|
12
|
-
#
|
13
|
-
# \Custom deprecators must respond to <tt>deprecation_warning(deprecated_method_name, message, caller_backtrace)</tt>
|
14
|
-
# method where you can implement your custom warning behavior.
|
7
|
+
# A deprecator is typically an instance of ActiveSupport::Deprecation, but you can also pass any object that responds
|
8
|
+
# to <tt>deprecation_warning(deprecated_method_name, message, caller_backtrace)</tt> where you can implement your
|
9
|
+
# custom warning behavior.
|
15
10
|
#
|
16
11
|
# class MyLib::Deprecator
|
17
12
|
# def deprecation_warning(deprecated_method_name, message, caller_backtrace = nil)
|
@@ -19,7 +14,15 @@ class Module
|
|
19
14
|
# Kernel.warn message
|
20
15
|
# end
|
21
16
|
# end
|
22
|
-
def deprecate(*method_names)
|
23
|
-
ActiveSupport::Deprecation
|
17
|
+
def deprecate(*method_names, deprecator: nil, **options)
|
18
|
+
if deprecator.is_a?(ActiveSupport::Deprecation)
|
19
|
+
deprecator.deprecate_methods(self, *method_names, **options)
|
20
|
+
elsif deprecator
|
21
|
+
# we just need any instance to call deprecate_methods, but the deprecation will be emitted by deprecator
|
22
|
+
ActiveSupport.deprecator.deprecate_methods(self, *method_names, **options, deprecator: deprecator)
|
23
|
+
else
|
24
|
+
ActiveSupport.deprecator.warn("Module.deprecate without a deprecator is deprecated")
|
25
|
+
ActiveSupport::Deprecation._instance.deprecate_methods(self, *method_names, **options)
|
26
|
+
end
|
24
27
|
end
|
25
28
|
end
|
@@ -7,6 +7,7 @@ class Numeric
|
|
7
7
|
TERABYTE = GIGABYTE * 1024
|
8
8
|
PETABYTE = TERABYTE * 1024
|
9
9
|
EXABYTE = PETABYTE * 1024
|
10
|
+
ZETTABYTE = EXABYTE * 1024
|
10
11
|
|
11
12
|
# Enables the use of byte calculations and declarations, like 45.bytes + 2.6.megabytes
|
12
13
|
#
|
@@ -63,4 +64,12 @@ class Numeric
|
|
63
64
|
self * EXABYTE
|
64
65
|
end
|
65
66
|
alias :exabyte :exabytes
|
67
|
+
|
68
|
+
# Returns the number of bytes equivalent to the zettabytes provided.
|
69
|
+
#
|
70
|
+
# 2.zettabytes # => 2_361_183_241_434_822_606_848
|
71
|
+
def zettabytes
|
72
|
+
self * ZETTABYTE
|
73
|
+
end
|
74
|
+
alias :zettabyte :zettabytes
|
66
75
|
end
|
@@ -5,6 +5,8 @@ require "active_support/number_helper"
|
|
5
5
|
|
6
6
|
module ActiveSupport
|
7
7
|
module NumericWithFormat
|
8
|
+
# \Numeric With Format
|
9
|
+
#
|
8
10
|
# Provides options for converting numbers into formatted strings.
|
9
11
|
# Options are provided for phone numbers, currency, percentage,
|
10
12
|
# precision, positional notation, file size, and pretty printing.
|
@@ -3,4 +3,3 @@
|
|
3
3
|
require "active_support/core_ext/numeric/bytes"
|
4
4
|
require "active_support/core_ext/numeric/time"
|
5
5
|
require "active_support/core_ext/numeric/conversions"
|
6
|
-
require "active_support/core_ext/numeric/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
|
@@ -53,3 +53,19 @@ class Hash
|
|
53
53
|
hash
|
54
54
|
end
|
55
55
|
end
|
56
|
+
|
57
|
+
class Module
|
58
|
+
# Returns a copy of module or class if it's anonymous. If it's
|
59
|
+
# named, returns +self+.
|
60
|
+
#
|
61
|
+
# Object.deep_dup == Object # => true
|
62
|
+
# klass = Class.new
|
63
|
+
# klass.deep_dup == klass # => false
|
64
|
+
def deep_dup
|
65
|
+
if name.nil?
|
66
|
+
super
|
67
|
+
else
|
68
|
+
self
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -28,23 +28,32 @@ class Object
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
def duplicable?
|
37
|
-
false
|
38
|
-
end
|
31
|
+
methods_are_duplicable = begin
|
32
|
+
Object.instance_method(:duplicable?).dup
|
33
|
+
true
|
34
|
+
rescue TypeError
|
35
|
+
false
|
39
36
|
end
|
40
37
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
38
|
+
unless methods_are_duplicable
|
39
|
+
class Method
|
40
|
+
# Methods are not duplicable:
|
41
|
+
#
|
42
|
+
# method(:puts).duplicable? # => false
|
43
|
+
# method(:puts).dup # => TypeError: allocator undefined for Method
|
44
|
+
def duplicable?
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class UnboundMethod
|
50
|
+
# Unbound methods are not duplicable:
|
51
|
+
#
|
52
|
+
# method(:puts).unbind.duplicable? # => false
|
53
|
+
# method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
|
54
|
+
def duplicable?
|
55
|
+
false
|
56
|
+
end
|
48
57
|
end
|
49
58
|
end
|
50
59
|
|
@@ -53,7 +62,7 @@ require "singleton"
|
|
53
62
|
module Singleton
|
54
63
|
# Singleton instances are not duplicable:
|
55
64
|
#
|
56
|
-
#
|
65
|
+
# Class.new.include(Singleton).instance.dup # TypeError (can't dup instance of singleton
|
57
66
|
def duplicable?
|
58
67
|
false
|
59
68
|
end
|
@@ -1,16 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Object
|
4
|
-
# Returns true if this object is included in the argument.
|
5
|
-
#
|
4
|
+
# Returns true if this object is included in the argument.
|
5
|
+
#
|
6
|
+
# When argument is a +Range+, +#cover?+ is used to properly handle inclusion
|
7
|
+
# check within open ranges. Otherwise, argument must be any object which responds
|
8
|
+
# to +#include?+. Usage:
|
6
9
|
#
|
7
10
|
# characters = ["Konata", "Kagami", "Tsukasa"]
|
8
11
|
# "Konata".in?(characters) # => true
|
9
12
|
#
|
10
|
-
#
|
11
|
-
# to +#include?+.
|
13
|
+
# For non +Range+ arguments, this will throw an +ArgumentError+ if the argument
|
14
|
+
# doesn't respond to +#include?+.
|
12
15
|
def in?(another_object)
|
13
|
-
another_object
|
16
|
+
case another_object
|
17
|
+
when Range
|
18
|
+
another_object.cover?(self)
|
19
|
+
else
|
20
|
+
another_object.include?(self)
|
21
|
+
end
|
14
22
|
rescue NoMethodError
|
15
23
|
raise ArgumentError.new("The parameter passed to #in? must respond to #include?")
|
16
24
|
end
|
@@ -12,19 +12,29 @@ class Object
|
|
12
12
|
#
|
13
13
|
# C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
|
14
14
|
def instance_values
|
15
|
-
|
15
|
+
instance_variables.to_h do |ivar|
|
16
|
+
[ivar[1..-1].freeze, instance_variable_get(ivar)]
|
17
|
+
end
|
16
18
|
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
20
|
+
if Symbol.method_defined?(:name) # RUBY_VERSION >= "3.0"
|
21
|
+
# Returns an array of instance variable names as strings including "@".
|
22
|
+
#
|
23
|
+
# class C
|
24
|
+
# def initialize(x, y)
|
25
|
+
# @x, @y = x, y
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# C.new(0, 1).instance_variable_names # => ["@y", "@x"]
|
30
|
+
def instance_variable_names
|
31
|
+
instance_variables.map(&:name)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
def instance_variable_names
|
35
|
+
variables = instance_variables
|
36
|
+
variables.map! { |s| s.to_s.freeze }
|
37
|
+
variables
|
38
|
+
end
|
29
39
|
end
|
30
40
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Hack to load
|
3
|
+
# Hack to load JSON gem first so we can override its to_json.
|
4
4
|
require "json"
|
5
5
|
require "bigdecimal"
|
6
6
|
require "ipaddr"
|
@@ -29,7 +29,7 @@ require "active_support/core_ext/date/conversions"
|
|
29
29
|
# It should be noted that when using ::JSON.{generate,dump} directly, ActiveSupport's encoder is
|
30
30
|
# bypassed completely. This means that as_json won't be invoked and the JSON gem will simply
|
31
31
|
# ignore any options it does not natively understand. This also means that ::JSON.{generate,dump}
|
32
|
-
# should give exactly the same results with or without
|
32
|
+
# should give exactly the same results with or without Active Support.
|
33
33
|
|
34
34
|
module ActiveSupport
|
35
35
|
module ToJsonWithActiveSupportEncoder # :nodoc:
|
@@ -65,9 +65,17 @@ class Object
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
if RUBY_VERSION >= "3.2"
|
69
|
+
class Data # :nodoc:
|
70
|
+
def as_json(options = nil)
|
71
|
+
to_h.as_json(options)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
68
76
|
class Struct # :nodoc:
|
69
77
|
def as_json(options = nil)
|
70
|
-
|
78
|
+
to_h.as_json(options)
|
71
79
|
end
|
72
80
|
end
|
73
81
|
|
@@ -225,9 +233,11 @@ class Pathname # :nodoc:
|
|
225
233
|
end
|
226
234
|
end
|
227
235
|
|
228
|
-
|
229
|
-
|
230
|
-
|
236
|
+
unless IPAddr.method_defined?(:as_json, false)
|
237
|
+
class IPAddr # :nodoc:
|
238
|
+
def as_json(options = nil)
|
239
|
+
to_s
|
240
|
+
end
|
231
241
|
end
|
232
242
|
end
|
233
243
|
|
@@ -72,8 +72,6 @@ class Hash
|
|
72
72
|
#
|
73
73
|
# The string pairs "key=value" that conform the query string
|
74
74
|
# are sorted lexicographically in ascending order.
|
75
|
-
#
|
76
|
-
# This method is also aliased as +to_param+.
|
77
75
|
def to_query(namespace = nil)
|
78
76
|
query = filter_map do |key, value|
|
79
77
|
unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Object
|
4
|
+
# Set and restore public attributes around a block.
|
5
|
+
#
|
6
|
+
# client.timeout # => 5
|
7
|
+
# client.with(timeout: 1) do
|
8
|
+
# client.timeout # => 1
|
9
|
+
# end
|
10
|
+
# client.timeout # => 5
|
11
|
+
#
|
12
|
+
# This method is a shorthand for the common begin/ensure pattern:
|
13
|
+
#
|
14
|
+
# old_value = object.attribute
|
15
|
+
# begin
|
16
|
+
# object.attribute = new_value
|
17
|
+
# # do things
|
18
|
+
# ensure
|
19
|
+
# object.attribute = old_value
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# It can be used on any object as long as both the reader and writer methods
|
23
|
+
# are public.
|
24
|
+
def with(**attributes)
|
25
|
+
old_values = {}
|
26
|
+
begin
|
27
|
+
attributes.each do |key, value|
|
28
|
+
old_values[key] = public_send(key)
|
29
|
+
public_send("#{key}=", value)
|
30
|
+
end
|
31
|
+
yield
|
32
|
+
ensure
|
33
|
+
old_values.each do |key, old_value|
|
34
|
+
public_send("#{key}=", old_value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# #with isn't usable on immediates, so we might as well undefine the
|
41
|
+
# method in common immediate classes to avoid potential confusion.
|
42
|
+
[NilClass, TrueClass, FalseClass, Integer, Float, Symbol].each do |klass|
|
43
|
+
klass.undef_method(:with)
|
44
|
+
end
|
@@ -5,9 +5,9 @@ require "active_support/option_merger"
|
|
5
5
|
class Object
|
6
6
|
# An elegant way to factor duplication out of options passed to a series of
|
7
7
|
# method calls. Each method called in the block, with the block variable as
|
8
|
-
# the receiver, will have its options merged with the default +options+
|
9
|
-
# provided. Each method called on
|
10
|
-
# hash as its final argument.
|
8
|
+
# the receiver, will have its options merged with the default +options+
|
9
|
+
# <tt>Hash</tt> or <tt>Hash</tt>-like object provided. Each method called on
|
10
|
+
# the block variable must take an options hash as its final argument.
|
11
11
|
#
|
12
12
|
# Without <tt>with_options</tt>, this code contains duplication:
|
13
13
|
#
|
@@ -64,11 +64,11 @@ 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
|
71
|
-
# enum phone_number_type
|
71
|
+
# enum :phone_number_type, { home: 0, office: 1, mobile: 2 }
|
72
72
|
#
|
73
73
|
# with_options presence: true do
|
74
74
|
# validates :phone_number_type, inclusion: { in: Phone.phone_number_types.keys }
|
@@ -83,11 +83,11 @@ class Object
|
|
83
83
|
# end
|
84
84
|
# end
|
85
85
|
#
|
86
|
-
#
|
87
|
-
# #
|
86
|
+
# styled.link_to "I'm red", "/"
|
87
|
+
# # => <a href="/" style="color: red;">I'm red</a>
|
88
88
|
#
|
89
|
-
#
|
90
|
-
# #
|
89
|
+
# styled.button_tag "I'm red too!"
|
90
|
+
# # => <button style="color: red;">I'm red too!</button>
|
91
91
|
#
|
92
92
|
def with_options(options, &block)
|
93
93
|
option_merger = ActiveSupport::OptionMerger.new(self, options)
|
@@ -13,4 +13,5 @@ require "active_support/core_ext/object/instance_variables"
|
|
13
13
|
require "active_support/core_ext/object/json"
|
14
14
|
require "active_support/core_ext/object/to_param"
|
15
15
|
require "active_support/core_ext/object/to_query"
|
16
|
+
require "active_support/core_ext/object/with"
|
16
17
|
require "active_support/core_ext/object/with_options"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
class Pathname
|
6
|
+
# An Pathname is blank if it's empty:
|
7
|
+
#
|
8
|
+
# Pathname.new("").blank? # => true
|
9
|
+
# Pathname.new(" ").blank? # => false
|
10
|
+
# Pathname.new("test").blank? # => false
|
11
|
+
#
|
12
|
+
# @return [true, false]
|
13
|
+
def blank?
|
14
|
+
to_s.empty?
|
15
|
+
end
|
16
|
+
end
|
@@ -1,13 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
|
+
# = \Range With Format
|
4
5
|
module RangeWithFormat
|
5
6
|
RANGE_FORMATS = {
|
6
7
|
db: -> (start, stop) do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
if start && stop
|
9
|
+
case start
|
10
|
+
when String then "BETWEEN '#{start}' AND '#{stop}'"
|
11
|
+
else
|
12
|
+
"BETWEEN '#{start.to_fs(:db)}' AND '#{stop.to_fs(:db)}'"
|
13
|
+
end
|
14
|
+
elsif start
|
15
|
+
case start
|
16
|
+
when String then ">= '#{start}'"
|
17
|
+
else
|
18
|
+
">= '#{start.to_fs(:db)}'"
|
19
|
+
end
|
20
|
+
elsif stop
|
21
|
+
case stop
|
22
|
+
when String then "<= '#{stop}'"
|
23
|
+
else
|
24
|
+
"<= '#{stop.to_fs(:db)}'"
|
25
|
+
end
|
11
26
|
end
|
12
27
|
end
|
13
28
|
}
|
@@ -19,9 +34,15 @@ module ActiveSupport
|
|
19
34
|
# range = (1..100) # => 1..100
|
20
35
|
#
|
21
36
|
# range.to_s # => "1..100"
|
22
|
-
# range.to_fs(:db)
|
37
|
+
# range.to_fs(:db) # => "BETWEEN '1' AND '100'"
|
23
38
|
#
|
24
|
-
#
|
39
|
+
# range = (1..) # => 1..
|
40
|
+
# range.to_fs(:db) # => ">= '1'"
|
41
|
+
#
|
42
|
+
# range = (..100) # => ..100
|
43
|
+
# range.to_fs(:db) # => "<= '100'"
|
44
|
+
#
|
45
|
+
# == Adding your own range formats to to_fs
|
25
46
|
# You can add your own formats to the Range::RANGE_FORMATS hash.
|
26
47
|
# Use the format name as the hash key and a Proc instance.
|
27
48
|
#
|
@@ -29,7 +50,7 @@ module ActiveSupport
|
|
29
50
|
# Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_fs(:db)} and #{stop.to_fs(:db)}" }
|
30
51
|
def to_fs(format = :default)
|
31
52
|
if formatter = RANGE_FORMATS[format]
|
32
|
-
formatter.call(
|
53
|
+
formatter.call(self.begin, self.end)
|
33
54
|
else
|
34
55
|
to_s
|
35
56
|
end
|