alignment_audit

alignment_audit

MISALIGNED (non-additive, breaking)

alignment_audit_granular_level

v0.7.0 Alignment Audit (Parameter-Level)

This document audits alignment between RatatuiRuby v0.7.0 and the upstream Ratatui/Crossterm Rust libraries at the parameter and enum value level. Only gaps are listed.

[!IMPORTANT] MISSING = Can be added as new features, backwards-compatible. MISALIGNED = Requires breaking changes before v1.0.0 release.


MISSING — Layout Module
Layout::Rect — Missing Methods
Missing Method Signature Notes
area rect.area → Integer Returns width * height
left rect.left → Integer Returns x (alias)
right rect.right → Integer Returns x + width
top rect.top → Integer Returns y (alias)
bottom rect.bottom → Integer Returns y + height
union rect.union(other) → Rect Bounding box of both rects
inner rect.inner(margin) → Rect Shrink by margin
offset rect.offset(dx, dy) → Rect Translate position
clamp rect.clamp(other) → Rect Clamp to bounds
rows rect.rows → Iterator Iterate row positions
columns rect.columns → Iterator Iterate column positions
positions rect.positions → Iterator Iterate all positions
is_empty rect.empty? → Boolean True if zero area

Layout::Constraint — Missing Batch Constructors
Missing Method Signature
from_lengths Constraint.from_lengths([10, 20, 30]) → [Constraint]
from_percentages Constraint.from_percentages([25, 50, 25]) → [Constraint]
from_mins Constraint.from_mins([5, 10, 15]) → [Constraint]
from_maxes Constraint.from_maxes([20, 30, 40]) → [Constraint]
from_fills Constraint.from_fills([1, 2, 1]) → [Constraint]
from_ratios Constraint.from_ratios([[1,4], [2,4], [1,4]]) → [Constraint]

Layout::Layout — Missing Parameters
Missing Parameter Ratatui Type Notes
margin Margin { horizontal, vertical } Edge margins
spacing u16 Gap between segments

MISSING — Style Module
Style::Style — Missing Parameters/Methods
MISSING — Text Module
Text::Span — Missing Methods
Missing Method Signature Notes
width span.width → Integer Display width in terminal cells
raw Span.raw(content) → Span Constructor without style (alias for new(content:))
patch_style span.patch_style(style) → Span Merge style on top of existing
reset_style span.reset_style → Span Clear style

Text::Line — Missing Methods
Missing Method Signature Notes
left_aligned line.left_aligned → Line Fluent setter for :left alignment
centered line.centered → Line Fluent setter for :center alignment
right_aligned line.right_aligned → Line Fluent setter for :right alignment
push_span line.push_span(span) → Line Append span
patch_style line.patch_style(style) → Line Merge style on all spans
reset_style line.reset_style → Line Clear style on all spans


Widgets::Table — Missing Row Methods (via Widgets::Row)
Missing Ratatui API Notes
enable_strikethrough row.enable_strikethrough() Enable strikethrough on row

Widget Computation Methods — Missing

These are public &self methods on upstream widgets that compute/query values without rendering.

| Widget | Missing Method | Ratatui API | Notes | |——–|—————-|————-|——-|

| List | len | list.len() → usize | Number of items in the list | | List | is_empty | list.is_empty() → bool | True if no items (empty? in Ruby) | | Canvas | get_point | canvas.get_point(x, y) → Option<(usize, usize)> | Map coordinates to grid cell |

[!NOTE] Paragraph#line_count(width) and Paragraph#line_width ARE exposed ✓Tabs#width IS exposed ✓


State Navigation Methods — Missing

ListState and TableState have navigation helpers that are not exposed.

State Class Missing Method Ratatui API Notes
ListState select_next state.select_next() Move selection to next item
ListState select_previous state.select_previous() Move selection to previous item
ListState select_first state.select_first() Jump to first item
ListState select_last state.select_last() Jump to last item

| TableState | selected_cell | state.selected_cell() | Get (row, col) tuple | | TableState | with_selected_cell | state.with_selected_cell((r,c)) | Builder pattern | | TableState | select_next_column | state.select_next_column() | Navigate columns | | TableState | select_previous_column | state.select_previous_column() | Navigate columns | | TableState | select_first_column | state.select_first_column() | Jump to first column | | TableState | select_last_column | state.select_last_column() | Jump to last column |


Layout Module — Additional Missing
Module Missing Ratatui API Notes
Rect as_position rect.as_position() → Position Convert to Position
Rect as_size rect.as_size() → Size Convert to Size
Constraint apply constraint.apply(length) → u16 Compute constrained size
Layout split_with_spacers layout.split_with_spacers(area) Returns segments AND spacers

Color — Missing Constructors
Missing Ratatui API Notes
from_u32 Color::from_u32(0xRRGGBB) Construct from hex integer
from_hsl Color::from_hsl(hsl) Construct from HSL (requires palette feature)
from_hsluv Color::from_hsluv(hsluv) Construct from HSLuv (requires palette feature)

Buffer — Missing Query Methods
Missing Method Ratatui API Notes
content buffer.content() → &[Cell] Get all cells as slice
get buffer.get(x, y) → &Cell Get cell at position
index_of buffer.index_of(x, y) → usize Position to linear index
pos_of buffer.pos_of(i) → (u16, u16) Linear index to position

alignment_audit_high_level

v0.7.0 Alignment Audit

This document audits strict alignment between RatatuiRuby v0.7.0 and the upstream Ratatui/Crossterm Rust libraries. The audit covers modules, classes, static methods, and constructor arguments as specified in the Ruby Frontend Design.

[!NOTE] The TUI facade API is explicitly excluded from this audit. It provides ergonomic shortcuts that intentionally diverge from Ratatui naming.

—

| margin | Margin | ❌ Missing | Gap | | spacing | u16 | ❌ Missing | Gap |

Verdict: Core layout aligned. Margin and spacing are gaps.



Gaps Analysis: MISSING vs MISALIGNED

[!IMPORTANT] MISSING = Can be added as new features without breaking backwards compatibility.
MISALIGNED = Requires breaking changes before v1.0.0 to fix API shape.

MISSING Features (Additive, Backwards-Compatible) ✅

These are gaps that can be filled in future minor releases without breaking existing code:

Component Missing Feature Notes
Rect area(), left(), right(), top(), bottom() New instance methods
Rect union(other), inner(margin), offset(offset) New instance methods
Constraint from_lengths(), from_percentages(), etc. New class methods
Layout margin, spacing New optional constructor args
Style sub_modifier, underline_color New optional constructor args
Span width() instance method New instance method
Span raw() constructor New class method (alias for new)
Line left_aligned(), centered(), right_aligned() New instance methods (fluent)

alignment_audit_symbol_sets

Audit of symbol set alignment between Ratatui’s symbols:: module and RatatuiRuby.

[!IMPORTANT] MISSING = Can be added as new features, backwards-compatible. MISALIGNED = Requires breaking changes before v1.0.0.

| scrollbar::Set | 4 predefined sets | ❌ Not exposed | MISSING | | shade constants | 5 constants | ❌ Not exposed | MISSING |

MISSING — Marker Enum
Marker::HalfBlock

| Marker::HalfBlock | ❌ Not exposed | MISSING |

Impact: Users cannot use the HalfBlock marker type, which provides double-resolution square pixels using █, ▄, and ▀ characters.


MISSING — Line Set Customization

Ratatui provides symbols::line::Set with predefined sets: - NORMAL — Standard box-drawing characters - ROUNDED — Rounded corners - DOUBLE — Double-line characters - THICK — Thick line characters

Ruby Status: Not directly exposed. Users cannot customize line symbols for widgets that use them internally.


MISSING — Bar Set Customization

Ratatui provides symbols::bar::Set with predefined sets: - THREE_LEVELS — 3 distinct fill levels - NINE_LEVELS — 9 distinct fill levels (default)

Ruby Status: Not exposed. Used internally by widgets like Sparkline but not configurable.


MISSING — Block Set Customization

Ratatui provides symbols::block::Set with predefined sets: - THREE_LEVELS — 3 distinct fill levels - NINE_LEVELS — 9 distinct fill levels (default)

Ruby Status: Not exposed. Used internally by Gauge widget but not configurable.


MISSING — Scrollbar Set Customization

Ratatui provides symbols::scrollbar::Set with predefined sets: - DOUBLE_VERTICAL — Double-line vertical scrollbar - DOUBLE_HORIZONTAL — Double-line horizontal scrollbar - VERTICAL — Single-line vertical scrollbar - HORIZONTAL — Single-line horizontal scrollbar

Ruby Status: Not exposed. Scrollbar widget not currently implemented in RatatuiRuby.


MISSING — Shade Constants

Ratatui provides symbols::shade constants: - EMPTY — (space) - LIGHT — ░ - MEDIUM — ▒ - DARK — ▓


Recommendations
Priority Item Notes
Low Add :half_block marker Single symbol addition
Low Expose line::Set customization For LineGauge widget
Low Expose bar::Set customization For Sparkline widget
Low Expose block::Set customization For Gauge widget
Medium Implement Scrollbar widget Would include scrollbar::Set

All missing items are additive and do not require breaking changes.


alignment_audit_tui_final

TUI API Alignment Audit

This document audits the RatatuiRuby::TUI facade API for method and parameter naming, with a focus on Developer Experience (DX) before the v1.0.0 release.

Design Philosophy

The TUI API follows a “Mullet Architecture”: structured namespaces in the library, flat ergonomic DSL for users.

Guiding Principles:

  1. Terseness — Fewer keystrokes for common operations

  2. DWIM — Do What I Mean; intuitive defaults

  3. TIMTOWTDI — Multiple valid ways to express the same thing

  4. Big Tent — Aliases for CSS/frontend developers, Ratatui natives, and Ruby purists

  5. Two Levels Max — tui.thing and tui.scope_thing, never tui.scope.thing, never tui.ascope_bscope_thing

Breaking Changes: Pre-1.0 with few external users. Rename aggressively for DX. Document in CHANGELOG.


Method Naming Recommendations
Pattern: Base Methods + Aliases + Dispatchers

Base methods align with Ratatui’s module API names. Aliases provide ergonomic shortcuts.

  1. Base method (Ratatui-aligned): tui.shape_circle(...) — matches Widgets::Shape::Circle

  2. Aliases (ergonomic): tui.circle(...), tui.circle_shape(...)

  3. Dispatcher: tui.shape(:circle, ...) — errors helpfully on missing type

This pattern applies to: shapes, constraints, text elements.


Canvas Shapes
Base Method Add Aliases Dispatcher
shape_circle circle, circle_shape shape(:circle, ...)
shape_line line_shape (not bare line — conflicts with Text::Line) shape(:line, ...)
shape_point point, point_shape shape(:point, ...)
shape_rectangle rectangle, rectangle_shape shape(:rectangle, ...)
shape_map map, map_shape shape(:map, ...)
shape_label label, label_shape shape(:label, ...)

Dispatcher signature:

def shape(type, **kwargs)
  case type
  when :circle then shape_circle(**kwargs)
  when :line then shape_line(**kwargs)
  # ...
  else
    raise ArgumentError, "Unknown shape type: #{type.inspect}. " \
      "Valid types: :circle, :line, :point, :rectangle, :map, :label"
  end
end

Layout Constraints

Ratatui’s constraints map well to CSS layout concepts. Offer aliases for both communities:

Base Method Add Aliases (CSS-Friendly) Dispatcher
constraint_length(n) fixed(n), length(n) constraint(:length, n)
constraint_percentage(n) percent(n), percentage(n) constraint(:percentage, n)
constraint_min(n) min(n), min_content(n) constraint(:min, n)
constraint_max(n) max(n), max_content(n) constraint(:max, n)
constraint_fill(n) fill(n), flex(n), fr(n) constraint(:fill, n)
constraint_ratio(a,b) ratio(a,b), aspect(a,b) constraint(:ratio, a, b)

CSS Flexbox/Grid parallels: - fill(1) ≈ CSS flex: 1 or 1fr - fixed(100) ≈ CSS width: 100px - min(50) ≈ CSS min-width: 50px - percent(25) ≈ CSS width: 25%

Dispatcher signature:

def constraint(type, *args)
  case type
  when :length, :fixed then constraint_length(*args)
  when :percentage, :percent then constraint_percentage(*args)
  when :min then constraint_min(*args)
  when :max then constraint_max(*args)
  when :fill, :flex, :fr then constraint_fill(*args)
  when :ratio, :aspect then constraint_ratio(*args)
  else
    raise ArgumentError, "Unknown constraint type: #{type.inspect}. " \
      "Valid types: :length, :percentage, :min, :max, :fill, :ratio"
  end
end

Layout Operations
Current Add Alias Rationale
layout_split split 52 usages in examples; clear in context

Text Factories
Current Status Notes
text_span ✓ Has alias span
text_line ✓ Has alias line
text_width Keep as-is Distinct from length (constraint)

Add dispatcher:

def text(type, **kwargs)
  case type
  when :span then text_span(**kwargs)
  when :line then text_line(**kwargs)
  else
    raise ArgumentError, "Unknown text type: #{type.inspect}. Valid types: :span, :line"
  end
end

Widget Factories
Current Add Alias Rationale
list_item item Clear in list context
table_row Keep alongside row DWIM — both valid mental models
table_cell Keep as-is cell means Buffer::Cell
bar_chart_bar Keep alongside bar DWIM — don’t deprecate
bar_chart_bar_group Keep alongside bar_group DWIM — don’t deprecate

Add dispatcher:

def widget(type, **kwargs)
  case type
  when :block then block(**kwargs)
  when :paragraph then paragraph(**kwargs)
  when :list then list(**kwargs)
  when :table then table(**kwargs)
  # ... all widgets
  else
    raise ArgumentError, "Unknown widget type: #{type.inspect}."
  end
end

State Factories
Current Status
list_state Keep as-is
table_state Keep as-is
scrollbar_state Keep as-is

Add dispatcher:

def state(type, **kwargs)
  case type
  when :list then list_state(**kwargs)
  when :table then table_state(**kwargs)
  when :scrollbar then scrollbar_state(**kwargs)
  else
    raise ArgumentError, "Unknown state type: #{type.inspect}."
  end
end

Parameter Names

All current parameter names are well-chosen. No changes recommended.

Widget Parameter Status
List selected_index, highlight_style, etc. ✓
Table row_highlight_style, selected_row, etc. ✓
Scrollbar content_length, position, etc. ✓
All block, style, offset ✓ Consistent

Summary of Changes
High Priority (Immediate DX Wins)
  1. Add split alias for layout_split

  2. Add item alias for list_item

  3. Add terse shape aliases: circle, point, rectangle, map, label

  4. Add CSS-friendly constraint aliases: fixed, percent, fill, flex, fr, min, max

Medium Priority (Pattern Completion)
  1. Add dispatcher methods: shape(type, ...), constraint(type, ...), text(type, ...), widget(type, ...), state(type, ...)

  2. Add bidirectional shape aliases: circle_shape, point_shape, etc.

Not Changing

Implementation Checklist

Breaking Changes Analysis

If all recommendations in this audit are adopted, none constitute breaking changes under semver.

Recommendation Breaking? Rationale
Add split alias No Additive; layout_split unchanged
Add item alias No Additive; list_item unchanged
Add terse shape aliases (circle, etc.) No Additive; shape_* methods unchanged
Add CSS-friendly constraint aliases No Additive; constraint_* methods unchanged
Add bidirectional aliases (*_shape) No Additive; does not remove existing forms
Add dispatcher methods No Additive; new methods only
Keep verbose forms (table_row, etc.) No No removal or rename

Conclusion: This audit recommends only additive changes. All existing code will continue to work unchanged.

[!NOTE] If we later decide to remove verbose forms like bar_chart_bar or bar_chart_bar_group, that would be a breaking change requiring a major version bump. This audit explicitly recommends keeping them (DWIM philosophy).


dwim_dx

dwim_dx

Problem Statement

Ruby’s philosophy of “Do What I Mean” (DWIM) and human-centric design should extend to ratatui_ruby’s API. Currently, app developers encounter friction points that force them to remember non-obvious conventions, use overly verbose code, or pattern-match when simple predicates would suffice.

This proposal identifies DX issues across the widget API and suggests improvements that maintain backward compatibility while providing ergonomic alternatives.

DX Issues Identified

1. Confusing Event Method Names

Current problem: event.char doesn’t exist, but event.code returns things like "enter", "ctrl", not just characters.

What users expect: - event.char should return the printable character (matching the name) - event.ctrl_c?, event.enter?, etc. should work for all key combinations - event.key?, event.mouse? predicates exist but only for broad categories

Solution implemented: Added char method and dynamic predicates via method_missing. See lib/ratatui_ruby/event/key.rb.

2. Dual Parameter APIs Without Predicates

Current problem: Widgets accept both forms but no convenience methods to query the state:

### Both work, but which one does the widget store?
gauge1 = Gauge.new(ratio: 0.75)
gauge2 = Gauge.new(percent: 75)
gauge1.ratio  # Works
gauge1.percent  # Does NOT exist

Similarly with List and Table:

list.selected_index = 2  # Works
list.selected?  # Does NOT exist
list.is_selected?  # Does NOT exist

Affected widgets: - Gauge (ratio vs percent) - LineGauge (ratio vs percent) - List (selected_index with no query methods) - Table (selected_row and selected_column with no query methods)

Suggested solutions:

For Gauge and LineGauge:

### Add convenience predicates
gauge.percent  # => 75 (coerced from ratio internally)
gauge.percent = 50  # => Updates ratio to 0.5

### Or provide explicit accessors
gauge.as_percent  # => 75
gauge.as_ratio   # => 0.75

For List and Table:

list.selected?  # => true if selected_index is not nil
list.selection  # => 2 (alias for selected_index)
list.selected_item  # => "Item 3"

table.selected_row?  # => true if selected_row is not nil
table.selected_cell?  # => true if both row and column selected
3. Symbol Constants for Enum Values

Current problem: Magic symbol values scattered across code:

list = List.new(
  highlight_spacing: :when_selected,  # What are the other options?
  direction: :top_to_bottom,          # Is :bottom_to_top valid?
)

layout = Layout.new(
  flex: :legacy  # What does "legacy" mean?
)

gauge = Gauge.new(
  use_unicode: true  # Unclear what ASCII fallback looks like
)

Users must consult docs or source code to discover valid options.

Suggested solution: Add constants to widget classes:

class List < Data
  # Highlight spacing modes
  HIGHLIGHT_ALWAYS = :always
  HIGHLIGHT_WHEN_SELECTED = :when_selected
  HIGHLIGHT_NEVER = :never

  # Direction modes
  DIRECTION_TOP_TO_BOTTOM = :top_to_bottom
  DIRECTION_BOTTOM_TO_TOP = :bottom_to_top
end

list = List.new(
  highlight_spacing: List::HIGHLIGHT_WHEN_SELECTED,
  direction: List::DIRECTION_TOP_TO_BOTTOM,
)

Benefits: - IDE autocomplete shows valid options - Self-documenting code - Typos caught at runtime (symbol vs constant) - Easy to grep for where these modes are used

Affected widgets and their enum values: - List: highlight_spacing (:always, :when_selected, :never), direction (:top_to_bottom, :bottom_to_top) - Table: highlight_spacing (same as List), flex (:legacy, :default, :fill) - Layout: direction (:vertical, :horizontal), flex (:legacy, :default, :fill) - Gauge/LineGauge: use_unicode (boolean, but could have MODE_UNICODE, MODE_ASCII) - Paragraph: alignment (:left, :center, :right) - Block: border_type (:plain, :rounded, :double, :thick) - Canvas: marker (:braille, :dots, :half_block, :sextant, :octant)

4. Inconsistent Style APIs

Current problem: Different widgets accept styles differently:

### Table accepts both
table = Table.new(style: Style.new(fg: :blue))
table = Table.new(style: { fg: :blue })  # Hash shorthand

### But Paragraph doesn't
paragraph = Paragraph.new(text: "hi", style: Style.new(fg: :blue))
paragraph = Paragraph.new(text: "hi", style: { fg: :blue })  # Works but undocumented

### And Gauge has separate properties
gauge = Gauge.new(style: Style.new(fg: :blue), gauge_style: Style.new(fg: :green))

Suggested solution: Standardize style handling across all widgets:

  1. All widgets should accept Style objects and Hash shorthand

  2. Document this clearly in each widget

  3. Add a convenience constructor:

class Style
  def self.with(fg: nil, bg: nil, modifiers: [])
    Style.new(fg: fg, bg: bg, modifiers: modifiers)
  end
end

### Cleaner than always spelling out keyword args
paragraph = Paragraph.new(text: "hi", style: Style.with(fg: :blue))
5. Missing State Query Predicates

Current problem: Widgets store state but provide no query methods:

list.selected_index = 0

### To check if something is selected, must do:
if list.selected_index&.nonzero?  # Awkward
if list.selected_index.nil? == false  # Confusing

### Should be:
list.selected?  # => true
list.empty?  # => false (for items array)

Suggested solution: Add predicates to state-holding widgets:

### List
list.selected?      # => !selected_index.nil?
list.empty?         # => items.empty?
list.selection      # => selected_index (alias)
list.selected_item  # => items[selected_index] (convenience)

### Table
table.selected_row?    # => !selected_row.nil?
table.selected_cell?   # => !selected_row.nil? && !selected_column.nil?
table.empty?           # => rows.empty?

### Gauge
gauge.filled?          # => ratio > 0
gauge.complete?        # => ratio >= 1.0
6. Magic Numeric Coercions

Current problem: Widgets accept Numeric but silently coerce:

### These all work, but behavior is undocumented
list = List.new(selected_index: "2")    # Coerced to 2
list = List.new(selected_index: 2.7)    # Coerced to 2
list = List.new(selected_index: 2.0)    # Coerced to 2

gauge = Gauge.new(percent: 150)  # Should clamp?
gauge = Gauge.new(ratio: 1.5)    # Should clamp?

Suggested solution:

  1. Document coercion rules explicitly in RDoc

  2. Add validation and raise on invalid inputs:

def initialize(percent: nil, ...)
  if percent
    raise ArgumentError, "percent must be 0..100, got #{percent}" unless percent.between?(0, 100)
    ratio = Float(percent) / 100.0
  end
end
  1. Provide clear error messages:

    gauge = Gauge.new(percent: 150)
    ### => ArgumentError: percent must be between 0 and 100 (got 150)
    

Implementation Strategy

Phase 1: State Query Predicates
Phase 2: Symbol Constants
Phase 3: Style Consistency
Phase 4: Numeric Coercion Validation
Phase 5: Convenience Accessors

Example: Before and After

Before (Confusing)
class GameApp
  def initialize
    @menu = List.new(
      items: ["Start Game", "Load Game", "Options", "Quit"],
      selected_index: 0,
      highlight_spacing: :when_selected,  # What's valid here?
      direction: :top_to_bottom
    )
  end

  def handle_input(event)
    case event
    when :ctrl_c
      exit
    when :up
      if @menu.selected_index && @menu.selected_index > 0
        @menu = @menu.with(selected_index: @menu.selected_index - 1)
      end
    end
  end

  def render(tui)
    tui.draw(@menu)
  end
end
After (DWIM)
class GameApp
  def initialize
    @menu = List.new(
      items: ["Start Game", "Load Game", "Options", "Quit"],
      selected_index: 0,
      highlight_spacing: List::HIGHLIGHT_WHEN_SELECTED,  # IDE autocomplete!
      direction: List::DIRECTION_TOP_TO_BOTTOM
    )
  end

  def handle_input(event)
    return if event.ctrl_c?  # Dynamic predicate!
    
    if event.up?
      move_menu_up if @menu.selected?  # State predicate!
    end
  end

  def move_menu_up
    index = @menu.selected_index
    return if index == 0
    @menu = @menu.with(selected_index: index - 1)
  end

  def render(tui)
    tui.draw(@menu)
  end
end

Migration Path

All changes are backward compatible (additive): - Existing code using symbols continues to work - New constants coexist with symbols - New predicates don’t change existing behavior - New methods are additions, not replacements

Apps can migrate at their own pace:

### Old style still works
list = List.new(highlight_spacing: :when_selected)

### New style also works
list = List.new(highlight_spacing: List::HIGHLIGHT_WHEN_SELECTED)

### Mix and match
if list.selected?  # New predicate
  puts list.selected_index  # Old accessor
end

Metrics for Success

  1. Discoverability: New developers can find valid options via IDE autocomplete

  2. Clarity: Code self-documents valid states and modes

  3. Type safety: Constants and predicates provide type checking

  4. Error feedback: Invalid inputs raise with helpful messages

  5. Backward compatibility: Zero breaking changes, all existing code works

Related Issues


examples_audit

examples_audit

P1: Moderate (Quality)
  1. {Add RDoc Cross-Links}[#1-add-rdoc-cross-links-examples–aliases] (Documentation discoverability)

  2. Link library classes/methods to examples

  3. Link DWIM/TIMTOWTDI aliases

  4. Create consistent pattern across public APIs


p2_moderate

Priority 2: Moderate (Quality Gates)

These are v1.0.0 quality improvements that refine the example suite after P0 is complete. Not blocking, but recommended for maintainability and API consistency.


1. Add RDoc Cross-Links (Examples & Aliases)

Status: Important for API discoverability — Documentation should link library and examples

RDoc should cross-link between: - Library classes/methods ↔ Examples that use them (See also: examples/widget_foo) - Primary methods ↔ DWIM/TIMTOWTDI aliases (See also: tui.foo_bar as alias for tui.foo(:bar))

Current Practice

Done for: - RatatuiRuby::Frame#set_cursor_position ↔ RatatuiRuby::Cursor (cross-linking) - Limited elsewhere

Gaps
Action
  1. Add # See also: examples/widget_foo/app.rb to class/method RDoc

  2. Link DWIM methods to TIMTOWTDI variants: # Also available as: tui.constraint_length (DWIM) vs tui.constraint(:length) (TIMTOWTDI)

  3. Create consistent pattern across all public APIs in lib/ratatui_ruby/

Example Pattern
#### Renders text with styling.
#
#### See also: examples/widget_paragraph/app.rb (basic paragraph rendering)
class Paragraph < Data.define(...)
  # ...
end

#### DWIM version of constraint creation
#### Also available as: constraint(type, value) for explicit control
def constraint_length(length)
  constraint(:length, length)
end

2. Enhance Widget Examples with Functional Context

Status: Recommended — Move beyond “parameter playgrounds” to “real-world patterns”

Current widget_* examples mostly focus on interactive parameter turning (changing colors, borders, etc.). While useful for API discovery, they don’t show how to use the widget in a real application logic flow.

The Standard: widget_tabs

The widget_tabs was enhanced to show conditional rendering of content based on the selected tab in git commit 38ceed39a011d557cc66e11a4598d3341dc7a0cc. It doesn’t just highlight the tab; it changes the screen content. This connects the widget (the tabs) to the problem it solves (view segregation).

Action

Identify other widget examples that could benefit from this “functional context” treatment:

Goal: Every widget example should answer “How do I build a feature with this?” not just “What does this parameter do?”