I'm trying to parse a yaml file like this:
a:
a1:
a2:
b:
b1:
b11:
b2:
i get a hash like this:
{"a"=>{"a1"=>nil, "a2"=>nil}, "b"=>{"b1"=>{"b11"=>nil}, "b2"=>nil}}
and i want to turn it to a list:
%ul
%li a
%ul
%li a1
%li a2
%li b
%ul
%li b1
%ul
%li b11
%li b2
I'm trying to search the most efficent way doesn't matter how deep is the hash
Finally i did in this way:
KeyWords = %w(url)
# Convert a multilevel hash into haml multilevel tree
# Special KeyWords
# url : item url
def hash_to_haml(hash, url = nil)
haml_tag(:ul) do
hash.each do |key, value|
unless KeyWords.include?(key)
url = get_url(key, value)
haml_tag(:li) do
haml_tag(:a, :href => url ) do
haml_concat(key)
end
hash_to_haml(value) if value.is_a?(Hash) && !value.empty?
end
end
end
end
end
private
def get_url(key, hash)
# TODO: get full url from hash
if hash.nil?
"/#{key}"
else
hash.include?("url") ? hash.delete("url") : "/#{key}"
end
end
Now is prepared to parse options too.
I've done this one:
Usage:
Output:
EDIT- Clarifications:
string * n
repeatsstring
n
times.array.join
is more efficient than creating a bunch of strings and joining them with+
.To output to plain HTML you can just perform a recursive call of the same function within a
each
block (or use the function as theeach
block as I have done here):To output to whatever templating language you're using (HAML, I think), we need to keep track of indentation, so things are a little more complicated -- we're going to use a function that takes the indenting depth as a parameter, and returns another function to be called on each key/value pair that prints that key/value pair (recursively) with appropriate indentation. (In functional programming, calling a function this way is called a "partially applied function", and they're usually a little easier to define than in Ruy.)
Here's a solution that does both HTML and Haml. Slightly wordy, but readable.