activesupport 4.2.11.1 → 5.2.8.1
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 +441 -399
- data/MIT-LICENSE +2 -2
- data/README.rdoc +4 -5
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +7 -5
- data/lib/active_support/benchmarkable.rb +6 -4
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +41 -35
- data/lib/active_support/cache/mem_cache_store.rb +91 -91
- data/lib/active_support/cache/memory_store.rb +27 -30
- data/lib/active_support/cache/null_store.rb +7 -8
- data/lib/active_support/cache/redis_cache_store.rb +466 -0
- data/lib/active_support/cache/strategy/local_cache.rb +67 -34
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
- data/lib/active_support/cache.rb +287 -196
- data/lib/active_support/callbacks.rb +640 -590
- data/lib/active_support/concern.rb +11 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
- data/lib/active_support/concurrency/share_lock.rb +227 -0
- data/lib/active_support/configurable.rb +8 -5
- data/lib/active_support/core_ext/array/access.rb +29 -1
- data/lib/active_support/core_ext/array/conversions.rb +22 -18
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +11 -18
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -3
- data/lib/active_support/core_ext/array/wrap.rb +7 -4
- data/lib/active_support/core_ext/array.rb +9 -6
- data/lib/active_support/core_ext/benchmark.rb +3 -1
- data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/class/attribute.rb +41 -22
- data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
- data/lib/active_support/core_ext/class/subclasses.rb +20 -6
- data/lib/active_support/core_ext/class.rb +4 -3
- data/lib/active_support/core_ext/date/acts_like.rb +3 -1
- data/lib/active_support/core_ext/date/blank.rb +14 -0
- data/lib/active_support/core_ext/date/calculations.rb +11 -9
- data/lib/active_support/core_ext/date/conversions.rb +25 -23
- data/lib/active_support/core_ext/date/zones.rb +4 -2
- data/lib/active_support/core_ext/date.rb +6 -4
- data/lib/active_support/core_ext/date_and_time/calculations.rb +170 -58
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
- data/lib/active_support/core_ext/date_and_time/zones.rb +12 -12
- data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
- data/lib/active_support/core_ext/date_time/blank.rb +14 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +36 -18
- data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
- data/lib/active_support/core_ext/date_time/conversions.rb +16 -12
- 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 +101 -33
- data/lib/active_support/core_ext/file/atomic.rb +38 -31
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/hash/compact.rb +14 -9
- data/lib/active_support/core_ext/hash/conversions.rb +62 -41
- data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
- data/lib/active_support/core_ext/hash/except.rb +11 -8
- data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
- data/lib/active_support/core_ext/hash/keys.rb +33 -27
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -8
- data/lib/active_support/core_ext/hash/transform_values.rb +14 -5
- data/lib/active_support/core_ext/hash.rb +11 -9
- data/lib/active_support/core_ext/integer/inflections.rb +3 -1
- data/lib/active_support/core_ext/integer/multiple.rb +2 -0
- 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/agnostics.rb +2 -0
- data/lib/active_support/core_ext/kernel/concern.rb +5 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +6 -5
- data/lib/active_support/core_ext/load_error.rb +3 -22
- data/lib/active_support/core_ext/marshal.rb +8 -8
- data/lib/active_support/core_ext/module/aliasing.rb +6 -44
- data/lib/active_support/core_ext/module/anonymous.rb +12 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
- data/lib/active_support/core_ext/module/attribute_accessors.rb +43 -40
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +150 -0
- data/lib/active_support/core_ext/module/concerning.rb +11 -12
- data/lib/active_support/core_ext/module/delegation.rb +99 -29
- data/lib/active_support/core_ext/module/deprecation.rb +4 -2
- data/lib/active_support/core_ext/module/introspection.rb +9 -9
- data/lib/active_support/core_ext/module/reachable.rb +5 -2
- data/lib/active_support/core_ext/module/redefine_method.rb +49 -0
- data/lib/active_support/core_ext/module/remove_method.rb +8 -3
- data/lib/active_support/core_ext/module.rb +14 -11
- data/lib/active_support/core_ext/name_error.rb +22 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +78 -81
- data/lib/active_support/core_ext/numeric/inquiry.rb +28 -0
- data/lib/active_support/core_ext/numeric/time.rb +35 -23
- data/lib/active_support/core_ext/numeric.rb +6 -3
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +27 -2
- data/lib/active_support/core_ext/object/conversions.rb +6 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
- data/lib/active_support/core_ext/object/duplicable.rb +41 -14
- data/lib/active_support/core_ext/object/inclusion.rb +5 -3
- data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
- data/lib/active_support/core_ext/object/json.rb +49 -19
- 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 +69 -21
- data/lib/active_support/core_ext/object/with_options.rb +16 -3
- data/lib/active_support/core_ext/object.rb +14 -13
- data/lib/active_support/core_ext/range/compare_range.rb +61 -0
- data/lib/active_support/core_ext/range/conversions.rb +27 -7
- data/lib/active_support/core_ext/range/each.rb +19 -17
- data/lib/active_support/core_ext/range/include_range.rb +2 -22
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -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 +6 -0
- data/lib/active_support/core_ext/securerandom.rb +25 -0
- data/lib/active_support/core_ext/string/access.rb +8 -6
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +7 -4
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +6 -5
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +61 -24
- data/lib/active_support/core_ext/string/inquiry.rb +3 -1
- data/lib/active_support/core_ext/string/multibyte.rb +15 -7
- data/lib/active_support/core_ext/string/output_safety.rb +62 -38
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
- data/lib/active_support/core_ext/string/strip.rb +4 -5
- 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/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +85 -51
- data/lib/active_support/core_ext/time/compatibility.rb +4 -2
- data/lib/active_support/core_ext/time/conversions.rb +20 -13
- data/lib/active_support/core_ext/time/zones.rb +41 -7
- data/lib/active_support/core_ext/time.rb +7 -6
- data/lib/active_support/core_ext/uri.rb +6 -8
- data/lib/active_support/core_ext.rb +3 -1
- data/lib/active_support/current_attributes.rb +195 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +57 -0
- data/lib/active_support/dependencies.rb +152 -161
- data/lib/active_support/deprecation/behaviors.rb +44 -11
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/instance_delegator.rb +17 -2
- data/lib/active_support/deprecation/method_wrappers.rb +66 -20
- data/lib/active_support/deprecation/proxy_wrappers.rb +56 -28
- data/lib/active_support/deprecation/reporting.rb +32 -12
- data/lib/active_support/deprecation.rb +12 -9
- data/lib/active_support/descendants_tracker.rb +2 -0
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration/iso8601_parser.rb +125 -0
- data/lib/active_support/duration/iso8601_serializer.rb +55 -0
- data/lib/active_support/duration.rb +314 -38
- data/lib/active_support/encrypted_configuration.rb +49 -0
- data/lib/active_support/encrypted_file.rb +99 -0
- data/lib/active_support/evented_file_update_checker.rb +205 -0
- data/lib/active_support/execution_wrapper.rb +131 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +63 -37
- data/lib/active_support/gem_version.rb +5 -3
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +123 -28
- data/lib/active_support/i18n.rb +8 -6
- data/lib/active_support/i18n_railtie.rb +37 -13
- data/lib/active_support/inflections.rb +13 -11
- data/lib/active_support/inflector/inflections.rb +61 -12
- data/lib/active_support/inflector/methods.rb +163 -136
- data/lib/active_support/inflector/transliterate.rb +48 -27
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/json/decoding.rb +16 -13
- data/lib/active_support/json/encoding.rb +11 -58
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +25 -25
- data/lib/active_support/lazy_load_hooks.rb +50 -20
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber/test_helper.rb +14 -12
- data/lib/active_support/log_subscriber.rb +13 -10
- data/lib/active_support/logger.rb +8 -7
- data/lib/active_support/logger_silence.rb +6 -4
- data/lib/active_support/logger_thread_safe_level.rb +7 -5
- data/lib/active_support/message_encryptor.rb +168 -53
- data/lib/active_support/message_verifier.rb +150 -17
- 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/chars.rb +36 -23
- data/lib/active_support/multibyte/unicode.rb +100 -96
- data/lib/active_support/multibyte.rb +4 -2
- data/lib/active_support/notifications/fanout.rb +11 -9
- data/lib/active_support/notifications/instrumenter.rb +27 -7
- data/lib/active_support/notifications.rb +11 -7
- data/lib/active_support/number_helper/number_converter.rb +13 -11
- data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +9 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +11 -9
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +9 -8
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +13 -4
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +23 -56
- data/lib/active_support/number_helper/rounding_helper.rb +66 -0
- data/lib/active_support/number_helper.rb +94 -68
- data/lib/active_support/option_merger.rb +3 -1
- data/lib/active_support/ordered_hash.rb +6 -4
- data/lib/active_support/ordered_options.rb +23 -5
- data/lib/active_support/per_thread_registry.rb +9 -4
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +16 -8
- data/lib/active_support/railtie.rb +43 -9
- data/lib/active_support/reloader.rb +131 -0
- data/lib/active_support/rescuable.rb +108 -53
- data/lib/active_support/security_utils.rb +15 -11
- data/lib/active_support/string_inquirer.rb +11 -3
- data/lib/active_support/subscriber.rb +21 -16
- data/lib/active_support/tagged_logging.rb +14 -11
- data/lib/active_support/test_case.rb +19 -47
- data/lib/active_support/testing/assertions.rb +137 -20
- data/lib/active_support/testing/autorun.rb +4 -2
- 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 +14 -10
- data/lib/active_support/testing/file_fixtures.rb +36 -0
- data/lib/active_support/testing/isolation.rb +34 -25
- data/lib/active_support/testing/method_call_assertions.rb +43 -0
- data/lib/active_support/testing/setup_and_teardown.rb +13 -8
- data/lib/active_support/testing/stream.rb +44 -0
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +81 -15
- data/lib/active_support/time.rb +14 -12
- data/lib/active_support/time_with_zone.rb +169 -39
- data/lib/active_support/values/time_zone.rb +196 -61
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini/jdom.rb +116 -114
- data/lib/active_support/xml_mini/libxml.rb +16 -13
- data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
- data/lib/active_support/xml_mini/nokogiri.rb +14 -12
- data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
- data/lib/active_support/xml_mini/rexml.rb +11 -9
- data/lib/active_support/xml_mini.rb +37 -37
- data/lib/active_support.rb +12 -11
- metadata +57 -27
- data/lib/active_support/concurrency/latch.rb +0 -27
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
- data/lib/active_support/core_ext/date_time/zones.rb +0 -6
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
- data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
- data/lib/active_support/core_ext/object/itself.rb +0 -15
- data/lib/active_support/core_ext/struct.rb +0 -6
- data/lib/active_support/core_ext/thread.rb +0 -86
- data/lib/active_support/core_ext/time/marshal.rb +0 -30
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/date_time/acts_like"
|
4
|
+
require "active_support/core_ext/date_time/blank"
|
5
|
+
require "active_support/core_ext/date_time/calculations"
|
6
|
+
require "active_support/core_ext/date_time/compatibility"
|
7
|
+
require "active_support/core_ext/date_time/conversions"
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "securerandom"
|
2
4
|
|
3
5
|
module Digest
|
4
6
|
module UUID
|
@@ -12,7 +14,7 @@ module Digest
|
|
12
14
|
# Using Digest::MD5 generates version 3 UUIDs; Digest::SHA1 generates version 5 UUIDs.
|
13
15
|
# uuid_from_hash always generates the same UUID for a given name and namespace combination.
|
14
16
|
#
|
15
|
-
# See RFC 4122 for details of UUID at:
|
17
|
+
# See RFC 4122 for details of UUID at: https://www.ietf.org/rfc/rfc4122.txt
|
16
18
|
def self.uuid_from_hash(hash_class, uuid_namespace, name)
|
17
19
|
if hash_class == Digest::MD5
|
18
20
|
version = 3
|
@@ -26,7 +28,7 @@ module Digest
|
|
26
28
|
hash.update(uuid_namespace)
|
27
29
|
hash.update(name)
|
28
30
|
|
29
|
-
ary = hash.digest.unpack(
|
31
|
+
ary = hash.digest.unpack("NnnnnN")
|
30
32
|
ary[2] = (ary[2] & 0x0FFF) | (version << 12)
|
31
33
|
ary[3] = (ary[3] & 0x3FFF) | 0x8000
|
32
34
|
|
@@ -35,12 +37,12 @@ module Digest
|
|
35
37
|
|
36
38
|
# Convenience method for uuid_from_hash using Digest::MD5.
|
37
39
|
def self.uuid_v3(uuid_namespace, name)
|
38
|
-
|
40
|
+
uuid_from_hash(Digest::MD5, uuid_namespace, name)
|
39
41
|
end
|
40
42
|
|
41
43
|
# Convenience method for uuid_from_hash using Digest::SHA1.
|
42
44
|
def self.uuid_v5(uuid_namespace, name)
|
43
|
-
|
45
|
+
uuid_from_hash(Digest::SHA1, uuid_namespace, name)
|
44
46
|
end
|
45
47
|
|
46
48
|
# Convenience method for SecureRandom.uuid.
|
@@ -1,39 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Enumerable
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# payments.sum { |p| p.price * p.tax_rate }
|
5
|
-
# payments.sum(&:price)
|
6
|
-
#
|
7
|
-
# The latter is a shortcut for:
|
8
|
-
#
|
9
|
-
# payments.inject(0) { |sum, p| sum + p.price }
|
10
|
-
#
|
11
|
-
# It can also calculate the sum without the use of a block.
|
4
|
+
# Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
|
5
|
+
# when we omit an identity.
|
12
6
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
7
|
+
# We tried shimming it to attempt the fast native method, rescue TypeError,
|
8
|
+
# and fall back to the compatible implementation, but that's much slower than
|
9
|
+
# just calling the compat method in the first place.
|
10
|
+
if Enumerable.instance_methods(false).include?(:sum) && !((?a..?b).sum rescue false)
|
11
|
+
# :stopdoc:
|
12
|
+
|
13
|
+
# We can't use Refinements here because Refinements with Module which will be prepended
|
14
|
+
# doesn't work well https://bugs.ruby-lang.org/issues/13446
|
15
|
+
alias :_original_sum_with_required_identity :sum
|
16
|
+
private :_original_sum_with_required_identity
|
17
|
+
|
18
|
+
# :startdoc:
|
19
|
+
|
20
|
+
# Calculates a sum from the elements.
|
21
|
+
#
|
22
|
+
# payments.sum { |p| p.price * p.tax_rate }
|
23
|
+
# payments.sum(&:price)
|
24
|
+
#
|
25
|
+
# The latter is a shortcut for:
|
26
|
+
#
|
27
|
+
# payments.inject(0) { |sum, p| sum + p.price }
|
28
|
+
#
|
29
|
+
# It can also calculate the sum without the use of a block.
|
30
|
+
#
|
31
|
+
# [5, 15, 10].sum # => 30
|
32
|
+
# ['foo', 'bar'].sum # => "foobar"
|
33
|
+
# [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
|
34
|
+
#
|
35
|
+
# The default sum of an empty list is zero. You can override this default:
|
36
|
+
#
|
37
|
+
# [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
|
38
|
+
def sum(identity = nil, &block)
|
39
|
+
if identity
|
40
|
+
_original_sum_with_required_identity(identity, &block)
|
41
|
+
elsif block_given?
|
42
|
+
map(&block).sum(identity)
|
43
|
+
else
|
44
|
+
inject(:+) || 0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
else
|
48
|
+
def sum(identity = nil, &block)
|
49
|
+
if block_given?
|
50
|
+
map(&block).sum(identity)
|
51
|
+
else
|
52
|
+
sum = identity ? inject(identity, :+) : inject(:+)
|
53
|
+
sum || identity || 0
|
54
|
+
end
|
25
55
|
end
|
26
56
|
end
|
27
57
|
|
28
58
|
# Convert an enumerable to a hash.
|
29
59
|
#
|
30
60
|
# people.index_by(&:login)
|
31
|
-
#
|
61
|
+
# # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
|
32
62
|
# people.index_by { |person| "#{person.first_name} #{person.last_name}" }
|
33
|
-
#
|
63
|
+
# # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
|
34
64
|
def index_by
|
35
65
|
if block_given?
|
36
|
-
|
66
|
+
result = {}
|
67
|
+
each { |elem| result[yield(elem)] = elem }
|
68
|
+
result
|
37
69
|
else
|
38
70
|
to_enum(:index_by) { size if respond_to?(:size) }
|
39
71
|
end
|
@@ -60,20 +92,47 @@ module Enumerable
|
|
60
92
|
def exclude?(object)
|
61
93
|
!include?(object)
|
62
94
|
end
|
95
|
+
|
96
|
+
# Returns a copy of the enumerable without the specified elements.
|
97
|
+
#
|
98
|
+
# ["David", "Rafael", "Aaron", "Todd"].without "Aaron", "Todd"
|
99
|
+
# # => ["David", "Rafael"]
|
100
|
+
#
|
101
|
+
# {foo: 1, bar: 2, baz: 3}.without :bar
|
102
|
+
# # => {foo: 1, baz: 3}
|
103
|
+
def without(*elements)
|
104
|
+
reject { |element| elements.include?(element) }
|
105
|
+
end
|
106
|
+
|
107
|
+
# Convert an enumerable to an array based on the given key.
|
108
|
+
#
|
109
|
+
# [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
|
110
|
+
# # => ["David", "Rafael", "Aaron"]
|
111
|
+
#
|
112
|
+
# [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
|
113
|
+
# # => [[1, "David"], [2, "Rafael"]]
|
114
|
+
def pluck(*keys)
|
115
|
+
if keys.many?
|
116
|
+
map { |element| keys.map { |key| element[key] } }
|
117
|
+
else
|
118
|
+
map { |element| element[keys.first] }
|
119
|
+
end
|
120
|
+
end
|
63
121
|
end
|
64
122
|
|
65
123
|
class Range #:nodoc:
|
66
124
|
# Optimize range sum to use arithmetic progression if a block is not given and
|
67
125
|
# we have a range of numeric values.
|
68
|
-
def sum(identity =
|
126
|
+
def sum(identity = nil)
|
69
127
|
if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
|
70
128
|
super
|
71
129
|
else
|
72
130
|
actual_last = exclude_end? ? (last - 1) : last
|
73
131
|
if actual_last >= first
|
74
|
-
|
132
|
+
sum = identity || 0
|
133
|
+
sum + (actual_last - first + 1) * (actual_last + first) / 2
|
75
134
|
else
|
76
|
-
identity
|
135
|
+
identity || 0
|
77
136
|
end
|
78
137
|
end
|
79
138
|
end
|
@@ -85,12 +144,21 @@ end
|
|
85
144
|
# and fall back to the compatible implementation, but that's much slower than
|
86
145
|
# just calling the compat method in the first place.
|
87
146
|
if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
|
88
|
-
|
89
|
-
|
147
|
+
# Using Refinements here in order not to expose our internal method
|
148
|
+
using Module.new {
|
149
|
+
refine Array do
|
150
|
+
alias :orig_sum :sum
|
151
|
+
end
|
152
|
+
}
|
90
153
|
|
91
|
-
|
92
|
-
|
93
|
-
|
154
|
+
class Array
|
155
|
+
def sum(init = nil, &block) #:nodoc:
|
156
|
+
if init.is_a?(Numeric) || first.is_a?(Numeric)
|
157
|
+
init ||= 0
|
158
|
+
orig_sum(init, &block)
|
159
|
+
else
|
160
|
+
super
|
161
|
+
end
|
94
162
|
end
|
95
163
|
end
|
96
164
|
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
|
@@ -8,51 +10,56 @@ class File
|
|
8
10
|
# file.write('hello')
|
9
11
|
# end
|
10
12
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
+
# This method needs to create a temporary file. By default it will create it
|
14
|
+
# in the same directory as the destination file. If you don't like this
|
15
|
+
# behavior you can provide a different directory but it must be on the
|
16
|
+
# same physical filesystem as the file you're trying to write.
|
13
17
|
#
|
14
18
|
# File.atomic_write('/data/something.important', '/data/tmp') do |file|
|
15
19
|
# file.write('hello')
|
16
20
|
# end
|
17
|
-
def self.atomic_write(file_name, temp_dir =
|
18
|
-
require
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
21
|
+
def self.atomic_write(file_name, temp_dir = dirname(file_name))
|
22
|
+
require "tempfile" unless defined?(Tempfile)
|
23
|
+
|
24
|
+
Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file|
|
25
|
+
temp_file.binmode
|
26
|
+
return_val = yield temp_file
|
27
|
+
temp_file.close
|
28
|
+
|
29
|
+
old_stat = if exist?(file_name)
|
30
|
+
# Get original file permissions
|
31
|
+
stat(file_name)
|
32
|
+
else
|
33
|
+
# If not possible, probe which are the default permissions in the
|
34
|
+
# destination directory.
|
35
|
+
probe_stat_in(dirname(file_name))
|
36
|
+
end
|
34
37
|
|
35
|
-
|
36
|
-
|
38
|
+
if old_stat
|
39
|
+
# Set correct permissions on new file
|
40
|
+
begin
|
41
|
+
chown(old_stat.uid, old_stat.gid, temp_file.path)
|
42
|
+
# This operation will affect filesystem ACL's
|
43
|
+
chmod(old_stat.mode, temp_file.path)
|
44
|
+
rescue Errno::EPERM, Errno::EACCES
|
45
|
+
# Changing file ownership failed, moving on.
|
46
|
+
end
|
47
|
+
end
|
37
48
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# This operation will affect filesystem ACL's
|
42
|
-
chmod(old_stat.mode, file_name)
|
43
|
-
rescue Errno::EPERM, Errno::EACCES
|
44
|
-
# Changing file ownership failed, moving on.
|
49
|
+
# Overwrite original file with temp file
|
50
|
+
rename(temp_file.path, file_name)
|
51
|
+
return_val
|
45
52
|
end
|
46
53
|
end
|
47
54
|
|
48
55
|
# Private utility method.
|
49
56
|
def self.probe_stat_in(dir) #:nodoc:
|
50
57
|
basename = [
|
51
|
-
|
58
|
+
".permissions_check",
|
52
59
|
Thread.current.object_id,
|
53
60
|
Process.pid,
|
54
61
|
rand(1000000)
|
55
|
-
].join(
|
62
|
+
].join(".")
|
56
63
|
|
57
64
|
file_name = join(dir, basename)
|
58
65
|
FileUtils.touch(file_name)
|
@@ -1,24 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Hash
|
2
4
|
unless Hash.instance_methods(false).include?(:compact)
|
3
5
|
# Returns a hash with non +nil+ values.
|
4
6
|
#
|
5
|
-
# hash = { a: true, b: false, c: nil}
|
6
|
-
# hash.compact
|
7
|
-
# hash
|
8
|
-
# { c: nil }.compact
|
7
|
+
# hash = { a: true, b: false, c: nil }
|
8
|
+
# hash.compact # => { a: true, b: false }
|
9
|
+
# hash # => { a: true, b: false, c: nil }
|
10
|
+
# { c: nil }.compact # => {}
|
11
|
+
# { c: true }.compact # => { c: true }
|
9
12
|
def compact
|
10
|
-
|
13
|
+
select { |_, value| !value.nil? }
|
11
14
|
end
|
12
15
|
end
|
13
16
|
|
14
17
|
unless Hash.instance_methods(false).include?(:compact!)
|
15
18
|
# Replaces current hash with non +nil+ values.
|
19
|
+
# Returns +nil+ if no changes were made, otherwise returns the hash.
|
16
20
|
#
|
17
|
-
# hash = { a: true, b: false, c: nil}
|
18
|
-
# hash.compact!
|
19
|
-
# hash
|
21
|
+
# hash = { a: true, b: false, c: nil }
|
22
|
+
# hash.compact! # => { a: true, b: false }
|
23
|
+
# hash # => { a: true, b: false }
|
24
|
+
# { c: true }.compact! # => nil
|
20
25
|
def compact!
|
21
|
-
|
26
|
+
reject! { |_, value| value.nil? }
|
22
27
|
end
|
23
28
|
end
|
24
29
|
end
|
@@ -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/time"
|
5
|
+
require "active_support/core_ext/object/blank"
|
6
|
+
require "active_support/core_ext/object/to_param"
|
7
|
+
require "active_support/core_ext/object/to_query"
|
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:
|
@@ -31,7 +33,7 @@ class Hash
|
|
31
33
|
# with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
|
32
34
|
# callable can add nodes by using <tt>options[:builder]</tt>.
|
33
35
|
#
|
34
|
-
#
|
36
|
+
# {foo: lambda { |options, key| options[:builder].b(key) }}.to_xml
|
35
37
|
# # => "<b>foo</b>"
|
36
38
|
#
|
37
39
|
# * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
|
@@ -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)
|
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]
|
@@ -105,7 +107,25 @@ class Hash
|
|
105
107
|
# # => {"hash"=>{"foo"=>1, "bar"=>2}}
|
106
108
|
#
|
107
109
|
# +DisallowedType+ is raised if the XML contains attributes with <tt>type="yaml"</tt> or
|
108
|
-
# <tt>type="symbol"</tt>. Use <tt>Hash.from_trusted_xml</tt> to
|
110
|
+
# <tt>type="symbol"</tt>. Use <tt>Hash.from_trusted_xml</tt> to
|
111
|
+
# parse this XML.
|
112
|
+
#
|
113
|
+
# Custom +disallowed_types+ can also be passed in the form of an
|
114
|
+
# array.
|
115
|
+
#
|
116
|
+
# xml = <<-XML
|
117
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
118
|
+
# <hash>
|
119
|
+
# <foo type="integer">1</foo>
|
120
|
+
# <bar type="string">"David"</bar>
|
121
|
+
# </hash>
|
122
|
+
# XML
|
123
|
+
#
|
124
|
+
# hash = Hash.from_xml(xml, ['integer'])
|
125
|
+
# # => ActiveSupport::XMLConverter::DisallowedType: Disallowed type attribute: "integer"
|
126
|
+
#
|
127
|
+
# Note that passing custom disallowed types will override the default types,
|
128
|
+
# which are Symbol and YAML.
|
109
129
|
def from_xml(xml, disallowed_types = nil)
|
110
130
|
ActiveSupport::XMLConverter.new(xml, disallowed_types).to_h
|
111
131
|
end
|
@@ -119,6 +139,8 @@ end
|
|
119
139
|
|
120
140
|
module ActiveSupport
|
121
141
|
class XMLConverter # :nodoc:
|
142
|
+
# Raised if the XML contains attributes with type="yaml" or
|
143
|
+
# type="symbol". Read Hash#from_xml for more details.
|
122
144
|
class DisallowedType < StandardError
|
123
145
|
def initialize(type)
|
124
146
|
super "Disallowed type attribute: #{type.inspect}"
|
@@ -139,36 +161,36 @@ module ActiveSupport
|
|
139
161
|
private
|
140
162
|
def normalize_keys(params)
|
141
163
|
case params
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
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
|
148
170
|
end
|
149
171
|
end
|
150
172
|
|
151
173
|
def deep_to_h(value)
|
152
174
|
case value
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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}"
|
161
183
|
end
|
162
184
|
end
|
163
185
|
|
164
186
|
def process_hash(value)
|
165
|
-
if value.include?(
|
166
|
-
raise DisallowedType, value[
|
187
|
+
if value.include?("type") && !value["type"].is_a?(Hash) && @disallowed_types.include?(value["type"])
|
188
|
+
raise DisallowedType, value["type"]
|
167
189
|
end
|
168
190
|
|
169
191
|
if become_array?(value)
|
170
|
-
_, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) })
|
171
|
-
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?)
|
172
194
|
[]
|
173
195
|
else
|
174
196
|
case entries
|
@@ -184,28 +206,28 @@ module ActiveSupport
|
|
184
206
|
process_content(value)
|
185
207
|
|
186
208
|
elsif become_empty_string?(value)
|
187
|
-
|
209
|
+
""
|
188
210
|
elsif become_hash?(value)
|
189
|
-
xml_value = Hash[value.map { |k,v| [k, deep_to_h(v)] }]
|
211
|
+
xml_value = Hash[value.map { |k, v| [k, deep_to_h(v)] }]
|
190
212
|
|
191
213
|
# Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
|
192
214
|
# how multipart uploaded files from HTML appear
|
193
|
-
xml_value[
|
215
|
+
xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
|
194
216
|
end
|
195
217
|
end
|
196
218
|
|
197
219
|
def become_content?(value)
|
198
|
-
value[
|
220
|
+
value["type"] == "file" || (value["__content__"] && (value.keys.size == 1 || value["__content__"].present?))
|
199
221
|
end
|
200
222
|
|
201
223
|
def become_array?(value)
|
202
|
-
value[
|
224
|
+
value["type"] == "array"
|
203
225
|
end
|
204
226
|
|
205
227
|
def become_empty_string?(value)
|
206
228
|
# { "string" => true }
|
207
229
|
# No tests fail when the second term is removed.
|
208
|
-
value[
|
230
|
+
value["type"] == "string" && value["nil"] != "true"
|
209
231
|
end
|
210
232
|
|
211
233
|
def become_hash?(value)
|
@@ -214,19 +236,19 @@ module ActiveSupport
|
|
214
236
|
|
215
237
|
def nothing?(value)
|
216
238
|
# blank or nil parsed values are represented by nil
|
217
|
-
value.blank? || value[
|
239
|
+
value.blank? || value["nil"] == "true"
|
218
240
|
end
|
219
241
|
|
220
242
|
def garbage?(value)
|
221
243
|
# If the type is the only element which makes it then
|
222
244
|
# this still makes the value nil, except if type is
|
223
245
|
# an XML node(where type['value'] is a Hash)
|
224
|
-
value[
|
246
|
+
value["type"] && !value["type"].is_a?(::Hash) && value.size == 1
|
225
247
|
end
|
226
248
|
|
227
249
|
def process_content(value)
|
228
|
-
content = value[
|
229
|
-
if parser = ActiveSupport::XmlMini::PARSING[value[
|
250
|
+
content = value["__content__"]
|
251
|
+
if parser = ActiveSupport::XmlMini::PARSING[value["type"]]
|
230
252
|
parser.arity == 1 ? parser.call(content) : parser.call(content, value)
|
231
253
|
else
|
232
254
|
content
|
@@ -237,6 +259,5 @@ module ActiveSupport
|
|
237
259
|
value.map! { |i| deep_to_h(i) }
|
238
260
|
value.length > 1 ? value : value.first
|
239
261
|
end
|
240
|
-
|
241
262
|
end
|
242
263
|
end
|
@@ -1,10 +1,12 @@
|
|
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
|
#
|
4
6
|
# h1 = { a: true, b: { c: [1, 2, 3] } }
|
5
7
|
# h2 = { a: false, b: { x: [3, 4, 5] } }
|
6
8
|
#
|
7
|
-
# h1.deep_merge(h2)
|
9
|
+
# h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
|
8
10
|
#
|
9
11
|
# Like with Hash#merge in the standard library, a block can be provided
|
10
12
|
# to merge values:
|
@@ -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
|
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Hash
|
2
|
-
# Returns a hash that includes everything
|
3
|
-
# hash = { a: true, b: false, c: nil}
|
4
|
-
# hash.except(:c)
|
5
|
-
# hash # => {
|
4
|
+
# Returns a hash that includes everything except given keys.
|
5
|
+
# hash = { a: true, b: false, c: nil }
|
6
|
+
# hash.except(:c) # => { a: true, b: false }
|
7
|
+
# hash.except(:a, :b) # => { c: nil }
|
8
|
+
# hash # => { a: true, b: false, c: nil }
|
6
9
|
#
|
7
10
|
# This is useful for limiting a set of parameters to everything but a few known toggles:
|
8
11
|
# @person.update(params[:person].except(:admin))
|
@@ -10,10 +13,10 @@ class Hash
|
|
10
13
|
dup.except!(*keys)
|
11
14
|
end
|
12
15
|
|
13
|
-
#
|
14
|
-
# hash = { a: true, b: false, c: nil}
|
15
|
-
# hash.except!(:c) # => { a: true, b: false}
|
16
|
-
# hash
|
16
|
+
# Removes the given keys from hash and returns it.
|
17
|
+
# hash = { a: true, b: false, c: nil }
|
18
|
+
# hash.except!(:c) # => { a: true, b: false }
|
19
|
+
# hash # => { a: true, b: false }
|
17
20
|
def except!(*keys)
|
18
21
|
keys.each { |key| delete(key) }
|
19
22
|
self
|
@@ -1,12 +1,13 @@
|
|
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
|
8
9
|
def with_indifferent_access
|
9
|
-
ActiveSupport::HashWithIndifferentAccess.
|
10
|
+
ActiveSupport::HashWithIndifferentAccess.new(self)
|
10
11
|
end
|
11
12
|
|
12
13
|
# Called when object is nested under an object that receives
|