Require the library.
require 'ansi/code'
ANSI::Code can be used as a functions module.
str = ANSI::Code.red + "Hello" + ANSI::Code.blue + "World"
str.assert == "\e[31mHello\e[34mWorld"
If a block is supplied to each method then yielded value will be wrapped in the ANSI code and clear code.
str = ANSI::Code.red{ "Hello" } + ANSI::Code.blue{ "World" }
str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m"
More conveniently the ANSI::Code module extends ANSI itself.
str = ANSI.red + "Hello" + ANSI.blue + "World"
str.assert == "\e[31mHello\e[34mWorld"
str = ANSI.red{ "Hello" } + ANSI.blue{ "World" }
str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m"
In the appropriate context the ANSI::Code module can also be included, making its methods directly accessible.
include ANSI::Code
str = red + "Hello" + blue + "World"
str.assert == "\e[31mHello\e[34mWorld"
str = red{ "Hello" } + blue{ "World" }
str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m"
Along with the single font colors, the library include background colors.
str = on_red + "Hello"
str.assert == "\e[41mHello"
As well as combined color methods.
str = white_on_red + "Hello"
str.assert == "\e[37m\e[41mHello"
The ANSI::Code module supports most standard ANSI codes, though not all platforms support every code, so YMMV.
In addition the library offers an extension to String class called #ansi, which allows some of the ANSI::Code methods to be called in a more object-oriented fashion.
require 'ansi/core'
str = "Hello".ansi(:red) + "World".ansi(:blue)
str.assert == "\e[31mHello\e[0m\e[34mWorld\e[0m"
Require the ANSI::Logger library.
require 'ansi/logger'
Create a new ANSI::Logger
log = ANSI::Logger.new(STDOUT)
Info logging appears normal.
log.info{"Info logs are green.\n"}
Warn logging appears yellow.
log.warn{"Warn logs are yellow.\n"}
Debug logging appears cyan.
log.debug{"Debug logs are cyan.\n"}
Error logging appears red.
log.error{"Error logs are red.\n"}
Fatal logging appears bright red.
log.fatal{"Fatal logs are bold red!\n"}
Pretty progress bars are easy to construct.
require 'ansi/progressbar'
pbar = ANSI::Progressbar.new("Test Bar", 100)
Running the bar simply requires calling the #inc method during a loop and calling #finish when done.
100.times do |i|
sleep 0.01
pbar.inc
end
pbar.finish
We will use this same rountine in all the examples below, so lets make a quick macro for it. Notice we have to use #reset first before reusing the same progress bar.
def run(pbar)
pbar.reset
100.times do |i|
sleep 0.01
pbar.inc
end
pbar.finish
puts
end
The progress bar can be stylized in almost any way. The #format setter provides control over the parts that appear on the line. For example, by default the format is:
pbar.format("%-14s %3d%% %s %s", :title, :percentage, :bar, :stat)
So lets vary it up to demonstrate the case.
pbar.format("%-14s %3d%% %s %s", :title, :percentage, :stat, :bar)
run(pbar)
The progress bar has an extra build in format intended for use with file downloads called #transer_mode.
pbar.transfer_mode
run(pbar)
Calling this methods is the same as calling:
pbar.format("%-14s %3d%% %s %s",:title, :percentage, :bar, :stat_for_file_transfer)
run(pbar)
The #style setter allows each part of the line be modified with ANSI codes. And the #bar_mark writer can be used to change the character used to make the bar.
pbar.standard_mode
pbar.style(:title => [:red], :bar=>[:blue])
pbar.bar_mark = "="
run(pbar)
The ANSI::Mixin module is design for including into String-like classes. It will support any class that defines a #to_s method.
require 'ansi/mixin'
In this demonstration we will simply include it in the core String class.
class ::String
include ANSI::Mixin
end
Now all strings will have access to ANSI's style and color codes via simple method calls.
"roses".red.assert == "\e[31mroses\e[0m"
"violets".blue.assert == "\e[34mviolets\e[0m"
"sugar".italic.assert == "\e[3msugar\e[0m"
The method can be combined, of course.
"you".italic.bold.assert == "\e[1m\e[3myou\e[0m\e[0m"
The mixin also supports background methods.
"envy".on_green.assert == "\e[42menvy\e[0m"
And it also supports the combined foreground-on-background methods.
"b&w".white_on_black.assert == "\e[37m\e[40mb&w\e[0m"
The ANSI::String class is a very sophisticated implementation of Ruby's standard String class, but one that can handle ANSI codes seamlessly.
require 'ansi/string'
flower1 = ANSI::String.new("Roses")
flower2 = ANSI::String.new("Violets")
Like any other string.
flower1.to_s.assert == "Roses"
flower2.to_s.assert == "Violets"
Bet now we can add color.
flower1.red!
flower2.blue!
flower1.to_s.assert == "\e[31mRoses\e[0m"
flower2.to_s.assert == "\e[34mViolets\e[0m"
Despite that the string representation now contains ANSI codes, we can still manipulate the string in much the same way that we manipulate an ordinary string.
flower1.size.assert == 5
flower2.size.assert == 7
Like ordinary strings we can concatenate the two strings
flowers = flower1 + ' ' + flower2
flowers.to_s.assert == "\e[31mRoses\e[0m \e[34mViolets\e[0m"
flowers.size.assert == 13
Standard case conversion such as #upcase and #downcase work.
flower1.upcase.to_s.assert == "\e[31mROSES\e[0m"
flower1.downcase.to_s.assert == "\e[31mroses\e[0m"
Some of the most difficult methods to re-implement were the substitution methods such as #sub and #gsub. They are still somewhat more limited than the original string methods, but their primary functionality should work.
flower1.gsub('s', 'z').to_s.assert == "\e[31mRozez\e[0m"
There are still a number of methods that need implementation. ANSI::String is currently a very partial implementation. But as you can see from the methods it does currently support, is it already useful.
The +Columns+ class makes it easy to create nice looking text columns, sorted from top to bottom, right to left (as opposed to the other way around).
require 'ansi/columns'
list = %w{a b c d e f g h i j k l}
columns = ANSI::Columns.new(list)
columns.to_s(4)
The output will be:
a d g j
b e h k
c f i l
Besides an array of elements, Columns.new can take a string in which the elements are divided by newlines characters. The default column size can also be given to the initializer.
list = "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl"
columns = ANSI::Columns.new(list, :columns=>6)
columns.to_s
The output will be:
a c e g i k
b d f h j l
If the column count is +nil+, then the number of columns will be calculated as a best fit for the current terminal window.
Columns can adjust the padding between cells.
list = %w{a b c d e f g h i j k l}
columns = ANSI::Columns.new(list, :padding=>2)
columns.to_s(4)
The output will be:
a d g j
b e h k
c f i l
Columns can also be aligned either left or right.
list = %w{xx xx xx yy y yy z zz z}
columns = ANSI::Columns.new(list, :align=>:right)
columns.to_s(3)
The output will be:
xx yy z
xx y zz
xx yy z
Lastly, columns can be augmented with ANSI codes. This is done through a formatting block. The block can take up to three parameters, the cell content, the column and row numbers, or the cell and the column and row numbers.
list = %w{a b c d e f g h i j k l}
columns = ANSI::Columns.new(list){ |c,r| r % 2 == 0 ? :red : :blue }
out = columns.to_s(4)
out.assert == (
"\e[31ma \e[0m\e[31md \e[0m\e[31mg \e[0m\e[31mj \e[0m\n" +
"\e[34mb \e[0m\e[34me \e[0m\e[34mh \e[0m\e[34mk \e[0m\n" +
"\e[31mc \e[0m\e[31mf \e[0m\e[31mi \e[0m\e[31ml \e[0m\n"
)
The ANSI::Table class can be used to output tabular data with nicely formated ASCII cell borders.
require 'ansi/table'
The constructor takes an 2-dimensional array.
data = [
[ 10, 20, 30 ],
[ 20, 10, 20 ],
[ 50, 40, 20 ]
]
table = ANSI::Table.new(data)
table.to_s
The output will be:
+----+----+----+
| 10 | 20 | 30 |
| 20 | 10 | 20 |
| 50 | 40 | 20 |
+----+----+----+
require 'ansi/diff'
a = 'abcYefg'
b = 'abcXefg'
diff = ANSI::Diff.new(a,b)
diff.to_s.assert == "\e[31mabc\e[0m\e[33mYefg\e[0m\n\e[31mabc\e[0mXefg"
Try another.
a = 'abc'
b = 'abcdef'
diff = ANSI::Diff.new(a,b)
diff.to_s.assert == "\e[31mabc\e[0m\n\e[31mabc\e[0mdef"
And another.
a = 'abcXXXghi'
b = 'abcdefghi'
diff = ANSI::Diff.new(a,b)
diff.to_s.assert == "\e[31mabc\e[0m\e[33mXXXghi\e[0m\n\e[31mabc\e[0mdefghi"
And another.
a = 'abcXXXdefghi'
b = 'abcdefghi'
diff = ANSI::Diff.new(a,b)
diff.to_s.assert == "\e[31mabc\e[0m\e[33mXXX\e[0m\e[35mdefghi\e[0m\n\e[31mabc\e[0m\e[35mdefghi\e[0m"
Comparison that is mostly different.
a = 'abcpppz123'
b = 'abcxyzzz43'
diff = ANSI::Diff.new(a,b)
diff.to_s.assert == "\e[31mabc\e[0m\e[33mpppz123\e[0m\n\e[31mabc\e[0mxyzzz43"
The BBCode module provides methods for converting between BBCodes, basic HTML and ANSI codes.
require 'ansi/bbcode'
BBCodes are color and style codes in square brackets, quite popular with on line forums.
bbcode = "this is [COLOR=red]red[/COLOR], this is [B]bold[/B]"
We can convert this to ANSI code simply enough:
ansi = ANSI::BBCode.bbcode_to_ansi(bbcode)
ansi.assert == "this is \e[0;31mred\e[0m, this is \e[1mbold\e[0m\n"
In addition the BBCode module supports conversion to simple HTML.
html = ANSI::BBCode.bbcode_to_html(bbcode)
html.assert == "this is <font color=\"red\">red</font>, this is <strong>bold</strong><br />\n"
We should be ables to get the terminal width via the terminal_width
method.
width = ANSI::Terminal.terminal_width
Fixnum.assert === width