class Admin::Stats::HashWithReaders

Helper hash subclass with three purposes:

  1. Give a type to the objects returned, rather than just being Hashes.

  2. Provide attribute readers that fail if the key is missing, to help detect mistakes faster.

  3. Simplify serialization by making all keys strings, not symbols, but still allowing key access by symbol.

Public Class Methods

deep_clear_subclasses(obj) click to toggle source

Convert Hash subclasses into plain hashes for YAML/XML dump. Assumptions:

Hash keys will be strings - don't need to clear them
No custom objects with Hash subclass contents
# File lib/admin/stats/results.rb, line 62
def self.deep_clear_subclasses(obj)
  deep_convert(obj, {}, lambda { Hash.new })
end
deep_convert_hashes(obj) click to toggle source

Convert plain hashes into HashWithReaders Assumptions:

Hash keys will be strings - don't need to convert them
No custom objects with Hash subclass contents
# File lib/admin/stats/results.rb, line 70
def self.deep_convert_hashes(obj)
  deep_convert(obj, {}, lambda { HashWithReaders.new })
end

Private Class Methods

deep_convert(obj, dedup, new_lambda) click to toggle source
# File lib/admin/stats/results.rb, line 75
def self.deep_convert(obj, dedup, new_lambda)
  id = obj.__id__ # used to deduplicate converted copies
  case obj
  when Hash
    return dedup[id] if dedup.has_key? id
    dedup[id] = copy = new_lambda.call
    obj.each {|k,v| copy[k.to_s] = deep_convert(v, dedup, new_lambda)}
    copy
  when Array
    return dedup[id] if dedup.has_key? id
    obj.inject(dedup[id] = []) {|a,v| a << deep_convert(v, dedup, new_lambda)}
  else
    obj # not going to operate on other kinds of objects
  end
end

Public Instance Methods

[](key) click to toggle source

Keys switched from symbols to strings - so, translate for any code already accessing by symbol.

Calls superclass method
# File lib/admin/stats/results.rb, line 15
def [](key); super(key.to_s); end
[]=(key, *args) click to toggle source
Calls superclass method
# File lib/admin/stats/results.rb, line 16
def []=(key, *args); super(key.to_s, *args); end
has_key?(key) click to toggle source
Calls superclass method
# File lib/admin/stats/results.rb, line 17
def has_key?(key); super(key.to_s); end
inspect() click to toggle source
# File lib/admin/stats/results.rb, line 38
def inspect; "#{self.class} #{super}"; end
merge(hash) click to toggle source
# File lib/admin/stats/results.rb, line 18
def merge(hash); self.clone.merge! hash; end
merge!(hash) click to toggle source
# File lib/admin/stats/results.rb, line 19
def merge!(hash)
  hash.each {|k,v| self[k] = v} #ah, but now keys are converted to string.
  self
end
method_missing(sym, *args) click to toggle source

provide readers for keys

Calls superclass method
# File lib/admin/stats/results.rb, line 25
def method_missing(sym, *args)
  # don't screen other things that operate via method_missing
  return super if [:to_ary, :to_json, :to_yaml, :to_xml].include? sym
  key = sym.to_s
  return self[key] if self.has_key? key
  raise NoSuchKey.new("#{self.class} has no key #{sym}: #{self.inspect}")
end
pretty_inspect() click to toggle source
# File lib/admin/stats/results.rb, line 39
def pretty_inspect; "#{self.class} #{super}"; end
respond_to?(sym, *args) click to toggle source
Calls superclass method
# File lib/admin/stats/results.rb, line 32
def respond_to?(sym, *args)
  has_key?(sym) || super
end
to_s() click to toggle source

make classes easily identified in output

# File lib/admin/stats/results.rb, line 37
def to_s; "#{self.class} #{super}"; end