command_kit 0.2.2 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +4 -5
- data/.rubocop.yml +14 -1
- data/ChangeLog.md +82 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +18 -9
- data/command_kit.gemspec +0 -1
- data/examples/printing/tables.rb +141 -0
- data/gemspec.yml +3 -3
- data/lib/command_kit/arguments/argument.rb +2 -2
- data/lib/command_kit/arguments.rb +27 -2
- data/lib/command_kit/bug_report.rb +105 -0
- data/lib/command_kit/colors.rb +488 -15
- data/lib/command_kit/command.rb +1 -2
- data/lib/command_kit/edit.rb +54 -0
- data/lib/command_kit/env.rb +1 -1
- data/lib/command_kit/file_utils.rb +46 -0
- data/lib/command_kit/options/option.rb +45 -22
- data/lib/command_kit/options/option_value.rb +2 -2
- data/lib/command_kit/options/parser.rb +1 -4
- data/lib/command_kit/options/quiet.rb +1 -1
- data/lib/command_kit/options/verbose.rb +2 -2
- data/lib/command_kit/options/version.rb +10 -0
- data/lib/command_kit/options.rb +89 -14
- data/lib/command_kit/os.rb +1 -1
- data/lib/command_kit/printing/fields.rb +56 -0
- data/lib/command_kit/printing/indent.rb +1 -1
- data/lib/command_kit/printing/lists.rb +91 -0
- data/lib/command_kit/printing/tables/border_style.rb +169 -0
- data/lib/command_kit/printing/tables/cell_builder.rb +93 -0
- data/lib/command_kit/printing/tables/row_builder.rb +111 -0
- data/lib/command_kit/printing/tables/style.rb +198 -0
- data/lib/command_kit/printing/tables/table_builder.rb +145 -0
- data/lib/command_kit/printing/tables/table_formatter.rb +254 -0
- data/lib/command_kit/printing/tables.rb +208 -0
- data/lib/command_kit/program_name.rb +9 -0
- data/lib/command_kit/stdio.rb +5 -1
- data/lib/command_kit/version.rb +1 -1
- data/spec/arguments_spec.rb +33 -0
- data/spec/bug_report_spec.rb +266 -0
- data/spec/colors_spec.rb +232 -195
- data/spec/command_name_spec.rb +1 -1
- data/spec/command_spec.rb +2 -2
- data/spec/edit_spec.rb +72 -0
- data/spec/file_utils_spec.rb +59 -0
- data/spec/fixtures/template.erb +5 -0
- data/spec/options/option_spec.rb +48 -2
- data/spec/options/parser_spec.rb +0 -10
- data/spec/options/quiet_spec.rb +51 -0
- data/spec/options/verbose_spec.rb +51 -0
- data/spec/options/version_spec.rb +146 -0
- data/spec/options_spec.rb +46 -0
- data/spec/pager_spec.rb +1 -1
- data/spec/printing/fields_spec.rb +167 -0
- data/spec/printing/lists_spec.rb +99 -0
- data/spec/printing/tables/border_style.rb +43 -0
- data/spec/printing/tables/cell_builer_spec.rb +135 -0
- data/spec/printing/tables/row_builder_spec.rb +165 -0
- data/spec/printing/tables/style_spec.rb +377 -0
- data/spec/printing/tables/table_builder_spec.rb +252 -0
- data/spec/printing/tables/table_formatter_spec.rb +1180 -0
- data/spec/printing/tables_spec.rb +1069 -0
- data/spec/program_name_spec.rb +8 -0
- metadata +36 -7
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module CommandKit
|
5
|
+
#
|
6
|
+
# File manipulation related methods.
|
7
|
+
#
|
8
|
+
# @since 0.3.0
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
#
|
12
|
+
module FileUtils
|
13
|
+
include ::FileUtils
|
14
|
+
|
15
|
+
#
|
16
|
+
# Renders an erb file and optionally writes it out to a destination file.
|
17
|
+
#
|
18
|
+
# @param [String] source
|
19
|
+
# The path to the erb template file.
|
20
|
+
#
|
21
|
+
# @param [String, nil] dest
|
22
|
+
# The path to the destination file.
|
23
|
+
#
|
24
|
+
# @return [String, nil]
|
25
|
+
# If no destination path argument is given, the rendered erb template
|
26
|
+
# String will be returned.
|
27
|
+
#
|
28
|
+
# @example Rendering a ERB template and saving it's output:
|
29
|
+
# erb File.join(template_dir,'README.md.erb'), 'README.md'
|
30
|
+
#
|
31
|
+
# @example Rendering a ERB template and capturing it's output:
|
32
|
+
# output = erb(File.join(template_dir,'_partial.erb'))
|
33
|
+
#
|
34
|
+
def erb(source,dest=nil)
|
35
|
+
erb = ERB.new(File.read(source), trim_mode: '-')
|
36
|
+
result = erb.result(binding)
|
37
|
+
|
38
|
+
if dest
|
39
|
+
File.write(dest,result)
|
40
|
+
return
|
41
|
+
else
|
42
|
+
return result
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -40,6 +40,13 @@ module CommandKit
|
|
40
40
|
# @return [Proc, nil]
|
41
41
|
attr_reader :block
|
42
42
|
|
43
|
+
# The optional category to group the option under.
|
44
|
+
#
|
45
|
+
# @return [String, nil]
|
46
|
+
#
|
47
|
+
# @since 0.3.0
|
48
|
+
attr_reader :category
|
49
|
+
|
43
50
|
#
|
44
51
|
# Initializes the option.
|
45
52
|
#
|
@@ -65,9 +72,12 @@ module CommandKit
|
|
65
72
|
# @option value [String, nil] usage
|
66
73
|
# The usage string for the option's value.
|
67
74
|
#
|
68
|
-
# @param [String] desc
|
75
|
+
# @param [String, Array<String>] desc
|
69
76
|
# The description for the option.
|
70
77
|
#
|
78
|
+
# @param [String, nil] category
|
79
|
+
# The optional category to group the option under.
|
80
|
+
#
|
71
81
|
# @yield [(value)]
|
72
82
|
# If a block is given, it will be called when the option is parsed.
|
73
83
|
#
|
@@ -78,25 +88,27 @@ module CommandKit
|
|
78
88
|
# The `value` keyword argument was not a `Hash`, `true`, `false`, or
|
79
89
|
# `nil`.
|
80
90
|
#
|
81
|
-
def initialize(name, short:
|
82
|
-
long:
|
83
|
-
equals:
|
84
|
-
value:
|
85
|
-
desc:
|
91
|
+
def initialize(name, short: nil,
|
92
|
+
long: self.class.default_long_opt(name),
|
93
|
+
equals: false,
|
94
|
+
value: nil,
|
95
|
+
desc: ,
|
96
|
+
category: nil,
|
86
97
|
&block)
|
87
|
-
@name
|
88
|
-
@short
|
89
|
-
@long
|
90
|
-
@equals
|
91
|
-
@value
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
@desc
|
99
|
-
@
|
98
|
+
@name = name
|
99
|
+
@short = short
|
100
|
+
@long = long
|
101
|
+
@equals = equals
|
102
|
+
@value = case value
|
103
|
+
when Hash then OptionValue.new(**value)
|
104
|
+
when true then OptionValue.new()
|
105
|
+
when false, nil then nil
|
106
|
+
else
|
107
|
+
raise(TypeError,"value: keyword must be Hash, true, false, or nil")
|
108
|
+
end
|
109
|
+
@desc = desc
|
110
|
+
@category = category
|
111
|
+
@block = block
|
100
112
|
end
|
101
113
|
|
102
114
|
#
|
@@ -142,7 +154,11 @@ module CommandKit
|
|
142
154
|
# The usage strings.
|
143
155
|
#
|
144
156
|
def usage
|
145
|
-
|
157
|
+
if equals? && (@value && @value.optional?)
|
158
|
+
[*@short, "#{@long}[#{separator}#{@value && @value.usage}]"]
|
159
|
+
else
|
160
|
+
[*@short, "#{@long}#{separator}#{@value && @value.usage}"]
|
161
|
+
end
|
146
162
|
end
|
147
163
|
|
148
164
|
#
|
@@ -179,7 +195,7 @@ module CommandKit
|
|
179
195
|
#
|
180
196
|
# The option description.
|
181
197
|
#
|
182
|
-
# @return [String]
|
198
|
+
# @return [String, Array<String>]
|
183
199
|
#
|
184
200
|
# @note
|
185
201
|
# If {#default_value} returns a value, the description will contain the
|
@@ -187,7 +203,14 @@ module CommandKit
|
|
187
203
|
#
|
188
204
|
def desc
|
189
205
|
if (value = default_value)
|
190
|
-
"
|
206
|
+
default_text = "(Default: #{value})"
|
207
|
+
|
208
|
+
case @desc
|
209
|
+
when Array
|
210
|
+
@desc + [default_text]
|
211
|
+
else
|
212
|
+
"#{@desc} #{default_text}"
|
213
|
+
end
|
191
214
|
else
|
192
215
|
@desc
|
193
216
|
end
|
@@ -19,7 +19,7 @@ module CommandKit
|
|
19
19
|
class OptionValue < Arguments::ArgumentValue
|
20
20
|
|
21
21
|
# Maps OptionParser types to USAGE strings.
|
22
|
-
|
22
|
+
DEFAULT_USAGES = {
|
23
23
|
# NOTE: NilClass and Object are intentionally omitted
|
24
24
|
Date => 'DATE',
|
25
25
|
DateTime => 'DATE_TIME',
|
@@ -90,7 +90,7 @@ module CommandKit
|
|
90
90
|
# The given type was not a Class, Hash, Array, or Regexp.
|
91
91
|
#
|
92
92
|
def self.default_usage(type)
|
93
|
-
|
93
|
+
DEFAULT_USAGES.fetch(type) do
|
94
94
|
case type
|
95
95
|
when Hash then type.keys.join('|')
|
96
96
|
when Array then type.join('|')
|
@@ -22,7 +22,7 @@ module CommandKit
|
|
22
22
|
# end
|
23
23
|
# end
|
24
24
|
#
|
25
|
-
# def
|
25
|
+
# def run(*argv)
|
26
26
|
# if @custom
|
27
27
|
# puts "Custom mode enabled"
|
28
28
|
# end
|
@@ -78,9 +78,6 @@ module CommandKit
|
|
78
78
|
@option_parser = OptionParser.new do |opts|
|
79
79
|
opts.banner = "Usage: #{usage}"
|
80
80
|
|
81
|
-
opts.separator ''
|
82
|
-
opts.separator 'Options:'
|
83
|
-
|
84
81
|
opts.on_tail('-h','--help','Print help information') do
|
85
82
|
help
|
86
83
|
exit(0)
|
@@ -5,6 +5,16 @@ module CommandKit
|
|
5
5
|
#
|
6
6
|
# Defines a version option.
|
7
7
|
#
|
8
|
+
# ## Examples
|
9
|
+
#
|
10
|
+
# include CommandKit::Options::Version
|
11
|
+
#
|
12
|
+
# version '0.1.0'
|
13
|
+
#
|
14
|
+
# def run(*argv)
|
15
|
+
# # ...
|
16
|
+
# end
|
17
|
+
#
|
8
18
|
module Version
|
9
19
|
#
|
10
20
|
# Includes {Options}, extends {Version::ClassMethods}, and defines a
|
data/lib/command_kit/options.rb
CHANGED
@@ -23,6 +23,25 @@ module CommandKit
|
|
23
23
|
# @bar = arg.split(':')
|
24
24
|
# end
|
25
25
|
#
|
26
|
+
# ### Multi-line Descriptions
|
27
|
+
#
|
28
|
+
# option :opt, value: {type: String},
|
29
|
+
# desc: [
|
30
|
+
# 'line1',
|
31
|
+
# 'line2',
|
32
|
+
# '...'
|
33
|
+
# ]
|
34
|
+
#
|
35
|
+
# ### Option Categories
|
36
|
+
#
|
37
|
+
# option :opt1, value: {type: String},
|
38
|
+
# category: 'Foo Category',
|
39
|
+
# desc: 'Option 1'
|
40
|
+
#
|
41
|
+
# option :opt2, value: {type: String},
|
42
|
+
# category: 'Foo Category',
|
43
|
+
# desc: 'Option 2'
|
44
|
+
#
|
26
45
|
# ### initialize and using instance variables
|
27
46
|
#
|
28
47
|
# option :number, value: {type: Integer},
|
@@ -111,9 +130,12 @@ module CommandKit
|
|
111
130
|
# @option value [String, nil] usage
|
112
131
|
# The usage string for the option's value.
|
113
132
|
#
|
114
|
-
# @option kwargs [String] desc
|
133
|
+
# @option kwargs [String, Array<String>] desc
|
115
134
|
# The description for the option.
|
116
135
|
#
|
136
|
+
# @option kwargs [String, nil] category
|
137
|
+
# The optional category to group the option under.
|
138
|
+
#
|
117
139
|
# @yield [(value)]
|
118
140
|
# If a block is given, it will be passed the parsed option value.
|
119
141
|
#
|
@@ -129,6 +151,19 @@ module CommandKit
|
|
129
151
|
# @example Define an option:
|
130
152
|
# option :foo, desc: "Foo option"
|
131
153
|
#
|
154
|
+
# @example Define an option with a multi-line description:
|
155
|
+
# option :foo, desc: [
|
156
|
+
# "Line 1",
|
157
|
+
# "Line 2"
|
158
|
+
# ]
|
159
|
+
#
|
160
|
+
# @example Defines multiple options within a category:
|
161
|
+
# option :foo, desc: "Foo option",
|
162
|
+
# category: 'Other Options'
|
163
|
+
#
|
164
|
+
# option :bar, desc: "Bar option",
|
165
|
+
# category: 'Other Options'
|
166
|
+
#
|
132
167
|
# @example With a custom short option:
|
133
168
|
# option :foo, short: '-f',
|
134
169
|
# desc: "Foo option"
|
@@ -212,19 +247,7 @@ module CommandKit
|
|
212
247
|
|
213
248
|
super(**kwargs)
|
214
249
|
|
215
|
-
|
216
|
-
default_value = option.default_value
|
217
|
-
|
218
|
-
@options[option.name] = default_value unless default_value.nil?
|
219
|
-
|
220
|
-
option_parser.on(*option.usage,option.type,option.desc) do |arg,*captures|
|
221
|
-
@options[option.name] = arg
|
222
|
-
|
223
|
-
if option.block
|
224
|
-
instance_exec(*arg,*captures,&option.block)
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
250
|
+
define_option_categories()
|
228
251
|
end
|
229
252
|
|
230
253
|
#
|
@@ -237,5 +260,57 @@ module CommandKit
|
|
237
260
|
help_options
|
238
261
|
help_arguments
|
239
262
|
end
|
263
|
+
|
264
|
+
private
|
265
|
+
|
266
|
+
#
|
267
|
+
# Defines all of the options, grouped by category.
|
268
|
+
#
|
269
|
+
def define_option_categories
|
270
|
+
categories = self.class.options.values.group_by(&:category)
|
271
|
+
|
272
|
+
categories.each do |category,options|
|
273
|
+
if category
|
274
|
+
define_options_category(category,options)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
define_options_category('Options',categories.fetch(nil,[]))
|
279
|
+
end
|
280
|
+
|
281
|
+
#
|
282
|
+
# Defines a new category of options with a header.
|
283
|
+
#
|
284
|
+
# @param [String] category
|
285
|
+
# The category name.
|
286
|
+
#
|
287
|
+
# @param [Array<Option>, nil] options
|
288
|
+
# The options to define.
|
289
|
+
#
|
290
|
+
def define_options_category(category,options)
|
291
|
+
option_parser.separator ''
|
292
|
+
option_parser.separator "#{category}:"
|
293
|
+
|
294
|
+
options.each(&method(:define_option))
|
295
|
+
end
|
296
|
+
|
297
|
+
#
|
298
|
+
# Defines an individual option.
|
299
|
+
#
|
300
|
+
# @param [Option] option
|
301
|
+
#
|
302
|
+
def define_option(option)
|
303
|
+
default_value = option.default_value
|
304
|
+
|
305
|
+
@options[option.name] = default_value unless default_value.nil?
|
306
|
+
|
307
|
+
option_parser.on(*option.usage,option.type,option.desc) do |arg,*captures|
|
308
|
+
@options[option.name] = arg
|
309
|
+
|
310
|
+
if option.block
|
311
|
+
instance_exec(*arg,*captures,&option.block)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
240
315
|
end
|
241
316
|
end
|
data/lib/command_kit/os.rb
CHANGED
@@ -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
|
@@ -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
|