rubyguides

Kernel#format

format(format_string [, arguments...]) -> string

The format method (alias for sprintf) creates a formatted string using specifiers similar to C’s printf. It provides precise control over string formatting.

Basic format specifiers

# %d - Integer
format("%d", 42)          # => "42"

# %f - Float
format("%.2f", 3.14159)  # => "3.14"

# %s - String
format("%s", "hello")    # => "hello"

# %x - Hex
format("%x", 255)        # => "ff"

Each specifier expects a matching argument of the right type. Passing a string to %d raises an ArgumentError, so the specifier and the value must agree. The four basic types shown here cover most everyday formatting needs, and they can be combined with width and precision flags for finer control.

Width and precision

# Minimum width
format("%5d", 42)       # => "   42"

# Left align
format("%-5d", 42)       # => "42   "

# Precision
format("%.3f", 3.14159) # => "3.142"

Width sets the minimum field size and pads with spaces by default. A negative width left-aligns the value within the field. Precision controls decimal places for floats and the maximum length for strings, rounding the value when it exceeds the specified digits.

Multiple arguments

format("Name: %s, Age: %d", "Alice", 30)
# => "Name: Alice, Age: 30"

When you pass more values than specifiers, the extra arguments are ignored. When you pass fewer, format raises an ArgumentError. Each positional argument maps to the next specifier in left-to-right order, so the format string reads like a template with placeholder slots.

Practical examples

Currency formatting

def format_currency(amount)
  format("$%.2f", amount)
end

format_currency(19.99)   # => "$19.99"
format_currency(1000.00)  # => "$1000.00"

Wrapping format in a helper method keeps the specifier string close to the values it formats. This is a good pattern when the same formatting rule is used in several places: the helper gives the rule a name and keeps the specifier string in one spot.

Table generation

headers = ["Name", "Score"]
rows = [["Alice", 95], ["Bob", 87]]

puts format("%-10s %5s", *headers)
rows.each { |r| puts format("%-10s %5d", *r) }

The splat operator unpacks each row array into separate arguments for format. Left-aligning the name column and right-aligning the score column produces a clean table where the values line up neatly regardless of the name length. The header row uses string specifiers for both columns, while the data rows use a decimal specifier for the score.

Padding

# Zero-padded
format("%05d", 42)     # => "00042"

# Hex with padding
format("%08X", 255)   # => "000000FF"

Zero-padding with %0 fills the field width with zeros instead of spaces, which is the standard format for fixed-width numeric identifiers, hex color codes, and serial numbers. The %08X example produces an eight-character uppercase hex value, commonly used in memory dumps and color representations.

Named parameters (Ruby 2.6+)

format("%{name} is %{age} years old", name: "Bob", age: 25)
# => "Bob is 25 years old"

Named parameters make long format strings much easier to read because the placeholder names describe what each slot expects. This is especially helpful in templates that have more than three or four values, where positional specifiers force the reader to count arguments to understand which value goes where.

Flags

# +: Always show sign
format("%+d", 5)       # => "+5"
format("%+d", -5)     # => "-5"

# Space: Space for positive
format("% d", 5)      # => " 5"

# #: Alternate form
format("%#x", 255)    # => "0xff"
format("%#o", 64)     # => "0100"

The + flag forces a sign even for positive numbers, which is useful in financial reports where you want to make gains explicit. The space flag reserves space for the sign without printing a +, keeping positive and negative numbers aligned in a column. The # flag adds the conventional prefix for hex, octal, and binary output.

Array arguments

# Using * to expand array
args = ["Hello", 42]
format("Message: %s, Code: %d", *args)

When the arguments are already in an array, splatting them into format is cleaner than indexing into the array individually. This pattern appears often in logging and message-building code where the values are gathered from several distinct sources and collected into one array before being formatted into the final output string for display.

Percentage

# Literal percent
format("100%%")        # => "100%"
format("%.0f%%", 75.5) # => "76%"

Use format when the layout matters

format is most useful when the output needs a predictable layout that plain interpolation would make awkward. Tables, reports, padded numbers, and fixed-width strings all benefit from a method that lets you declare the shape directly with minimal code.

# A simple report row with format
format("%-20s %8.2f", "Total revenue", 15432.50)
# => "Total revenue        15432.50"

The call site usually reads like a small template, which makes the intention clear even to someone scanning the code quickly. That is one of the strengths of format: the pattern is visible, and the values are slotted into the pattern without a lot of ceremony.

Keep specifiers close to the data

The specifier string and the arguments should live close together in the code, because the relationship between them is the whole point of the method. When the format string gets long, a named helper can keep the call site readable without hiding the structure.

# Helper keeps specifiers close to their values
def format_row(label, value)
  format("%-12s %6d", label, value)
end

That matters in reporting code, where a small mismatch between a specifier and an argument can produce output that looks almost right but is still wrong. Clear placement makes those problems easier to spot.

Prefer readability over cleverness

format can do a lot, but the best examples usually stay simple. If the string starts to depend on many width flags, conversions, or nested helper calls, it may be worth stepping back and checking whether the output could be built more plainly. The method is strongest when the structure is obvious and the result is easy to compare with the source values. That keeps the formatting logic maintainable for the next person who has to update it.

Common use cases

  • Generating formatted output
  • String interpolation with control
  • Building reports
  • Internationalization

See Also