command_kit 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +4 -6
  3. data/.rubocop.yml +13 -0
  4. data/ChangeLog.md +18 -0
  5. data/Gemfile +2 -0
  6. data/LICENSE.txt +1 -1
  7. data/README.md +18 -9
  8. data/command_kit.gemspec +0 -1
  9. data/examples/printing/tables.rb +141 -0
  10. data/gemspec.yml +3 -3
  11. data/lib/command_kit/bug_report.rb +105 -0
  12. data/lib/command_kit/colors.rb +4 -4
  13. data/lib/command_kit/edit.rb +54 -0
  14. data/lib/command_kit/env.rb +1 -1
  15. data/lib/command_kit/options/option.rb +5 -1
  16. data/lib/command_kit/options/option_value.rb +2 -2
  17. data/lib/command_kit/options/parser.rb +1 -1
  18. data/lib/command_kit/options/quiet.rb +1 -1
  19. data/lib/command_kit/options/verbose.rb +2 -2
  20. data/lib/command_kit/options/version.rb +10 -0
  21. data/lib/command_kit/options.rb +1 -1
  22. data/lib/command_kit/os.rb +1 -1
  23. data/lib/command_kit/printing/fields.rb +56 -0
  24. data/lib/command_kit/printing/indent.rb +1 -1
  25. data/lib/command_kit/printing/lists.rb +91 -0
  26. data/lib/command_kit/printing/tables/border_style.rb +169 -0
  27. data/lib/command_kit/printing/tables/cell_builder.rb +93 -0
  28. data/lib/command_kit/printing/tables/row_builder.rb +111 -0
  29. data/lib/command_kit/printing/tables/style.rb +198 -0
  30. data/lib/command_kit/printing/tables/table_builder.rb +145 -0
  31. data/lib/command_kit/printing/tables/table_formatter.rb +254 -0
  32. data/lib/command_kit/printing/tables.rb +208 -0
  33. data/lib/command_kit/stdio.rb +5 -1
  34. data/lib/command_kit/version.rb +1 -1
  35. data/spec/bug_report_spec.rb +266 -0
  36. data/spec/colors_spec.rb +6 -0
  37. data/spec/command_name_spec.rb +1 -1
  38. data/spec/edit_spec.rb +72 -0
  39. data/spec/options/option_spec.rb +12 -2
  40. data/spec/options/quiet_spec.rb +51 -0
  41. data/spec/options/verbose_spec.rb +51 -0
  42. data/spec/options/version_spec.rb +146 -0
  43. data/spec/pager_spec.rb +1 -1
  44. data/spec/printing/fields_spec.rb +167 -0
  45. data/spec/printing/lists_spec.rb +99 -0
  46. data/spec/printing/tables/border_style.rb +43 -0
  47. data/spec/printing/tables/cell_builer_spec.rb +135 -0
  48. data/spec/printing/tables/row_builder_spec.rb +165 -0
  49. data/spec/printing/tables/style_spec.rb +377 -0
  50. data/spec/printing/tables/table_builder_spec.rb +252 -0
  51. data/spec/printing/tables/table_formatter_spec.rb +1180 -0
  52. data/spec/printing/tables_spec.rb +1069 -0
  53. metadata +33 -7
@@ -0,0 +1,56 @@
1
+ require 'command_kit/printing/indent'
2
+
3
+ module CommandKit
4
+ module Printing
5
+ #
6
+ # Supports printing aligned key/value fields.
7
+ #
8
+ # @since 0.4.0
9
+ #
10
+ module Fields
11
+ include Indent
12
+
13
+ #
14
+ # Prints a Hash as left-justified `:` separated fields.
15
+ #
16
+ # @param [Hash, Array<(Object, Object)>] fields
17
+ # The fields to print.
18
+ #
19
+ # @example
20
+ # print_fields('Name' => 'foo', 'Version' => '0.1.0')
21
+ # # Name: foo
22
+ # # Version: 0.1.0
23
+ #
24
+ # @api public
25
+ #
26
+ def print_fields(fields)
27
+ max_length = 0
28
+
29
+ fields = fields.map { |name,value|
30
+ name = name.to_s
31
+ value = value.to_s
32
+ max_length = name.length if name.length > max_length
33
+
34
+ [name, value]
35
+ }
36
+
37
+ fields.each do |name,value|
38
+ first_line, *rest = value.to_s.lines(chomp: true)
39
+
40
+ # print the first line with the header
41
+ header = "#{name}:".ljust(max_length + 1)
42
+ puts "#{header} #{first_line}"
43
+
44
+ # indent and print the rest of the lines
45
+ indent(max_length + 2) do
46
+ rest.each do |line|
47
+ puts line
48
+ end
49
+ end
50
+ end
51
+
52
+ return nil
53
+ end
54
+ end
55
+ end
56
+ end
@@ -7,7 +7,7 @@ module CommandKit
7
7
  #
8
8
  # include Printing::Indent
9
9
  #
10
- # def main
10
+ # def run
11
11
  # puts "regular output:"
12
12
  #
13
13
  # indent(4) do
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'command_kit/printing/indent'
4
+
5
+ module CommandKit
6
+ module Printing
7
+ #
8
+ # Methods for printing lists.
9
+ #
10
+ # ## Examples
11
+ #
12
+ # include Printing::Lists
13
+ #
14
+ # def main
15
+ # print_list %w[foo bar baz]
16
+ # # * foo
17
+ # # * bar
18
+ # # * baz
19
+ #
20
+ # list = ['item 1', 'item 2', ['sub-item 1', 'sub-item 2']]
21
+ # print_list(list)
22
+ # # * item 1
23
+ # # * item 2
24
+ # # * sub-item 1
25
+ # # * sub-item 2
26
+ #
27
+ # print_list %w[foo bar baz], bullet: '-'
28
+ # # - foo
29
+ # # - bar
30
+ # # - baz
31
+ # end
32
+ #
33
+ # @since 0.4.0
34
+ #
35
+ module Lists
36
+ include Indent
37
+
38
+ #
39
+ # Prints a bulleted list of items.
40
+ #
41
+ # @param [Array<#to_s, Array>] list
42
+ # The list of items to print.
43
+ #
44
+ # @param [String] bullet
45
+ # The bullet character to use for line item.
46
+ #
47
+ # @example
48
+ # print_list %w[foo bar baz]
49
+ # # * foo
50
+ # # * bar
51
+ # # * baz
52
+ #
53
+ # @example print a nested list:
54
+ # list = ['item 1', 'item 2', ['sub-item 1', 'sub-item 2']]
55
+ # print_list(list)
56
+ # # * item 1
57
+ # # * item 2
58
+ # # * sub-item 1
59
+ # # * sub-item 2
60
+ #
61
+ # @example with a custom bullet character:
62
+ # print_list %w[foo bar baz], bullet: '-'
63
+ # # - foo
64
+ # # - bar
65
+ # # - baz
66
+ #
67
+ # @since 0.4.0
68
+ #
69
+ def print_list(list, bullet: '*')
70
+ list.each do |item|
71
+ case item
72
+ when Array
73
+ indent { print_list(item, bullet: bullet) }
74
+ else
75
+ first_line, *rest = item.to_s.lines(chomp: true)
76
+
77
+ # print the bullet only on the first list
78
+ puts "#{bullet} #{first_line}"
79
+
80
+ # indent the remaining lines
81
+ indent(bullet.length + 1) do
82
+ rest.each do |line|
83
+ puts line
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,169 @@
1
+ module CommandKit
2
+ module Printing
3
+ module Tables
4
+ #
5
+ # Represents the table's border style.
6
+ #
7
+ # @api private
8
+ #
9
+ class BorderStyle
10
+
11
+ # The top-left-corner border character.
12
+ #
13
+ # @return [String]
14
+ attr_reader :top_left_corner
15
+
16
+ # The top-border character.
17
+ #
18
+ # @return [String]
19
+ attr_reader :top_border
20
+
21
+ # The top-joined-border character.
22
+ #
23
+ # @return [String]
24
+ attr_reader :top_joined_border
25
+
26
+ # The top-right-corner border character.
27
+ #
28
+ # @return [String]
29
+ attr_reader :top_right_corner
30
+
31
+ # The left-hand-side border character.
32
+ #
33
+ # @return [String]
34
+ attr_reader :left_border
35
+
36
+ # The left-hand-side-joined-border character.
37
+ #
38
+ # @return [String]
39
+ attr_reader :left_joined_border
40
+
41
+ # The horizontal-separator character.
42
+ #
43
+ # @return [String]
44
+ attr_reader :horizontal_separator
45
+
46
+ # The vertical-separator character.
47
+ #
48
+ # @return [String]
49
+ attr_reader :vertical_separator
50
+
51
+ # The inner-joined border character.
52
+ #
53
+ # @return [String]
54
+ attr_reader :inner_joined_border
55
+
56
+ # The right-hand-side border character.
57
+ #
58
+ # @return [String]
59
+ attr_reader :right_border
60
+
61
+ # The right-hand-side joined border character.
62
+ #
63
+ # @return [String]
64
+ attr_reader :right_joined_border
65
+
66
+ # The bottom border character.
67
+ #
68
+ # @return [String]
69
+ attr_reader :bottom_border
70
+
71
+ # The bottom-left-corner border character.
72
+ #
73
+ # @return [String]
74
+ attr_reader :bottom_left_corner
75
+
76
+ # The bottom-joined border character.
77
+ #
78
+ # @return [String]
79
+ attr_reader :bottom_joined_border
80
+
81
+ # The bottom-right-corner border character.
82
+ #
83
+ # @return [String]
84
+ attr_reader :bottom_right_corner
85
+
86
+ #
87
+ # Initializes the border style.
88
+ #
89
+ # @param [String] top_left_corner
90
+ # The top-left-corner border character.
91
+ #
92
+ # @param [String] top_border
93
+ # The top-border character.
94
+ #
95
+ # @param [String] top_joined_border
96
+ # The top-joined-border character.
97
+ #
98
+ # @param [String] top_right_corner
99
+ # The top-right-corner border character.
100
+ #
101
+ # @param [String] left_border
102
+ # The left-hand-side border character.
103
+ #
104
+ # @param [String] left_joined_border
105
+ # The left-hand-side-joined-border character.
106
+ #
107
+ # @param [String] horizontal_separator
108
+ # The horizontal-separator character.
109
+ #
110
+ # @param [String] vertical_separator
111
+ # The vertical-separator character.
112
+ #
113
+ # @param [String] inner_joined_border
114
+ # The inner-joined border character.
115
+ #
116
+ # @param [String] right_border
117
+ # The right-hand-side border character.
118
+ #
119
+ # @param [String] right_joined_border
120
+ # The right-hand-side joined border character.
121
+ #
122
+ # @param [String] bottom_border
123
+ # The bottom border character.
124
+ #
125
+ # @param [String] bottom_left_corner
126
+ # The bottom-left-corner border character.
127
+ #
128
+ # @param [String] bottom_joined_border
129
+ # The bottom-joined border character.
130
+ #
131
+ # @param [String] bottom_right_corner
132
+ # The bottom-right-corner border character.
133
+ #
134
+ def initialize(top_left_corner: ' ',
135
+ top_border: ' ',
136
+ top_joined_border: ' ',
137
+ top_right_corner: ' ',
138
+ left_border: ' ',
139
+ left_joined_border: ' ',
140
+ horizontal_separator: ' ',
141
+ vertical_separator: ' ',
142
+ inner_joined_border: ' ',
143
+ right_border: ' ',
144
+ right_joined_border: ' ',
145
+ bottom_border: ' ',
146
+ bottom_left_corner: ' ',
147
+ bottom_joined_border: ' ',
148
+ bottom_right_corner: ' ')
149
+ @top_left_corner = top_left_corner
150
+ @top_border = top_border
151
+ @top_joined_border = top_joined_border
152
+ @top_right_corner = top_right_corner
153
+ @left_border = left_border
154
+ @left_joined_border = left_joined_border
155
+ @horizontal_separator = horizontal_separator
156
+ @vertical_separator = vertical_separator
157
+ @inner_joined_border = inner_joined_border
158
+ @right_border = right_border
159
+ @right_joined_border = right_joined_border
160
+ @bottom_border = bottom_border
161
+ @bottom_left_corner = bottom_left_corner
162
+ @bottom_joined_border = bottom_joined_border
163
+ @bottom_right_corner = bottom_right_corner
164
+ end
165
+
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CommandKit
4
+ module Printing
5
+ module Tables
6
+ #
7
+ # Build's a cell and calculates it's dimensions.
8
+ #
9
+ # @api private
10
+ #
11
+ class CellBuilder
12
+
13
+ # The lines within the cell.
14
+ #
15
+ # @return [Array<String>]
16
+ attr_reader :lines
17
+
18
+ # The height (in lines) of the cell.
19
+ #
20
+ # @return [Integer]
21
+ attr_reader :height
22
+
23
+ # The with (in characters) of the cell.
24
+ #
25
+ # @return [Integer]
26
+ attr_reader :width
27
+
28
+ #
29
+ # Initializes the cell.
30
+ #
31
+ # @param [#to_s] value
32
+ # The value for the cell.
33
+ #
34
+ def initialize(value=nil)
35
+ @lines = []
36
+ @height = 0
37
+ @width = 0
38
+
39
+ if value
40
+ value.to_s.each_line(chomp: true) do |line|
41
+ self << line
42
+ end
43
+ end
44
+ end
45
+
46
+ #
47
+ # Calculates the width of a string, sans any ASNI escape sequences.
48
+ #
49
+ # @param [String] string
50
+ # The string to calculate the width of.
51
+ #
52
+ # @return [Integer]
53
+ # The display width of the string.
54
+ #
55
+ def self.line_width(string)
56
+ string.gsub(/\e\[\d+m/,'').length
57
+ end
58
+
59
+ #
60
+ # Adds a line to the cell.
61
+ #
62
+ # @param [String] line
63
+ # A line to add to the cell.
64
+ #
65
+ # @return [self]
66
+ #
67
+ def <<(line)
68
+ line_width = self.class.line_width(line)
69
+
70
+ @height += 1
71
+ @width = line_width if line_width > @width
72
+
73
+ @lines << line
74
+ return self
75
+ end
76
+
77
+ #
78
+ # Fetches a line from the cell.
79
+ #
80
+ # @param [Integer] line_index
81
+ # The line index to fetch.
82
+ #
83
+ # @return [String]
84
+ # The line at the line index or an empty String if the cell is empty.
85
+ #
86
+ def [](line_index)
87
+ @lines.fetch(line_index,'')
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,111 @@
1
+ require 'command_kit/printing/tables/cell_builder'
2
+
3
+ module CommandKit
4
+ module Printing
5
+ module Tables
6
+ #
7
+ # Builds a table row and calculates it's dimensions.
8
+ #
9
+ # @api private
10
+ #
11
+ class RowBuilder
12
+
13
+ include Enumerable
14
+
15
+ # The cells within the row.
16
+ #
17
+ # @return [Array<CellBuilder>]
18
+ attr_reader :cells
19
+
20
+ # The height (in lines) for the row.
21
+ #
22
+ # @return [Integer]
23
+ attr_reader :height
24
+
25
+ # The width (in characters) for the row.
26
+ #
27
+ # @return [Integer]
28
+ attr_reader :width
29
+
30
+ # The number of columns in the row.
31
+ #
32
+ # @return [Integer]
33
+ attr_reader :columns
34
+
35
+ #
36
+ # Initializes the row.
37
+ #
38
+ # @param [Array, nil] cells
39
+ # The cells for the row.
40
+ #
41
+ def initialize(cells=nil)
42
+ @cells = []
43
+
44
+ @height = 0
45
+ @width = 0
46
+
47
+ @columns = 0
48
+
49
+ if cells
50
+ cells.each { |value| self << value }
51
+ end
52
+ end
53
+
54
+ # An empty cell.
55
+ EMPTY_CELL = CellBuilder.new
56
+
57
+ #
58
+ # Appends a value to the row.
59
+ #
60
+ # @param [#to_s] value
61
+ # The cell value to add to the row.
62
+ #
63
+ # @return [self]
64
+ #
65
+ def <<(value)
66
+ new_cell = if value then CellBuilder.new(value)
67
+ else EMPTY_CELL
68
+ end
69
+
70
+ @height = new_cell.height if new_cell.height > @height
71
+ @width += new_cell.width
72
+ @columns += 1
73
+
74
+ @cells << new_cell
75
+ return self
76
+ end
77
+
78
+ #
79
+ # Fetches a cell from the row.
80
+ #
81
+ # @param [Integer] column_index
82
+ # The column index.
83
+ #
84
+ # @return [CellBuilder]
85
+ # The cell at the given column index or an empty cell if the row
86
+ # does not have a cell at the given column index.
87
+ #
88
+ def [](column_index)
89
+ @cells.fetch(column_index,EMPTY_CELL)
90
+ end
91
+
92
+ #
93
+ # Enumerates over each cell in the row.
94
+ #
95
+ # @yield [cell]
96
+ # The given block will be passed each cell within the row.
97
+ #
98
+ # @yieldparam [CellBuilder] cell
99
+ # A cell within the row.
100
+ #
101
+ # @return [Enumerator]
102
+ # If no block is given, an Enumerator will be returned.
103
+ #
104
+ def each(&block)
105
+ @cells.each(&block)
106
+ end
107
+
108
+ end
109
+ end
110
+ end
111
+ end