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 convert_key(key) #:nodoc:
def convert_key(key) #:nodoc: key.to_s end
def convert_value(val, duping = false) #: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) } else val end end
def custom_reader(key)
Retrieves an attribute set in the Mash. Will convert
def custom_reader(key) value = regular_reader(convert_key(key)) yield value if block_given? value end
def custom_writer(key, value, convert = true) #: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: regular_writer(convert_key(key), convert ? convert_value(value) : value) end
def deep_merge(other_hash, &blk)
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)
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 custom_writer(key, value, false) end end self end
def delete(key)
def delete(key) super(convert_key(key)) end
def dup
def dup self.class.new(self, default) end
def fetch(key, *args)
def fetch(key, *args) super(convert_key(key), *args) end
def id #:nodoc:
def id #:nodoc: self['id'] end
def initialize(source_hash = nil, default = nil, &blk)
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)
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 method_missing(method_name, *args, &blk)
def method_missing(method_name, *args, &blk) return self.[](method_name, &blk) if key?(method_name) suffixes_regex = ALLOWED_SUFFIXES.join match = method_name.to_s.match(/(.*?)([#{suffixes_regex}]?)$/) case match[2] when '=' self[match[1]] = args.first when '?' !!self[match[1]] when '!' initializing_reader(match[1]) when '_' underbang_reader(match[1]) else default(method_name) end 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?(method_name, include_private = false)
Will return true if the Mash has had a key
def respond_to?(method_name, include_private = false) return true if key?(method_name) || prefix_method?(method_name) super end
def shallow_merge(other_hash)
def shallow_merge(other_hash) dup.shallow_update(other_hash) end
def shallow_update(other_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 type #:nodoc:
def type #:nodoc: self['type'] end
def underbang_reader(key)
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