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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +4 -5
  3. data/.rubocop.yml +14 -1
  4. data/ChangeLog.md +82 -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/arguments/argument.rb +2 -2
  12. data/lib/command_kit/arguments.rb +27 -2
  13. data/lib/command_kit/bug_report.rb +105 -0
  14. data/lib/command_kit/colors.rb +488 -15
  15. data/lib/command_kit/command.rb +1 -2
  16. data/lib/command_kit/edit.rb +54 -0
  17. data/lib/command_kit/env.rb +1 -1
  18. data/lib/command_kit/file_utils.rb +46 -0
  19. data/lib/command_kit/options/option.rb +45 -22
  20. data/lib/command_kit/options/option_value.rb +2 -2
  21. data/lib/command_kit/options/parser.rb +1 -4
  22. data/lib/command_kit/options/quiet.rb +1 -1
  23. data/lib/command_kit/options/verbose.rb +2 -2
  24. data/lib/command_kit/options/version.rb +10 -0
  25. data/lib/command_kit/options.rb +89 -14
  26. data/lib/command_kit/os.rb +1 -1
  27. data/lib/command_kit/printing/fields.rb +56 -0
  28. data/lib/command_kit/printing/indent.rb +1 -1
  29. data/lib/command_kit/printing/lists.rb +91 -0
  30. data/lib/command_kit/printing/tables/border_style.rb +169 -0
  31. data/lib/command_kit/printing/tables/cell_builder.rb +93 -0
  32. data/lib/command_kit/printing/tables/row_builder.rb +111 -0
  33. data/lib/command_kit/printing/tables/style.rb +198 -0
  34. data/lib/command_kit/printing/tables/table_builder.rb +145 -0
  35. data/lib/command_kit/printing/tables/table_formatter.rb +254 -0
  36. data/lib/command_kit/printing/tables.rb +208 -0
  37. data/lib/command_kit/program_name.rb +9 -0
  38. data/lib/command_kit/stdio.rb +5 -1
  39. data/lib/command_kit/version.rb +1 -1
  40. data/spec/arguments_spec.rb +33 -0
  41. data/spec/bug_report_spec.rb +266 -0
  42. data/spec/colors_spec.rb +232 -195
  43. data/spec/command_name_spec.rb +1 -1
  44. data/spec/command_spec.rb +2 -2
  45. data/spec/edit_spec.rb +72 -0
  46. data/spec/file_utils_spec.rb +59 -0
  47. data/spec/fixtures/template.erb +5 -0
  48. data/spec/options/option_spec.rb +48 -2
  49. data/spec/options/parser_spec.rb +0 -10
  50. data/spec/options/quiet_spec.rb +51 -0
  51. data/spec/options/verbose_spec.rb +51 -0
  52. data/spec/options/version_spec.rb +146 -0
  53. data/spec/options_spec.rb +46 -0
  54. data/spec/pager_spec.rb +1 -1
  55. data/spec/printing/fields_spec.rb +167 -0
  56. data/spec/printing/lists_spec.rb +99 -0
  57. data/spec/printing/tables/border_style.rb +43 -0
  58. data/spec/printing/tables/cell_builer_spec.rb +135 -0
  59. data/spec/printing/tables/row_builder_spec.rb +165 -0
  60. data/spec/printing/tables/style_spec.rb +377 -0
  61. data/spec/printing/tables/table_builder_spec.rb +252 -0
  62. data/spec/printing/tables/table_formatter_spec.rb +1180 -0
  63. data/spec/printing/tables_spec.rb +1069 -0
  64. data/spec/program_name_spec.rb +8 -0
  65. metadata +36 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d04119403fa9585e0258d2b20bb7c307d124aafb70c88e03749395c7b4eedb97
4
- data.tar.gz: 3ec992adf12bbc98313bb6ff8f3038091b50b31abbf8950765a71edd771378fb
3
+ metadata.gz: 72a3fdeb65d9eb4c4e996aa95ea7e8131e220c2cb24be8b17d56e1742a156d35
4
+ data.tar.gz: d05b75366f58c219c9680d07571a171239f0ab8f77580cb1c2d47c6322d7e74c
5
5
  SHA512:
6
- metadata.gz: faeeaa08921ab315a825d4b1ff69f6b254c53b6675dd4278478b77200d6d2afb688d110757685ed33d74b90a6b1e9394c12135c3ab5f08e2ca3ca5834ead248d
7
- data.tar.gz: 6b4ba3da0434c9fbd93d92a4c9d91e8eb53f1185df15edb21283c09b2ddf9ec4dc9fcb3708bdf83a1158cef92c988ccb5133ec5664ac9dcb213bdcde45aacf3d
6
+ metadata.gz: 1cc85835b40fded3170ee21619620dbb988dd3427fa8cb48456f09a7991b6eed72299a81ba19be543c260557504d5636237993f33360d463d72a87600ca14441
7
+ data.tar.gz: 9d57ec57d540547d2fa664faf8e3bb1e0c0aa06929162d3dac849f858911aa5e7610e8294b2189927d8633de8e9784079df548a3e900fd73c57f76e72c87ad9d
@@ -10,12 +10,11 @@ jobs:
10
10
  fail-fast: false
11
11
  matrix:
12
12
  ruby:
13
- - 2.7
14
- - 3.0
13
+ - '3.0'
14
+ - '3.1'
15
15
  # TODO: uncomment when jruby supports ruby >= 2.7
16
16
  # - jruby
17
- # TODO: uncomment when truffleruby supports splatting empty kwargs
18
- # - truffleruby
17
+ - truffleruby
19
18
  name: Ruby ${{ matrix.ruby }}
20
19
  steps:
21
20
  - uses: actions/checkout@v2
@@ -36,7 +35,7 @@ jobs:
36
35
  - name: Set up Ruby
37
36
  uses: ruby/setup-ruby@v1
38
37
  with:
39
- ruby-version: 2.7
38
+ ruby-version: 3.0
40
39
  - name: Install dependencies
41
40
  run: bundle install --jobs 4 --retry 3
42
41
  - name: Run rubocop
data/.rubocop.yml CHANGED
@@ -7,7 +7,7 @@ AllCops:
7
7
  # our rules
8
8
  #
9
9
 
10
- Layout/FirstArrayElementIndentation: { EnforcedStyle: consistent }
10
+ Layout/FirstArrayElementIndentation: { Exclude: ['spec/**/*'] }
11
11
  Layout/LineLength: { Enabled: false }
12
12
  Layout/SpaceAroundEqualsInParameterDefault: { EnforcedStyle: no_space }
13
13
  Lint/ConstantDefinitionInBlock: { Exclude: ['spec/**/*'] }
@@ -22,6 +22,7 @@ Style/PercentLiteralDelimiters:
22
22
  '%I': '[]'
23
23
  '%w': '[]'
24
24
  '%W': '[]'
25
+ Style/UnlessElse: { Enabled: false }
25
26
 
26
27
  #
27
28
  # rules that are in flux
@@ -139,3 +140,15 @@ Style/TrailingCommaInHashLiteral: { Enabled: false } # Offense count: 2
139
140
 
140
141
  # rubocop cannot tell that rubygems_mfa_required is enabled in gemspec.yml
141
142
  Gemspec/RequireMFA: { Enabled: false }
143
+
144
+ # make an exception for our gemspec code
145
+ Gemspec/DuplicatedAssignment:
146
+ Exclude:
147
+ - 'command_kit.gemspec'
148
+
149
+ Bundler/OrderedGems: { Enabled: false }
150
+
151
+ # rubocup is not aware of vertical alignment of matrixes (Array of Arrays).
152
+ Layout/SpaceInsideArrayLiteralBrackets: { Enabled: false }
153
+
154
+ Naming/HeredocDelimiterNaming: { Enabled: false }
data/ChangeLog.md CHANGED
@@ -1,3 +1,85 @@
1
+ ### 0.4.0 / 2022-11-11
2
+
3
+ * Added {CommandKit::BugReport}.
4
+ * Added {CommandKit::Edit}.
5
+ * Added {CommandKit::Printing::Fields}.
6
+ * Added {CommandKit::Printing::Lists}.
7
+ * Added {CommandKit::Printing::Tables}.
8
+
9
+ #### CommandKit::Colors
10
+
11
+ * Support disabling ANSI color output if the `NO_COLOR` environment variable is
12
+ set.
13
+
14
+ #### CommandKit::Options
15
+
16
+ * Correct the option usage for long option flags that have optional values
17
+ (ex: `--longopt[=VALUE]`).
18
+
19
+ ### 0.3.0 / 2021-12-26
20
+
21
+ * Added {CommandKit::FileUtils}.
22
+
23
+ #### CommandKit::FileUtils
24
+
25
+ * Added {CommandKit::FileUtils#erb #erb}.
26
+
27
+ #### CommandKit::Colors
28
+
29
+ * Added {CommandKit::Colors::ANSI::RESET_FG RESET_FG}.
30
+ * Added {CommandKit::Colors::ANSI.bright_black bright_black}.
31
+ * Added {CommandKit::Colors::ANSI.gray gray}.
32
+ * Added {CommandKit::Colors::ANSI.bright_red bright_red}.
33
+ * Added {CommandKit::Colors::ANSI.bright_green bright_green}.
34
+ * Added {CommandKit::Colors::ANSI.bright_yellow bright_yellow}.
35
+ * Added {CommandKit::Colors::ANSI.bright_blue bright_blue}.
36
+ * Added {CommandKit::Colors::ANSI.bright_magenta bright_magenta}.
37
+ * Added {CommandKit::Colors::ANSI.bright_cyan bright_cyan}.
38
+ * Added {CommandKit::Colors::ANSI.bright_white bright_white}.
39
+ * Added {CommandKit::Colors::ANSI.on_bright_black on_bright_black}.
40
+ * Added {CommandKit::Colors::ANSI.on_gray on_gray}.
41
+ * Added {CommandKit::Colors::ANSI.on_bright_red on_bright_red}.
42
+ * Added {CommandKit::Colors::ANSI.on_bright_green on_bright_green}.
43
+ * Added {CommandKit::Colors::ANSI.on_bright_yellow on_bright_yellow}.
44
+ * Added {CommandKit::Colors::ANSI.on_bright_blue on_bright_blue}.
45
+ * Added {CommandKit::Colors::ANSI.on_bright_magenta on_bright_magenta}.
46
+ * Added {CommandKit::Colors::ANSI.on_bright_cyan on_bright_cyan}.
47
+ * Added {CommandKit::Colors::ANSI.on_bright_white on_bright_white}.
48
+
49
+ #### ComandKit::Options
50
+
51
+ * Allow grouping options into categories:
52
+
53
+ option :opt1, category: 'Foo Options',
54
+ desc: 'Option 1'
55
+
56
+ option :opt2, category: 'Foo Options',
57
+ desc: 'Option 1'
58
+
59
+ * Allow options to have multi-line descriptions:
60
+
61
+ option :opt1, short: '-o',
62
+ desc: [
63
+ 'line1',
64
+ 'line2',
65
+ '...'
66
+ ]
67
+
68
+ #### CommandKit::Arguments
69
+
70
+ * Allow arguments to have multi-line descriptions:
71
+
72
+ argument :arg1, desc: [
73
+ 'line1',
74
+ 'line2',
75
+ '...'
76
+ ]
77
+
78
+
79
+ #### CommandKit::ProgramName
80
+
81
+ * Added {CommandKit::ProgramName#command_name}.
82
+
1
83
  ### 0.2.2 / 2021-12-26
2
84
 
3
85
  #### CommandKit::Help::Man
data/Gemfile CHANGED
@@ -12,6 +12,8 @@ group :development do
12
12
  gem 'simplecov', '~> 0.20', require: false
13
13
 
14
14
  gem 'kramdown'
15
+ gem 'redcarpet', platform: :mri
15
16
  gem 'yard', '~> 0.9'
16
17
  gem 'yard-spellcheck', require: false
18
+ gem 'dead_end'
17
19
  end
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2021 Hal Brodigan
1
+ Copyright (c) 2021-2022 Hal Brodigan
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -11,30 +11,33 @@
11
11
 
12
12
  ## Description
13
13
 
14
- A Ruby toolkit for building clean, correct, and robust CLI commands as
14
+ A modular Ruby toolkit for building clean, correct, and robust CLI commands as
15
15
  plain-old Ruby classes.
16
16
 
17
17
  ## Features
18
18
 
19
19
  * **Simple** - Commands are plain-old ruby classes, with options and
20
- arguments declared as attributes. All features are ruby modules that can be
20
+ arguments declared as attributes. All features are Ruby modules that can be
21
21
  included into command classes.
22
22
  * **Correct** - CommandKit behaves like a standard UNIX command.
23
23
  * Safely handles Ctrl^C / SIGINT interrupts and [exits with 130](https://tldp.org/LDP/abs/html/exitcodes.html).
24
24
  * Safely handles broken pipes (aka `mycmd | head`).
25
- * Respects common environment variables (ex: `TERM=dumb`).
25
+ * Respects common environment variables (ex: `TERM=dumb` and `NO_COLOR`).
26
26
  * Uses [OptionParser][optparse] for POSIX option parsing.
27
- * Disables ANSI color when output is redirected to a file.
27
+ * Disables ANSI color when output is redirected to a file or when `NO_COLOR`
28
+ is set.
28
29
  * **Complete** - Provides many additional CLI features.
29
30
  * OS detection.
30
31
  * Terminal size detection.
31
32
  * ANSI coloring support.
32
33
  * Interactive input.
34
+ * Rich text printing support (fields, lists, and tables).
33
35
  * Subcommands (explicit or lazy-loaded) and command aliases.
34
36
  * Displaying man pages for `--help`/`help`.
35
37
  * Using the pager (aka `less`).
36
38
  * [XDG directories](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) (aka `~/.config/`, `~/.local/share/`, `~/.cache/`).
37
- * **Testable** - Since commands are plain-old ruby classes, it's easy to
39
+ * Exception handling / Bug reporting.
40
+ * **Testable** - Since commands are plain-old Ruby classes, it's easy to
38
41
  initialize them and call `#main` or `#run`.
39
42
 
40
43
  ## Anti-Features
@@ -45,7 +48,7 @@ plain-old Ruby classes.
45
48
 
46
49
  ## Requirements
47
50
 
48
- * [ruby] >= 2.7.0
51
+ * [ruby] >= 3.0.0
49
52
 
50
53
  ## Install
51
54
 
@@ -56,13 +59,13 @@ $ gem install command_kit
56
59
  ### gemspec
57
60
 
58
61
  ```ruby
59
- gem.add_dependency 'command_kit', '~> 0.2'
62
+ gem.add_dependency 'command_kit', '~> 0.3'
60
63
  ```
61
64
 
62
65
  ### Gemfile
63
66
 
64
67
  ```ruby
65
- gem 'command_kit', '~> 0.2'
68
+ gem 'command_kit', '~> 0.3'
66
69
  ```
67
70
 
68
71
  ## Examples
@@ -204,6 +207,7 @@ end
204
207
  ### Reference
205
208
 
206
209
  * [CommandKit::Arguments](https://rubydoc.info/gems/command_kit/CommandKit/Arguments)
210
+ * [CommandKit::BugReport](https://rubydoc.info/gems/command_kit/CommandKit/BugReport)
207
211
  * [CommandKit::Colors](https://rubydoc.info/gems/command_kit/CommandKit/Colors)
208
212
  * [CommandKit::Command](https://rubydoc.info/gems/command_kit/CommandKit/Command)
209
213
  * [CommandKit::CommandName](https://rubydoc.info/gems/command_kit/CommandKit/CommandName)
@@ -211,11 +215,13 @@ end
211
215
  * [CommandKit::Commands::AutoLoad](https://rubydoc.info/gems/command_kit/CommandKit/Commands/AutoLoad)
212
216
  * [CommandKit::Commands::AutoRequire](https://rubydoc.info/gems/command_kit/CommandKit/Commands/AutoRequire)
213
217
  * [CommandKit::Description](https://rubydoc.info/gems/command_kit/CommandKit/Description)
218
+ * [CommandKit::Edit](https://rubydoc.info/gems/command_kit/CommandKit/Edit)
214
219
  * [CommandKit::Env](https://rubydoc.info/gems/command_kit/CommandKit/Env)
215
220
  * [CommandKit::Env::Home](https://rubydoc.info/gems/command_kit/CommandKit/Env/Home)
216
221
  * [CommandKit::Env::Path](https://rubydoc.info/gems/command_kit/CommandKit/Env/Path)
217
222
  * [CommandKit::Examples](https://rubydoc.info/gems/command_kit/CommandKit/Examples)
218
223
  * [CommandKit::ExceptionHandler](https://rubydoc.info/gems/command_kit/CommandKit/ExceptionHandler)
224
+ * [CommandKit::FileUtils](https://rubydoc.info/gems/command_kit/CommandKit/FileUtils)
219
225
  * [CommandKit::Help](https://rubydoc.info/gems/command_kit/CommandKit/Help)
220
226
  * [CommandKit::Help::Man](https://rubydoc.info/gems/command_kit/CommandKit/Help/Man)
221
227
  * [CommandKit::Interactive](https://rubydoc.info/gems/command_kit/CommandKit/Interactive)
@@ -225,7 +231,10 @@ end
225
231
  * [CommandKit::Options::Verbose](https://rubydoc.info/gems/command_kit/CommandKit/Options/Verbose)
226
232
  * [CommandKit::Pager](https://rubydoc.info/gems/command_kit/CommandKit/Pager)
227
233
  * [CommandKit::Printing](https://rubydoc.info/gems/command_kit/CommandKit/Printing)
234
+ * [CommandKit::Printing::Fields](https://rubydoc.info/gems/command_kit/CommandKit/Printing/Fields)
228
235
  * [CommandKit::Printing::Indent](https://rubydoc.info/gems/command_kit/CommandKit/Printing/Indent)
236
+ * [CommandKit::Printing::Lists](https://rubydoc.info/gems/command_kit/CommandKit/Printing/Lists)
237
+ * [CommandKit::Printing::Tables](https://rubydoc.info/gems/command_kit/CommandKit/Printing/Tables)
229
238
  * [CommandKit::ProgramName](https://rubydoc.info/gems/command_kit/CommandKit/ProgramName)
230
239
  * [CommandKit::Stdio](https://rubydoc.info/gems/command_kit/CommandKit/Stdio)
231
240
  * [CommandKit::Terminal](https://rubydoc.info/gems/command_kit/CommandKit/Terminal)
@@ -244,7 +253,7 @@ Twitter.
244
253
 
245
254
  ## Copyright
246
255
 
247
- Copyright (c) 2021 Hal Brodigan
256
+ Copyright (c) 2021-2022 Hal Brodigan
248
257
 
249
258
  See {file:LICENSE.txt} for details.
250
259
 
data/command_kit.gemspec CHANGED
@@ -32,7 +32,6 @@ Gem::Specification.new do |gem|
32
32
  gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
33
33
 
34
34
  gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
35
- gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
36
35
  gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
37
36
 
38
37
  gem.require_paths = Array(gemspec.fetch('require_paths') {
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path('../../../lib',__FILE__))
4
+ require 'command_kit/command'
5
+ require 'command_kit/printing/tables'
6
+
7
+ class TablesCmd < CommandKit::Command
8
+
9
+ include CommandKit::Printing::Tables
10
+
11
+ def run
12
+ header = ['A', 'B', 'C']
13
+ table = [
14
+ ['AAAA', 'BBBB', 'CCCC'],
15
+ ['AAAA', 'BBBB', 'CCCC'],
16
+ ['AAAA', 'BBBB', 'CCCC']
17
+ ]
18
+
19
+ puts
20
+ puts "Table:"
21
+ puts
22
+ print_table table
23
+
24
+ puts
25
+ puts "Table with header:"
26
+ puts
27
+ print_table table, header: header
28
+
29
+ puts
30
+ puts "ASCII border:"
31
+ puts
32
+
33
+ print_table table, header: header,
34
+ border: :ascii
35
+
36
+ puts
37
+ puts "Border + Separated rows:"
38
+ puts
39
+
40
+ print_table table, header: header,
41
+ border: :ascii,
42
+ separate_rows: true
43
+
44
+ puts
45
+ puts "Lined border:"
46
+ puts
47
+
48
+ print_table table, header: header,
49
+ border: :line
50
+
51
+ puts
52
+ puts "Double line border:"
53
+ puts
54
+
55
+ print_table table, header: header,
56
+ border: :double_line
57
+
58
+ uneven_table = [
59
+ ['AAAAAA', 'B', 'CCCCCCC'],
60
+ ['AAA', 'BBBB', 'CCC' ],
61
+ ['A', 'BBBBBBB', 'C' ]
62
+ ]
63
+
64
+ puts
65
+ puts "Left-justified:"
66
+ puts
67
+
68
+ print_table uneven_table, header: header,
69
+ justify: :left,
70
+ justify_header: :left,
71
+ border: :line
72
+
73
+ puts
74
+ puts "Right-justified:"
75
+ puts
76
+
77
+ print_table uneven_table, header: header,
78
+ justify: :right,
79
+ justify_header: :right,
80
+ border: :line
81
+
82
+ puts
83
+ puts "Center-justified:"
84
+ puts
85
+
86
+ print_table uneven_table, header: header,
87
+ justify: :center,
88
+ justify_header: :center,
89
+ border: :line
90
+
91
+ puts
92
+ puts "Table with empty cells:"
93
+ puts
94
+
95
+ table_with_empty_cells = [
96
+ ['AAAA', 'BBBB', 'CCCC'],
97
+ ['AAAA', nil, 'CCCC'],
98
+ ['AAAA', 'BBBB']
99
+ ]
100
+
101
+ print_table table_with_empty_cells, header: header,
102
+ justify: :left,
103
+ border: :line
104
+
105
+ puts
106
+ puts "Multi-line table:"
107
+ puts
108
+
109
+ multi_line_table = [
110
+ ['AAAA', 'BBBB', "CCCC\nCC"],
111
+ ['AAAA', "BBBB\nB", 'CCCC'],
112
+ ["AAAA\nAA\nA", "BBBB", "CCCC"]
113
+ ]
114
+
115
+ print_table multi_line_table, header: header,
116
+ justify: :left,
117
+ border: :line
118
+
119
+ puts
120
+ puts "Indent aware:"
121
+ puts
122
+
123
+ puts "* Item 1"
124
+ indent do
125
+ puts "* Item 2"
126
+ puts
127
+
128
+ indent do
129
+ print_table table, header: header,
130
+ border: :line
131
+ end
132
+ end
133
+
134
+ puts
135
+ end
136
+
137
+ end
138
+
139
+ if __FILE__ == $0
140
+ TablesCmd.start
141
+ end
data/gemspec.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  name: command_kit
2
- summary: A toolkit for building Ruby CLI commands
2
+ summary: An all-in-one modular Ruby CLI toolkit
3
3
  description:
4
- A Ruby toolkit for building clean, correct, and robust CLI commands as
4
+ A modular Ruby toolkit for building clean, correct, and robust CLI commands as
5
5
  plain-old Ruby classes.
6
6
 
7
7
  license: MIT
@@ -16,7 +16,7 @@ metadata:
16
16
  changelog_uri: https://github.com/postmodern/command_kit.rb/blob/main/ChangeLog.md
17
17
  rubygems_mfa_required: 'true'
18
18
 
19
- required_ruby_version: ">= 2.7.0"
19
+ required_ruby_version: ">= 3.0.0"
20
20
 
21
21
  development_dependencies:
22
22
  bundler: ~> 2.0
@@ -16,7 +16,7 @@ module CommandKit
16
16
 
17
17
  # The argument's description.
18
18
  #
19
- # @return [String]
19
+ # @return [String, Array<String>]
20
20
  attr_reader :desc
21
21
 
22
22
  #
@@ -34,7 +34,7 @@ module CommandKit
34
34
  # @param [Boolean] repeats
35
35
  # Specifies whether the argument can be repeated multiple times.
36
36
  #
37
- # @param [String] desc
37
+ # @param [String, Array<String>] desc
38
38
  # The description for the argument.
39
39
  #
40
40
  # @yield [(value)]
@@ -46,6 +46,14 @@ module CommandKit
46
46
  # def run(*files)
47
47
  # end
48
48
  #
49
+ # ### Multi-line descriptions
50
+ #
51
+ # argument :arg, desc: [
52
+ # 'line1',
53
+ # 'line2',
54
+ # '...'
55
+ # ]
56
+ #
49
57
  module Arguments
50
58
  include Usage
51
59
  include Main
@@ -114,7 +122,7 @@ module CommandKit
114
122
  # @option kwargs [Boolean] repeats
115
123
  # Specifies whether the argument can be repeated multiple times.
116
124
  #
117
- # @option kwargs [String] desc
125
+ # @option kwargs [String, Array<String>] desc
118
126
  # The description for the argument.
119
127
  #
120
128
  # @return [Argument]
@@ -123,6 +131,12 @@ module CommandKit
123
131
  # @example Define an argument:
124
132
  # argument :bar, desc: "Bar argument"
125
133
  #
134
+ # @example Defines an argument with a multi-line description:
135
+ # argument :bar, desc: [
136
+ # "Line 1 ...",
137
+ # "Line 2 ..."
138
+ # ]
139
+ #
126
140
  # @example With a custom usage string:
127
141
  # argument :bar, usage: 'BAR',
128
142
  # desc: "Bar argument"
@@ -191,7 +205,18 @@ module CommandKit
191
205
  puts 'Arguments:'
192
206
 
193
207
  arguments.each_value do |arg|
194
- puts " #{arg.usage.ljust(33)}#{arg.desc}"
208
+ case arg.desc
209
+ when Array
210
+ arg.desc.each_with_index do |line,index|
211
+ if index == 0
212
+ puts " #{arg.usage.ljust(33)}#{line}"
213
+ else
214
+ puts " #{' '.ljust(33)}#{line}"
215
+ end
216
+ end
217
+ else
218
+ puts " #{arg.usage.ljust(33)}#{arg.desc}"
219
+ end
195
220
  end
196
221
  end
197
222
  end
@@ -0,0 +1,105 @@
1
+ require 'command_kit/exception_handler'
2
+ require 'command_kit/printing'
3
+
4
+ module CommandKit
5
+ #
6
+ # Adds an exception handler to print a bug report when an unhandled exception
7
+ # is raised by `run`.
8
+ #
9
+ # @since 0.4.0
10
+ #
11
+ module BugReport
12
+ include ExceptionHandler
13
+ include Printing
14
+
15
+ #
16
+ # @api private
17
+ #
18
+ module ModuleMethods
19
+ #
20
+ # Extends {ClassMethods} or {ModuleMethods}, depending on whether
21
+ # {Options} is being included into a class or a module.
22
+ #
23
+ # @param [Class, Module] context
24
+ # The class or module which is including {Options}.
25
+ #
26
+ def included(context)
27
+ super(context)
28
+
29
+ if context.class == Module
30
+ context.extend ModuleMethods
31
+ else
32
+ context.extend ClassMethods
33
+ end
34
+ end
35
+ end
36
+
37
+ extend ModuleMethods
38
+
39
+ #
40
+ # Defines class-level methods.
41
+ #
42
+ module ClassMethods
43
+ #
44
+ # Gets or sets the bug report URL.
45
+ #
46
+ # @param [String, nil] new_url
47
+ # The new bug report URL.
48
+ #
49
+ # @return [String, nil]
50
+ # The bug report URL.
51
+ #
52
+ # @example
53
+ # bug_report_url 'https://github.com/user/repo/issues/new'
54
+ #
55
+ def bug_report_url(new_url=nil)
56
+ if new_url
57
+ @bug_report_url = new_url
58
+ else
59
+ @bug_report_url || if superclass.kind_of?(ClassMethods)
60
+ superclass.bug_report_url
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ #
67
+ # The bug report URL.
68
+ #
69
+ # @return [String, nil]
70
+ #
71
+ def bug_report_url
72
+ self.class.bug_report_url
73
+ end
74
+
75
+ #
76
+ # Overrides {#on_exception} to print a bug report for unhandled exceptions
77
+ # and then exit with `-1`.
78
+ #
79
+ # @param [Exception] error
80
+ # The unhandled exception.
81
+ #
82
+ def on_exception(error)
83
+ print_bug_report(error)
84
+ exit(-1)
85
+ end
86
+
87
+ #
88
+ # Prints a bug report for the unhandled exception.
89
+ #
90
+ # @param [Exception] error
91
+ # The unhandled exception.
92
+ #
93
+ def print_bug_report(error)
94
+ url = bug_report_url
95
+
96
+ stderr.puts
97
+ stderr.puts "Oops! Looks like you have found a bug. Please report it!"
98
+ stderr.puts url if url
99
+ stderr.puts
100
+ stderr.puts '```'
101
+ print_exception(error)
102
+ stderr.puts '```'
103
+ end
104
+ end
105
+ end