module Hashie::Extensions::IndifferentAccess

def self.included(base)

def self.included(base)
  base.class_eval do
    alias_method :regular_writer, :[]=
    alias_method :[]=, :indifferent_writer
    %w(default update replace fetch delete key? values_at).each do |m|
      alias_method "regular_#{m}", m
      alias_method m, "indifferent_#{m}"
    end
    %w(include? member? has_key?).each do |key_alias|
      alias_method key_alias, :indifferent_key?
    end
  end
end

def self.inject(hash)

provided. See #inject!
Injects indifferent access into a duplicate of the hash
def self.inject(hash)
  inject!(hash.dup)
end

def self.inject!(hash)

allows IndifferentAccess to spread to sub-hashes.
a hash without modifying the actual class. This is what
This will inject indifferent access into an instance of
def self.inject!(hash)
  (class << hash; self; end).send :include, IndifferentAccess
  hash.convert!
end

def convert!

is injecting itself into member hashes.
their proper indifferent state. Used when IndifferentAccess
Iterates through the keys and values, reconverting them to
def convert!
  keys.each do |k|
    regular_writer convert_key(k), convert_value(self.regular_delete(k))
  end
  self
end

def convert_key(key)

def convert_key(key)
  key.to_s
end

def convert_value(value)

def convert_value(value)
  if hash_lacking_indifference?(value)
    IndifferentAccess.inject(value.dup)
  elsif value.is_a?(::Array)
    value.dup.replace(value.map { |e| convert_value(e) })
  else
    value
  end
end

def hash_lacking_indifference?(other)

def hash_lacking_indifference?(other)
  other.is_a?(::Hash) &&
  !(other.respond_to?(:indifferent_access?) &&
    other.indifferent_access?)
end

def hash_with_indifference?(other)

def hash_with_indifference?(other)
  other.is_a?(::Hash) &&
  other.respond_to?(:indifferent_access?) &&
  other.indifferent_access?
end

def indifferent_access?; true end

def indifferent_access?; true end

def indifferent_default(key = nil)

def indifferent_default(key = nil)
  return self[convert_key(key)] if key?(key)
  regular_default(key)
end

def indifferent_delete(key); regular_delete convert_key(key) end

def indifferent_delete(key);         regular_delete convert_key(key)                       end

def indifferent_fetch(key, *args); regular_fetch convert_key(key), *args end

def indifferent_fetch(key, *args);   regular_fetch  convert_key(key), *args                end

def indifferent_key?(key); regular_key? convert_key(key) end

def indifferent_key?(key);           regular_key?   convert_key(key)                       end

def indifferent_replace(other_hash)

def indifferent_replace(other_hash)
  (keys - other_hash.keys).each { |key| delete(key) }
  other_hash.each { |key, value| self[key] = value }
  self
end

def indifferent_update(other_hash)

def indifferent_update(other_hash)
  return regular_update(other_hash) if hash_with_indifference?(other_hash)
  other_hash.each_pair do |k,v|
    self[k] = v
  end
end

def indifferent_values_at(*indices); indices.map{|i| self[i] } end

def indifferent_values_at(*indices); indices.map{|i| self[i] }                             end

def indifferent_writer(key, value); regular_writer convert_key(key), convert_value(value) end

def indifferent_writer(key, value);  regular_writer convert_key(key), convert_value(value) end