activesupport 4.2.0 → 5.2.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 +366 -232
- data/MIT-LICENSE +2 -2
- data/README.rdoc +4 -5
- data/lib/active_support.rb +17 -7
- 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.rb +271 -177
- data/lib/active_support/cache/file_store.rb +41 -35
- data/lib/active_support/cache/mem_cache_store.rb +97 -88
- 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 +454 -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/callbacks.rb +654 -560
- data/lib/active_support/concern.rb +5 -3
- 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 +8 -5
- data/lib/active_support/core_ext.rb +3 -1
- data/lib/active_support/core_ext/array.rb +9 -6
- 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/benchmark.rb +3 -1
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
- data/lib/active_support/core_ext/class.rb +4 -3
- 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 -8
- data/lib/active_support/core_ext/date.rb +6 -4
- 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 +31 -23
- data/lib/active_support/core_ext/date/zones.rb +4 -2
- data/lib/active_support/core_ext/date_and_time/calculations.rb +179 -56
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +12 -12
- data/lib/active_support/core_ext/date_time.rb +7 -4
- 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 +58 -20
- data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +16 -12
- data/lib/active_support/core_ext/digest/uuid.rb +7 -5
- data/lib/active_support/core_ext/enumerable.rb +107 -28
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/file/atomic.rb +38 -31
- data/lib/active_support/core_ext/hash.rb +11 -9
- data/lib/active_support/core_ext/hash/compact.rb +24 -15
- data/lib/active_support/core_ext/hash/conversions.rb +63 -43
- 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 +16 -7
- data/lib/active_support/core_ext/integer.rb +5 -3
- 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 -33
- data/lib/active_support/core_ext/kernel.rb +6 -5
- 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 -83
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/load_error.rb +3 -22
- data/lib/active_support/core_ext/marshal.rb +13 -10
- data/lib/active_support/core_ext/module.rb +14 -11
- 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 +121 -39
- 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/name_error.rb +22 -2
- data/lib/active_support/core_ext/numeric.rb +6 -3
- data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +79 -74
- data/lib/active_support/core_ext/numeric/inquiry.rb +28 -0
- data/lib/active_support/core_ext/numeric/time.rb +35 -38
- data/lib/active_support/core_ext/object.rb +14 -13
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +29 -4
- 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 +98 -45
- 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 +6 -4
- data/lib/active_support/core_ext/object/try.rb +70 -22
- data/lib/active_support/core_ext/object/with_options.rb +16 -3
- data/lib/active_support/core_ext/range.rb +7 -4
- 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 +21 -19
- 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/regexp.rb +6 -0
- data/lib/active_support/core_ext/securerandom.rb +25 -0
- data/lib/active_support/core_ext/string.rb +15 -13
- data/lib/active_support/core_ext/string/access.rb +9 -7
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +8 -5
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +10 -8
- 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 +35 -35
- 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/time.rb +7 -5
- data/lib/active_support/core_ext/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +101 -51
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- 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/uri.rb +5 -4
- data/lib/active_support/current_attributes.rb +195 -0
- data/lib/active_support/dependencies.rb +143 -160
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +57 -0
- data/lib/active_support/deprecation.rb +12 -9
- data/lib/active_support/deprecation/behaviors.rb +41 -12
- 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 +54 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +56 -28
- data/lib/active_support/deprecation/reporting.rb +32 -12
- data/lib/active_support/descendants_tracker.rb +2 -0
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration.rb +326 -30
- data/lib/active_support/duration/iso8601_parser.rb +125 -0
- data/lib/active_support/duration/iso8601_serializer.rb +55 -0
- 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 +128 -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 +4 -2
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +130 -30
- data/lib/active_support/i18n.rb +8 -6
- data/lib/active_support/i18n_railtie.rb +34 -14
- data/lib/active_support/inflections.rb +13 -11
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/inflector/inflections.rb +61 -12
- data/lib/active_support/inflector/methods.rb +161 -136
- data/lib/active_support/inflector/transliterate.rb +48 -27
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/json/decoding.rb +16 -13
- data/lib/active_support/json/encoding.rb +15 -57
- 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.rb +13 -10
- data/lib/active_support/log_subscriber/test_helper.rb +14 -12
- data/lib/active_support/logger.rb +54 -3
- data/lib/active_support/logger_silence.rb +12 -7
- data/lib/active_support/logger_thread_safe_level.rb +33 -0
- data/lib/active_support/message_encryptor.rb +173 -51
- 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.rb +4 -2
- data/lib/active_support/multibyte/chars.rb +37 -24
- data/lib/active_support/multibyte/unicode.rb +100 -96
- data/lib/active_support/notifications.rb +11 -7
- data/lib/active_support/notifications/fanout.rb +10 -8
- data/lib/active_support/notifications/instrumenter.rb +27 -7
- data/lib/active_support/number_helper.rb +94 -68
- 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/option_merger.rb +3 -1
- data/lib/active_support/ordered_hash.rb +6 -4
- data/lib/active_support/ordered_options.rb +22 -4
- data/lib/active_support/per_thread_registry.rb +13 -6
- 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 +17 -6
- data/lib/active_support/string_inquirer.rb +11 -3
- data/lib/active_support/subscriber.rb +15 -14
- data/lib/active_support/tagged_logging.rb +14 -11
- data/lib/active_support/test_case.rb +18 -46
- 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 +12 -3
- 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 +96 -27
- data/lib/active_support/time.rb +14 -12
- data/lib/active_support/time_with_zone.rb +195 -53
- data/lib/active_support/values/time_zone.rb +200 -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.rb +69 -51
- data/lib/active_support/xml_mini/jdom.rb +116 -113
- data/lib/active_support/xml_mini/libxml.rb +17 -16
- data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
- data/lib/active_support/xml_mini/nokogiri.rb +15 -15
- data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
- data/lib/active_support/xml_mini/rexml.rb +17 -16
- metadata +55 -43
- data/lib/active_support/concurrency/latch.rb +0 -27
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -14
- 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 -11
- 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,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
|
+
elsif temp_dir != dirname(file_name)
|
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,9 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/hash/compact"
|
4
|
+
require "active_support/core_ext/hash/conversions"
|
5
|
+
require "active_support/core_ext/hash/deep_merge"
|
6
|
+
require "active_support/core_ext/hash/except"
|
7
|
+
require "active_support/core_ext/hash/indifferent_access"
|
8
|
+
require "active_support/core_ext/hash/keys"
|
9
|
+
require "active_support/core_ext/hash/reverse_merge"
|
10
|
+
require "active_support/core_ext/hash/slice"
|
11
|
+
require "active_support/core_ext/hash/transform_values"
|
@@ -1,20 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Hash
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
unless Hash.instance_methods(false).include?(:compact)
|
5
|
+
# Returns a hash with non +nil+ values.
|
6
|
+
#
|
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 }
|
12
|
+
def compact
|
13
|
+
select { |_, value| !value.nil? }
|
14
|
+
end
|
10
15
|
end
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
unless Hash.instance_methods(false).include?(:compact!)
|
18
|
+
# Replaces current hash with non +nil+ values.
|
19
|
+
# Returns +nil+ if no changes were made, otherwise returns the hash.
|
20
|
+
#
|
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
|
25
|
+
def compact!
|
26
|
+
reject! { |_, value| value.nil? }
|
27
|
+
end
|
19
28
|
end
|
20
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>.
|
@@ -55,8 +57,7 @@ class Hash
|
|
55
57
|
#
|
56
58
|
# XML_TYPE_NAMES = {
|
57
59
|
# "Symbol" => "symbol",
|
58
|
-
# "
|
59
|
-
# "Bignum" => "integer",
|
60
|
+
# "Integer" => "integer",
|
60
61
|
# "BigDecimal" => "decimal",
|
61
62
|
# "Float" => "float",
|
62
63
|
# "TrueClass" => "boolean",
|
@@ -72,11 +73,11 @@ class Hash
|
|
72
73
|
# configure your own builder with the <tt>:builder</tt> option. The method also accepts
|
73
74
|
# options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
|
74
75
|
def to_xml(options = {})
|
75
|
-
require
|
76
|
+
require "active_support/builder" unless defined?(Builder)
|
76
77
|
|
77
78
|
options = options.dup
|
78
79
|
options[:indent] ||= 2
|
79
|
-
options[:root] ||=
|
80
|
+
options[:root] ||= "hash"
|
80
81
|
options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
|
81
82
|
|
82
83
|
builder = options[:builder]
|
@@ -106,7 +107,25 @@ class Hash
|
|
106
107
|
# # => {"hash"=>{"foo"=>1, "bar"=>2}}
|
107
108
|
#
|
108
109
|
# +DisallowedType+ is raised if the XML contains attributes with <tt>type="yaml"</tt> or
|
109
|
-
# <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.
|
110
129
|
def from_xml(xml, disallowed_types = nil)
|
111
130
|
ActiveSupport::XMLConverter.new(xml, disallowed_types).to_h
|
112
131
|
end
|
@@ -120,6 +139,8 @@ end
|
|
120
139
|
|
121
140
|
module ActiveSupport
|
122
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.
|
123
144
|
class DisallowedType < StandardError
|
124
145
|
def initialize(type)
|
125
146
|
super "Disallowed type attribute: #{type.inspect}"
|
@@ -140,36 +161,36 @@ module ActiveSupport
|
|
140
161
|
private
|
141
162
|
def normalize_keys(params)
|
142
163
|
case params
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
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
|
149
170
|
end
|
150
171
|
end
|
151
172
|
|
152
173
|
def deep_to_h(value)
|
153
174
|
case value
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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}"
|
162
183
|
end
|
163
184
|
end
|
164
185
|
|
165
186
|
def process_hash(value)
|
166
|
-
if value.include?(
|
167
|
-
raise DisallowedType, value[
|
187
|
+
if value.include?("type") && !value["type"].is_a?(Hash) && @disallowed_types.include?(value["type"])
|
188
|
+
raise DisallowedType, value["type"]
|
168
189
|
end
|
169
190
|
|
170
191
|
if become_array?(value)
|
171
|
-
_, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) })
|
172
|
-
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?)
|
173
194
|
[]
|
174
195
|
else
|
175
196
|
case entries
|
@@ -185,28 +206,28 @@ module ActiveSupport
|
|
185
206
|
process_content(value)
|
186
207
|
|
187
208
|
elsif become_empty_string?(value)
|
188
|
-
|
209
|
+
""
|
189
210
|
elsif become_hash?(value)
|
190
|
-
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)] }]
|
191
212
|
|
192
213
|
# Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
|
193
214
|
# how multipart uploaded files from HTML appear
|
194
|
-
xml_value[
|
215
|
+
xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
|
195
216
|
end
|
196
217
|
end
|
197
218
|
|
198
219
|
def become_content?(value)
|
199
|
-
value[
|
220
|
+
value["type"] == "file" || (value["__content__"] && (value.keys.size == 1 || value["__content__"].present?))
|
200
221
|
end
|
201
222
|
|
202
223
|
def become_array?(value)
|
203
|
-
value[
|
224
|
+
value["type"] == "array"
|
204
225
|
end
|
205
226
|
|
206
227
|
def become_empty_string?(value)
|
207
228
|
# { "string" => true }
|
208
229
|
# No tests fail when the second term is removed.
|
209
|
-
value[
|
230
|
+
value["type"] == "string" && value["nil"] != "true"
|
210
231
|
end
|
211
232
|
|
212
233
|
def become_hash?(value)
|
@@ -215,19 +236,19 @@ module ActiveSupport
|
|
215
236
|
|
216
237
|
def nothing?(value)
|
217
238
|
# blank or nil parsed values are represented by nil
|
218
|
-
value.blank? || value[
|
239
|
+
value.blank? || value["nil"] == "true"
|
219
240
|
end
|
220
241
|
|
221
242
|
def garbage?(value)
|
222
243
|
# If the type is the only element which makes it then
|
223
244
|
# this still makes the value nil, except if type is
|
224
245
|
# an XML node(where type['value'] is a Hash)
|
225
|
-
value[
|
246
|
+
value["type"] && !value["type"].is_a?(::Hash) && value.size == 1
|
226
247
|
end
|
227
248
|
|
228
249
|
def process_content(value)
|
229
|
-
content = value[
|
230
|
-
if parser = ActiveSupport::XmlMini::PARSING[value[
|
250
|
+
content = value["__content__"]
|
251
|
+
if parser = ActiveSupport::XmlMini::PARSING[value["type"]]
|
231
252
|
parser.arity == 1 ? parser.call(content) : parser.call(content, value)
|
232
253
|
else
|
233
254
|
content
|
@@ -238,6 +259,5 @@ module ActiveSupport
|
|
238
259
|
value.map! { |i| deep_to_h(i) }
|
239
260
|
value.length > 1 ? value : value.first
|
240
261
|
end
|
241
|
-
|
242
262
|
end
|
243
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
|