Created
December 31, 2010 04:36
-
-
Save potatosalad/760726 to your computer and use it in GitHub Desktop.
Ruby quiz for convert hash "dot paths" into actual hash hierarchy.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#require 'rubygems' | |
require 'pp' | |
#require 'ap' # Awesome Print | |
class Object | |
# expects [ [ symbol, *args ], ... ] | |
def recursive_send(*args) | |
args.inject(self) { |obj, m| obj.send(m.shift, *m) } | |
end | |
end | |
class Hash | |
# auto creates children | |
# from: http://rubyworks.github.com/facets/doc/api/core/Hash.html | |
def self.autonew(*args) | |
leet = lambda { |hsh, key| hsh[key] = new( &leet ) } | |
new(*args,&leet) | |
end | |
def explode(divider = '.') | |
h = Hash.autonew | |
for k,v in self.dup | |
tree = k.split(divider).map { |x| [ :[], x ] } | |
tree.push([ :[]=, tree.pop[1], v ]) | |
h.recursive_send(*tree) | |
end | |
h | |
end | |
def implode(divider = '.') | |
h = Hash.new | |
self.dup.each_path(divider) do |path, value| | |
h[path] = value | |
end | |
h | |
end | |
# each_path method for multi-dimensional Hash | |
# from: http://snippets.dzone.com/posts/show/3565 | |
def each_path(divider = '.') | |
raise ArgumentError unless block_given? | |
self.class.each_path(self, '', divider) { |path, object| yield path, object } | |
end | |
protected | |
def self.each_path(object, path = '', divider = '.', &block) | |
if object.is_a?(Hash) | |
object.each do |key, value| | |
self.each_path value, "#{path}#{path.empty? ? '' : divider}#{key}", divider, &block | |
end | |
else | |
yield path, object | |
end | |
end | |
end | |
params = {} | |
params['foo.bar.aaa'] = 'AAA' | |
params['foo.bar.aab'] = 'AAB' | |
params['foo.bar.aac'] = 'AAC' | |
params['foo.bla.aaa'] = '111' | |
params['foo.bla.aab'] = '112' | |
params['foo.bla.aac'] = '113' | |
params['abc.def.foo.bar.aaa'] = '000' | |
params['abc.def.foo.bar.aab'] = '001' | |
params['abc.def.foo.bar.aac'] = '002' | |
puts "== Params ==" | |
#ap params | |
pp params | |
puts "\n== Params (exploded) ==" | |
#ap params.explode | |
pp params.explode | |
puts "\n== Paths from params (exploded) ==" | |
paths = [] | |
params.explode.each_path { |path, value| paths << [ path, value ] } | |
#ap paths | |
pp paths | |
puts "\n== Example of implode with / as divider ==" | |
#ap params.explode.implode('/') | |
pp params.explode.implode('/') | |
puts "\n== Example of implode with reverse explode ==" | |
#ap params.explode.implode('/').explode('/') | |
pp params.explode.implode('/').explode('/') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
== Params == | |
{ | |
"foo.bar.aaa" => "AAA", | |
"foo.bar.aab" => "AAB", | |
"foo.bar.aac" => "AAC", | |
"foo.bla.aaa" => "111", | |
"foo.bla.aab" => "112", | |
"foo.bla.aac" => "113", | |
"abc.def.foo.bar.aaa" => "000", | |
"abc.def.foo.bar.aab" => "001", | |
"abc.def.foo.bar.aac" => "002" | |
} | |
== Params (exploded) == | |
{ | |
"foo" => { | |
"bar" => { | |
"aaa" => "AAA", | |
"aab" => "AAB", | |
"aac" => "AAC" | |
}, | |
"bla" => { | |
"aaa" => "111", | |
"aab" => "112", | |
"aac" => "113" | |
} | |
}, | |
"abc" => { | |
"def" => { | |
"foo" => { | |
"bar" => { | |
"aaa" => "000", | |
"aab" => "001", | |
"aac" => "002" | |
} | |
} | |
} | |
} | |
} | |
== Paths from params (exploded) == | |
[ | |
[0] [ | |
[0] "foo.bar.aaa", | |
[1] "AAA" | |
], | |
[1] [ | |
[0] "foo.bar.aab", | |
[1] "AAB" | |
], | |
[2] [ | |
[0] "foo.bar.aac", | |
[1] "AAC" | |
], | |
[3] [ | |
[0] "foo.bla.aaa", | |
[1] "111" | |
], | |
[4] [ | |
[0] "foo.bla.aab", | |
[1] "112" | |
], | |
[5] [ | |
[0] "foo.bla.aac", | |
[1] "113" | |
], | |
[6] [ | |
[0] "abc.def.foo.bar.aaa", | |
[1] "000" | |
], | |
[7] [ | |
[0] "abc.def.foo.bar.aab", | |
[1] "001" | |
], | |
[8] [ | |
[0] "abc.def.foo.bar.aac", | |
[1] "002" | |
] | |
] | |
== Example of implode with / as divider == | |
{ | |
"foo/bar/aaa" => "AAA", | |
"foo/bar/aab" => "AAB", | |
"foo/bar/aac" => "AAC", | |
"foo/bla/aaa" => "111", | |
"foo/bla/aab" => "112", | |
"foo/bla/aac" => "113", | |
"abc/def/foo/bar/aaa" => "000", | |
"abc/def/foo/bar/aab" => "001", | |
"abc/def/foo/bar/aac" => "002" | |
} | |
== Example of implode with reverse explode == | |
{ | |
"foo" => { | |
"bar" => { | |
"aaa" => "AAA", | |
"aab" => "AAB", | |
"aac" => "AAC" | |
}, | |
"bla" => { | |
"aaa" => "111", | |
"aab" => "112", | |
"aac" => "113" | |
} | |
}, | |
"abc" => { | |
"def" => { | |
"foo" => { | |
"bar" => { | |
"aaa" => "000", | |
"aab" => "001", | |
"aac" => "002" | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I needed the
#explode
method so I implemented it as a function without the core extensionsNote: I'm using some ruby 2.x features, like keyword args and
Array#to_h
but they could be factored out easily.https://gist.github.com/arronmabrey/185d042e5219be203578