activesupport 7.0.8.7 → 7.2.2.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 +143 -459
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- 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 +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 +49 -17
- data/lib/active_support/cache/mem_cache_store.rb +94 -128
- data/lib/active_support/cache/memory_store.rb +80 -25
- data/lib/active_support/cache/null_store.rb +6 -0
- data/lib/active_support/cache/redis_cache_store.rb +165 -152
- data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
- data/lib/active_support/cache/strategy/local_cache.rb +29 -14
- data/lib/active_support/cache.rb +363 -291
- data/lib/active_support/callbacks.rb +118 -134
- 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/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 +2 -2
- 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 +3 -75
- 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 +0 -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/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.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +1 -5
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +21 -15
- 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 +1 -1
- 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 +16 -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 +53 -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 +160 -36
- data/lib/active_support/evented_file_update_checker.rb +0 -1
- data/lib/active_support/execution_wrapper.rb +4 -5
- data/lib/active_support/file_update_checker.rb +5 -3
- 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 +41 -25
- 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 +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 +6 -4
- 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 +220 -89
- 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 +4 -2
- 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 +3 -0
- 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 +43 -0
- 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 +12 -3
- data/lib/active_support.rb +15 -3
- metadata +140 -19
- 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
|
#
|
@@ -36,11 +36,11 @@ class DateTime
|
|
36
36
|
if formatter = ::Time::DATE_FORMATS[format]
|
37
37
|
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
38
38
|
else
|
39
|
-
|
39
|
+
to_s
|
40
40
|
end
|
41
41
|
end
|
42
42
|
alias_method :to_formatted_s, :to_fs
|
43
|
-
|
43
|
+
|
44
44
|
|
45
45
|
# Returns a formatted string of the offset from UTC, or an alternative
|
46
46
|
# 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
|
#
|
@@ -289,38 +233,22 @@ end
|
|
289
233
|
class Range # :nodoc:
|
290
234
|
# Optimize range sum to use arithmetic progression if a block is not given and
|
291
235
|
# we have a range of numeric values.
|
292
|
-
def sum(
|
236
|
+
def sum(initial_value = 0)
|
293
237
|
if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
|
294
238
|
super
|
295
239
|
else
|
296
240
|
actual_last = exclude_end? ? (last - 1) : last
|
297
241
|
if actual_last >= first
|
298
|
-
sum =
|
242
|
+
sum = initial_value || 0
|
299
243
|
sum + (actual_last - first + 1) * (actual_last + first) / 2
|
300
244
|
else
|
301
|
-
|
245
|
+
initial_value || 0
|
302
246
|
end
|
303
247
|
end
|
304
248
|
end
|
305
249
|
end
|
306
250
|
|
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
251
|
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
252
|
# Removes all blank elements from the +Array+ in place and returns self.
|
325
253
|
# Uses Object#blank? for determining if an item is blank.
|
326
254
|
#
|
@@ -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[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[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
|
@@ -19,16 +19,27 @@ class Module
|
|
19
19
|
end
|
20
20
|
alias_method :attr_internal, :attr_internal_accessor
|
21
21
|
|
22
|
-
class << self
|
23
|
-
|
22
|
+
class << self
|
23
|
+
attr_reader :attr_internal_naming_format
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def attr_internal_naming_format=(format)
|
26
|
+
if format.start_with?("@")
|
27
|
+
ActiveSupport.deprecator.warn <<~MESSAGE
|
28
|
+
Setting `attr_internal_naming_format` with a `@` prefix is deprecated and will be removed in Rails 8.0.
|
29
|
+
|
30
|
+
You can simply replace #{format.inspect} by #{format.delete_prefix("@").inspect}.
|
31
|
+
MESSAGE
|
32
|
+
|
33
|
+
format = format.delete_prefix("@")
|
34
|
+
end
|
35
|
+
@attr_internal_naming_format = format
|
28
36
|
end
|
37
|
+
end
|
38
|
+
self.attr_internal_naming_format = "_%s"
|
29
39
|
|
40
|
+
private
|
30
41
|
def attr_internal_define(attr_name, type)
|
31
|
-
internal_name =
|
42
|
+
internal_name = Module.attr_internal_naming_format % attr_name
|
32
43
|
# use native attr_* methods as they are faster on some Ruby implementations
|
33
44
|
public_send("attr_#{type}", internal_name)
|
34
45
|
attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
|