Skip to content
Browse files

Convert hash extension modules to class reopens

  • Loading branch information...
1 parent bc4e2aa commit b4a1718832c70005e45a930d5106857cf882e147 @jeremy jeremy committed Mar 21, 2009
View
10 activesupport/lib/active_support/core_ext/hash.rb
@@ -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)
View
33 activesupport/lib/active_support/core_ext/hash/deep_merge.rb
@@ -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
View
28 activesupport/lib/active_support/core_ext/hash/diff.rb
@@ -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
View
35 activesupport/lib/active_support/core_ext/hash/except.rb
@@ -1,25 +1,16 @@
-require 'set'
-
-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
+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
- # 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
View
146 activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
@@ -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
View
84 activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -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
+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
+ # 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
+ # 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
+ # 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!
+ 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
- end
+ # 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
View
57 activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
@@ -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
+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
- alias_method :reverse_update, :reverse_merge!
- end
- 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
View
66 activesupport/lib/active_support/core_ext/hash/slice.rb
@@ -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
-
View
129 activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -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

0 comments on commit b4a1718

Please sign in to comment.
Something went wrong with that request. Please try again.