1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
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
|