command_kit 0.3.0 → 0.4.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 (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