activesupport 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +572 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +40 -0
- data/lib/active_support.rb +96 -0
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +5 -0
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +132 -0
- data/lib/active_support/benchmarkable.rb +51 -0
- data/lib/active_support/builder.rb +8 -0
- data/lib/active_support/cache.rb +830 -0
- data/lib/active_support/cache/file_store.rb +196 -0
- data/lib/active_support/cache/mem_cache_store.rb +212 -0
- data/lib/active_support/cache/memory_store.rb +174 -0
- data/lib/active_support/cache/null_store.rb +48 -0
- data/lib/active_support/cache/redis_cache_store.rb +488 -0
- data/lib/active_support/cache/strategy/local_cache.rb +194 -0
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
- data/lib/active_support/callbacks.rb +856 -0
- data/lib/active_support/concern.rb +171 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
- data/lib/active_support/concurrency/share_lock.rb +227 -0
- data/lib/active_support/configurable.rb +146 -0
- data/lib/active_support/core_ext.rb +5 -0
- data/lib/active_support/core_ext/array.rb +9 -0
- data/lib/active_support/core_ext/array/access.rb +104 -0
- data/lib/active_support/core_ext/array/conversions.rb +213 -0
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +31 -0
- data/lib/active_support/core_ext/array/grouping.rb +109 -0
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -0
- data/lib/active_support/core_ext/array/wrap.rb +48 -0
- data/lib/active_support/core_ext/benchmark.rb +16 -0
- data/lib/active_support/core_ext/big_decimal.rb +3 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
- data/lib/active_support/core_ext/class.rb +4 -0
- data/lib/active_support/core_ext/class/attribute.rb +141 -0
- data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/class/subclasses.rb +54 -0
- data/lib/active_support/core_ext/date.rb +7 -0
- data/lib/active_support/core_ext/date/acts_like.rb +10 -0
- data/lib/active_support/core_ext/date/blank.rb +14 -0
- data/lib/active_support/core_ext/date/calculations.rb +146 -0
- data/lib/active_support/core_ext/date/conversions.rb +96 -0
- data/lib/active_support/core_ext/date/zones.rb +8 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +351 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
- data/lib/active_support/core_ext/date_time.rb +7 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
- data/lib/active_support/core_ext/date_time/blank.rb +14 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +211 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +107 -0
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/digest/uuid.rb +53 -0
- data/lib/active_support/core_ext/enumerable.rb +188 -0
- data/lib/active_support/core_ext/file.rb +3 -0
- data/lib/active_support/core_ext/file/atomic.rb +70 -0
- data/lib/active_support/core_ext/hash.rb +10 -0
- data/lib/active_support/core_ext/hash/compact.rb +5 -0
- data/lib/active_support/core_ext/hash/conversions.rb +263 -0
- data/lib/active_support/core_ext/hash/deep_merge.rb +34 -0
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +24 -0
- data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
- data/lib/active_support/core_ext/hash/keys.rb +143 -0
- data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
- data/lib/active_support/core_ext/hash/slice.rb +26 -0
- data/lib/active_support/core_ext/hash/transform_values.rb +5 -0
- data/lib/active_support/core_ext/integer.rb +5 -0
- data/lib/active_support/core_ext/integer/inflections.rb +31 -0
- data/lib/active_support/core_ext/integer/multiple.rb +12 -0
- data/lib/active_support/core_ext/integer/time.rb +22 -0
- data/lib/active_support/core_ext/kernel.rb +5 -0
- data/lib/active_support/core_ext/kernel/concern.rb +14 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
- data/lib/active_support/core_ext/load_error.rb +9 -0
- data/lib/active_support/core_ext/marshal.rb +24 -0
- data/lib/active_support/core_ext/module.rb +13 -0
- data/lib/active_support/core_ext/module/aliasing.rb +31 -0
- data/lib/active_support/core_ext/module/anonymous.rb +30 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +38 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
- data/lib/active_support/core_ext/module/concerning.rb +134 -0
- data/lib/active_support/core_ext/module/delegation.rb +313 -0
- data/lib/active_support/core_ext/module/deprecation.rb +25 -0
- data/lib/active_support/core_ext/module/introspection.rb +86 -0
- data/lib/active_support/core_ext/module/reachable.rb +6 -0
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +17 -0
- data/lib/active_support/core_ext/name_error.rb +38 -0
- data/lib/active_support/core_ext/numeric.rb +5 -0
- data/lib/active_support/core_ext/numeric/bytes.rb +66 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +136 -0
- data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
- data/lib/active_support/core_ext/numeric/time.rb +66 -0
- data/lib/active_support/core_ext/object.rb +16 -0
- data/lib/active_support/core_ext/object/acts_like.rb +21 -0
- data/lib/active_support/core_ext/object/blank.rb +155 -0
- data/lib/active_support/core_ext/object/conversions.rb +6 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +55 -0
- data/lib/active_support/core_ext/object/duplicable.rb +49 -0
- data/lib/active_support/core_ext/object/inclusion.rb +29 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +30 -0
- data/lib/active_support/core_ext/object/json.rb +228 -0
- data/lib/active_support/core_ext/object/to_param.rb +3 -0
- data/lib/active_support/core_ext/object/to_query.rb +89 -0
- data/lib/active_support/core_ext/object/try.rb +156 -0
- data/lib/active_support/core_ext/object/with_options.rb +82 -0
- data/lib/active_support/core_ext/range.rb +7 -0
- data/lib/active_support/core_ext/range/compare_range.rb +70 -0
- data/lib/active_support/core_ext/range/conversions.rb +41 -0
- data/lib/active_support/core_ext/range/each.rb +25 -0
- data/lib/active_support/core_ext/range/include_range.rb +9 -0
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
- data/lib/active_support/core_ext/range/overlaps.rb +10 -0
- data/lib/active_support/core_ext/regexp.rb +7 -0
- data/lib/active_support/core_ext/securerandom.rb +45 -0
- data/lib/active_support/core_ext/string.rb +15 -0
- data/lib/active_support/core_ext/string/access.rb +114 -0
- data/lib/active_support/core_ext/string/behavior.rb +8 -0
- data/lib/active_support/core_ext/string/conversions.rb +59 -0
- data/lib/active_support/core_ext/string/exclude.rb +13 -0
- data/lib/active_support/core_ext/string/filters.rb +145 -0
- data/lib/active_support/core_ext/string/indent.rb +45 -0
- data/lib/active_support/core_ext/string/inflections.rb +259 -0
- data/lib/active_support/core_ext/string/inquiry.rb +15 -0
- data/lib/active_support/core_ext/string/multibyte.rb +58 -0
- data/lib/active_support/core_ext/string/output_safety.rb +314 -0
- data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/string/strip.rb +27 -0
- data/lib/active_support/core_ext/string/zones.rb +16 -0
- data/lib/active_support/core_ext/time.rb +7 -0
- data/lib/active_support/core_ext/time/acts_like.rb +10 -0
- data/lib/active_support/core_ext/time/calculations.rb +344 -0
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +72 -0
- data/lib/active_support/core_ext/time/zones.rb +113 -0
- data/lib/active_support/core_ext/uri.rb +25 -0
- data/lib/active_support/current_attributes.rb +203 -0
- data/lib/active_support/dependencies.rb +806 -0
- data/lib/active_support/dependencies/autoload.rb +79 -0
- data/lib/active_support/dependencies/interlock.rb +57 -0
- data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
- data/lib/active_support/deprecation.rb +46 -0
- data/lib/active_support/deprecation/behaviors.rb +109 -0
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/instance_delegator.rb +39 -0
- data/lib/active_support/deprecation/method_wrappers.rb +78 -0
- data/lib/active_support/deprecation/proxy_wrappers.rb +173 -0
- data/lib/active_support/deprecation/reporting.rb +114 -0
- data/lib/active_support/descendants_tracker.rb +109 -0
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration.rb +433 -0
- data/lib/active_support/duration/iso8601_parser.rb +124 -0
- data/lib/active_support/duration/iso8601_serializer.rb +54 -0
- data/lib/active_support/encrypted_configuration.rb +45 -0
- data/lib/active_support/encrypted_file.rb +100 -0
- data/lib/active_support/evented_file_update_checker.rb +235 -0
- data/lib/active_support/execution_wrapper.rb +129 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +163 -0
- data/lib/active_support/gem_version.rb +17 -0
- data/lib/active_support/gzip.rb +38 -0
- data/lib/active_support/hash_with_indifferent_access.rb +399 -0
- data/lib/active_support/i18n.rb +16 -0
- data/lib/active_support/i18n_railtie.rb +126 -0
- data/lib/active_support/inflections.rb +72 -0
- data/lib/active_support/inflector.rb +9 -0
- data/lib/active_support/inflector/inflections.rb +257 -0
- data/lib/active_support/inflector/methods.rb +398 -0
- data/lib/active_support/inflector/transliterate.rb +147 -0
- data/lib/active_support/json.rb +4 -0
- data/lib/active_support/json/decoding.rb +76 -0
- data/lib/active_support/json/encoding.rb +134 -0
- data/lib/active_support/key_generator.rb +41 -0
- data/lib/active_support/lazy_load_hooks.rb +82 -0
- data/lib/active_support/locale/en.rb +31 -0
- data/lib/active_support/locale/en.yml +135 -0
- data/lib/active_support/log_subscriber.rb +135 -0
- data/lib/active_support/log_subscriber/test_helper.rb +106 -0
- data/lib/active_support/logger.rb +93 -0
- data/lib/active_support/logger_silence.rb +45 -0
- data/lib/active_support/logger_thread_safe_level.rb +56 -0
- data/lib/active_support/message_encryptor.rb +227 -0
- data/lib/active_support/message_verifier.rb +205 -0
- data/lib/active_support/messages/metadata.rb +71 -0
- data/lib/active_support/messages/rotation_configuration.rb +22 -0
- data/lib/active_support/messages/rotator.rb +56 -0
- data/lib/active_support/multibyte.rb +23 -0
- data/lib/active_support/multibyte/chars.rb +216 -0
- data/lib/active_support/multibyte/unicode.rb +157 -0
- data/lib/active_support/notifications.rb +253 -0
- data/lib/active_support/notifications/fanout.rb +244 -0
- data/lib/active_support/notifications/instrumenter.rb +164 -0
- data/lib/active_support/number_helper.rb +378 -0
- data/lib/active_support/number_helper/number_converter.rb +184 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +31 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +70 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +61 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +56 -0
- data/lib/active_support/number_helper/rounding_helper.rb +66 -0
- data/lib/active_support/option_merger.rb +27 -0
- data/lib/active_support/ordered_hash.rb +50 -0
- data/lib/active_support/ordered_options.rb +85 -0
- data/lib/active_support/parameter_filter.rb +129 -0
- data/lib/active_support/per_thread_registry.rb +60 -0
- data/lib/active_support/proxy_object.rb +15 -0
- data/lib/active_support/rails.rb +29 -0
- data/lib/active_support/railtie.rb +80 -0
- data/lib/active_support/reloader.rb +130 -0
- data/lib/active_support/rescuable.rb +174 -0
- data/lib/active_support/security_utils.rb +31 -0
- data/lib/active_support/string_inquirer.rb +34 -0
- data/lib/active_support/subscriber.rb +169 -0
- data/lib/active_support/tagged_logging.rb +88 -0
- data/lib/active_support/test_case.rb +163 -0
- data/lib/active_support/testing/assertions.rb +228 -0
- data/lib/active_support/testing/autorun.rb +7 -0
- data/lib/active_support/testing/constant_lookup.rb +51 -0
- data/lib/active_support/testing/declarative.rb +28 -0
- data/lib/active_support/testing/deprecation.rb +38 -0
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +110 -0
- data/lib/active_support/testing/method_call_assertions.rb +70 -0
- data/lib/active_support/testing/parallelization.rb +128 -0
- data/lib/active_support/testing/setup_and_teardown.rb +55 -0
- data/lib/active_support/testing/stream.rb +44 -0
- data/lib/active_support/testing/tagged_logging.rb +27 -0
- data/lib/active_support/testing/time_helpers.rb +200 -0
- data/lib/active_support/time.rb +20 -0
- data/lib/active_support/time_with_zone.rb +561 -0
- data/lib/active_support/values/time_zone.rb +570 -0
- data/lib/active_support/version.rb +10 -0
- data/lib/active_support/xml_mini.rb +202 -0
- data/lib/active_support/xml_mini/jdom.rb +183 -0
- data/lib/active_support/xml_mini/libxml.rb +80 -0
- data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
- data/lib/active_support/xml_mini/nokogiri.rb +83 -0
- data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
- data/lib/active_support/xml_mini/rexml.rb +130 -0
- metadata +385 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/number_helper/number_converter"
|
|
4
|
+
|
|
5
|
+
module ActiveSupport
|
|
6
|
+
module NumberHelper
|
|
7
|
+
class NumberToRoundedConverter < NumberConverter # :nodoc:
|
|
8
|
+
self.namespace = :precision
|
|
9
|
+
self.validate_float = true
|
|
10
|
+
|
|
11
|
+
def convert
|
|
12
|
+
helper = RoundingHelper.new(options)
|
|
13
|
+
rounded_number = helper.round(number)
|
|
14
|
+
|
|
15
|
+
if precision = options[:precision]
|
|
16
|
+
if options[:significant] && precision > 0
|
|
17
|
+
digits = helper.digit_count(rounded_number)
|
|
18
|
+
precision -= digits
|
|
19
|
+
precision = 0 if precision < 0 # don't let it be negative
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
formatted_string =
|
|
23
|
+
if BigDecimal === rounded_number && rounded_number.finite?
|
|
24
|
+
s = rounded_number.to_s("F")
|
|
25
|
+
s << "0" * precision
|
|
26
|
+
a, b = s.split(".", 2)
|
|
27
|
+
a << "."
|
|
28
|
+
a << b[0, precision]
|
|
29
|
+
else
|
|
30
|
+
"%00.#{precision}f" % rounded_number
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
formatted_string = rounded_number
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
delimited_number = NumberToDelimitedConverter.convert(formatted_string, options)
|
|
37
|
+
format_number(delimited_number)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def strip_insignificant_zeros
|
|
43
|
+
options[:strip_insignificant_zeros]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def format_number(number)
|
|
47
|
+
if strip_insignificant_zeros
|
|
48
|
+
escaped_separator = Regexp.escape(options[:separator])
|
|
49
|
+
number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, "")
|
|
50
|
+
else
|
|
51
|
+
number
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
module NumberHelper
|
|
5
|
+
class RoundingHelper # :nodoc:
|
|
6
|
+
attr_reader :options
|
|
7
|
+
|
|
8
|
+
def initialize(options)
|
|
9
|
+
@options = options
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def round(number)
|
|
13
|
+
return number unless precision
|
|
14
|
+
number = convert_to_decimal(number)
|
|
15
|
+
if significant && precision > 0
|
|
16
|
+
round_significant(number)
|
|
17
|
+
else
|
|
18
|
+
round_without_significant(number)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def digit_count(number)
|
|
23
|
+
return 1 if number.zero?
|
|
24
|
+
(Math.log10(absolute_number(number)) + 1).floor
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
def round_without_significant(number)
|
|
29
|
+
number = number.round(precision)
|
|
30
|
+
number = number.to_i if precision == 0 && number.finite?
|
|
31
|
+
number = number.abs if number.zero? # prevent showing negative zeros
|
|
32
|
+
number
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def round_significant(number)
|
|
36
|
+
return 0 if number.zero?
|
|
37
|
+
digits = digit_count(number)
|
|
38
|
+
multiplier = 10**(digits - precision)
|
|
39
|
+
(number / BigDecimal(multiplier.to_f.to_s)).round * multiplier
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def convert_to_decimal(number)
|
|
43
|
+
case number
|
|
44
|
+
when Float, String
|
|
45
|
+
BigDecimal(number.to_s)
|
|
46
|
+
when Rational
|
|
47
|
+
BigDecimal(number, digit_count(number.to_i) + precision)
|
|
48
|
+
else
|
|
49
|
+
number.to_d
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def precision
|
|
54
|
+
options[:precision]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def significant
|
|
58
|
+
options[:significant]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def absolute_number(number)
|
|
62
|
+
number.respond_to?(:abs) ? number.abs : number.to_d.abs
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/hash/deep_merge"
|
|
4
|
+
|
|
5
|
+
module ActiveSupport
|
|
6
|
+
class OptionMerger #:nodoc:
|
|
7
|
+
instance_methods.each do |method|
|
|
8
|
+
undef_method(method) if method !~ /^(__|instance_eval|class|object_id)/
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(context, options)
|
|
12
|
+
@context, @options = context, options
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
def method_missing(method, *arguments, &block)
|
|
17
|
+
if arguments.first.is_a?(Proc)
|
|
18
|
+
proc = arguments.pop
|
|
19
|
+
arguments << lambda { |*args| @options.deep_merge(proc.call(*args)) }
|
|
20
|
+
else
|
|
21
|
+
arguments << (arguments.last.respond_to?(:to_hash) ? @options.deep_merge(arguments.pop) : @options.dup)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
@context.__send__(method, *arguments, &block)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "yaml"
|
|
4
|
+
|
|
5
|
+
YAML.add_builtin_type("omap") do |type, val|
|
|
6
|
+
ActiveSupport::OrderedHash[val.map { |v| v.to_a.first }]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ActiveSupport
|
|
10
|
+
# DEPRECATED: <tt>ActiveSupport::OrderedHash</tt> implements a hash that preserves
|
|
11
|
+
# insertion order.
|
|
12
|
+
#
|
|
13
|
+
# oh = ActiveSupport::OrderedHash.new
|
|
14
|
+
# oh[:a] = 1
|
|
15
|
+
# oh[:b] = 2
|
|
16
|
+
# oh.keys # => [:a, :b], this order is guaranteed
|
|
17
|
+
#
|
|
18
|
+
# Also, maps the +omap+ feature for YAML files
|
|
19
|
+
# (See http://yaml.org/type/omap.html) to support ordered items
|
|
20
|
+
# when loading from yaml.
|
|
21
|
+
#
|
|
22
|
+
# <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
|
|
23
|
+
# with other implementations.
|
|
24
|
+
class OrderedHash < ::Hash
|
|
25
|
+
def to_yaml_type
|
|
26
|
+
"!tag:yaml.org,2002:omap"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def encode_with(coder)
|
|
30
|
+
coder.represent_seq "!omap", map { |k, v| { k => v } }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def select(*args, &block)
|
|
34
|
+
dup.tap { |hash| hash.select!(*args, &block) }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def reject(*args, &block)
|
|
38
|
+
dup.tap { |hash| hash.reject!(*args, &block) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def nested_under_indifferent_access
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Returns true to make sure that this hash is extractable via <tt>Array#extract_options!</tt>
|
|
46
|
+
def extractable_options?
|
|
47
|
+
true
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/object/blank"
|
|
4
|
+
|
|
5
|
+
module ActiveSupport
|
|
6
|
+
# Usually key value pairs are handled something like this:
|
|
7
|
+
#
|
|
8
|
+
# h = {}
|
|
9
|
+
# h[:boy] = 'John'
|
|
10
|
+
# h[:girl] = 'Mary'
|
|
11
|
+
# h[:boy] # => 'John'
|
|
12
|
+
# h[:girl] # => 'Mary'
|
|
13
|
+
# h[:dog] # => nil
|
|
14
|
+
#
|
|
15
|
+
# Using +OrderedOptions+, the above code could be reduced to:
|
|
16
|
+
#
|
|
17
|
+
# h = ActiveSupport::OrderedOptions.new
|
|
18
|
+
# h.boy = 'John'
|
|
19
|
+
# h.girl = 'Mary'
|
|
20
|
+
# h.boy # => 'John'
|
|
21
|
+
# h.girl # => 'Mary'
|
|
22
|
+
# h.dog # => nil
|
|
23
|
+
#
|
|
24
|
+
# To raise an exception when the value is blank, append a
|
|
25
|
+
# bang to the key name, like:
|
|
26
|
+
#
|
|
27
|
+
# h.dog! # => raises KeyError: :dog is blank
|
|
28
|
+
#
|
|
29
|
+
class OrderedOptions < Hash
|
|
30
|
+
alias_method :_get, :[] # preserve the original #[] method
|
|
31
|
+
protected :_get # make it protected
|
|
32
|
+
|
|
33
|
+
def []=(key, value)
|
|
34
|
+
super(key.to_sym, value)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def [](key)
|
|
38
|
+
super(key.to_sym)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def method_missing(name, *args)
|
|
42
|
+
name_string = name.to_s
|
|
43
|
+
if name_string.chomp!("=")
|
|
44
|
+
self[name_string] = args.first
|
|
45
|
+
else
|
|
46
|
+
bangs = name_string.chomp!("!")
|
|
47
|
+
|
|
48
|
+
if bangs
|
|
49
|
+
self[name_string].presence || raise(KeyError.new(":#{name_string} is blank"))
|
|
50
|
+
else
|
|
51
|
+
self[name_string]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def respond_to_missing?(name, include_private)
|
|
57
|
+
true
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# +InheritableOptions+ provides a constructor to build an +OrderedOptions+
|
|
62
|
+
# hash inherited from another hash.
|
|
63
|
+
#
|
|
64
|
+
# Use this if you already have some hash and you want to create a new one based on it.
|
|
65
|
+
#
|
|
66
|
+
# h = ActiveSupport::InheritableOptions.new({ girl: 'Mary', boy: 'John' })
|
|
67
|
+
# h.girl # => 'Mary'
|
|
68
|
+
# h.boy # => 'John'
|
|
69
|
+
class InheritableOptions < OrderedOptions
|
|
70
|
+
def initialize(parent = nil)
|
|
71
|
+
if parent.kind_of?(OrderedOptions)
|
|
72
|
+
# use the faster _get when dealing with OrderedOptions
|
|
73
|
+
super() { |h, k| parent._get(k) }
|
|
74
|
+
elsif parent
|
|
75
|
+
super() { |h, k| parent[k] }
|
|
76
|
+
else
|
|
77
|
+
super()
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def inheritable_copy
|
|
82
|
+
self.class.new(self)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/object/duplicable"
|
|
4
|
+
require "active_support/core_ext/array/extract"
|
|
5
|
+
|
|
6
|
+
module ActiveSupport
|
|
7
|
+
# +ParameterFilter+ allows you to specify keys for sensitive data from
|
|
8
|
+
# hash-like object and replace corresponding value. Filtering only certain
|
|
9
|
+
# sub-keys from a hash is possible by using the dot notation:
|
|
10
|
+
# 'credit_card.number'. If a proc is given, each key and value of a hash and
|
|
11
|
+
# all sub-hashes are passed to it, where the value or the key can be replaced
|
|
12
|
+
# using String#replace or similar methods.
|
|
13
|
+
#
|
|
14
|
+
# ActiveSupport::ParameterFilter.new([:password])
|
|
15
|
+
# => replaces the value to all keys matching /password/i with "[FILTERED]"
|
|
16
|
+
#
|
|
17
|
+
# ActiveSupport::ParameterFilter.new([:foo, "bar"])
|
|
18
|
+
# => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
|
|
19
|
+
#
|
|
20
|
+
# ActiveSupport::ParameterFilter.new(["credit_card.code"])
|
|
21
|
+
# => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
|
|
22
|
+
# change { file: { code: "xxxx"} }
|
|
23
|
+
#
|
|
24
|
+
# ActiveSupport::ParameterFilter.new([-> (k, v) do
|
|
25
|
+
# v.reverse! if k =~ /secret/i
|
|
26
|
+
# end])
|
|
27
|
+
# => reverses the value to all keys matching /secret/i
|
|
28
|
+
class ParameterFilter
|
|
29
|
+
FILTERED = "[FILTERED]" # :nodoc:
|
|
30
|
+
|
|
31
|
+
# Create instance with given filters. Supported type of filters are +String+, +Regexp+, and +Proc+.
|
|
32
|
+
# Other types of filters are treated as +String+ using +to_s+.
|
|
33
|
+
# For +Proc+ filters, key, value, and optional original hash is passed to block arguments.
|
|
34
|
+
#
|
|
35
|
+
# ==== Options
|
|
36
|
+
#
|
|
37
|
+
# * <tt>:mask</tt> - A replaced object when filtered. Defaults to +"[FILTERED]"+
|
|
38
|
+
def initialize(filters = [], mask: FILTERED)
|
|
39
|
+
@filters = filters
|
|
40
|
+
@mask = mask
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Mask value of +params+ if key matches one of filters.
|
|
44
|
+
def filter(params)
|
|
45
|
+
compiled_filter.call(params)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns filtered value for given key. For +Proc+ filters, third block argument is not populated.
|
|
49
|
+
def filter_param(key, value)
|
|
50
|
+
@filters.empty? ? value : compiled_filter.value_for_key(key, value)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def compiled_filter
|
|
56
|
+
@compiled_filter ||= CompiledFilter.compile(@filters, mask: @mask)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class CompiledFilter # :nodoc:
|
|
60
|
+
def self.compile(filters, mask:)
|
|
61
|
+
return lambda { |params| params.dup } if filters.empty?
|
|
62
|
+
|
|
63
|
+
strings, regexps, blocks = [], [], []
|
|
64
|
+
|
|
65
|
+
filters.each do |item|
|
|
66
|
+
case item
|
|
67
|
+
when Proc
|
|
68
|
+
blocks << item
|
|
69
|
+
when Regexp
|
|
70
|
+
regexps << item
|
|
71
|
+
else
|
|
72
|
+
strings << Regexp.escape(item.to_s)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
deep_regexps = regexps.extract! { |r| r.to_s.include?("\\.") }
|
|
77
|
+
deep_strings = strings.extract! { |s| s.include?("\\.") }
|
|
78
|
+
|
|
79
|
+
regexps << Regexp.new(strings.join("|"), true) unless strings.empty?
|
|
80
|
+
deep_regexps << Regexp.new(deep_strings.join("|"), true) unless deep_strings.empty?
|
|
81
|
+
|
|
82
|
+
new regexps, deep_regexps, blocks, mask: mask
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
attr_reader :regexps, :deep_regexps, :blocks
|
|
86
|
+
|
|
87
|
+
def initialize(regexps, deep_regexps, blocks, mask:)
|
|
88
|
+
@regexps = regexps
|
|
89
|
+
@deep_regexps = deep_regexps.any? ? deep_regexps : nil
|
|
90
|
+
@blocks = blocks
|
|
91
|
+
@mask = mask
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def call(params, parents = [], original_params = params)
|
|
95
|
+
filtered_params = params.class.new
|
|
96
|
+
|
|
97
|
+
params.each do |key, value|
|
|
98
|
+
filtered_params[key] = value_for_key(key, value, parents, original_params)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
filtered_params
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def value_for_key(key, value, parents = [], original_params = nil)
|
|
105
|
+
parents.push(key) if deep_regexps
|
|
106
|
+
if regexps.any? { |r| r.match?(key) }
|
|
107
|
+
value = @mask
|
|
108
|
+
elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| r.match?(joined) }
|
|
109
|
+
value = @mask
|
|
110
|
+
elsif value.is_a?(Hash)
|
|
111
|
+
value = call(value, parents, original_params)
|
|
112
|
+
elsif value.is_a?(Array)
|
|
113
|
+
# If we don't pop the current parent it will be duplicated as we
|
|
114
|
+
# process each array value.
|
|
115
|
+
parents.pop if deep_regexps
|
|
116
|
+
value = value.map { |v| value_for_key(key, v, parents, original_params) }
|
|
117
|
+
# Restore the parent stack after processing the array.
|
|
118
|
+
parents.push(key) if deep_regexps
|
|
119
|
+
elsif blocks.any?
|
|
120
|
+
key = key.dup if key.duplicable?
|
|
121
|
+
value = value.dup if value.duplicable?
|
|
122
|
+
blocks.each { |b| b.arity == 2 ? b.call(key, value) : b.call(key, value, original_params) }
|
|
123
|
+
end
|
|
124
|
+
parents.pop if deep_regexps
|
|
125
|
+
value
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/module/delegation"
|
|
4
|
+
|
|
5
|
+
module ActiveSupport
|
|
6
|
+
# NOTE: This approach has been deprecated for end-user code in favor of {thread_mattr_accessor}[rdoc-ref:Module#thread_mattr_accessor] and friends.
|
|
7
|
+
# Please use that approach instead.
|
|
8
|
+
#
|
|
9
|
+
# This module is used to encapsulate access to thread local variables.
|
|
10
|
+
#
|
|
11
|
+
# Instead of polluting the thread locals namespace:
|
|
12
|
+
#
|
|
13
|
+
# Thread.current[:connection_handler]
|
|
14
|
+
#
|
|
15
|
+
# you define a class that extends this module:
|
|
16
|
+
#
|
|
17
|
+
# module ActiveRecord
|
|
18
|
+
# class RuntimeRegistry
|
|
19
|
+
# extend ActiveSupport::PerThreadRegistry
|
|
20
|
+
#
|
|
21
|
+
# attr_accessor :connection_handler
|
|
22
|
+
# end
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# and invoke the declared instance accessors as class methods. So
|
|
26
|
+
#
|
|
27
|
+
# ActiveRecord::RuntimeRegistry.connection_handler = connection_handler
|
|
28
|
+
#
|
|
29
|
+
# sets a connection handler local to the current thread, and
|
|
30
|
+
#
|
|
31
|
+
# ActiveRecord::RuntimeRegistry.connection_handler
|
|
32
|
+
#
|
|
33
|
+
# returns a connection handler local to the current thread.
|
|
34
|
+
#
|
|
35
|
+
# This feature is accomplished by instantiating the class and storing the
|
|
36
|
+
# instance as a thread local keyed by the class name. In the example above
|
|
37
|
+
# a key "ActiveRecord::RuntimeRegistry" is stored in <tt>Thread.current</tt>.
|
|
38
|
+
# The class methods proxy to said thread local instance.
|
|
39
|
+
#
|
|
40
|
+
# If the class has an initializer, it must accept no arguments.
|
|
41
|
+
module PerThreadRegistry
|
|
42
|
+
def self.extended(object)
|
|
43
|
+
object.instance_variable_set "@per_thread_registry_key", object.name.freeze
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def instance
|
|
47
|
+
Thread.current[@per_thread_registry_key] ||= new
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
def method_missing(name, *args, &block)
|
|
52
|
+
# Caches the method definition as a singleton method of the receiver.
|
|
53
|
+
#
|
|
54
|
+
# By letting #delegate handle it, we avoid an enclosure that'll capture args.
|
|
55
|
+
singleton_class.delegate name, to: :instance
|
|
56
|
+
|
|
57
|
+
send(name, *args, &block)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|