command_kit 0.1.0.rc1 → 0.2.2

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 (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