module Eymiha # The MethodicHash is some method_missing magic that uses method names as hash # keys, so hash assignment and lookup appear to be attribute writing and # reading. For instance, if # # mh = MethodicHash.new # mh['four'] = 'iv' # mh[:seven] = 'vii' # mh.eighteen = 'xviii' # # then # # mh['four'] ---> 'iv' # mh[:four] ---> 'iv' # mh.four ---> 'iv' # mh['seven'] ---> 'vii' # mh[:seven] ---> 'vii' # mh.seven ---> 'vii' # mh['eighteen'] ---> 'xviii' # mh[:eighteen] ---> 'xviii' # mh.eighteen ---> 'xviii' # # This allows access to simply declared facts to be embedded in Ruby code and # leverages the possibility of hashing procs. # # Note that if the hash uses anything but strings or symbols as keys, the # magic stands a good chance of failing, raising an error or acting in a # bizarre manner. Note also that methods of the Hash cannot be used as # 'attribute' names. class MethodicHash < Hash # Try to look up using a key directly, or if that fails as a string, or as # a symbol as last resort. If a symbol conversion doesn't exists, rescue # with a nil. def [](key) begin super(key) || super(key.to_s) || super(key.to_sym) rescue nil end end # Deletes and returns the key-value pairs from hash whose keys are equal to # key.to_s or key.to_sym. If both key.to_s and key.to_sym are in the hash, # then both values are returned in an Array, respectively. If neither key is # found, the delete is deferred to the Hash. def delete(key,&block) values = [key.to_s, key.to_sym].collect {|k| super(k){ nil } }.compact case values.size when 0 then super(key,&block) when 1 then values[0] when 2 then values end end # A missing method is assummed to be the assignment of a value of a key, or # the lookup of a value with a key. def method_missing(method,*args) string = method.to_s if string[string.length-1,1] == '=' self[string[0,string.length-1].to_sym] = args[0] else self[method] end end end end