Class: SlashedHash
- Includes:
- StandardHashMethodsInRuby
- Defined in:
- lib/hash_magic.rb
Overview
A SlashedHash is a hash whose values can be accessed in the normal manner, or with keys that are slash(‘/’)-separated strings. To get the whole hash as a single flattened level, call SlashedHash#flat. All keys are converted to strings. All end-of-the-chain values are kept in whatever value they are.
s = {'a' => 'b', 'c' => {'d' => :e}}.slashed
s['a'] #=> 'b'
s['c'] #=> {slashed: 'd'=>:e}
s['c']['d'] #=> :e
s['c/d'] #=> :e
Instance Method Summary collapse
-
#==(other) ⇒ Object
:nodoc:.
- #[](key) ⇒ Object
-
#[]=(key, value) ⇒ Object
Same as above, except sets value rather than retrieving it.
-
#clear ⇒ Object
:nodoc:.
-
#delete(key, &block) ⇒ Object
You can use slashed keys here, too.
-
#empty? ⇒ Boolean
:nodoc:.
-
#expand ⇒ Object
Expands the whole hash to Hash objects …
-
#fetch(key, default = :ehisehoah0928309q98y30, &block) ⇒ Object
:nodoc:.
-
#flat ⇒ Object
Gives a list of all keys in all levels in the multi-level hash, joined by slashes.
-
#index(value) ⇒ Object
This gives you the slashed key of the value, no matter where the value is in the tree.
-
#initialize(hsh = {}) ⇒ SlashedHash
constructor
A new instance of SlashedHash.
-
#inspect ⇒ Object
:nodoc:.
-
#keys ⇒ Object
This gives you only the top-level keys, no slashes.
-
#ordered(*keys_in_order) ⇒ Object
Same as ordered! but returns a new SlashedHash object instead of modifying the same.
-
#ordered!(*keys_in_order) ⇒ Object
Sets the SlashedArray as ordered.
-
#rehash ⇒ Object
This is rewritten to mean something slightly different than usual: Use this to restructure the hash, for cases when you end up with an array holding several hashes.
-
#slashed ⇒ Object
:nodoc:.
- #to_string_array ⇒ Object
Constructor Details
#initialize(hsh = {}) ⇒ SlashedHash
Returns a new instance of SlashedHash.
171 172 173 174 175 |
# File 'lib/hash_magic.rb', line 171 def initialize(hsh={}) raise ArgumentError, "must be a hash or array of slashed values" unless hsh.is_a?(Hash) || hsh.is_a?(Array) @constructor = hsh.is_a?(Hash) ? hsh.class : Hash @flat = flatten_to_hash(hsh) end |
Instance Method Details
#==(other) ⇒ Object
:nodoc:
281 282 283 284 285 286 287 288 289 |
# File 'lib/hash_magic.rb', line 281 def ==(other) # :nodoc: if other.is_a?(SlashedHash) @slashed == other.instance_variable_get(:@slashed) elsif other.is_a?(Hash) self == SlashedHash.new(other) else raise TypeError, "Cannot compare #{other.class.name} with SlashedHash" end end |
#[](key) ⇒ Object
Behaves like the usual Hash#[] method, but you can access nested hash values by composing a single key of the traversing keys joined by ‘/’:
hash['c']['d'] # is the same as:
hash['c/d']
182 183 184 185 186 187 188 189 190 191 |
# File 'lib/hash_magic.rb', line 182 def [](key) rg = Regexp.new("^#{key}/?") start_obj = if @constructor == OrderedHash @constructor.new((@flat.instance_variable_get(:@keys_in_order) || []).collect {|e| e.gsub(rg,'')}) else @constructor.new end v = @flat.has_key?(key) ? @flat[key] : self.class.new(@flat.reject {|k,v| !(k == key || k =~ rg)}.inject(start_obj) {|h,(k,v)| h[k.gsub(rg,'')] = v; h}) v.is_a?(self.class) && v.empty? ? nil : v end |
#[]=(key, value) ⇒ Object
Same as above, except sets value rather than retrieving it.
193 194 195 196 197 198 199 200 201 202 |
# File 'lib/hash_magic.rb', line 193 def []=(key,value) @flat.reject! {|k,v| k == key || k =~ Regexp.new("^#{key}/")} if value.is_a?(Hash) flatten_to_hash(value).each do |hk,hv| @flat[key.to_s+'/'+hk.to_s] = hv end else @flat[key.to_s] = value end end |
#clear ⇒ Object
:nodoc:
203 204 205 |
# File 'lib/hash_magic.rb', line 203 def clear # :nodoc: @flat.clear end |
#delete(key, &block) ⇒ Object
You can use slashed keys here, too.
224 225 226 227 228 229 |
# File 'lib/hash_magic.rb', line 224 def delete(key,&block) value = @flat.has_key?(key) ? @flat[key] : self.class.new(@flat.reject {|k,v| !(k == key || k =~ Regexp.new("^#{key}/"))}.inject({}) {|h,(k,v)| h[k.split('/',2)[1]] = v; h}) return block.call(key) if value.is_a?(self.class) && value.empty? && block_given? @flat.keys.reject {|k| !(k == key || k =~ Regexp.new("^#{key}/"))}.each {|k| @flat.delete(k)} return value end |
#empty? ⇒ Boolean
:nodoc:
230 231 232 |
# File 'lib/hash_magic.rb', line 230 def empty? # :nodoc: @flat.empty? end |
#expand ⇒ Object
Expands the whole hash to Hash objects … not useful very often, it seems.
257 258 259 |
# File 'lib/hash_magic.rb', line 257 def inject({}) {|h,(k,v)| h[k] = v.is_a?(SlashedHash) ? v. : v; h} end |
#fetch(key, default = :ehisehoah0928309q98y30, &block) ⇒ Object
:nodoc:
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/hash_magic.rb', line 206 def fetch(key,default=:ehisehoah0928309q98y30,&block) # :nodoc: value = @flat.has_key?(key) ? @flat[key] : self.class.new(@flat.reject {|k,v| !(k == key || k =~ Regexp.new("^#{key}/"))}.inject({}) {|h,(k,v)| h[k.split('/',2)[1]] = v; h}) if value.is_a?(self.class) && value.empty? if default == :ehisehoah0928309q98y30 if block_given? block.call(key) else raise IndexError end value else default end else value end end |
#flat ⇒ Object
Gives a list of all keys in all levels in the multi-level hash, joined by slashes.
{'a'=>{'b'=>'c', 'c'=>'d'}, 'b'=>'c'}.slashed.flat.keys
=> ['a/b', 'a/c', 'b']
253 254 255 |
# File 'lib/hash_magic.rb', line 253 def flat @flat end |
#index(value) ⇒ Object
This gives you the slashed key of the value, no matter where the value is in the tree.
234 235 236 |
# File 'lib/hash_magic.rb', line 234 def index(value) @flat.index(value) end |
#inspect ⇒ Object
:nodoc:
237 238 239 |
# File 'lib/hash_magic.rb', line 237 def inspect # :nodoc: @flat.inspect.insert(1,'slashed: ') end |
#keys ⇒ Object
This gives you only the top-level keys, no slashes. To get the list of slashed keys, do hash.flat.keys
241 242 243 |
# File 'lib/hash_magic.rb', line 241 def keys @flat.inject([]) {|a,(k,v)| a << [k.split('/',2)].flatten[0]; a}.uniq end |
#ordered(*keys_in_order) ⇒ Object
Same as ordered! but returns a new SlashedHash object instead of modifying the same.
267 268 269 |
# File 'lib/hash_magic.rb', line 267 def ordered(*keys_in_order) dup.ordered!(*keys_in_order) end |
#ordered!(*keys_in_order) ⇒ Object
Sets the SlashedArray as ordered. The *keys_in_order must be a flat array of slashed keys that specify the order for each level:
s = {'a'=>{'b'=>'c', 'c'=>'d'}, 'b'=>'c'}.slashed
s.ordered!('b', 'a/c', 'a/b')
s. # => {'b'=>'c', 'a'=>{'c'=>'d', 'b'=>'c'}}
# Note that the expanded hashes will *still* be ordered!
275 276 277 278 279 280 |
# File 'lib/hash_magic.rb', line 275 def ordered!(*keys_in_order) return self if @constructor == OrderedHash @constructor = OrderedHash @flat = @flat.ordered(*keys_in_order) self end |
#rehash ⇒ Object
This is rewritten to mean something slightly different than usual: Use this to restructure the hash, for cases when you end up with an array holding several hashes.
246 247 248 |
# File 'lib/hash_magic.rb', line 246 def rehash # :nodoc: @flat.rehash end |
#slashed ⇒ Object
:nodoc:
263 264 265 |
# File 'lib/hash_magic.rb', line 263 def slashed # :nodoc: self end |
#to_string_array ⇒ Object
260 261 262 |
# File 'lib/hash_magic.rb', line 260 def to_string_array flatten_to_array(flat,[]) end |