Question
When running a simple Ruby script, what is the easiest way to display an object's fields in the console? I need an equivalent to PHP's print_r() that also works well with arrays.
Short Answer
Ruby provides several useful debugging tools for displaying values: p prints an inspectable representation, object.inspect returns that representation as a string, and pp pretty-prints nested arrays and hashes. For a custom object's stored instance variables, use instance_variables and instance_variable_get when you need to see its internal state explicitly.
Concept
Ruby does not have one exact equivalent of PHP's print_r(), because Ruby offers a few tools for different inspection needs.
putsdisplays a human-friendly string by callingto_s.pdisplays a debugging representation by callinginspect.inspectreturns that debugging representation as a string.pp(pretty print) formats nested data across multiple lines, making complex arrays and hashes easier to read.
For debugging, p and pp are usually better choices than puts. They preserve useful details such as quotation marks around strings, array brackets, hash keys, and escape characters.
Custom Ruby objects may display their class and instance variables automatically through inspect, but that output is not a guaranteed public API. If you specifically need the object's instance variables, Ruby provides reflection methods such as instance_variables and instance_variable_get.
These tools matter because developers constantly need to verify what data exists at a particular point in a program: API responses, configuration hashes, parsed files, loop values, and an object's current state.
Mental Model
Think of a Ruby value as an item you want to identify.
putsis like asking someone to describe the item in a pleasant sentence.pis like asking for the item's diagnostic label, including technical details.ppis like laying the contents of a large box neatly on a table so each part is easy to examine.
When debugging, the diagnostic label or neatly arranged contents are usually more useful than a friendly description.
Syntax and Examples
Use p for a quick debug print:
name = "Ada"
p name
# "Ada"
p calls inspect, so these are closely related:
items = ["book", "pen", 3]
p items
puts items.inspect
Both display a representation similar to:
["book", "pen", 3]
Use pp for nested arrays and hashes. Load Ruby's standard pp library first:
require "pp"
order = {
id: 42,
customer: {
name: "Ada",
address: { city: "London", country: "UK" }
},
items: ["book", "pen"]
}
pp order
pp formats the nested structure over multiple lines when necessary, which is easier to scan than one very long line.
For a custom object:
class User
def initialize(name, admin)
@name = name
@admin = admin
end
end
user = User.new("Ada", true)
p user
A typical result is similar to:
#<User:0x0000... @name="Ada", @admin=true>
The hexadecimal object identifier changes between runs, so do not rely on it in program logic.
Step by Step Execution
Consider this script:
require "pp"
scores = [
{ player: "Ada", points: 10 },
{ player: "Lin", points: 15 }
]
p scores
pp scores
Execution flow:
require "pp"loads theppmethod from Ruby's standard library.- Ruby creates an array containing two hashes and assigns it to
scores. p scorescallsscores.inspectand writes its returned string to standard output. The result is commonly compact and may appear on one line.pp scoresrecursively formats the array and its hashes. It adds line breaks and indentation when useful.- Neither
pnorppchangesscores; they only display it.
You can also inspect selected object fields explicitly:
class Product
def initialize(name, price)
@name = name
@price = price
end
end
product = Product.new("Notebook", 4.50)
product.instance_variables.each do |variable|
value = product.instance_variable_get(variable)
puts "#{variable}: #{value.inspect}"
end
This visits :@name and :@price, retrieves each stored value, and prints a readable line for each one.
Real World Use Cases
- Inspecting API data: Use
pp response_bodyafter parsing JSON to understand a nested response before extracting values. - Debugging configuration: Print a hash of environment-specific settings to verify the values loaded by a script.
- Checking loop data: Use
p recordinside a loop to find an unexpected record or missing field. - Investigating parsed files: Pretty-print CSV-derived hashes, YAML data, or JSON data while developing an import script.
- Examining object state: Use
p serviceor list instance variables when a class appears to hold the wrong values. - Writing quick command-line scripts: Print an array of results with
ppbefore deciding how to format the final output for users.
Real Codebase Usage
In production codebases, direct console printing is most common during local development, scripts, and temporary debugging. Developers generally choose the tool based on the purpose.
Quick local debugging
p params
p user_id
This is useful for a quick checkpoint because strings remain visibly quoted and arrays remain structured.
Readable nested diagnostics
require "pp"
pp payload
This is common when inspecting request payloads or deeply nested application data.
Logging selected, meaningful fields
Rather than dumping an entire object—which can be noisy or expose secrets—real applications often log a small hash:
logger.info(
event: "payment_failed",
order_id: order.id,
error_class: error.class.name
)
Validation and guard clauses
When a value is unexpected, inspect it near the boundary where it enters the program:
unless payload.is_a?(Hash)
p payload
raise ArgumentError, "payload must be a Hash"
end
For long-running applications, use the project's logger instead of leaving p statements in code. Remove temporary debugging output or replace it with deliberate, safe logging.
Common Mistakes
Using puts when you need debugging detail
value = ["a", "b"]
puts value
This prints each array element on its own line:
a
b
Use p value or pp value when you need to see the array structure.
Expecting p to return the inspected string
text = p({ status: "ok" })
p prints the value and returns the original object, not the string from inspect. If you need a string, use inspect:
text = { status: "ok" }.inspect
Forgetting to load pp
pp data
In a normal Ruby script, this can fail because pp is not loaded automatically. Add:
require "pp"
Assuming every object's inspect output is complete
A class can define its own inspect method. Some objects intentionally hide internal details, and some objects contain a large amount of data. If needed, inspect known public methods or explicit instance variables instead.
Printing sensitive data
Avoid dumping passwords, access tokens, session data, or full customer records into a shared terminal or application log. Print only the fields needed to diagnose the problem.
Treating instance variables as a stable public interface
instance_variables is useful for debugging, but application code should normally use public methods such as user.name rather than reaching into @name directly.
Comparisons
| Tool | Main purpose | Output style | Return value | Best use |
|---|---|---|---|---|
puts value | User-facing display | Uses to_s; may lose structure | nil | Simple text output |
p value | Quick debugging | Uses inspect | The original value | One-line inspection |
value.inspect | Build a debug string | Uses inspect | A String | Interpolation, logging, custom output |
pp value | Read nested data | Pretty-formatted inspection | The original value | Arrays and hashes with nesting |
object.instance_variables | Find stored instance variables | Array of symbols | An array | Inspecting custom object state |
p versus pp:
p data # fastest quick check
pp data # easier to read when data is deeply nested
Use inspect when you need the representation as data rather than immediate console output:
message = "Unexpected response: #{response.inspect}"
Cheat Sheet
# Quick debugging output
p value
# Get a debugging representation as a String
text = value.inspect
# Pretty-print nested data
require "pp"
pp value
# List an object's instance variable names
object.instance_variables
# => [:@name, :@count]
# Read one instance variable dynamically
object.instance_variable_get(:@name)
Rules of thumb:
- Use
putsfor simple user-facing output. - Use
pfor fast debugging. - Use
ppfor complex arrays and hashes. - Use
inspectwhen you need a string. - Do not leave noisy debug prints or sensitive values in production logs.
- Prefer public reader methods over instance-variable reflection in normal application logic.
FAQ
What is Ruby's equivalent of PHP print_r()?
For quick inspection, use p value. For more readable output of nested arrays and hashes, use require "pp" followed by pp value.
What is the difference between p and puts in Ruby?
puts uses to_s and aims for readable text. p uses inspect, which preserves debugging details such as quotes, brackets, and escape sequences.
Do I need to require anything to use p?
No. p is available by default. pp requires require "pp" in a standard Ruby script.
How do I print an array on one line in Ruby?
Use p array or puts array.inspect. puts array prints each element separately, which is often not what you want for debugging.
How do I see the fields of a Ruby object?
Start with p object. To list its instance variables, call object.instance_variables. To read one dynamically, call object.instance_variable_get(:@field_name).
Why does p object show a value like 0x0000...?
That is part of Ruby's default object inspection output and helps identify the object instance. It is not stable between program runs.
Can inspect be customized?
Yes. A class can define its own inspect method. This can make debugging output clearer, but it should avoid exposing secrets.
Mini Project
Description
Create a small inventory-debugging script. It stores products as hashes inside an array, pretty-prints the full inventory, and then displays the instance variables of an InventoryReport object. This mirrors the kind of temporary diagnostic script used while checking imported data.
Goal
Print nested inventory data clearly and inspect the stored state of a custom Ruby object.
Requirements
- Create an array containing at least two product hashes.
- Give each product a name, price, and tags array.
- Pretty-print the complete inventory.
- Create an object that stores the inventory and a report name.
- Print each instance variable name and its inspected value.
Keep learning
Related questions
Add a Default Value to an Existing Column in a Rails Migration
Learn how to add or change a default value on an existing database column using Rails Active Record migrations safely.
Calling a Class Method from an Instance in Ruby
Learn how to call a class method from an instance in Ruby using self.class, with examples, pitfalls, and practical usage patterns.
Calling an Overridden Monkey-Patched Method in Ruby
Learn how to call the original method when monkey patching in Ruby, including alias_method patterns, examples, pitfalls, and practical usage.