我有一个大哈希嵌套数组和哈希。我想简单地打印出来,所以它'可读'的用户。

我希望它有点像to_yaml -这是相当可读的-但仍然太高科技看起来。

最终需要读取这些数据块的将是最终用户,因此它们需要被清晰地格式化。

有什么建议吗?


在Rails中,Ruby中的数组和哈希有内置的to_json函数。我会使用JSON,因为它在web浏览器中是非常可读的,例如谷歌Chrome。

也就是说,如果你担心它看起来太“科技”,你可能应该写自己的函数,用空格和其他字符替换散列和数组中的花括号和方括号。

在gsub函数中找到一个很好的方法。继续使用不同的字符和不同数量的空白,直到你找到一些看起来有吸引力的东西。http://ruby-doc.org/core-1.9.3/String.html#method-i-gsub


require 'pp'
pp my_hash

如果你需要一个内置的解决方案,只是想要合理的换行,可以使用pp。

如果可以安装gem,请使用awesome_print。(取决于你的用户,你可能希望使用index:false选项来关闭显示数组下标。)


如果你有JSON,我推荐JSON.pretty_generate(散列),因为它比awesome_print更简单,在pre标签中看起来很棒,并且允许轻松地从网页复制。(请参见:如何在Ruby on Rails中“漂亮”地格式化JSON输出?)


如果要打印给用户,请使用上面的答案。

如果你只想在控制台为自己打印,我建议使用撬宝石而不是irb。除了漂亮的印刷,撬还有很多其他功能(查看下面的railscast)

宝石安装撬

看看这个铁路广播:

http://railscasts.com/episodes/280-pry-with-rails


使用Pry,你只需要添加以下代码到你的~/.pryrc:

require "awesome_print"
AwesomePrint.pry!

另一个解决方案比pp或awesome_print更适合我:

require 'pry' # must install the gem... but you ALWAYS want pry installed anyways
Pry::ColorPrinter.pp(obj)

在我尝试的所有宝石中,show_data宝石对我来说工作得最好,我现在广泛地使用它来记录Rails中的参数散列


如果你没有任何花哨的宝石操作,但有JSON,这个CLI行将适用于哈希:

把JSON.pretty_generate (my_hash)。Gsub (":", " =>")

#=>
{
  :key1 => "value1",

  :key2 => "value2",

  :key3 => "value3"
}

下面是使用json和rouge的另一种方法:

require 'json'
require 'rouge'

formatter = Rouge::Formatters::Terminal256.new
json_lexer = Rouge::Lexers::JSON.new

puts formatter.format(json_lexer.lex(JSON.pretty_generate(JSON.parse(response))))

(解析来自RestClient的响应)


如果你相信你的键是正常的,json很容易做到:

JSON.pretty_generate(a: 1, 2 => 3, 3 => nil).
  gsub(": null", ": nil").
  gsub(/(^\s*)"([a-zA-Z][a-zA-Z\d_]*)":/, "\\1\\2:"). # "foo": 1 -> foo: 1
  gsub(/(^\s*)(".*?"):/, "\\1\\2 =>") # "123": 1 -> "123" => 1

{
  a: 1,
  "2" => 3,
  "3" => nil
}

对于大型嵌套散列,此脚本可能对您有帮助。它以类似python的漂亮语法打印嵌套散列,仅缩进以方便复制。

module PrettyHash
  # Usage: PrettyHash.call(nested_hash)
  # Prints the nested hash in the easy to look on format
  # Returns the amount of all values in the nested hash

  def self.call(hash, level: 0, indent: 2)
    unique_values_count = 0
    hash.each do |k, v|
      (level * indent).times { print ' ' }
      print "#{k}:"
      if v.is_a?(Hash)
        puts
        unique_values_count += call(v, level: level + 1, indent: indent)
      else
        puts " #{v}"
        unique_values_count += 1
      end
    end
    unique_values_count
  end
end

使用示例:

  h = {a: { b: { c: :d }, e: :f }, g: :i }
  PrettyHash.call(h)

a:
  b:
    c: d
  e: f
g: i
=> 3

返回值是嵌套散列的所有结束级值的计数(3)。


在Rails中

如果你需要

一个“漂亮的打印”哈希 例如,Rails.logger 具体来说,就是对散列中的对象运行inspect 这是有用的,如果你覆盖/定义检查方法在你的对象,就像你应该

... 那么这个工作很棒!(如果你的Hash对象越大,嵌套越多,效果会更好。)

logger.error my_hash.pretty_inspect

例如:

class MyObject1
  def inspect
    "<#{'*' * 10} My Object 1 #{'*' * 10}>"
  end
end

class MyObject2
  def inspect
    "<#{'*' * 10} My Object 2 #{'*' * 10}>"
  end
end

my_hash = { a: 1, b: MyObject1.new, MyObject2.new => 3 }

Rails.logger.error my_hash
# {:a=>1, :b=><********** My Object 1 **********>, <********** My Object 2 **********>=>3}

# EW! ^

Rails.logger.error my_hash.pretty_inspect
# {:a=>1,
#  :b=><********** My Object 1 **********>,
#  <********** My Object 2 **********>=>3}

pretty_inspect来自PrettyPrint, rails默认包含PrettyPrint。因此,不需要宝石,也不需要转换为JSON。

不在Rails中

如果你没有使用Rails,或者由于某些原因上述操作失败,请先尝试使用require "pp"。例如:

require "pp"  # <-----------

class MyObject1
  def inspect
    "<#{'*' * 10} My Object 1 #{'*' * 10}>"
  end
end

class MyObject2
  def inspect
    "<#{'*' * 10} My Object 2 #{'*' * 10}>"
  end
end

my_hash = { a: 1, b: MyObject1.new, MyObject2.new => 3 }

puts my_hash
# {:a=>1, :b=><********** My Object 1 **********>, <********** My Object 2 **********>=>3}

# EW! ^

puts my_hash.pretty_inspect
# {:a=>1,
#  :b=><********** My Object 1 **********>,
#  <********** My Object 2 **********>=>3}

完整示例

大ol' pretty_checked哈希示例从我的项目与项目特定的文本从我的检查对象编校:

{<***::******************[**:****, ************************:****]********* * ****** ******************** **** :: *********** - *** ******* *********>=>
  {:errors=>
    ["************ ************ ********** ***** ****** ******** ***** ****** ******** **** ********** **** ***** ***** ******* ******",
     "************ ************ ********** ***** ****** ******** ***** ****** ******** **** ********** is invalid",
     "************ ************ ********** ***** ****** ******** is invalid",
     "************ ************ ********** is invalid",
     "************ ************ is invalid",
     "************ is invalid"],
   :************=>
    [{<***::**********[**:****, *************:**, ******************:*, ***********************:****] :: **** **** ****>=>
       {:************=>
         [{<***::***********[**:*****, *************:****, *******************:**]******* :: *** - ******* ***** - *>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: *** - *>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ********* - *>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ********** - ********** *>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ******** - *>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: **** - *******>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: *** - ********** ***** - *>=>
            {}}]}},
     {<***::**********[**:****, *************:**, ******************:*, ***********************:****] ******************** :: *** - *****>=>
       {:errors=>
         ["************ ********** ***** ****** ******** ***** ****** ******** **** ********** **** ***** ***** ******* ******",
          "************ ********** ***** ****** ******** ***** ****** ******** **** ********** is invalid",
          "************ ********** ***** ****** ******** is invalid",
          "************ ********** is invalid",
          "************ is invalid"],
        :************=>
         [{<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - ********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - ********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *******>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]*********** :: ****>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *******>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *******>=>
            {:errors=>
              ["********** ***** ****** ******** ***** ****** ******** **** ********** **** ***** ***** ******* ******",
               "********** ***** ****** ******** ***** ****** ******** **** ********** is invalid",
               "********** ***** ****** ******** is invalid",
               "********** is invalid"],
             :**********************=>
              [{<***::*******************[**:******, ************************:***]****-************ ******************** ***: * :: *** - ***** * ****** ** - ******* * **: *******>=>
                 {:errors=>
                   ["***** ****** ******** **** ********** **** ***** ***** ******* ******",
                    "***** ****** ******** **** ********** is invalid"],
                  :***************=>
                   [{<***::********************************[**:******, *************:******, ***********:******, ***********:"************ ************"]** * *** * ****-******* * ******** * ********* ******************** *********************: ***** :: "**** *" -> "">=>
                      {:errors=>["**** ***** ***** ******* ******"],
                       :**********=>
                        {<***::*****************[**:******, ****************:["****** ***", "****** ***", "****** ****", "******* ***", "******* ****", "******* ***", "****"], **:""] :: "**** *" -> "">=>
                          {:errors=>
                            ["***** ******* ******",
                             "***** ******* ******"]}}}}]}}]}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - ********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}}]}}]}}

我是通过一个搜索引擎来寻找一种以人类可读的格式打印哈希值给最终用户的方法的——特别是键中带有下划线的哈希值。

以下是我最终使用Rails 6.0.3.4所做的事情:

hash.map do |key, val|
  key.to_s.humanize + ': ' + val.to_s
end.join('; ')

# Turns {:foo_bar => 'baz', :fee_ber => :bez} into 'Foo bar: Baz; Fee ber: Bez'.

使用纯Ruby的漂亮打印散列(没有宝石)

我看到这个帖子是为了自己解决这个问题。

我有一个大的哈希,我想让漂亮,但我需要保持在ruby哈希符号,而不是JSON。

这是代码+示例

使用pretty_generate来获得格式化好的JSON字符串。 将所有JSON键替换为symbol: equivalent

puts JSON.pretty_generate(result)
         .gsub(/(?:\"|\')(?<key>[^"]*)(?:\"|\')(?=:)(?:\:)/) { |_|
              "#{Regexp.last_match(:key)}:"
          }

示例JSON

{
  "extensions": {
    "heading": "extensions",
    "take": "all",
    "array_columns": [
      "name"
    ]
  },
  "tables": {
    "heading": "tables",
    "take": "all",
    "array_columns": [
      "name"
    ]
  },
  "foreign_keys": {
    "heading": "foreign_keys",
    "take": "all",
    "array_columns": [
      "name"
    ]
  },
  "all_indexes": {
    "heading": "all_indexes",
    "take": "all",
    "array_columns": [
      "name"
    ]
  },
  "keys": {
    "heading": "keys",
    "take": "all",
    "array_columns": [
      "name"
    ]
  }
}

Ruby哈希示例

{
  extensions: {
    heading: "extensions",
    take: "all",
    array_columns: [
      "name"
    ]
  },
  tables: {
    heading: "tables",
    take: "all",
    array_columns: [
      "name"
    ]
  },
  foreign_keys: {
    heading: "foreign_keys",
    take: "all",
    array_columns: [
      "name"
    ]
  },
  all_indexes: {
    heading: "all_indexes",
    take: "all",
    array_columns: [
      "name"
    ]
  },
  keys: {
    heading: "keys",
    take: "all",
    array_columns: [
      "name"
    ]
  }
}