activesupport 5.0.0 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +343 -590
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -4
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +11 -5
- data/lib/active_support/backtrace_cleaner.rb +33 -5
- data/lib/active_support/benchmarkable.rb +5 -3
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +45 -53
- data/lib/active_support/cache/mem_cache_store.rb +81 -79
- data/lib/active_support/cache/memory_store.rb +69 -41
- data/lib/active_support/cache/null_store.rb +11 -4
- data/lib/active_support/cache/redis_cache_store.rb +493 -0
- data/lib/active_support/cache/strategy/local_cache.rb +74 -37
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
- data/lib/active_support/cache.rb +332 -161
- data/lib/active_support/callbacks.rb +657 -586
- data/lib/active_support/concern.rb +79 -6
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
- data/lib/active_support/concurrency/share_lock.rb +59 -19
- data/lib/active_support/configurable.rb +15 -17
- data/lib/active_support/configuration_file.rb +46 -0
- data/lib/active_support/core_ext/array/access.rb +21 -7
- data/lib/active_support/core_ext/array/conversions.rb +20 -18
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +3 -1
- data/lib/active_support/core_ext/array/inquiry.rb +3 -1
- data/lib/active_support/core_ext/array/wrap.rb +2 -0
- data/lib/active_support/core_ext/array.rb +9 -7
- data/lib/active_support/core_ext/benchmark.rb +5 -3
- data/lib/active_support/core_ext/big_decimal/conversions.rb +6 -6
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/class/attribute.rb +52 -49
- data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
- data/lib/active_support/core_ext/class/subclasses.rb +18 -26
- data/lib/active_support/core_ext/class.rb +4 -2
- data/lib/active_support/core_ext/date/acts_like.rb +3 -1
- data/lib/active_support/core_ext/date/blank.rb +3 -1
- data/lib/active_support/core_ext/date/calculations.rb +16 -13
- data/lib/active_support/core_ext/date/conversions.rb +23 -21
- data/lib/active_support/core_ext/date/zones.rb +4 -2
- data/lib/active_support/core_ext/date.rb +7 -5
- data/lib/active_support/core_ext/date_and_time/calculations.rb +82 -53
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -5
- data/lib/active_support/core_ext/date_and_time/zones.rb +9 -9
- data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
- data/lib/active_support/core_ext/date_time/blank.rb +3 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +23 -11
- data/lib/active_support/core_ext/date_time/compatibility.rb +15 -2
- data/lib/active_support/core_ext/date_time/conversions.rb +14 -13
- data/lib/active_support/core_ext/date_time.rb +7 -5
- data/lib/active_support/core_ext/digest/uuid.rb +7 -5
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +165 -29
- data/lib/active_support/core_ext/file/atomic.rb +7 -5
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +40 -39
- data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +4 -2
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -2
- data/lib/active_support/core_ext/hash/keys.rb +9 -36
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -29
- data/lib/active_support/core_ext/hash.rb +10 -9
- data/lib/active_support/core_ext/integer/inflections.rb +3 -1
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +11 -18
- data/lib/active_support/core_ext/integer.rb +5 -3
- data/lib/active_support/core_ext/kernel/concern.rb +3 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +3 -1
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +5 -4
- data/lib/active_support/core_ext/load_error.rb +2 -23
- data/lib/active_support/core_ext/marshal.rb +6 -2
- data/lib/active_support/core_ext/module/aliasing.rb +5 -48
- data/lib/active_support/core_ext/module/anonymous.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +7 -5
- data/lib/active_support/core_ext/module/attribute_accessors.rb +53 -59
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +31 -24
- data/lib/active_support/core_ext/module/concerning.rb +16 -11
- data/lib/active_support/core_ext/module/delegation.rb +159 -44
- data/lib/active_support/core_ext/module/deprecation.rb +2 -0
- data/lib/active_support/core_ext/module/introspection.rb +23 -26
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +5 -23
- data/lib/active_support/core_ext/module.rb +13 -12
- data/lib/active_support/core_ext/name_error.rb +36 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -134
- data/lib/active_support/core_ext/numeric/time.rb +18 -26
- data/lib/active_support/core_ext/numeric.rb +5 -4
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +14 -2
- data/lib/active_support/core_ext/object/conversions.rb +6 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +4 -2
- data/lib/active_support/core_ext/object/duplicable.rb +13 -62
- data/lib/active_support/core_ext/object/inclusion.rb +3 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
- data/lib/active_support/core_ext/object/json.rb +42 -15
- data/lib/active_support/core_ext/object/to_param.rb +3 -1
- data/lib/active_support/core_ext/object/to_query.rb +10 -5
- data/lib/active_support/core_ext/object/try.rb +20 -8
- data/lib/active_support/core_ext/object/with_options.rb +15 -2
- data/lib/active_support/core_ext/object.rb +14 -12
- data/lib/active_support/core_ext/range/compare_range.rb +82 -0
- data/lib/active_support/core_ext/range/conversions.rb +35 -25
- data/lib/active_support/core_ext/range/each.rb +5 -2
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
- data/lib/active_support/core_ext/range/overlaps.rb +2 -0
- data/lib/active_support/core_ext/range.rb +7 -4
- data/lib/active_support/core_ext/regexp.rb +10 -1
- data/lib/active_support/core_ext/securerandom.rb +28 -6
- data/lib/active_support/core_ext/string/access.rb +9 -18
- data/lib/active_support/core_ext/string/behavior.rb +2 -0
- data/lib/active_support/core_ext/string/conversions.rb +5 -2
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +47 -4
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +78 -29
- data/lib/active_support/core_ext/string/inquiry.rb +4 -1
- data/lib/active_support/core_ext/string/multibyte.rb +10 -5
- data/lib/active_support/core_ext/string/output_safety.rb +86 -31
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
- data/lib/active_support/core_ext/string/strip.rb +5 -1
- data/lib/active_support/core_ext/string/zones.rb +4 -2
- data/lib/active_support/core_ext/string.rb +15 -13
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +117 -45
- data/lib/active_support/core_ext/time/compatibility.rb +13 -2
- data/lib/active_support/core_ext/time/conversions.rb +18 -12
- data/lib/active_support/core_ext/time/zones.rb +9 -7
- data/lib/active_support/core_ext/time.rb +7 -5
- data/lib/active_support/core_ext/uri.rb +12 -7
- data/lib/active_support/core_ext.rb +3 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +208 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +7 -1
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +172 -98
- data/lib/active_support/deprecation/behaviors.rb +45 -13
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +16 -2
- data/lib/active_support/deprecation/method_wrappers.rb +32 -17
- data/lib/active_support/deprecation/proxy_wrappers.rb +35 -7
- data/lib/active_support/deprecation/reporting.rb +61 -16
- data/lib/active_support/deprecation.rb +17 -9
- data/lib/active_support/descendants_tracker.rb +61 -9
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration/iso8601_parser.rb +67 -66
- data/lib/active_support/duration/iso8601_serializer.rb +25 -17
- data/lib/active_support/duration.rb +349 -46
- data/lib/active_support/encrypted_configuration.rb +45 -0
- data/lib/active_support/encrypted_file.rb +117 -0
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +88 -112
- data/lib/active_support/execution_wrapper.rb +25 -13
- data/lib/active_support/executor.rb +3 -1
- data/lib/active_support/file_update_checker.rb +56 -51
- data/lib/active_support/fork_tracker.rb +62 -0
- data/lib/active_support/gem_version.rb +4 -2
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +153 -49
- data/lib/active_support/i18n.rb +9 -6
- data/lib/active_support/i18n_railtie.rb +30 -20
- data/lib/active_support/inflections.rb +13 -11
- data/lib/active_support/inflector/inflections.rb +28 -15
- data/lib/active_support/inflector/methods.rb +120 -109
- data/lib/active_support/inflector/transliterate.rb +60 -25
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/json/decoding.rb +30 -29
- data/lib/active_support/json/encoding.rb +22 -11
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +6 -36
- data/lib/active_support/lazy_load_hooks.rb +53 -20
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber/test_helper.rb +11 -9
- data/lib/active_support/log_subscriber.rb +51 -18
- data/lib/active_support/logger.rb +9 -22
- data/lib/active_support/logger_silence.rb +14 -21
- data/lib/active_support/logger_thread_safe_level.rb +55 -8
- data/lib/active_support/message_encryptor.rb +170 -53
- data/lib/active_support/message_verifier.rb +91 -20
- data/lib/active_support/messages/metadata.rb +80 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotator.rb +57 -0
- data/lib/active_support/multibyte/chars.rb +24 -78
- data/lib/active_support/multibyte/unicode.rb +21 -352
- data/lib/active_support/multibyte.rb +4 -2
- data/lib/active_support/notifications/fanout.rb +121 -19
- data/lib/active_support/notifications/instrumenter.rb +78 -14
- data/lib/active_support/notifications.rb +80 -12
- data/lib/active_support/number_helper/number_converter.rb +17 -16
- data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +13 -12
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -13
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -4
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +18 -55
- data/lib/active_support/number_helper/rounding_helper.rb +50 -0
- data/lib/active_support/number_helper.rb +45 -16
- data/lib/active_support/option_merger.rb +25 -4
- data/lib/active_support/ordered_hash.rb +6 -4
- data/lib/active_support/ordered_options.rb +23 -9
- data/lib/active_support/parameter_filter.rb +133 -0
- data/lib/active_support/per_thread_registry.rb +7 -5
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +8 -9
- data/lib/active_support/railtie.rb +62 -11
- data/lib/active_support/reloader.rb +12 -11
- data/lib/active_support/rescuable.rb +20 -11
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +26 -15
- data/lib/active_support/string_inquirer.rb +12 -3
- data/lib/active_support/subscriber.rb +77 -23
- data/lib/active_support/tagged_logging.rb +52 -17
- data/lib/active_support/test_case.rb +106 -29
- data/lib/active_support/testing/assertions.rb +144 -8
- data/lib/active_support/testing/autorun.rb +5 -10
- data/lib/active_support/testing/constant_lookup.rb +2 -1
- data/lib/active_support/testing/declarative.rb +3 -1
- data/lib/active_support/testing/deprecation.rb +4 -2
- data/lib/active_support/testing/file_fixtures.rb +4 -0
- data/lib/active_support/testing/isolation.rb +19 -24
- data/lib/active_support/testing/method_call_assertions.rb +31 -2
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/parallelization.rb +51 -0
- data/lib/active_support/testing/setup_and_teardown.rb +13 -8
- data/lib/active_support/testing/stream.rb +30 -29
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +125 -24
- data/lib/active_support/time.rb +14 -12
- data/lib/active_support/time_with_zone.rb +142 -55
- data/lib/active_support/values/time_zone.rb +160 -53
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini/jdom.rb +115 -114
- data/lib/active_support/xml_mini/libxml.rb +15 -14
- data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
- data/lib/active_support/xml_mini/nokogiri.rb +13 -13
- data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
- data/lib/active_support/xml_mini/rexml.rb +18 -9
- data/lib/active_support/xml_mini.rb +44 -42
- data/lib/active_support.rb +19 -10
- metadata +79 -37
- data/lib/active_support/concurrency/latch.rb +0 -19
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
- data/lib/active_support/core_ext/hash/compact.rb +0 -20
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -29
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -3
- data/lib/active_support/core_ext/module/method_transplanting.rb +0 -3
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -70
- data/lib/active_support/core_ext/module/reachable.rb +0 -8
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
- data/lib/active_support/core_ext/range/include_range.rb +0 -23
- data/lib/active_support/core_ext/struct.rb +0 -3
- data/lib/active_support/core_ext/time/marshal.rb +0 -3
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,12 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tzinfo"
|
4
|
+
require "concurrent/map"
|
4
5
|
|
5
6
|
module ActiveSupport
|
6
7
|
# The TimeZone class serves as a wrapper around TZInfo::Timezone instances.
|
7
8
|
# It allows us to do the following:
|
8
9
|
#
|
9
|
-
# * Limit the set of zones provided by TZInfo to a meaningful subset of
|
10
|
+
# * Limit the set of zones provided by TZInfo to a meaningful subset of 134
|
10
11
|
# zones.
|
11
12
|
# * Retrieve and display zones with a friendlier name
|
12
13
|
# (e.g., "Eastern Time (US & Canada)" instead of "America/New_York").
|
@@ -28,7 +29,7 @@ module ActiveSupport
|
|
28
29
|
class TimeZone
|
29
30
|
# Keys are Rails TimeZone names, values are TZInfo identifiers.
|
30
31
|
MAPPING = {
|
31
|
-
"International Date Line West" => "
|
32
|
+
"International Date Line West" => "Etc/GMT+12",
|
32
33
|
"Midway Island" => "Pacific/Midway",
|
33
34
|
"American Samoa" => "Pacific/Pago_Pago",
|
34
35
|
"Hawaii" => "Pacific/Honolulu",
|
@@ -59,6 +60,7 @@ module ActiveSupport
|
|
59
60
|
"Buenos Aires" => "America/Argentina/Buenos_Aires",
|
60
61
|
"Montevideo" => "America/Montevideo",
|
61
62
|
"Georgetown" => "America/Guyana",
|
63
|
+
"Puerto Rico" => "America/Puerto_Rico",
|
62
64
|
"Greenland" => "America/Godthab",
|
63
65
|
"Mid-Atlantic" => "Atlantic/South_Georgia",
|
64
66
|
"Azores" => "Atlantic/Azores",
|
@@ -180,8 +182,9 @@ module ActiveSupport
|
|
180
182
|
"Samoa" => "Pacific/Apia"
|
181
183
|
}
|
182
184
|
|
183
|
-
UTC_OFFSET_WITH_COLON =
|
184
|
-
UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.tr(
|
185
|
+
UTC_OFFSET_WITH_COLON = "%s%02d:%02d" # :nodoc:
|
186
|
+
UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.tr(":", "") # :nodoc:
|
187
|
+
private_constant :UTC_OFFSET_WITH_COLON, :UTC_OFFSET_WITHOUT_COLON
|
185
188
|
|
186
189
|
@lazy_zones_map = Concurrent::Map.new
|
187
190
|
@country_zones = Concurrent::Map.new
|
@@ -193,14 +196,14 @@ module ActiveSupport
|
|
193
196
|
# ActiveSupport::TimeZone.seconds_to_utc_offset(-21_600) # => "-06:00"
|
194
197
|
def seconds_to_utc_offset(seconds, colon = true)
|
195
198
|
format = colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON
|
196
|
-
sign = (seconds < 0 ?
|
199
|
+
sign = (seconds < 0 ? "-" : "+")
|
197
200
|
hours = seconds.abs / 3600
|
198
201
|
minutes = (seconds.abs % 3600) / 60
|
199
202
|
format % [sign, hours, minutes]
|
200
203
|
end
|
201
204
|
|
202
205
|
def find_tzinfo(name)
|
203
|
-
TZInfo::Timezone.
|
206
|
+
TZInfo::Timezone.get(MAPPING[name] || name)
|
204
207
|
end
|
205
208
|
|
206
209
|
alias_method :create, :new
|
@@ -226,17 +229,17 @@ module ActiveSupport
|
|
226
229
|
# Returns +nil+ if no such time zone is known to the system.
|
227
230
|
def [](arg)
|
228
231
|
case arg
|
229
|
-
|
232
|
+
when String
|
230
233
|
begin
|
231
234
|
@lazy_zones_map[arg] ||= create(arg)
|
232
235
|
rescue TZInfo::InvalidTimezoneIdentifier
|
233
236
|
nil
|
234
237
|
end
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
238
|
+
when Numeric, ActiveSupport::Duration
|
239
|
+
arg *= 3600 if arg.abs <= 13
|
240
|
+
all.find { |z| z.utc_offset == arg.to_i }
|
241
|
+
else
|
242
|
+
raise ArgumentError, "invalid argument to TimeZone[]: #{arg.inspect}"
|
240
243
|
end
|
241
244
|
end
|
242
245
|
|
@@ -250,18 +253,35 @@ module ActiveSupport
|
|
250
253
|
# for time zones in the country specified by its ISO 3166-1 Alpha2 code.
|
251
254
|
def country_zones(country_code)
|
252
255
|
code = country_code.to_s.upcase
|
253
|
-
@country_zones[code] ||=
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
256
|
+
@country_zones[code] ||= load_country_zones(code)
|
257
|
+
end
|
258
|
+
|
259
|
+
def clear #:nodoc:
|
260
|
+
@lazy_zones_map = Concurrent::Map.new
|
261
|
+
@country_zones = Concurrent::Map.new
|
262
|
+
@zones = nil
|
263
|
+
@zones_map = nil
|
258
264
|
end
|
259
265
|
|
260
266
|
private
|
267
|
+
def load_country_zones(code)
|
268
|
+
country = TZInfo::Country.get(code)
|
269
|
+
country.zone_identifiers.flat_map do |tz_id|
|
270
|
+
if MAPPING.value?(tz_id)
|
271
|
+
MAPPING.inject([]) do |memo, (key, value)|
|
272
|
+
memo << self[key] if value == tz_id
|
273
|
+
memo
|
274
|
+
end
|
275
|
+
else
|
276
|
+
create(tz_id, nil, TZInfo::Timezone.get(tz_id))
|
277
|
+
end
|
278
|
+
end.sort!
|
279
|
+
end
|
280
|
+
|
261
281
|
def zones_map
|
262
|
-
@zones_map ||=
|
263
|
-
|
264
|
-
|
282
|
+
@zones_map ||= MAPPING.each_with_object({}) do |(name, _), zones|
|
283
|
+
timezone = self[name]
|
284
|
+
zones[name] = timezone if timezone
|
265
285
|
end
|
266
286
|
end
|
267
287
|
end
|
@@ -282,11 +302,7 @@ module ActiveSupport
|
|
282
302
|
|
283
303
|
# Returns the offset of this time zone from UTC in seconds.
|
284
304
|
def utc_offset
|
285
|
-
|
286
|
-
@utc_offset
|
287
|
-
else
|
288
|
-
tzinfo.current_period.utc_offset if tzinfo && tzinfo.current_period
|
289
|
-
end
|
305
|
+
@utc_offset || tzinfo&.current_period&.base_utc_offset
|
290
306
|
end
|
291
307
|
|
292
308
|
# Returns a formatted string of the offset from UTC, or an alternative
|
@@ -295,7 +311,7 @@ module ActiveSupport
|
|
295
311
|
# zone = ActiveSupport::TimeZone['Central Time (US & Canada)']
|
296
312
|
# zone.formatted_offset # => "-06:00"
|
297
313
|
# zone.formatted_offset(false) # => "-0600"
|
298
|
-
def formatted_offset(colon=true, alternate_utc_string = nil)
|
314
|
+
def formatted_offset(colon = true, alternate_utc_string = nil)
|
299
315
|
utc_offset == 0 && alternate_utc_string || self.class.seconds_to_utc_offset(utc_offset, colon)
|
300
316
|
end
|
301
317
|
|
@@ -314,6 +330,13 @@ module ActiveSupport
|
|
314
330
|
re === name || re === MAPPING[name]
|
315
331
|
end
|
316
332
|
|
333
|
+
# Compare #name and TZInfo identifier to a supplied regexp, returning +true+
|
334
|
+
# if a match is found.
|
335
|
+
def match?(re)
|
336
|
+
(re == name) || (re == MAPPING[name]) ||
|
337
|
+
((Regexp === re) && (re.match?(name) || re.match?(MAPPING[name])))
|
338
|
+
end
|
339
|
+
|
317
340
|
# Returns a textual representation of this time zone.
|
318
341
|
def to_s
|
319
342
|
"(GMT#{formatted_offset}) #{name}"
|
@@ -335,8 +358,48 @@ module ActiveSupport
|
|
335
358
|
# Time.zone = 'Hawaii' # => "Hawaii"
|
336
359
|
# Time.utc(2000).to_f # => 946684800.0
|
337
360
|
# Time.zone.at(946684800.0) # => Fri, 31 Dec 1999 14:00:00 HST -10:00
|
338
|
-
|
339
|
-
|
361
|
+
#
|
362
|
+
# A second argument can be supplied to specify sub-second precision.
|
363
|
+
#
|
364
|
+
# Time.zone = 'Hawaii' # => "Hawaii"
|
365
|
+
# Time.at(946684800, 123456.789).nsec # => 123456789
|
366
|
+
def at(*args)
|
367
|
+
Time.at(*args).utc.in_time_zone(self)
|
368
|
+
end
|
369
|
+
|
370
|
+
# Method for creating new ActiveSupport::TimeWithZone instance in time zone
|
371
|
+
# of +self+ from an ISO 8601 string.
|
372
|
+
#
|
373
|
+
# Time.zone = 'Hawaii' # => "Hawaii"
|
374
|
+
# Time.zone.iso8601('1999-12-31T14:00:00') # => Fri, 31 Dec 1999 14:00:00 HST -10:00
|
375
|
+
#
|
376
|
+
# If the time components are missing then they will be set to zero.
|
377
|
+
#
|
378
|
+
# Time.zone = 'Hawaii' # => "Hawaii"
|
379
|
+
# Time.zone.iso8601('1999-12-31') # => Fri, 31 Dec 1999 00:00:00 HST -10:00
|
380
|
+
#
|
381
|
+
# If the string is invalid then an +ArgumentError+ will be raised unlike +parse+
|
382
|
+
# which usually returns +nil+ when given an invalid date string.
|
383
|
+
def iso8601(str)
|
384
|
+
parts = Date._iso8601(str)
|
385
|
+
|
386
|
+
raise ArgumentError, "invalid date" if parts.empty?
|
387
|
+
|
388
|
+
time = Time.new(
|
389
|
+
parts.fetch(:year),
|
390
|
+
parts.fetch(:mon),
|
391
|
+
parts.fetch(:mday),
|
392
|
+
parts.fetch(:hour, 0),
|
393
|
+
parts.fetch(:min, 0),
|
394
|
+
parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0),
|
395
|
+
parts.fetch(:offset, 0)
|
396
|
+
)
|
397
|
+
|
398
|
+
if parts[:offset]
|
399
|
+
TimeWithZone.new(time.utc, self)
|
400
|
+
else
|
401
|
+
TimeWithZone.new(nil, self, time)
|
402
|
+
end
|
340
403
|
end
|
341
404
|
|
342
405
|
# Method for creating new ActiveSupport::TimeWithZone instance in time zone
|
@@ -355,10 +418,42 @@ module ActiveSupport
|
|
355
418
|
# components are supplied, then the day of the month defaults to 1:
|
356
419
|
#
|
357
420
|
# Time.zone.parse('Mar 2000') # => Wed, 01 Mar 2000 00:00:00 HST -10:00
|
358
|
-
|
421
|
+
#
|
422
|
+
# If the string is invalid then an +ArgumentError+ could be raised.
|
423
|
+
def parse(str, now = now())
|
359
424
|
parts_to_time(Date._parse(str, false), now)
|
360
425
|
end
|
361
426
|
|
427
|
+
# Method for creating new ActiveSupport::TimeWithZone instance in time zone
|
428
|
+
# of +self+ from an RFC 3339 string.
|
429
|
+
#
|
430
|
+
# Time.zone = 'Hawaii' # => "Hawaii"
|
431
|
+
# Time.zone.rfc3339('2000-01-01T00:00:00Z') # => Fri, 31 Dec 1999 14:00:00 HST -10:00
|
432
|
+
#
|
433
|
+
# If the time or zone components are missing then an +ArgumentError+ will
|
434
|
+
# be raised. This is much stricter than either +parse+ or +iso8601+ which
|
435
|
+
# allow for missing components.
|
436
|
+
#
|
437
|
+
# Time.zone = 'Hawaii' # => "Hawaii"
|
438
|
+
# Time.zone.rfc3339('1999-12-31') # => ArgumentError: invalid date
|
439
|
+
def rfc3339(str)
|
440
|
+
parts = Date._rfc3339(str)
|
441
|
+
|
442
|
+
raise ArgumentError, "invalid date" if parts.empty?
|
443
|
+
|
444
|
+
time = Time.new(
|
445
|
+
parts.fetch(:year),
|
446
|
+
parts.fetch(:mon),
|
447
|
+
parts.fetch(:mday),
|
448
|
+
parts.fetch(:hour),
|
449
|
+
parts.fetch(:min),
|
450
|
+
parts.fetch(:sec) + parts.fetch(:sec_fraction, 0),
|
451
|
+
parts.fetch(:offset)
|
452
|
+
)
|
453
|
+
|
454
|
+
TimeWithZone.new(time.utc, self)
|
455
|
+
end
|
456
|
+
|
362
457
|
# Parses +str+ according to +format+ and returns an ActiveSupport::TimeWithZone.
|
363
458
|
#
|
364
459
|
# Assumes that +str+ is a time in the time zone +self+,
|
@@ -379,7 +474,7 @@ module ActiveSupport
|
|
379
474
|
# components are supplied, then the day of the month defaults to 1:
|
380
475
|
#
|
381
476
|
# Time.zone.strptime('Mar 2000', '%b %Y') # => Wed, 01 Mar 2000 00:00:00 HST -10:00
|
382
|
-
def strptime(str, format, now=now())
|
477
|
+
def strptime(str, format, now = now())
|
383
478
|
parts_to_time(DateTime._strptime(str, format), now)
|
384
479
|
end
|
385
480
|
|
@@ -408,15 +503,22 @@ module ActiveSupport
|
|
408
503
|
end
|
409
504
|
|
410
505
|
# Adjust the given time to the simultaneous time in the time zone
|
411
|
-
# represented by +self+. Returns a
|
412
|
-
# ActiveSupport::TimeWithZone instance, use
|
506
|
+
# represented by +self+. Returns a local time with the appropriate offset
|
507
|
+
# -- if you want an ActiveSupport::TimeWithZone instance, use
|
508
|
+
# Time#in_time_zone() instead.
|
509
|
+
#
|
510
|
+
# As of tzinfo 2, utc_to_local returns a Time with a non-zero utc_offset.
|
511
|
+
# See the `utc_to_local_returns_utc_offset_times` config for more info.
|
413
512
|
def utc_to_local(time)
|
414
|
-
tzinfo.utc_to_local(time)
|
513
|
+
tzinfo.utc_to_local(time).yield_self do |t|
|
514
|
+
ActiveSupport.utc_to_local_returns_utc_offset_times ?
|
515
|
+
t : Time.utc(t.year, t.month, t.day, t.hour, t.min, t.sec, t.sec_fraction)
|
516
|
+
end
|
415
517
|
end
|
416
518
|
|
417
519
|
# Adjust the given time to the simultaneous time in UTC. Returns a
|
418
520
|
# Time.utc() instance.
|
419
|
-
def local_to_utc(time, dst=true)
|
521
|
+
def local_to_utc(time, dst = true)
|
420
522
|
tzinfo.local_to_utc(time, dst)
|
421
523
|
end
|
422
524
|
|
@@ -428,8 +530,8 @@ module ActiveSupport
|
|
428
530
|
|
429
531
|
# Available so that TimeZone instances respond like TZInfo::Timezone
|
430
532
|
# instances.
|
431
|
-
def period_for_local(time, dst=true)
|
432
|
-
tzinfo.period_for_local(time, dst)
|
533
|
+
def period_for_local(time, dst = true)
|
534
|
+
tzinfo.period_for_local(time, dst) { |periods| periods.last }
|
433
535
|
end
|
434
536
|
|
435
537
|
def periods_for_local(time) #:nodoc:
|
@@ -437,29 +539,34 @@ module ActiveSupport
|
|
437
539
|
end
|
438
540
|
|
439
541
|
def init_with(coder) #:nodoc:
|
440
|
-
initialize(coder[
|
542
|
+
initialize(coder["name"])
|
441
543
|
end
|
442
544
|
|
443
545
|
def encode_with(coder) #:nodoc:
|
444
|
-
coder.tag ="!ruby/object:#{self.class}"
|
445
|
-
coder.map = {
|
546
|
+
coder.tag = "!ruby/object:#{self.class}"
|
547
|
+
coder.map = { "name" => tzinfo.name }
|
446
548
|
end
|
447
549
|
|
448
550
|
private
|
449
551
|
def parts_to_time(parts, now)
|
552
|
+
raise ArgumentError, "invalid date" if parts.nil?
|
450
553
|
return if parts.empty?
|
451
554
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
555
|
+
if parts[:seconds]
|
556
|
+
time = Time.at(parts[:seconds])
|
557
|
+
else
|
558
|
+
time = Time.new(
|
559
|
+
parts.fetch(:year, now.year),
|
560
|
+
parts.fetch(:mon, now.month),
|
561
|
+
parts.fetch(:mday, parts[:year] || parts[:mon] ? 1 : now.day),
|
562
|
+
parts.fetch(:hour, 0),
|
563
|
+
parts.fetch(:min, 0),
|
564
|
+
parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0),
|
565
|
+
parts.fetch(:offset, 0)
|
566
|
+
)
|
567
|
+
end
|
568
|
+
|
569
|
+
if parts[:offset] || parts[:seconds]
|
463
570
|
TimeWithZone.new(time.utc, self)
|
464
571
|
else
|
465
572
|
TimeWithZone.new(nil, self, time)
|
@@ -1,9 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
raise "JRuby is required to use the JDOM backend for XmlMini" unless RUBY_PLATFORM.include?("java")
|
4
|
+
|
5
|
+
require "jruby"
|
4
6
|
include Java
|
5
7
|
|
6
|
-
require
|
8
|
+
require "active_support/core_ext/object/blank"
|
7
9
|
|
8
10
|
java_import javax.xml.parsers.DocumentBuilder unless defined? DocumentBuilder
|
9
11
|
java_import javax.xml.parsers.DocumentBuilderFactory unless defined? DocumentBuilderFactory
|
@@ -16,7 +18,7 @@ module ActiveSupport
|
|
16
18
|
module XmlMini_JDOM #:nodoc:
|
17
19
|
extend self
|
18
20
|
|
19
|
-
CONTENT_KEY =
|
21
|
+
CONTENT_KEY = "__content__"
|
20
22
|
|
21
23
|
NODE_TYPE_NAMES = %w{ATTRIBUTE_NODE CDATA_SECTION_NODE COMMENT_NODE DOCUMENT_FRAGMENT_NODE
|
22
24
|
DOCUMENT_NODE DOCUMENT_TYPE_NODE ELEMENT_NODE ENTITY_NODE ENTITY_REFERENCE_NODE NOTATION_NODE
|
@@ -38,7 +40,7 @@ module ActiveSupport
|
|
38
40
|
else
|
39
41
|
@dbf = DocumentBuilderFactory.new_instance
|
40
42
|
# secure processing of java xml
|
41
|
-
#
|
43
|
+
# https://archive.is/9xcQQ
|
42
44
|
@dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
|
43
45
|
@dbf.setFeature("http://xml.org/sax/features/external-general-entities", false)
|
44
46
|
@dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false)
|
@@ -46,136 +48,135 @@ module ActiveSupport
|
|
46
48
|
xml_string_reader = StringReader.new(data)
|
47
49
|
xml_input_source = InputSource.new(xml_string_reader)
|
48
50
|
doc = @dbf.new_document_builder.parse(xml_input_source)
|
49
|
-
merge_element!({CONTENT_KEY =>
|
51
|
+
merge_element!({ CONTENT_KEY => "" }, doc.document_element, XmlMini.depth)
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
55
|
private
|
56
|
+
# Convert an XML element and merge into the hash
|
57
|
+
#
|
58
|
+
# hash::
|
59
|
+
# Hash to merge the converted element into.
|
60
|
+
# element::
|
61
|
+
# XML element to merge into hash
|
62
|
+
def merge_element!(hash, element, depth)
|
63
|
+
raise "Document too deep!" if depth == 0
|
64
|
+
delete_empty(hash)
|
65
|
+
merge!(hash, element.tag_name, collapse(element, depth))
|
66
|
+
end
|
54
67
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
# Hash to merge the converted element into.
|
59
|
-
# element::
|
60
|
-
# XML element to merge into hash
|
61
|
-
def merge_element!(hash, element, depth)
|
62
|
-
raise 'Document too deep!' if depth == 0
|
63
|
-
delete_empty(hash)
|
64
|
-
merge!(hash, element.tag_name, collapse(element, depth))
|
65
|
-
end
|
66
|
-
|
67
|
-
def delete_empty(hash)
|
68
|
-
hash.delete(CONTENT_KEY) if hash[CONTENT_KEY] == ''
|
69
|
-
end
|
70
|
-
|
71
|
-
# Actually converts an XML document element into a data structure.
|
72
|
-
#
|
73
|
-
# element::
|
74
|
-
# The document element to be collapsed.
|
75
|
-
def collapse(element, depth)
|
76
|
-
hash = get_attributes(element)
|
68
|
+
def delete_empty(hash)
|
69
|
+
hash.delete(CONTENT_KEY) if hash[CONTENT_KEY] == ""
|
70
|
+
end
|
77
71
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
72
|
+
# Actually converts an XML document element into a data structure.
|
73
|
+
#
|
74
|
+
# element::
|
75
|
+
# The document element to be collapsed.
|
76
|
+
def collapse(element, depth)
|
77
|
+
hash = get_attributes(element)
|
78
|
+
|
79
|
+
child_nodes = element.child_nodes
|
80
|
+
if child_nodes.length > 0
|
81
|
+
(0...child_nodes.length).each do |i|
|
82
|
+
child = child_nodes.item(i)
|
83
|
+
merge_element!(hash, child, depth - 1) unless child.node_type == Node.TEXT_NODE
|
84
|
+
end
|
85
|
+
merge_texts!(hash, element) unless empty_content?(element)
|
86
|
+
hash
|
87
|
+
else
|
88
|
+
merge_texts!(hash, element)
|
83
89
|
end
|
84
|
-
merge_texts!(hash, element) unless empty_content?(element)
|
85
|
-
hash
|
86
|
-
else
|
87
|
-
merge_texts!(hash, element)
|
88
90
|
end
|
89
|
-
end
|
90
91
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
92
|
+
# Merge all the texts of an element into the hash
|
93
|
+
#
|
94
|
+
# hash::
|
95
|
+
# Hash to add the converted element to.
|
96
|
+
# element::
|
97
|
+
# XML element whose texts are to me merged into the hash
|
98
|
+
def merge_texts!(hash, element)
|
99
|
+
delete_empty(hash)
|
100
|
+
text_children = texts(element)
|
101
|
+
if text_children.join.empty?
|
102
|
+
hash
|
103
|
+
else
|
104
|
+
# must use value to prevent double-escaping
|
105
|
+
merge!(hash, CONTENT_KEY, text_children.join)
|
106
|
+
end
|
105
107
|
end
|
106
|
-
end
|
107
108
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
109
|
+
# Adds a new key/value pair to an existing Hash. If the key to be added
|
110
|
+
# already exists and the existing value associated with key is not
|
111
|
+
# an Array, it will be wrapped in an Array. Then the new value is
|
112
|
+
# appended to that Array.
|
113
|
+
#
|
114
|
+
# hash::
|
115
|
+
# Hash to add key/value pair to.
|
116
|
+
# key::
|
117
|
+
# Key to be added.
|
118
|
+
# value::
|
119
|
+
# Value to be associated with key.
|
120
|
+
def merge!(hash, key, value)
|
121
|
+
if hash.has_key?(key)
|
122
|
+
if hash[key].instance_of?(Array)
|
123
|
+
hash[key] << value
|
124
|
+
else
|
125
|
+
hash[key] = [hash[key], value]
|
126
|
+
end
|
127
|
+
elsif value.instance_of?(Array)
|
128
|
+
hash[key] = [value]
|
123
129
|
else
|
124
|
-
hash[key] =
|
130
|
+
hash[key] = value
|
125
131
|
end
|
126
|
-
|
127
|
-
hash[key] = [value]
|
128
|
-
else
|
129
|
-
hash[key] = value
|
132
|
+
hash
|
130
133
|
end
|
131
|
-
hash
|
132
|
-
end
|
133
134
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
135
|
+
# Converts the attributes array of an XML element into a hash.
|
136
|
+
# Returns an empty Hash if node has no attributes.
|
137
|
+
#
|
138
|
+
# element::
|
139
|
+
# XML element to extract attributes from.
|
140
|
+
def get_attributes(element)
|
141
|
+
attribute_hash = {}
|
142
|
+
attributes = element.attributes
|
143
|
+
(0...attributes.length).each do |i|
|
144
|
+
attribute_hash[CONTENT_KEY] ||= ""
|
145
|
+
attribute_hash[attributes.item(i).name] = attributes.item(i).value
|
146
|
+
end
|
147
|
+
attribute_hash
|
145
148
|
end
|
146
|
-
attribute_hash
|
147
|
-
end
|
148
149
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
150
|
+
# Determines if a document element has text content
|
151
|
+
#
|
152
|
+
# element::
|
153
|
+
# XML element to be checked.
|
154
|
+
def texts(element)
|
155
|
+
texts = []
|
156
|
+
child_nodes = element.child_nodes
|
157
|
+
(0...child_nodes.length).each do |i|
|
158
|
+
item = child_nodes.item(i)
|
159
|
+
if item.node_type == Node.TEXT_NODE
|
160
|
+
texts << item.get_data
|
161
|
+
end
|
160
162
|
end
|
163
|
+
texts
|
161
164
|
end
|
162
|
-
texts
|
163
|
-
end
|
164
165
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
166
|
+
# Determines if a document element has text content
|
167
|
+
#
|
168
|
+
# element::
|
169
|
+
# XML element to be checked.
|
170
|
+
def empty_content?(element)
|
171
|
+
text = +""
|
172
|
+
child_nodes = element.child_nodes
|
173
|
+
(0...child_nodes.length).each do |i|
|
174
|
+
item = child_nodes.item(i)
|
175
|
+
if item.node_type == Node.TEXT_NODE
|
176
|
+
text << item.get_data.strip
|
177
|
+
end
|
176
178
|
end
|
179
|
+
text.strip.length == 0
|
177
180
|
end
|
178
|
-
text.strip.length == 0
|
179
|
-
end
|
180
181
|
end
|
181
182
|
end
|