term_utils 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/term_utils/tab.rb +318 -0
- data/lib/term_utils.rb +1 -0
- metadata +46 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 60ba5398037f0291a34bfdce7f66e51c0176aeb52adb19106ac99069c76f93b3
|
4
|
+
data.tar.gz: b36a84ff036db667ca44d5db3cf7ec1ff043a003082e21b15f5883dbb92f7907
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dad2e32447a9dc4cfdea92e404e4950dd43eb85a6cb6494739540b5387b7d29cd79b6b233814eef36a56b3c0e8bd016260946c428b4856099f385eabee65bf08
|
7
|
+
data.tar.gz: fa4a83783fc89c162f6e0232fe25010b7e9098fc290116a8d9f913e5c415da209fa1740ddf6e09202e7587e2a0b7a36152c217bfcc7877c42339cb27696460d3
|
@@ -0,0 +1,318 @@
|
|
1
|
+
module TermUtils
|
2
|
+
module Tab
|
3
|
+
# Represents a table.
|
4
|
+
class Table
|
5
|
+
# @return [Symbol]
|
6
|
+
attr_accessor :id
|
7
|
+
# @return [Array<Tab::Column>]
|
8
|
+
attr_accessor :columns
|
9
|
+
# @param opts [Hash]
|
10
|
+
# @option opts [Symbol] :id
|
11
|
+
def initialize(opts = {})
|
12
|
+
@id = opts.fetch(:id, nil)
|
13
|
+
@columns = []
|
14
|
+
end
|
15
|
+
# Defines a column.
|
16
|
+
# @param id [Symbol]
|
17
|
+
# @param opts [Hash]
|
18
|
+
# @option opts [Integer] :width
|
19
|
+
# @return [Tab::Column]
|
20
|
+
def define_column(id, opts = {}, &block)
|
21
|
+
col = @columns.find { |c| c.id == id }
|
22
|
+
if col
|
23
|
+
block.call(col) if block
|
24
|
+
col.validate
|
25
|
+
else
|
26
|
+
opts[:id] = id
|
27
|
+
opts[:index] = @columns.length
|
28
|
+
col = Column.new(opts)
|
29
|
+
block.call(col) if block
|
30
|
+
col.validate
|
31
|
+
@columns << col
|
32
|
+
end
|
33
|
+
col
|
34
|
+
end
|
35
|
+
# Finds a column.
|
36
|
+
# @param id [Symbol]
|
37
|
+
# @return [Tab::Column, nil]
|
38
|
+
def find_column(id)
|
39
|
+
@columns.find { |c| c.id == id }
|
40
|
+
end
|
41
|
+
# Creates a new table printer.
|
42
|
+
# @param io [IO]
|
43
|
+
# @param values [Array<Object>, Hash<Symbol, Object>]
|
44
|
+
# @param opts [Hash]
|
45
|
+
# @option opts [Integer] :offset
|
46
|
+
# @option opts [Integer] :column_separator_width
|
47
|
+
# @return [Tab::Printer]
|
48
|
+
def printer(io, opts = {}, &block)
|
49
|
+
ptr = Printer.new(self, io, opts)
|
50
|
+
block.call(ptr) if block
|
51
|
+
ptr
|
52
|
+
end
|
53
|
+
# Prints a header row.
|
54
|
+
# @param io [IO]
|
55
|
+
# @param values [Array<Object>, Hash<Symbol, Object>]
|
56
|
+
# @param opts [Hash]
|
57
|
+
# @option opts [Integer] :offset
|
58
|
+
# @option opts [Integer] :column_separator_width
|
59
|
+
# @return [nil]
|
60
|
+
def print_header(io, values = nil, opts = {})
|
61
|
+
vals = values
|
62
|
+
if values.nil?
|
63
|
+
vals = @columns.map { |col| col.id.to_s }
|
64
|
+
elsif values.is_a? Hash
|
65
|
+
vals = []
|
66
|
+
@columns.each do |col|
|
67
|
+
vals << values[col.id]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
raise "wrong values (not array)" unless vals.is_a? Array
|
71
|
+
offset = opts.fetch(:offset, 0)
|
72
|
+
column_separator_width = opts.fetch(:column_separator_width, 2)
|
73
|
+
sb = StringIO.new
|
74
|
+
sb << " " * offset if offset > 0
|
75
|
+
@columns.each do |col|
|
76
|
+
sb << " " * column_separator_width if col.index > 0
|
77
|
+
sb << col.render_header(vals[col.index])
|
78
|
+
end
|
79
|
+
io.puts sb.string
|
80
|
+
end
|
81
|
+
# Prints a data row.
|
82
|
+
# @param io [IO]
|
83
|
+
# @param values [Array<Object>, Hash<Symbol, Object>]
|
84
|
+
# @param opts [Hash]
|
85
|
+
# @option opts [Integer] :offset
|
86
|
+
# @option opts [Integer] :column_separator_width
|
87
|
+
# @return [nil]
|
88
|
+
def print_data(io, values, opts = {})
|
89
|
+
vals = values
|
90
|
+
if values.is_a? Hash
|
91
|
+
vals = []
|
92
|
+
@columns.each do |col|
|
93
|
+
vals << values[col.id]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
raise "wrong values (not array)" unless vals.is_a? Array
|
97
|
+
offset = opts.fetch(:offset, 0)
|
98
|
+
column_separator_width = opts.fetch(:column_separator_width, 2)
|
99
|
+
sb = StringIO.new
|
100
|
+
sb << " " * offset if offset > 0
|
101
|
+
@columns.each do |col|
|
102
|
+
sb << " " * column_separator_width if col.index > 0
|
103
|
+
sb << col.render_data(vals[col.index])
|
104
|
+
end
|
105
|
+
io.puts sb.string
|
106
|
+
end
|
107
|
+
# Prints a separator row.
|
108
|
+
# @param io [IO]
|
109
|
+
# @param opts [Hash]
|
110
|
+
# @option opts [Integer] :offset
|
111
|
+
# @option opts [Integer] :column_separator_width
|
112
|
+
# @return [nil]
|
113
|
+
def print_separator(io, opts = {})
|
114
|
+
offset = opts.fetch(:offset, 0)
|
115
|
+
column_separator_width = opts.fetch(:column_separator_width, 2)
|
116
|
+
sb = StringIO.new
|
117
|
+
sb << " " * offset if offset > 0
|
118
|
+
@columns.each do |col|
|
119
|
+
sb << " " * column_separator_width if col.index > 0
|
120
|
+
sb << "-" * col.width
|
121
|
+
end
|
122
|
+
io.puts sb.string
|
123
|
+
end
|
124
|
+
# Returns column titles.
|
125
|
+
# @return [Hash<Symbol, String>]
|
126
|
+
def titles
|
127
|
+
h = {}
|
128
|
+
@columns.each do |col|
|
129
|
+
h[col.id] = col.id.to_s
|
130
|
+
end
|
131
|
+
h
|
132
|
+
end
|
133
|
+
end
|
134
|
+
# Represents a table column.
|
135
|
+
class Column
|
136
|
+
# @return [Symbol]
|
137
|
+
attr_accessor :id
|
138
|
+
# @return [Integer]
|
139
|
+
attr_accessor :index
|
140
|
+
# @return [Integer]
|
141
|
+
attr_accessor :width
|
142
|
+
# @return [Symbol] `:left`, `:right`.
|
143
|
+
attr_accessor :align
|
144
|
+
# @return [Boolean]
|
145
|
+
attr_accessor :fixed
|
146
|
+
# @return [String]
|
147
|
+
attr_accessor :ellipsis
|
148
|
+
# @return [Proc, String, nil]
|
149
|
+
attr_accessor :format
|
150
|
+
# @param opts [Hash]
|
151
|
+
# @option opts [Symbol] :id
|
152
|
+
# @option opts [Integer] :index
|
153
|
+
# @option opts [Integer] :width
|
154
|
+
# @option opts [Symbol] :align
|
155
|
+
# @option opts [Boolean] :fixed
|
156
|
+
# @option opts [String] :ellipsis
|
157
|
+
# @option opts [Proc, String, nil] :format
|
158
|
+
def initialize(opts = {})
|
159
|
+
@id = opts.fetch(:id)
|
160
|
+
@index = opts.fetch(:index)
|
161
|
+
@width = opts.fetch(:width, 8)
|
162
|
+
@align = opts.fetch(:align, :left)
|
163
|
+
@fixed = opts.fetch(:fixed, false)
|
164
|
+
@ellipsis = opts.fetch(:ellipsis, "?")
|
165
|
+
@format = opts.fetch(:format, nil)
|
166
|
+
end
|
167
|
+
# Validates the column represented by this one.
|
168
|
+
# @return [nil]
|
169
|
+
def validate
|
170
|
+
raise "missing column id (nil)" if @id.nil?
|
171
|
+
raise "missing column index (nil)" if @index.nil?
|
172
|
+
raise "wrong column index (not integer)" unless @index.is_a? Integer
|
173
|
+
raise "wrong column index (not >= 0)" if @index < 0
|
174
|
+
raise "missing column width (nil)" if @width.nil?
|
175
|
+
raise "wrong column width (not integer)" unless @width.is_a? Integer
|
176
|
+
raise "wrong column width (not > 0)" if @width <= 0
|
177
|
+
raise "wrong column align (not :left or :right)" unless %i{left right}.index @align
|
178
|
+
end
|
179
|
+
# Aligns and cuts a given string.
|
180
|
+
# @param str [String]
|
181
|
+
# @return [String]
|
182
|
+
def align_cut(str)
|
183
|
+
if @align == :left
|
184
|
+
# Align left
|
185
|
+
if @fixed and (str.length > @width)
|
186
|
+
str = "#{str[0..(@width - (@ellipsis.length + 1))]}#{@ellipsis}"
|
187
|
+
else
|
188
|
+
str = "%-*s" % [@width, str]
|
189
|
+
end
|
190
|
+
else
|
191
|
+
# Align right
|
192
|
+
if @fixed and (str.length > @width)
|
193
|
+
str = "#{@ellipsis}#{str[(str.length - @width + @ellipsis.length)..(str.length - 1)]}"
|
194
|
+
else
|
195
|
+
str = "%*s" % [@width, str]
|
196
|
+
end
|
197
|
+
end
|
198
|
+
str
|
199
|
+
end
|
200
|
+
# Renders a given header.
|
201
|
+
# @param v [Object]
|
202
|
+
# return [String]
|
203
|
+
def render_header(v)
|
204
|
+
str = v
|
205
|
+
str = str.to_s unless str.is_a? String
|
206
|
+
align_cut str
|
207
|
+
end
|
208
|
+
# Renders a given value.
|
209
|
+
# @param v [Object]
|
210
|
+
# return [String]
|
211
|
+
def render_data(v)
|
212
|
+
str = v
|
213
|
+
if v
|
214
|
+
if @format.is_a? Proc
|
215
|
+
str = @format.call(v)
|
216
|
+
elsif @format.is_a? String
|
217
|
+
str = @format % v
|
218
|
+
end
|
219
|
+
end
|
220
|
+
str = str.to_s unless str.is_a? String
|
221
|
+
align_cut str
|
222
|
+
end
|
223
|
+
end
|
224
|
+
# Represents a table printer.
|
225
|
+
class Printer
|
226
|
+
# @return [Tab::Table]
|
227
|
+
attr_accessor :table
|
228
|
+
# @return [IO]
|
229
|
+
attr_accessor :io
|
230
|
+
# @return [Hash]
|
231
|
+
attr_accessor :options
|
232
|
+
# @param table [Tab::Table]
|
233
|
+
# @param io [IO]
|
234
|
+
# @param options [Hash]
|
235
|
+
def initialize(table, io, options)
|
236
|
+
@table = table
|
237
|
+
@io = io
|
238
|
+
@options = options
|
239
|
+
end
|
240
|
+
def line
|
241
|
+
@io.puts ""
|
242
|
+
end
|
243
|
+
def header(values = nil, opts = {})
|
244
|
+
@table.print_header(@io, values, @options.merge(opts))
|
245
|
+
end
|
246
|
+
def data(values, opts = {})
|
247
|
+
@table.print_data(@io, values, @options.merge(opts))
|
248
|
+
end
|
249
|
+
# Prints a separator.
|
250
|
+
# @param opts [Hash]
|
251
|
+
# @option opts [Integer] :offset
|
252
|
+
# @option opts [Integer] :column_separator_width
|
253
|
+
# @return [nil]
|
254
|
+
def separator(opts = {})
|
255
|
+
@table.print_separator(@io, @options.merge(opts))
|
256
|
+
end
|
257
|
+
end
|
258
|
+
# Represents a holder of tables.
|
259
|
+
class Holder
|
260
|
+
# @return [Hash<Symbol, Tab::Table>]
|
261
|
+
attr_accessor :tables
|
262
|
+
def initialize(opts = {})
|
263
|
+
@tables = {}
|
264
|
+
end
|
265
|
+
# Defines a table.
|
266
|
+
# @param id [Symbol]
|
267
|
+
# @param opts [Hash]
|
268
|
+
# @return [Tab::Table]
|
269
|
+
def define_table(id, opts = {}, &block)
|
270
|
+
if @tables.has_key? id
|
271
|
+
block.call(@tables[id]) if block
|
272
|
+
else
|
273
|
+
opts[:id] = id
|
274
|
+
new_tab = Table.new(opts)
|
275
|
+
block.call(new_tab) if block
|
276
|
+
@tables[id] = new_tab
|
277
|
+
end
|
278
|
+
@tables[id]
|
279
|
+
end
|
280
|
+
# Finds a table.
|
281
|
+
# @param id [Symbol]
|
282
|
+
# @return [Tab::Table, nil]
|
283
|
+
def find_table(id)
|
284
|
+
@tables[id]
|
285
|
+
end
|
286
|
+
# Creates a new table printer.
|
287
|
+
# @param id [Symbol]
|
288
|
+
# @param io [IO]
|
289
|
+
# @param values [Array<Object>, Hash<Symbol, Object>]
|
290
|
+
# @param opts [Hash]
|
291
|
+
# @option opts [Integer] :offset
|
292
|
+
# @option opts [Integer] :column_separator_width
|
293
|
+
# @return [Tab::Printer]
|
294
|
+
def printer(id, io, opts = {}, &block)
|
295
|
+
find_table(id).printer(io, opts, &block)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
@@default_holder = Holder.new
|
299
|
+
# Defines a table.
|
300
|
+
# @param id [Symbol]
|
301
|
+
# @param opts [Hash]
|
302
|
+
# @return [Tab::Table]
|
303
|
+
def self.define_table(id, opts = {}, &block)
|
304
|
+
@@default_holder.define_table(id, opts = {}, &block)
|
305
|
+
end
|
306
|
+
# Creates a new table printer.
|
307
|
+
# @param id [Symbol]
|
308
|
+
# @param io [IO]
|
309
|
+
# @param values [Array<Object>, Hash<Symbol, Object>]
|
310
|
+
# @param opts [Hash]
|
311
|
+
# @option opts [Integer] :offset
|
312
|
+
# @option opts [Integer] :column_separator_width
|
313
|
+
# @return [Tab::Printer]
|
314
|
+
def self.printer(id, io, opts = {}, &block)
|
315
|
+
@@default_holder.find_table(id).printer(io, opts, &block)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
data/lib/term_utils.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'term_utils/tab'
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: term_utils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thomas Baron
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-10-15 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: 'Provides terminal utilities like table formatting.
|
14
|
+
|
15
|
+
'
|
16
|
+
email: tvbaron at gmail dot com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/term_utils.rb
|
22
|
+
- lib/term_utils/tab.rb
|
23
|
+
homepage: https://git.yellowcube.net/tvb/term_utils
|
24
|
+
licenses:
|
25
|
+
- GPL-3.0
|
26
|
+
metadata: {}
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubygems_version: 3.0.3
|
43
|
+
signing_key:
|
44
|
+
specification_version: 4
|
45
|
+
summary: Terminal utilities.
|
46
|
+
test_files: []
|