command_kit 0.1.0.pre1 → 0.1.0.pre2
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.
- checksums.yaml +4 -4
- data/README.md +37 -140
- data/examples/colors.rb +30 -0
- data/examples/command.rb +65 -0
- data/examples/pager.rb +30 -0
- data/lib/command_kit/arguments.rb +49 -18
- data/lib/command_kit/arguments/argument.rb +14 -44
- data/lib/command_kit/arguments/argument_value.rb +1 -30
- data/lib/command_kit/command.rb +45 -3
- data/lib/command_kit/commands.rb +6 -0
- data/lib/command_kit/commands/auto_load/subcommand.rb +3 -0
- data/lib/command_kit/commands/subcommand.rb +3 -0
- data/lib/command_kit/description.rb +3 -1
- data/lib/command_kit/examples.rb +3 -1
- data/lib/command_kit/help.rb +3 -0
- data/lib/command_kit/help/man.rb +74 -39
- data/lib/command_kit/main.rb +2 -0
- data/lib/command_kit/options.rb +46 -9
- data/lib/command_kit/options/option.rb +35 -5
- data/lib/command_kit/options/option_value.rb +40 -3
- data/lib/command_kit/pager.rb +6 -0
- data/lib/command_kit/version.rb +1 -1
- data/lib/command_kit/xdg.rb +8 -1
- data/spec/arguments/argument_spec.rb +3 -39
- data/spec/arguments/argument_value_spec.rb +1 -61
- data/spec/arguments_spec.rb +7 -0
- data/spec/help/man_spec.rb +348 -0
- data/spec/options/option_spec.rb +45 -6
- data/spec/options/option_value_spec.rb +52 -3
- data/spec/pager_spec.rb +2 -4
- metadata +10 -8
- data/lib/command_kit/arguments/usage.rb +0 -6
- data/lib/command_kit/options/usage.rb +0 -6
@@ -7,82 +7,52 @@ module CommandKit
|
|
7
7
|
#
|
8
8
|
class Argument < ArgumentValue
|
9
9
|
|
10
|
+
# The argument's name.
|
11
|
+
#
|
10
12
|
# @return [Symbol]
|
11
13
|
attr_reader :name
|
12
14
|
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
# @return [String, nil]
|
15
|
+
# The argument's description.
|
16
|
+
#
|
17
|
+
# @return [String]
|
17
18
|
attr_reader :desc
|
18
19
|
|
19
|
-
# @return [Regexp, nil]
|
20
|
-
attr_reader :pattern
|
21
|
-
|
22
|
-
# @return [Proc, nil]
|
23
|
-
attr_reader :parser
|
24
|
-
|
25
|
-
# @return [Proc, nil]
|
26
|
-
attr_reader :block
|
27
|
-
|
28
20
|
#
|
29
21
|
# Initializes the argument.
|
30
22
|
#
|
31
23
|
# @param [Symbol] name
|
32
|
-
#
|
33
|
-
# @param [Class, Hash, Array, Regexp] type
|
24
|
+
# The name of the argument.
|
34
25
|
#
|
35
26
|
# @param [String, nil] usage
|
36
|
-
#
|
37
|
-
# @param [Object, Proc, nil] default
|
27
|
+
# The usage string for the argument. Defaults to the argument's name.
|
38
28
|
#
|
39
29
|
# @param [Boolean] required
|
30
|
+
# Specifies whether the argument is required or optional.
|
40
31
|
#
|
41
32
|
# @param [Boolean] repeats
|
33
|
+
# Specifies whether the argument can be repeated multiple times.
|
42
34
|
#
|
43
35
|
# @param [String] desc
|
44
|
-
#
|
45
|
-
# @note `usage` will be assigned a default value based on `type` and
|
46
|
-
# `name`.
|
36
|
+
# The description for the argument.
|
47
37
|
#
|
48
38
|
# @yield [(value)]
|
39
|
+
# If a block is given, it will be used to parse the argument's value.
|
40
|
+
# Note: not currently used.
|
49
41
|
#
|
50
42
|
# @yieldparam [Object, nil] value
|
51
43
|
#
|
52
|
-
def initialize(name,
|
53
|
-
usage: name.to_s.upcase,
|
54
|
-
default: nil,
|
44
|
+
def initialize(name, usage: name.to_s.upcase,
|
55
45
|
required: true,
|
56
46
|
repeats: false,
|
57
|
-
desc:
|
58
|
-
&block)
|
47
|
+
desc: )
|
59
48
|
super(
|
60
|
-
type: type,
|
61
49
|
usage: usage,
|
62
|
-
default: default,
|
63
50
|
required: required
|
64
51
|
)
|
65
52
|
|
66
53
|
@name = name
|
67
54
|
@repeats = repeats
|
68
55
|
@desc = desc
|
69
|
-
|
70
|
-
@pattern, @parser = self.class.parser(@type)
|
71
|
-
|
72
|
-
@block = block
|
73
|
-
end
|
74
|
-
|
75
|
-
#
|
76
|
-
# Looks up the option parser for the given `OptionParser` type.
|
77
|
-
#
|
78
|
-
# @param [Class] type
|
79
|
-
# The `OptionParser` type class.
|
80
|
-
#
|
81
|
-
# @return [(Regexp, Proc), nil]
|
82
|
-
# The matching pattern and converter proc.
|
83
|
-
#
|
84
|
-
def self.parser(type)
|
85
|
-
OptionParser::DefaultList.search(:atype,type)
|
86
56
|
end
|
87
57
|
|
88
58
|
#
|
@@ -5,16 +5,6 @@ module CommandKit
|
|
5
5
|
#
|
6
6
|
class ArgumentValue
|
7
7
|
|
8
|
-
# The desired type of the argument value.
|
9
|
-
#
|
10
|
-
# @return [Class, Hash, Array, Regexp, nil]
|
11
|
-
attr_reader :type
|
12
|
-
|
13
|
-
# The default parsed value for the argument value.
|
14
|
-
#
|
15
|
-
# @return [Object, Proc, nil]
|
16
|
-
attr_reader :default
|
17
|
-
|
18
8
|
# Specifies whether the argument value is required or optional.
|
19
9
|
#
|
20
10
|
# @return [Boolean]
|
@@ -28,22 +18,14 @@ module CommandKit
|
|
28
18
|
#
|
29
19
|
# Initializes the argument value.
|
30
20
|
#
|
31
|
-
# @param [Class, Hash, Array, Regexp] type
|
32
|
-
# The type of the argument value.
|
33
|
-
#
|
34
21
|
# @param [Boolean] required
|
35
22
|
# Specifies whether the argument value is required or optional.
|
36
23
|
#
|
37
24
|
# @param [String] usage
|
38
25
|
# The usage string to represent the argument value.
|
39
26
|
#
|
40
|
-
|
41
|
-
# The default parsed value for the argument value.
|
42
|
-
#
|
43
|
-
def initialize(type: nil, required: true, default: nil, usage: )
|
44
|
-
@type = type
|
27
|
+
def initialize(required: true, usage: )
|
45
28
|
@required = required
|
46
|
-
@default = default
|
47
29
|
@usage = usage
|
48
30
|
end
|
49
31
|
|
@@ -65,17 +47,6 @@ module CommandKit
|
|
65
47
|
!@required
|
66
48
|
end
|
67
49
|
|
68
|
-
#
|
69
|
-
# Returns a new default value.
|
70
|
-
#
|
71
|
-
# @return [Object]
|
72
|
-
#
|
73
|
-
def default_value
|
74
|
-
if @default.respond_to?(:call) then @default.call
|
75
|
-
else @default.dup
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
50
|
end
|
80
51
|
end
|
81
52
|
end
|
data/lib/command_kit/command.rb
CHANGED
@@ -13,16 +13,58 @@ module CommandKit
|
|
13
13
|
#
|
14
14
|
# The command class base-class.
|
15
15
|
#
|
16
|
+
# @note
|
17
|
+
# Command classes are not required to inherit from {Command}. If you do not
|
18
|
+
# wish to inherit from the {Command} base class, you can instead include
|
19
|
+
# the individual modules. This class only exists as a convenience.
|
20
|
+
#
|
16
21
|
# ## Examples
|
17
22
|
#
|
18
23
|
# class MyCmd < CommandKit::Command
|
19
24
|
#
|
20
|
-
#
|
25
|
+
# usage '[OPTIONS] [-o OUTPUT] FILE'
|
26
|
+
#
|
27
|
+
# option :count, short: '-c',
|
28
|
+
# value: {
|
29
|
+
# type: Integer,
|
30
|
+
# default: 1
|
31
|
+
# },
|
32
|
+
# desc: "Number of times"
|
33
|
+
#
|
34
|
+
# option :output, short: '-o',
|
35
|
+
# value: {
|
36
|
+
# type: String,
|
37
|
+
# usage: 'FILE'
|
38
|
+
# },
|
39
|
+
# desc: "Optional output file"
|
40
|
+
#
|
41
|
+
# argument :file, required: true,
|
42
|
+
# usage: 'FILE',
|
43
|
+
# desc: "Input file"
|
44
|
+
#
|
45
|
+
# examples [
|
46
|
+
# '-o path/to/output.txt path/to/input.txt',
|
47
|
+
# '-v -c 2 -o path/to/output.txt path/to/input.txt',
|
48
|
+
# ]
|
21
49
|
#
|
50
|
+
# description 'Example command'
|
51
|
+
#
|
52
|
+
# def run(*files)
|
53
|
+
# # ...
|
54
|
+
# end
|
22
55
|
# end
|
23
56
|
#
|
24
|
-
#
|
25
|
-
#
|
57
|
+
# ### initialize and using ivars
|
58
|
+
#
|
59
|
+
# option :verbose, short: '-v', desc: "Increase verbose level" do
|
60
|
+
# @verbose += 1
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# def initialize(**kwargs)
|
64
|
+
# super(**kwargs)
|
65
|
+
#
|
66
|
+
# @verbose = 0
|
67
|
+
# end
|
26
68
|
#
|
27
69
|
class Command
|
28
70
|
|
data/lib/command_kit/commands.rb
CHANGED
@@ -158,6 +158,12 @@ module CommandKit
|
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
161
|
+
#
|
162
|
+
# Initializes the command.
|
163
|
+
#
|
164
|
+
# @note Adds a special rule to the {Options#option_parser #option_parser} to
|
165
|
+
# stop parsing options when the first non-option is encountered.
|
166
|
+
#
|
161
167
|
def initialize(**kwargs)
|
162
168
|
super(**kwargs)
|
163
169
|
|
@@ -3,6 +3,9 @@ require 'command_kit/commands/subcommand'
|
|
3
3
|
module CommandKit
|
4
4
|
module Commands
|
5
5
|
class AutoLoad < Module
|
6
|
+
#
|
7
|
+
# Represents a registered subcommand that will be auto-loaded.
|
8
|
+
#
|
6
9
|
class Subcommand < Commands::Subcommand
|
7
10
|
|
8
11
|
# The fully qualified constant of the command class.
|
@@ -54,7 +54,9 @@ module CommandKit
|
|
54
54
|
if new_description
|
55
55
|
@description = new_description
|
56
56
|
else
|
57
|
-
@description ||
|
57
|
+
@description || if superclass.kind_of?(ClassMethods)
|
58
|
+
superclass.description
|
59
|
+
end
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|
data/lib/command_kit/examples.rb
CHANGED
@@ -61,7 +61,9 @@ module CommandKit
|
|
61
61
|
if new_examples
|
62
62
|
@examples = Array(new_examples)
|
63
63
|
else
|
64
|
-
@examples ||
|
64
|
+
@examples || if superclass.kind_of?(ClassMethods)
|
65
|
+
superclass.examples
|
66
|
+
end
|
65
67
|
end
|
66
68
|
end
|
67
69
|
end
|
data/lib/command_kit/help.rb
CHANGED
data/lib/command_kit/help/man.rb
CHANGED
@@ -1,16 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'command_kit/command_name'
|
4
|
+
require 'command_kit/help'
|
5
|
+
require 'command_kit/stdio'
|
6
|
+
|
3
7
|
module CommandKit
|
4
8
|
module Help
|
5
9
|
#
|
6
10
|
# Allows displaying a man-page instead of the usual `--help` output.
|
7
11
|
#
|
8
|
-
# ##
|
12
|
+
# ## Examples
|
13
|
+
#
|
14
|
+
# class Foo < CommandKit::Command
|
15
|
+
#
|
16
|
+
# include CommandKit::Help::Man
|
9
17
|
#
|
10
|
-
#
|
11
|
-
#
|
18
|
+
# man_dir "#{__dir__}/../../man"
|
19
|
+
#
|
20
|
+
# end
|
12
21
|
#
|
13
22
|
module Man
|
23
|
+
include CommandName
|
24
|
+
include Help
|
25
|
+
include Stdio
|
26
|
+
|
14
27
|
module ModuleMethods
|
15
28
|
#
|
16
29
|
# Extends {ClassMethods} or {ModuleMethods}, depending on whether
|
@@ -33,7 +46,7 @@ module CommandKit
|
|
33
46
|
extend ModuleMethods
|
34
47
|
|
35
48
|
#
|
36
|
-
#
|
49
|
+
# Class-level methods.
|
37
50
|
#
|
38
51
|
module ClassMethods
|
39
52
|
#
|
@@ -46,74 +59,96 @@ module CommandKit
|
|
46
59
|
# The class'es or superclass'es man-page directory.
|
47
60
|
#
|
48
61
|
# @example
|
49
|
-
# man_dir
|
62
|
+
# man_dir "#{__dir__}/../../man"
|
50
63
|
#
|
51
64
|
def man_dir(new_man_dir=nil)
|
52
65
|
if new_man_dir
|
53
|
-
@man_dir =
|
66
|
+
@man_dir = new_man_dir
|
54
67
|
else
|
55
|
-
@man_dir ||
|
68
|
+
@man_dir || if superclass.kind_of?(ClassMethods)
|
69
|
+
superclass.man_dir
|
70
|
+
end
|
56
71
|
end
|
57
72
|
end
|
58
|
-
end
|
59
73
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
74
|
+
#
|
75
|
+
# Gets or sets the class'es man-page file name.
|
76
|
+
#
|
77
|
+
# @param [String, nil] new_man_page
|
78
|
+
# If a String is given, the class'es man-page file name will be set.
|
79
|
+
#
|
80
|
+
# @return [String]
|
81
|
+
# The class'es or superclass'es man-page file name.
|
82
|
+
#
|
83
|
+
def man_page(new_man_page=nil)
|
84
|
+
if new_man_page
|
85
|
+
@man_page = new_man_page
|
86
|
+
else
|
87
|
+
@man_page || "#{command_name}.1"
|
88
|
+
end
|
89
|
+
end
|
69
90
|
end
|
70
91
|
|
71
92
|
#
|
72
|
-
#
|
93
|
+
# Displays the given man page.
|
94
|
+
#
|
95
|
+
# @param [String] page
|
96
|
+
# The man page file name.
|
73
97
|
#
|
74
|
-
# @param [String]
|
75
|
-
# The
|
98
|
+
# @param [Integer, String, nil] section
|
99
|
+
# The optional section number to specify.
|
76
100
|
#
|
77
|
-
# @return [
|
78
|
-
#
|
101
|
+
# @return [Boolean, nil]
|
102
|
+
# Specifies whether the `man` command was successful or not.
|
103
|
+
# Returns `nil` when the `man` command is not installed.
|
79
104
|
#
|
80
|
-
def
|
81
|
-
|
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
|
82
111
|
end
|
83
112
|
|
84
113
|
#
|
85
|
-
#
|
114
|
+
# Provides help information by showing one of the man pages within
|
115
|
+
# {ClassMethods#man_dir .man_dir}.
|
86
116
|
#
|
87
|
-
# @param [String]
|
88
|
-
# The man page
|
117
|
+
# @param [String] man_page
|
118
|
+
# The file name of the man page to display.
|
89
119
|
#
|
90
120
|
# @return [Boolean, nil]
|
91
121
|
# Specifies whether the `man` command was successful or not.
|
92
122
|
# Returns `nil` when the `man` command is not installed.
|
93
123
|
#
|
94
|
-
|
95
|
-
|
124
|
+
# @raise [NotImplementedError]
|
125
|
+
# {ClassMethods#man_dir .man_dir} does not have a value.
|
126
|
+
#
|
127
|
+
def help_man(man_page=self.class.man_page)
|
128
|
+
unless self.class.man_dir
|
129
|
+
raise(NotImplementedError,"#{self.class}.man_dir not set")
|
130
|
+
end
|
131
|
+
|
132
|
+
man_path = File.join(self.class.man_dir,man_page)
|
133
|
+
|
134
|
+
man(man_path)
|
96
135
|
end
|
97
136
|
|
98
137
|
#
|
99
|
-
# Displays the {#man_page}
|
138
|
+
# Displays the {ClassMethods#man_page .man_page} in
|
139
|
+
# {ClassMethods#man_dir .man_dir} instead of the usual `--help` output.
|
100
140
|
#
|
101
141
|
# @raise [NotImplementedError]
|
102
|
-
# {ClassMethods#man_dir man_dir} does not have a value.
|
142
|
+
# {ClassMethods#man_dir .man_dir} does not have a value.
|
103
143
|
#
|
104
144
|
# @note
|
105
145
|
# if `TERM` is `dumb` or `$stdout` is not a TTY, fallsback to printing
|
106
146
|
# the usual `--help` output.
|
107
147
|
#
|
108
148
|
def help
|
109
|
-
if
|
110
|
-
|
111
|
-
|
112
|
-
end
|
113
|
-
|
114
|
-
man_path = File.join(self.class.man_dir,man_page)
|
115
|
-
|
116
|
-
if man(man_path).nil?
|
149
|
+
if stdout.tty?
|
150
|
+
if help_man.nil?
|
151
|
+
# the `man` command is not installed
|
117
152
|
super
|
118
153
|
end
|
119
154
|
else
|