command_kit 0.1.0.pre1 → 0.1.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|