aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/core_ext/hash
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support/core_ext/hash')
-rw-r--r--activesupport/lib/active_support/core_ext/hash/conversions.rb48
-rw-r--r--activesupport/lib/active_support/core_ext/hash/deep_dup.rb11
-rw-r--r--activesupport/lib/active_support/core_ext/hash/indifferent_access.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/hash/keys.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/hash/reverse_merge.rb23
5 files changed, 54 insertions, 42 deletions
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb
index 2763af6121..3005fef44c 100644
--- a/activesupport/lib/active_support/core_ext/hash/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -7,7 +7,7 @@ require 'active_support/core_ext/string/inflections'
class Hash
# Returns a string containing an XML representation of its receiver:
- #
+ #
# {"foo" => 1, "bar" => 2}.to_xml
# # =>
# # <?xml version="1.0" encoding="UTF-8"?>
@@ -15,22 +15,34 @@ class Hash
# # <foo type="integer">1</foo>
# # <bar type="integer">2</bar>
# # </hash>
- #
+ #
# To do so, the method loops over the pairs and builds nodes that depend on
# the _values_. Given a pair +key+, +value+:
- #
+ #
# * If +value+ is a hash there's a recursive call with +key+ as <tt>:root</tt>.
- #
+ #
# * If +value+ is an array there's a recursive call with +key+ as <tt>:root</tt>,
# and +key+ singularized as <tt>:children</tt>.
- #
+ #
# * If +value+ is a callable object it must expect one or two arguments. Depending
# on the arity, the callable is invoked with the +options+ hash as first argument
- # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. Its
- # return value becomes a new node.
- #
+ # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
+ # callable can add nodes by using <tt>options[:builder]</tt>.
+ #
+ # "foo".to_xml(lambda { |options, key| options[:builder].b(key) })
+ # # => "<b>foo</b>"
+ #
# * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
- #
+ #
+ # class Foo
+ # def to_xml(options)
+ # options[:builder].bar "fooing!"
+ # end
+ # end
+ #
+ # {:foo => Foo.new}.to_xml(:skip_instruct => true)
+ # # => "<hash><bar>fooing!</bar></hash>"
+ #
# * Otherwise, a node with +key+ as tag is created with a string representation of
# +value+ as text node. If +value+ is +nil+ an attribute "nil" set to "true" is added.
# Unless the option <tt>:skip_types</tt> exists and is true, an attribute "type" is
@@ -48,9 +60,9 @@ class Hash
# "DateTime" => "datetime",
# "Time" => "datetime"
# }
- #
+ #
# By default the root node is "hash", but that's configurable via the <tt>:root</tt> option.
- #
+ #
# The default XML builder is a fresh instance of <tt>Builder::XmlMarkup</tt>. You can
# configure your own builder with the <tt>:builder</tt> option. The method also accepts
# options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
@@ -108,17 +120,14 @@ class Hash
# blank or nil parsed values are represented by nil
elsif value.blank? || value['nil'] == 'true'
nil
- # If the type is the only element which makes it then
+ # If the type is the only element which makes it then
# this still makes the value nil, except if type is
# a XML node(where type['value'] is a Hash)
elsif value['type'] && value.size == 1 && !value['type'].is_a?(::Hash)
nil
else
- xml_value = value.inject({}) do |h,(k,v)|
- h[k] = typecast_xml_value(v)
- h
- end
-
+ xml_value = Hash[value.map { |k,v| [k, typecast_xml_value(v)] }]
+
# Turn { :files => { :file => #<StringIO> } into { :files => #<StringIO> } so it is compatible with
# how multipart uploaded files from HTML appear
xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
@@ -136,10 +145,7 @@ class Hash
def unrename_keys(params)
case params.class.to_s
when "Hash"
- params.inject({}) do |h,(k,v)|
- h[k.to_s.tr("-", "_")] = unrename_keys(v)
- h
- end
+ Hash[params.map { |k,v| [k.to_s.tr("-", "_"), unrename_keys(v)] } ]
when "Array"
params.map { |v| unrename_keys(v) }
else
diff --git a/activesupport/lib/active_support/core_ext/hash/deep_dup.rb b/activesupport/lib/active_support/core_ext/hash/deep_dup.rb
new file mode 100644
index 0000000000..447142605c
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/hash/deep_dup.rb
@@ -0,0 +1,11 @@
+class Hash
+ # Returns a deep copy of hash.
+ def deep_dup
+ duplicate = self.dup
+ duplicate.each_pair do |k,v|
+ tv = duplicate[k]
+ duplicate[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_dup : v
+ end
+ duplicate
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
index 0420e206af..aad4b61e16 100644
--- a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
+++ b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
@@ -7,8 +7,6 @@ class Hash
# {:a => 1}.with_indifferent_access["a"] # => 1
#
def with_indifferent_access
- hash = ActiveSupport::HashWithIndifferentAccess.new(self)
- hash.default = self.default
- hash
+ ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default(self)
end
end
diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb
index 045a6944fa..d8748b1138 100644
--- a/activesupport/lib/active_support/core_ext/hash/keys.rb
+++ b/activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -35,11 +35,13 @@ class Hash
# as keys, this will fail.
#
# ==== Examples
- # { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key(s): years"
- # { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key(s): name, age"
+ # { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
+ # { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key: name"
# { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
def assert_valid_keys(*valid_keys)
- unknown_keys = keys - [valid_keys].flatten
- raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
+ valid_keys.flatten!
+ each_key do |k|
+ raise(ArgumentError, "Unknown key: #{k}") unless valid_keys.include?(k)
+ end
end
end
diff --git a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
index d7ebd5feef..01863a162b 100644
--- a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
+++ b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
@@ -1,27 +1,22 @@
class Hash
- # Allows for reverse merging two hashes where the keys in the calling hash take precedence over those
- # in the <tt>other_hash</tt>. This is particularly useful for initializing an option hash with default values:
+ # Merges the caller into +other_hash+. For example,
#
- # def setup(options = {})
- # options.reverse_merge! :size => 25, :velocity => 10
- # end
+ # options = options.reverse_merge(:size => 25, :velocity => 10)
#
- # Using <tt>merge</tt>, the above example would look as follows:
+ # is equivalent to
#
- # def setup(options = {})
- # { :size => 25, :velocity => 10 }.merge(options)
- # end
+ # options = {:size => 25, :velocity => 10}.merge(options)
#
- # The default <tt>:size</tt> and <tt>:velocity</tt> are only set if the +options+ hash passed in doesn't already
- # have the respective key.
+ # This is particularly useful for initializing an options hash
+ # with default values.
def reverse_merge(other_hash)
other_hash.merge(self)
end
- # Performs the opposite of <tt>merge</tt>, with the keys and values from the first hash taking precedence over the second.
- # Modifies the receiver in place.
+ # Destructive +reverse_merge+.
def reverse_merge!(other_hash)
- merge!( other_hash ){|k,o,n| o }
+ # right wins if there is no left
+ merge!( other_hash ){|key,left,right| left }
end
alias_method :reverse_update, :reverse_merge!