rich-ruby 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +80 -0
- data/LICENSE +21 -21
- data/README.md +547 -547
- data/docs/architecture.md +43 -0
- data/docs/cheat-sheet.md +52 -0
- data/docs/customization.md +53 -0
- data/docs/how-to-use.md +96 -0
- data/docs/test-report.md +112 -0
- data/docs/troubleshooting.md +36 -0
- data/docs/windows-notes.md +30 -0
- data/examples/demo.rb +106 -106
- data/examples/showcase.rb +420 -420
- data/examples/smoke_test.rb +41 -41
- data/examples/stress_test.rb +604 -604
- data/examples/syntax_markdown_demo.rb +166 -166
- data/examples/verify.rb +216 -215
- data/examples/visual_demo.rb +145 -145
- data/lib/rich/_palettes.rb +148 -148
- data/lib/rich/box.rb +342 -342
- data/lib/rich/cells.rb +524 -512
- data/lib/rich/color.rb +631 -628
- data/lib/rich/color_triplet.rb +227 -220
- data/lib/rich/console.rb +604 -549
- data/lib/rich/control.rb +332 -332
- data/lib/rich/json.rb +260 -254
- data/lib/rich/layout.rb +314 -314
- data/lib/rich/markdown.rb +531 -509
- data/lib/rich/markup.rb +186 -175
- data/lib/rich/panel.rb +318 -311
- data/lib/rich/progress.rb +430 -430
- data/lib/rich/segment.rb +387 -387
- data/lib/rich/style.rb +464 -433
- data/lib/rich/syntax.rb +1220 -1145
- data/lib/rich/table.rb +547 -525
- data/lib/rich/terminal_theme.rb +126 -126
- data/lib/rich/text.rb +460 -433
- data/lib/rich/tree.rb +220 -220
- data/lib/rich/version.rb +5 -5
- data/lib/rich/win32_console.rb +620 -582
- data/lib/rich.rb +108 -108
- metadata +15 -5
data/examples/verify.rb
CHANGED
|
@@ -1,215 +1,216 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Full verification test for the Rich library
|
|
4
|
-
|
|
5
|
-
require_relative "../lib/rich"
|
|
6
|
-
|
|
7
|
-
puts "=" * 60
|
|
8
|
-
puts "Rich Library Verification Test"
|
|
9
|
-
puts "=" * 60
|
|
10
|
-
puts ""
|
|
11
|
-
|
|
12
|
-
# Track results
|
|
13
|
-
results = []
|
|
14
|
-
|
|
15
|
-
def test(name)
|
|
16
|
-
print "Testing #{name}... "
|
|
17
|
-
begin
|
|
18
|
-
yield
|
|
19
|
-
puts "✓ PASS"
|
|
20
|
-
true
|
|
21
|
-
rescue StandardError => e
|
|
22
|
-
puts "✗ FAIL: #{e.message}"
|
|
23
|
-
false
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Test 1: Basic imports
|
|
28
|
-
results << test("Module loading") do
|
|
29
|
-
raise "Console not defined" unless defined?(Rich::Console)
|
|
30
|
-
raise "Color not defined" unless defined?(Rich::Color)
|
|
31
|
-
raise "Style not defined" unless defined?(Rich::Style)
|
|
32
|
-
raise "Text not defined" unless defined?(Rich::Text)
|
|
33
|
-
raise "Panel not defined" unless defined?(Rich::Panel)
|
|
34
|
-
raise "Table not defined" unless defined?(Rich::Table)
|
|
35
|
-
raise "Tree not defined" unless defined?(Rich::Tree)
|
|
36
|
-
raise "Progress not defined" unless defined?(Rich::ProgressBar)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Test 2: ColorTriplet
|
|
40
|
-
results << test("ColorTriplet") do
|
|
41
|
-
triplet = Rich::ColorTriplet.new(255, 128, 64)
|
|
42
|
-
raise "Hex wrong" unless triplet.hex == "
|
|
43
|
-
raise "
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
raise "
|
|
66
|
-
raise "
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
raise "
|
|
82
|
-
raise "
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
raise "
|
|
89
|
-
raise "
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
raise "
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
text.
|
|
103
|
-
|
|
104
|
-
raise "
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
raise "
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
raise "No
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
table.
|
|
126
|
-
table.add_column("
|
|
127
|
-
table.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
raise "No
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
tree.
|
|
137
|
-
tree.add("Child
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
raise "No
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
raise "
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
spinner.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
boxes
|
|
166
|
-
|
|
167
|
-
raise "Missing
|
|
168
|
-
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
raise "
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
raise "
|
|
201
|
-
raise "
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
puts "
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
puts "
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Full verification test for the Rich library
|
|
4
|
+
|
|
5
|
+
require_relative "../lib/rich"
|
|
6
|
+
|
|
7
|
+
puts "=" * 60
|
|
8
|
+
puts "Rich Library Verification Test"
|
|
9
|
+
puts "=" * 60
|
|
10
|
+
puts ""
|
|
11
|
+
|
|
12
|
+
# Track results
|
|
13
|
+
results = []
|
|
14
|
+
|
|
15
|
+
def test(name)
|
|
16
|
+
print "Testing #{name}... "
|
|
17
|
+
begin
|
|
18
|
+
yield
|
|
19
|
+
puts "✓ PASS"
|
|
20
|
+
true
|
|
21
|
+
rescue StandardError => e
|
|
22
|
+
puts "✗ FAIL: #{e.message}"
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Test 1: Basic imports
|
|
28
|
+
results << test("Module loading") do
|
|
29
|
+
raise "Console not defined" unless defined?(Rich::Console)
|
|
30
|
+
raise "Color not defined" unless defined?(Rich::Color)
|
|
31
|
+
raise "Style not defined" unless defined?(Rich::Style)
|
|
32
|
+
raise "Text not defined" unless defined?(Rich::Text)
|
|
33
|
+
raise "Panel not defined" unless defined?(Rich::Panel)
|
|
34
|
+
raise "Table not defined" unless defined?(Rich::Table)
|
|
35
|
+
raise "Tree not defined" unless defined?(Rich::Tree)
|
|
36
|
+
raise "Progress not defined" unless defined?(Rich::ProgressBar)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Test 2: ColorTriplet
|
|
40
|
+
results << test("ColorTriplet") do
|
|
41
|
+
triplet = Rich::ColorTriplet.new(255, 128, 64)
|
|
42
|
+
raise "Hex wrong" unless triplet.hex == "ff8040"
|
|
43
|
+
raise "Hex-with-hash wrong" unless triplet.hex_with_hash == "#ff8040"
|
|
44
|
+
raise "RGB wrong" unless triplet.red == 255 && triplet.green == 128
|
|
45
|
+
|
|
46
|
+
from_hex = Rich::ColorTriplet.from_hex("#00ff00")
|
|
47
|
+
raise "From hex wrong" unless from_hex.green == 255
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Test 3: Color parsing
|
|
51
|
+
results << test("Color parsing") do
|
|
52
|
+
red = Rich::Color.parse("red")
|
|
53
|
+
raise "Red not parsed" unless red.type == Rich::ColorType::STANDARD
|
|
54
|
+
|
|
55
|
+
hex = Rich::Color.parse("#ff5500")
|
|
56
|
+
raise "Hex not parsed" unless hex.type == Rich::ColorType::TRUECOLOR
|
|
57
|
+
|
|
58
|
+
named = Rich::Color.parse("bright_blue")
|
|
59
|
+
raise "Named not parsed" unless named.number == 12
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Test 4: Style parsing
|
|
63
|
+
results << test("Style parsing") do
|
|
64
|
+
style = Rich::Style.parse("bold red on white")
|
|
65
|
+
raise "Bold not set" unless style.bold?
|
|
66
|
+
raise "Color wrong" unless style.color.name == "red"
|
|
67
|
+
raise "Bgcolor wrong" unless style.bgcolor.name == "white"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Test 5: Style combination
|
|
71
|
+
results << test("Style combination") do
|
|
72
|
+
s1 = Rich::Style.parse("bold")
|
|
73
|
+
s2 = Rich::Style.parse("red")
|
|
74
|
+
combined = s1 + s2
|
|
75
|
+
raise "Combination failed" unless combined.bold? && combined.color.name == "red"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Test 6: Console creation
|
|
79
|
+
results << test("Console creation") do
|
|
80
|
+
console = Rich::Console.new
|
|
81
|
+
raise "Width missing" unless console.width > 0
|
|
82
|
+
raise "Height missing" unless console.height > 0
|
|
83
|
+
raise "Color system missing" unless Rich::ColorSystem::ALL.include?(console.color_system)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Test 7: Cell width calculation
|
|
87
|
+
results << test("Cell width calculation") do
|
|
88
|
+
raise "ASCII wrong" unless Rich::Cells.cell_len("Hello") == 5
|
|
89
|
+
raise "CJK wrong" unless Rich::Cells.cell_len("你好") == 4 # 2 chars × 2 width
|
|
90
|
+
raise "Empty wrong" unless Rich::Cells.cell_len("") == 0
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Test 8: Segment creation
|
|
94
|
+
results << test("Segment creation") do
|
|
95
|
+
seg = Rich::Segment.new("Hello", style: Rich::Style.parse("bold"))
|
|
96
|
+
raise "Text wrong" unless seg.text == "Hello"
|
|
97
|
+
raise "Style missing" unless seg.style.bold?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Test 9: Text with spans
|
|
101
|
+
results << test("Text with spans") do
|
|
102
|
+
text = Rich::Text.new("Hello ")
|
|
103
|
+
text.append("World", style: "red")
|
|
104
|
+
raise "Plain wrong" unless text.plain == "Hello World"
|
|
105
|
+
raise "Spans wrong" unless text.spans.length == 1
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Test 10: Markup parsing
|
|
109
|
+
results << test("Markup parsing") do
|
|
110
|
+
text = Rich::Markup.parse("[bold]Hello[/bold]")
|
|
111
|
+
raise "Parse failed" unless text.plain == "Hello"
|
|
112
|
+
raise "Style not applied" unless text.spans.any? { |s| s.style.bold? }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Test 11: Panel rendering
|
|
116
|
+
results << test("Panel rendering") do
|
|
117
|
+
panel = Rich::Panel.new("Content", title: "Title")
|
|
118
|
+
output = panel.render(max_width: 40)
|
|
119
|
+
raise "No border" unless output.include?("╭") || output.include?("+")
|
|
120
|
+
raise "No content" unless output.include?("Content")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Test 12: Table rendering
|
|
124
|
+
results << test("Table rendering") do
|
|
125
|
+
table = Rich::Table.new
|
|
126
|
+
table.add_column("Name")
|
|
127
|
+
table.add_column("Value")
|
|
128
|
+
table.add_row("Key", "123")
|
|
129
|
+
output = table.render(max_width: 40)
|
|
130
|
+
raise "No header" unless output.include?("Name")
|
|
131
|
+
raise "No data" unless output.include?("123")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Test 13: Tree rendering
|
|
135
|
+
results << test("Tree rendering") do
|
|
136
|
+
tree = Rich::Tree.new("Root")
|
|
137
|
+
tree.add("Child 1")
|
|
138
|
+
tree.add("Child 2")
|
|
139
|
+
output = tree.render
|
|
140
|
+
raise "No root" unless output.include?("Root")
|
|
141
|
+
raise "No children" unless output.include?("Child")
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Test 14: Progress bar
|
|
145
|
+
results << test("Progress bar") do
|
|
146
|
+
bar = Rich::ProgressBar.new(total: 100, completed: 50)
|
|
147
|
+
raise "Progress wrong" unless bar.progress == 0.5
|
|
148
|
+
raise "Percentage wrong" unless bar.percentage == 50
|
|
149
|
+
|
|
150
|
+
bar.advance(25)
|
|
151
|
+
raise "Advance failed" unless bar.percentage == 75
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Test 15: Spinner
|
|
155
|
+
results << test("Spinner") do
|
|
156
|
+
spinner = Rich::Spinner.new
|
|
157
|
+
frame1 = spinner.frame
|
|
158
|
+
spinner.advance
|
|
159
|
+
frame2 = spinner.frame
|
|
160
|
+
raise "Spinner not advancing" if frame1 == frame2 && spinner.frames.length > 1
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Test 16: Box styles
|
|
164
|
+
results << test("Box styles") do
|
|
165
|
+
boxes = [Rich::Box::ASCII, Rich::Box::ROUNDED, Rich::Box::HEAVY, Rich::Box::DOUBLE]
|
|
166
|
+
boxes.each do |box|
|
|
167
|
+
raise "Missing top_left" if box.top_left.nil?
|
|
168
|
+
raise "Missing horizontal" if box.horizontal.nil?
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Test 17: JSON highlighting
|
|
173
|
+
results << test("JSON highlighting") do
|
|
174
|
+
data = { "name" => "test", "value" => 123 }
|
|
175
|
+
output = Rich::JSON.to_s(data)
|
|
176
|
+
raise "No output" if output.empty?
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Test 18: Columns layout
|
|
180
|
+
results << test("Columns layout") do
|
|
181
|
+
cols = Rich::Columns.new(%w[one two three four])
|
|
182
|
+
output = cols.render(max_width: 40)
|
|
183
|
+
raise "No content" unless output.include?("one")
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Test 19: Windows Console API (on Windows)
|
|
187
|
+
if Gem.win_platform?
|
|
188
|
+
results << test("Windows Console API") do
|
|
189
|
+
raise "Win32Console not loaded" unless defined?(Rich::Win32Console)
|
|
190
|
+
raise "supports_ansi? missing" unless Rich::Win32Console.respond_to?(:supports_ansi?)
|
|
191
|
+
|
|
192
|
+
# Get console size
|
|
193
|
+
size = Rich::Win32Console.get_size
|
|
194
|
+
raise "Size detection failed" unless size && size[0] > 0
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Test 20: Control codes
|
|
199
|
+
results << test("Control codes") do
|
|
200
|
+
raise "Clear missing" if Rich::Control.clear_screen.empty?
|
|
201
|
+
raise "Cursor up missing" if Rich::Control.cursor_up(5).empty?
|
|
202
|
+
raise "Reset missing" if Rich::Control.reset.empty?
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
puts ""
|
|
206
|
+
puts "=" * 60
|
|
207
|
+
passed = results.count(true)
|
|
208
|
+
total = results.length
|
|
209
|
+
puts "Results: #{passed}/#{total} tests passed"
|
|
210
|
+
puts "=" * 60
|
|
211
|
+
|
|
212
|
+
if passed == total
|
|
213
|
+
puts "\n🎉 All tests passed! Rich library is fully functional."
|
|
214
|
+
else
|
|
215
|
+
puts "\n⚠️ Some tests failed. Please review the output above."
|
|
216
|
+
end
|