Найкращий спосіб красивого друку хешу


169

У мене великий хеш із вкладеними масивами та хешами. Я хотів би просто роздрукувати його, щоб він був "читабельним" для користувача.

Я хотів би, щоб це було на зразок to_yaml - це досить читабельно - але все ще занадто технологічно виглядає.

Зрештою, це будуть кінцеві користувачі, яким потрібно прочитати ці фрагменти даних, тому їх потрібно чітко відформатувати.

Будь-які пропозиції?



онлайн-утиліта jsonviewer.stack.hu . Однак він не працює належним чином для синтаксису хеш-ракет.
Аміт Патель

Відповіді:


256
require 'pp'
pp my_hash

Використовуйте, ppякщо вам потрібно вбудоване рішення і просто хочете розумних розривів рядків.

Використовуйте awesome_print, якщо ви можете встановити дорогоцінний камінь. (Залежно від користувачів, ви можете скористатися index:falseопцією, щоб вимкнути показ індексів масиву.)


pp приємно, але дуже шкода, що глибину не можна обмежувати.
акім

95

Якщо у вас є JSON, рекомендую, JSON.pretty_generate(hash)оскільки він простіший, ніж awesome_print , чудово виглядає в preтезі та дозволяє легко копіювати з веб-сторінки. (Дивіться також: Як я можу "гарненько" відформатувати вихід JSON у Ruby on Rails? )


Ця відповідь отримає користь із фактичного прикладу
Ведмідь Тревіс

@TravisBear Є приклад виводу, якщо ви натиснете посилання "див. Також" у моїй відповіді. Я рекомендую цю відповідь, зокрема: stackoverflow.com/a/1823885/109618
David J.

8
Було бputs JSON.pretty_generate(hash)
joeloui

Якщо вам потрібно створити 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

Використовуйте відповіді вище, якщо ви друкуєте для користувачів.

Якщо ви хочете роздрукувати його для себе лише в консолі, я пропоную використовувати дорогоцінний камінь замість irb. Окрім гарного друку, pry має також безліч інших особливостей (перевірте рейліскад нижче)

gem встановити pry

І перевірте цю рейкову передачу:

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!

1

З усіх дорогоцінних каменів, які я спробував, show_dataдорогоцінний камінь працював найкраще для мене, я зараз його широко використовую для того, щоб весь час записувати хеш-парами в Rails.


0

Для великих вкладених хешей цей сценарій може бути корисним для вас. Він друкує вкладений хеш у приємному синтаксисі python / like з лише відступів, щоб полегшити його копіювання.

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) усіх кінцевих значень вкладеного хеша.


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 на об'єктах у хеші
    • що корисно, якщо ви переосмислите / визначите 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 , який рейли включає за замовчуванням. Отже, жодні дорогоцінні камені не потрібні і не потрібні перетворення на 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=>
                            ["***** ******* ******",
                             "***** ******* ******"]}}}}]}}]}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - ********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}}]}}]}}

-4

Під Rails масиви та хеші в Ruby мають вбудовані функції to_json. Я б використовував JSON лише тому, що він легко читається у веб-браузері, наприклад, Google Chrome.

Якщо говорити, якщо ви переймаєтесь виглядом занадто "технологічного вигляду", ви, ймовірно, повинні написати свою функцію, яка замінює фігурні дужки та квадратні дужки у ваших хешах та масивах на пробіли та інші символи.

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


7
Масиви та хеші не мають вбудованого методу to_json, це додає ActiveSupport від Rails.
Том Де Леу

Це навіть гірше, ніж звичайний irb / pry:{"programming_language":{"ruby":{},"python":{}}}
Darek Nędza

ОП не виключила Рейлів
Вілл Шеппард
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.