Skip to content

Instantly share code, notes, and snippets.

@rklemme
Created May 28, 2010 08:51
Show Gist options
  • Select an option

  • Save rklemme/416922 to your computer and use it in GitHub Desktop.

Select an option

Save rklemme/416922 to your computer and use it in GitHub Desktop.
# This class works as a proxy for an instance
# and presents it as Hash.
class InstanceHash
include Enumerable
def initialize(obj, default_val = nil, &default_proc)
@obj = obj
@default = default_val
@default_proc = default_proc || lambda {|h,k| @default}
end
def size
keys.size
end
def empty?
keys.empty?
end
def keys
@obj.instance_variables
end
def values
keys.map {|iv| get_val(iv)}
end
def has_key? k
check_key(normalize(k))
end
alias key? has_key?
def has_value? v
keys.any? {|iv| v.eql? get_val(iv)}
end
alias value? has_value?
def each_pair
keys.each do |iv|
yield iv, get_val(iv)
end
self
end
alias each each_pair
def each_key(&b)
keys.each(&b)
self
end
def each_value
keys.each do |iv|
yield get_val(iv)
end
self
end
def fetch(key, &fallback)
iv = normalize(key)
if check_key(iv)
get_val(iv)
elsif fallback
fallback[iv]
else
raise KeyError, 'key not found'
end
end
def [] key
fetch key do |iv|
@default_proc[self, iv]
end
end
def []= key, val
@obj.instance_variable_set(normalize(key), val)
end
def assoc key
iv = normalize(key)
check_key(iv) && [iv, get_val(iv)]
end
def rassoc val
each_pair do |iv, v|
return [iv, v] if val.eql? v
end
nil
end
private
# check a key
# iv must be normalized
def check_key(iv)
@obj.instance_variable_defined? iv
end
# get a value
# iv must be normalized
def get_val(iv)
@obj.instance_variable_get(iv)
end
# Convert a String or Symbol into a proper
# ivar name
def normalize(var_name)
case var_name
when /\A@/ # covers String and Symbol
var_name
when String,Symbol
:"@#{var_name}"
else
raise ArgumentError, "Not a valid instance variable key: %p" % var_name
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment