Skip to content

Instantly share code, notes, and snippets.

@semenyukdmitry
Forked from potatosalad/hashquiz.rb
Created August 15, 2018 13:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save semenyukdmitry/a71277b92b5db51cf94250cbb1a6456a to your computer and use it in GitHub Desktop.
Save semenyukdmitry/a71277b92b5db51cf94250cbb1a6456a to your computer and use it in GitHub Desktop.
Ruby quiz for convert hash "dot paths" into actual hash hierarchy.
#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('/')
== 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