Ruby on rails 将ruby哈希转换为html列表
我正在尝试解析yaml文件,如下所示:Ruby on rails 将ruby哈希转换为html列表,ruby-on-rails,ruby,hash,Ruby On Rails,Ruby,Hash,我正在尝试解析yaml文件,如下所示: a: a1: a2: b: b1: b11: b2: {"a"=>{"a1"=>nil, "a2"=>nil}, "b"=>{"b1"=>{"b11"=>nil}, "b2"=>nil}} 我得到的哈希值如下: a: a1: a2: b: b1: b11: b2: {"a"=>{"a1"=>nil, "a2"=>nil}, "b"=>{"b1"=>{"b1
a:
a1:
a2:
b:
b1:
b11:
b2:
{"a"=>{"a1"=>nil, "a2"=>nil}, "b"=>{"b1"=>{"b11"=>nil}, "b2"=>nil}}
我得到的哈希值如下:
a:
a1:
a2:
b:
b1:
b11:
b2:
{"a"=>{"a1"=>nil, "a2"=>nil}, "b"=>{"b1"=>{"b11"=>nil}, "b2"=>nil}}
我想把它变成一个列表:
%ul
%li a
%ul
%li a1
%li a2
%li b
%ul
%li b1
%ul
%li b11
%li b2
无论散列有多深,我都在尝试寻找最有效的方法
最后我这样做了:
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
现在也准备解析选项。要输出为纯HTML,您只需在
每个
块中执行相同函数的递归调用(或者像我在这里所做的那样将函数用作每个
块):
需要“yaml”
yaml=我已经做了这个:
INDENT = ' ' # use 2 spaces for indentation
def hash_to_haml(hash, level=0)
result = [ "#{INDENT * level}%ul" ]
hash.each do |key,value|
result << "#{INDENT * (level + 1)}%li #{key}"
result << hash_to_haml(value, level + 2) if value.is_a?(Hash)
end
result.join("\n")
end
输出:
%ul
%li a
%ul
%li a1
%li a2
%li b
%ul
%li b1
%ul
%li b11
%li b2
编辑-澄清:
string*n
重复string
n
次
- 使用
array.join
比创建一组字符串并用+
连接它们更有效
这里有一个同时处理HTML和Haml的解决方案。有点罗嗦,但可读性强
class ListMaker
def initialize(hash)
@hash = hash
@indent = " "
@level = 0
@out = []
end
def append(tag,value=nil)
str = @indent * @level + "#{tag}"
str += @tag_space + value unless value.nil?
str += "\n"
@out << str
end
def ul(hash)
open_tag('ul') { li(hash) }
end
def li(hash)
@level += 1
hash.each do |key,value|
open_tag('li',key) { ul(value) if value.is_a?(Hash) }
end
@level -= 1
end
def list
ul(@hash)
@out.join
end
end
class HtmlListMaker < ListMaker
def initialize(hash)
super
@tag_space = ""
end
def open_tag(tag,value=nil,&block)
append("<#{tag}>",value)
yield if block_given?
append("</#{tag}>")
end
end
class HamlListMaker < ListMaker
def initialize(hash)
super
@tag_space = " "
end
def open_tag(tag,value=nil,&block)
append("%#{tag}",value)
yield if block_given?
end
end
require 'yaml'
yaml = <<EOS
a:
a1:
a2:
b:
b1:
b11:
b2:
EOS
hash = YAML.load(yaml) # {"a"=>{"a1"=>nil, "a2"=>nil}, "b"=>{"b1"=>{"b11"=>nil}, "b2"=>nil}}
puts HamlListMaker.new(hash).list
# %ul
# %li a
# %ul
# %li a1
# %li a2
# %li b
# %ul
# %li b1
# %ul
# %li b11
# %li b2
puts HtmlListMaker.new(hash).list
# <ul>
# <li>a
# <ul>
# <li>a1
# </li>
# <li>a2
# </li>
# </ul>
# </li>
# <li>b
# <ul>
# <li>b1
# <ul>
# <li>b11
# </li>
# </ul>
# </li>
# <li>b2
# </li>
# </ul>
# </li>
# </ul>
类ListMaker
def初始化(哈希)
@散列=散列
@缩进=“”
@级别=0
@out=[]
结束
def append(标记,值=nil)
str=@indent*@level+“#{tag}”
str+=@tag_space+值,除非value.nil?
str+=“\n”
@out nil},“b”=>{“b1”=>{“b11”=>nil},“b2”=>nil}
放置HamlListMaker.new(hash.list)
#%ul
#%li a
#%ul
#%li a1
#%li a2
#%li b
#%ul
#%li b1
#%ul
#%li b11
#%li b2
将htmlistMaker.new(hash.list)放入
#
#- a
#
#- a1
#
#- a2
#
#
#
#- b
#
#- b1
#
#- b11
#
#
#
#- b2
#
#
#
#
你能修正你问题的格式吗?对于代码kata来说,这是一个非常好的问题。非常好,但为了让它正常工作,我需要将前3行修改为:def hash_to_html(map)key=map[0]value=map[1]我建议返回值,而不是执行put。这样,该函数可以在其他地方使用(而不仅仅是在控制台上)。@JAlberto:我很困惑:map[0]
和map[1]
在您给出的示例数据中都会返回零。@egarcia:是的,您可以这样做。我认为OP可以很容易地做出改变,如果它适合他的风格。@KenBloom它在这里工作(ruby 1.9)使用示例哈希和doing map[0]map[1]与您的代码我得到一个:ArgumentError:使用每个或map的参数数目错误参见Nakilon回答中关于1个字母的变量名的注释。很好,但此解决方案的问题是,如果您通过HAML::Engine处理生成的输出,它将抱怨非法嵌套:内容不能与%li同时在同一行中给出,也不能嵌套在其中。
%ul
%li a
%ul
%li a1
%li a2
%li b
%ul
%li b1
%ul
%li b11
%li b2
class ListMaker
def initialize(hash)
@hash = hash
@indent = " "
@level = 0
@out = []
end
def append(tag,value=nil)
str = @indent * @level + "#{tag}"
str += @tag_space + value unless value.nil?
str += "\n"
@out << str
end
def ul(hash)
open_tag('ul') { li(hash) }
end
def li(hash)
@level += 1
hash.each do |key,value|
open_tag('li',key) { ul(value) if value.is_a?(Hash) }
end
@level -= 1
end
def list
ul(@hash)
@out.join
end
end
class HtmlListMaker < ListMaker
def initialize(hash)
super
@tag_space = ""
end
def open_tag(tag,value=nil,&block)
append("<#{tag}>",value)
yield if block_given?
append("</#{tag}>")
end
end
class HamlListMaker < ListMaker
def initialize(hash)
super
@tag_space = " "
end
def open_tag(tag,value=nil,&block)
append("%#{tag}",value)
yield if block_given?
end
end
require 'yaml'
yaml = <<EOS
a:
a1:
a2:
b:
b1:
b11:
b2:
EOS
hash = YAML.load(yaml) # {"a"=>{"a1"=>nil, "a2"=>nil}, "b"=>{"b1"=>{"b11"=>nil}, "b2"=>nil}}
puts HamlListMaker.new(hash).list
# %ul
# %li a
# %ul
# %li a1
# %li a2
# %li b
# %ul
# %li b1
# %ul
# %li b11
# %li b2
puts HtmlListMaker.new(hash).list
# <ul>
# <li>a
# <ul>
# <li>a1
# </li>
# <li>a2
# </li>
# </ul>
# </li>
# <li>b
# <ul>
# <li>b1
# <ul>
# <li>b11
# </li>
# </ul>
# </li>
# <li>b2
# </li>
# </ul>
# </li>
# </ul>