Printing a Hash
Credit: Ben Giddings
Problem
You want to print out the contents of a Hash, but Kernel#puts doesn't give very useful results.
h = {} h[:name] = "Robert" h[:nickname] = "Bob" h[:age] = 43 h[:email_addresses] = {:home => "bob@example.com", :work => "robert@example.com"} h # => {:email_addresses=>["bob@example.com", "robert@example.com"], # :nickname=>"Bob", :name=>"Robert", :age=>43} puts h # nicknameBobage43nameRobertemail_addresseshomebob@example.comworkrobert@example.com puts h[:email_addresses] # homebob@example.comworkrobert@example.com
Solution
|
The easiest way to print a hash is to use Kernel#p. Kernel#p prints out the "inspected" version of its arguments: the string you get by calling inspect on the hash. The "inspected" version of an object often looks like Ruby source code for creating the object, so it's usually readable:
p h[:email_addresses] # {:home=>"bob@example.com", :work=>"robert@example.com"}
For small hashes intended for manual inspection, this may be all you need. However, there are two difficulties. One is that Kernel#p only prints to stdout. The second is that the printed version contains no newlines, making it difficult to read large hashes.
p h # {:nickname=>"Bob", :age=>43, :name=>"Robert", :email_addresses=>{:home=> # "bob@example.com", :work=>"robert@example.com"}}
When the hash you're trying to print is too large, the pp ("pretty-print") module produces very readable results:
require ' pp' pp h[:email_addresses] # {:home=>"bob@example.com", :work=>"robert@example.com"} pp h # {:email_addresses=>{:home=>"bob@example.com", :work=>"robert@example.com"} # :nickname=>"Bob", # :name=>"Robert", # :age=>43}
Discussion
There are a number of ways of printing hash contents. The solution you choose depends on the complexity of the hash you're trying to print, where you're trying to print the hash, and your personal preferences. The best general-purpose solution is the pp library.
When a given hash element is too big to fit on one line, pp knows to put it on multiple lines. Not only that, but (as with Hash#inspect), the output is valid Ruby syntax for creating the hash: you can copy and paste it directly into a Ruby program to recreate the hash.
The pp library can also pretty-print to I/O streams besides standard output, and can print to shorter lines (the default line length is 79). This example prints the hash to $stderr and wraps at column 50:
PP::pp(h, $stderr, 50) # {:nickname=>"Bob", # :email_addresses=> # {:home=>"bob@example.com", # :work=>"robert@example.com"}, # :age=>43, # :name=>"Robert"} # => #
You can also print hashes by converting them into YAML with the yaml library. YAML is a human-readable markup language for describing data structures:
require 'yaml' puts h.to_yaml # -- # :nickname: Bob # :age: 43 # :name: Robert # :email_addresses: # :home: bob@example.com # :work: robert@example.com
If none of these is suitable, you can print the hash out yourself by using Hash#each_pair to iterate over the hash elements:
h[:email_addresses].each_pair do |key, val| puts "#{key} => #{val}" end # home => bob@example.com # work => robert@example.com
See Also
- Recipe 8.10, "Getting a Human-Readable Printout of Any Object," covers the general case of this problem
- Recipe 13.1, "Serializing Data with YAML"