165 lines
3.3 KiB
Ruby
165 lines
3.3 KiB
Ruby
require 'hashery/crud_hash'
|
|
|
|
module Hashery
|
|
|
|
# CastingHash is just like CRUDHash, except that both keys and values
|
|
# can be passed through casting procedures.
|
|
#
|
|
class CastingHash < CRUDHash
|
|
|
|
#
|
|
# Like `#new` but can take a priming Hash or Array-pairs.
|
|
#
|
|
# hash - Hash-like object.
|
|
#
|
|
# Examples
|
|
#
|
|
# CastingHash[:a,1,:b,2]
|
|
#
|
|
# Returns `CastingHash`.
|
|
#
|
|
def self.[](hash)
|
|
s = new
|
|
hash.each{ |k,v| s[k] = v }
|
|
s
|
|
end
|
|
|
|
#
|
|
# Unlike traditional Hash a CastingHash's block argument
|
|
# coerces key/value pairs when #store is called.
|
|
#
|
|
# default - Default value.
|
|
# cast_proc - Casting procedure.
|
|
#
|
|
def initialize(default=nil, &cast_proc)
|
|
@cast_proc = cast_proc
|
|
super(default, &nil)
|
|
end
|
|
|
|
#
|
|
# The cast procedure.
|
|
#
|
|
# proc - Casting procedure.
|
|
#
|
|
# Returns `Proc` used for casting.
|
|
#
|
|
def cast_proc(&proc)
|
|
@cast_proc = proc if proc
|
|
@cast_proc
|
|
end
|
|
|
|
#
|
|
# Set `cast_proc`. This procedure must take two arguments (`key, value`)
|
|
# and return the same.
|
|
#
|
|
# proc - Casting procedure.
|
|
#
|
|
# Returns +proc+.
|
|
#
|
|
def cast_proc=(proc)
|
|
raise ArgumentError unless Proc === proc or NilClass === proc
|
|
@cast_proc = proc
|
|
end
|
|
|
|
#
|
|
# CRUD method for create and update. Unlike the parent class
|
|
# the key, value pair are passed threw the cast_proc before
|
|
# being set in the underlying hash table.
|
|
#
|
|
# key - Key of entry.
|
|
# value - Value of entry.
|
|
#
|
|
# Returns the +value+.
|
|
#
|
|
def store(key, value)
|
|
super(*cast_pair(key, value))
|
|
end
|
|
|
|
#
|
|
# Replace current entries with those from another Hash,
|
|
# or Hash-like object. Each entry is run through the
|
|
# casting procedure as it is added.
|
|
#
|
|
# other - Hash-like object.
|
|
#
|
|
# Returns +self+.
|
|
#
|
|
def replace(other)
|
|
super cast(other)
|
|
end
|
|
|
|
#
|
|
# Convert the CastingHash to a regular Hash.
|
|
#
|
|
# Returns an ordinary `Hash`.
|
|
#
|
|
def to_hash
|
|
h = {}; each{ |k,v| h[k] = v }; h
|
|
end
|
|
|
|
#
|
|
# Returns an ordinary `Hash`.
|
|
#
|
|
alias_method :to_h, :to_hash
|
|
|
|
#
|
|
# Recast all entries via the cast procedure.
|
|
#
|
|
# TODO: Isn't this the same as `#rehash`?
|
|
#
|
|
# Returns +self+.
|
|
#
|
|
def recast!
|
|
replace self
|
|
end
|
|
|
|
private
|
|
|
|
#
|
|
# If `cast_proc` is defined then use it to process key-value pair,
|
|
# otherwise return them as is.
|
|
#
|
|
# key - Key of entry.
|
|
# value - Value of entry.
|
|
#
|
|
# Returns `Array` of key-value pair.
|
|
#
|
|
def cast_pair(key, value)
|
|
if cast_proc
|
|
return cast_proc.call(key, value)
|
|
else
|
|
return key, value
|
|
end
|
|
end
|
|
|
|
#
|
|
# Cast a given +hash+ according to the `#key_proc` and `#value_proc`.
|
|
#
|
|
# hash - A `Hash` or anything the responds to `#each` like a hash.
|
|
#
|
|
# Returns a recasted `Hash`.
|
|
#
|
|
def cast(hash)
|
|
h = {}
|
|
hash.each do |k,v|
|
|
k, v = cast_pair(k, v)
|
|
h[k] = v
|
|
end
|
|
h
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
# TODO: Should we add #to_casting_hash to Hash classs?
|
|
|
|
#class Hash
|
|
#
|
|
# # Convert a Hash to a CastingHash.
|
|
# def to_casting_hash(value_cast=nil, &key_cast)
|
|
# CastingHash.new(self, value_cast, &key_cast)
|
|
# end
|
|
#
|
|
#end
|