activesupport 3.1.0 → 5.0.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 +7 -0
- data/CHANGELOG.md +798 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +13 -7
- data/lib/active_support/array_inquirer.rb +44 -0
- data/lib/active_support/backtrace_cleaner.rb +38 -34
- data/lib/active_support/benchmarkable.rb +17 -28
- data/lib/active_support/cache/file_store.rb +85 -70
- data/lib/active_support/cache/mem_cache_store.rb +75 -66
- data/lib/active_support/cache/memory_store.rb +31 -23
- data/lib/active_support/cache/null_store.rb +41 -0
- data/lib/active_support/cache/strategy/local_cache.rb +73 -70
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
- data/lib/active_support/cache.rb +360 -294
- data/lib/active_support/callbacks.rb +563 -393
- data/lib/active_support/concern.rb +42 -34
- data/lib/active_support/concurrency/latch.rb +19 -0
- data/lib/active_support/concurrency/share_lock.rb +186 -0
- data/lib/active_support/configurable.rb +70 -12
- data/lib/active_support/core_ext/array/access.rb +53 -9
- data/lib/active_support/core_ext/array/conversions.rb +109 -62
- data/lib/active_support/core_ext/array/extract_options.rb +2 -2
- data/lib/active_support/core_ext/array/grouping.rb +39 -32
- data/lib/active_support/core_ext/array/inquiry.rb +17 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +7 -0
- data/lib/active_support/core_ext/array/wrap.rb +16 -18
- data/lib/active_support/core_ext/array.rb +2 -2
- data/lib/active_support/core_ext/benchmark.rb +7 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -36
- data/lib/active_support/core_ext/class/attribute.rb +47 -34
- data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -79
- data/lib/active_support/core_ext/class/subclasses.rb +12 -7
- data/lib/active_support/core_ext/class.rb +0 -3
- data/lib/active_support/core_ext/date/blank.rb +12 -0
- data/lib/active_support/core_ext/date/calculations.rb +57 -167
- data/lib/active_support/core_ext/date/conversions.rb +31 -42
- data/lib/active_support/core_ext/date/zones.rb +2 -10
- data/lib/active_support/core_ext/date.rb +5 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +335 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +1 -0
- data/lib/active_support/core_ext/date_time/blank.rb +12 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +132 -65
- data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +36 -34
- data/lib/active_support/core_ext/date_time.rb +5 -0
- data/lib/active_support/core_ext/digest/uuid.rb +51 -0
- data/lib/active_support/core_ext/enumerable.rb +81 -74
- data/lib/active_support/core_ext/file/atomic.rb +53 -26
- data/lib/active_support/core_ext/file.rb +0 -1
- data/lib/active_support/core_ext/hash/compact.rb +20 -0
- data/lib/active_support/core_ext/hash/conversions.rb +175 -70
- data/lib/active_support/core_ext/hash/deep_merge.rb +30 -8
- data/lib/active_support/core_ext/hash/except.rb +11 -12
- data/lib/active_support/core_ext/hash/indifferent_access.rb +7 -8
- data/lib/active_support/core_ext/hash/keys.rb +147 -24
- data/lib/active_support/core_ext/hash/reverse_merge.rb +2 -3
- data/lib/active_support/core_ext/hash/slice.rb +22 -14
- data/lib/active_support/core_ext/hash/transform_values.rb +29 -0
- data/lib/active_support/core_ext/hash.rb +2 -2
- data/lib/active_support/core_ext/integer/inflections.rb +13 -1
- data/lib/active_support/core_ext/integer/multiple.rb +4 -0
- data/lib/active_support/core_ext/integer/time.rb +12 -22
- data/lib/active_support/core_ext/kernel/agnostics.rb +2 -2
- data/lib/active_support/core_ext/kernel/concern.rb +12 -0
- data/lib/active_support/core_ext/kernel/debugger.rb +2 -15
- data/lib/active_support/core_ext/kernel/reporting.rb +12 -62
- data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -7
- data/lib/active_support/core_ext/kernel.rb +2 -3
- data/lib/active_support/core_ext/load_error.rb +14 -7
- data/lib/active_support/core_ext/marshal.rb +22 -0
- data/lib/active_support/core_ext/module/aliasing.rb +16 -12
- data/lib/active_support/core_ext/module/anonymous.rb +12 -8
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
- data/lib/active_support/core_ext/module/attribute_accessors.rb +165 -13
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
- data/lib/active_support/core_ext/module/concerning.rb +135 -0
- data/lib/active_support/core_ext/module/delegation.rb +141 -68
- data/lib/active_support/core_ext/module/deprecation.rb +17 -3
- data/lib/active_support/core_ext/module/introspection.rb +9 -31
- data/lib/active_support/core_ext/module/method_transplanting.rb +3 -0
- data/lib/active_support/core_ext/module/qualified_const.rb +70 -0
- data/lib/active_support/core_ext/module/reachable.rb +1 -3
- data/lib/active_support/core_ext/module/remove_method.rb +24 -5
- data/lib/active_support/core_ext/module.rb +3 -3
- data/lib/active_support/core_ext/name_error.rb +15 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
- data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
- data/lib/active_support/core_ext/numeric/time.rb +31 -36
- data/lib/active_support/core_ext/numeric.rb +2 -0
- data/lib/active_support/core_ext/object/acts_like.rb +4 -4
- data/lib/active_support/core_ext/object/blank.rb +52 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +53 -0
- data/lib/active_support/core_ext/object/duplicable.rb +12 -20
- data/lib/active_support/core_ext/object/inclusion.rb +13 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +7 -12
- data/lib/active_support/core_ext/object/json.rb +205 -0
- data/lib/active_support/core_ext/object/to_param.rb +1 -55
- data/lib/active_support/core_ext/object/to_query.rb +66 -9
- data/lib/active_support/core_ext/object/try.rb +124 -33
- data/lib/active_support/core_ext/object/with_options.rb +37 -11
- data/lib/active_support/core_ext/object.rb +2 -1
- data/lib/active_support/core_ext/range/conversions.rb +17 -7
- data/lib/active_support/core_ext/range/each.rb +21 -0
- data/lib/active_support/core_ext/range/include_range.rb +20 -18
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +23 -0
- data/lib/active_support/core_ext/string/access.rb +95 -90
- data/lib/active_support/core_ext/string/behavior.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +41 -38
- data/lib/active_support/core_ext/string/exclude.rb +6 -1
- data/lib/active_support/core_ext/string/filters.rb +70 -17
- data/lib/active_support/core_ext/string/indent.rb +43 -0
- data/lib/active_support/core_ext/string/inflections.rb +139 -59
- data/lib/active_support/core_ext/string/inquiry.rb +2 -2
- data/lib/active_support/core_ext/string/multibyte.rb +46 -65
- data/lib/active_support/core_ext/string/output_safety.rb +153 -56
- data/lib/active_support/core_ext/string/strip.rb +3 -6
- data/lib/active_support/core_ext/string/zones.rb +14 -0
- data/lib/active_support/core_ext/string.rb +2 -3
- data/lib/active_support/core_ext/struct.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +173 -173
- data/lib/active_support/core_ext/time/compatibility.rb +5 -0
- data/lib/active_support/core_ext/time/conversions.rb +33 -29
- data/lib/active_support/core_ext/time/marshal.rb +2 -56
- data/lib/active_support/core_ext/time/zones.rb +57 -32
- data/lib/active_support/core_ext/time.rb +5 -0
- data/lib/active_support/core_ext/uri.rb +13 -19
- data/lib/active_support/core_ext.rb +3 -2
- data/lib/active_support/dependencies/autoload.rb +47 -20
- data/lib/active_support/dependencies/interlock.rb +51 -0
- data/lib/active_support/dependencies.rb +315 -265
- data/lib/active_support/deprecation/behaviors.rb +71 -30
- data/lib/active_support/deprecation/instance_delegator.rb +24 -0
- data/lib/active_support/deprecation/method_wrappers.rb +59 -18
- data/lib/active_support/deprecation/proxy_wrappers.rb +82 -14
- data/lib/active_support/deprecation/reporting.rb +61 -14
- data/lib/active_support/deprecation.rb +38 -13
- data/lib/active_support/descendants_tracker.rb +34 -19
- data/lib/active_support/duration/iso8601_parser.rb +122 -0
- data/lib/active_support/duration/iso8601_serializer.rb +51 -0
- data/lib/active_support/duration.rb +85 -14
- data/lib/active_support/evented_file_update_checker.rb +194 -0
- data/lib/active_support/execution_wrapper.rb +117 -0
- data/lib/active_support/executor.rb +6 -0
- data/lib/active_support/file_update_checker.rb +138 -17
- data/lib/active_support/gem_version.rb +15 -0
- data/lib/active_support/gzip.rb +11 -5
- data/lib/active_support/hash_with_indifferent_access.rb +199 -49
- data/lib/active_support/i18n.rb +6 -2
- data/lib/active_support/i18n_railtie.rb +40 -21
- data/lib/active_support/inflections.rb +22 -13
- data/lib/active_support/inflector/inflections.rb +175 -144
- data/lib/active_support/inflector/methods.rb +328 -91
- data/lib/active_support/inflector/transliterate.rb +51 -37
- data/lib/active_support/json/decoding.rb +31 -22
- data/lib/active_support/json/encoding.rb +88 -248
- data/lib/active_support/key_generator.rb +71 -0
- data/lib/active_support/lazy_load_hooks.rb +27 -25
- data/lib/active_support/locale/en.yml +102 -3
- data/lib/active_support/log_subscriber/test_helper.rb +24 -21
- data/lib/active_support/log_subscriber.rb +36 -49
- data/lib/active_support/logger.rb +106 -0
- data/lib/active_support/logger_silence.rb +28 -0
- data/lib/active_support/logger_thread_safe_level.rb +31 -0
- data/lib/active_support/message_encryptor.rb +72 -36
- data/lib/active_support/message_verifier.rb +96 -24
- data/lib/active_support/multibyte/chars.rb +88 -333
- data/lib/active_support/multibyte/unicode.rb +156 -136
- data/lib/active_support/multibyte.rb +5 -28
- data/lib/active_support/notifications/fanout.rb +115 -19
- data/lib/active_support/notifications/instrumenter.rb +52 -15
- data/lib/active_support/notifications.rb +168 -33
- data/lib/active_support/number_helper/number_converter.rb +182 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +44 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +28 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +68 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +62 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +58 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +92 -0
- data/lib/active_support/number_helper.rb +368 -0
- data/lib/active_support/option_merger.rb +1 -1
- data/lib/active_support/ordered_hash.rb +18 -183
- data/lib/active_support/ordered_options.rb +44 -24
- data/lib/active_support/per_thread_registry.rb +58 -0
- data/lib/active_support/proxy_object.rb +13 -0
- data/lib/active_support/rails.rb +27 -0
- data/lib/active_support/railtie.rb +25 -34
- data/lib/active_support/reloader.rb +129 -0
- data/lib/active_support/rescuable.rb +98 -48
- data/lib/active_support/security_utils.rb +27 -0
- data/lib/active_support/string_inquirer.rb +14 -9
- data/lib/active_support/subscriber.rb +120 -0
- data/lib/active_support/tagged_logging.rb +78 -0
- data/lib/active_support/test_case.rb +69 -17
- data/lib/active_support/testing/assertions.rb +43 -41
- data/lib/active_support/testing/autorun.rb +12 -0
- data/lib/active_support/testing/constant_lookup.rb +50 -0
- data/lib/active_support/testing/declarative.rb +7 -21
- data/lib/active_support/testing/deprecation.rb +14 -33
- data/lib/active_support/testing/file_fixtures.rb +34 -0
- data/lib/active_support/testing/isolation.rb +53 -95
- data/lib/active_support/testing/method_call_assertions.rb +41 -0
- data/lib/active_support/testing/setup_and_teardown.rb +21 -82
- data/lib/active_support/testing/stream.rb +42 -0
- data/lib/active_support/testing/tagged_logging.rb +25 -0
- data/lib/active_support/testing/time_helpers.rb +134 -0
- data/lib/active_support/time.rb +6 -23
- data/lib/active_support/time_with_zone.rb +239 -92
- data/lib/active_support/values/time_zone.rb +236 -160
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +5 -7
- data/lib/active_support/xml_mini/jdom.rb +19 -13
- data/lib/active_support/xml_mini/libxml.rb +3 -4
- data/lib/active_support/xml_mini/libxmlsax.rb +2 -3
- data/lib/active_support/xml_mini/nokogiri.rb +3 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +2 -3
- data/lib/active_support/xml_mini/rexml.rb +8 -10
- data/lib/active_support/xml_mini.rb +66 -34
- data/lib/active_support.rb +40 -23
- metadata +185 -134
- data/CHANGELOG +0 -1534
- data/lib/active_support/base64.rb +0 -42
- data/lib/active_support/basic_object.rb +0 -21
- data/lib/active_support/buffered_logger.rb +0 -137
- data/lib/active_support/cache/compressed_mem_cache_store.rb +0 -13
- data/lib/active_support/cache/synchronized_memory_store.rb +0 -11
- data/lib/active_support/core_ext/array/random_access.rb +0 -30
- data/lib/active_support/core_ext/array/uniq_by.rb +0 -16
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -44
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +0 -178
- data/lib/active_support/core_ext/date/freeze.rb +0 -31
- data/lib/active_support/core_ext/date_time/zones.rb +0 -21
- data/lib/active_support/core_ext/exception.rb +0 -3
- data/lib/active_support/core_ext/file/path.rb +0 -5
- data/lib/active_support/core_ext/float/rounding.rb +0 -19
- data/lib/active_support/core_ext/float.rb +0 -1
- data/lib/active_support/core_ext/hash/deep_dup.rb +0 -11
- data/lib/active_support/core_ext/hash/diff.rb +0 -13
- data/lib/active_support/core_ext/kernel/requires.rb +0 -28
- data/lib/active_support/core_ext/logger.rb +0 -81
- data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +0 -31
- data/lib/active_support/core_ext/module/method_names.rb +0 -14
- data/lib/active_support/core_ext/module/synchronization.rb +0 -43
- data/lib/active_support/core_ext/object/to_json.rb +0 -19
- data/lib/active_support/core_ext/proc.rb +0 -14
- data/lib/active_support/core_ext/process/daemon.rb +0 -23
- data/lib/active_support/core_ext/process.rb +0 -1
- data/lib/active_support/core_ext/range/blockless_step.rb +0 -29
- data/lib/active_support/core_ext/range/cover.rb +0 -3
- data/lib/active_support/core_ext/rexml.rb +0 -46
- data/lib/active_support/core_ext/string/encoding.rb +0 -11
- data/lib/active_support/core_ext/string/interpolation.rb +0 -2
- data/lib/active_support/core_ext/string/xchar.rb +0 -18
- data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +0 -10
- data/lib/active_support/file_watcher.rb +0 -36
- data/lib/active_support/json/variable.rb +0 -9
- data/lib/active_support/memoizable.rb +0 -105
- data/lib/active_support/multibyte/exceptions.rb +0 -8
- data/lib/active_support/multibyte/utils.rb +0 -60
- data/lib/active_support/ruby/shim.rb +0 -22
- data/lib/active_support/secure_random.rb +0 -6
- data/lib/active_support/testing/mochaing.rb +0 -7
- data/lib/active_support/testing/pending.rb +0 -52
- data/lib/active_support/testing/performance/jruby.rb +0 -115
- data/lib/active_support/testing/performance/rubinius.rb +0 -113
- data/lib/active_support/testing/performance/ruby/mri.rb +0 -57
- data/lib/active_support/testing/performance/ruby/yarv.rb +0 -57
- data/lib/active_support/testing/performance/ruby.rb +0 -152
- data/lib/active_support/testing/performance.rb +0 -317
- data/lib/active_support/time/autoload.rb +0 -5
- data/lib/active_support/whiny_nil.rb +0 -60
@@ -1,14 +1,16 @@
|
|
1
1
|
require 'active_support/xml_mini'
|
2
2
|
require 'active_support/time'
|
3
|
+
require 'active_support/core_ext/object/blank'
|
4
|
+
require 'active_support/core_ext/object/to_param'
|
5
|
+
require 'active_support/core_ext/object/to_query'
|
3
6
|
require 'active_support/core_ext/array/wrap'
|
4
7
|
require 'active_support/core_ext/hash/reverse_merge'
|
5
|
-
require 'active_support/core_ext/object/blank'
|
6
8
|
require 'active_support/core_ext/string/inflections'
|
7
9
|
|
8
10
|
class Hash
|
9
11
|
# Returns a string containing an XML representation of its receiver:
|
10
12
|
#
|
11
|
-
# {
|
13
|
+
# { foo: 1, bar: 2 }.to_xml
|
12
14
|
# # =>
|
13
15
|
# # <?xml version="1.0" encoding="UTF-8"?>
|
14
16
|
# # <hash>
|
@@ -26,22 +28,25 @@ class Hash
|
|
26
28
|
#
|
27
29
|
# * If +value+ is a callable object it must expect one or two arguments. Depending
|
28
30
|
# on the arity, the callable is invoked with the +options+ hash as first argument
|
29
|
-
# with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
|
31
|
+
# with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
|
30
32
|
# callable can add nodes by using <tt>options[:builder]</tt>.
|
31
33
|
#
|
32
|
-
#
|
34
|
+
# {foo: lambda { |options, key| options[:builder].b(key) }}.to_xml
|
33
35
|
# # => "<b>foo</b>"
|
34
36
|
#
|
35
37
|
# * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
|
36
|
-
#
|
38
|
+
#
|
37
39
|
# class Foo
|
38
40
|
# def to_xml(options)
|
39
|
-
# options[:builder].bar
|
41
|
+
# options[:builder].bar 'fooing!'
|
40
42
|
# end
|
41
43
|
# end
|
42
|
-
#
|
43
|
-
# {:
|
44
|
-
# # =>
|
44
|
+
#
|
45
|
+
# { foo: Foo.new }.to_xml(skip_instruct: true)
|
46
|
+
# # =>
|
47
|
+
# # <hash>
|
48
|
+
# # <bar>fooing!</bar>
|
49
|
+
# # </hash>
|
45
50
|
#
|
46
51
|
# * Otherwise, a node with +key+ as tag is created with a string representation of
|
47
52
|
# +value+ as text node. If +value+ is +nil+ an attribute "nil" set to "true" is added.
|
@@ -50,15 +55,14 @@ class Hash
|
|
50
55
|
#
|
51
56
|
# XML_TYPE_NAMES = {
|
52
57
|
# "Symbol" => "symbol",
|
53
|
-
# "
|
54
|
-
# "Bignum" => "integer",
|
58
|
+
# "Integer" => "integer",
|
55
59
|
# "BigDecimal" => "decimal",
|
56
60
|
# "Float" => "float",
|
57
61
|
# "TrueClass" => "boolean",
|
58
62
|
# "FalseClass" => "boolean",
|
59
63
|
# "Date" => "date",
|
60
|
-
# "DateTime" => "
|
61
|
-
# "Time" => "
|
64
|
+
# "DateTime" => "dateTime",
|
65
|
+
# "Time" => "dateTime"
|
62
66
|
# }
|
63
67
|
#
|
64
68
|
# By default the root node is "hash", but that's configurable via the <tt>:root</tt> option.
|
@@ -71,87 +75,188 @@ class Hash
|
|
71
75
|
|
72
76
|
options = options.dup
|
73
77
|
options[:indent] ||= 2
|
74
|
-
options[:root] ||=
|
75
|
-
options[:builder] ||= Builder::XmlMarkup.new(:
|
78
|
+
options[:root] ||= 'hash'
|
79
|
+
options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
|
76
80
|
|
77
81
|
builder = options[:builder]
|
78
82
|
builder.instruct! unless options.delete(:skip_instruct)
|
79
83
|
|
80
84
|
root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
|
81
85
|
|
82
|
-
builder.
|
86
|
+
builder.tag!(root) do
|
83
87
|
each { |key, value| ActiveSupport::XmlMini.to_tag(key, value, options) }
|
84
88
|
yield builder if block_given?
|
85
89
|
end
|
86
90
|
end
|
87
91
|
|
88
92
|
class << self
|
89
|
-
|
90
|
-
|
93
|
+
# Returns a Hash containing a collection of pairs when the key is the node name and the value is
|
94
|
+
# its content
|
95
|
+
#
|
96
|
+
# xml = <<-XML
|
97
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
98
|
+
# <hash>
|
99
|
+
# <foo type="integer">1</foo>
|
100
|
+
# <bar type="integer">2</bar>
|
101
|
+
# </hash>
|
102
|
+
# XML
|
103
|
+
#
|
104
|
+
# hash = Hash.from_xml(xml)
|
105
|
+
# # => {"hash"=>{"foo"=>1, "bar"=>2}}
|
106
|
+
#
|
107
|
+
# +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
|
109
|
+
# parse this XML.
|
110
|
+
#
|
111
|
+
# Custom +disallowed_types+ can also be passed in the form of an
|
112
|
+
# array.
|
113
|
+
#
|
114
|
+
# xml = <<-XML
|
115
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
116
|
+
# <hash>
|
117
|
+
# <foo type="integer">1</foo>
|
118
|
+
# <bar type="string">"David"</bar>
|
119
|
+
# </hash>
|
120
|
+
# XML
|
121
|
+
#
|
122
|
+
# hash = Hash.from_xml(xml, ['integer'])
|
123
|
+
# # => ActiveSupport::XMLConverter::DisallowedType: Disallowed type attribute: "integer"
|
124
|
+
#
|
125
|
+
# Note that passing custom disallowed types will override the default types,
|
126
|
+
# which are Symbol and YAML.
|
127
|
+
def from_xml(xml, disallowed_types = nil)
|
128
|
+
ActiveSupport::XMLConverter.new(xml, disallowed_types).to_h
|
129
|
+
end
|
130
|
+
|
131
|
+
# Builds a Hash from XML just like <tt>Hash.from_xml</tt>, but also allows Symbol and YAML.
|
132
|
+
def from_trusted_xml(xml)
|
133
|
+
from_xml xml, []
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
module ActiveSupport
|
139
|
+
class XMLConverter # :nodoc:
|
140
|
+
# Raised if the XML contains attributes with type="yaml" or
|
141
|
+
# type="symbol". Read Hash#from_xml for more details.
|
142
|
+
class DisallowedType < StandardError
|
143
|
+
def initialize(type)
|
144
|
+
super "Disallowed type attribute: #{type.inspect}"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
DISALLOWED_TYPES = %w(symbol yaml)
|
149
|
+
|
150
|
+
def initialize(xml, disallowed_types = nil)
|
151
|
+
@xml = normalize_keys(XmlMini.parse(xml))
|
152
|
+
@disallowed_types = disallowed_types || DISALLOWED_TYPES
|
153
|
+
end
|
154
|
+
|
155
|
+
def to_h
|
156
|
+
deep_to_h(@xml)
|
91
157
|
end
|
92
158
|
|
93
159
|
private
|
94
|
-
def
|
95
|
-
case
|
96
|
-
when
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
entries.collect { |v| typecast_xml_value(v) }
|
105
|
-
when "Hash"
|
106
|
-
[typecast_xml_value(entries)]
|
107
|
-
else
|
108
|
-
raise "can't typecast #{entries.inspect}"
|
109
|
-
end
|
110
|
-
end
|
111
|
-
elsif value['type'] == 'file' ||
|
112
|
-
(value["__content__"] && (value.keys.size == 1 || value["__content__"].present?))
|
113
|
-
content = value["__content__"]
|
114
|
-
if parser = ActiveSupport::XmlMini::PARSING[value["type"]]
|
115
|
-
parser.arity == 1 ? parser.call(content) : parser.call(content, value)
|
116
|
-
else
|
117
|
-
content
|
118
|
-
end
|
119
|
-
elsif value['type'] == 'string' && value['nil'] != 'true'
|
120
|
-
""
|
121
|
-
# blank or nil parsed values are represented by nil
|
122
|
-
elsif value.blank? || value['nil'] == 'true'
|
123
|
-
nil
|
124
|
-
# If the type is the only element which makes it then
|
125
|
-
# this still makes the value nil, except if type is
|
126
|
-
# a XML node(where type['value'] is a Hash)
|
127
|
-
elsif value['type'] && value.size == 1 && !value['type'].is_a?(::Hash)
|
128
|
-
nil
|
129
|
-
else
|
130
|
-
xml_value = Hash[value.map { |k,v| [k, typecast_xml_value(v)] }]
|
160
|
+
def normalize_keys(params)
|
161
|
+
case params
|
162
|
+
when Hash
|
163
|
+
Hash[params.map { |k,v| [k.to_s.tr('-', '_'), normalize_keys(v)] } ]
|
164
|
+
when Array
|
165
|
+
params.map { |v| normalize_keys(v) }
|
166
|
+
else
|
167
|
+
params
|
168
|
+
end
|
169
|
+
end
|
131
170
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
when
|
137
|
-
value
|
138
|
-
|
139
|
-
when 'String'
|
171
|
+
def deep_to_h(value)
|
172
|
+
case value
|
173
|
+
when Hash
|
174
|
+
process_hash(value)
|
175
|
+
when Array
|
176
|
+
process_array(value)
|
177
|
+
when String
|
140
178
|
value
|
141
179
|
else
|
142
180
|
raise "can't typecast #{value.class.name} - #{value.inspect}"
|
143
181
|
end
|
144
182
|
end
|
145
183
|
|
146
|
-
def
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
184
|
+
def process_hash(value)
|
185
|
+
if value.include?('type') && !value['type'].is_a?(Hash) && @disallowed_types.include?(value['type'])
|
186
|
+
raise DisallowedType, value['type']
|
187
|
+
end
|
188
|
+
|
189
|
+
if become_array?(value)
|
190
|
+
_, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) })
|
191
|
+
if entries.nil? || value['__content__'].try(:empty?)
|
192
|
+
[]
|
152
193
|
else
|
153
|
-
|
194
|
+
case entries
|
195
|
+
when Array
|
196
|
+
entries.collect { |v| deep_to_h(v) }
|
197
|
+
when Hash
|
198
|
+
[deep_to_h(entries)]
|
199
|
+
else
|
200
|
+
raise "can't typecast #{entries.inspect}"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
elsif become_content?(value)
|
204
|
+
process_content(value)
|
205
|
+
|
206
|
+
elsif become_empty_string?(value)
|
207
|
+
''
|
208
|
+
elsif become_hash?(value)
|
209
|
+
xml_value = Hash[value.map { |k,v| [k, deep_to_h(v)] }]
|
210
|
+
|
211
|
+
# Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
|
212
|
+
# how multipart uploaded files from HTML appear
|
213
|
+
xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value
|
154
214
|
end
|
155
215
|
end
|
216
|
+
|
217
|
+
def become_content?(value)
|
218
|
+
value['type'] == 'file' || (value['__content__'] && (value.keys.size == 1 || value['__content__'].present?))
|
219
|
+
end
|
220
|
+
|
221
|
+
def become_array?(value)
|
222
|
+
value['type'] == 'array'
|
223
|
+
end
|
224
|
+
|
225
|
+
def become_empty_string?(value)
|
226
|
+
# { "string" => true }
|
227
|
+
# No tests fail when the second term is removed.
|
228
|
+
value['type'] == 'string' && value['nil'] != 'true'
|
229
|
+
end
|
230
|
+
|
231
|
+
def become_hash?(value)
|
232
|
+
!nothing?(value) && !garbage?(value)
|
233
|
+
end
|
234
|
+
|
235
|
+
def nothing?(value)
|
236
|
+
# blank or nil parsed values are represented by nil
|
237
|
+
value.blank? || value['nil'] == 'true'
|
238
|
+
end
|
239
|
+
|
240
|
+
def garbage?(value)
|
241
|
+
# If the type is the only element which makes it then
|
242
|
+
# this still makes the value nil, except if type is
|
243
|
+
# an XML node(where type['value'] is a Hash)
|
244
|
+
value['type'] && !value['type'].is_a?(::Hash) && value.size == 1
|
245
|
+
end
|
246
|
+
|
247
|
+
def process_content(value)
|
248
|
+
content = value['__content__']
|
249
|
+
if parser = ActiveSupport::XmlMini::PARSING[value['type']]
|
250
|
+
parser.arity == 1 ? parser.call(content) : parser.call(content, value)
|
251
|
+
else
|
252
|
+
content
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def process_array(value)
|
257
|
+
value.map! { |i| deep_to_h(i) }
|
258
|
+
value.length > 1 ? value : value.first
|
259
|
+
end
|
260
|
+
|
156
261
|
end
|
157
262
|
end
|
@@ -1,16 +1,38 @@
|
|
1
1
|
class Hash
|
2
2
|
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
3
|
-
|
4
|
-
|
3
|
+
#
|
4
|
+
# h1 = { a: true, b: { c: [1, 2, 3] } }
|
5
|
+
# h2 = { a: false, b: { x: [3, 4, 5] } }
|
6
|
+
#
|
7
|
+
# h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
|
8
|
+
#
|
9
|
+
# Like with Hash#merge in the standard library, a block can be provided
|
10
|
+
# to merge values:
|
11
|
+
#
|
12
|
+
# h1 = { a: 100, b: 200, c: { c1: 100 } }
|
13
|
+
# h2 = { b: 250, c: { c1: 200 } }
|
14
|
+
# h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
|
15
|
+
# # => { a: 100, b: 450, c: { c1: 300 } }
|
16
|
+
def deep_merge(other_hash, &block)
|
17
|
+
dup.deep_merge!(other_hash, &block)
|
5
18
|
end
|
6
19
|
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
self[
|
20
|
+
# Same as +deep_merge+, but modifies +self+.
|
21
|
+
def deep_merge!(other_hash, &block)
|
22
|
+
other_hash.each_pair do |current_key, other_value|
|
23
|
+
this_value = self[current_key]
|
24
|
+
|
25
|
+
self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash)
|
26
|
+
this_value.deep_merge(other_value, &block)
|
27
|
+
else
|
28
|
+
if block_given? && key?(current_key)
|
29
|
+
block.call(current_key, this_value, other_value)
|
30
|
+
else
|
31
|
+
other_value
|
32
|
+
end
|
33
|
+
end
|
13
34
|
end
|
35
|
+
|
14
36
|
self
|
15
37
|
end
|
16
38
|
end
|
@@ -1,21 +1,20 @@
|
|
1
1
|
class Hash
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# If the receiver responds to +convert_key+, the method is called on each of the
|
8
|
-
# arguments. This allows +except+ to play nice with hashes with indifferent access
|
9
|
-
# for instance:
|
10
|
-
#
|
11
|
-
# {:a => 1}.with_indifferent_access.except(:a) # => {}
|
12
|
-
# {:a => 1}.with_indifferent_access.except("a") # => {}
|
2
|
+
# Returns a hash that includes everything except given keys.
|
3
|
+
# hash = { a: true, b: false, c: nil }
|
4
|
+
# hash.except(:c) # => { a: true, b: false }
|
5
|
+
# hash.except(:a, :b) # => { c: nil }
|
6
|
+
# hash # => { a: true, b: false, c: nil }
|
13
7
|
#
|
8
|
+
# This is useful for limiting a set of parameters to everything but a few known toggles:
|
9
|
+
# @person.update(params[:person].except(:admin))
|
14
10
|
def except(*keys)
|
15
11
|
dup.except!(*keys)
|
16
12
|
end
|
17
13
|
|
18
|
-
#
|
14
|
+
# Removes the given keys from hash and returns it.
|
15
|
+
# hash = { a: true, b: false, c: nil }
|
16
|
+
# hash.except!(:c) # => { a: true, b: false }
|
17
|
+
# hash # => { a: true, b: false }
|
19
18
|
def except!(*keys)
|
20
19
|
keys.each { |key| delete(key) }
|
21
20
|
self
|
@@ -2,23 +2,22 @@ require 'active_support/hash_with_indifferent_access'
|
|
2
2
|
|
3
3
|
class Hash
|
4
4
|
|
5
|
-
# Returns an
|
6
|
-
#
|
7
|
-
# {:a => 1}.with_indifferent_access["a"] # => 1
|
5
|
+
# Returns an <tt>ActiveSupport::HashWithIndifferentAccess</tt> out of its receiver:
|
8
6
|
#
|
7
|
+
# { a: 1 }.with_indifferent_access['a'] # => 1
|
9
8
|
def with_indifferent_access
|
10
|
-
ActiveSupport::HashWithIndifferentAccess.
|
9
|
+
ActiveSupport::HashWithIndifferentAccess.new(self)
|
11
10
|
end
|
12
11
|
|
13
12
|
# Called when object is nested under an object that receives
|
14
13
|
# #with_indifferent_access. This method will be called on the current object
|
15
14
|
# by the enclosing object and is aliased to #with_indifferent_access by
|
16
15
|
# default. Subclasses of Hash may overwrite this method to return +self+ if
|
17
|
-
# converting to an
|
16
|
+
# converting to an <tt>ActiveSupport::HashWithIndifferentAccess</tt> would not be
|
18
17
|
# desirable.
|
19
18
|
#
|
20
|
-
# b = {:
|
21
|
-
# {:
|
22
|
-
#
|
19
|
+
# b = { b: 1 }
|
20
|
+
# { a: b }.with_indifferent_access['a'] # calls b.nested_under_indifferent_access
|
21
|
+
# # => {"b"=>1}
|
23
22
|
alias nested_under_indifferent_access with_indifferent_access
|
24
23
|
end
|
@@ -1,47 +1,170 @@
|
|
1
1
|
class Hash
|
2
|
-
#
|
3
|
-
|
4
|
-
|
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
|
5
19
|
end
|
6
20
|
|
7
|
-
# Destructively
|
8
|
-
|
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?
|
9
25
|
keys.each do |key|
|
10
|
-
self[key
|
26
|
+
self[yield(key)] = delete(key)
|
11
27
|
end
|
12
28
|
self
|
13
29
|
end
|
14
30
|
|
15
|
-
#
|
31
|
+
# Returns a new hash with all keys converted to strings.
|
32
|
+
#
|
33
|
+
# hash = { name: 'Rob', age: '28' }
|
34
|
+
#
|
35
|
+
# hash.stringify_keys
|
36
|
+
# # => {"name"=>"Rob", "age"=>"28"}
|
37
|
+
def stringify_keys
|
38
|
+
transform_keys(&:to_s)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Destructively converts all keys to strings. Same as
|
42
|
+
# +stringify_keys+, but modifies +self+.
|
43
|
+
def stringify_keys!
|
44
|
+
transform_keys!(&:to_s)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns a new hash with all keys converted to symbols, as long as
|
16
48
|
# they respond to +to_sym+.
|
49
|
+
#
|
50
|
+
# hash = { 'name' => 'Rob', 'age' => '28' }
|
51
|
+
#
|
52
|
+
# hash.symbolize_keys
|
53
|
+
# # => {:name=>"Rob", :age=>"28"}
|
17
54
|
def symbolize_keys
|
18
|
-
|
55
|
+
transform_keys{ |key| key.to_sym rescue key }
|
19
56
|
end
|
57
|
+
alias_method :to_options, :symbolize_keys
|
20
58
|
|
21
|
-
# Destructively
|
22
|
-
# to +to_sym+.
|
59
|
+
# Destructively converts all keys to symbols, as long as they respond
|
60
|
+
# to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
|
23
61
|
def symbolize_keys!
|
24
|
-
|
25
|
-
self[(key.to_sym rescue key) || key] = delete(key)
|
26
|
-
end
|
27
|
-
self
|
62
|
+
transform_keys!{ |key| key.to_sym rescue key }
|
28
63
|
end
|
29
|
-
|
30
|
-
alias_method :to_options, :symbolize_keys
|
31
64
|
alias_method :to_options!, :symbolize_keys!
|
32
65
|
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# as keys, this will fail.
|
66
|
+
# Validates all keys in a hash match <tt>*valid_keys</tt>, raising
|
67
|
+
# +ArgumentError+ on a mismatch.
|
36
68
|
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
# { :
|
69
|
+
# Note that keys are treated differently than HashWithIndifferentAccess,
|
70
|
+
# meaning that string and symbol keys will not match.
|
71
|
+
#
|
72
|
+
# { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: :years. Valid keys are: :name, :age"
|
73
|
+
# { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: :name. Valid keys are: 'name', 'age'"
|
74
|
+
# { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
|
41
75
|
def assert_valid_keys(*valid_keys)
|
42
76
|
valid_keys.flatten!
|
43
77
|
each_key do |k|
|
44
|
-
|
78
|
+
unless valid_keys.include?(k)
|
79
|
+
raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}")
|
80
|
+
end
|
45
81
|
end
|
46
82
|
end
|
83
|
+
|
84
|
+
# Returns a new hash with all keys converted by the block operation.
|
85
|
+
# This includes the keys from the root hash and from all
|
86
|
+
# nested hashes and arrays.
|
87
|
+
#
|
88
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
89
|
+
#
|
90
|
+
# hash.deep_transform_keys{ |key| key.to_s.upcase }
|
91
|
+
# # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
|
92
|
+
def deep_transform_keys(&block)
|
93
|
+
_deep_transform_keys_in_object(self, &block)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Destructively converts all keys by using the block operation.
|
97
|
+
# This includes the keys from the root hash and from all
|
98
|
+
# nested hashes and arrays.
|
99
|
+
def deep_transform_keys!(&block)
|
100
|
+
_deep_transform_keys_in_object!(self, &block)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns a new hash with all keys converted to strings.
|
104
|
+
# This includes the keys from the root hash and from all
|
105
|
+
# nested hashes and arrays.
|
106
|
+
#
|
107
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
108
|
+
#
|
109
|
+
# hash.deep_stringify_keys
|
110
|
+
# # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
|
111
|
+
def deep_stringify_keys
|
112
|
+
deep_transform_keys(&:to_s)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Destructively converts all keys to strings.
|
116
|
+
# This includes the keys from the root hash and from all
|
117
|
+
# nested hashes and arrays.
|
118
|
+
def deep_stringify_keys!
|
119
|
+
deep_transform_keys!(&:to_s)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Returns a new hash with all keys converted to symbols, as long as
|
123
|
+
# they respond to +to_sym+. This includes the keys from the root hash
|
124
|
+
# and from all nested hashes and arrays.
|
125
|
+
#
|
126
|
+
# hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
|
127
|
+
#
|
128
|
+
# hash.deep_symbolize_keys
|
129
|
+
# # => {:person=>{:name=>"Rob", :age=>"28"}}
|
130
|
+
def deep_symbolize_keys
|
131
|
+
deep_transform_keys{ |key| key.to_sym rescue key }
|
132
|
+
end
|
133
|
+
|
134
|
+
# Destructively converts all keys to symbols, as long as they respond
|
135
|
+
# to +to_sym+. This includes the keys from the root hash and from all
|
136
|
+
# nested hashes and arrays.
|
137
|
+
def deep_symbolize_keys!
|
138
|
+
deep_transform_keys!{ |key| key.to_sym rescue key }
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
# support methods for deep transforming nested hashes and arrays
|
143
|
+
def _deep_transform_keys_in_object(object, &block)
|
144
|
+
case object
|
145
|
+
when Hash
|
146
|
+
object.each_with_object({}) do |(key, value), result|
|
147
|
+
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
|
148
|
+
end
|
149
|
+
when Array
|
150
|
+
object.map {|e| _deep_transform_keys_in_object(e, &block) }
|
151
|
+
else
|
152
|
+
object
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def _deep_transform_keys_in_object!(object, &block)
|
157
|
+
case object
|
158
|
+
when Hash
|
159
|
+
object.keys.each do |key|
|
160
|
+
value = object.delete(key)
|
161
|
+
object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
|
162
|
+
end
|
163
|
+
object
|
164
|
+
when Array
|
165
|
+
object.map! {|e| _deep_transform_keys_in_object!(e, &block)}
|
166
|
+
else
|
167
|
+
object
|
168
|
+
end
|
169
|
+
end
|
47
170
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
class Hash
|
2
2
|
# Merges the caller into +other_hash+. For example,
|
3
3
|
#
|
4
|
-
# options = options.reverse_merge(:
|
4
|
+
# options = options.reverse_merge(size: 25, velocity: 10)
|
5
5
|
#
|
6
6
|
# is equivalent to
|
7
7
|
#
|
8
|
-
# options = {:
|
8
|
+
# options = { size: 25, velocity: 10 }.merge(options)
|
9
9
|
#
|
10
10
|
# This is particularly useful for initializing an options hash
|
11
11
|
# with default values.
|
@@ -18,6 +18,5 @@ class Hash
|
|
18
18
|
# right wins if there is no left
|
19
19
|
merge!( other_hash ){|key,left,right| left }
|
20
20
|
end
|
21
|
-
|
22
21
|
alias_method :reverse_update, :reverse_merge!
|
23
22
|
end
|