command_kit 0.1.0.rc1 → 0.1.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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +1 -1
  3. data/README.md +7 -4
  4. data/gemspec.yml +1 -1
  5. data/lib/command_kit.rb +1 -0
  6. data/lib/command_kit/arguments.rb +16 -1
  7. data/lib/command_kit/arguments/argument.rb +2 -0
  8. data/lib/command_kit/arguments/argument_value.rb +2 -0
  9. data/lib/command_kit/colors.rb +32 -0
  10. data/lib/command_kit/command.rb +5 -0
  11. data/lib/command_kit/command_name.rb +9 -0
  12. data/lib/command_kit/commands.rb +30 -0
  13. data/lib/command_kit/commands/auto_load.rb +16 -0
  14. data/lib/command_kit/commands/auto_require.rb +16 -0
  15. data/lib/command_kit/commands/command.rb +3 -0
  16. data/lib/command_kit/commands/help.rb +2 -0
  17. data/lib/command_kit/commands/parent_command.rb +7 -0
  18. data/lib/command_kit/commands/subcommand.rb +12 -0
  19. data/lib/command_kit/description.rb +12 -1
  20. data/lib/command_kit/env.rb +4 -0
  21. data/lib/command_kit/env/home.rb +9 -0
  22. data/lib/command_kit/env/path.rb +15 -0
  23. data/lib/command_kit/examples.rb +12 -1
  24. data/lib/command_kit/exception_handler.rb +4 -0
  25. data/lib/command_kit/help.rb +7 -1
  26. data/lib/command_kit/help/man.rb +13 -0
  27. data/lib/command_kit/inflector.rb +2 -0
  28. data/lib/command_kit/interactive.rb +62 -1
  29. data/lib/command_kit/main.rb +11 -0
  30. data/lib/command_kit/options.rb +12 -0
  31. data/lib/command_kit/options/option.rb +2 -0
  32. data/lib/command_kit/options/option_value.rb +2 -0
  33. data/lib/command_kit/options/parser.rb +29 -0
  34. data/lib/command_kit/options/quiet.rb +3 -0
  35. data/lib/command_kit/options/verbose.rb +5 -0
  36. data/lib/command_kit/options/version.rb +6 -0
  37. data/lib/command_kit/os.rb +6 -0
  38. data/lib/command_kit/pager.rb +27 -0
  39. data/lib/command_kit/printing.rb +23 -0
  40. data/lib/command_kit/printing/indent.rb +23 -0
  41. data/lib/command_kit/program_name.rb +7 -0
  42. data/lib/command_kit/stdio.rb +24 -0
  43. data/lib/command_kit/terminal.rb +12 -0
  44. data/lib/command_kit/usage.rb +14 -0
  45. data/lib/command_kit/version.rb +1 -1
  46. data/lib/command_kit/xdg.rb +13 -0
  47. data/spec/arguments/argument_spec.rb +1 -1
  48. data/spec/arguments_spec.rb +3 -27
  49. data/spec/colors_spec.rb +21 -13
  50. data/spec/command_name_spec.rb +1 -1
  51. data/spec/command_spec.rb +4 -1
  52. data/spec/commands/auto_load/subcommand_spec.rb +1 -1
  53. data/spec/commands/auto_load_spec.rb +1 -1
  54. data/spec/commands/auto_require_spec.rb +2 -2
  55. data/spec/commands/help_spec.rb +1 -1
  56. data/spec/commands/parent_command_spec.rb +1 -1
  57. data/spec/commands/subcommand_spec.rb +1 -1
  58. data/spec/commands_spec.rb +1 -1
  59. data/spec/description_spec.rb +1 -25
  60. data/spec/env/home_spec.rb +1 -1
  61. data/spec/env/path_spec.rb +1 -1
  62. data/spec/examples_spec.rb +1 -25
  63. data/spec/help/man_spec.rb +1 -1
  64. data/spec/help_spec.rb +0 -25
  65. data/spec/inflector_spec.rb +1 -1
  66. data/spec/main_spec.rb +7 -7
  67. data/spec/options/option_spec.rb +3 -3
  68. data/spec/options/option_value_spec.rb +1 -1
  69. data/spec/options_spec.rb +1 -1
  70. data/spec/os_spec.rb +1 -1
  71. data/spec/pager_spec.rb +1 -1
  72. data/spec/printing/indent_spec.rb +1 -1
  73. data/spec/printing_spec.rb +10 -2
  74. data/spec/program_name_spec.rb +1 -1
  75. data/spec/spec_helper.rb +0 -3
  76. data/spec/terminal_spec.rb +1 -1
  77. data/spec/usage_spec.rb +1 -1
  78. data/spec/xdg_spec.rb +1 -1
  79. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c8944ddc49470bbe03b23cdf0df4cc9e5f94010208e15b373430453556ff2ed
4
- data.tar.gz: bfebe1ddb5ae5a078e5910de55f626ae69dc8716f3d5152690e9002b68878bfe
3
+ metadata.gz: acf8c9763694ffe7ac298e158863a3165c5d8f1a2209d1cac5b01e9c60d9dd85
4
+ data.tar.gz: 98669568909de27878be028ae8b0251ddc6e8a4740af23037bd234d06778b2ce
5
5
  SHA512:
6
- metadata.gz: a8f00bba78443b945ea4c41efeaf4488eb6c65867ac637b4ae368d6a53724802395f0f9d5d464241fbe9d7f22fd1657e50161df4846fcdcce174f4abf206abb7
7
- data.tar.gz: 497da95cec49705d426da9dfa27aa5f7ca9e462375dba94375244e5180f9ac9f1735850022fdfd61876cb6661a5988c568eda518dac010859be69589c3780843
6
+ metadata.gz: b04269a04b5d474f2a17724e04fa015fe5c1eefdbba9f53cf06c49c727c369ae3ba9a77e336c09f69fc3e7c8b6e5f77fa98abe7912c022213489d5b04191f5bb
7
+ data.tar.gz: 01c43327289df1e30970e618b2d133e26bc5e6cdd3d65cc6fad7cbc369e44085fd164cb0b93a241df6508e3019fbfed658f83191e958457ec6f7ecfed86b88b3
data/ChangeLog.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.1.0 / 2021-07-XX
1
+ ### 0.1.0 / 2021-07-16
2
2
 
3
3
  * Initial release:
4
4
  * {CommandKit::Arguments}
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # command_kit
2
2
 
3
- * [Homepage](https://github.com/postmodern/command_kit#readme)
4
- * [Issues](https://github.com/postmodern/command_kit/issues)
3
+ * [Homepage](https://github.com/postmodern/command_kit.rb#readme)
4
+ * [Forum](https://github.com/postmodern/command_kit.rb/discussions)
5
+ * [Issues](https://github.com/postmodern/command_kit.rb/issues)
5
6
  * [Documentation](http://rubydoc.info/gems/command_kit/frames)
6
- * [Email](mailto:postmodern.mod3 at gmail.com)
7
7
 
8
8
  ## Description
9
9
 
@@ -20,9 +20,12 @@ plain-old Ruby classes.
20
20
  * Correctly handles broken pipes (aka `mycmd | head`).
21
21
  * Correctly handles when stdout or stdin is redirected to a file.
22
22
  * Uses [OptionParser][optparse] for POSIX option parsing.
23
- * Supports optional ANSI coloring.
24
23
  * Supports optionally displaying a man-page instead of `--help`
25
24
  (see {CommandKit::Help::Man}).
25
+ * Supports optional ANSI coloring.
26
+ * Supports interactively prompting for user input.
27
+ * Supports easily detecting the terminal size.
28
+ * Supports paging output with `less` or `more`.
26
29
  * Supports XDG directories (`~/.config/`, `~/.local/share/`, `~/.cache/`).
27
30
  * Easy to test (ex: `MyCmd.main(arg1, arg2, options: {foo: foo}) # => 0`)
28
31
 
data/gemspec.yml CHANGED
@@ -7,7 +7,7 @@ description:
7
7
  license: MIT
8
8
  authors: Postmodern
9
9
  email: postmodern.mod3@gmail.com
10
- homepage: https://github.com/postmodern/command_kit#readme
10
+ homepage: https://github.com/postmodern/command_kit.rb#readme
11
11
 
12
12
  required_ruby_version: ">= 2.7.0"
13
13
 
data/lib/command_kit.rb CHANGED
@@ -1 +1,2 @@
1
+ require 'command_kit/command'
1
2
  require 'command_kit/version'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'command_kit/main'
2
4
  require 'command_kit/help'
3
5
  require 'command_kit/arguments/argument'
@@ -46,6 +48,9 @@ module CommandKit
46
48
  include Main
47
49
  include Help
48
50
 
51
+ #
52
+ # @api private
53
+ #
49
54
  module ModuleMethods
50
55
  #
51
56
  # Extends {ClassMethods} or {ModuleMethods}, depending on whether
@@ -77,6 +82,8 @@ module CommandKit
77
82
  # @return [Hash{Symbol => Argument}]
78
83
  # The defined argument for the class and it's superclass.
79
84
  #
85
+ # @api semipublic
86
+ #
80
87
  def arguments
81
88
  @arguments ||= if superclass.kind_of?(ClassMethods)
82
89
  superclass.arguments.dup
@@ -131,6 +138,8 @@ module CommandKit
131
138
  # argument :bar, repeats: true,
132
139
  # desc: "Bar argument"
133
140
  #
141
+ # @api public
142
+ #
134
143
  def argument(name,**kwargs)
135
144
  arguments[name] = Argument.new(name,**kwargs)
136
145
  end
@@ -147,6 +156,8 @@ module CommandKit
147
156
  # The exit status code. If too few or too many arguments are given, then
148
157
  # an error message is printed and `1` is returned.
149
158
  #
159
+ # @api public
160
+ #
150
161
  def main(argv=[])
151
162
  required_args = self.class.arguments.each_value.count(&:required?)
152
163
  optional_args = self.class.arguments.each_value.count(&:optional?)
@@ -168,6 +179,8 @@ module CommandKit
168
179
  #
169
180
  # Prints any defined arguments, along with the usual `--help` information.
170
181
  #
182
+ # @api semipublic
183
+ #
171
184
  def help_arguments
172
185
  unless (arguments = self.class.arguments).empty?
173
186
  puts
@@ -183,8 +196,10 @@ module CommandKit
183
196
  # Calls the superclass'es `#help` method, if it's defined, then calls
184
197
  # {#help_arguments}.
185
198
  #
199
+ # @api public
200
+ #
186
201
  def help
187
- super if defined?(super)
202
+ super
188
203
 
189
204
  help_arguments
190
205
  end
@@ -5,6 +5,8 @@ module CommandKit
5
5
  #
6
6
  # Represents a defined argument.
7
7
  #
8
+ # @api private
9
+ #
8
10
  class Argument < ArgumentValue
9
11
 
10
12
  # The argument's name.
@@ -3,6 +3,8 @@ module CommandKit
3
3
  #
4
4
  # Represents an individual argument value.
5
5
  #
6
+ # @api private
7
+ #
6
8
  class ArgumentValue
7
9
 
8
10
  # Specifies whether the argument value is required or optional.
@@ -88,6 +88,8 @@ module CommandKit
88
88
  #
89
89
  # @see RESET
90
90
  #
91
+ # @api public
92
+ #
91
93
  def reset
92
94
  RESET
93
95
  end
@@ -95,6 +97,8 @@ module CommandKit
95
97
  #
96
98
  # @see reset
97
99
  #
100
+ # @api public
101
+ #
98
102
  def clear
99
103
  reset
100
104
  end
@@ -110,6 +114,8 @@ module CommandKit
110
114
  #
111
115
  # @see BOLD
112
116
  #
117
+ # @api public
118
+ #
113
119
  def bold(string=nil)
114
120
  if string then "#{BOLD}#{string}#{RESET_INTENSITY}"
115
121
  else BOLD
@@ -127,6 +133,8 @@ module CommandKit
127
133
  #
128
134
  # @see BLACK
129
135
  #
136
+ # @api public
137
+ #
130
138
  def black(string=nil)
131
139
  if string then "#{BLACK}#{string}#{RESET_COLOR}"
132
140
  else BLACK
@@ -144,6 +152,8 @@ module CommandKit
144
152
  #
145
153
  # @see RED
146
154
  #
155
+ # @api public
156
+ #
147
157
  def red(string=nil)
148
158
  if string then "#{RED}#{string}#{RESET_COLOR}"
149
159
  else RED
@@ -161,6 +171,8 @@ module CommandKit
161
171
  #
162
172
  # @see GREEN
163
173
  #
174
+ # @api public
175
+ #
164
176
  def green(string=nil)
165
177
  if string then "#{GREEN}#{string}#{RESET_COLOR}"
166
178
  else GREEN
@@ -178,6 +190,8 @@ module CommandKit
178
190
  #
179
191
  # @see YELLOW
180
192
  #
193
+ # @api public
194
+ #
181
195
  def yellow(string=nil)
182
196
  if string then "#{YELLOW}#{string}#{RESET_COLOR}"
183
197
  else YELLOW
@@ -195,6 +209,8 @@ module CommandKit
195
209
  #
196
210
  # @see BLUE
197
211
  #
212
+ # @api public
213
+ #
198
214
  def blue(string=nil)
199
215
  if string then "#{BLUE}#{string}#{RESET_COLOR}"
200
216
  else BLUE
@@ -212,6 +228,8 @@ module CommandKit
212
228
  #
213
229
  # @see MAGENTA
214
230
  #
231
+ # @api public
232
+ #
215
233
  def magenta(string=nil)
216
234
  if string then "#{MAGENTA}#{string}#{RESET_COLOR}"
217
235
  else MAGENTA
@@ -229,6 +247,8 @@ module CommandKit
229
247
  #
230
248
  # @see CYAN
231
249
  #
250
+ # @api public
251
+ #
232
252
  def cyan(string=nil)
233
253
  if string then "#{CYAN}#{string}#{RESET_COLOR}"
234
254
  else CYAN
@@ -246,6 +266,8 @@ module CommandKit
246
266
  #
247
267
  # @see WHITE
248
268
  #
269
+ # @api public
270
+ #
249
271
  def white(string=nil)
250
272
  if string then "#{WHITE}#{string}#{RESET_COLOR}"
251
273
  else WHITE
@@ -331,6 +353,8 @@ module CommandKit
331
353
  # output. Color output will also be disabled if the given stream is not
332
354
  # a TTY.
333
355
  #
356
+ # @api public
357
+ #
334
358
  def ansi?(stream=stdout)
335
359
  env['TERM'] != 'dumb' && stream.tty?
336
360
  end
@@ -343,6 +367,14 @@ module CommandKit
343
367
  # @return [ANSI, PlainText]
344
368
  # The ANSI module or PlainText dummy module.
345
369
  #
370
+ # @example
371
+ # puts colors.green("Hello world")
372
+ #
373
+ # @example Using colors with stderr output:
374
+ # stderr.puts colors(stderr).green("Hello world")
375
+ #
376
+ # @api public
377
+ #
346
378
  def colors(stream=stdout)
347
379
  color = if ansi?(stream) then ANSI
348
380
  else PlainText
@@ -9,6 +9,8 @@ require 'command_kit/examples'
9
9
  require 'command_kit/description'
10
10
  require 'command_kit/exception_handler'
11
11
 
12
+ require 'fileutils'
13
+
12
14
  module CommandKit
13
15
  #
14
16
  # The command class base-class.
@@ -66,6 +68,8 @@ module CommandKit
66
68
  # @verbose = 0
67
69
  # end
68
70
  #
71
+ # @api public
72
+ #
69
73
  class Command
70
74
 
71
75
  include Main
@@ -79,6 +83,7 @@ module CommandKit
79
83
  include Examples
80
84
  include Description
81
85
  include ExceptionHandler
86
+ include FileUtils
82
87
 
83
88
  end
84
89
  end
@@ -31,6 +31,9 @@ module CommandKit
31
31
  # # => "foo-cmd"
32
32
  #
33
33
  module CommandName
34
+ #
35
+ # @api private
36
+ #
34
37
  module ModuleMethods
35
38
  #
36
39
  # Extends {ClassMethods} or {ModuleMethods}, depending on whether
@@ -65,6 +68,8 @@ module CommandKit
65
68
  #
66
69
  # @return [String]
67
70
  #
71
+ # @api public
72
+ #
68
73
  def command_name(new_command_name=nil)
69
74
  if new_command_name
70
75
  @command_name = new_command_name.to_s
@@ -77,6 +82,8 @@ module CommandKit
77
82
  # The commands name.
78
83
  #
79
84
  # @return [String]
85
+ #
86
+ # @api public
80
87
  attr_reader :command_name
81
88
 
82
89
  #
@@ -86,6 +93,8 @@ module CommandKit
86
93
  # Overrides the command name. Defaults to
87
94
  # {ClassMethods#command_name self.class.command_name}.
88
95
  #
96
+ # @api public
97
+ #
89
98
  def initialize(command_name: self.class.command_name, **kwargs)
90
99
  @command_name = command_name
91
100
 
@@ -41,6 +41,9 @@ module CommandKit
41
41
  include Stdio
42
42
  include Env
43
43
 
44
+ #
45
+ # @api private
46
+ #
44
47
  module ModuleMethods
45
48
  #
46
49
  # Extends {ClassMethods} or {ModuleMethods}, depending on whether
@@ -73,6 +76,8 @@ module CommandKit
73
76
  #
74
77
  # @return [Hash{String => Subcommand}]
75
78
  # The Hash of sub-command names and command classes.
79
+ #
80
+ # @api semipublic
76
81
  #
77
82
  def commands
78
83
  @commands ||= if superclass.kind_of?(ClassMethods)
@@ -88,6 +93,8 @@ module CommandKit
88
93
  # @return [Hash{String => String}]
89
94
  # The Hash of command aliases to primary command names.
90
95
  #
96
+ # @api semipublic
97
+ #
91
98
  def command_aliases
92
99
  @command_aliases ||= if superclass.kind_of?(ClassMethods)
93
100
  superclass.command_aliases.dup
@@ -125,6 +132,8 @@ module CommandKit
125
132
  # @example
126
133
  # command 'foo-bar', FooBar
127
134
  #
135
+ # @api public
136
+ #
128
137
  def command(name=nil, command_class, **kwargs)
129
138
  name = if name then name.to_s
130
139
  else command_class.command_name
@@ -145,8 +154,12 @@ module CommandKit
145
154
  # Gets the command.
146
155
  #
147
156
  # @param [String] name
157
+ # The command name.
148
158
  #
149
159
  # @return [Class#main, nil]
160
+ # The command class or `nil` if no command could be found.
161
+ #
162
+ # @api private
150
163
  #
151
164
  def get_command(name)
152
165
  name = name.to_s
@@ -164,6 +177,8 @@ module CommandKit
164
177
  # @note Adds a special rule to the {Options#option_parser #option_parser} to
165
178
  # stop parsing options when the first non-option is encountered.
166
179
  #
180
+ # @api public
181
+ #
167
182
  def initialize(**kwargs)
168
183
  super(**kwargs)
169
184
 
@@ -181,6 +196,8 @@ module CommandKit
181
196
  # @return [Object#main, nil]
182
197
  # The initialized subcommand.
183
198
  #
199
+ # @api private
200
+ #
184
201
  def command(name)
185
202
  unless (command_class = self.class.get_command(name))
186
203
  return
@@ -225,6 +242,8 @@ module CommandKit
225
242
  # @return [Integer]
226
243
  # The exit status of the command.
227
244
  #
245
+ # @api semipublic
246
+ #
228
247
  def invoke(name,*argv)
229
248
  if (command = command(name))
230
249
  command.main(argv)
@@ -237,6 +256,9 @@ module CommandKit
237
256
  # Prints an error about an unknown command and exits with an error code.
238
257
  #
239
258
  # @param [String] name
259
+ # The command name.
260
+ #
261
+ # @api semipublic
240
262
  #
241
263
  def command_not_found(name)
242
264
  print_error "'#{name}' is not a #{command_name} command. See `#{command_name} help`"
@@ -256,6 +278,8 @@ module CommandKit
256
278
  #
257
279
  # @see command_not_found
258
280
  #
281
+ # @api semipublic
282
+ #
259
283
  def on_unknown_command(name,argv=[])
260
284
  command_not_found(name)
261
285
  end
@@ -265,6 +289,8 @@ module CommandKit
265
289
  #
266
290
  # @note If no subcommand is given, {#help} will be called.
267
291
  #
292
+ # @api public
293
+ #
268
294
  def run(command=nil,*argv)
269
295
  if command
270
296
  exit invoke(command,*argv)
@@ -276,6 +302,8 @@ module CommandKit
276
302
  #
277
303
  # Prints the available commands and their summaries.
278
304
  #
305
+ # @api semipublic
306
+ #
279
307
  def help_commands
280
308
  unless self.class.commands.empty?
281
309
  puts
@@ -296,6 +324,8 @@ module CommandKit
296
324
  #
297
325
  # Prints help information and available commands.
298
326
  #
327
+ # @api public
328
+ #
299
329
  def help
300
330
  super
301
331
 
@@ -40,16 +40,22 @@ module CommandKit
40
40
  # The auto-load subcommands.
41
41
  #
42
42
  # @return [Hash{String => Subcommand}]
43
+ #
44
+ # @api private
43
45
  attr_reader :commands
44
46
 
45
47
  # The path to the directory containing the command files.
46
48
  #
47
49
  # @return [String]
50
+ #
51
+ # @api private
48
52
  attr_reader :dir
49
53
 
50
54
  # The namespace that the will contain the command classes.
51
55
  #
52
56
  # @return [String]
57
+ #
58
+ # @api private
53
59
  attr_reader :namespace
54
60
 
55
61
  #
@@ -65,6 +71,8 @@ module CommandKit
65
71
  # If a block is given, it will be used to explicitly map the files
66
72
  # within {#dir} as commands.
67
73
  #
74
+ # @api public
75
+ #
68
76
  def initialize(dir: , namespace: )
69
77
  @commands = {}
70
78
 
@@ -106,6 +114,8 @@ module CommandKit
106
114
  # @option kwargs [Array<String>] aliases
107
115
  # Optional alias names for the subcommand.
108
116
  #
117
+ # @api public
118
+ #
109
119
  def command(name, constant, file, **kwargs)
110
120
  @commands[name.to_s] = Subcommand.new(
111
121
  "#{@namespace}::#{constant}",
@@ -123,6 +133,8 @@ module CommandKit
123
133
  # @return [String]
124
134
  # The joined absolute path.
125
135
  #
136
+ # @api private
137
+ #
126
138
  def join(path)
127
139
  File.join(@dir,path)
128
140
  end
@@ -133,6 +145,8 @@ module CommandKit
133
145
  # @return [Array<String>]
134
146
  # The paths to the `.rb` files in the directory.
135
147
  #
148
+ # @api private
149
+ #
136
150
  def files
137
151
  Dir.glob(join('*.rb'))
138
152
  end
@@ -144,6 +158,8 @@ module CommandKit
144
158
  # @param [Class] command
145
159
  # The command class including {AutoLoad}.
146
160
  #
161
+ # @api private
162
+ #
147
163
  def included(command)
148
164
  command.include Commands
149
165
  command.commands.merge!(@commands)