mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Convert hash extension modules to class reopens
This commit is contained in:
@@ -1,2 +1,10 @@
|
||||
require 'active_support/core_ext/hash/deep_merge'
|
||||
require 'active_support/core_ext/hash/diff'
|
||||
require 'active_support/core_ext/hash/except'
|
||||
require 'active_support/core_ext/hash/indifferent_access'
|
||||
require 'active_support/core_ext/hash/keys'
|
||||
require 'active_support/core_ext/hash/reverse_merge'
|
||||
require 'active_support/core_ext/hash/slice'
|
||||
|
||||
require 'active_support/core_ext/util'
|
||||
ActiveSupport.core_ext Hash, %w(keys indifferent_access deep_merge reverse_merge conversions diff slice except)
|
||||
ActiveSupport.core_ext Hash, %w(conversions)
|
||||
|
||||
@@ -1,23 +1,16 @@
|
||||
module ActiveSupport #:nodoc:
|
||||
module CoreExtensions #:nodoc:
|
||||
module Hash #:nodoc:
|
||||
# Allows for deep merging
|
||||
module DeepMerge
|
||||
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
||||
def deep_merge(other_hash)
|
||||
self.merge(other_hash) do |key, oldval, newval|
|
||||
oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
|
||||
newval = newval.to_hash if newval.respond_to?(:to_hash)
|
||||
oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? oldval.deep_merge(newval) : newval
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
||||
# Modifies the receiver in place.
|
||||
def deep_merge!(other_hash)
|
||||
replace(deep_merge(other_hash))
|
||||
end
|
||||
end
|
||||
class Hash
|
||||
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
||||
def deep_merge(other_hash)
|
||||
merge(other_hash) do |key, oldval, newval|
|
||||
oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
|
||||
newval = newval.to_hash if newval.respond_to?(:to_hash)
|
||||
oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? oldval.deep_merge(newval) : newval
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
||||
# Modifies the receiver in place.
|
||||
def deep_merge!(other_hash)
|
||||
replace(deep_merge(other_hash))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
module ActiveSupport #:nodoc:
|
||||
module CoreExtensions #:nodoc:
|
||||
module Hash #:nodoc:
|
||||
module Diff
|
||||
# Returns a hash that represents the difference between two hashes.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# {1 => 2}.diff(1 => 2) # => {}
|
||||
# {1 => 2}.diff(1 => 3) # => {1 => 2}
|
||||
# {}.diff(1 => 2) # => {1 => 2}
|
||||
# {1 => 2, 3 => 4}.diff(1 => 2) # => {3 => 4}
|
||||
def diff(h2)
|
||||
self.dup.delete_if { |k, v| h2[k] == v }.merge(h2.dup.delete_if { |k, v| self.has_key?(k) })
|
||||
end
|
||||
end
|
||||
end
|
||||
class Hash
|
||||
# Returns a hash that represents the difference between two hashes.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# {1 => 2}.diff(1 => 2) # => {}
|
||||
# {1 => 2}.diff(1 => 3) # => {1 => 2}
|
||||
# {}.diff(1 => 2) # => {1 => 2}
|
||||
# {1 => 2, 3 => 4}.diff(1 => 2) # => {3 => 4}
|
||||
def diff(h2)
|
||||
dup.delete_if { |k, v| h2[k] == v }.merge(h2.dup.delete_if { |k, v| has_key?(k) })
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,25 +1,16 @@
|
||||
require 'set'
|
||||
class Hash
|
||||
# Return a hash that includes everything but the given keys. This is useful for
|
||||
# limiting a set of parameters to everything but a few known toggles:
|
||||
#
|
||||
# @person.update_attributes(params[:person].except(:admin))
|
||||
def except(*keys)
|
||||
dup.except!(*keys)
|
||||
end
|
||||
|
||||
module ActiveSupport #:nodoc:
|
||||
module CoreExtensions #:nodoc:
|
||||
module Hash #:nodoc:
|
||||
# Return a hash that includes everything but the given keys. This is useful for
|
||||
# limiting a set of parameters to everything but a few known toggles:
|
||||
#
|
||||
# @person.update_attributes(params[:person].except(:admin))
|
||||
module Except
|
||||
# Returns a new hash without the given keys.
|
||||
def except(*keys)
|
||||
dup.except!(*keys)
|
||||
end
|
||||
|
||||
# Replaces the hash without the given keys.
|
||||
def except!(*keys)
|
||||
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
||||
keys.each { |key| delete(key) }
|
||||
self
|
||||
end
|
||||
end
|
||||
end
|
||||
# Replaces the hash without the given keys.
|
||||
def except!(*keys)
|
||||
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
||||
keys.each { |key| delete(key) }
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,143 +1,9 @@
|
||||
# This class has dubious semantics and we only have it so that
|
||||
# people can write params[:key] instead of params['key']
|
||||
# and they get the same value for both keys.
|
||||
require 'active_support/hash_with_indifferent_access'
|
||||
|
||||
class HashWithIndifferentAccess < Hash
|
||||
def initialize(constructor = {})
|
||||
if constructor.is_a?(Hash)
|
||||
super()
|
||||
update(constructor)
|
||||
else
|
||||
super(constructor)
|
||||
end
|
||||
end
|
||||
|
||||
def default(key = nil)
|
||||
if key.is_a?(Symbol) && include?(key = key.to_s)
|
||||
self[key]
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
||||
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
||||
|
||||
# Assigns a new value to the hash:
|
||||
#
|
||||
# hash = HashWithIndifferentAccess.new
|
||||
# hash[:key] = "value"
|
||||
#
|
||||
def []=(key, value)
|
||||
regular_writer(convert_key(key), convert_value(value))
|
||||
end
|
||||
|
||||
# Updates the instantized hash with values from the second:
|
||||
#
|
||||
# hash_1 = HashWithIndifferentAccess.new
|
||||
# hash_1[:key] = "value"
|
||||
#
|
||||
# hash_2 = HashWithIndifferentAccess.new
|
||||
# hash_2[:key] = "New Value!"
|
||||
#
|
||||
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
|
||||
#
|
||||
def update(other_hash)
|
||||
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
|
||||
self
|
||||
end
|
||||
|
||||
alias_method :merge!, :update
|
||||
|
||||
# Checks the hash for a key matching the argument passed in:
|
||||
#
|
||||
# hash = HashWithIndifferentAccess.new
|
||||
# hash["key"] = "value"
|
||||
# hash.key? :key # => true
|
||||
# hash.key? "key" # => true
|
||||
#
|
||||
def key?(key)
|
||||
super(convert_key(key))
|
||||
end
|
||||
|
||||
alias_method :include?, :key?
|
||||
alias_method :has_key?, :key?
|
||||
alias_method :member?, :key?
|
||||
|
||||
# Fetches the value for the specified key, same as doing hash[key]
|
||||
def fetch(key, *extras)
|
||||
super(convert_key(key), *extras)
|
||||
end
|
||||
|
||||
# Returns an array of the values at the specified indices:
|
||||
#
|
||||
# hash = HashWithIndifferentAccess.new
|
||||
# hash[:a] = "x"
|
||||
# hash[:b] = "y"
|
||||
# hash.values_at("a", "b") # => ["x", "y"]
|
||||
#
|
||||
def values_at(*indices)
|
||||
indices.collect {|key| self[convert_key(key)]}
|
||||
end
|
||||
|
||||
# Returns an exact copy of the hash.
|
||||
def dup
|
||||
HashWithIndifferentAccess.new(self)
|
||||
end
|
||||
|
||||
# Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
|
||||
# Does not overwrite the existing hash.
|
||||
def merge(hash)
|
||||
self.dup.update(hash)
|
||||
end
|
||||
|
||||
# Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
|
||||
# This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
|
||||
def reverse_merge(other_hash)
|
||||
super other_hash.with_indifferent_access
|
||||
end
|
||||
|
||||
# Removes a specified key from the hash.
|
||||
def delete(key)
|
||||
super(convert_key(key))
|
||||
end
|
||||
|
||||
def stringify_keys!; self end
|
||||
def symbolize_keys!; self end
|
||||
def to_options!; self end
|
||||
|
||||
# Convert to a Hash with String keys.
|
||||
def to_hash
|
||||
Hash.new(default).merge(self)
|
||||
end
|
||||
|
||||
protected
|
||||
def convert_key(key)
|
||||
key.kind_of?(Symbol) ? key.to_s : key
|
||||
end
|
||||
|
||||
def convert_value(value)
|
||||
case value
|
||||
when Hash
|
||||
value.with_indifferent_access
|
||||
when Array
|
||||
value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ActiveSupport #:nodoc:
|
||||
module CoreExtensions #:nodoc:
|
||||
module Hash #:nodoc:
|
||||
module IndifferentAccess #:nodoc:
|
||||
def with_indifferent_access
|
||||
hash = HashWithIndifferentAccess.new(self)
|
||||
hash.default = self.default
|
||||
hash
|
||||
end
|
||||
end
|
||||
end
|
||||
class Hash
|
||||
def with_indifferent_access
|
||||
hash = HashWithIndifferentAccess.new(self)
|
||||
hash.default = self.default
|
||||
hash
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,52 +1,46 @@
|
||||
module ActiveSupport #:nodoc:
|
||||
module CoreExtensions #:nodoc:
|
||||
module Hash #:nodoc:
|
||||
module Keys
|
||||
# Return a new hash with all keys converted to strings.
|
||||
def stringify_keys
|
||||
inject({}) do |options, (key, value)|
|
||||
options[key.to_s] = value
|
||||
options
|
||||
end
|
||||
end
|
||||
|
||||
# Destructively convert all keys to strings.
|
||||
def stringify_keys!
|
||||
keys.each do |key|
|
||||
self[key.to_s] = delete(key)
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# Return a new hash with all keys converted to symbols.
|
||||
def symbolize_keys
|
||||
inject({}) do |options, (key, value)|
|
||||
options[(key.to_sym rescue key) || key] = value
|
||||
options
|
||||
end
|
||||
end
|
||||
|
||||
# Destructively convert all keys to symbols.
|
||||
def symbolize_keys!
|
||||
self.replace(self.symbolize_keys)
|
||||
end
|
||||
|
||||
alias_method :to_options, :symbolize_keys
|
||||
alias_method :to_options!, :symbolize_keys!
|
||||
|
||||
# Validate all keys in a hash match *valid keys, raising ArgumentError on a mismatch.
|
||||
# Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols
|
||||
# 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", :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?
|
||||
end
|
||||
end
|
||||
class Hash
|
||||
# Return a new hash with all keys converted to strings.
|
||||
def stringify_keys
|
||||
inject({}) do |options, (key, value)|
|
||||
options[key.to_s] = value
|
||||
options
|
||||
end
|
||||
end
|
||||
|
||||
# Destructively convert all keys to strings.
|
||||
def stringify_keys!
|
||||
keys.each do |key|
|
||||
self[key.to_s] = delete(key)
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# Return a new hash with all keys converted to symbols.
|
||||
def symbolize_keys
|
||||
inject({}) do |options, (key, value)|
|
||||
options[(key.to_sym rescue key) || key] = value
|
||||
options
|
||||
end
|
||||
end
|
||||
|
||||
# Destructively convert all keys to symbols.
|
||||
def symbolize_keys!
|
||||
self.replace(self.symbolize_keys)
|
||||
end
|
||||
|
||||
alias_method :to_options, :symbolize_keys
|
||||
alias_method :to_options!, :symbolize_keys!
|
||||
|
||||
# Validate all keys in a hash match *valid keys, raising ArgumentError on a mismatch.
|
||||
# Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols
|
||||
# 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", :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?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,35 +1,28 @@
|
||||
module ActiveSupport #:nodoc:
|
||||
module CoreExtensions #:nodoc:
|
||||
module Hash #:nodoc:
|
||||
# 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:
|
||||
#
|
||||
# def setup(options = {})
|
||||
# options.reverse_merge! :size => 25, :velocity => 10
|
||||
# end
|
||||
#
|
||||
# Using <tt>merge</tt>, the above example would look as follows:
|
||||
#
|
||||
# def setup(options = {})
|
||||
# { :size => 25, :velocity => 10 }.merge(options)
|
||||
# end
|
||||
#
|
||||
# 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.
|
||||
module ReverseMerge
|
||||
# Performs the opposite of <tt>merge</tt>, with the keys and values from the first hash taking precedence over the second.
|
||||
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.
|
||||
def reverse_merge!(other_hash)
|
||||
replace(reverse_merge(other_hash))
|
||||
end
|
||||
|
||||
alias_method :reverse_update, :reverse_merge!
|
||||
end
|
||||
end
|
||||
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:
|
||||
#
|
||||
# def setup(options = {})
|
||||
# options.reverse_merge! :size => 25, :velocity => 10
|
||||
# end
|
||||
#
|
||||
# Using <tt>merge</tt>, the above example would look as follows:
|
||||
#
|
||||
# def setup(options = {})
|
||||
# { :size => 25, :velocity => 10 }.merge(options)
|
||||
# end
|
||||
#
|
||||
# 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.
|
||||
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.
|
||||
def reverse_merge!(other_hash)
|
||||
replace(reverse_merge(other_hash))
|
||||
end
|
||||
|
||||
alias_method :reverse_update, :reverse_merge!
|
||||
end
|
||||
|
||||
@@ -1,40 +1,32 @@
|
||||
module ActiveSupport #:nodoc:
|
||||
module CoreExtensions #:nodoc:
|
||||
module Hash #:nodoc:
|
||||
# Slice a hash to include only the given keys. This is useful for
|
||||
# limiting an options hash to valid keys before passing to a method:
|
||||
#
|
||||
# def search(criteria = {})
|
||||
# assert_valid_keys(:mass, :velocity, :time)
|
||||
# end
|
||||
#
|
||||
# search(options.slice(:mass, :velocity, :time))
|
||||
#
|
||||
# If you have an array of keys you want to limit to, you should splat them:
|
||||
#
|
||||
# valid_keys = [:mass, :velocity, :time]
|
||||
# search(options.slice(*valid_keys))
|
||||
module Slice
|
||||
# Returns a new hash with only the given keys.
|
||||
def slice(*keys)
|
||||
keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
||||
hash = self.class.new
|
||||
keys.each { |k| hash[k] = self[k] if has_key?(k) }
|
||||
hash
|
||||
end
|
||||
class Hash
|
||||
# Slice a hash to include only the given keys. This is useful for
|
||||
# limiting an options hash to valid keys before passing to a method:
|
||||
#
|
||||
# def search(criteria = {})
|
||||
# assert_valid_keys(:mass, :velocity, :time)
|
||||
# end
|
||||
#
|
||||
# search(options.slice(:mass, :velocity, :time))
|
||||
#
|
||||
# If you have an array of keys you want to limit to, you should splat them:
|
||||
#
|
||||
# valid_keys = [:mass, :velocity, :time]
|
||||
# search(options.slice(*valid_keys))
|
||||
def slice(*keys)
|
||||
keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
||||
hash = self.class.new
|
||||
keys.each { |k| hash[k] = self[k] if has_key?(k) }
|
||||
hash
|
||||
end
|
||||
|
||||
# Replaces the hash with only the given keys.
|
||||
# Returns a hash contained the removed key/value pairs
|
||||
# {:a => 1, :b => 2, :c => 3, :d => 4}.slice!(:a, :b) # => {:c => 3, :d =>4}
|
||||
def slice!(*keys)
|
||||
keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
||||
omit = slice(*self.keys - keys)
|
||||
hash = slice(*keys)
|
||||
replace(hash)
|
||||
omit
|
||||
end
|
||||
end
|
||||
end
|
||||
# Replaces the hash with only the given keys.
|
||||
# Returns a hash contained the removed key/value pairs
|
||||
# {:a => 1, :b => 2, :c => 3, :d => 4}.slice!(:a, :b) # => {:c => 3, :d =>4}
|
||||
def slice!(*keys)
|
||||
keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
||||
omit = slice(*self.keys - keys)
|
||||
hash = slice(*keys)
|
||||
replace(hash)
|
||||
omit
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
129
activesupport/lib/active_support/hash_with_indifferent_access.rb
Normal file
129
activesupport/lib/active_support/hash_with_indifferent_access.rb
Normal file
@@ -0,0 +1,129 @@
|
||||
# This class has dubious semantics and we only have it so that
|
||||
# people can write params[:key] instead of params['key']
|
||||
# and they get the same value for both keys.
|
||||
|
||||
class HashWithIndifferentAccess < Hash
|
||||
def initialize(constructor = {})
|
||||
if constructor.is_a?(Hash)
|
||||
super()
|
||||
update(constructor)
|
||||
else
|
||||
super(constructor)
|
||||
end
|
||||
end
|
||||
|
||||
def default(key = nil)
|
||||
if key.is_a?(Symbol) && include?(key = key.to_s)
|
||||
self[key]
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
||||
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
||||
|
||||
# Assigns a new value to the hash:
|
||||
#
|
||||
# hash = HashWithIndifferentAccess.new
|
||||
# hash[:key] = "value"
|
||||
#
|
||||
def []=(key, value)
|
||||
regular_writer(convert_key(key), convert_value(value))
|
||||
end
|
||||
|
||||
# Updates the instantized hash with values from the second:
|
||||
#
|
||||
# hash_1 = HashWithIndifferentAccess.new
|
||||
# hash_1[:key] = "value"
|
||||
#
|
||||
# hash_2 = HashWithIndifferentAccess.new
|
||||
# hash_2[:key] = "New Value!"
|
||||
#
|
||||
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
|
||||
#
|
||||
def update(other_hash)
|
||||
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
|
||||
self
|
||||
end
|
||||
|
||||
alias_method :merge!, :update
|
||||
|
||||
# Checks the hash for a key matching the argument passed in:
|
||||
#
|
||||
# hash = HashWithIndifferentAccess.new
|
||||
# hash["key"] = "value"
|
||||
# hash.key? :key # => true
|
||||
# hash.key? "key" # => true
|
||||
#
|
||||
def key?(key)
|
||||
super(convert_key(key))
|
||||
end
|
||||
|
||||
alias_method :include?, :key?
|
||||
alias_method :has_key?, :key?
|
||||
alias_method :member?, :key?
|
||||
|
||||
# Fetches the value for the specified key, same as doing hash[key]
|
||||
def fetch(key, *extras)
|
||||
super(convert_key(key), *extras)
|
||||
end
|
||||
|
||||
# Returns an array of the values at the specified indices:
|
||||
#
|
||||
# hash = HashWithIndifferentAccess.new
|
||||
# hash[:a] = "x"
|
||||
# hash[:b] = "y"
|
||||
# hash.values_at("a", "b") # => ["x", "y"]
|
||||
#
|
||||
def values_at(*indices)
|
||||
indices.collect {|key| self[convert_key(key)]}
|
||||
end
|
||||
|
||||
# Returns an exact copy of the hash.
|
||||
def dup
|
||||
HashWithIndifferentAccess.new(self)
|
||||
end
|
||||
|
||||
# Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
|
||||
# Does not overwrite the existing hash.
|
||||
def merge(hash)
|
||||
self.dup.update(hash)
|
||||
end
|
||||
|
||||
# Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
|
||||
# This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
|
||||
def reverse_merge(other_hash)
|
||||
super other_hash.with_indifferent_access
|
||||
end
|
||||
|
||||
# Removes a specified key from the hash.
|
||||
def delete(key)
|
||||
super(convert_key(key))
|
||||
end
|
||||
|
||||
def stringify_keys!; self end
|
||||
def symbolize_keys!; self end
|
||||
def to_options!; self end
|
||||
|
||||
# Convert to a Hash with String keys.
|
||||
def to_hash
|
||||
Hash.new(default).merge(self)
|
||||
end
|
||||
|
||||
protected
|
||||
def convert_key(key)
|
||||
key.kind_of?(Symbol) ? key.to_s : key
|
||||
end
|
||||
|
||||
def convert_value(value)
|
||||
case value
|
||||
when Hash
|
||||
value.with_indifferent_access
|
||||
when Array
|
||||
value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user