# Rainbow: a Ruby gem for colouring terminal output without surprises

> Rainbow is a small Ruby gem that wraps a string in ANSI escape codes through a presenter object, with a refinement mode that adds colour methods to plain strings, four ways of naming a colour, and a global switch that turns colour off automatically when the output is not a terminal. The last of those is the feature that makes it safe to put in a library.

**ku1ik/rainbow** — Ruby gem for colorizing printed text on ANSI terminals

- Repository: https://github.com/ku1ik/rainbow
- Stars: 842 · Forks: 71
- Language: Ruby
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/ku1ik-rainbow

## A presenter object, not a monkey patch

Rainbow is a Ruby gem for colorizing printed text on ANSI terminals, and the design choice that defines it is that colour is applied through a presenter object rather than by extending the String class.

You wrap a string in the Rainbow function and then call a colour method on the result:

```ruby
require 'rainbow'

puts Rainbow("this is red").red + " and " + Rainbow("this on yellow bg").bg(:yellow) + " and " + Rainbow("even bright underlined!").underline.bright
```

The result is the raw string with escape sequences around it, and the README shows what that looks like, with the text colour code, the background code and the underline and bright codes wrapping the text and a reset at the end.

The chaining works because every method returns the presenter object itself, so the calls compose in any order and the string comes out at the end. The set of methods is the ANSI attribute set, colour and background with aliases, bright, underline, blink, inverse, hide, faint, italic, and cross out which is also called strike. Two of them come with a caveat in the README, faint and italic, which are noted as not well supported by terminal emulators. That kind of note is worth taking seriously, since a user who relies on italic for emphasis will get nothing on a terminal that ignores it.

Beyond the eight basic ANSI colours there are named methods for aqua, silver, aliceblue and indianred, and the colour list section of the README runs through the full X11 palette.

## The refinement version, and the error it fixes

There is a second way to use the library, and the README explains it with a shell session, which is the clearest way to see the difference.

With the refinement, you require the refinement file and use the using keyword to activate it:

```ruby
require 'rainbow/refinement'
using Rainbow
puts "Hi!".green
```

The IRB example in the README shows what happens without it. A plain string does not respond to the colour method, and the interpreter answers with a NoMethodError for blue on a String. After the using statement, the same call on the same string returns the escaped text.

So the refinement is a refinement in the technical sense, a change to how a method call on String resolves, and it is scoped to the file that activates it rather than to the whole program. That scoping is the reason to prefer it in some cases and to avoid it in others. Inside your own script, where you want the terse form, it is pleasant. Inside a library that somebody else loads, activating a refinement changes the meaning of String method calls in your code, and a host application may already have a refinement doing something else with those methods.

The README presents the refinement as an option rather than the default, and that ordering is sensible. The presenter form is explicit, it cannot surprise a host application, and it costs one extra wrapper call.

## Four ways to name a colour, and only one of them is portable

The colour specification section is the part of the README with a real technical judgement in it, and the difference it draws matters for anyone whose output is read by other people.

There are four ways to specify a colour. An ANSI colour number, where zero is black, one is red and so on. A colour name as a symbol, which can be an ANSI colour name or an X11 colour name. An RGB triplet as three separate values in the range zero to 255. Or an RGB triplet as a hex string, with or without the leading hash.

The subtlety is in what those names mean. The README says that ANSI colours can be changed in accordance with the terminal setting, but an X11 colour is just syntax sugar for an RGB triplet, so you always see what you specified. In other words, .red means whatever your terminal thinks red is, and aliceblue means the exact colour you asked for, approximated to the nearest entry in the 256 colour palette when the terminal is not a true colour one.

That approximation is the second point. When you give an RGB value, the library finds the nearest match from the 256 colour palette, and the README notes that it requires a 256 colour capable terminal to display correctly. So a hex colour on a 16 colour terminal will be visibly wrong, and there is no warning about it.

The random colour example at the end of the section shows both forms in practice, one drawing from the first eight ANSI colours and one from named X11 colours, and the escaped output shows the difference between the two encodings in the numbers.

## The default switch is what makes it safe in a library

The configuration section is one setting, and it is the most important line in the README for anybody who plans to use Rainbow in code that other people run.

Rainbow can be enabled or disabled globally, and when it is disabled all the methods return an unmodified string, so the colour call is still there in the source but the escape codes are not in the output. The README also says that it is enabled by default unless standard output or standard error is not a terminal, or the terminal is dumb.

That detection is the feature. A command line tool that prints coloured output when a human is watching and plain output when the result is piped into another program does not corrupt a log file, does not fill a captured test output with escape sequences, and does not need every call site to ask whether it is talking to a terminal. The decision is made once, globally, by the library.

The same section explains why the uncolor method exists. The Rainbow module provides it to strip away any existing colour or formatting from a string, and the README says this may be handy for determining the visual length of strings, since the escape codes count as characters but take up no space on screen. A formatter that pads a column to a fixed width has to compute the length of the visible text, and this is the method that makes that possible without a second colour parser.

The example is short: build a coloured string, then strip it and get the plain text back.

## Separate instances, when one formatter writes to a file

The advanced usage section addresses a case that the global switch cannot handle, and the case is common in server code.

The global Rainbow function and the global enabled flag operate on one shared wrapper instance. If you want to enable or disable colouring in separate parts of an application, the README says you can get a new wrapper instance for each of them and control the colouring state at runtime.

```ruby
rainbow_one = Rainbow.new
rainbow_two = Rainbow.new

rainbow_one.enabled = false

Rainbow("hello").red          # => "\e[31mhello\e[0m" ("hello" if not on TTY)
rainbow_one.wrap("hello").red # => "hello"
rainbow_two.wrap("hello").red # => "\e[31mhello\e[0m" ("hello" if not on TTY)
```

The scenario the README describes is an application with several output formatters, some of which print to a terminal and others write to a file. Without per-instance control, the library would detect that the terminal is a terminal and colourise every string, including the ones destined for a file, because the detection is global and the writers are not.

Each new instance inherits the global enabled state by default, so the behaviour of an instance that nobody touched is exactly the behaviour you would expect from the global setting, and the per-instance override is an explicit act. That is a small API with one clear purpose, which is the right shape for a feature in a library this widely used.

The repository also carries the usual Ruby tooling, a Rakefile, a Guardfile for file watching, a RuboCop configuration with a separate todo file, and a spec directory, so the behaviour described in the README is the behaviour the suite checks.

## Conclusion

Adopt Rainbow if you write Ruby that prints to a terminal and want colour that disappears on its own when the output is piped into a file, because the gem checks whether standard output is a terminal and disables itself when it is not. Do not adopt it if you need the refinement form in a library that loads into an application you do not control, since a refinement changes the string class for the file that uses it. Before you rely on a colour, remember that an ANSI name follows the terminal's own palette while an X11 name is a fixed RGB triplet, so the two will not look the same on every machine.

## FAQ

### How do I print coloured text with the Rainbow gem?

Wrap the string in the Rainbow function and call a colour method on the result, for example Rainbow("this is red").red, and a background method for a background colour. Every method returns the presenter object, so calls can be chained in any order.

### How does Rainbow decide whether to add escape codes?

It is enabled by default unless standard output or standard error is not a terminal, or the terminal is dumb, so output is plain when it is piped into a file. You can also set Rainbow.enabled yourself, and when it is disabled every method returns the unmodified string.

### What is the refinement form of the Rainbow gem?

Requiring the refinement file and using the using keyword adds the colour methods to plain strings, so you can write "Hi!".green instead of wrapping the string. The README shows that without using Rainbow the same call raises a NoMethodError on a String.

### Which colour formats does Rainbow accept?

An ANSI colour number, a colour name as a symbol which can be an ANSI or an X11 name, an RGB triplet as three values from zero to 255, and an RGB triplet as a hex string with or without a leading hash. An RGB value is matched to the nearest of the 256 colour palette, so it needs a 256 colour capable terminal to look right.

### How do I strip colours from a string in Rainbow?

The Rainbow module provides an uncolor method that removes any existing colour or formatting. The README suggests it for determining the visual length of a string, since the escape codes take up no space on screen but do count as characters.

## Sources

- [Issues](https://github.com/ku1ik/rainbow/issues)
- [ku1ik/rainbow on GitHub](https://github.com/ku1ik/rainbow)
- [License: MIT](https://github.com/ku1ik/rainbow/blob/master/LICENSE)
- [README](https://github.com/ku1ik/rainbow/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ku1ik-rainbow
