activesupport 7.0.8.7 → 7.2.3
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 +229 -397
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -5
- data/lib/active_support/actionable_error.rb +3 -1
- data/lib/active_support/array_inquirer.rb +3 -1
- data/lib/active_support/backtrace_cleaner.rb +39 -7
- data/lib/active_support/benchmarkable.rb +1 -0
- data/lib/active_support/broadcast_logger.rb +238 -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 +51 -19
- data/lib/active_support/cache/mem_cache_store.rb +98 -134
- data/lib/active_support/cache/memory_store.rb +85 -30
- data/lib/active_support/cache/null_store.rb +8 -2
- data/lib/active_support/cache/redis_cache_store.rb +166 -153
- data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
- data/lib/active_support/cache/strategy/local_cache.rb +64 -13
- data/lib/active_support/cache.rb +364 -292
- data/lib/active_support/callbacks.rb +121 -136
- 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 +1 -2
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/benchmark.rb +1 -0
- data/lib/active_support/core_ext/class/attribute.rb +2 -2
- data/lib/active_support/core_ext/class/subclasses.rb +17 -34
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +1 -2
- 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_and_time/compatibility.rb +28 -1
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +6 -4
- data/lib/active_support/core_ext/date_time.rb +0 -1
- data/lib/active_support/core_ext/digest/uuid.rb +7 -10
- data/lib/active_support/core_ext/enumerable.rb +20 -80
- data/lib/active_support/core_ext/erb/util.rb +201 -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/keys.rb +4 -4
- data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
- 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 +20 -119
- data/lib/active_support/core_ext/module/deprecation.rb +12 -12
- data/lib/active_support/core_ext/module/introspection.rb +3 -1
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +5 -3
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +4 -2
- data/lib/active_support/core_ext/object/json.rb +17 -7
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/object/with.rb +46 -0
- data/lib/active_support/core_ext/object/with_options.rb +4 -4
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +20 -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/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +2 -2
- data/lib/active_support/core_ext/securerandom.rb +24 -12
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +24 -18
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +16 -5
- data/lib/active_support/core_ext/string/multibyte.rb +3 -3
- data/lib/active_support/core_ext/string/output_safety.rb +34 -177
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +36 -30
- data/lib/active_support/core_ext/time/compatibility.rb +24 -0
- data/lib/active_support/core_ext/time/conversions.rb +1 -3
- data/lib/active_support/core_ext/time/zones.rb +4 -4
- data/lib/active_support/core_ext/time.rb +0 -1
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/current_attributes.rb +60 -46
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/delegation.rb +202 -0
- data/lib/active_support/dependencies/autoload.rb +9 -16
- data/lib/active_support/deprecation/behaviors.rb +65 -42
- data/lib/active_support/deprecation/constant_accessor.rb +47 -25
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +3 -5
- data/lib/active_support/deprecation/method_wrappers.rb +6 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +34 -22
- data/lib/active_support/deprecation/reporting.rb +49 -27
- data/lib/active_support/deprecation.rb +39 -9
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +66 -172
- data/lib/active_support/duration/iso8601_parser.rb +2 -2
- data/lib/active_support/duration/iso8601_serializer.rb +1 -4
- data/lib/active_support/duration.rb +13 -7
- data/lib/active_support/encrypted_configuration.rb +30 -9
- data/lib/active_support/encrypted_file.rb +9 -4
- 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 +163 -36
- data/lib/active_support/evented_file_update_checker.rb +0 -1
- data/lib/active_support/execution_wrapper.rb +5 -6
- data/lib/active_support/file_update_checker.rb +6 -4
- data/lib/active_support/fork_tracker.rb +4 -32
- 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 +50 -30
- data/lib/active_support/html_safe_translation.rb +19 -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 +23 -11
- 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 +3 -2
- data/lib/active_support/json/encoding.rb +48 -48
- 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 +74 -34
- data/lib/active_support/logger.rb +22 -60
- data/lib/active_support/logger_thread_safe_level.rb +10 -32
- 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 +305 -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 +229 -89
- data/lib/active_support/message_verifiers.rb +137 -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 +38 -31
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +8 -3
- data/lib/active_support/multibyte/unicode.rb +9 -37
- data/lib/active_support/notifications/fanout.rb +248 -87
- data/lib/active_support/notifications/instrumenter.rb +93 -25
- data/lib/active_support/notifications.rb +29 -28
- data/lib/active_support/number_helper/number_converter.rb +16 -7
- 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 -318
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_hash.rb +3 -3
- data/lib/active_support/ordered_options.rb +67 -15
- data/lib/active_support/parameter_filter.rb +84 -69
- data/lib/active_support/proxy_object.rb +8 -3
- data/lib/active_support/railtie.rb +25 -20
- 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 +4 -2
- data/lib/active_support/subscriber.rb +10 -27
- data/lib/active_support/syntax_error_proxy.rb +60 -0
- data/lib/active_support/tagged_logging.rb +64 -25
- data/lib/active_support/test_case.rb +156 -7
- data/lib/active_support/testing/assertions.rb +28 -12
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +54 -0
- data/lib/active_support/testing/deprecation.rb +20 -27
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +21 -9
- data/lib/active_support/testing/method_call_assertions.rb +7 -8
- data/lib/active_support/testing/parallelization/server.rb +18 -2
- data/lib/active_support/testing/parallelization/worker.rb +2 -2
- data/lib/active_support/testing/parallelization.rb +12 -1
- 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/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +38 -16
- data/lib/active_support/time_with_zone.rb +12 -18
- data/lib/active_support/values/time_zone.rb +25 -14
- 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 +14 -3
- data/lib/active_support.rb +15 -3
- metadata +142 -24
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -40
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -36
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -36
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -73
- data/lib/active_support/core_ext/uri.rb +0 -5
- data/lib/active_support/deprecation/instance_delegator.rb +0 -38
- data/lib/active_support/per_thread_registry.rb +0 -65
- data/lib/active_support/ruby_features.rb +0 -7
|
@@ -1,41 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "active_support/
|
|
3
|
+
require "active_support/descendants_tracker"
|
|
4
4
|
|
|
5
5
|
class Class
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# C.descendants # => []
|
|
11
|
-
#
|
|
12
|
-
# class B < C; end
|
|
13
|
-
# C.descendants # => [B]
|
|
14
|
-
#
|
|
15
|
-
# class A < B; end
|
|
16
|
-
# C.descendants # => [B, A]
|
|
17
|
-
#
|
|
18
|
-
# class D < C; end
|
|
19
|
-
# C.descendants # => [B, A, D]
|
|
20
|
-
def descendants
|
|
21
|
-
subclasses.concat(subclasses.flat_map(&:descendants))
|
|
22
|
-
end
|
|
23
|
-
else
|
|
24
|
-
def descendants
|
|
25
|
-
ObjectSpace.each_object(singleton_class).reject do |k|
|
|
26
|
-
k.singleton_class? || k == self
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Returns an array with the direct children of +self+.
|
|
6
|
+
# Returns an array with all classes that are < than its receiver.
|
|
7
|
+
#
|
|
8
|
+
# class C; end
|
|
9
|
+
# C.descendants # => []
|
|
32
10
|
#
|
|
33
|
-
# class
|
|
34
|
-
#
|
|
35
|
-
# class Baz < Bar; end
|
|
11
|
+
# class B < C; end
|
|
12
|
+
# C.descendants # => [B]
|
|
36
13
|
#
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
14
|
+
# class A < B; end
|
|
15
|
+
# C.descendants # => [B, A]
|
|
16
|
+
#
|
|
17
|
+
# class D < C; end
|
|
18
|
+
# C.descendants # => [B, A, D]
|
|
19
|
+
def descendants
|
|
20
|
+
subclasses.concat(subclasses.flat_map(&:descendants))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
prepend ActiveSupport::DescendantsTracker::ReloadedClassesFiltering
|
|
41
24
|
end
|
|
@@ -52,11 +52,10 @@ class Date
|
|
|
52
52
|
strftime(formatter)
|
|
53
53
|
end
|
|
54
54
|
else
|
|
55
|
-
|
|
55
|
+
to_s
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
alias_method :to_formatted_s, :to_fs
|
|
59
|
-
alias_method :to_default_s, :to_s
|
|
60
59
|
|
|
61
60
|
# Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
|
|
62
61
|
def readable_inspect
|
|
@@ -4,5 +4,4 @@ require "active_support/core_ext/date/acts_like"
|
|
|
4
4
|
require "active_support/core_ext/date/blank"
|
|
5
5
|
require "active_support/core_ext/date/calculations"
|
|
6
6
|
require "active_support/core_ext/date/conversions"
|
|
7
|
-
require "active_support/core_ext/date/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
|
|
8
7
|
require "active_support/core_ext/date/zones"
|
|
@@ -157,6 +157,16 @@ module DateAndTime
|
|
|
157
157
|
end
|
|
158
158
|
alias :at_end_of_quarter :end_of_quarter
|
|
159
159
|
|
|
160
|
+
# Returns the quarter for a date/time.
|
|
161
|
+
#
|
|
162
|
+
# Date.new(2010, 1, 31).quarter # => 1
|
|
163
|
+
# Date.new(2010, 4, 12).quarter # => 2
|
|
164
|
+
# Date.new(2010, 9, 15).quarter # => 3
|
|
165
|
+
# Date.new(2010, 12, 25).quarter # => 4
|
|
166
|
+
def quarter
|
|
167
|
+
(month / 3.0).ceil
|
|
168
|
+
end
|
|
169
|
+
|
|
160
170
|
# Returns a new date/time at the beginning of the year.
|
|
161
171
|
#
|
|
162
172
|
# today = Date.today # => Fri, 10 Jul 2015
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "active_support/core_ext/module/attribute_accessors"
|
|
4
|
+
require "active_support/core_ext/module/redefine_method"
|
|
4
5
|
|
|
5
6
|
module DateAndTime
|
|
6
7
|
module Compatibility
|
|
@@ -11,7 +12,33 @@ module DateAndTime
|
|
|
11
12
|
# of the receiver. For backwards compatibility we're overriding
|
|
12
13
|
# this behavior, but new apps will have an initializer that sets
|
|
13
14
|
# this to true, because the new behavior is preferred.
|
|
14
|
-
mattr_accessor :preserve_timezone,
|
|
15
|
+
mattr_accessor :preserve_timezone, instance_accessor: false, default: nil
|
|
16
|
+
|
|
17
|
+
singleton_class.silence_redefinition_of_method :preserve_timezone
|
|
18
|
+
|
|
19
|
+
#--
|
|
20
|
+
# This re-implements the behaviour of the mattr_reader, instead
|
|
21
|
+
# of prepending on to it, to avoid overcomplicating a module that
|
|
22
|
+
# is in turn included in several places. This will all go away in
|
|
23
|
+
# Rails 8.0 anyway.
|
|
24
|
+
def self.preserve_timezone # :nodoc:
|
|
25
|
+
if @@preserve_timezone.nil?
|
|
26
|
+
# Only warn once, the first time the value is used (which should
|
|
27
|
+
# be the first time #to_time is called).
|
|
28
|
+
ActiveSupport.deprecator.warn(
|
|
29
|
+
"to_time will always preserve the timezone offset of the receiver in Rails 8.0. " \
|
|
30
|
+
"To opt in to the new behavior, set `ActiveSupport.to_time_preserves_timezone = true`."
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
@@preserve_timezone = false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
@@preserve_timezone
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def preserve_timezone # :nodoc:
|
|
40
|
+
Compatibility.preserve_timezone
|
|
41
|
+
end
|
|
15
42
|
|
|
16
43
|
# Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
|
|
17
44
|
#
|
|
@@ -11,7 +11,8 @@ class DateTime
|
|
|
11
11
|
#
|
|
12
12
|
# This method is aliased to <tt>to_formatted_s</tt>.
|
|
13
13
|
#
|
|
14
|
-
#
|
|
14
|
+
# ==== Examples
|
|
15
|
+
#
|
|
15
16
|
# datetime = DateTime.civil(2007, 12, 4, 0, 0, 0, 0) # => Tue, 04 Dec 2007 00:00:00 +0000
|
|
16
17
|
#
|
|
17
18
|
# datetime.to_fs(:db) # => "2007-12-04 00:00:00"
|
|
@@ -23,7 +24,8 @@ class DateTime
|
|
|
23
24
|
# datetime.to_fs(:rfc822) # => "Tue, 04 Dec 2007 00:00:00 +0000"
|
|
24
25
|
# datetime.to_fs(:iso8601) # => "2007-12-04T00:00:00+00:00"
|
|
25
26
|
#
|
|
26
|
-
#
|
|
27
|
+
# ==== Adding your own datetime formats to +to_fs+
|
|
28
|
+
#
|
|
27
29
|
# DateTime formats are shared with Time. You can add your own to the
|
|
28
30
|
# Time::DATE_FORMATS hash. Use the format name as the hash key and
|
|
29
31
|
# either a strftime string or Proc instance that takes a time or
|
|
@@ -36,11 +38,11 @@ class DateTime
|
|
|
36
38
|
if formatter = ::Time::DATE_FORMATS[format]
|
|
37
39
|
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
|
38
40
|
else
|
|
39
|
-
|
|
41
|
+
to_s
|
|
40
42
|
end
|
|
41
43
|
end
|
|
42
44
|
alias_method :to_formatted_s, :to_fs
|
|
43
|
-
|
|
45
|
+
|
|
44
46
|
|
|
45
47
|
# Returns a formatted string of the offset from UTC, or an alternative
|
|
46
48
|
# string if the time zone is already UTC.
|
|
@@ -5,4 +5,3 @@ require "active_support/core_ext/date_time/blank"
|
|
|
5
5
|
require "active_support/core_ext/date_time/calculations"
|
|
6
6
|
require "active_support/core_ext/date_time/compatibility"
|
|
7
7
|
require "active_support/core_ext/date_time/conversions"
|
|
8
|
-
require "active_support/core_ext/date_time/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
|
|
@@ -10,8 +10,6 @@ module Digest
|
|
|
10
10
|
OID_NAMESPACE = "k\xA7\xB8\x12\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
|
|
11
11
|
X500_NAMESPACE = "k\xA7\xB8\x14\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
|
|
12
12
|
|
|
13
|
-
mattr_accessor :use_rfc4122_namespaced_uuids, instance_accessor: false, default: false
|
|
14
|
-
|
|
15
13
|
# Generates a v5 non-random UUID (Universally Unique IDentifier).
|
|
16
14
|
#
|
|
17
15
|
# Using OpenSSL::Digest::MD5 generates version 3 UUIDs; OpenSSL::Digest::SHA1 generates version 5 UUIDs.
|
|
@@ -55,22 +53,21 @@ module Digest
|
|
|
55
53
|
SecureRandom.uuid
|
|
56
54
|
end
|
|
57
55
|
|
|
56
|
+
# Returns the nil UUID. This is a special form of UUID that is specified to
|
|
57
|
+
# have all 128 bits set to zero.
|
|
58
|
+
def self.nil_uuid
|
|
59
|
+
"00000000-0000-0000-0000-000000000000"
|
|
60
|
+
end
|
|
61
|
+
|
|
58
62
|
def self.pack_uuid_namespace(namespace)
|
|
59
63
|
if [DNS_NAMESPACE, OID_NAMESPACE, URL_NAMESPACE, X500_NAMESPACE].include?(namespace)
|
|
60
64
|
namespace
|
|
61
|
-
|
|
65
|
+
else
|
|
62
66
|
match_data = namespace.match(/\A(\h{8})-(\h{4})-(\h{4})-(\h{4})-(\h{4})(\h{8})\z/)
|
|
63
67
|
|
|
64
68
|
raise ArgumentError, "Only UUIDs are valid namespace identifiers" unless match_data.present?
|
|
65
69
|
|
|
66
70
|
match_data.captures.map { |s| s.to_i(16) }.pack("NnnnnN")
|
|
67
|
-
else
|
|
68
|
-
ActiveSupport::Deprecation.warn <<~WARNING.squish
|
|
69
|
-
Providing a namespace ID that is not one of the constants defined on Digest::UUID generates an incorrect UUID value according to RFC 4122.
|
|
70
|
-
To enable the correct behavior, set the Rails.application.config.active_support.use_rfc4122_namespaced_uuids configuration option to true.
|
|
71
|
-
WARNING
|
|
72
|
-
|
|
73
|
-
namespace
|
|
74
71
|
end
|
|
75
72
|
end
|
|
76
73
|
|
|
@@ -25,18 +25,6 @@ module Enumerable
|
|
|
25
25
|
ActiveSupport::EnumerableCoreExt::SoleItemExpectedError = remove_const(:SoleItemExpectedError)
|
|
26
26
|
singleton_class.prepend(ActiveSupport::EnumerableCoreExt::Constants)
|
|
27
27
|
|
|
28
|
-
# Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
|
|
29
|
-
# when we omit an identity.
|
|
30
|
-
|
|
31
|
-
# :stopdoc:
|
|
32
|
-
|
|
33
|
-
# We can't use Refinements here because Refinements with Module which will be prepended
|
|
34
|
-
# doesn't work well https://bugs.ruby-lang.org/issues/13446
|
|
35
|
-
alias :_original_sum_with_required_identity :sum
|
|
36
|
-
private :_original_sum_with_required_identity
|
|
37
|
-
|
|
38
|
-
# :startdoc:
|
|
39
|
-
|
|
40
28
|
# Calculates the minimum from the extracted elements.
|
|
41
29
|
#
|
|
42
30
|
# payments = [Payment.new(5), Payment.new(15), Payment.new(10)]
|
|
@@ -53,50 +41,6 @@ module Enumerable
|
|
|
53
41
|
map(&key).max
|
|
54
42
|
end
|
|
55
43
|
|
|
56
|
-
# Calculates a sum from the elements.
|
|
57
|
-
#
|
|
58
|
-
# payments.sum { |p| p.price * p.tax_rate }
|
|
59
|
-
# payments.sum(&:price)
|
|
60
|
-
#
|
|
61
|
-
# The latter is a shortcut for:
|
|
62
|
-
#
|
|
63
|
-
# payments.inject(0) { |sum, p| sum + p.price }
|
|
64
|
-
#
|
|
65
|
-
# It can also calculate the sum without the use of a block.
|
|
66
|
-
#
|
|
67
|
-
# [5, 15, 10].sum # => 30
|
|
68
|
-
# ['foo', 'bar'].sum('') # => "foobar"
|
|
69
|
-
# [[1, 2], [3, 1, 5]].sum([]) # => [1, 2, 3, 1, 5]
|
|
70
|
-
#
|
|
71
|
-
# The default sum of an empty list is zero. You can override this default:
|
|
72
|
-
#
|
|
73
|
-
# [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
|
|
74
|
-
def sum(identity = nil, &block)
|
|
75
|
-
if identity
|
|
76
|
-
_original_sum_with_required_identity(identity, &block)
|
|
77
|
-
elsif block_given?
|
|
78
|
-
map(&block).sum
|
|
79
|
-
else
|
|
80
|
-
first = true
|
|
81
|
-
|
|
82
|
-
reduce(nil) do |sum, value|
|
|
83
|
-
if first
|
|
84
|
-
first = false
|
|
85
|
-
|
|
86
|
-
unless value.is_a?(Numeric) || value.respond_to?(:coerce)
|
|
87
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
|
88
|
-
Rails 7.0 has deprecated Enumerable.sum in favor of Ruby's native implementation available since 2.4.
|
|
89
|
-
Sum of non-numeric elements requires an initial argument.
|
|
90
|
-
MSG
|
|
91
|
-
end
|
|
92
|
-
value
|
|
93
|
-
else
|
|
94
|
-
sum + value
|
|
95
|
-
end
|
|
96
|
-
end || 0
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
44
|
# Convert an enumerable to a hash, using the block result as the key and the
|
|
101
45
|
# element as the value.
|
|
102
46
|
#
|
|
@@ -254,16 +198,28 @@ module Enumerable
|
|
|
254
198
|
end
|
|
255
199
|
|
|
256
200
|
# Returns the sole item in the enumerable. If there are no items, or more
|
|
257
|
-
# than one item, raises
|
|
201
|
+
# than one item, raises Enumerable::SoleItemExpectedError.
|
|
258
202
|
#
|
|
259
203
|
# ["x"].sole # => "x"
|
|
260
204
|
# Set.new.sole # => Enumerable::SoleItemExpectedError: no item found
|
|
261
205
|
# { a: 1, b: 2 }.sole # => Enumerable::SoleItemExpectedError: multiple items found
|
|
262
206
|
def sole
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
207
|
+
result = nil
|
|
208
|
+
found = false
|
|
209
|
+
|
|
210
|
+
each do |*element|
|
|
211
|
+
if found
|
|
212
|
+
raise SoleItemExpectedError, "multiple items found"
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
result = element.size == 1 ? element[0] : element
|
|
216
|
+
found = true
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
if found
|
|
220
|
+
result
|
|
221
|
+
else
|
|
222
|
+
raise SoleItemExpectedError, "no item found"
|
|
267
223
|
end
|
|
268
224
|
end
|
|
269
225
|
end
|
|
@@ -289,38 +245,22 @@ end
|
|
|
289
245
|
class Range # :nodoc:
|
|
290
246
|
# Optimize range sum to use arithmetic progression if a block is not given and
|
|
291
247
|
# we have a range of numeric values.
|
|
292
|
-
def sum(
|
|
248
|
+
def sum(initial_value = 0)
|
|
293
249
|
if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
|
|
294
250
|
super
|
|
295
251
|
else
|
|
296
252
|
actual_last = exclude_end? ? (last - 1) : last
|
|
297
253
|
if actual_last >= first
|
|
298
|
-
sum =
|
|
254
|
+
sum = initial_value || 0
|
|
299
255
|
sum + (actual_last - first + 1) * (actual_last + first) / 2
|
|
300
256
|
else
|
|
301
|
-
|
|
257
|
+
initial_value || 0
|
|
302
258
|
end
|
|
303
259
|
end
|
|
304
260
|
end
|
|
305
261
|
end
|
|
306
262
|
|
|
307
|
-
# Using Refinements here in order not to expose our internal method
|
|
308
|
-
using Module.new {
|
|
309
|
-
refine Array do
|
|
310
|
-
alias :orig_sum :sum
|
|
311
|
-
end
|
|
312
|
-
}
|
|
313
|
-
|
|
314
263
|
class Array # :nodoc:
|
|
315
|
-
def sum(init = nil, &block)
|
|
316
|
-
if init.is_a?(Numeric) || first.is_a?(Numeric)
|
|
317
|
-
init ||= 0
|
|
318
|
-
orig_sum(init, &block)
|
|
319
|
-
else
|
|
320
|
-
super
|
|
321
|
-
end
|
|
322
|
-
end
|
|
323
|
-
|
|
324
264
|
# Removes all blank elements from the +Array+ in place and returns self.
|
|
325
265
|
# Uses Object#blank? for determining if an item is blank.
|
|
326
266
|
#
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "erb"
|
|
4
|
+
|
|
5
|
+
module ActiveSupport
|
|
6
|
+
module CoreExt
|
|
7
|
+
module ERBUtil
|
|
8
|
+
# HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
|
|
9
|
+
# This method is not for public consumption! Seriously!
|
|
10
|
+
def html_escape(s) # :nodoc:
|
|
11
|
+
s = s.to_s
|
|
12
|
+
if s.html_safe?
|
|
13
|
+
s
|
|
14
|
+
else
|
|
15
|
+
super(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
alias :unwrapped_html_escape :html_escape # :nodoc:
|
|
19
|
+
|
|
20
|
+
# A utility method for escaping HTML tag characters.
|
|
21
|
+
# This method is also aliased as <tt>h</tt>.
|
|
22
|
+
#
|
|
23
|
+
# puts html_escape('is a > 0 & a < 10?')
|
|
24
|
+
# # => is a > 0 & a < 10?
|
|
25
|
+
def html_escape(s) # rubocop:disable Lint/DuplicateMethods
|
|
26
|
+
unwrapped_html_escape(s).html_safe
|
|
27
|
+
end
|
|
28
|
+
alias h html_escape
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
module ERBUtilPrivate
|
|
32
|
+
include ERBUtil
|
|
33
|
+
private :unwrapped_html_escape, :html_escape, :h
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class ERB
|
|
39
|
+
module Util
|
|
40
|
+
HTML_ESCAPE = { "&" => "&", ">" => ">", "<" => "<", '"' => """, "'" => "'" }
|
|
41
|
+
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
|
|
42
|
+
|
|
43
|
+
# Following XML requirements: https://www.w3.org/TR/REC-xml/#NT-Name
|
|
44
|
+
TAG_NAME_START_CODEPOINTS = "@:A-Z_a-z\u{C0}-\u{D6}\u{D8}-\u{F6}\u{F8}-\u{2FF}\u{370}-\u{37D}\u{37F}-\u{1FFF}" \
|
|
45
|
+
"\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \
|
|
46
|
+
"\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}"
|
|
47
|
+
INVALID_TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_CODEPOINTS}]/
|
|
48
|
+
TAG_NAME_FOLLOWING_CODEPOINTS = "#{TAG_NAME_START_CODEPOINTS}\\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}"
|
|
49
|
+
INVALID_TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_FOLLOWING_CODEPOINTS}]/
|
|
50
|
+
SAFE_XML_TAG_NAME_REGEXP = /\A[#{TAG_NAME_START_CODEPOINTS}][#{TAG_NAME_FOLLOWING_CODEPOINTS}]*\z/
|
|
51
|
+
TAG_NAME_REPLACEMENT_CHAR = "_"
|
|
52
|
+
|
|
53
|
+
prepend ActiveSupport::CoreExt::ERBUtilPrivate
|
|
54
|
+
singleton_class.prepend ActiveSupport::CoreExt::ERBUtil
|
|
55
|
+
|
|
56
|
+
# A utility method for escaping HTML without affecting existing escaped entities.
|
|
57
|
+
#
|
|
58
|
+
# html_escape_once('1 < 2 & 3')
|
|
59
|
+
# # => "1 < 2 & 3"
|
|
60
|
+
#
|
|
61
|
+
# html_escape_once('<< Accept & Checkout')
|
|
62
|
+
# # => "<< Accept & Checkout"
|
|
63
|
+
def html_escape_once(s)
|
|
64
|
+
ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE).html_safe
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
module_function :html_escape_once
|
|
68
|
+
|
|
69
|
+
# A utility method for escaping HTML entities in JSON strings. Specifically, the
|
|
70
|
+
# &, > and < characters are replaced with their equivalent unicode escaped form -
|
|
71
|
+
# \u0026, \u003e, and \u003c. The Unicode sequences \u2028 and \u2029 are also
|
|
72
|
+
# escaped as they are treated as newline characters in some JavaScript engines.
|
|
73
|
+
# These sequences have identical meaning as the original characters inside the
|
|
74
|
+
# context of a JSON string, so assuming the input is a valid and well-formed
|
|
75
|
+
# JSON value, the output will have equivalent meaning when parsed:
|
|
76
|
+
#
|
|
77
|
+
# json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
|
|
78
|
+
# # => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
|
|
79
|
+
#
|
|
80
|
+
# json_escape(json)
|
|
81
|
+
# # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
|
|
82
|
+
#
|
|
83
|
+
# JSON.parse(json) == JSON.parse(json_escape(json))
|
|
84
|
+
# # => true
|
|
85
|
+
#
|
|
86
|
+
# The intended use case for this method is to escape JSON strings before including
|
|
87
|
+
# them inside a script tag to avoid XSS vulnerability:
|
|
88
|
+
#
|
|
89
|
+
# <script>
|
|
90
|
+
# var currentUser = <%= raw json_escape(current_user.to_json) %>;
|
|
91
|
+
# </script>
|
|
92
|
+
#
|
|
93
|
+
# It is necessary to +raw+ the result of +json_escape+, so that quotation marks
|
|
94
|
+
# don't get converted to <tt>"</tt> entities. +json_escape+ doesn't
|
|
95
|
+
# automatically flag the result as HTML safe, since the raw value is unsafe to
|
|
96
|
+
# use inside HTML attributes.
|
|
97
|
+
#
|
|
98
|
+
# If your JSON is being used downstream for insertion into the DOM, be aware of
|
|
99
|
+
# whether or not it is being inserted via <tt>html()</tt>. Most jQuery plugins do this.
|
|
100
|
+
# If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
|
|
101
|
+
# content returned by your JSON.
|
|
102
|
+
#
|
|
103
|
+
# If you need to output JSON elsewhere in your HTML, you can just do something
|
|
104
|
+
# like this, as any unsafe characters (including quotation marks) will be
|
|
105
|
+
# automatically escaped for you:
|
|
106
|
+
#
|
|
107
|
+
# <div data-user-info="<%= current_user.to_json %>">...</div>
|
|
108
|
+
#
|
|
109
|
+
# WARNING: this helper only works with valid JSON. Using this on non-JSON values
|
|
110
|
+
# will open up serious XSS vulnerabilities. For example, if you replace the
|
|
111
|
+
# +current_user.to_json+ in the example above with user input instead, the browser
|
|
112
|
+
# will happily <tt>eval()</tt> that string as JavaScript.
|
|
113
|
+
#
|
|
114
|
+
# The escaping performed in this method is identical to those performed in the
|
|
115
|
+
# Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
|
|
116
|
+
# set to true. Because this transformation is idempotent, this helper can be
|
|
117
|
+
# applied even if +ActiveSupport.escape_html_entities_in_json+ is already true.
|
|
118
|
+
#
|
|
119
|
+
# Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+
|
|
120
|
+
# is enabled, or if you are unsure where your JSON string originated from, it
|
|
121
|
+
# is recommended that you always apply this helper (other libraries, such as the
|
|
122
|
+
# JSON gem, do not provide this kind of protection by default; also some gems
|
|
123
|
+
# might override +to_json+ to bypass Active Support's encoder).
|
|
124
|
+
def json_escape(s)
|
|
125
|
+
result = s.to_s.dup
|
|
126
|
+
result.gsub!(">", '\u003e')
|
|
127
|
+
result.gsub!("<", '\u003c')
|
|
128
|
+
result.gsub!("&", '\u0026')
|
|
129
|
+
result.gsub!("\u2028", '\u2028')
|
|
130
|
+
result.gsub!("\u2029", '\u2029')
|
|
131
|
+
s.html_safe? ? result.html_safe : result
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
module_function :json_escape
|
|
135
|
+
|
|
136
|
+
# A utility method for escaping XML names of tags and names of attributes.
|
|
137
|
+
#
|
|
138
|
+
# xml_name_escape('1 < 2 & 3')
|
|
139
|
+
# # => "1___2___3"
|
|
140
|
+
#
|
|
141
|
+
# It follows the requirements of the specification: https://www.w3.org/TR/REC-xml/#NT-Name
|
|
142
|
+
def xml_name_escape(name)
|
|
143
|
+
name = name.to_s
|
|
144
|
+
return "" if name.blank?
|
|
145
|
+
return name if name.match?(SAFE_XML_TAG_NAME_REGEXP)
|
|
146
|
+
|
|
147
|
+
starting_char = name[0]
|
|
148
|
+
starting_char.gsub!(INVALID_TAG_NAME_START_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
|
|
149
|
+
|
|
150
|
+
return starting_char if name.size == 1
|
|
151
|
+
|
|
152
|
+
following_chars = name[1..-1]
|
|
153
|
+
following_chars.gsub!(INVALID_TAG_NAME_FOLLOWING_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
|
|
154
|
+
|
|
155
|
+
starting_char << following_chars
|
|
156
|
+
end
|
|
157
|
+
module_function :xml_name_escape
|
|
158
|
+
|
|
159
|
+
# Tokenizes a line of ERB. This is really just for error reporting and
|
|
160
|
+
# nobody should use it.
|
|
161
|
+
def self.tokenize(source) # :nodoc:
|
|
162
|
+
require "strscan"
|
|
163
|
+
source = StringScanner.new(source.chomp)
|
|
164
|
+
tokens = []
|
|
165
|
+
|
|
166
|
+
start_re = /<%(?:={1,2}|-|\#|%)?/m
|
|
167
|
+
finish_re = /(?:[-=])?%>/m
|
|
168
|
+
|
|
169
|
+
while !source.eos?
|
|
170
|
+
pos = source.pos
|
|
171
|
+
source.scan_until(/(?:#{start_re}|#{finish_re})/)
|
|
172
|
+
raise NotImplementedError if source.matched.nil?
|
|
173
|
+
len = source.pos - source.matched.bytesize - pos
|
|
174
|
+
|
|
175
|
+
case source.matched
|
|
176
|
+
when start_re
|
|
177
|
+
tokens << [:TEXT, source.string.byteslice(pos, len)] if len > 0
|
|
178
|
+
tokens << [:OPEN, source.matched]
|
|
179
|
+
if source.scan(/(.*?)(?=#{finish_re}|\z)/m)
|
|
180
|
+
tokens << [:CODE, source.matched] unless source.matched.empty?
|
|
181
|
+
tokens << [:CLOSE, source.scan(finish_re)] unless source.eos?
|
|
182
|
+
else
|
|
183
|
+
raise NotImplementedError
|
|
184
|
+
end
|
|
185
|
+
when finish_re
|
|
186
|
+
tokens << [:CODE, source.string.byteslice(pos, len)] if len > 0
|
|
187
|
+
tokens << [:CLOSE, source.matched]
|
|
188
|
+
else
|
|
189
|
+
raise NotImplementedError, source.matched
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
unless source.eos? || source.exist?(start_re) || source.exist?(finish_re)
|
|
193
|
+
tokens << [:TEXT, source.rest]
|
|
194
|
+
source.terminate
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
tokens
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
@@ -68,7 +68,7 @@ class Hash
|
|
|
68
68
|
#
|
|
69
69
|
# By default the root node is "hash", but that's configurable via the <tt>:root</tt> option.
|
|
70
70
|
#
|
|
71
|
-
# The default XML builder is a fresh instance of
|
|
71
|
+
# The default XML builder is a fresh instance of +Builder::XmlMarkup+. You can
|
|
72
72
|
# configure your own builder with the <tt>:builder</tt> option. The method also accepts
|
|
73
73
|
# options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
|
|
74
74
|
def to_xml(options = {})
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/deep_mergeable"
|
|
4
|
+
|
|
3
5
|
class Hash
|
|
6
|
+
include ActiveSupport::DeepMergeable
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# :method: deep_merge
|
|
10
|
+
# :call-seq: deep_merge(other_hash, &block)
|
|
11
|
+
#
|
|
4
12
|
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
|
5
13
|
#
|
|
6
14
|
# h1 = { a: true, b: { c: [1, 2, 3] } }
|
|
@@ -15,20 +23,20 @@ class Hash
|
|
|
15
23
|
# h2 = { b: 250, c: { c1: 200 } }
|
|
16
24
|
# h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
|
|
17
25
|
# # => { a: 100, b: 450, c: { c1: 300 } }
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
#
|
|
27
|
+
#--
|
|
28
|
+
# Implemented by ActiveSupport::DeepMergeable#deep_merge.
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# :method: deep_merge!
|
|
32
|
+
# :call-seq: deep_merge!(other_hash, &block)
|
|
33
|
+
#
|
|
34
|
+
# Same as #deep_merge, but modifies +self+.
|
|
35
|
+
#
|
|
36
|
+
#--
|
|
37
|
+
# Implemented by ActiveSupport::DeepMergeable#deep_merge!.
|
|
21
38
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
merge!(other_hash) do |key, this_val, other_val|
|
|
25
|
-
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
|
|
26
|
-
this_val.deep_merge(other_val, &block)
|
|
27
|
-
elsif block_given?
|
|
28
|
-
block.call(key, this_val, other_val)
|
|
29
|
-
else
|
|
30
|
-
other_val
|
|
31
|
-
end
|
|
32
|
-
end
|
|
39
|
+
def deep_merge?(other) # :nodoc:
|
|
40
|
+
other.is_a?(Hash)
|
|
33
41
|
end
|
|
34
42
|
end
|
|
@@ -8,13 +8,13 @@ class Hash
|
|
|
8
8
|
# hash.stringify_keys
|
|
9
9
|
# # => {"name"=>"Rob", "age"=>"28"}
|
|
10
10
|
def stringify_keys
|
|
11
|
-
transform_keys
|
|
11
|
+
transform_keys { |k| Symbol === k ? k.name : k.to_s }
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
# Destructively converts all keys to strings. Same as
|
|
15
15
|
# +stringify_keys+, but modifies +self+.
|
|
16
16
|
def stringify_keys!
|
|
17
|
-
transform_keys!
|
|
17
|
+
transform_keys! { |k| Symbol === k ? k.name : k.to_s }
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
# Returns a new hash with all keys converted to symbols, as long as
|
|
@@ -82,14 +82,14 @@ class Hash
|
|
|
82
82
|
# hash.deep_stringify_keys
|
|
83
83
|
# # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
|
|
84
84
|
def deep_stringify_keys
|
|
85
|
-
deep_transform_keys
|
|
85
|
+
deep_transform_keys { |k| Symbol === k ? k.name : k.to_s }
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
# Destructively converts all keys to strings.
|
|
89
89
|
# This includes the keys from the root hash and from all
|
|
90
90
|
# nested hashes and arrays.
|
|
91
91
|
def deep_stringify_keys!
|
|
92
|
-
deep_transform_keys!
|
|
92
|
+
deep_transform_keys! { |k| Symbol === k ? k.name : k.to_s }
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
# Returns a new hash with all keys converted to symbols, as long as
|