activesupport 5.1.7 → 6.1.7
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 +4 -4
- data/CHANGELOG.md +434 -490
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -5
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +2 -0
- data/lib/active_support/array_inquirer.rb +6 -2
- data/lib/active_support/backtrace_cleaner.rb +31 -3
- data/lib/active_support/benchmarkable.rb +3 -1
- data/lib/active_support/builder.rb +2 -0
- data/lib/active_support/cache/file_store.rb +37 -36
- data/lib/active_support/cache/mem_cache_store.rb +72 -56
- data/lib/active_support/cache/memory_store.rb +61 -33
- data/lib/active_support/cache/null_store.rb +10 -3
- data/lib/active_support/cache/redis_cache_store.rb +493 -0
- data/lib/active_support/cache/strategy/local_cache.rb +67 -21
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
- data/lib/active_support/cache.rb +310 -126
- data/lib/active_support/callbacks.rb +106 -100
- data/lib/active_support/concern.rb +79 -6
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -1
- data/lib/active_support/configurable.rb +12 -14
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +21 -7
- data/lib/active_support/core_ext/array/conversions.rb +7 -5
- 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 +2 -0
- data/lib/active_support/core_ext/array/inquiry.rb +2 -0
- data/lib/active_support/core_ext/array/wrap.rb +2 -0
- data/lib/active_support/core_ext/array.rb +3 -1
- data/lib/active_support/core_ext/benchmark.rb +4 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +2 -0
- data/lib/active_support/core_ext/big_decimal.rb +2 -0
- data/lib/active_support/core_ext/class/attribute.rb +50 -47
- data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/class/subclasses.rb +18 -40
- data/lib/active_support/core_ext/class.rb +2 -0
- data/lib/active_support/core_ext/date/acts_like.rb +2 -0
- data/lib/active_support/core_ext/date/blank.rb +2 -0
- data/lib/active_support/core_ext/date/calculations.rb +8 -5
- data/lib/active_support/core_ext/date/conversions.rb +12 -10
- data/lib/active_support/core_ext/date/zones.rb +2 -0
- data/lib/active_support/core_ext/date.rb +2 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +61 -37
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
- data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
- data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
- data/lib/active_support/core_ext/date_time/blank.rb +2 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
- data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -1
- data/lib/active_support/core_ext/date_time.rb +2 -0
- data/lib/active_support/core_ext/digest/uuid.rb +4 -1
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +174 -71
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/file.rb +2 -0
- data/lib/active_support/core_ext/hash/conversions.rb +7 -5
- 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 +2 -0
- data/lib/active_support/core_ext/hash/keys.rb +3 -30
- 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 +3 -2
- data/lib/active_support/core_ext/integer/inflections.rb +2 -0
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +7 -14
- data/lib/active_support/core_ext/integer.rb +2 -0
- data/lib/active_support/core_ext/kernel/concern.rb +2 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +2 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +2 -1
- data/lib/active_support/core_ext/load_error.rb +3 -8
- data/lib/active_support/core_ext/marshal.rb +4 -0
- data/lib/active_support/core_ext/module/aliasing.rb +2 -0
- data/lib/active_support/core_ext/module/anonymous.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +44 -56
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +18 -18
- data/lib/active_support/core_ext/module/concerning.rb +15 -10
- data/lib/active_support/core_ext/module/delegation.rb +103 -58
- data/lib/active_support/core_ext/module/deprecation.rb +2 -0
- data/lib/active_support/core_ext/module/introspection.rb +18 -15
- 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 +3 -1
- 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 +131 -129
- data/lib/active_support/core_ext/numeric/time.rb +7 -15
- data/lib/active_support/core_ext/numeric.rb +2 -1
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +13 -3
- data/lib/active_support/core_ext/object/conversions.rb +2 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
- data/lib/active_support/core_ext/object/duplicable.rb +9 -114
- data/lib/active_support/core_ext/object/inclusion.rb +2 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
- data/lib/active_support/core_ext/object/json.rb +22 -2
- data/lib/active_support/core_ext/object/to_param.rb +2 -0
- data/lib/active_support/core_ext/object/to_query.rb +2 -0
- data/lib/active_support/core_ext/object/try.rb +19 -7
- data/lib/active_support/core_ext/object/with_options.rb +4 -2
- data/lib/active_support/core_ext/object.rb +2 -0
- 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 +4 -1
- data/lib/active_support/core_ext/regexp.rb +10 -5
- data/lib/active_support/core_ext/securerandom.rb +25 -3
- data/lib/active_support/core_ext/string/access.rb +7 -16
- data/lib/active_support/core_ext/string/behavior.rb +2 -0
- data/lib/active_support/core_ext/string/conversions.rb +3 -0
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +44 -1
- data/lib/active_support/core_ext/string/indent.rb +2 -0
- data/lib/active_support/core_ext/string/inflections.rb +69 -16
- data/lib/active_support/core_ext/string/inquiry.rb +3 -0
- data/lib/active_support/core_ext/string/multibyte.rb +9 -4
- data/lib/active_support/core_ext/string/output_safety.rb +104 -20
- 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 +2 -0
- data/lib/active_support/core_ext/string.rb +2 -0
- 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 +2 -0
- data/lib/active_support/core_ext/time/calculations.rb +76 -18
- data/lib/active_support/core_ext/time/compatibility.rb +4 -2
- data/lib/active_support/core_ext/time/conversions.rb +4 -0
- data/lib/active_support/core_ext/time/zones.rb +6 -4
- data/lib/active_support/core_ext/time.rb +2 -0
- data/lib/active_support/core_ext/uri.rb +11 -6
- data/lib/active_support/core_ext.rb +3 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +210 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +2 -0
- data/lib/active_support/dependencies/zeitwerk_integration.rb +120 -0
- data/lib/active_support/dependencies.rb +134 -60
- data/lib/active_support/deprecation/behaviors.rb +43 -11
- data/lib/active_support/deprecation/constant_accessor.rb +4 -2
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +2 -1
- data/lib/active_support/deprecation/method_wrappers.rb +29 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +32 -6
- data/lib/active_support/deprecation/reporting.rb +54 -9
- data/lib/active_support/deprecation.rb +9 -2
- data/lib/active_support/descendants_tracker.rb +61 -9
- data/lib/active_support/digest.rb +22 -0
- data/lib/active_support/duration/iso8601_parser.rb +6 -6
- data/lib/active_support/duration/iso8601_serializer.rb +20 -14
- data/lib/active_support/duration.rb +102 -45
- 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 +84 -117
- data/lib/active_support/execution_wrapper.rb +19 -13
- data/lib/active_support/executor.rb +2 -0
- data/lib/active_support/file_update_checker.rb +2 -1
- data/lib/active_support/fork_tracker.rb +64 -0
- data/lib/active_support/gem_version.rb +3 -1
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +123 -41
- data/lib/active_support/i18n.rb +4 -1
- data/lib/active_support/i18n_railtie.rb +19 -14
- data/lib/active_support/inflections.rb +2 -0
- data/lib/active_support/inflector/inflections.rb +19 -8
- data/lib/active_support/inflector/methods.rb +87 -77
- data/lib/active_support/inflector/transliterate.rb +56 -18
- data/lib/active_support/inflector.rb +2 -0
- data/lib/active_support/json/decoding.rb +27 -26
- data/lib/active_support/json/encoding.rb +13 -3
- data/lib/active_support/json.rb +2 -0
- data/lib/active_support/key_generator.rb +3 -33
- data/lib/active_support/lazy_load_hooks.rb +7 -2
- 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 +2 -0
- data/lib/active_support/log_subscriber.rb +42 -11
- data/lib/active_support/logger.rb +4 -17
- data/lib/active_support/logger_silence.rb +13 -20
- data/lib/active_support/logger_thread_safe_level.rb +54 -7
- data/lib/active_support/message_encryptor.rb +100 -32
- data/lib/active_support/message_verifier.rb +85 -14
- 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 +12 -68
- data/lib/active_support/multibyte/unicode.rb +17 -327
- data/lib/active_support/multibyte.rb +2 -0
- data/lib/active_support/notifications/fanout.rb +118 -16
- data/lib/active_support/notifications/instrumenter.rb +73 -9
- data/lib/active_support/notifications.rb +74 -8
- data/lib/active_support/number_helper/number_converter.rb +7 -6
- 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 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +6 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -3
- 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 -2
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +14 -27
- data/lib/active_support/number_helper/rounding_helper.rb +16 -30
- data/lib/active_support/number_helper.rb +40 -12
- data/lib/active_support/option_merger.rb +24 -3
- data/lib/active_support/ordered_hash.rb +3 -1
- data/lib/active_support/ordered_options.rb +17 -5
- data/lib/active_support/parameter_filter.rb +133 -0
- data/lib/active_support/per_thread_registry.rb +4 -1
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +3 -10
- data/lib/active_support/railtie.rb +60 -9
- data/lib/active_support/reloader.rb +12 -11
- data/lib/active_support/rescuable.rb +7 -6
- 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 +6 -3
- data/lib/active_support/subscriber.rb +74 -24
- data/lib/active_support/tagged_logging.rb +44 -8
- data/lib/active_support/test_case.rb +94 -2
- data/lib/active_support/testing/assertions.rb +58 -20
- data/lib/active_support/testing/autorun.rb +2 -0
- data/lib/active_support/testing/constant_lookup.rb +2 -0
- data/lib/active_support/testing/declarative.rb +2 -0
- data/lib/active_support/testing/deprecation.rb +2 -1
- data/lib/active_support/testing/file_fixtures.rb +4 -0
- data/lib/active_support/testing/isolation.rb +4 -2
- data/lib/active_support/testing/method_call_assertions.rb +30 -1
- 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 +12 -7
- data/lib/active_support/testing/stream.rb +3 -2
- data/lib/active_support/testing/tagged_logging.rb +2 -0
- data/lib/active_support/testing/time_helpers.rb +78 -13
- data/lib/active_support/time.rb +2 -0
- data/lib/active_support/time_with_zone.rb +113 -41
- data/lib/active_support/values/time_zone.rb +54 -25
- data/lib/active_support/version.rb +2 -0
- data/lib/active_support/xml_mini/jdom.rb +5 -4
- data/lib/active_support/xml_mini/libxml.rb +4 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +6 -4
- data/lib/active_support/xml_mini/nokogiri.rb +4 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +5 -3
- data/lib/active_support/xml_mini/rexml.rb +12 -3
- data/lib/active_support/xml_mini.rb +5 -11
- data/lib/active_support.rb +18 -13
- metadata +71 -32
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
- data/lib/active_support/core_ext/hash/compact.rb +0 -27
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- 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/values/unicode_tables.dat +0 -0
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/array/conversions"
|
2
4
|
require "active_support/core_ext/module/delegation"
|
3
5
|
require "active_support/core_ext/object/acts_like"
|
4
6
|
require "active_support/core_ext/string/filters"
|
5
|
-
require "active_support/deprecation"
|
6
7
|
|
7
8
|
module ActiveSupport
|
8
9
|
# Provides accurate date and time measurements using Date#advance and
|
@@ -38,7 +39,7 @@ module ActiveSupport
|
|
38
39
|
|
39
40
|
def +(other)
|
40
41
|
if Duration === other
|
41
|
-
seconds = value + other.parts
|
42
|
+
seconds = value + other.parts.fetch(:seconds, 0)
|
42
43
|
new_parts = other.parts.merge(seconds: seconds)
|
43
44
|
new_value = value + other.value
|
44
45
|
|
@@ -50,8 +51,8 @@ module ActiveSupport
|
|
50
51
|
|
51
52
|
def -(other)
|
52
53
|
if Duration === other
|
53
|
-
seconds = value - other.parts
|
54
|
-
new_parts = other.parts.
|
54
|
+
seconds = value - other.parts.fetch(:seconds, 0)
|
55
|
+
new_parts = other.parts.transform_values(&:-@)
|
55
56
|
new_parts = new_parts.merge(seconds: seconds)
|
56
57
|
new_value = value - other.value
|
57
58
|
|
@@ -63,7 +64,7 @@ module ActiveSupport
|
|
63
64
|
|
64
65
|
def *(other)
|
65
66
|
if Duration === other
|
66
|
-
new_parts = other.parts.
|
67
|
+
new_parts = other.parts.transform_values { |other_value| value * other_value }
|
67
68
|
new_value = value * other.value
|
68
69
|
|
69
70
|
Duration.new(new_value, new_parts)
|
@@ -131,7 +132,7 @@ module ActiveSupport
|
|
131
132
|
class << self
|
132
133
|
# Creates a new Duration from string formatted according to ISO 8601 Duration.
|
133
134
|
#
|
134
|
-
# See {ISO 8601}[
|
135
|
+
# See {ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601#Durations] for more information.
|
135
136
|
# This method allows negative parts to be present in pattern.
|
136
137
|
# If invalid string is provided, it will raise +ActiveSupport::Duration::ISO8601Parser::ParsingError+.
|
137
138
|
def parse(iso8601duration)
|
@@ -146,31 +147,31 @@ module ActiveSupport
|
|
146
147
|
end
|
147
148
|
|
148
149
|
def seconds(value) #:nodoc:
|
149
|
-
new(value,
|
150
|
+
new(value, seconds: value)
|
150
151
|
end
|
151
152
|
|
152
153
|
def minutes(value) #:nodoc:
|
153
|
-
new(value * SECONDS_PER_MINUTE,
|
154
|
+
new(value * SECONDS_PER_MINUTE, minutes: value)
|
154
155
|
end
|
155
156
|
|
156
157
|
def hours(value) #:nodoc:
|
157
|
-
new(value * SECONDS_PER_HOUR,
|
158
|
+
new(value * SECONDS_PER_HOUR, hours: value)
|
158
159
|
end
|
159
160
|
|
160
161
|
def days(value) #:nodoc:
|
161
|
-
new(value * SECONDS_PER_DAY,
|
162
|
+
new(value * SECONDS_PER_DAY, days: value)
|
162
163
|
end
|
163
164
|
|
164
165
|
def weeks(value) #:nodoc:
|
165
|
-
new(value * SECONDS_PER_WEEK,
|
166
|
+
new(value * SECONDS_PER_WEEK, weeks: value)
|
166
167
|
end
|
167
168
|
|
168
169
|
def months(value) #:nodoc:
|
169
|
-
new(value * SECONDS_PER_MONTH,
|
170
|
+
new(value * SECONDS_PER_MONTH, months: value)
|
170
171
|
end
|
171
172
|
|
172
173
|
def years(value) #:nodoc:
|
173
|
-
new(value * SECONDS_PER_YEAR,
|
174
|
+
new(value * SECONDS_PER_YEAR, years: value)
|
174
175
|
end
|
175
176
|
|
176
177
|
# Creates a new Duration from a seconds value that is converted
|
@@ -180,25 +181,28 @@ module ActiveSupport
|
|
180
181
|
# ActiveSupport::Duration.build(2716146).parts # => {:months=>1, :days=>1}
|
181
182
|
#
|
182
183
|
def build(value)
|
184
|
+
unless value.is_a?(::Numeric)
|
185
|
+
raise TypeError, "can't build an #{self.name} from a #{value.class.name}"
|
186
|
+
end
|
187
|
+
|
183
188
|
parts = {}
|
184
|
-
|
189
|
+
remainder_sign = value <=> 0
|
190
|
+
remainder = value.round(9).abs
|
185
191
|
|
186
192
|
PARTS.each do |part|
|
187
193
|
unless part == :seconds
|
188
194
|
part_in_seconds = PARTS_IN_SECONDS[part]
|
189
|
-
parts[part] = remainder.div(part_in_seconds)
|
190
|
-
remainder
|
195
|
+
parts[part] = remainder.div(part_in_seconds) * remainder_sign
|
196
|
+
remainder %= part_in_seconds
|
191
197
|
end
|
192
|
-
end
|
198
|
+
end unless value == 0
|
193
199
|
|
194
|
-
parts[:seconds] = remainder
|
195
|
-
parts.reject! { |k, v| v.zero? }
|
200
|
+
parts[:seconds] = remainder * remainder_sign
|
196
201
|
|
197
202
|
new(value, parts)
|
198
203
|
end
|
199
204
|
|
200
205
|
private
|
201
|
-
|
202
206
|
def calculate_total_seconds(parts)
|
203
207
|
parts.inject(0) do |total, (part, value)|
|
204
208
|
total + value * PARTS_IN_SECONDS[part]
|
@@ -207,13 +211,16 @@ module ActiveSupport
|
|
207
211
|
end
|
208
212
|
|
209
213
|
def initialize(value, parts) #:nodoc:
|
210
|
-
@value, @parts = value, parts
|
211
|
-
@parts.
|
214
|
+
@value, @parts = value, parts
|
215
|
+
@parts.reject! { |k, v| v.zero? } unless value == 0
|
212
216
|
end
|
213
217
|
|
214
218
|
def coerce(other) #:nodoc:
|
215
|
-
|
219
|
+
case other
|
220
|
+
when Scalar
|
216
221
|
[other, self]
|
222
|
+
when Duration
|
223
|
+
[Scalar.new(other.value), self]
|
217
224
|
else
|
218
225
|
[Scalar.new(other), self]
|
219
226
|
end
|
@@ -233,13 +240,12 @@ module ActiveSupport
|
|
233
240
|
# are treated as seconds.
|
234
241
|
def +(other)
|
235
242
|
if Duration === other
|
236
|
-
parts = @parts.
|
237
|
-
|
238
|
-
parts[key] += value
|
243
|
+
parts = @parts.merge(other.parts) do |_key, value, other_value|
|
244
|
+
value + other_value
|
239
245
|
end
|
240
246
|
Duration.new(value + other.value, parts)
|
241
247
|
else
|
242
|
-
seconds = @parts
|
248
|
+
seconds = @parts.fetch(:seconds, 0) + other
|
243
249
|
Duration.new(value + other, @parts.merge(seconds: seconds))
|
244
250
|
end
|
245
251
|
end
|
@@ -253,9 +259,9 @@ module ActiveSupport
|
|
253
259
|
# Multiplies this Duration by a Numeric and returns a new Duration.
|
254
260
|
def *(other)
|
255
261
|
if Scalar === other || Duration === other
|
256
|
-
Duration.new(value * other.value, parts.
|
262
|
+
Duration.new(value * other.value, parts.transform_values { |number| number * other.value })
|
257
263
|
elsif Numeric === other
|
258
|
-
Duration.new(value * other, parts.
|
264
|
+
Duration.new(value * other, parts.transform_values { |number| number * other })
|
259
265
|
else
|
260
266
|
raise_type_error(other)
|
261
267
|
end
|
@@ -264,11 +270,11 @@ module ActiveSupport
|
|
264
270
|
# Divides this Duration by a Numeric and returns a new Duration.
|
265
271
|
def /(other)
|
266
272
|
if Scalar === other
|
267
|
-
Duration.new(value / other.value, parts.
|
273
|
+
Duration.new(value / other.value, parts.transform_values { |number| number / other.value })
|
268
274
|
elsif Duration === other
|
269
275
|
value / other.value
|
270
276
|
elsif Numeric === other
|
271
|
-
Duration.new(value / other, parts.
|
277
|
+
Duration.new(value / other, parts.transform_values { |number| number / other })
|
272
278
|
else
|
273
279
|
raise_type_error(other)
|
274
280
|
end
|
@@ -287,7 +293,11 @@ module ActiveSupport
|
|
287
293
|
end
|
288
294
|
|
289
295
|
def -@ #:nodoc:
|
290
|
-
Duration.new(-value, parts.
|
296
|
+
Duration.new(-value, parts.transform_values(&:-@))
|
297
|
+
end
|
298
|
+
|
299
|
+
def +@ #:nodoc:
|
300
|
+
self
|
291
301
|
end
|
292
302
|
|
293
303
|
def is_a?(klass) #:nodoc:
|
@@ -334,12 +344,55 @@ module ActiveSupport
|
|
334
344
|
# 1.year.to_i # => 31556952
|
335
345
|
#
|
336
346
|
# In such cases, Ruby's core
|
337
|
-
# Date[
|
338
|
-
# Time[
|
347
|
+
# Date[https://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
|
348
|
+
# Time[https://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
|
339
349
|
# date and time arithmetic.
|
340
350
|
def to_i
|
341
351
|
@value.to_i
|
342
352
|
end
|
353
|
+
alias :in_seconds :to_i
|
354
|
+
|
355
|
+
# Returns the amount of minutes a duration covers as a float
|
356
|
+
#
|
357
|
+
# 1.day.in_minutes # => 1440.0
|
358
|
+
def in_minutes
|
359
|
+
in_seconds / SECONDS_PER_MINUTE.to_f
|
360
|
+
end
|
361
|
+
|
362
|
+
# Returns the amount of hours a duration covers as a float
|
363
|
+
#
|
364
|
+
# 1.day.in_hours # => 24.0
|
365
|
+
def in_hours
|
366
|
+
in_seconds / SECONDS_PER_HOUR.to_f
|
367
|
+
end
|
368
|
+
|
369
|
+
# Returns the amount of days a duration covers as a float
|
370
|
+
#
|
371
|
+
# 12.hours.in_days # => 0.5
|
372
|
+
def in_days
|
373
|
+
in_seconds / SECONDS_PER_DAY.to_f
|
374
|
+
end
|
375
|
+
|
376
|
+
# Returns the amount of weeks a duration covers as a float
|
377
|
+
#
|
378
|
+
# 2.months.in_weeks # => 8.696
|
379
|
+
def in_weeks
|
380
|
+
in_seconds / SECONDS_PER_WEEK.to_f
|
381
|
+
end
|
382
|
+
|
383
|
+
# Returns the amount of months a duration covers as a float
|
384
|
+
#
|
385
|
+
# 9.weeks.in_months # => 2.07
|
386
|
+
def in_months
|
387
|
+
in_seconds / SECONDS_PER_MONTH.to_f
|
388
|
+
end
|
389
|
+
|
390
|
+
# Returns the amount of years a duration covers as a float
|
391
|
+
#
|
392
|
+
# 30.days.in_years # => 0.082
|
393
|
+
def in_years
|
394
|
+
in_seconds / SECONDS_PER_YEAR.to_f
|
395
|
+
end
|
343
396
|
|
344
397
|
# Returns +true+ if +other+ is also a Duration instance, which has the
|
345
398
|
# same parts as this one.
|
@@ -368,8 +421,9 @@ module ActiveSupport
|
|
368
421
|
alias :before :ago
|
369
422
|
|
370
423
|
def inspect #:nodoc:
|
424
|
+
return "#{value} seconds" if parts.empty?
|
425
|
+
|
371
426
|
parts.
|
372
|
-
reduce(::Hash.new(0)) { |h, (l, r)| h[l] += r; h }.
|
373
427
|
sort_by { |unit, _ | PARTS.index(unit) }.
|
374
428
|
map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }.
|
375
429
|
to_sentence(locale: ::I18n.default_locale)
|
@@ -379,10 +433,6 @@ module ActiveSupport
|
|
379
433
|
to_i
|
380
434
|
end
|
381
435
|
|
382
|
-
def respond_to_missing?(method, include_private = false) #:nodoc:
|
383
|
-
@value.respond_to?(method, include_private)
|
384
|
-
end
|
385
|
-
|
386
436
|
def init_with(coder) #:nodoc:
|
387
437
|
initialize(coder["value"], coder["parts"])
|
388
438
|
end
|
@@ -398,10 +448,15 @@ module ActiveSupport
|
|
398
448
|
end
|
399
449
|
|
400
450
|
private
|
401
|
-
|
402
451
|
def sum(sign, time = ::Time.current)
|
403
|
-
|
404
|
-
|
452
|
+
unless time.acts_like?(:time) || time.acts_like?(:date)
|
453
|
+
raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
|
454
|
+
end
|
455
|
+
|
456
|
+
if parts.empty?
|
457
|
+
time.since(sign * value)
|
458
|
+
else
|
459
|
+
parts.inject(time) do |t, (type, number)|
|
405
460
|
if type == :seconds
|
406
461
|
t.since(sign * number)
|
407
462
|
elsif type == :minutes
|
@@ -411,14 +466,16 @@ module ActiveSupport
|
|
411
466
|
else
|
412
467
|
t.advance(type => sign * number)
|
413
468
|
end
|
414
|
-
else
|
415
|
-
raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
|
416
469
|
end
|
417
470
|
end
|
418
471
|
end
|
419
472
|
|
473
|
+
def respond_to_missing?(method, _)
|
474
|
+
value.respond_to?(method)
|
475
|
+
end
|
476
|
+
|
420
477
|
def method_missing(method, *args, &block)
|
421
|
-
value.
|
478
|
+
value.public_send(method, *args, &block)
|
422
479
|
end
|
423
480
|
|
424
481
|
def raise_type_error(other)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
require "active_support/encrypted_file"
|
5
|
+
require "active_support/ordered_options"
|
6
|
+
require "active_support/core_ext/object/inclusion"
|
7
|
+
require "active_support/core_ext/module/delegation"
|
8
|
+
|
9
|
+
module ActiveSupport
|
10
|
+
class EncryptedConfiguration < EncryptedFile
|
11
|
+
delegate :[], :fetch, to: :config
|
12
|
+
delegate_missing_to :options
|
13
|
+
|
14
|
+
def initialize(config_path:, key_path:, env_key:, raise_if_missing_key:)
|
15
|
+
super content_path: config_path, key_path: key_path,
|
16
|
+
env_key: env_key, raise_if_missing_key: raise_if_missing_key
|
17
|
+
end
|
18
|
+
|
19
|
+
# Allow a config to be started without a file present
|
20
|
+
def read
|
21
|
+
super
|
22
|
+
rescue ActiveSupport::EncryptedFile::MissingContentError
|
23
|
+
""
|
24
|
+
end
|
25
|
+
|
26
|
+
def write(contents)
|
27
|
+
deserialize(contents)
|
28
|
+
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def config
|
33
|
+
@config ||= deserialize(read).deep_symbolize_keys
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def options
|
38
|
+
@options ||= ActiveSupport::InheritableOptions.new(config)
|
39
|
+
end
|
40
|
+
|
41
|
+
def deserialize(config)
|
42
|
+
YAML.load(config).presence || {}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
require "tmpdir"
|
5
|
+
require "active_support/message_encryptor"
|
6
|
+
|
7
|
+
module ActiveSupport
|
8
|
+
class EncryptedFile
|
9
|
+
class MissingContentError < RuntimeError
|
10
|
+
def initialize(content_path)
|
11
|
+
super "Missing encrypted content file in #{content_path}."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class MissingKeyError < RuntimeError
|
16
|
+
def initialize(key_path:, env_key:)
|
17
|
+
super \
|
18
|
+
"Missing encryption key to decrypt file with. " +
|
19
|
+
"Ask your team for your master key and write it to #{key_path} or put it in the ENV['#{env_key}']."
|
20
|
+
end
|
21
|
+
end
|
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
|
+
|
29
|
+
CIPHER = "aes-128-gcm"
|
30
|
+
|
31
|
+
def self.generate_key
|
32
|
+
SecureRandom.hex(ActiveSupport::MessageEncryptor.key_len(CIPHER))
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.expected_key_length # :nodoc:
|
36
|
+
@expected_key_length ||= generate_key.length
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
attr_reader :content_path, :key_path, :env_key, :raise_if_missing_key
|
41
|
+
|
42
|
+
def initialize(content_path:, key_path:, env_key:, raise_if_missing_key:)
|
43
|
+
@content_path = Pathname.new(content_path).yield_self { |path| path.symlink? ? path.realpath : path }
|
44
|
+
@key_path = Pathname.new(key_path)
|
45
|
+
@env_key, @raise_if_missing_key = env_key, raise_if_missing_key
|
46
|
+
end
|
47
|
+
|
48
|
+
def key
|
49
|
+
read_env_key || read_key_file || handle_missing_key
|
50
|
+
end
|
51
|
+
|
52
|
+
def read
|
53
|
+
if !key.nil? && content_path.exist?
|
54
|
+
decrypt content_path.binread
|
55
|
+
else
|
56
|
+
raise MissingContentError, content_path
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def write(contents)
|
61
|
+
IO.binwrite "#{content_path}.tmp", encrypt(contents)
|
62
|
+
FileUtils.mv "#{content_path}.tmp", content_path
|
63
|
+
end
|
64
|
+
|
65
|
+
def change(&block)
|
66
|
+
writing read, &block
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
private
|
71
|
+
def writing(contents)
|
72
|
+
tmp_file = "#{Process.pid}.#{content_path.basename.to_s.chomp('.enc')}"
|
73
|
+
tmp_path = Pathname.new File.join(Dir.tmpdir, tmp_file)
|
74
|
+
tmp_path.binwrite contents
|
75
|
+
|
76
|
+
yield tmp_path
|
77
|
+
|
78
|
+
updated_contents = tmp_path.binread
|
79
|
+
|
80
|
+
write(updated_contents) if updated_contents != contents
|
81
|
+
ensure
|
82
|
+
FileUtils.rm(tmp_path) if tmp_path&.exist?
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def encrypt(contents)
|
87
|
+
check_key_length
|
88
|
+
encryptor.encrypt_and_sign contents
|
89
|
+
end
|
90
|
+
|
91
|
+
def decrypt(contents)
|
92
|
+
encryptor.decrypt_and_verify contents
|
93
|
+
end
|
94
|
+
|
95
|
+
def encryptor
|
96
|
+
@encryptor ||= ActiveSupport::MessageEncryptor.new([ key ].pack("H*"), cipher: CIPHER)
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def read_env_key
|
101
|
+
ENV[env_key]
|
102
|
+
end
|
103
|
+
|
104
|
+
def read_key_file
|
105
|
+
return @key_file_contents if defined?(@key_file_contents)
|
106
|
+
@key_file_contents = (key_path.binread.strip if key_path.exist?)
|
107
|
+
end
|
108
|
+
|
109
|
+
def handle_missing_key
|
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
|
115
|
+
end
|
116
|
+
end
|
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
|