File: active_support/core_ext/hash/indifferent_access.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: ActiveSupport#131
  module: CoreExtensions#132
  module: Hash#133
  module: IndifferentAccess#134
has properties
method: with_indifferent_access #135
  class: HashWithIndifferentAccess#5
inherits from
  Hash ( Builtin-Module )
has properties
method: initialize / 1 #6
method: default / 1 #15
method: []= / 2 #31
method: update / 1 #45
method: key? / 1 #59
method: fetch / 2 #68
method: values_at / 1 #79
method: dup #84
method: merge / 1 #90
method: reverse_merge / 1 #96
method: delete / 1 #101
method: stringify_keys! #105
method: symbolize_keys! #106
method: to_options! #107
method: to_hash #110
method: convert_key / 1 #115
method: convert_value / 1 #119

Class Hierarchy

Code

   1  # This class has dubious semantics and we only have it so that
   2  # people can write params[:key] instead of params['key']
   3  # and they get the same value for both keys.
   4 
   5  class HashWithIndifferentAccess < Hash
   6    def initialize(constructor = {})
   7      if constructor.is_a?(Hash)
   8        super()
   9        update(constructor)
  10      else
  11        super(constructor)
  12      end
  13    end
  14 
  15    def default(key = nil)
  16      if key.is_a?(Symbol) && include?(key = key.to_s)
  17        self[key]
  18      else
  19        super
  20      end
  21    end
  22 
  23    alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
  24    alias_method :regular_update, :update unless method_defined?(:regular_update)
  25 
  26    # Assigns a new value to the hash:
  27    #
  28    #   hash = HashWithIndifferentAccess.new
  29    #   hash[:key] = "value"
  30    #
  31    def []=(key, value)
  32      regular_writer(convert_key(key), convert_value(value))
  33    end
  34 
  35    # Updates the instantized hash with values from the second:
  36    # 
  37    #   hash_1 = HashWithIndifferentAccess.new
  38    #   hash_1[:key] = "value"
  39    # 
  40    #   hash_2 = HashWithIndifferentAccess.new
  41    #   hash_2[:key] = "New Value!"
  42    # 
  43    #   hash_1.update(hash_2) # => {"key"=>"New Value!"}
  44    # 
  45    def update(other_hash)
  46      other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
  47      self
  48    end
  49 
  50    alias_method :merge!, :update
  51 
  52    # Checks the hash for a key matching the argument passed in:
  53    #
  54    #   hash = HashWithIndifferentAccess.new
  55    #   hash["key"] = "value"
  56    #   hash.key? :key  # => true
  57    #   hash.key? "key" # => true
  58    #
  59    def key?(key)
  60      super(convert_key(key))
  61    end
  62 
  63    alias_method :include?, :key?
  64    alias_method :has_key?, :key?
  65    alias_method :member?, :key?
  66 
  67    # Fetches the value for the specified key, same as doing hash[key]
  68    def fetch(key, *extras)
  69      super(convert_key(key), *extras)
  70    end
  71 
  72    # Returns an array of the values at the specified indices:
  73    #
  74    #   hash = HashWithIndifferentAccess.new
  75    #   hash[:a] = "x"
  76    #   hash[:b] = "y"
  77    #   hash.values_at("a", "b") # => ["x", "y"]
  78    #
  79    def values_at(*indices)
  80      indices.collect {|key| self[convert_key(key)]}
  81    end
  82 
  83    # Returns an exact copy of the hash.
  84    def dup
  85      HashWithIndifferentAccess.new(self)
  86    end
  87 
  88    # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
  89    # Does not overwrite the existing hash.
  90    def merge(hash)
  91      self.dup.update(hash)
  92    end
  93 
  94    # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
  95    # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
  96    def reverse_merge(other_hash)
  97      super other_hash.with_indifferent_access
  98    end
  99 
 100    # Removes a specified key from the hash.
 101    def delete(key)
 102      super(convert_key(key))
 103    end
 104 
 105    def stringify_keys!; self end
 106    def symbolize_keys!; self end
 107    def to_options!; self end
 108 
 109    # Convert to a Hash with String keys.
 110    def to_hash
 111      Hash.new(default).merge(self)
 112    end
 113 
 114    protected
 115      def convert_key(key)
 116        key.kind_of?(Symbol) ? key.to_s : key
 117      end
 118 
 119      def convert_value(value)
 120        case value
 121        when Hash
 122          value.with_indifferent_access
 123        when Array
 124          value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
 125        else
 126          value
 127        end
 128      end
 129  end
 130 
 131  module ActiveSupport #:nodoc:
 132    module CoreExtensions #:nodoc:
 133      module Hash #:nodoc:
 134        module IndifferentAccess #:nodoc:
 135          def with_indifferent_access
 136            hash = HashWithIndifferentAccess.new(self)
 137            hash.default = self.default
 138            hash
 139          end
 140        end
 141      end
 142    end
 143  end