Skip to content

Commit

Permalink
Vendor ExtLib's Mash.
Browse files Browse the repository at this point in the history
  • Loading branch information
gix committed Mar 6, 2011
1 parent 2629964 commit b80610f
Show file tree
Hide file tree
Showing 6 changed files with 490 additions and 156 deletions.
2 changes: 1 addition & 1 deletion lib/dm-core.rb
Expand Up @@ -13,7 +13,6 @@ module Undefined; end

require 'dm-core/ext/singleton_class'
require 'dm-core/as/core_ext/object/blank'
require 'dm-core/as/mash'
require 'dm-core/as/inflector'

require 'dm-core/ext/hash'
Expand All @@ -34,6 +33,7 @@ module DataMapper
require 'dm-core/ext/module'
require 'dm-core/ext/array'

require 'dm-core/support/mash'
require 'dm-core/support/chainable'
require 'dm-core/support/deprecate'
require 'dm-core/support/descendant_set'
Expand Down
152 changes: 0 additions & 152 deletions lib/dm-core/as/mash.rb

This file was deleted.

174 changes: 174 additions & 0 deletions lib/dm-core/support/mash.rb
@@ -0,0 +1,174 @@
module DataMapper
# This class has dubious semantics and we only have it so that people can write
# params[:key] instead of params['key'].
class Mash < Hash

# @param constructor<Object>
# The default value for the mash. Defaults to an empty hash.
#
# @details [Alternatives]
# If constructor is a Hash, a new mash will be created based on the keys of
# the hash and no default value will be set.
def initialize(constructor = {})
if constructor.is_a?(Hash)
super()
update(constructor)
else
super(constructor)
end
end

# @param key<Object> The default value for the mash. Defaults to nil.
#
# @details [Alternatives]
# If key is a Symbol and it is a key in the mash, then the default value will
# be set to the value matching the key.
def default(key = nil)
if key.is_a?(Symbol) && include?(key = key.to_s)
self[key]
else
super
end
end

alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
alias_method :regular_update, :update unless method_defined?(:regular_update)

# @param key<Object> The key to set.
# @param value<Object>
# The value to set the key to.
#
# @see Mash#convert_key
# @see Mash#convert_value
def []=(key, value)
regular_writer(convert_key(key), convert_value(value))
end

# @param other_hash<Hash>
# A hash to update values in the mash with. The keys and the values will be
# converted to Mash format.
#
# @return [Mash] The updated mash.
def update(other_hash)
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
self
end

alias_method :merge!, :update

# @param key<Object> The key to check for. This will be run through convert_key.
#
# @return [Boolean] True if the key exists in the mash.
def key?(key)
super(convert_key(key))
end

# def include? def has_key? def member?
alias_method :include?, :key?
alias_method :has_key?, :key?
alias_method :member?, :key?

# @param key<Object> The key to fetch. This will be run through convert_key.
# @param *extras<Array> Default value.
#
# @return [Object] The value at key or the default value.
def fetch(key, *extras)
super(convert_key(key), *extras)
end

# @param *indices<Array>
# The keys to retrieve values for. These will be run through +convert_key+.
#
# @return [Array] The values at each of the provided keys
def values_at(*indices)
indices.collect {|key| self[convert_key(key)]}
end

# @param hash<Hash> The hash to merge with the mash.
#
# @return [Mash] A new mash with the hash values merged in.
def merge(hash)
self.dup.update(hash)
end

# @param key<Object>
# The key to delete from the mash.\
def delete(key)
super(convert_key(key))
end

# Returns a mash that includes everything but the given +keys+.
#
# @param [Array<String, Symbol>] *keys The mash keys to exclude.
#
# @return [Mash] A new mash without the selected keys.
#
# @example
# { :one => 1, :two => 2, :three => 3 }.except(:one)
# #=> { "two" => 2, "three" => 3 }
def except(*keys)
self.dup.except!(*keys.map {|k| convert_key(k)})
end

# Removes the specified +keys+ from the mash.
#
# @param [Array] *keys The mash keys to exclude.
#
# @return [Hash] +hash+
#
# @example
# mash = { :one => 1, :two => 2, :three => 3 }
# mash.except!(:one, :two)
# mash # => { :three => 3 }
def except!(*keys)
keys.each { |key| delete(key) }
self
end

# Used to provide the same interface as Hash.
#
# @return [Mash] This mash unchanged.
def stringify_keys!; self end

# @return [Hash] The mash as a Hash with symbolized keys.
def symbolize_keys
h = Hash.new(default)
each { |key, val| h[key.to_sym] = val }
h
end

# @return [Hash] The mash as a Hash with string keys.
def to_hash
Hash.new(default).merge(self)
end

protected
# @param key<Object> The key to convert.
#
# @param [Object]
# The converted key. If the key was a symbol, it will be converted to a
# string.
#
# @api private
def convert_key(key)
key.kind_of?(Symbol) ? key.to_s : key
end

# @param value<Object> The value to convert.
#
# @return [Object]
# The converted value. A Hash or an Array of hashes, will be converted to
# their Mash equivalents.
#
# @api private
def convert_value(value)
if value.class == Hash
value.to_mash
elsif value.is_a?(Array)
value.collect { |e| convert_value(e) }
else
value
end
end
end
end
4 changes: 2 additions & 2 deletions spec/unit/array_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
require 'dm-core/ext/array'
require 'dm-core/as/mash'
require 'dm-core/support/mash'

describe DataMapper::Ext::Array do
before :all do
Expand All @@ -27,7 +27,7 @@
end

it 'should return a Mash' do
@return.should be_kind_of(Mash)
@return.should be_kind_of(DataMapper::Mash)
end

it 'should return expected value' do
Expand Down
2 changes: 1 addition & 1 deletion spec/unit/hash_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
require 'dm-core/ext/hash'
require 'dm-core/as/mash'
require 'dm-core/support/mash'

describe DataMapper::Ext::Hash, "only" do
before do
Expand Down

0 comments on commit b80610f

Please sign in to comment.