ANSI escape codes in Ruby
Ruby's double-quoted strings accept \e as the ESC literal (no need for \x1b or \033), and puts / print / STDOUT.write are byte-clean on every platform. Ruby 3.0+ on Windows auto-enables ENABLE_VIRTUAL_TERMINAL_PROCESSING on the standard streams, so \e[31m lights up Conhost and Windows Terminal without a colorama-style shim.
For ergonomic styling: colorize monkey-patches String with chainable colour methods ("oops".red.bold), term-ansicolor (Florian Frank's classic — powers pry and rspec) offers both module-call (Term::ANSIColor.red(...)) and mixin styles, and pastel (from the TTY toolkit) ships isolated SGR helpers that auto-detect NO_COLOR and CLICOLOR_FORCE without polluting String. For full TUIs reach for the rest of the TTY toolkit — tty-prompt, tty-spinner, tty-cursor, tty-progressbar.
Recommended libraries
- colorize
Monkey-patches
Stringwith chainable colour methods —"oops".red.bold.on_white. ~30M downloads, the de facto choice for one-off scripts and Rakefile output. Supports 8 named colours + extended palette viacolorize(color: :red, mode: :bold, background: :white). - term-ansicolor
Florian Frank's classic gem (since 2009) — both module-call style (
Term::ANSIColor.red("text")) and mixin style (include Term::ANSIColor; red("text")). Powerspry,rspec,cucumber, and a long tail of Ruby CLI tools. HonoursNO_COLORsince 1.7.0. - pastel
Module-scoped SGR helper —
Pastel.new.red.bold("oops"). NoStringmonkey-patching. The TTY toolkit's idiomatic colour layer;Pastel.new(enabled: nil)auto-detects viatty?+NO_COLOR+CLICOLOR_FORCE. Supports decorators (pastel.decorate("text", :red, :bold)) and 256-colouron_<color>chains. - tty-prompt
Interactive prompts —
select,ask,multi_select,mask(password),yes?/no?, with polished styling and keyboard navigation. Pairs withtty-spinner,tty-progressbar,tty-cursorfor a full TUI stack. Used by Hanami, Pry, Bundler-style installers, and Foreman.
Idiomatic patterns
puts "\e[1;31merror:\e[0m permission denied"require 'colorize'
puts "error:".red.bold + " permission denied"
puts "ok".green
puts "deprecated".yellow.on_blackrequire 'pastel'
# Pastel.new(enabled: nil) auto-detects:
# STDOUT.tty? AND NO_COLOR not set AND CLICOLOR != '0'
# CLICOLOR_FORCE=1 forces colour even when redirected.
pastel = Pastel.new
puts "#{pastel.red.bold('error:')} permission denied"
puts pastel.decorate('lavender truecolor', :on_blue, :bold)
# Disable globally — e.g. in CI:
plain = Pastel.new(enabled: false)
puts plain.red('this prints as plain text')STDOUT.print "\e[?25l" # hide cursor
at_exit { STDOUT.print "\e[?25h" } # restore on any exit path
100.times do |i|
# \r returns to col 1, \e[K erases to end of line
STDOUT.print "\r\e[K#{i + 1}% complete"
STDOUT.flush
sleep 0.02
end
puts