activesupport 5.0.0 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +343 -590
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -4
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +11 -5
- data/lib/active_support/backtrace_cleaner.rb +33 -5
- data/lib/active_support/benchmarkable.rb +5 -3
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +45 -53
- data/lib/active_support/cache/mem_cache_store.rb +81 -79
- data/lib/active_support/cache/memory_store.rb +69 -41
- data/lib/active_support/cache/null_store.rb +11 -4
- data/lib/active_support/cache/redis_cache_store.rb +493 -0
- data/lib/active_support/cache/strategy/local_cache.rb +74 -37
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
- data/lib/active_support/cache.rb +332 -161
- data/lib/active_support/callbacks.rb +657 -586
- data/lib/active_support/concern.rb +79 -6
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
- data/lib/active_support/concurrency/share_lock.rb +59 -19
- data/lib/active_support/configurable.rb +15 -17
- data/lib/active_support/configuration_file.rb +46 -0
- data/lib/active_support/core_ext/array/access.rb +21 -7
- data/lib/active_support/core_ext/array/conversions.rb +20 -18
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +3 -1
- data/lib/active_support/core_ext/array/inquiry.rb +3 -1
- data/lib/active_support/core_ext/array/wrap.rb +2 -0
- data/lib/active_support/core_ext/array.rb +9 -7
- data/lib/active_support/core_ext/benchmark.rb +5 -3
- data/lib/active_support/core_ext/big_decimal/conversions.rb +6 -6
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/class/attribute.rb +52 -49
- data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
- data/lib/active_support/core_ext/class/subclasses.rb +18 -26
- data/lib/active_support/core_ext/class.rb +4 -2
- data/lib/active_support/core_ext/date/acts_like.rb +3 -1
- data/lib/active_support/core_ext/date/blank.rb +3 -1
- data/lib/active_support/core_ext/date/calculations.rb +16 -13
- data/lib/active_support/core_ext/date/conversions.rb +23 -21
- data/lib/active_support/core_ext/date/zones.rb +4 -2
- data/lib/active_support/core_ext/date.rb +7 -5
- data/lib/active_support/core_ext/date_and_time/calculations.rb +82 -53
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -5
- data/lib/active_support/core_ext/date_and_time/zones.rb +9 -9
- data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
- data/lib/active_support/core_ext/date_time/blank.rb +3 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +23 -11
- data/lib/active_support/core_ext/date_time/compatibility.rb +15 -2
- data/lib/active_support/core_ext/date_time/conversions.rb +14 -13
- data/lib/active_support/core_ext/date_time.rb +7 -5
- data/lib/active_support/core_ext/digest/uuid.rb +7 -5
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +165 -29
- data/lib/active_support/core_ext/file/atomic.rb +7 -5
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +40 -39
- data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +4 -2
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -2
- data/lib/active_support/core_ext/hash/keys.rb +9 -36
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -29
- data/lib/active_support/core_ext/hash.rb +10 -9
- data/lib/active_support/core_ext/integer/inflections.rb +3 -1
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +11 -18
- data/lib/active_support/core_ext/integer.rb +5 -3
- data/lib/active_support/core_ext/kernel/concern.rb +3 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +3 -1
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +5 -4
- data/lib/active_support/core_ext/load_error.rb +2 -23
- data/lib/active_support/core_ext/marshal.rb +6 -2
- data/lib/active_support/core_ext/module/aliasing.rb +5 -48
- data/lib/active_support/core_ext/module/anonymous.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +7 -5
- data/lib/active_support/core_ext/module/attribute_accessors.rb +53 -59
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +31 -24
- data/lib/active_support/core_ext/module/concerning.rb +16 -11
- data/lib/active_support/core_ext/module/delegation.rb +159 -44
- data/lib/active_support/core_ext/module/deprecation.rb +2 -0
- data/lib/active_support/core_ext/module/introspection.rb +23 -26
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +5 -23
- data/lib/active_support/core_ext/module.rb +13 -12
- data/lib/active_support/core_ext/name_error.rb +36 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -134
- data/lib/active_support/core_ext/numeric/time.rb +18 -26
- data/lib/active_support/core_ext/numeric.rb +5 -4
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +14 -2
- data/lib/active_support/core_ext/object/conversions.rb +6 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +4 -2
- data/lib/active_support/core_ext/object/duplicable.rb +13 -62
- data/lib/active_support/core_ext/object/inclusion.rb +3 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
- data/lib/active_support/core_ext/object/json.rb +42 -15
- data/lib/active_support/core_ext/object/to_param.rb +3 -1
- data/lib/active_support/core_ext/object/to_query.rb +10 -5
- data/lib/active_support/core_ext/object/try.rb +20 -8
- data/lib/active_support/core_ext/object/with_options.rb +15 -2
- data/lib/active_support/core_ext/object.rb +14 -12
- data/lib/active_support/core_ext/range/compare_range.rb +82 -0
- data/lib/active_support/core_ext/range/conversions.rb +35 -25
- data/lib/active_support/core_ext/range/each.rb +5 -2
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
- data/lib/active_support/core_ext/range/overlaps.rb +2 -0
- data/lib/active_support/core_ext/range.rb +7 -4
- data/lib/active_support/core_ext/regexp.rb +10 -1
- data/lib/active_support/core_ext/securerandom.rb +28 -6
- data/lib/active_support/core_ext/string/access.rb +9 -18
- data/lib/active_support/core_ext/string/behavior.rb +2 -0
- data/lib/active_support/core_ext/string/conversions.rb +5 -2
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +47 -4
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +78 -29
- data/lib/active_support/core_ext/string/inquiry.rb +4 -1
- data/lib/active_support/core_ext/string/multibyte.rb +10 -5
- data/lib/active_support/core_ext/string/output_safety.rb +86 -31
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
- data/lib/active_support/core_ext/string/strip.rb +5 -1
- data/lib/active_support/core_ext/string/zones.rb +4 -2
- data/lib/active_support/core_ext/string.rb +15 -13
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +117 -45
- data/lib/active_support/core_ext/time/compatibility.rb +13 -2
- data/lib/active_support/core_ext/time/conversions.rb +18 -12
- data/lib/active_support/core_ext/time/zones.rb +9 -7
- data/lib/active_support/core_ext/time.rb +7 -5
- data/lib/active_support/core_ext/uri.rb +12 -7
- data/lib/active_support/core_ext.rb +3 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +208 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +7 -1
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +172 -98
- data/lib/active_support/deprecation/behaviors.rb +45 -13
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +16 -2
- data/lib/active_support/deprecation/method_wrappers.rb +32 -17
- data/lib/active_support/deprecation/proxy_wrappers.rb +35 -7
- data/lib/active_support/deprecation/reporting.rb +61 -16
- data/lib/active_support/deprecation.rb +17 -9
- data/lib/active_support/descendants_tracker.rb +61 -9
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration/iso8601_parser.rb +67 -66
- data/lib/active_support/duration/iso8601_serializer.rb +25 -17
- data/lib/active_support/duration.rb +349 -46
- data/lib/active_support/encrypted_configuration.rb +45 -0
- data/lib/active_support/encrypted_file.rb +117 -0
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +88 -112
- data/lib/active_support/execution_wrapper.rb +25 -13
- data/lib/active_support/executor.rb +3 -1
- data/lib/active_support/file_update_checker.rb +56 -51
- data/lib/active_support/fork_tracker.rb +62 -0
- data/lib/active_support/gem_version.rb +4 -2
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +153 -49
- data/lib/active_support/i18n.rb +9 -6
- data/lib/active_support/i18n_railtie.rb +30 -20
- data/lib/active_support/inflections.rb +13 -11
- data/lib/active_support/inflector/inflections.rb +28 -15
- data/lib/active_support/inflector/methods.rb +120 -109
- data/lib/active_support/inflector/transliterate.rb +60 -25
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/json/decoding.rb +30 -29
- data/lib/active_support/json/encoding.rb +22 -11
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +6 -36
- data/lib/active_support/lazy_load_hooks.rb +53 -20
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber/test_helper.rb +11 -9
- data/lib/active_support/log_subscriber.rb +51 -18
- data/lib/active_support/logger.rb +9 -22
- data/lib/active_support/logger_silence.rb +14 -21
- data/lib/active_support/logger_thread_safe_level.rb +55 -8
- data/lib/active_support/message_encryptor.rb +170 -53
- data/lib/active_support/message_verifier.rb +91 -20
- data/lib/active_support/messages/metadata.rb +80 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotator.rb +57 -0
- data/lib/active_support/multibyte/chars.rb +24 -78
- data/lib/active_support/multibyte/unicode.rb +21 -352
- data/lib/active_support/multibyte.rb +4 -2
- data/lib/active_support/notifications/fanout.rb +121 -19
- data/lib/active_support/notifications/instrumenter.rb +78 -14
- data/lib/active_support/notifications.rb +80 -12
- data/lib/active_support/number_helper/number_converter.rb +17 -16
- data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +13 -12
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -13
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -4
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +18 -55
- data/lib/active_support/number_helper/rounding_helper.rb +50 -0
- data/lib/active_support/number_helper.rb +45 -16
- data/lib/active_support/option_merger.rb +25 -4
- data/lib/active_support/ordered_hash.rb +6 -4
- data/lib/active_support/ordered_options.rb +23 -9
- data/lib/active_support/parameter_filter.rb +133 -0
- data/lib/active_support/per_thread_registry.rb +7 -5
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +8 -9
- data/lib/active_support/railtie.rb +62 -11
- data/lib/active_support/reloader.rb +12 -11
- data/lib/active_support/rescuable.rb +20 -11
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +26 -15
- data/lib/active_support/string_inquirer.rb +12 -3
- data/lib/active_support/subscriber.rb +77 -23
- data/lib/active_support/tagged_logging.rb +52 -17
- data/lib/active_support/test_case.rb +106 -29
- data/lib/active_support/testing/assertions.rb +144 -8
- data/lib/active_support/testing/autorun.rb +5 -10
- data/lib/active_support/testing/constant_lookup.rb +2 -1
- data/lib/active_support/testing/declarative.rb +3 -1
- data/lib/active_support/testing/deprecation.rb +4 -2
- data/lib/active_support/testing/file_fixtures.rb +4 -0
- data/lib/active_support/testing/isolation.rb +19 -24
- data/lib/active_support/testing/method_call_assertions.rb +31 -2
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/parallelization.rb +51 -0
- data/lib/active_support/testing/setup_and_teardown.rb +13 -8
- data/lib/active_support/testing/stream.rb +30 -29
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +125 -24
- data/lib/active_support/time.rb +14 -12
- data/lib/active_support/time_with_zone.rb +142 -55
- data/lib/active_support/values/time_zone.rb +160 -53
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini/jdom.rb +115 -114
- data/lib/active_support/xml_mini/libxml.rb +15 -14
- data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
- data/lib/active_support/xml_mini/nokogiri.rb +13 -13
- data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
- data/lib/active_support/xml_mini/rexml.rb +18 -9
- data/lib/active_support/xml_mini.rb +44 -42
- data/lib/active_support.rb +19 -10
- metadata +79 -37
- data/lib/active_support/concurrency/latch.rb +0 -19
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
- data/lib/active_support/core_ext/hash/compact.rb +0 -20
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -29
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -3
- data/lib/active_support/core_ext/module/method_transplanting.rb +0 -3
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -70
- data/lib/active_support/core_ext/module/reachable.rb +0 -8
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
- data/lib/active_support/core_ext/range/include_range.rb +0 -23
- data/lib/active_support/core_ext/struct.rb +0 -3
- data/lib/active_support/core_ext/time/marshal.rb +0 -3
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,4 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Enumerable
|
4
|
+
INDEX_WITH_DEFAULT = Object.new
|
5
|
+
private_constant :INDEX_WITH_DEFAULT
|
6
|
+
|
7
|
+
# Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
|
8
|
+
# when we omit an identity.
|
9
|
+
|
10
|
+
# :stopdoc:
|
11
|
+
|
12
|
+
# We can't use Refinements here because Refinements with Module which will be prepended
|
13
|
+
# doesn't work well https://bugs.ruby-lang.org/issues/13446
|
14
|
+
alias :_original_sum_with_required_identity :sum
|
15
|
+
private :_original_sum_with_required_identity
|
16
|
+
|
17
|
+
# :startdoc:
|
18
|
+
|
2
19
|
# Calculates a sum from the elements.
|
3
20
|
#
|
4
21
|
# payments.sum { |p| p.price * p.tax_rate }
|
@@ -12,34 +29,66 @@ module Enumerable
|
|
12
29
|
#
|
13
30
|
# [5, 15, 10].sum # => 30
|
14
31
|
# ['foo', 'bar'].sum # => "foobar"
|
15
|
-
# [[1, 2], [3, 1, 5]].sum => [1, 2, 3, 1, 5]
|
32
|
+
# [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
|
16
33
|
#
|
17
34
|
# The default sum of an empty list is zero. You can override this default:
|
18
35
|
#
|
19
36
|
# [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
|
20
37
|
def sum(identity = nil, &block)
|
21
|
-
if
|
38
|
+
if identity
|
39
|
+
_original_sum_with_required_identity(identity, &block)
|
40
|
+
elsif block_given?
|
22
41
|
map(&block).sum(identity)
|
23
42
|
else
|
24
|
-
|
25
|
-
sum || identity || 0
|
43
|
+
inject(:+) || 0
|
26
44
|
end
|
27
45
|
end
|
28
46
|
|
29
|
-
# Convert an enumerable to a hash
|
47
|
+
# Convert an enumerable to a hash, using the block result as the key and the
|
48
|
+
# element as the value.
|
30
49
|
#
|
31
50
|
# people.index_by(&:login)
|
32
|
-
#
|
51
|
+
# # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
|
52
|
+
#
|
33
53
|
# people.index_by { |person| "#{person.first_name} #{person.last_name}" }
|
34
|
-
#
|
54
|
+
# # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
|
35
55
|
def index_by
|
36
56
|
if block_given?
|
37
|
-
|
57
|
+
result = {}
|
58
|
+
each { |elem| result[yield(elem)] = elem }
|
59
|
+
result
|
38
60
|
else
|
39
61
|
to_enum(:index_by) { size if respond_to?(:size) }
|
40
62
|
end
|
41
63
|
end
|
42
64
|
|
65
|
+
# Convert an enumerable to a hash, using the element as the key and the block
|
66
|
+
# result as the value.
|
67
|
+
#
|
68
|
+
# post = Post.new(title: "hey there", body: "what's up?")
|
69
|
+
#
|
70
|
+
# %i( title body ).index_with { |attr_name| post.public_send(attr_name) }
|
71
|
+
# # => { title: "hey there", body: "what's up?" }
|
72
|
+
#
|
73
|
+
# If an argument is passed instead of a block, it will be used as the value
|
74
|
+
# for all elements:
|
75
|
+
#
|
76
|
+
# %i( created_at updated_at ).index_with(Time.now)
|
77
|
+
# # => { created_at: 2020-03-09 22:31:47, updated_at: 2020-03-09 22:31:47 }
|
78
|
+
def index_with(default = INDEX_WITH_DEFAULT)
|
79
|
+
if block_given?
|
80
|
+
result = {}
|
81
|
+
each { |elem| result[elem] = yield(elem) }
|
82
|
+
result
|
83
|
+
elsif default != INDEX_WITH_DEFAULT
|
84
|
+
result = {}
|
85
|
+
each { |elem| result[elem] = default }
|
86
|
+
result
|
87
|
+
else
|
88
|
+
to_enum(:index_with) { size if respond_to?(:size) }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
43
92
|
# Returns +true+ if the enumerable has more than 1 element. Functionally
|
44
93
|
# equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,
|
45
94
|
# much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+
|
@@ -56,37 +105,110 @@ module Enumerable
|
|
56
105
|
end
|
57
106
|
end
|
58
107
|
|
108
|
+
# Returns a new array that includes the passed elements.
|
109
|
+
#
|
110
|
+
# [ 1, 2, 3 ].including(4, 5)
|
111
|
+
# # => [ 1, 2, 3, 4, 5 ]
|
112
|
+
#
|
113
|
+
# ["David", "Rafael"].including %w[ Aaron Todd ]
|
114
|
+
# # => ["David", "Rafael", "Aaron", "Todd"]
|
115
|
+
def including(*elements)
|
116
|
+
to_a.including(*elements)
|
117
|
+
end
|
118
|
+
|
59
119
|
# The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
|
60
120
|
# collection does not include the object.
|
61
121
|
def exclude?(object)
|
62
122
|
!include?(object)
|
63
123
|
end
|
64
124
|
|
65
|
-
# Returns a copy of the enumerable
|
125
|
+
# Returns a copy of the enumerable excluding the specified elements.
|
66
126
|
#
|
67
|
-
# ["David", "Rafael", "Aaron", "Todd"].
|
68
|
-
#
|
127
|
+
# ["David", "Rafael", "Aaron", "Todd"].excluding "Aaron", "Todd"
|
128
|
+
# # => ["David", "Rafael"]
|
69
129
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
|
130
|
+
# ["David", "Rafael", "Aaron", "Todd"].excluding %w[ Aaron Todd ]
|
131
|
+
# # => ["David", "Rafael"]
|
132
|
+
#
|
133
|
+
# {foo: 1, bar: 2, baz: 3}.excluding :bar
|
134
|
+
# # => {foo: 1, baz: 3}
|
135
|
+
def excluding(*elements)
|
136
|
+
elements.flatten!(1)
|
73
137
|
reject { |element| elements.include?(element) }
|
74
138
|
end
|
75
139
|
|
76
|
-
#
|
140
|
+
# Alias for #excluding.
|
141
|
+
def without(*elements)
|
142
|
+
excluding(*elements)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Extract the given key from each element in the enumerable.
|
77
146
|
#
|
78
147
|
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
|
79
|
-
#
|
148
|
+
# # => ["David", "Rafael", "Aaron"]
|
80
149
|
#
|
81
150
|
# [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
|
82
|
-
#
|
151
|
+
# # => [[1, "David"], [2, "Rafael"]]
|
83
152
|
def pluck(*keys)
|
84
153
|
if keys.many?
|
85
154
|
map { |element| keys.map { |key| element[key] } }
|
86
155
|
else
|
87
|
-
|
156
|
+
key = keys.first
|
157
|
+
map { |element| element[key] }
|
88
158
|
end
|
89
159
|
end
|
160
|
+
|
161
|
+
# Extract the given key from the first element in the enumerable.
|
162
|
+
#
|
163
|
+
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pick(:name)
|
164
|
+
# # => "David"
|
165
|
+
#
|
166
|
+
# [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pick(:id, :name)
|
167
|
+
# # => [1, "David"]
|
168
|
+
def pick(*keys)
|
169
|
+
return if none?
|
170
|
+
|
171
|
+
if keys.many?
|
172
|
+
keys.map { |key| first[key] }
|
173
|
+
else
|
174
|
+
first[keys.first]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Returns a new +Array+ without the blank items.
|
179
|
+
# Uses Object#blank? for determining if an item is blank.
|
180
|
+
#
|
181
|
+
# [1, "", nil, 2, " ", [], {}, false, true].compact_blank
|
182
|
+
# # => [1, 2, true]
|
183
|
+
#
|
184
|
+
# Set.new([nil, "", 1, 2])
|
185
|
+
# # => [2, 1] (or [1, 2])
|
186
|
+
#
|
187
|
+
# When called on a +Hash+, returns a new +Hash+ without the blank values.
|
188
|
+
#
|
189
|
+
# { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
|
190
|
+
# #=> { b: 1, f: true }
|
191
|
+
def compact_blank
|
192
|
+
reject(&:blank?)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
class Hash
|
197
|
+
# Hash#reject has its own definition, so this needs one too.
|
198
|
+
def compact_blank #:nodoc:
|
199
|
+
reject { |_k, v| v.blank? }
|
200
|
+
end
|
201
|
+
|
202
|
+
# Removes all blank values from the +Hash+ in place and returns self.
|
203
|
+
# Uses Object#blank? for determining if a value is blank.
|
204
|
+
#
|
205
|
+
# h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
|
206
|
+
# h.compact_blank!
|
207
|
+
# # => { b: 1, f: true }
|
208
|
+
def compact_blank!
|
209
|
+
# use delete_if rather than reject! because it always returns self even if nothing changed
|
210
|
+
delete_if { |_k, v| v.blank? }
|
211
|
+
end
|
90
212
|
end
|
91
213
|
|
92
214
|
class Range #:nodoc:
|
@@ -107,18 +229,32 @@ class Range #:nodoc:
|
|
107
229
|
end
|
108
230
|
end
|
109
231
|
|
110
|
-
#
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
232
|
+
# Using Refinements here in order not to expose our internal method
|
233
|
+
using Module.new {
|
234
|
+
refine Array do
|
235
|
+
alias :orig_sum :sum
|
236
|
+
end
|
237
|
+
}
|
238
|
+
|
239
|
+
class Array #:nodoc:
|
240
|
+
# Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
|
241
|
+
def sum(init = nil, &block)
|
242
|
+
if init.is_a?(Numeric) || first.is_a?(Numeric)
|
243
|
+
init ||= 0
|
244
|
+
orig_sum(init, &block)
|
245
|
+
else
|
121
246
|
super
|
122
247
|
end
|
123
248
|
end
|
249
|
+
|
250
|
+
# Removes all blank elements from the +Array+ in place and returns self.
|
251
|
+
# Uses Object#blank? for determining if an item is blank.
|
252
|
+
#
|
253
|
+
# a = [1, "", nil, 2, " ", [], {}, false, true]
|
254
|
+
# a.compact_blank!
|
255
|
+
# # => [1, 2, true]
|
256
|
+
def compact_blank!
|
257
|
+
# use delete_if rather than reject! because it always returns self even if nothing changed
|
258
|
+
delete_if(&:blank?)
|
259
|
+
end
|
124
260
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
2
4
|
|
3
5
|
class File
|
4
6
|
# Write to a file atomically. Useful for situations where you don't
|
@@ -17,7 +19,7 @@ class File
|
|
17
19
|
# file.write('hello')
|
18
20
|
# end
|
19
21
|
def self.atomic_write(file_name, temp_dir = dirname(file_name))
|
20
|
-
require
|
22
|
+
require "tempfile" unless defined?(Tempfile)
|
21
23
|
|
22
24
|
Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file|
|
23
25
|
temp_file.binmode
|
@@ -27,7 +29,7 @@ class File
|
|
27
29
|
old_stat = if exist?(file_name)
|
28
30
|
# Get original file permissions
|
29
31
|
stat(file_name)
|
30
|
-
|
32
|
+
else
|
31
33
|
# If not possible, probe which are the default permissions in the
|
32
34
|
# destination directory.
|
33
35
|
probe_stat_in(dirname(file_name))
|
@@ -53,11 +55,11 @@ class File
|
|
53
55
|
# Private utility method.
|
54
56
|
def self.probe_stat_in(dir) #:nodoc:
|
55
57
|
basename = [
|
56
|
-
|
58
|
+
".permissions_check",
|
57
59
|
Thread.current.object_id,
|
58
60
|
Process.pid,
|
59
61
|
rand(1000000)
|
60
|
-
].join(
|
62
|
+
].join(".")
|
61
63
|
|
62
64
|
file_name = join(dir, basename)
|
63
65
|
FileUtils.touch(file_name)
|
@@ -1,11 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/xml_mini"
|
4
|
+
require "active_support/core_ext/object/blank"
|
5
|
+
require "active_support/core_ext/object/to_param"
|
6
|
+
require "active_support/core_ext/object/to_query"
|
7
|
+
require "active_support/core_ext/object/try"
|
8
|
+
require "active_support/core_ext/array/wrap"
|
9
|
+
require "active_support/core_ext/hash/reverse_merge"
|
10
|
+
require "active_support/core_ext/string/inflections"
|
9
11
|
|
10
12
|
class Hash
|
11
13
|
# Returns a string containing an XML representation of its receiver:
|
@@ -71,11 +73,11 @@ class Hash
|
|
71
73
|
# configure your own builder with the <tt>:builder</tt> option. The method also accepts
|
72
74
|
# options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
|
73
75
|
def to_xml(options = {})
|
74
|
-
require
|
76
|
+
require "active_support/builder" unless defined?(Builder::XmlMarkup)
|
75
77
|
|
76
78
|
options = options.dup
|
77
79
|
options[:indent] ||= 2
|
78
|
-
options[:root] ||=
|
80
|
+
options[:root] ||= "hash"
|
79
81
|
options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
|
80
82
|
|
81
83
|
builder = options[:builder]
|
@@ -159,36 +161,36 @@ module ActiveSupport
|
|
159
161
|
private
|
160
162
|
def normalize_keys(params)
|
161
163
|
case params
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
164
|
+
when Hash
|
165
|
+
Hash[params.map { |k, v| [k.to_s.tr("-", "_"), normalize_keys(v)] } ]
|
166
|
+
when Array
|
167
|
+
params.map { |v| normalize_keys(v) }
|
168
|
+
else
|
169
|
+
params
|
168
170
|
end
|
169
171
|
end
|
170
172
|
|
171
173
|
def deep_to_h(value)
|
172
174
|
case value
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
175
|
+
when Hash
|
176
|
+
process_hash(value)
|
177
|
+
when Array
|
178
|
+
process_array(value)
|
179
|
+
when String
|
180
|
+
value
|
181
|
+
else
|
182
|
+
raise "can't typecast #{value.class.name} - #{value.inspect}"
|
181
183
|
end
|
182
184
|
end
|
183
185
|
|
184
186
|
def process_hash(value)
|
185
|
-
if value.include?(
|
186
|
-
raise DisallowedType, value[
|
187
|
+
if value.include?("type") && !value["type"].is_a?(Hash) && @disallowed_types.include?(value["type"])
|
188
|
+
raise DisallowedType, value["type"]
|
187
189
|
end
|
188
190
|
|
189
191
|
if become_array?(value)
|
190
|
-
_, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) })
|
191
|
-
if entries.nil? || value[
|
192
|
+
_, entries = Array.wrap(value.detect { |k, v| not v.is_a?(String) })
|
193
|
+
if entries.nil? || value["__content__"].try(:empty?)
|
192
194
|
[]
|
193
195
|
else
|
194
196
|
case entries
|
@@ -204,28 +206,28 @@ module ActiveSupport
|
|
204
206
|
process_content(value)
|
205
207
|
|
206
208
|
elsif become_empty_string?(value)
|
207
|
-
|
209
|
+
""
|
208
210
|
elsif become_hash?(value)
|
209
|
-
xml_value =
|
211
|
+
xml_value = value.transform_values { |v| deep_to_h(v) }
|
210
212
|
|
211
213
|
# Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
|
212
214
|
# how multipart uploaded files from HTML appear
|
213
|
-
xml_value[
|
215
|
+
xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
|
214
216
|
end
|
215
217
|
end
|
216
218
|
|
217
219
|
def become_content?(value)
|
218
|
-
value[
|
220
|
+
value["type"] == "file" || (value["__content__"] && (value.keys.size == 1 || value["__content__"].present?))
|
219
221
|
end
|
220
222
|
|
221
223
|
def become_array?(value)
|
222
|
-
value[
|
224
|
+
value["type"] == "array"
|
223
225
|
end
|
224
226
|
|
225
227
|
def become_empty_string?(value)
|
226
228
|
# { "string" => true }
|
227
229
|
# No tests fail when the second term is removed.
|
228
|
-
value[
|
230
|
+
value["type"] == "string" && value["nil"] != "true"
|
229
231
|
end
|
230
232
|
|
231
233
|
def become_hash?(value)
|
@@ -234,19 +236,19 @@ module ActiveSupport
|
|
234
236
|
|
235
237
|
def nothing?(value)
|
236
238
|
# blank or nil parsed values are represented by nil
|
237
|
-
value.blank? || value[
|
239
|
+
value.blank? || value["nil"] == "true"
|
238
240
|
end
|
239
241
|
|
240
242
|
def garbage?(value)
|
241
243
|
# If the type is the only element which makes it then
|
242
244
|
# this still makes the value nil, except if type is
|
243
245
|
# an XML node(where type['value'] is a Hash)
|
244
|
-
value[
|
246
|
+
value["type"] && !value["type"].is_a?(::Hash) && value.size == 1
|
245
247
|
end
|
246
248
|
|
247
249
|
def process_content(value)
|
248
|
-
content = value[
|
249
|
-
if parser = ActiveSupport::XmlMini::PARSING[value[
|
250
|
+
content = value["__content__"]
|
251
|
+
if parser = ActiveSupport::XmlMini::PARSING[value["type"]]
|
250
252
|
parser.arity == 1 ? parser.call(content) : parser.call(content, value)
|
251
253
|
else
|
252
254
|
content
|
@@ -257,6 +259,5 @@ module ActiveSupport
|
|
257
259
|
value.map! { |i| deep_to_h(i) }
|
258
260
|
value.length > 1 ? value : value.first
|
259
261
|
end
|
260
|
-
|
261
262
|
end
|
262
263
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Hash
|
2
4
|
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
3
5
|
#
|
@@ -19,20 +21,14 @@ class Hash
|
|
19
21
|
|
20
22
|
# Same as +deep_merge+, but modifies +self+.
|
21
23
|
def deep_merge!(other_hash, &block)
|
22
|
-
other_hash
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
merge!(other_hash) do |key, this_val, other_val|
|
25
|
+
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
|
26
|
+
this_val.deep_merge(other_val, &block)
|
27
|
+
elsif block_given?
|
28
|
+
block.call(key, this_val, other_val)
|
27
29
|
else
|
28
|
-
|
29
|
-
block.call(current_key, this_value, other_value)
|
30
|
-
else
|
31
|
-
other_value
|
32
|
-
end
|
30
|
+
other_val
|
33
31
|
end
|
34
32
|
end
|
35
|
-
|
36
|
-
self
|
37
33
|
end
|
38
34
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
# Returns a new hash with all values converted by the block operation.
|
5
|
+
# This includes the values from the root hash and from all
|
6
|
+
# nested hashes and arrays.
|
7
|
+
#
|
8
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
9
|
+
#
|
10
|
+
# hash.deep_transform_values{ |value| value.to_s.upcase }
|
11
|
+
# # => {person: {name: "ROB", age: "28"}}
|
12
|
+
def deep_transform_values(&block)
|
13
|
+
_deep_transform_values_in_object(self, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Destructively converts all values by using the block operation.
|
17
|
+
# This includes the values from the root hash and from all
|
18
|
+
# nested hashes and arrays.
|
19
|
+
def deep_transform_values!(&block)
|
20
|
+
_deep_transform_values_in_object!(self, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
# Support methods for deep transforming nested hashes and arrays.
|
25
|
+
def _deep_transform_values_in_object(object, &block)
|
26
|
+
case object
|
27
|
+
when Hash
|
28
|
+
object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
|
29
|
+
when Array
|
30
|
+
object.map { |e| _deep_transform_values_in_object(e, &block) }
|
31
|
+
else
|
32
|
+
yield(object)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def _deep_transform_values_in_object!(object, &block)
|
37
|
+
case object
|
38
|
+
when Hash
|
39
|
+
object.transform_values! { |value| _deep_transform_values_in_object!(value, &block) }
|
40
|
+
when Array
|
41
|
+
object.map! { |e| _deep_transform_values_in_object!(e, &block) }
|
42
|
+
else
|
43
|
+
yield(object)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Hash
|
2
4
|
# Returns a hash that includes everything except given keys.
|
3
5
|
# hash = { a: true, b: false, c: nil }
|
@@ -8,8 +10,8 @@ class Hash
|
|
8
10
|
# This is useful for limiting a set of parameters to everything but a few known toggles:
|
9
11
|
# @person.update(params[:person].except(:admin))
|
10
12
|
def except(*keys)
|
11
|
-
|
12
|
-
end
|
13
|
+
slice(*self.keys - keys)
|
14
|
+
end unless method_defined?(:except)
|
13
15
|
|
14
16
|
# Removes the given keys from hash and returns it.
|
15
17
|
# hash = { a: true, b: false, c: nil }
|
@@ -1,7 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "active_support/hash_with_indifferent_access"
|
4
4
|
|
5
|
+
class Hash
|
5
6
|
# Returns an <tt>ActiveSupport::HashWithIndifferentAccess</tt> out of its receiver:
|
6
7
|
#
|
7
8
|
# { a: 1 }.with_indifferent_access['a'] # => 1
|
@@ -1,33 +1,6 @@
|
|
1
|
-
|
2
|
-
# Returns a new hash with all keys converted using the +block+ operation.
|
3
|
-
#
|
4
|
-
# hash = { name: 'Rob', age: '28' }
|
5
|
-
#
|
6
|
-
# hash.transform_keys { |key| key.to_s.upcase } # => {"NAME"=>"Rob", "AGE"=>"28"}
|
7
|
-
#
|
8
|
-
# If you do not provide a +block+, it will return an Enumerator
|
9
|
-
# for chaining with other methods:
|
10
|
-
#
|
11
|
-
# hash.transform_keys.with_index { |k, i| [k, i].join } # => {"name0"=>"Rob", "age1"=>"28"}
|
12
|
-
def transform_keys
|
13
|
-
return enum_for(:transform_keys) { size } unless block_given?
|
14
|
-
result = {}
|
15
|
-
each_key do |key|
|
16
|
-
result[yield(key)] = self[key]
|
17
|
-
end
|
18
|
-
result
|
19
|
-
end
|
20
|
-
|
21
|
-
# Destructively converts all keys using the +block+ operations.
|
22
|
-
# Same as +transform_keys+ but modifies +self+.
|
23
|
-
def transform_keys!
|
24
|
-
return enum_for(:transform_keys!) { size } unless block_given?
|
25
|
-
keys.each do |key|
|
26
|
-
self[yield(key)] = delete(key)
|
27
|
-
end
|
28
|
-
self
|
29
|
-
end
|
1
|
+
# frozen_string_literal: true
|
30
2
|
|
3
|
+
class Hash
|
31
4
|
# Returns a new hash with all keys converted to strings.
|
32
5
|
#
|
33
6
|
# hash = { name: 'Rob', age: '28' }
|
@@ -52,14 +25,14 @@ class Hash
|
|
52
25
|
# hash.symbolize_keys
|
53
26
|
# # => {:name=>"Rob", :age=>"28"}
|
54
27
|
def symbolize_keys
|
55
|
-
transform_keys{ |key| key.to_sym rescue key }
|
28
|
+
transform_keys { |key| key.to_sym rescue key }
|
56
29
|
end
|
57
30
|
alias_method :to_options, :symbolize_keys
|
58
31
|
|
59
32
|
# Destructively converts all keys to symbols, as long as they respond
|
60
33
|
# to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
|
61
34
|
def symbolize_keys!
|
62
|
-
transform_keys!{ |key| key.to_sym rescue key }
|
35
|
+
transform_keys! { |key| key.to_sym rescue key }
|
63
36
|
end
|
64
37
|
alias_method :to_options!, :symbolize_keys!
|
65
38
|
|
@@ -128,18 +101,18 @@ class Hash
|
|
128
101
|
# hash.deep_symbolize_keys
|
129
102
|
# # => {:person=>{:name=>"Rob", :age=>"28"}}
|
130
103
|
def deep_symbolize_keys
|
131
|
-
deep_transform_keys{ |key| key.to_sym rescue key }
|
104
|
+
deep_transform_keys { |key| key.to_sym rescue key }
|
132
105
|
end
|
133
106
|
|
134
107
|
# Destructively converts all keys to symbols, as long as they respond
|
135
108
|
# to +to_sym+. This includes the keys from the root hash and from all
|
136
109
|
# nested hashes and arrays.
|
137
110
|
def deep_symbolize_keys!
|
138
|
-
deep_transform_keys!{ |key| key.to_sym rescue key }
|
111
|
+
deep_transform_keys! { |key| key.to_sym rescue key }
|
139
112
|
end
|
140
113
|
|
141
114
|
private
|
142
|
-
#
|
115
|
+
# Support methods for deep transforming nested hashes and arrays.
|
143
116
|
def _deep_transform_keys_in_object(object, &block)
|
144
117
|
case object
|
145
118
|
when Hash
|
@@ -147,7 +120,7 @@ class Hash
|
|
147
120
|
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
|
148
121
|
end
|
149
122
|
when Array
|
150
|
-
object.map {|e| _deep_transform_keys_in_object(e, &block) }
|
123
|
+
object.map { |e| _deep_transform_keys_in_object(e, &block) }
|
151
124
|
else
|
152
125
|
object
|
153
126
|
end
|
@@ -162,7 +135,7 @@ class Hash
|
|
162
135
|
end
|
163
136
|
object
|
164
137
|
when Array
|
165
|
-
object.map! {|e| _deep_transform_keys_in_object!(e, &block)}
|
138
|
+
object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
|
166
139
|
else
|
167
140
|
object
|
168
141
|
end
|