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.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/lib/term_utils/tab.rb +318 -0
  3. data/lib/term_utils.rb +1 -0
  4. 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: []