command_kit 0.1.0.rc1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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)