class Hashie::Mash


mash.author # => <Mash name=“Michael Bleigh”>
mash.author!.name = “Michael Bleigh”
mash = Mash.new
mash.author! # => <Mash>
mash.author # => nil
mash = Mash.new
== Bang Example
mash.f.last # => 12
mash.f.first.g # => 44
mash.a.d.e # => “abc”
mash.a.b # => 23
mash = Mash.new(hash)
hash = {:a => {:b => 23, :d => {:e => “abc”}}, :f => [{:g => 44, :h => 29}, 12]}
== Hash Conversion Example
mash.name? # => true
mash.name # => “Bob”
mash.name = “Bob”
mash.name? # => false
mash = Mash.new
== Basic Example
* Bang (!): Forces the existence of this key, used for deep Mashes. Think of it as “touch” for mashes.
* Existence (?): Returns true or false depending on whether that key has been set.
* Assignment (=): Sets the attribute of the given method name.
* No punctuation: Returns the value of the hash for that key, or nil if none exists.
based on the following rules:
A Mash will look at the methods you pass it and perform operations
with some additional goodies.
without the overhead of actually doing so. Think of it as OpenStruct
as an API-accessing library that wants to fake robust objects
accessors for hash keys. This is useful for such implementations
Mash allows you to create pseudo-objects that have method-like

def [](key)

any key passed in to a string before retrieving.
Retrieves an attribute set in the Mash. Will convert
def [](key)
  key = convert_key(key)
  regular_reader(key)
end

def []=(key,value) #:nodoc:

:nodoc:
into Mashes for nesting purposes.
a string before it is set, and Hashes will be converted
Sets an attribute in the Mash. Key will be converted to
def []=(key,value) #:nodoc:
  key = convert_key(key)
  regular_writer(key, convert_value(value))
end

def convert_key(key) #:nodoc:

:nodoc:
def convert_key(key) #:nodoc:
  key.to_s
end

def convert_value(val, duping=false) #:nodoc:

:nodoc:
def convert_value(val, duping=false) #:nodoc:
  case val
    when ::Hash
      val = val.dup if duping
      Hashie::Mash.new(val)
    when Array
      val.collect{ |e| convert_value(e) }
    else
      val
  end
end

def deep_merge(other_hash)

current mash.
Performs a deep_update on a duplicate of the
def deep_merge(other_hash)
  dup.deep_merge!(other_hash)
end

def deep_update(other_hash)

in hash, merging each hash in the hierarchy.
Recursively merges this mash with the passed
def deep_update(other_hash)
  other_hash = Hashie::Hash[other_hash].stringify_keys!
  
  other_hash.each_pair do |k,v|
    k = convert_key(k)
    self[k] = Hashie::Mash.new(self[k]).to_mash if self[k].is_a?(Hash) unless self[k].is_a?(Hashie::Mash)
    if self[k].is_a?(Hashie::Mash) && other_hash[k].is_a?(Hash)
      self[k] = self[k].deep_merge(other_hash[k])
    else
      self[k] = convert_value(other_hash[k],true)
    end
  end
  
  self
end

def default(key = nil)

be set to the value matching the key.
If key is a Symbol and it is a key in the mash, then the default value will
==== Alternatives

key:: The default value for the mash. Defaults to nil.
==== Parameters

Borrowed from Merb's Mash object.
def default(key = nil) 
  if key.is_a?(Symbol) && key?(key.to_s) 
    self[key] 
  else 
    key ? super : super()
  end 
end

def dup

Duplicates the current mash as a new mash.
def dup
  Mash.new(self, self.default)
end

def id #:nodoc:

:nodoc:
def id #:nodoc:
  self["id"] ? self["id"] : super
end

def initialize(source_hash = nil, default = nil, &blk)

them as well.
descending into arrays and hashes, converting
convert it to a Mash including recursively
If you pass in an existing hash, it will
def initialize(source_hash = nil, default = nil, &blk)
  deep_update(source_hash) if source_hash
  super default if default
  super &blk if blk
end

def initializing_reader(key)

if there isn't a value already assigned to the key requested.
This is the bang method reader, it will return a new Mash
def initializing_reader(key)
  self[key] = Hashie::Mash.new unless key?(key)
  self[key]
end

def key?(key)

def key?(key)
  picky_key?(convert_key(key))
end

def method_missing(method_name, *args) #:nodoc:

:nodoc:
def method_missing(method_name, *args) #:nodoc:
  if (match = method_name.to_s.match(/(.*)=$/)) && args.size == 1
    self[match[1]] = args.first
  elsif (match = method_name.to_s.match(/(.*)\?$/)) && args.size == 0
    key?(match[1])
  elsif (match = method_name.to_s.match(/(.*)!$/)) && args.size == 0
    initializing_reader(match[1])
  elsif key?(method_name)
    self[method_name]
  elsif match = method_name.to_s.match(/^([a-z][a-z0-9A-Z_]+)$/)
    default(method_name)
  else
    super
  end
end

def to_hash

Converts a mash back to a hash (with stringified keys)
def to_hash
  Hash.new(default).merge(self)
end

def update(other_hash)

Mash:: The updated mash.
==== Returns

stringified and Hashes will be converted to Mashes.
A hash to update values in the mash with. Keys will be
other_hash::
==== Parameters
def update(other_hash)
  other_hash.each_pair do |key, value|
    if respond_to?(convert_key(key) + "=")
      self.send(convert_key(key) + "=", convert_value(value))
    else
      regular_writer(convert_key(key), convert_value(value))
    end
  end
  self
end