activesupport 5.2.4.3 → 7.0.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.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +244 -459
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +31 -5
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/cache/file_store.rb +47 -41
- data/lib/active_support/cache/mem_cache_store.rb +151 -40
- data/lib/active_support/cache/memory_store.rb +68 -34
- data/lib/active_support/cache/null_store.rb +16 -3
- data/lib/active_support/cache/redis_cache_store.rb +103 -101
- data/lib/active_support/cache/strategy/local_cache.rb +56 -64
- data/lib/active_support/cache.rb +333 -116
- data/lib/active_support/callbacks.rb +244 -128
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +72 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +16 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -3
- data/lib/active_support/configurable.rb +15 -16
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +15 -7
- data/lib/active_support/core_ext/array/conversions.rb +18 -17
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/array.rb +2 -1
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +32 -47
- data/lib/active_support/core_ext/class/subclasses.rb +9 -22
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +15 -14
- data/lib/active_support/core_ext/date/conversions.rb +16 -15
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +41 -51
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +13 -14
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -13
- data/lib/active_support/core_ext/enumerable.rb +241 -76
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +3 -4
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +2 -2
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +2 -31
- data/lib/active_support/core_ext/hash/slice.rb +6 -27
- data/lib/active_support/core_ext/hash.rb +1 -2
- data/lib/active_support/core_ext/integer/multiple.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/kernel.rb +0 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +32 -39
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +35 -28
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +70 -33
- data/lib/active_support/core_ext/module/introspection.rb +16 -15
- data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
- data/lib/active_support/core_ext/module.rb +0 -1
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +132 -129
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -1
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +3 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +14 -110
- data/lib/active_support/core_ext/object/json.rb +44 -27
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +24 -14
- data/lib/active_support/core_ext/object/with_options.rb +21 -2
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +23 -27
- data/lib/active_support/core_ext/range/conversions.rb +32 -30
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -2
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +8 -5
- data/lib/active_support/core_ext/securerandom.rb +23 -3
- data/lib/active_support/core_ext/string/access.rb +5 -16
- data/lib/active_support/core_ext/string/conversions.rb +3 -2
- data/lib/active_support/core_ext/string/filters.rb +42 -1
- data/lib/active_support/core_ext/string/inflections.rb +46 -7
- data/lib/active_support/core_ext/string/inquiry.rb +2 -1
- data/lib/active_support/core_ext/string/multibyte.rb +6 -5
- data/lib/active_support/core_ext/string/output_safety.rb +129 -20
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/string/strip.rb +3 -1
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +59 -10
- data/lib/active_support/core_ext/time/conversions.rb +15 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +7 -22
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -22
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +47 -16
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +60 -715
- data/lib/active_support/deprecation/behaviors.rb +21 -5
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +18 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +31 -8
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +7 -2
- data/lib/active_support/descendants_tracker.rb +190 -34
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +5 -7
- data/lib/active_support/duration/iso8601_serializer.rb +27 -15
- data/lib/active_support/duration.rb +149 -67
- data/lib/active_support/encrypted_configuration.rb +12 -5
- data/lib/active_support/encrypted_file.rb +23 -5
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +85 -122
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +44 -21
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/file_update_checker.rb +0 -1
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +5 -5
- data/lib/active_support/hash_with_indifferent_access.rb +73 -43
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +2 -0
- data/lib/active_support/i18n_railtie.rb +15 -8
- data/lib/active_support/inflector/inflections.rb +25 -14
- data/lib/active_support/inflector/methods.rb +38 -71
- data/lib/active_support/inflector/transliterate.rb +47 -18
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/decoding.rb +25 -26
- data/lib/active_support/json/encoding.rb +14 -6
- data/lib/active_support/key_generator.rb +23 -38
- data/lib/active_support/lazy_load_hooks.rb +19 -5
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +8 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +51 -11
- data/lib/active_support/logger.rb +6 -22
- data/lib/active_support/logger_silence.rb +11 -19
- data/lib/active_support/logger_thread_safe_level.rb +45 -10
- data/lib/active_support/message_encryptor.rb +20 -19
- data/lib/active_support/message_verifier.rb +53 -21
- data/lib/active_support/messages/metadata.rb +13 -4
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +10 -9
- data/lib/active_support/multibyte/chars.rb +17 -76
- data/lib/active_support/multibyte/unicode.rb +7 -331
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +163 -37
- data/lib/active_support/notifications/instrumenter.rb +90 -11
- data/lib/active_support/notifications.rb +88 -30
- data/lib/active_support/number_helper/number_converter.rb +6 -9
- data/lib/active_support/number_helper/number_to_currency_converter.rb +12 -12
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -4
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +12 -7
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +36 -12
- data/lib/active_support/option_merger.rb +15 -4
- data/lib/active_support/ordered_hash.rb +2 -2
- data/lib/active_support/ordered_options.rb +14 -4
- data/lib/active_support/parameter_filter.rb +138 -0
- data/lib/active_support/per_thread_registry.rb +6 -1
- data/lib/active_support/rails.rb +1 -10
- data/lib/active_support/railtie.rb +77 -5
- data/lib/active_support/reloader.rb +5 -6
- data/lib/active_support/rescuable.rb +8 -8
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +2 -3
- data/lib/active_support/subscriber.rb +79 -46
- data/lib/active_support/tagged_logging.rb +58 -9
- data/lib/active_support/test_case.rb +79 -0
- data/lib/active_support/testing/assertions.rb +62 -11
- data/lib/active_support/testing/deprecation.rb +52 -2
- data/lib/active_support/testing/file_fixtures.rb +2 -0
- data/lib/active_support/testing/isolation.rb +4 -4
- data/lib/active_support/testing/method_call_assertions.rb +32 -5
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +55 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +4 -7
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +60 -14
- data/lib/active_support/time_with_zone.rb +139 -64
- data/lib/active_support/values/time_zone.rb +66 -30
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +3 -4
- data/lib/active_support/xml_mini/libxml.rb +7 -7
- data/lib/active_support/xml_mini/libxmlsax.rb +5 -5
- data/lib/active_support/xml_mini/nokogiri.rb +6 -6
- data/lib/active_support/xml_mini/nokogirisax.rb +4 -4
- data/lib/active_support/xml_mini/rexml.rb +11 -4
- data/lib/active_support/xml_mini.rb +7 -14
- data/lib/active_support.rb +30 -1
- metadata +64 -35
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
- data/lib/active_support/core_ext/hash/compact.rb +0 -29
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -11
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
- data/lib/active_support/core_ext/range/include_range.rb +0 -3
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "strscan"
|
4
|
-
require "active_support/core_ext/regexp"
|
5
4
|
|
6
5
|
module ActiveSupport
|
7
6
|
class Duration
|
@@ -14,14 +13,14 @@ module ActiveSupport
|
|
14
13
|
class ParsingError < ::ArgumentError; end
|
15
14
|
|
16
15
|
PERIOD_OR_COMMA = /\.|,/
|
17
|
-
PERIOD = "."
|
18
|
-
COMMA = ","
|
16
|
+
PERIOD = "."
|
17
|
+
COMMA = ","
|
19
18
|
|
20
|
-
SIGN_MARKER = /\A
|
19
|
+
SIGN_MARKER = /\A-|\+|/
|
21
20
|
DATE_MARKER = /P/
|
22
21
|
TIME_MARKER = /T/
|
23
|
-
DATE_COMPONENT = /(
|
24
|
-
TIME_COMPONENT = /(
|
22
|
+
DATE_COMPONENT = /(-?\d+(?:[.,]\d+)?)(Y|M|D|W)/
|
23
|
+
TIME_COMPONENT = /(-?\d+(?:[.,]\d+)?)(H|M|S)/
|
25
24
|
|
26
25
|
DATE_TO_PART = { "Y" => :years, "M" => :months, "W" => :weeks, "D" => :days }
|
27
26
|
TIME_TO_PART = { "H" => :hours, "M" => :minutes, "S" => :seconds }
|
@@ -81,7 +80,6 @@ module ActiveSupport
|
|
81
80
|
end
|
82
81
|
|
83
82
|
private
|
84
|
-
|
85
83
|
def finished?
|
86
84
|
scanner.eos?
|
87
85
|
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/object/blank"
|
4
|
-
require "active_support/core_ext/hash/transform_values"
|
5
4
|
|
6
5
|
module ActiveSupport
|
7
6
|
class Duration
|
8
7
|
# Serializes duration to string according to ISO 8601 Duration format.
|
9
8
|
class ISO8601Serializer # :nodoc:
|
9
|
+
DATE_COMPONENTS = %i(years months days)
|
10
|
+
|
10
11
|
def initialize(duration, precision: nil)
|
11
12
|
@duration = duration
|
12
13
|
@precision = precision
|
@@ -14,26 +15,25 @@ module ActiveSupport
|
|
14
15
|
|
15
16
|
# Builds and returns output string.
|
16
17
|
def serialize
|
17
|
-
parts
|
18
|
-
return "PT0S"
|
18
|
+
parts = normalize
|
19
|
+
return "PT0S" if parts.empty?
|
19
20
|
|
20
|
-
output = "P"
|
21
|
+
output = +"P"
|
21
22
|
output << "#{parts[:years]}Y" if parts.key?(:years)
|
22
23
|
output << "#{parts[:months]}M" if parts.key?(:months)
|
23
|
-
output << "#{parts[:weeks]}W" if parts.key?(:weeks)
|
24
24
|
output << "#{parts[:days]}D" if parts.key?(:days)
|
25
|
-
|
25
|
+
output << "#{parts[:weeks]}W" if parts.key?(:weeks)
|
26
|
+
time = +""
|
26
27
|
time << "#{parts[:hours]}H" if parts.key?(:hours)
|
27
28
|
time << "#{parts[:minutes]}M" if parts.key?(:minutes)
|
28
29
|
if parts.key?(:seconds)
|
29
|
-
time << "#{
|
30
|
+
time << "#{format_seconds(parts[:seconds])}S"
|
30
31
|
end
|
31
32
|
output << "T#{time}" unless time.empty?
|
32
|
-
|
33
|
+
output
|
33
34
|
end
|
34
35
|
|
35
36
|
private
|
36
|
-
|
37
37
|
# Return pair of duration's parts and whole duration sign.
|
38
38
|
# Parts are summarized (as they can become repetitive due to addition, etc).
|
39
39
|
# Zero parts are removed as not significant.
|
@@ -42,13 +42,25 @@ module ActiveSupport
|
|
42
42
|
parts = @duration.parts.each_with_object(Hash.new(0)) do |(k, v), p|
|
43
43
|
p[k] += v unless v.zero?
|
44
44
|
end
|
45
|
-
|
46
|
-
|
47
|
-
if parts
|
48
|
-
|
49
|
-
|
45
|
+
|
46
|
+
# Convert weeks to days and remove weeks if mixed with date parts
|
47
|
+
if week_mixed_with_date?(parts)
|
48
|
+
parts[:days] += parts.delete(:weeks) * SECONDS_PER_WEEK / SECONDS_PER_DAY
|
49
|
+
end
|
50
|
+
|
51
|
+
parts
|
52
|
+
end
|
53
|
+
|
54
|
+
def week_mixed_with_date?(parts)
|
55
|
+
parts.key?(:weeks) && (parts.keys & DATE_COMPONENTS).any?
|
56
|
+
end
|
57
|
+
|
58
|
+
def format_seconds(seconds)
|
59
|
+
if @precision
|
60
|
+
sprintf("%0.0#{@precision}f", seconds)
|
61
|
+
else
|
62
|
+
seconds.to_s
|
50
63
|
end
|
51
|
-
[parts, sign]
|
52
64
|
end
|
53
65
|
end
|
54
66
|
end
|
@@ -4,7 +4,6 @@ require "active_support/core_ext/array/conversions"
|
|
4
4
|
require "active_support/core_ext/module/delegation"
|
5
5
|
require "active_support/core_ext/object/acts_like"
|
6
6
|
require "active_support/core_ext/string/filters"
|
7
|
-
require "active_support/deprecation"
|
8
7
|
|
9
8
|
module ActiveSupport
|
10
9
|
# Provides accurate date and time measurements using Date#advance and
|
@@ -12,7 +11,7 @@ module ActiveSupport
|
|
12
11
|
#
|
13
12
|
# 1.month.ago # equivalent to Time.now.advance(months: -1)
|
14
13
|
class Duration
|
15
|
-
class Scalar < Numeric
|
14
|
+
class Scalar < Numeric # :nodoc:
|
16
15
|
attr_reader :value
|
17
16
|
delegate :to_i, :to_f, :to_s, to: :value
|
18
17
|
|
@@ -40,11 +39,11 @@ module ActiveSupport
|
|
40
39
|
|
41
40
|
def +(other)
|
42
41
|
if Duration === other
|
43
|
-
seconds = value + other.
|
44
|
-
new_parts = other.
|
42
|
+
seconds = value + other._parts.fetch(:seconds, 0)
|
43
|
+
new_parts = other._parts.merge(seconds: seconds)
|
45
44
|
new_value = value + other.value
|
46
45
|
|
47
|
-
Duration.new(new_value, new_parts)
|
46
|
+
Duration.new(new_value, new_parts, other.variable?)
|
48
47
|
else
|
49
48
|
calculate(:+, other)
|
50
49
|
end
|
@@ -52,12 +51,12 @@ module ActiveSupport
|
|
52
51
|
|
53
52
|
def -(other)
|
54
53
|
if Duration === other
|
55
|
-
seconds = value - other.
|
56
|
-
new_parts = other.
|
54
|
+
seconds = value - other._parts.fetch(:seconds, 0)
|
55
|
+
new_parts = other._parts.transform_values(&:-@)
|
57
56
|
new_parts = new_parts.merge(seconds: seconds)
|
58
57
|
new_value = value - other.value
|
59
58
|
|
60
|
-
Duration.new(new_value, new_parts)
|
59
|
+
Duration.new(new_value, new_parts, other.variable?)
|
61
60
|
else
|
62
61
|
calculate(:-, other)
|
63
62
|
end
|
@@ -65,10 +64,10 @@ module ActiveSupport
|
|
65
64
|
|
66
65
|
def *(other)
|
67
66
|
if Duration === other
|
68
|
-
new_parts = other.
|
67
|
+
new_parts = other._parts.transform_values { |other_value| value * other_value }
|
69
68
|
new_value = value * other.value
|
70
69
|
|
71
|
-
Duration.new(new_value, new_parts)
|
70
|
+
Duration.new(new_value, new_parts, other.variable?)
|
72
71
|
else
|
73
72
|
calculate(:*, other)
|
74
73
|
end
|
@@ -90,6 +89,10 @@ module ActiveSupport
|
|
90
89
|
end
|
91
90
|
end
|
92
91
|
|
92
|
+
def variable? # :nodoc:
|
93
|
+
false
|
94
|
+
end
|
95
|
+
|
93
96
|
private
|
94
97
|
def calculate(op, other)
|
95
98
|
if Scalar === other
|
@@ -124,8 +127,9 @@ module ActiveSupport
|
|
124
127
|
}.freeze
|
125
128
|
|
126
129
|
PARTS = [:years, :months, :weeks, :days, :hours, :minutes, :seconds].freeze
|
130
|
+
VARIABLE_PARTS = [:years, :months, :weeks, :days].freeze
|
127
131
|
|
128
|
-
|
132
|
+
attr_reader :value
|
129
133
|
|
130
134
|
autoload :ISO8601Parser, "active_support/duration/iso8601_parser"
|
131
135
|
autoload :ISO8601Serializer, "active_support/duration/iso8601_serializer"
|
@@ -141,38 +145,38 @@ module ActiveSupport
|
|
141
145
|
new(calculate_total_seconds(parts), parts)
|
142
146
|
end
|
143
147
|
|
144
|
-
def ===(other)
|
148
|
+
def ===(other) # :nodoc:
|
145
149
|
other.is_a?(Duration)
|
146
150
|
rescue ::NoMethodError
|
147
151
|
false
|
148
152
|
end
|
149
153
|
|
150
|
-
def seconds(value)
|
151
|
-
new(value,
|
154
|
+
def seconds(value) # :nodoc:
|
155
|
+
new(value, { seconds: value }, false)
|
152
156
|
end
|
153
157
|
|
154
|
-
def minutes(value)
|
155
|
-
new(value * SECONDS_PER_MINUTE,
|
158
|
+
def minutes(value) # :nodoc:
|
159
|
+
new(value * SECONDS_PER_MINUTE, { minutes: value }, false)
|
156
160
|
end
|
157
161
|
|
158
|
-
def hours(value)
|
159
|
-
new(value * SECONDS_PER_HOUR,
|
162
|
+
def hours(value) # :nodoc:
|
163
|
+
new(value * SECONDS_PER_HOUR, { hours: value }, false)
|
160
164
|
end
|
161
165
|
|
162
|
-
def days(value)
|
163
|
-
new(value * SECONDS_PER_DAY,
|
166
|
+
def days(value) # :nodoc:
|
167
|
+
new(value * SECONDS_PER_DAY, { days: value }, true)
|
164
168
|
end
|
165
169
|
|
166
|
-
def weeks(value)
|
167
|
-
new(value * SECONDS_PER_WEEK,
|
170
|
+
def weeks(value) # :nodoc:
|
171
|
+
new(value * SECONDS_PER_WEEK, { weeks: value }, true)
|
168
172
|
end
|
169
173
|
|
170
|
-
def months(value)
|
171
|
-
new(value * SECONDS_PER_MONTH,
|
174
|
+
def months(value) # :nodoc:
|
175
|
+
new(value * SECONDS_PER_MONTH, { months: value }, true)
|
172
176
|
end
|
173
177
|
|
174
|
-
def years(value)
|
175
|
-
new(value * SECONDS_PER_YEAR,
|
178
|
+
def years(value) # :nodoc:
|
179
|
+
new(value * SECONDS_PER_YEAR, { years: value }, true)
|
176
180
|
end
|
177
181
|
|
178
182
|
# Creates a new Duration from a seconds value that is converted
|
@@ -182,24 +186,33 @@ module ActiveSupport
|
|
182
186
|
# ActiveSupport::Duration.build(2716146).parts # => {:months=>1, :days=>1}
|
183
187
|
#
|
184
188
|
def build(value)
|
189
|
+
unless value.is_a?(::Numeric)
|
190
|
+
raise TypeError, "can't build an #{self.name} from a #{value.class.name}"
|
191
|
+
end
|
192
|
+
|
185
193
|
parts = {}
|
186
|
-
|
194
|
+
remainder_sign = value <=> 0
|
195
|
+
remainder = value.round(9).abs
|
196
|
+
variable = false
|
187
197
|
|
188
198
|
PARTS.each do |part|
|
189
199
|
unless part == :seconds
|
190
200
|
part_in_seconds = PARTS_IN_SECONDS[part]
|
191
|
-
parts[part] = remainder.div(part_in_seconds)
|
192
|
-
remainder
|
201
|
+
parts[part] = remainder.div(part_in_seconds) * remainder_sign
|
202
|
+
remainder %= part_in_seconds
|
203
|
+
|
204
|
+
unless parts[part].zero?
|
205
|
+
variable ||= VARIABLE_PARTS.include?(part)
|
206
|
+
end
|
193
207
|
end
|
194
|
-
end
|
208
|
+
end unless value == 0
|
195
209
|
|
196
|
-
parts[:seconds] = remainder
|
210
|
+
parts[:seconds] = remainder * remainder_sign
|
197
211
|
|
198
|
-
new(value, parts)
|
212
|
+
new(value, parts, variable)
|
199
213
|
end
|
200
214
|
|
201
215
|
private
|
202
|
-
|
203
216
|
def calculate_total_seconds(parts)
|
204
217
|
parts.inject(0) do |total, (part, value)|
|
205
218
|
total + value * PARTS_IN_SECONDS[part]
|
@@ -207,15 +220,28 @@ module ActiveSupport
|
|
207
220
|
end
|
208
221
|
end
|
209
222
|
|
210
|
-
def initialize(value, parts)
|
211
|
-
@value, @parts = value, parts
|
212
|
-
@parts.
|
213
|
-
@parts.
|
223
|
+
def initialize(value, parts, variable = nil) # :nodoc:
|
224
|
+
@value, @parts = value, parts
|
225
|
+
@parts.reject! { |k, v| v.zero? } unless value == 0
|
226
|
+
@parts.freeze
|
227
|
+
@variable = variable
|
228
|
+
|
229
|
+
if @variable.nil?
|
230
|
+
@variable = @parts.any? { |part, _| VARIABLE_PARTS.include?(part) }
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# Returns a copy of the parts hash that defines the duration
|
235
|
+
def parts
|
236
|
+
@parts.dup
|
214
237
|
end
|
215
238
|
|
216
|
-
def coerce(other)
|
217
|
-
|
239
|
+
def coerce(other) # :nodoc:
|
240
|
+
case other
|
241
|
+
when Scalar
|
218
242
|
[other, self]
|
243
|
+
when Duration
|
244
|
+
[Scalar.new(other.value), self]
|
219
245
|
else
|
220
246
|
[Scalar.new(other), self]
|
221
247
|
end
|
@@ -235,14 +261,13 @@ module ActiveSupport
|
|
235
261
|
# are treated as seconds.
|
236
262
|
def +(other)
|
237
263
|
if Duration === other
|
238
|
-
parts = @parts.
|
239
|
-
|
240
|
-
parts[key] += value
|
264
|
+
parts = @parts.merge(other._parts) do |_key, value, other_value|
|
265
|
+
value + other_value
|
241
266
|
end
|
242
|
-
Duration.new(value + other.value, parts)
|
267
|
+
Duration.new(value + other.value, parts, @variable || other.variable?)
|
243
268
|
else
|
244
|
-
seconds = @parts
|
245
|
-
Duration.new(value + other, @parts.merge(seconds: seconds))
|
269
|
+
seconds = @parts.fetch(:seconds, 0) + other
|
270
|
+
Duration.new(value + other, @parts.merge(seconds: seconds), @variable)
|
246
271
|
end
|
247
272
|
end
|
248
273
|
|
@@ -255,9 +280,9 @@ module ActiveSupport
|
|
255
280
|
# Multiplies this Duration by a Numeric and returns a new Duration.
|
256
281
|
def *(other)
|
257
282
|
if Scalar === other || Duration === other
|
258
|
-
Duration.new(value * other.value, parts.
|
283
|
+
Duration.new(value * other.value, @parts.transform_values { |number| number * other.value }, @variable || other.variable?)
|
259
284
|
elsif Numeric === other
|
260
|
-
Duration.new(value * other, parts.
|
285
|
+
Duration.new(value * other, @parts.transform_values { |number| number * other }, @variable)
|
261
286
|
else
|
262
287
|
raise_type_error(other)
|
263
288
|
end
|
@@ -266,11 +291,11 @@ module ActiveSupport
|
|
266
291
|
# Divides this Duration by a Numeric and returns a new Duration.
|
267
292
|
def /(other)
|
268
293
|
if Scalar === other
|
269
|
-
Duration.new(value / other.value, parts.
|
294
|
+
Duration.new(value / other.value, @parts.transform_values { |number| number / other.value }, @variable)
|
270
295
|
elsif Duration === other
|
271
296
|
value / other.value
|
272
297
|
elsif Numeric === other
|
273
|
-
Duration.new(value / other, parts.
|
298
|
+
Duration.new(value / other, @parts.transform_values { |number| number / other }, @variable)
|
274
299
|
else
|
275
300
|
raise_type_error(other)
|
276
301
|
end
|
@@ -288,11 +313,15 @@ module ActiveSupport
|
|
288
313
|
end
|
289
314
|
end
|
290
315
|
|
291
|
-
def -@
|
292
|
-
Duration.new(-value, parts.
|
316
|
+
def -@ # :nodoc:
|
317
|
+
Duration.new(-value, @parts.transform_values(&:-@), @variable)
|
293
318
|
end
|
294
319
|
|
295
|
-
def
|
320
|
+
def +@ # :nodoc:
|
321
|
+
self
|
322
|
+
end
|
323
|
+
|
324
|
+
def is_a?(klass) # :nodoc:
|
296
325
|
Duration == klass || value.is_a?(klass)
|
297
326
|
end
|
298
327
|
alias :kind_of? :is_a?
|
@@ -336,12 +365,55 @@ module ActiveSupport
|
|
336
365
|
# 1.year.to_i # => 31556952
|
337
366
|
#
|
338
367
|
# In such cases, Ruby's core
|
339
|
-
# Date[
|
340
|
-
# Time[
|
368
|
+
# Date[https://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
|
369
|
+
# Time[https://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
|
341
370
|
# date and time arithmetic.
|
342
371
|
def to_i
|
343
372
|
@value.to_i
|
344
373
|
end
|
374
|
+
alias :in_seconds :to_i
|
375
|
+
|
376
|
+
# Returns the amount of minutes a duration covers as a float
|
377
|
+
#
|
378
|
+
# 1.day.in_minutes # => 1440.0
|
379
|
+
def in_minutes
|
380
|
+
in_seconds / SECONDS_PER_MINUTE.to_f
|
381
|
+
end
|
382
|
+
|
383
|
+
# Returns the amount of hours a duration covers as a float
|
384
|
+
#
|
385
|
+
# 1.day.in_hours # => 24.0
|
386
|
+
def in_hours
|
387
|
+
in_seconds / SECONDS_PER_HOUR.to_f
|
388
|
+
end
|
389
|
+
|
390
|
+
# Returns the amount of days a duration covers as a float
|
391
|
+
#
|
392
|
+
# 12.hours.in_days # => 0.5
|
393
|
+
def in_days
|
394
|
+
in_seconds / SECONDS_PER_DAY.to_f
|
395
|
+
end
|
396
|
+
|
397
|
+
# Returns the amount of weeks a duration covers as a float
|
398
|
+
#
|
399
|
+
# 2.months.in_weeks # => 8.696
|
400
|
+
def in_weeks
|
401
|
+
in_seconds / SECONDS_PER_WEEK.to_f
|
402
|
+
end
|
403
|
+
|
404
|
+
# Returns the amount of months a duration covers as a float
|
405
|
+
#
|
406
|
+
# 9.weeks.in_months # => 2.07
|
407
|
+
def in_months
|
408
|
+
in_seconds / SECONDS_PER_MONTH.to_f
|
409
|
+
end
|
410
|
+
|
411
|
+
# Returns the amount of years a duration covers as a float
|
412
|
+
#
|
413
|
+
# 30.days.in_years # => 0.082
|
414
|
+
def in_years
|
415
|
+
in_seconds / SECONDS_PER_YEAR.to_f
|
416
|
+
end
|
345
417
|
|
346
418
|
# Returns +true+ if +other+ is also a Duration instance, which has the
|
347
419
|
# same parts as this one.
|
@@ -369,25 +441,24 @@ module ActiveSupport
|
|
369
441
|
alias :until :ago
|
370
442
|
alias :before :ago
|
371
443
|
|
372
|
-
def inspect
|
373
|
-
return "
|
444
|
+
def inspect # :nodoc:
|
445
|
+
return "#{value} seconds" if @parts.empty?
|
374
446
|
|
375
|
-
parts.
|
376
|
-
reduce(::Hash.new(0)) { |h, (l, r)| h[l] += r; h }.
|
447
|
+
@parts.
|
377
448
|
sort_by { |unit, _ | PARTS.index(unit) }.
|
378
449
|
map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }.
|
379
|
-
to_sentence(locale:
|
450
|
+
to_sentence(locale: false)
|
380
451
|
end
|
381
452
|
|
382
|
-
def as_json(options = nil)
|
453
|
+
def as_json(options = nil) # :nodoc:
|
383
454
|
to_i
|
384
455
|
end
|
385
456
|
|
386
|
-
def init_with(coder)
|
457
|
+
def init_with(coder) # :nodoc:
|
387
458
|
initialize(coder["value"], coder["parts"])
|
388
459
|
end
|
389
460
|
|
390
|
-
def encode_with(coder)
|
461
|
+
def encode_with(coder) # :nodoc:
|
391
462
|
coder.map = { "value" => @value, "parts" => @parts }
|
392
463
|
end
|
393
464
|
|
@@ -397,11 +468,24 @@ module ActiveSupport
|
|
397
468
|
ISO8601Serializer.new(self, precision: precision).serialize
|
398
469
|
end
|
399
470
|
|
400
|
-
|
471
|
+
def variable? # :nodoc:
|
472
|
+
@variable
|
473
|
+
end
|
474
|
+
|
475
|
+
def _parts # :nodoc:
|
476
|
+
@parts
|
477
|
+
end
|
401
478
|
|
479
|
+
private
|
402
480
|
def sum(sign, time = ::Time.current)
|
403
|
-
|
404
|
-
|
481
|
+
unless time.acts_like?(:time) || time.acts_like?(:date)
|
482
|
+
raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
|
483
|
+
end
|
484
|
+
|
485
|
+
if @parts.empty?
|
486
|
+
time.since(sign * value)
|
487
|
+
else
|
488
|
+
@parts.inject(time) do |t, (type, number)|
|
405
489
|
if type == :seconds
|
406
490
|
t.since(sign * number)
|
407
491
|
elsif type == :minutes
|
@@ -411,8 +495,6 @@ module ActiveSupport
|
|
411
495
|
else
|
412
496
|
t.advance(type => sign * number)
|
413
497
|
end
|
414
|
-
else
|
415
|
-
raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
|
416
498
|
end
|
417
499
|
end
|
418
500
|
end
|
@@ -34,16 +34,23 @@ module ActiveSupport
|
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
|
-
def
|
38
|
-
|
37
|
+
def deep_transform(hash)
|
38
|
+
return hash unless hash.is_a?(Hash)
|
39
|
+
|
40
|
+
h = ActiveSupport::InheritableOptions.new
|
41
|
+
hash.each do |k, v|
|
42
|
+
h[k] = deep_transform(v)
|
43
|
+
end
|
44
|
+
h
|
39
45
|
end
|
40
46
|
|
41
|
-
def
|
42
|
-
|
47
|
+
def options
|
48
|
+
@options ||= ActiveSupport::InheritableOptions.new(deep_transform(config))
|
43
49
|
end
|
44
50
|
|
45
51
|
def deserialize(config)
|
46
|
-
YAML.
|
52
|
+
doc = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(config) : YAML.load(config)
|
53
|
+
doc.presence || {}
|
47
54
|
end
|
48
55
|
end
|
49
56
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "pathname"
|
4
|
+
require "tmpdir"
|
4
5
|
require "active_support/message_encryptor"
|
5
6
|
|
6
7
|
module ActiveSupport
|
@@ -19,17 +20,28 @@ module ActiveSupport
|
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
23
|
+
class InvalidKeyLengthError < RuntimeError
|
24
|
+
def initialize
|
25
|
+
super "Encryption key must be exactly #{EncryptedFile.expected_key_length} characters."
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
22
29
|
CIPHER = "aes-128-gcm"
|
23
30
|
|
24
31
|
def self.generate_key
|
25
32
|
SecureRandom.hex(ActiveSupport::MessageEncryptor.key_len(CIPHER))
|
26
33
|
end
|
27
34
|
|
35
|
+
def self.expected_key_length # :nodoc:
|
36
|
+
@expected_key_length ||= generate_key.length
|
37
|
+
end
|
38
|
+
|
28
39
|
|
29
40
|
attr_reader :content_path, :key_path, :env_key, :raise_if_missing_key
|
30
41
|
|
31
42
|
def initialize(content_path:, key_path:, env_key:, raise_if_missing_key:)
|
32
|
-
@content_path
|
43
|
+
@content_path = Pathname.new(content_path).yield_self { |path| path.symlink? ? path.realpath : path }
|
44
|
+
@key_path = Pathname.new(key_path)
|
33
45
|
@env_key, @raise_if_missing_key = env_key, raise_if_missing_key
|
34
46
|
end
|
35
47
|
|
@@ -67,11 +79,12 @@ module ActiveSupport
|
|
67
79
|
|
68
80
|
write(updated_contents) if updated_contents != contents
|
69
81
|
ensure
|
70
|
-
FileUtils.rm(tmp_path) if tmp_path
|
82
|
+
FileUtils.rm(tmp_path) if tmp_path&.exist?
|
71
83
|
end
|
72
84
|
|
73
85
|
|
74
86
|
def encrypt(contents)
|
87
|
+
check_key_length
|
75
88
|
encryptor.encrypt_and_sign contents
|
76
89
|
end
|
77
90
|
|
@@ -85,15 +98,20 @@ module ActiveSupport
|
|
85
98
|
|
86
99
|
|
87
100
|
def read_env_key
|
88
|
-
ENV[env_key]
|
101
|
+
ENV[env_key].presence
|
89
102
|
end
|
90
103
|
|
91
104
|
def read_key_file
|
92
|
-
|
105
|
+
return @key_file_contents if defined?(@key_file_contents)
|
106
|
+
@key_file_contents = (key_path.binread.strip if key_path.exist?)
|
93
107
|
end
|
94
108
|
|
95
109
|
def handle_missing_key
|
96
|
-
raise MissingKeyError
|
110
|
+
raise MissingKeyError.new(key_path: key_path, env_key: env_key) if raise_if_missing_key
|
111
|
+
end
|
112
|
+
|
113
|
+
def check_key_length
|
114
|
+
raise InvalidKeyLengthError if key&.length != self.class.expected_key_length
|
97
115
|
end
|
98
116
|
end
|
99
117
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/string_inquirer"
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
class EnvironmentInquirer < StringInquirer # :nodoc:
|
7
|
+
DEFAULT_ENVIRONMENTS = ["development", "test", "production"]
|
8
|
+
def initialize(env)
|
9
|
+
super(env)
|
10
|
+
|
11
|
+
DEFAULT_ENVIRONMENTS.each do |default|
|
12
|
+
instance_variable_set :"@#{default}", env == default
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
DEFAULT_ENVIRONMENTS.each do |env|
|
17
|
+
class_eval "def #{env}?; @#{env}; end"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|