term_utils 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []