RatatuiRuby is a RubyGem built on Ratatui, a leading TUI library written in Rust. You get native performance with the joy of Ruby.
$ gem install ratatui_ruby --pre
SemVer Tag: v1.0.0-beta.2 RubyGems.org: 1.0.0.pre.beta.2
Standard TUIs erase themselves on exit. Your carefully formatted CLI output disappears. Users lose their scrollback.
Inline viewports solve this. They occupy a fixed number of lines, render rich UI, then leave the output in place when done.
Perfect for spinners, menus, progress indicators—any brief moment of richness.
class Spinner
def main
RatatuiRuby.run(viewport: :inline, height: 1) do |tui|
until connected?
status = tui.paragraph(text: "#{spin} Connecting...")
tui.draw { |frame| frame.render_widget(status, frame.area) }
return ending(tui, "Canceled!", :red) if tui.poll_event.ctrl_c?
end
ending(tui, "Connected!", :green)
end
end
def ending(tui, message, color) = tui.draw do |frame|
frame.render_widget(tui.paragraph(text: message, fg: color), frame.area)
end
def initialize = (@frame, @finish = 0, Time.now + 2)
def connected? = Time.now >= @finish
def spin = SPINNER[(@frame += 1) % SPINNER.length]
SPINNER = %w[⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏]
end
Spinner.new.main; puts
require "ratatui_ruby"
class RadioMenu
CHOICES = ["Production", "Staging", "Development"]
PREFIXES = { active: "●", inactive: "○" }
CONTROLS = "↑/↓: Select | Enter: Choose | Ctrl+C: Cancel"
TITLES = ["Select Environment",
{ content: CONTROLS,
position: :bottom,
alignment: :right }]
def call
RatatuiRuby.run(viewport: :inline, height: 5) do |tui|
@tui = tui
show_menu until chosen?
end
RadioMenu::CHOICES[@choice]
end
private
def show_menu = @tui.draw do |frame|
widget = @tui.paragraph(
text: menu_items,
block: @tui.block(borders: :all, titles: TITLES)
)
frame.render_widget(widget, frame.area)
end
def chosen?
interaction = @tui.poll_event
return choose if interaction.enter?
move_by(-1) if interaction.up?
move_by(1) if interaction.down?
quit! if interaction.ctrl_c?
false
end
def choose
prepare_next_line
@choice
end
def prepare_next_line
area = @tui.viewport_area
RatatuiRuby.cursor_position = [0, area.y + area.height]
puts
end
def quit!
prepare_next_line
exit 0
end
def move_by(line_count)
@choice = (@choice + line_count) % CHOICES.size
end
def menu_items = CHOICES.map.with_index do |choice, i|
"#{prefix_for(i)} #{choice}"
end
def prefix_for(choice_index)
return PREFIXES[:active] if choice_index == @choice
PREFIXES[:inactive]
end
def initialize = @choice = 0
end
choice = RadioMenu.new.call
puts "You chose #{choice}!"
RatatuiRuby.run do |tui|
loop do
tui.draw do |frame|
frame.render_widget(
tui.paragraph(
text: "Hello, RatatuiRuby!",
alignment: :center,
block: tui.block(
title: "My App",
titles: [{ content: "q: Quit", position: :bottom, alignment: :right }],
borders: [:all],
border_style: { fg: "cyan" }
)
),
frame.area
)
end
case tui.poll_event
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
break
else
nil
end
end
end
RatatuiRuby.run enters raw mode, switches to the alternate screen, and restores the terminal
on exit.
Inside the block: call draw to render, and poll_event to read input.
Need something else? Build custom widgets in Ruby!
require "ratatui_ruby/test_helper"
class TestColorPicker < Minitest::Test
include RatatuiRuby::TestHelper
def test_swatch_widget
with_test_terminal(10, 3) do
RatatuiRuby.draw do |frame|
frame.render_widget(Swatch.new(:red), frame.area)
end
assert_cell_style 2, 1, char: "█", bg: :red
end
end
def test_input_hex
with_test_terminal do
inject_keys "#", "f", "f", "0", "0", "0", "0"
inject_keys :enter, :q
ColorPicker.new.run
assert_snapshots "after_hex_entry"
end
end
end
The module sets up a headless terminal, injects events, and asserts on rendered output. Everything runs in-process with no external dependencies.
Ruby deserves world-class terminal user interfaces. TUI developers deserve a world-class language.
RatatuiRuby wraps Rust's Ratatui via native extension. The Rust library handles rendering. Your Ruby code handles design.
Text UIs are seeing a renaissance with many new TUI libraries popping up. The Ratatui bindings have proven to be full featured and stable.
Mike Perham, creator of Sidekiq and Faktory
Rust excels at low-level rendering. Ruby excels at expressing domain logic and UI. RatatuiRuby puts each language where it performs best.
CharmRuby wraps Charm's Go libraries. Both projects give Ruby developers TUI options.
| CharmRuby | RatatuiRuby | |
|---|---|---|
| Integration | Two runtimes, one process | Native extension in Rust |
| Runtime | Go + Ruby (competing) | Ruby (Rust has no runtime) |
| Memory | Two uncoordinated GCs | One Garbage Collector |
| Style | The Elm Architecture (TEA) | TEA, OOP, or Imperative |