Лучший способ красиво напечатать хеш

169

У меня есть большой хэш с вложенными массивами и хэшами. Я хотел бы просто распечатать его, чтобы он был «читабельным» для пользователя.

Я хотел бы, чтобы это было похоже на to_yaml - это довольно читабельно - но все еще слишком технологично.

В конечном счете, это будут конечные пользователи, которым нужно читать эти блоки данных, поэтому их нужно аккуратно отформатировать.

Какие-либо предложения?

Адам О'Коннор
источник
онлайн утилита jsonviewer.stack.hu . Однако он не работает должным образом для синтаксиса хэш-ракеты.
Амит Патель

Ответы:

256
require 'pp'
pp my_hash

Используйте, ppесли вам нужно встроенное решение и просто хотите разумные разрывы строк.

Используйте awesome_print, если вы можете установить гем. (В зависимости от ваших пользователей, вы можете использовать index:falseопцию, чтобы отключить отображение индексов массива.)

Phrogz
источник
pp это хорошо, но очень жаль, что невозможно ограничить глубину.
аким
95

Если у вас есть JSON, я рекомендую, JSON.pretty_generate(hash)потому что он проще, чем awesome_print , отлично выглядит в preтеге и позволяет легко копировать с веб-страницы. (См. Также: Как я могу «красиво» отформатировать вывод JSON в Ruby on Rails? )

Дэвид Дж.
источник
Этот ответ будет полезен из реального примера
Трэвис Медведь
@TravisBear Есть пример выходных данных, если вы нажмете ссылку «см. Также» в моем ответе. В частности, я рекомендую этот ответ: stackoverflow.com/a/1823885/109618
Дэвид Дж.
8
Это было быputs JSON.pretty_generate(hash)
Жоэлуи
Если вам нужно создать JSON, позвольте мне порекомендовать мою собственную (бесплатную, OSS, без рекламы) библиотеку для создания симпатичных JSON из Ruby или JS: NeatJSON (Ruby) и NeatJSON (Online / JS)
Phrogz
Извините, теперь я понимаю, что pretty_generate принимает объект Ruby, а не текст JSON.
Тони
26

Другое решение, которое работает для меня лучше, чем ppили awesome_print:

require 'pry' # must install the gem... but you ALWAYS want pry installed anyways
Pry::ColorPrinter.pp(obj)
Алекс Д
источник
2
Обратите внимание, что Pry::ColorPrinter.pp(obj)запись в стандартном формате, но может принимать дополнительные параметры, включая пункт назначения. НравитсяPry::ColorPrinter.pp(obj, a_logger)
Эрик Урбан
Я удивлен, что это не лучше задокументировано: я всегда использую pry в качестве консоли Rails, и я долго искал, как подключиться к его симпатичному принтеру, не используя другой драгоценный камень. Проголосовал, потому что это решение, наконец, положило конец моим долгим поискам. :-)
волшебник
20

Если у вас нет необычного действия с самоцветом, но есть JSON, эта строка CLI будет работать с хешем:

puts JSON.pretty_generate(my_hash).gsub(":", " =>")

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

  :key2 => "value2",

  :key3 => "value3"
}
Ник Швадерер
источник
8
Понижено, потому что это испортит любые ключи и значения, содержащие ":"
thomax
1
Это также не относится к нулю (JSON) против ноля (Ruby).
Rennex
1
Все еще удобно для большинства ситуаций.
Аврам
1
Не могу поверить в это три года спустя! Спасибо @Abram. :) Это не самое элегантное решение в мире, но оно работает в крайнем случае.
Ник
4

Используйте ответы выше, если вы печатаете для пользователей.

Если вы хотите распечатать его только для себя в консоли, я предлагаю использовать pry gem вместо irb. Помимо красивой печати, у pry также есть много других функций (проверьте Railscast ниже)

Gem Install Pry

И проверьте этот Railscast:

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

Абдо
источник
3

Это легко сделать с помощью 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
}
грубее
источник
1

Используя Pry, вам просто нужно добавить следующий код в ~ / .pryrc:

require "awesome_print"
AwesomePrint.pry!
bartoindahouse
источник
1

Из всех драгоценных камней, которые я пробовал, show_datagem работал лучше всего для меня, теперь я широко использую его для регистрации хэшей params в Rails почти все время

Dr.Strangelove
источник
0

Для больших вложенных хэшей этот скрипт может быть полезен для вас. Он печатает вложенный хеш в хорошем синтаксисе типа 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) всех значений конечного уровня вложенного хэша.

swilgosz
источник
0

Вот еще один подход с использованием 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)

саман
источник
0

В рельсах

Если тебе надо

  • "довольно печатный" хэш
  • например, Rails.logger
  • что, в частности, работает inspect на объектах в Hash
    • что полезно, если вы переопределяете / определяете 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. Таким образом, не нужно никаких драгоценных камней и не требуется преобразование в JSON.

Не в рельсах

Если вы не в 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}

Полный пример

pretty_inspectПример большого старого хэша из моего проекта с отредактированным текстом для моего проверенного объекта:

{<***::******************[**:****, ************************:****]********* * ****** ******************** **** :: *********** - *** ******* *********>=>
  {: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=>
                            ["***** ******* ******",
                             "***** ******* ******"]}}}}]}}]}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - ********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}}]}}]}}
pdobb
источник
-4

В Rails массивы и хэши в Ruby имеют встроенные функции to_json. Я бы использовал JSON только потому, что он хорошо читается в веб-браузере, например, в Google Chrome.

При этом, если вы обеспокоены тем, что это выглядит слишком «технологично», вы, вероятно, должны написать свою собственную функцию, которая заменяет фигурные скобки и квадратные скобки в ваших хешах и массивах пробелами и другими символами.

Посмотрите функцию gsub для очень хорошего способа сделать это. Продолжайте играть с разными персонажами и разным количеством пробелов, пока не найдете что-то привлекательное. http://ruby-doc.org/core-1.9.3/String.html#method-i-gsub

Sid
источник
7
Массивы и хэши не имеют встроенного метода to_json, они добавляются ActiveSupport из Rails.
Том Де Леу
Это даже хуже, чем обычно. Irb / pry:{"programming_language":{"ruby":{},"python":{}}}
Darek Nędza
ОП не исключил Rails
Уилл Шеппард