class Hashie::Mash


mash.author # => <Mash>
mash.author_.name = “Michael Bleigh” (assigned to temp object)
mash = Mash.new
mash.author_.name # => nil
mash.author_ # => <Mash>
mash.author # => nil
mash = Mash.new
== Under Bang Example
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
* Under Bang (_): Like Bang, but returns a new Mash rather than creating a key. Used to test existance in deep Mashes.
* 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 self.disable_warnings

Returns:
  • (void) -

Other tags:
    Api: - semipublic
def self.disable_warnings
  fail CannotDisableMashWarnings if self == Hashie::Mash
  @disable_warnings = true
end

def self.disable_warnings?

Returns:
  • (Boolean) -

Other tags:
    Api: - semipublic
def self.disable_warnings?
  !!@disable_warnings
end

def self.inherited(subclass)

Returns:
  • (void) -

Other tags:
    Api: - semipublic
def self.inherited(subclass)
  super
  subclass.disable_warnings if disable_warnings?
end

def self.load(path, options = {})

def self.load(path, options = {})
  @_mashes ||= new
  return @_mashes[path] if @_mashes.key?(path)
  fail ArgumentError, "The following file doesn't exist: #{path}" unless File.file?(path)
  parser = options.fetch(:parser) {  Hashie::Extensions::Parsers::YamlErbParser }
  @_mashes[path] = new(parser.perform(path)).freeze
end

def assign_property(name, value)

Assigns a value to a key
def assign_property(name, value)
  self[name] = 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 self.class
    val.dup
  when Hash
    duping ? val.dup : val
  when ::Hash
    val = val.dup if duping
    self.class.new(val)
  when Array
    val.map { |e| convert_value(e) }
  when ::Array
    Array.new(val.map { |e| convert_value(e) })
  else
    val
  end
end

def custom_reader(key)

any key passed in to a string before retrieving.
Retrieves an attribute set in the Mash. Will convert
def custom_reader(key)
  default_proc.call(self, key) if default_proc && !key?(key)
  value = regular_reader(convert_key(key))
  yield value if block_given?
  value
end

def custom_writer(key, value, convert = true) #: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 custom_writer(key, value, convert = true) #:nodoc:
  key_as_symbol = (key = convert_key(key)).to_sym
  log_built_in_message(key_as_symbol) if log_collision?(key_as_symbol)
  regular_writer(key, convert ? convert_value(value) : value)
end

def deep_merge(other_hash, &blk)

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

def deep_update(other_hash, &blk)

in hash, merging each hash in the hierarchy.
Recursively merges this mash with the passed
def deep_update(other_hash, &blk)
  other_hash.each_pair do |k, v|
    key = convert_key(k)
    if regular_reader(key).is_a?(Mash) && v.is_a?(::Hash)
      custom_reader(key).deep_update(v, &blk)
    else
      value = convert_value(v, true)
      value = convert_value(blk.call(key, self[k], value), true) if blk && self.key?(k)
      custom_writer(key, value, false)
    end
  end
  self
end

def delete(key)

def delete(key)
  super(convert_key(key))
end

def dig(*keys)

def dig(*keys)
  super(*keys.map { |key| convert_key(key) })
end

def dup

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

def extractable_options?

play nice with ActiveSupport Array#extract_options!
def extractable_options?
  true
end

def fetch(key, *args)

def fetch(key, *args)
  super(convert_key(key), *args)
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
  default ? super(default) : super(&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)
  ck = convert_key(key)
  regular_writer(ck, self.class.new) unless key?(ck)
  regular_reader(ck)
end

def key?(key)

def key?(key)
  super(convert_key(key))
end

def log_built_in_message(method_key)

def log_built_in_message(method_key)
  return if self.class.disable_warnings?
  method_information = Hashie::Utils.method_information(method(method_key))
  Hashie.logger.warn(
    'You are setting a key that conflicts with a built-in method ' \
    "#{self.class}##{method_key} #{method_information}. " \
    'This can cause unexpected behavior when accessing the key via as a ' \
    'property. You can still access the key via the #[] method.'
  )
end

def log_collision?(method_key)

def log_collision?(method_key)
  respond_to?(method_key) && !self.class.disable_warnings? &&
    !(regular_key?(method_key) || regular_key?(method_key.to_s))
end

def method_missing(method_name, *args, &blk)

def method_missing(method_name, *args, &blk)
  return self.[](method_name, &blk) if key?(method_name)
  name, suffix = method_name_and_suffix(method_name)
  case suffix
  when '='.freeze
    assign_property(name, args.first)
  when '?'.freeze
    !!self[name]
  when '!'.freeze
    initializing_reader(name)
  when '_'.freeze
    underbang_reader(name)
  else
    self[method_name]
  end
end

def method_name_and_suffix(method_name)

def method_name_and_suffix(method_name)
  method_name = method_name.to_s
  if method_name.end_with?(*ALLOWED_SUFFIXES)
    [method_name[0..-2], method_name[-1]]
  else
    [method_name[0..-1], nil]
  end
end

def method_suffix(method_name)

def method_suffix(method_name)
  method_name = method_name.to_s
  method_name[-1] if method_name.end_with?(*ALLOWED_SUFFIXES)
end

def prefix_method?(method_name)

def prefix_method?(method_name)
  method_name = method_name.to_s
  method_name.end_with?(*ALLOWED_SUFFIXES) && key?(method_name.chop)
end

def replace(other_hash)

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

def respond_to_missing?(method_name, *args)

def respond_to_missing?(method_name, *args)
  return true if key?(method_name)
  suffix = method_suffix(method_name)
  if suffix
    true
  else
    super
  end
end

def reverse_merge(other_hash)

another ActiveSupport method, see issue #270
def reverse_merge(other_hash)
  self.class.new(other_hash).merge(self)
end

def shallow_merge(other_hash)

Performs a shallow_update on a duplicate of the current mash
def shallow_merge(other_hash)
  dup.shallow_update(other_hash)
end

def shallow_update(other_hash)

changing the receiving hash
Merges (non-recursively) the hash from the argument,
def shallow_update(other_hash)
  other_hash.each_pair do |k, v|
    regular_writer(convert_key(k), convert_value(v, true))
  end
  self
end

def to_module(mash_method_name = :settings)

def to_module(mash_method_name = :settings)
  mash = self
  Module.new do |m|
    m.send :define_method, mash_method_name.to_sym do
      mash
    end
  end
end

def underbang_reader(key)

if there isn't a value already assigned to the key requested.
This is the under bang method reader, it will return a temporary new Mash
def underbang_reader(key)
  ck = convert_key(key)
  if key?(ck)
    regular_reader(ck)
  else
    self.class.new
  end
end

def values_at(*keys)

def values_at(*keys)
  super(*keys.map { |key| convert_key(key) })
end