lib/stacker_bee/rash.rb
require 'forwardable'
require 'stacker_bee/utilities'
module StackerBee
class Rash
extend Forwardable
include Utilities
def_delegators :@hash, *[
:default, :default_proc, :each_value, :empty?, :has_value?, :hash,
:length, :size, :value?, :values, :assoc, :each, :each_key, :each_pair,
:flatten, :invert, :keys, :key, :merge, :rassoc, :to_a, :to_h, :to_hash
]
def initialize(hash = {}, preferred_keys = [])
@hash = {}
save_preferred_keys preferred_keys
hash.each_pair do |key, value|
@hash[convert_key(key)] = convert_value(value)
end
@hash.freeze
end
def ==(other)
case other
when Rash
super || @hash == other.to_hash
when Hash
self == Rash.new(other)
else
super
end
end
def select(*args, &block)
Rash.new(@hash.select(*args, &block))
end
def reject(*args, &block)
Rash.new(@hash.reject(*args, &block))
end
def values_at(*keys)
@hash.values_at(*keys.map { |key| convert_key(key) })
end
def fetch(key, *args, &block)
@hash.fetch(convert_key(key), *args, &block)
end
def [](key)
@hash[convert_key(key)]
end
def key?(key)
@hash.key?(convert_key(key))
end
alias_method :include?, :key?
alias_method :has_key?, :key?
alias_method :member?, :key?
def to_hash
self.class.deep_dup(@hash)
end
def inspect
"#<#{self.class} #{@hash}>"
end
alias_method :to_s, :inspect
protected
def self.deep_dup(hash)
hash.dup.tap do |duplicate|
duplicate.each_pair do |key, value|
duplicate[key] = deep_dup(value) if value.is_a?(Hash)
end
end
end
def convert_key(key)
if key.is_a?(Numeric)
key
elsif preferred_key_format?(key)
preferred_key_format(key)
else
uncase(key)
end
end
def save_preferred_keys(keys)
@preferred_keys = keys.each_with_object({}) do |key, mapping|
mapping[uncase(key)] = key
end
end
def preferred_key_format?(key)
@preferred_keys.key?(uncase(key))
end
def preferred_key_format(key)
@preferred_keys[uncase(key)]
end
def convert_value(value)
case value
when Hash
Rash.new(value)
when Array
value.map { |item| convert_value(item) }
else
value
end
end
end
end