Ruby on rails 将ruby哈希转换为html列表

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

我正在尝试解析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"=>{"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>