Meilleur moyen d'imprimer un hash


169

J'ai un grand hachage avec des tableaux imbriqués et des hachages. Je voudrais simplement l'imprimer pour qu'il soit «lisible» pour l'utilisateur.

J'aimerais que ce soit un peu comme to_yaml - c'est assez lisible - mais toujours trop technologique.

En fin de compte, ce sont les utilisateurs finaux qui ont besoin de lire ces blocs de données afin qu'ils doivent être formatés proprement.

Aucune suggestion?



utilitaire en ligne jsonviewer.stack.hu . Cependant, cela ne fonctionne pas correctement pour la syntaxe des fusées de hachage.
Amit Patel

Réponses:


256
require 'pp'
pp my_hash

À utiliser ppsi vous avez besoin d'une solution intégrée et souhaitez simplement des sauts de ligne raisonnables.

Utilisez awesome_print si vous pouvez installer une gemme. (En fonction de vos utilisateurs, vous souhaiterez peut-être utiliser l' index:falseoption pour désactiver l'affichage des indices de tableau.)


pp c'est sympa, mais c'est vraiment dommage qu'on ne puisse pas limiter la profondeur.
akim

95

Si vous avez JSON, je le recommande JSON.pretty_generate(hash)car il est plus simple que awesome_print , a fière allure dans une prebalise et permet une copie facile à partir d'une page Web. (Voir aussi: Comment puis-je formater "joli" ma sortie JSON dans Ruby on Rails? )


Cette réponse bénéficierait d'un exemple réel
Travis Bear

@TravisBear Il y a un exemple de sortie si vous cliquez sur le lien «voir aussi» dans ma réponse. Je recommande cette réponse en particulier: stackoverflow.com/a/1823885/109618
David

8
Ce seraitputs JSON.pretty_generate(hash)
joeloui

Si vous avez besoin de créer JSON, permettez-moi de recommander ma propre bibliothèque (gratuite, OSS, sans publicité) pour créer de jolis JSON à partir de Ruby ou JS: NeatJSON (Ruby) et NeatJSON (Online / JS)
Phrogz

Désolé, je me rends compte maintenant que pretty_generate accepte un objet Ruby, pas du texte json.
Tony

26

Une autre solution qui fonctionne mieux pour moi que ppou awesome_print:

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

2
Notez que l' Pry::ColorPrinter.pp(obj)écrit en sortie standard mais peut prendre des paramètres supplémentaires, y compris la destination. J'aimePry::ColorPrinter.pp(obj, a_logger)
Eric Urban

Je suis surpris que ce ne soit pas mieux documenté: j'utilise toujours pry comme console Rails et je cherche depuis longtemps comment puiser dans sa jolie imprimante sans utiliser un autre bijou. Vote positif car cette solution a finalement mis fin à ma longue recherche. :-)
wiz

20

Si vous n'avez aucune action de gemme sophistiquée, mais que vous avez JSON, cette ligne CLI fonctionnera sur un hachage:

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

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

  :key2 => "value2",

  :key3 => "value3"
}

8
Voté contre car cela gâcherait toutes les clés et valeurs contenant ":"
thomax

1
Cela ne traite pas non plus de null (JSON) vs nil (Ruby).
Rennex

1
Toujours pratique pour la plupart des situations.
Abram

1
Je ne peux pas croire cela trois ans plus tard! Merci @Abram. :) Ce n'est pas la solution la plus élégante au monde mais elle fait avancer les choses en un clin d'œil.
Nick Schwaderer

4

Utilisez les réponses ci-dessus si vous imprimez aux utilisateurs.

Si vous souhaitez uniquement l'imprimer pour vous-même dans la console, je vous suggère d'utiliser le pry gem au lieu d'irb. Outre la jolie impression, pry possède également de nombreuses autres fonctionnalités (vérifiez le railcast ci-dessous)

gem installer pry

Et vérifiez ce railscast:

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


3

Facile à faire avec json si vous pensez que vos clés sont saines:

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

En utilisant Pry, il vous suffit d'ajouter le code suivant à votre ~ / .pryrc:

require "awesome_print"
AwesomePrint.pry!

1

De toutes les gemmes que j'ai essayées, la show_datagemme a fonctionné le mieux pour moi, je l'utilise maintenant beaucoup pour enregistrer le hachage des paramètres dans Rails à peu près tout le temps


0

Pour les hachages imbriqués volumineux, ce script peut vous être utile. Il imprime un hachage imbriqué dans une belle syntaxe de type python avec seulement des retraits pour faciliter la copie.

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

Exemple d'utilisation:

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

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

La valeur renvoyée est le nombre (3) de toutes les valeurs de niveau final du hachage imbriqué.


0

Voici une autre approche utilisant json et 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))))

(analyse la réponse de par exemple RestClient)


0

Dans les rails

Si tu as besoin

  • un hash "joli imprimé"
  • dans par exemple le Rails.logger
  • qui, en particulier, s'exécute inspectsur les objets dans le hachage
    • ce qui est utile si vous remplacez / définissez la inspectméthode dans vos objets comme vous êtes censé le faire

... alors cela fonctionne très bien! (Et de mieux en mieux, plus votre objet Hash est gros et imbriqué.)

logger.error my_hash.pretty_inspect

Par exemple:

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 vient de PrettyPrint , que les rails incluent par défaut. Donc, pas de gemmes nécessaires et aucune conversion en JSON nécessaire.

Pas dans les rails

Si vous n'êtes pas dans Rails ou si ce qui précède échoue pour une raison quelconque, essayez d' require "pp"abord d' utiliser . Par exemple:

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}

Un exemple complet

Grand pretty_inspectexemple de hachage de mon projet avec texte spécifique au projet de mes objets inspectés rédigés:

{<***::******************[**:****, ************************:****]********* * ****** ******************** **** :: *********** - *** ******* *********>=>
  {: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

Sous Rails, les tableaux et les hachages dans Ruby ont des fonctions to_json intégrées. J'utiliserais JSON simplement parce qu'il est très lisible dans un navigateur Web, par exemple Google Chrome.

Cela étant dit, si vous êtes préoccupé par le fait que cela semble trop "technique", vous devriez probablement écrire votre propre fonction qui remplace les accolades et les accolades carrées dans vos hachages et tableaux par des espaces blancs et d'autres caractères.

Recherchez la fonction gsub pour une très bonne façon de le faire. Continuez à jouer avec différents personnages et différentes quantités d'espaces jusqu'à ce que vous trouviez quelque chose qui semble attrayant. http://ruby-doc.org/core-1.9.3/String.html#method-i-gsub


7
Les tableaux et les hachages n'ont pas de méthode to_json intégrée, ceux-ci sont ajoutés par ActiveSupport de Rails.
Tom De Leu

C'est encore pire que la normale irb / pry:{"programming_language":{"ruby":{},"python":{}}}
Darek Nędza

OP n'a pas exclu Rails
Will Sheppard
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.