ruby_rich 0.1.0
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 +7 -0
- data/lib/ruby_rich/console.rb +53 -0
- data/lib/ruby_rich/progress_bar.rb +26 -0
- data/lib/ruby_rich/rich_panel.rb +94 -0
- data/lib/ruby_rich/rich_print.rb +60 -0
- data/lib/ruby_rich/rich_text.rb +80 -0
- data/lib/ruby_rich/table.rb +137 -0
- data/lib/ruby_rich/version.rb +3 -0
- data/lib/ruby_rich.rb +36 -0
- metadata +76 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: af37dc09091efdc06215f083a176d91ce1b9ecf240ba22f4471b739b9eaeb890
|
4
|
+
data.tar.gz: 57e7a9e0378b20353b94d9f815d9c96e1865f96128257857921c80e5f7a31fb9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 440203e48f904f11270482a9e80f9edb28787e64302d6d6dcf8527eaee2ec57028303e8d8a331b6bfe2ce45c445aba122ceaa6cdd975a524ce62f8c55fe2638f
|
7
|
+
data.tar.gz: 4f043b626479294f8d785e6e181614e1b2b0ca867f5714a8e6323ccb6b96433ad0ec7ef432b173ecc4cfbe9e6ecc215799174fffcb5953a3d0ce41bad8964f74
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RubyRich
|
2
|
+
class Console
|
3
|
+
def initialize
|
4
|
+
@lines = []
|
5
|
+
@buffer = []
|
6
|
+
@layout = { spacing: 1, align: :left }
|
7
|
+
end
|
8
|
+
|
9
|
+
def set_layout(spacing: 1, align: :left)
|
10
|
+
@layout[:spacing] = spacing
|
11
|
+
@layout[:align] = align
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_line(text)
|
15
|
+
@lines << text
|
16
|
+
end
|
17
|
+
|
18
|
+
def clear
|
19
|
+
print "\e[H\e[2J"
|
20
|
+
end
|
21
|
+
|
22
|
+
def render
|
23
|
+
clear
|
24
|
+
@lines.each_with_index do |line, index|
|
25
|
+
formatted_line = format_line(line)
|
26
|
+
@buffer << formatted_line
|
27
|
+
puts formatted_line
|
28
|
+
puts "\n" * @layout[:spacing] if index < @lines.size - 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def update_line(index, text)
|
33
|
+
return unless index.between?(0, @lines.size - 1)
|
34
|
+
|
35
|
+
@lines[index] = text
|
36
|
+
render
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def format_line(line)
|
42
|
+
content = line.is_a?(RichText) ? line.render : line
|
43
|
+
case @layout[:align]
|
44
|
+
when :center
|
45
|
+
content.center(80)
|
46
|
+
when :right
|
47
|
+
content.rjust(80)
|
48
|
+
else
|
49
|
+
content
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RubyRich
|
2
|
+
class ProgressBar
|
3
|
+
def initialize(total, width: 50, style: :default)
|
4
|
+
@total = total
|
5
|
+
@progress = 0
|
6
|
+
@width = width
|
7
|
+
@style = style
|
8
|
+
end
|
9
|
+
|
10
|
+
def advance(amount)
|
11
|
+
@progress += amount
|
12
|
+
@progress = @total if @progress > @total
|
13
|
+
render
|
14
|
+
end
|
15
|
+
|
16
|
+
def render
|
17
|
+
percentage = (@progress.to_f / @total * 100).to_i
|
18
|
+
completed_width = (@progress.to_f / @total * @width).to_i
|
19
|
+
incomplete_width = @width - completed_width
|
20
|
+
|
21
|
+
bar = "[#{"=" * completed_width}#{" " * incomplete_width}]"
|
22
|
+
print "\r#{bar} #{percentage}%"
|
23
|
+
puts if @progress == @total
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module RubyRich
|
2
|
+
class RichPanel
|
3
|
+
# ANSI escape codes for styling
|
4
|
+
ANSI_CODES = {
|
5
|
+
reset: "\e[0m",
|
6
|
+
bold: "\e[1m",
|
7
|
+
underline: "\e[4m",
|
8
|
+
color: {
|
9
|
+
black: "\e[30m",
|
10
|
+
red: "\e[31m",
|
11
|
+
green: "\e[32m",
|
12
|
+
yellow: "\e[33m",
|
13
|
+
blue: "\e[34m",
|
14
|
+
magenta: "\e[35m",
|
15
|
+
cyan: "\e[36m",
|
16
|
+
white: "\e[37m"
|
17
|
+
},
|
18
|
+
background: {
|
19
|
+
black: "\e[40m",
|
20
|
+
red: "\e[41m",
|
21
|
+
green: "\e[42m",
|
22
|
+
yellow: "\e[43m",
|
23
|
+
blue: "\e[44m",
|
24
|
+
magenta: "\e[45m",
|
25
|
+
cyan: "\e[46m",
|
26
|
+
white: "\e[47m"
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
attr_accessor :title, :content, :border_color, :title_color, :footer
|
31
|
+
|
32
|
+
def initialize(content, title: nil, footer: nil, border_color: :white, title_color: :white)
|
33
|
+
@content = content.is_a?(String) ? content.split("\n") : content
|
34
|
+
@title = title
|
35
|
+
@footer = footer
|
36
|
+
@border_color = border_color
|
37
|
+
@title_color = title_color
|
38
|
+
end
|
39
|
+
|
40
|
+
def render
|
41
|
+
content_lines = format_content
|
42
|
+
panel_width = calculate_panel_width(content_lines)
|
43
|
+
|
44
|
+
lines = []
|
45
|
+
lines << top_border(panel_width)
|
46
|
+
lines += content_lines.map { |line| format_line(line, panel_width) }
|
47
|
+
lines << bottom_border(panel_width)
|
48
|
+
|
49
|
+
lines.join("\n")
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def top_border(width)
|
55
|
+
title_text = @title ? colorize(" #{@title} ", @title_color) : ""
|
56
|
+
padding = (width - title_text.uncolorize.length - 2) / 2
|
57
|
+
"#{colorize("╭", @border_color)}#{colorize("─" * padding, @border_color)}#{title_text}#{colorize("─" * (width - title_text.uncolorize.length - padding - 2), @border_color)}#{colorize("╮", @border_color)}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def bottom_border(width)
|
61
|
+
footer_text = @footer ? colorize(" #{@footer} ", @title_color) : ""
|
62
|
+
padding = (width - footer_text.uncolorize.length - 2) / 2
|
63
|
+
"#{colorize("╰", @border_color)}#{colorize("─" * padding, @border_color)}#{footer_text}#{colorize("─" * (width - footer_text.uncolorize.length - padding - 2), @border_color)}#{colorize("╯", @border_color)}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def format_line(line, width)
|
67
|
+
"#{colorize("│", @border_color)} #{line.ljust(width - 4)} #{colorize("│", @border_color)}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def format_content
|
71
|
+
@content.map(&:strip)
|
72
|
+
end
|
73
|
+
|
74
|
+
def calculate_panel_width(content_lines)
|
75
|
+
[
|
76
|
+
@title ? @title.uncolorize.length + 4 : 0,
|
77
|
+
@footer ? @footer.uncolorize.length + 4 : 0,
|
78
|
+
content_lines.map(&:length).max + 4
|
79
|
+
].max
|
80
|
+
end
|
81
|
+
|
82
|
+
def colorize(text, color)
|
83
|
+
code = ANSI_CODES[:color][color] || ""
|
84
|
+
"#{code}#{text}#{ANSI_CODES[:reset]}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Extend String to remove ANSI codes for alignment
|
90
|
+
class String
|
91
|
+
def uncolorize
|
92
|
+
gsub(/\e\[[0-9;]*m/, '')
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module RubyRich
|
2
|
+
class RichPrint
|
3
|
+
def initialize
|
4
|
+
@style_regex = /\[([\w\s]+)\](.*?)\[\/[\w]*\]/
|
5
|
+
end
|
6
|
+
|
7
|
+
def print(*args)
|
8
|
+
processed_args = args.map do |arg|
|
9
|
+
next arg unless arg.is_a?(String)
|
10
|
+
|
11
|
+
# 处理表情符号
|
12
|
+
text = if arg.start_with?(':') && arg.end_with?(':')
|
13
|
+
Emoji.find_by_alias(arg[1..-2])&.raw || arg
|
14
|
+
else
|
15
|
+
arg
|
16
|
+
end
|
17
|
+
|
18
|
+
# 处理样式标记
|
19
|
+
while text.match?(@style_regex)
|
20
|
+
text = text.gsub(@style_regex) do |_|
|
21
|
+
style, content = $1, $2
|
22
|
+
apply_style(content, style)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
text
|
27
|
+
end
|
28
|
+
|
29
|
+
puts processed_args.join(' ')
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def apply_style(content, style)
|
35
|
+
style_methods = style.downcase.split
|
36
|
+
rich_text = RichRuby::RichText.new(content)
|
37
|
+
style.downcase.split.each do |method|
|
38
|
+
case method
|
39
|
+
when 'bold'
|
40
|
+
rich_text.style(bold: true)
|
41
|
+
when 'italic'
|
42
|
+
rich_text.style(italic: true)
|
43
|
+
when 'underline'
|
44
|
+
rich_text.style(underline: true)
|
45
|
+
when 'blink'
|
46
|
+
rich_text.style(blink: true)
|
47
|
+
when 'red', 'blue', 'green', 'yellow', 'magenta', 'cyan', 'white', 'black'
|
48
|
+
rich_text.style(color: method.to_sym)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
rich_text.render
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# 创建全局打印方法
|
56
|
+
$rich_print = RichPrint.new
|
57
|
+
def print(*args)
|
58
|
+
$rich_print.print(*args)
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module RubyRich
|
2
|
+
class RichText
|
3
|
+
# 默认主题
|
4
|
+
@@theme = {
|
5
|
+
error: { color: :red, bold: true },
|
6
|
+
success: { color: :green, bold: true },
|
7
|
+
info: { color: :cyan },
|
8
|
+
warning: { color: :yellow, bold: true }
|
9
|
+
}
|
10
|
+
|
11
|
+
# ANSI 转义码常量
|
12
|
+
ANSI_CODES = {
|
13
|
+
reset: "\e[0m",
|
14
|
+
bold: "\e[1m",
|
15
|
+
italic: "\e[3m",
|
16
|
+
underline: "\e[4m",
|
17
|
+
blink: "\e[5m",
|
18
|
+
color: {
|
19
|
+
black: "\e[30m",
|
20
|
+
red: "\e[31m",
|
21
|
+
green: "\e[32m",
|
22
|
+
yellow: "\e[33m",
|
23
|
+
blue: "\e[34m",
|
24
|
+
magenta: "\e[35m",
|
25
|
+
cyan: "\e[36m",
|
26
|
+
white: "\e[37m"
|
27
|
+
},
|
28
|
+
background: {
|
29
|
+
black: "\e[40m",
|
30
|
+
red: "\e[41m",
|
31
|
+
green: "\e[42m",
|
32
|
+
yellow: "\e[43m",
|
33
|
+
blue: "\e[44m",
|
34
|
+
magenta: "\e[45m",
|
35
|
+
cyan: "\e[46m",
|
36
|
+
white: "\e[47m"
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
def self.set_theme(new_theme)
|
41
|
+
@@theme.merge!(new_theme)
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(text, style: nil)
|
45
|
+
@text = text
|
46
|
+
@styles = []
|
47
|
+
apply_theme(style) if style
|
48
|
+
end
|
49
|
+
|
50
|
+
def style(color: nil, background: nil, bold: false, italic: false, underline: false, blink: false)
|
51
|
+
@styles << ANSI_CODES[:color][color] if color
|
52
|
+
@styles << ANSI_CODES[:background][background] if background
|
53
|
+
@styles << ANSI_CODES[:bold] if bold
|
54
|
+
@styles << ANSI_CODES[:italic] if italic
|
55
|
+
@styles << ANSI_CODES[:underline] if underline
|
56
|
+
@styles << ANSI_CODES[:blink] if blink
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def render
|
61
|
+
"#{@styles.join}#{@text}#{ANSI_CODES[:reset]}"
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def add_style(code, error_message)
|
67
|
+
if code
|
68
|
+
@styles << code
|
69
|
+
else
|
70
|
+
raise ArgumentError, error_message
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def apply_theme(style)
|
75
|
+
theme_styles = @@theme[style]
|
76
|
+
raise ArgumentError, "Undefined theme style: #{style}" unless theme_styles
|
77
|
+
style(**theme_styles)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'unicode/display_width'
|
2
|
+
|
3
|
+
module RubyRich
|
4
|
+
class Table
|
5
|
+
attr_accessor :headers, :rows, :align, :row_height
|
6
|
+
|
7
|
+
def initialize(headers: [], align: :left, row_height: 1)
|
8
|
+
@headers = headers.map { |h| format_cell(h) }
|
9
|
+
@rows = []
|
10
|
+
@align = align
|
11
|
+
@row_height = row_height
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_row(row)
|
15
|
+
@rows << row.map { |cell| format_cell(cell) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def render
|
19
|
+
column_widths = calculate_column_widths
|
20
|
+
lines = []
|
21
|
+
|
22
|
+
# Render headers
|
23
|
+
lines << render_row(@headers, column_widths, bold: true)
|
24
|
+
lines << "-" * (column_widths.sum { |w| w + 3 } + 1)
|
25
|
+
|
26
|
+
# Render rows
|
27
|
+
@rows.each do |row|
|
28
|
+
lines.concat(render_multiline_row(row, column_widths))
|
29
|
+
end
|
30
|
+
|
31
|
+
lines.join("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def format_cell(cell)
|
37
|
+
cell.is_a?(RichRuby::RichText) ? cell : RichRuby::RichText.new(cell.to_s)
|
38
|
+
end
|
39
|
+
|
40
|
+
def calculate_column_widths
|
41
|
+
widths = Array.new(@headers.size, 0)
|
42
|
+
|
43
|
+
# Calculate widths from headers
|
44
|
+
@headers.each_with_index do |header, i|
|
45
|
+
header_text = header.respond_to?(:render) ? header.render : header.to_s
|
46
|
+
header_width = Unicode::DisplayWidth.of(header_text.gsub(/\e\[[0-9;]*m/, ''))
|
47
|
+
widths[i] = [widths[i], header_width].max
|
48
|
+
end
|
49
|
+
|
50
|
+
# Calculate widths from rows
|
51
|
+
@rows.each do |row|
|
52
|
+
row.each_with_index do |cell, i|
|
53
|
+
cell_lines = cell.render.split("\n")
|
54
|
+
cell_lines.each do |line|
|
55
|
+
# Remove ANSI escape sequences before calculating width
|
56
|
+
plain_line = line.gsub(/\e\[[0-9;]*m/, '')
|
57
|
+
width = Unicode::DisplayWidth.of(plain_line)
|
58
|
+
widths[i] = [widths[i], width].max
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
widths
|
64
|
+
end
|
65
|
+
|
66
|
+
def render_row(row, column_widths, bold: false)
|
67
|
+
row.map.with_index do |cell, i|
|
68
|
+
content = bold ? cell.render : align_cell(cell.render, column_widths[i])
|
69
|
+
align_cell(content, column_widths[i])
|
70
|
+
end.join(" | ").prepend("| ").concat(" |")
|
71
|
+
end
|
72
|
+
|
73
|
+
def render_multiline_row(row, column_widths)
|
74
|
+
# Prepare each cell's lines
|
75
|
+
row_lines = row.map.with_index do |cell, i|
|
76
|
+
# 获取单元格的样式序列
|
77
|
+
style_sequence = cell.render.match(/\e\[[0-9;]*m/)&.to_s || ""
|
78
|
+
reset_sequence = style_sequence.empty? ? "" : "\e[0m"
|
79
|
+
|
80
|
+
# 分割成多行并保持样式
|
81
|
+
cell_content = cell.render.split("\n")
|
82
|
+
|
83
|
+
# 为每一行添加样式
|
84
|
+
cell_content.map! { |line|
|
85
|
+
line = line.gsub(/\e\[[0-9;]*m/, '') # 移除可能存在的样式序列
|
86
|
+
style_sequence + line + reset_sequence
|
87
|
+
}
|
88
|
+
|
89
|
+
# 填充到指定的行高
|
90
|
+
padded_content = cell_content + [" "] * [@row_height - cell_content.size, 0].max
|
91
|
+
|
92
|
+
# 对每一行应用对齐,保持样式
|
93
|
+
padded_content.map { |line| align_cell(line, column_widths[i]) }
|
94
|
+
end
|
95
|
+
|
96
|
+
# Normalize row height
|
97
|
+
max_height = row_lines.map(&:size).max
|
98
|
+
row_lines.each do |lines|
|
99
|
+
width = column_widths[row_lines.index(lines)]
|
100
|
+
style_sequence = lines.first.match(/\e\[[0-9;]*m/)&.to_s || ""
|
101
|
+
reset_sequence = style_sequence.empty? ? "" : "\e[0m"
|
102
|
+
lines.fill(style_sequence + " " * width + reset_sequence, lines.size...max_height)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Render each line of the row
|
106
|
+
(0...max_height).map do |line_index|
|
107
|
+
row_lines.map { |lines| lines[line_index] }.join(" | ").prepend("| ").concat(" |")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def align_cell(content, width)
|
112
|
+
style_sequences = content.scan(/\e\[[0-9;]*m/)
|
113
|
+
plain_content = content.gsub(/\e\[[0-9;]*m/, '')
|
114
|
+
|
115
|
+
# 计算实际显示宽度
|
116
|
+
display_width = Unicode::DisplayWidth.of(plain_content)
|
117
|
+
padding_needed = width - display_width
|
118
|
+
|
119
|
+
padded_content = case @align
|
120
|
+
when :center
|
121
|
+
left_padding = padding_needed / 2
|
122
|
+
right_padding = padding_needed - left_padding
|
123
|
+
" " * left_padding + plain_content + " " * right_padding
|
124
|
+
when :right
|
125
|
+
" " * padding_needed + plain_content
|
126
|
+
else
|
127
|
+
plain_content + " " * padding_needed
|
128
|
+
end
|
129
|
+
|
130
|
+
if style_sequences.any?
|
131
|
+
style_sequences.first + padded_content + "\e[0m"
|
132
|
+
else
|
133
|
+
padded_content
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/lib/ruby_rich.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# 加载所有依赖的 gem
|
4
|
+
require 'rouge'
|
5
|
+
require 'tty-cursor'
|
6
|
+
require 'tty-screen'
|
7
|
+
require 'redcarpet'
|
8
|
+
|
9
|
+
# 加载所有内部模块
|
10
|
+
require_relative 'ruby_rich/console'
|
11
|
+
require_relative 'ruby_rich/table'
|
12
|
+
require_relative 'ruby_rich/progress_bar'
|
13
|
+
require_relative 'ruby_rich/rich_text'
|
14
|
+
require_relative 'ruby_rich/rich_print'
|
15
|
+
require_relative 'ruby_rich/rich_panel'
|
16
|
+
require_relative 'ruby_rich/version'
|
17
|
+
|
18
|
+
# 定义主模块
|
19
|
+
module RubyRich
|
20
|
+
class Error < StandardError; end
|
21
|
+
|
22
|
+
# 提供一个便捷方法来创建控制台实例
|
23
|
+
def self.console
|
24
|
+
@console ||= Console.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# 提供一个便捷方法来创建富文本
|
28
|
+
def self.text(content = '')
|
29
|
+
RichText.new(content)
|
30
|
+
end
|
31
|
+
|
32
|
+
# 提供一个便捷方法来创建表格
|
33
|
+
def self.table
|
34
|
+
Table.new
|
35
|
+
end
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_rich
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- zhuang biaowei
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-02-02 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: rake
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '13.0'
|
19
|
+
type: :development
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '13.0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: minitest
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '5.0'
|
40
|
+
description: A Ruby gem providing rich text formatting, progress bars, tables and
|
41
|
+
other console output enhancements
|
42
|
+
email: zbw@kaiyuanshe.org
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- lib/ruby_rich.rb
|
48
|
+
- lib/ruby_rich/console.rb
|
49
|
+
- lib/ruby_rich/progress_bar.rb
|
50
|
+
- lib/ruby_rich/rich_panel.rb
|
51
|
+
- lib/ruby_rich/rich_print.rb
|
52
|
+
- lib/ruby_rich/rich_text.rb
|
53
|
+
- lib/ruby_rich/table.rb
|
54
|
+
- lib/ruby_rich/version.rb
|
55
|
+
homepage: https://github.com/zhuangbiaowei/ruby_rich
|
56
|
+
licenses:
|
57
|
+
- MIT
|
58
|
+
metadata: {}
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 2.7.0
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubygems_version: 3.6.2
|
74
|
+
specification_version: 4
|
75
|
+
summary: Rich text formatting and console output for Ruby
|
76
|
+
test_files: []
|