command_kit 0.1.0.rc1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +17 -3
  3. data/.rubocop.yml +141 -0
  4. data/ChangeLog.md +102 -1
  5. data/Gemfile +3 -0
  6. data/README.md +187 -116
  7. data/Rakefile +3 -2
  8. data/command_kit.gemspec +4 -4
  9. data/examples/command.rb +1 -1
  10. data/gemspec.yml +8 -1
  11. data/lib/command_kit/arguments/argument.rb +2 -0
  12. data/lib/command_kit/arguments/argument_value.rb +2 -0
  13. data/lib/command_kit/arguments.rb +25 -6
  14. data/lib/command_kit/colors.rb +253 -45
  15. data/lib/command_kit/command.rb +6 -1
  16. data/lib/command_kit/command_name.rb +9 -0
  17. data/lib/command_kit/commands/auto_load.rb +24 -1
  18. data/lib/command_kit/commands/auto_require.rb +16 -0
  19. data/lib/command_kit/commands/command.rb +3 -0
  20. data/lib/command_kit/commands/help.rb +5 -2
  21. data/lib/command_kit/commands/parent_command.rb +7 -0
  22. data/lib/command_kit/commands/subcommand.rb +13 -1
  23. data/lib/command_kit/commands.rb +54 -9
  24. data/lib/command_kit/description.rb +12 -1
  25. data/lib/command_kit/env/home.rb +9 -0
  26. data/lib/command_kit/env/path.rb +16 -1
  27. data/lib/command_kit/env.rb +4 -0
  28. data/lib/command_kit/examples.rb +12 -1
  29. data/lib/command_kit/exception_handler.rb +4 -0
  30. data/lib/command_kit/help/man.rb +28 -31
  31. data/lib/command_kit/help.rb +7 -1
  32. data/lib/command_kit/inflector.rb +49 -17
  33. data/lib/command_kit/interactive.rb +71 -1
  34. data/lib/command_kit/main.rb +18 -9
  35. data/lib/command_kit/man.rb +44 -0
  36. data/lib/command_kit/open_app.rb +69 -0
  37. data/lib/command_kit/options/option.rb +3 -6
  38. data/lib/command_kit/options/option_value.rb +5 -2
  39. data/lib/command_kit/options/parser.rb +46 -19
  40. data/lib/command_kit/options/quiet.rb +3 -0
  41. data/lib/command_kit/options/verbose.rb +5 -0
  42. data/lib/command_kit/options/version.rb +6 -0
  43. data/lib/command_kit/options.rb +32 -7
  44. data/lib/command_kit/os/linux.rb +157 -0
  45. data/lib/command_kit/os.rb +165 -11
  46. data/lib/command_kit/package_manager.rb +200 -0
  47. data/lib/command_kit/pager.rb +73 -4
  48. data/lib/command_kit/printing/indent.rb +27 -4
  49. data/lib/command_kit/printing.rb +35 -1
  50. data/lib/command_kit/program_name.rb +7 -0
  51. data/lib/command_kit/stdio.rb +24 -0
  52. data/lib/command_kit/sudo.rb +40 -0
  53. data/lib/command_kit/terminal.rb +17 -0
  54. data/lib/command_kit/usage.rb +14 -0
  55. data/lib/command_kit/version.rb +1 -1
  56. data/lib/command_kit/xdg.rb +13 -0
  57. data/lib/command_kit.rb +1 -0
  58. data/spec/arguments/argument_spec.rb +2 -2
  59. data/spec/arguments_spec.rb +54 -28
  60. data/spec/colors_spec.rb +277 -13
  61. data/spec/command_name_spec.rb +1 -1
  62. data/spec/command_spec.rb +79 -5
  63. data/spec/commands/auto_load/subcommand_spec.rb +1 -1
  64. data/spec/commands/auto_load_spec.rb +34 -3
  65. data/spec/commands/auto_require_spec.rb +2 -2
  66. data/spec/commands/help_spec.rb +1 -1
  67. data/spec/commands/parent_command_spec.rb +1 -1
  68. data/spec/commands/subcommand_spec.rb +1 -1
  69. data/spec/commands_spec.rb +102 -30
  70. data/spec/description_spec.rb +1 -25
  71. data/spec/env/home_spec.rb +1 -1
  72. data/spec/env/path_spec.rb +7 -1
  73. data/spec/examples_spec.rb +1 -25
  74. data/spec/exception_handler_spec.rb +1 -1
  75. data/spec/help/man_spec.rb +55 -58
  76. data/spec/help_spec.rb +0 -25
  77. data/spec/inflector_spec.rb +71 -9
  78. data/spec/main_spec.rb +7 -7
  79. data/spec/man_spec.rb +46 -0
  80. data/spec/open_app_spec.rb +85 -0
  81. data/spec/options/option_spec.rb +5 -5
  82. data/spec/options/option_value_spec.rb +56 -1
  83. data/spec/options_spec.rb +283 -1
  84. data/spec/os/linux_spec.rb +164 -0
  85. data/spec/os_spec.rb +201 -14
  86. data/spec/package_manager_spec.rb +806 -0
  87. data/spec/pager_spec.rb +72 -7
  88. data/spec/printing/indent_spec.rb +8 -6
  89. data/spec/printing_spec.rb +33 -3
  90. data/spec/program_name_spec.rb +1 -1
  91. data/spec/spec_helper.rb +0 -3
  92. data/spec/sudo_spec.rb +51 -0
  93. data/spec/terminal_spec.rb +31 -1
  94. data/spec/usage_spec.rb +2 -2
  95. data/spec/xdg_spec.rb +1 -1
  96. metadata +21 -5
@@ -3,6 +3,7 @@
3
3
  require 'command_kit/command_name'
4
4
  require 'command_kit/help'
5
5
  require 'command_kit/stdio'
6
+ require 'command_kit/man'
6
7
 
7
8
  module CommandKit
8
9
  module Help
@@ -23,7 +24,11 @@ module CommandKit
23
24
  include CommandName
24
25
  include Help
25
26
  include Stdio
27
+ include CommandKit::Man
26
28
 
29
+ #
30
+ # @api private
31
+ #
27
32
  module ModuleMethods
28
33
  #
29
34
  # Extends {ClassMethods} or {ModuleMethods}, depending on whether
@@ -61,9 +66,11 @@ module CommandKit
61
66
  # @example
62
67
  # man_dir "#{__dir__}/../../man"
63
68
  #
69
+ # @api public
70
+ #
64
71
  def man_dir(new_man_dir=nil)
65
72
  if new_man_dir
66
- @man_dir = new_man_dir
73
+ @man_dir = File.expand_path(new_man_dir)
67
74
  else
68
75
  @man_dir || if superclass.kind_of?(ClassMethods)
69
76
  superclass.man_dir
@@ -80,6 +87,8 @@ module CommandKit
80
87
  # @return [String]
81
88
  # The class'es or superclass'es man-page file name.
82
89
  #
90
+ # @api public
91
+ #
83
92
  def man_page(new_man_page=nil)
84
93
  if new_man_page
85
94
  @man_page = new_man_page
@@ -89,27 +98,6 @@ module CommandKit
89
98
  end
90
99
  end
91
100
 
92
- #
93
- # Displays the given man page.
94
- #
95
- # @param [String] page
96
- # The man page file name.
97
- #
98
- # @param [Integer, String, nil] section
99
- # The optional section number to specify.
100
- #
101
- # @return [Boolean, nil]
102
- # Specifies whether the `man` command was successful or not.
103
- # Returns `nil` when the `man` command is not installed.
104
- #
105
- def man(page, section: nil)
106
- if section
107
- system('man',section.to_s,page.to_s)
108
- else
109
- system('man',page.to_s)
110
- end
111
- end
112
-
113
101
  #
114
102
  # Provides help information by showing one of the man pages within
115
103
  # {ClassMethods#man_dir .man_dir}.
@@ -122,11 +110,13 @@ module CommandKit
122
110
  # Returns `nil` when the `man` command is not installed.
123
111
  #
124
112
  # @raise [NotImplementedError]
125
- # {ClassMethods#man_dir .man_dir} does not have a value.
113
+ # {ClassMethods#man_dir .man_dir} was not set in the class.
114
+ #
115
+ # @api semipublic
126
116
  #
127
117
  def help_man(man_page=self.class.man_page)
128
118
  unless self.class.man_dir
129
- raise(NotImplementedError,"#{self.class}.man_dir not set")
119
+ raise(NotImplementedError,"man_dir was not set in #{self.class}")
130
120
  end
131
121
 
132
122
  man_path = File.join(self.class.man_dir,man_page)
@@ -138,20 +128,27 @@ module CommandKit
138
128
  # Displays the {ClassMethods#man_page .man_page} in
139
129
  # {ClassMethods#man_dir .man_dir} instead of the usual `--help` output.
140
130
  #
141
- # @raise [NotImplementedError]
142
- # {ClassMethods#man_dir .man_dir} does not have a value.
143
- #
144
131
  # @note
145
- # if `TERM` is `dumb` or `$stdout` is not a TTY, fallsback to printing
146
- # the usual `--help` output.
132
+ # if `TERM` is `dumb` or `$stdout` is not a TTY, will fall back to
133
+ # printing the usual `--help` output.
134
+ #
135
+ # @api public
147
136
  #
148
137
  def help
149
138
  if stdout.tty?
150
- if help_man.nil?
151
- # the `man` command is not installed
139
+ if self.class.man_dir
140
+ status = help_man
141
+
142
+ if status.nil?
143
+ # the `man` command is not installed
144
+ super
145
+ end
146
+ else
147
+ # man_dir was not set
152
148
  super
153
149
  end
154
150
  else
151
+ # stdout is not a TTY
155
152
  super
156
153
  end
157
154
  end
@@ -15,6 +15,9 @@ module CommandKit
15
15
  # MyCmd.help
16
16
  #
17
17
  module Help
18
+ #
19
+ # @api private
20
+ #
18
21
  module ModuleMethods
19
22
  #
20
23
  # Extends {ClassMethods} or {ModuleMethods}, depending on whether {Help}
@@ -48,6 +51,8 @@ module CommandKit
48
51
  #
49
52
  # @see Help#help
50
53
  #
54
+ # @api public
55
+ #
51
56
  def help(**kwargs)
52
57
  new(**kwargs).help
53
58
  end
@@ -58,8 +63,9 @@ module CommandKit
58
63
  #
59
64
  # @abstract
60
65
  #
66
+ # @api public
67
+ #
61
68
  def help
62
- super if defined?(super)
63
69
  end
64
70
  end
65
71
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'strscan'
4
+
3
5
  module CommandKit
4
6
  #
5
7
  # A very simple inflector.
@@ -8,6 +10,8 @@ module CommandKit
8
10
  # If you need something more powerful, checkout
9
11
  # [dry-inflector](https://dry-rb.org/gems/dry-inflector/0.1/)
10
12
  #
13
+ # @api semipublic
14
+ #
11
15
  module Inflector
12
16
  #
13
17
  # Removes the namespace from a constant name.
@@ -31,16 +35,37 @@ module CommandKit
31
35
  # @return [String]
32
36
  # The resulting under_scored name.
33
37
  #
38
+ # @raise [ArgumentError]
39
+ # The given string contained non-alpha-numeric characters.
40
+ #
34
41
  def self.underscore(name)
35
- # sourced from: https://github.com/dry-rb/dry-inflector/blob/c918f967ff82611da374eb0847a77b7e012d3fa8/lib/dry/inflector.rb#L286-L287
36
- name = name.to_s.dup
42
+ scanner = StringScanner.new(name.to_s)
43
+ new_string = String.new
37
44
 
38
- name.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
39
- name.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
40
- name.tr!('-','_')
41
- name.downcase!
45
+ until scanner.eos?
46
+ if (separator = scanner.scan(/[_-]+/))
47
+ new_string << ('_' * separator.length)
48
+ else
49
+ if (capitalized = scanner.scan(/[A-Z][a-z\d]+/))
50
+ new_string << capitalized
51
+ elsif (uppercase = scanner.scan(/[A-Z][A-Z\d]*(?=[A-Z_-]|$)/))
52
+ new_string << uppercase
53
+ elsif (lowercase = scanner.scan(/[a-z][a-z\d]*/))
54
+ new_string << lowercase
55
+ else
56
+ raise(ArgumentError,"cannot convert string to underscored: #{scanner.string.inspect}")
57
+ end
42
58
 
43
- name
59
+ if (separator = scanner.scan(/[_-]+/))
60
+ new_string << ('_' * separator.length)
61
+ elsif !scanner.eos?
62
+ new_string << '_'
63
+ end
64
+ end
65
+ end
66
+
67
+ new_string.downcase!
68
+ new_string
44
69
  end
45
70
 
46
71
  #
@@ -65,20 +90,27 @@ module CommandKit
65
90
  # @return [String]
66
91
  # The CamelCased name.
67
92
  #
93
+ # @raise [ArgumentError]
94
+ # The given under_scored string contained non-alpha-numeric characters.
95
+ #
68
96
  def self.camelize(name)
69
- name = name.to_s.dup
70
-
71
- # sourced from: https://github.com/dry-rb/dry-inflector/blob/c918f967ff82611da374eb0847a77b7e012d3fa8/lib/dry/inflector.rb#L329-L334
72
- name.sub!(/^[a-z\d]*/,&:capitalize)
73
- name.gsub!(%r{(?:[_-]|(/))([a-z\d]*)}i) do |match|
74
- slash = Regexp.last_match(1)
75
- word = Regexp.last_match(2)
97
+ scanner = StringScanner.new(name.to_s)
98
+ new_string = String.new
76
99
 
77
- "#{slash}#{word.capitalize}"
100
+ until scanner.eos?
101
+ if (word = scanner.scan(/[A-Za-z\d]+/))
102
+ word.capitalize!
103
+ new_string << word
104
+ elsif scanner.scan(/[_-]+/)
105
+ # skip
106
+ elsif scanner.scan(/\//)
107
+ new_string << '::'
108
+ else
109
+ raise(ArgumentError,"cannot convert string to CamelCase: #{scanner.string.inspect}")
110
+ end
78
111
  end
79
112
 
80
- name.gsub!('/','::')
81
- name
113
+ new_string
82
114
  end
83
115
  end
84
116
  end
@@ -1,6 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'command_kit/stdio'
2
4
 
3
5
  module CommandKit
6
+ #
7
+ # Provides methods for asking the user for input.
8
+ #
9
+ # ## Examples
10
+ #
11
+ # first_name = ask("First name")
12
+ # last_name = ask("Last name")
13
+ #
14
+ # ### Asking for secret input
15
+ #
16
+ # password = ask_secret("Password")
17
+ #
18
+ # ### Asking Y/N?
19
+ #
20
+ # if ask_yes_or_no("Proceed anyways?")
21
+ # # ...
22
+ # else
23
+ # stderr.puts "Aborting!"
24
+ # end
25
+ #
26
+ # ### Asking multi-choice questions
27
+ #
28
+ # ask_multiple_choice("Select a flavor", %w[Apple Orange Lemon Lime])
29
+ # # 1) Apple
30
+ # # 2) Orange
31
+ # # 3) Lemon
32
+ # # 4) Lime
33
+ # # Select a flavor: 4
34
+ # #
35
+ # # => "Lime"
36
+ #
4
37
  module Interactive
5
38
  include Stdio
6
39
 
@@ -19,6 +52,23 @@ module CommandKit
19
52
  # @return [String]
20
53
  # The user input.
21
54
  #
55
+ # @example
56
+ # first_name = ask("First name")
57
+ # last_name = ask("Last name")
58
+ #
59
+ # @example Default value:
60
+ # ask("Country", default: "EU")
61
+ # # Country [EU]: <enter>
62
+ # # => "EU"
63
+ #
64
+ # @example Required non-empty input:
65
+ # ask("Email", required: true)
66
+ # # Email: <enter>
67
+ # # Email: bob@example.com<enter>
68
+ # # => "bob@example.com"
69
+ #
70
+ # @api public
71
+ #
22
72
  def ask(prompt, default: nil, required: false)
23
73
  prompt = prompt.chomp
24
74
  prompt << " [#{default}]" if default
@@ -56,7 +106,14 @@ module CommandKit
56
106
  # @example
57
107
  # ask_yes_or_no("Proceed anyways?")
58
108
  # # Proceed anyways? (Y/N): Y
59
- # # => :yes
109
+ # # => true
110
+ #
111
+ # @example Default value:
112
+ # ask_yes_or_no("Proceed anyways?", default: true)
113
+ # # Proceed anyways? (Y/N) [Y]: <enter>
114
+ # # => true
115
+ #
116
+ # @api public
60
117
  #
61
118
  def ask_yes_or_no(prompt, default: nil, **kwargs)
62
119
  default = case default
@@ -123,6 +180,8 @@ module CommandKit
123
180
  # #
124
181
  # # => "All of the above"
125
182
  #
183
+ # @api public
184
+ #
126
185
  def ask_multiple_choice(prompt,choices,**kwargs)
127
186
  choices = case choices
128
187
  when Array
@@ -159,11 +218,22 @@ module CommandKit
159
218
  #
160
219
  # Asks the user for secret input.
161
220
  #
221
+ # @param [String] prompt
222
+ # The prompt that will be printed before reading input.
223
+ #
224
+ # @param [Boolean] required
225
+ # Requires non-empty input.
226
+ #
227
+ # @return [String]
228
+ # The user input.
229
+ #
162
230
  # @example
163
231
  # ask_secret("Password")
164
232
  # # Password:
165
233
  # # => "s3cr3t"
166
234
  #
235
+ # @api public
236
+ #
167
237
  def ask_secret(prompt, required: true)
168
238
  if stdin.respond_to?(:noecho)
169
239
  stdin.noecho do
@@ -12,6 +12,9 @@ module CommandKit
12
12
  # end
13
13
  #
14
14
  module Main
15
+ #
16
+ # @api private
17
+ #
15
18
  module ModuleMethods
16
19
  #
17
20
  # Extends {ClassMethods} or {ModuleMethods}, depending on whether {Main}
@@ -43,16 +46,16 @@ module CommandKit
43
46
  # @param [Array<String>] argv
44
47
  # The Array of command-line arguments.
45
48
  #
49
+ # @api public
50
+ #
46
51
  def start(argv=ARGV, **kwargs)
47
- begin
48
- exit main(argv, **kwargs)
49
- rescue Interrupt
50
- # https://tldp.org/LDP/abs/html/exitcodes.html
51
- exit 130
52
- rescue Errno::EPIPE
53
- # STDOUT pipe broken
54
- exit 0
55
- end
52
+ exit main(argv, **kwargs)
53
+ rescue Interrupt
54
+ # https://tldp.org/LDP/abs/html/exitcodes.html
55
+ exit 130
56
+ rescue Errno::EPIPE
57
+ # STDOUT pipe broken
58
+ exit 0
56
59
  end
57
60
 
58
61
  #
@@ -68,6 +71,8 @@ module CommandKit
68
71
  # @return [Integer]
69
72
  # The exit status of the command.
70
73
  #
74
+ # @api public
75
+ #
71
76
  def main(argv=[], **kwargs)
72
77
  new(**kwargs).main(argv)
73
78
  end
@@ -84,6 +89,8 @@ module CommandKit
84
89
  #
85
90
  # @note `argv` is splatted into {#run}.
86
91
  #
92
+ # @api public
93
+ #
87
94
  def main(argv=[])
88
95
  run(*argv)
89
96
  return 0
@@ -99,6 +106,8 @@ module CommandKit
99
106
  #
100
107
  # @abstract
101
108
  #
109
+ # @api public
110
+ #
102
111
  def run(*args)
103
112
  end
104
113
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CommandKit
4
+ #
5
+ # Allows displaying man pages.
6
+ #
7
+ # ## Examples
8
+ #
9
+ # man "passwd"
10
+ # man "passwd", section: 5
11
+ #
12
+ # @since 0.2.0
13
+ #
14
+ module Man
15
+ #
16
+ # Displays the given man page.
17
+ #
18
+ # @param [String] page
19
+ # The man page file name.
20
+ #
21
+ # @param [Integer, String, nil] section
22
+ # The optional section number to specify.
23
+ #
24
+ # @return [Boolean, nil]
25
+ # Specifies whether the `man` command was successful or not.
26
+ # Returns `nil` when the `man` command is not installed.
27
+ #
28
+ # @example
29
+ # man "passwd"
30
+ #
31
+ # @example Display a man-page from a specific section:
32
+ # man "passwd", section: 5
33
+ #
34
+ # @api public
35
+ #
36
+ def man(page, section: nil)
37
+ if section
38
+ system('man',section.to_s,page.to_s)
39
+ else
40
+ system('man',page.to_s)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,69 @@
1
+ require 'command_kit/os'
2
+ require 'command_kit/env/path'
3
+
4
+ module CommandKit
5
+ #
6
+ # Allows opening a file or a URI with the system's preferred application for
7
+ # that file type or URI scheme.
8
+ #
9
+ # ## Examples
10
+ #
11
+ # open_app_for "movie.avi"
12
+ # open_app_for "https://github.com/postmodern/command_kit.rb#readme"
13
+ #
14
+ # @since 0.2.0
15
+ #
16
+ module OpenApp
17
+ include OS
18
+ include Env::Path
19
+
20
+ #
21
+ # Initializes the command and determines which open command to use.
22
+ #
23
+ # @param [Hash{Symbol => Object}] kwargs
24
+ # Additional keyword arguments.
25
+ #
26
+ # @api public
27
+ #
28
+ def initialize(**kwargs)
29
+ super(**kwargs)
30
+
31
+ @open_command = if macos?
32
+ 'open'
33
+ elsif linux? || bsd?
34
+ if command_installed?('xdg-open')
35
+ 'xdg-open'
36
+ end
37
+ elsif windows?
38
+ if command_installed?('invoke-item')
39
+ 'invoke-item'
40
+ else
41
+ 'start'
42
+ end
43
+ end
44
+ end
45
+
46
+ #
47
+ # Opens a file or URI using the system's preferred application for that
48
+ # file type or URI scheme.
49
+ #
50
+ # @param [String, URI] file_or_uri
51
+ # The file path or URI to open.
52
+ #
53
+ # @return [Boolean, nil]
54
+ # Specifies whether the file or URI was successfully opened or not.
55
+ # If the open command could not be determined, `nil` is returned.
56
+ #
57
+ # @example Open a file:
58
+ # open_app_for "movie.avi"
59
+ #
60
+ # @example Open a URI:
61
+ # open_app_for "https://github.com/postmodern/command_kit.rb"
62
+ #
63
+ def open_app_for(file_or_uri)
64
+ if @open_command
65
+ system(@open_command,file_or_uri.to_s)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -11,6 +11,8 @@ module CommandKit
11
11
  #
12
12
  # Represents a defined option.
13
13
  #
14
+ # @api private
15
+ #
14
16
  class Option
15
17
 
16
18
  # The option's name.
@@ -33,11 +35,6 @@ module CommandKit
33
35
  # @return [OptionValue, nil]
34
36
  attr_reader :value
35
37
 
36
- # The option's description.
37
- #
38
- # @return [String]
39
- attr_reader :desc
40
-
41
38
  # The optional block that will receive the parsed option value.
42
39
  #
43
40
  # @return [Proc, nil]
@@ -126,7 +123,7 @@ module CommandKit
126
123
  end
127
124
 
128
125
  #
129
- # The separator characer between the option and option value.
126
+ # The separator character between the option and option value.
130
127
  #
131
128
  # @return ['=', ' ', nil]
132
129
  #
@@ -14,6 +14,8 @@ module CommandKit
14
14
  #
15
15
  # Represents an additional argument associated with an option flag.
16
16
  #
17
+ # @api private
18
+ #
17
19
  class OptionValue < Arguments::ArgumentValue
18
20
 
19
21
  # Maps OptionParser types to USAGE strings.
@@ -39,7 +41,7 @@ module CommandKit
39
41
 
40
42
  # The desired type of the argument value.
41
43
  #
42
- # @return [Class, Hash, Array, Regexp, nil]
44
+ # @return [Class, Hash, Array, Regexp]
43
45
  attr_reader :type
44
46
 
45
47
  # The default parsed value for the argument value.
@@ -90,10 +92,11 @@ module CommandKit
90
92
  def self.default_usage(type)
91
93
  USAGES.fetch(type) do
92
94
  case type
93
- when Class then Inflector.underscore(type.name).upcase
94
95
  when Hash then type.keys.join('|')
95
96
  when Array then type.join('|')
96
97
  when Regexp then type.source
98
+ when Class
99
+ Inflector.underscore(Inflector.demodularize(type.name)).upcase
97
100
  else
98
101
  raise(TypeError,"unsupported option type: #{type.inspect}")
99
102
  end