shellopts 2.0.2 → 2.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/shellopts/formatter.rb +3 -2
- data/lib/shellopts/program.rb +52 -63
- data/lib/shellopts/version.rb +1 -1
- data/lib/shellopts.rb +26 -4
- data/main +25 -11
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3a8b18b0a610c14ac4a85f80cd70ff5f85ca7dc868b25615a67a3ad71f737b5
|
4
|
+
data.tar.gz: 2b0442868d8ddf102a5f8ee1b3d3307ecbea17a95512f5164d4a64a9d3fa9ec7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c90ab9e0049ba64e21c2b0fd408b438df84c0265fced52b84d221bdb2b96f92e75624c00ab59526c9caa80f67e2e7d55c5bcf0cb8138b803722b424e08ea9202
|
7
|
+
data.tar.gz: 372e29956c8f3e27f8f5617215cf610403d40a307257c0c63605e94bd39fffaa8bf9cb165e82fe61497fcc8f0519c4298c1bf4480fa26735f5bf5c01e12fe8e2
|
data/lib/shellopts/formatter.rb
CHANGED
@@ -38,16 +38,17 @@ module ShellOpts
|
|
38
38
|
using Ext::Array::Wrap
|
39
39
|
|
40
40
|
def puts_usage(bol: false)
|
41
|
+
width = [Formatter.rest, Formatter::USAGE_MAX_WIDTH].min
|
41
42
|
if descrs.size == 0
|
42
43
|
print (lead = Formatter.command_prefix || "")
|
43
44
|
indent(lead.size, ' ', bol: bol && lead == "") {
|
44
|
-
puts render(:multi,
|
45
|
+
puts render(:multi, width)
|
45
46
|
}
|
46
47
|
else
|
47
48
|
lead = Formatter.command_prefix || ""
|
48
49
|
descrs.each { |descr|
|
49
50
|
print lead
|
50
|
-
puts render(:single,
|
51
|
+
puts render(:single, width, args: [descr.text])
|
51
52
|
}
|
52
53
|
end
|
53
54
|
end
|
data/lib/shellopts/program.rb
CHANGED
@@ -4,30 +4,33 @@
|
|
4
4
|
module ShellOpts
|
5
5
|
# Command represents a program or a subcommand. It is derived from
|
6
6
|
# BasicObject to have only a minimum of inherited member methods.
|
7
|
-
# Additional methods defined in Command use the '__<identifier>__' naming
|
8
|
-
# convention that doesn't collide with option or subcommand names but
|
9
|
-
# they're rarely used in application code
|
10
7
|
#
|
11
8
|
# The names of the inherited methods can't be used as options or
|
12
9
|
# command namess. They are: instance_eval, instance_exec method_missing,
|
13
10
|
# singleton_method_added, singleton_method_removed, and
|
14
|
-
# singleton_method_undefined
|
11
|
+
# singleton_method_undefined.
|
12
|
+
#
|
13
|
+
# Additional methods defined in Command use the '__<identifier>__' naming
|
14
|
+
# convention that doesn't collide with option or subcommand names but
|
15
|
+
# they're rarely used in application code
|
15
16
|
#
|
16
17
|
# Command also defines #subcommand and #subcommand! but they can be
|
17
18
|
# overshadowed by an option or command declaration. Their values can
|
18
19
|
# still be accessed using the dashed name, though
|
19
20
|
#
|
20
|
-
#
|
21
|
+
# Option and Command objects can be accessed using #[]. #key? is also defined
|
21
22
|
#
|
22
23
|
# The following methods are created dynamically for each declared option
|
23
24
|
# with an attribute name
|
24
25
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
26
|
+
# <identifier>(default = nil)
|
27
|
+
# <identifier>=(value)
|
28
|
+
# <identifier>?()
|
29
|
+
#
|
30
|
+
# The default value is used if the option or its value is missing
|
28
31
|
#
|
29
32
|
# Options without an an attribute can still be accessed using #[] or trough
|
30
|
-
# #
|
33
|
+
# #__option_values__, #__option_hash, or #__options_list__
|
31
34
|
#
|
32
35
|
# Each subcommand has a single method:
|
33
36
|
#
|
@@ -42,9 +45,9 @@ module ShellOpts
|
|
42
45
|
|
43
46
|
# These names can't be used as option or command names
|
44
47
|
RESERVED_OPTION_NAMES = %w(
|
45
|
-
is_a
|
46
|
-
|
47
|
-
|
48
|
+
is_a instance_eval instance_exec method_missing singleton_method_added
|
49
|
+
singleton_method_removed singleton_method_undefined
|
50
|
+
)
|
48
51
|
|
49
52
|
# These methods can be overridden by an option (the value is not used -
|
50
53
|
# this is just for informational purposes)
|
@@ -59,43 +62,25 @@ module ShellOpts
|
|
59
62
|
object
|
60
63
|
end
|
61
64
|
|
62
|
-
# Return command
|
65
|
+
# Return command or option object if present, otherwise nil. Returns a
|
66
|
+
# possibly empty array of option objects if the option is repeatable
|
63
67
|
#
|
64
68
|
# The key is the name or identifier of the object or any any option
|
65
69
|
# alias. Eg. :f, '-f', :file, or '--file' are all usable as option keys
|
66
70
|
# and :cmd! or 'cmd' as command keys
|
67
71
|
#
|
68
|
-
# For options, the returned value is the argument given by the user
|
69
|
-
# optionally converted to Integer or Float or nil if the option doesn't
|
70
|
-
# take arguments. If the option takes an argument and it is repeatable
|
71
|
-
# the value is an array of the arguments. Repeatable options without
|
72
|
-
# arguments have the number of occurences as the value
|
73
|
-
#
|
74
72
|
def [](key)
|
75
73
|
case object = __grammar__[key]
|
76
74
|
when ::ShellOpts::Grammar::Command
|
77
75
|
object.ident == __subcommand__!.__ident__ ? __subcommand__! : nil
|
78
76
|
when ::ShellOpts::Grammar::Option
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
# Assign a value to an existing option. This can be used to implement
|
86
|
-
# default values. #[]= doesn't currently check the type of the given
|
87
|
-
# value so take care. Note that the corresponding option(s) in
|
88
|
-
# #__option_list__ is not updated
|
89
|
-
def []=(key, value)
|
90
|
-
case object = __grammar__[key]
|
91
|
-
when ::ShellOpts::Grammar::Command
|
92
|
-
::Kernel.raise ArgumentError, "#{key.inspect} is not an option"
|
93
|
-
when ::ShellOpts::Grammar::Option
|
94
|
-
object.argument? || object.repeatable? or
|
95
|
-
::Kernel.raise ArgumentError, "#{key.inspect} is not assignable"
|
96
|
-
__options__[object.ident] = value
|
77
|
+
if object.repeatable?
|
78
|
+
__option_hash__[object.ident] || []
|
79
|
+
else
|
80
|
+
__option_hash__[object.ident]
|
81
|
+
end
|
97
82
|
else
|
98
|
-
::Kernel.raise ArgumentError, "Unknown
|
83
|
+
::Kernel.raise ::ArgumentError, "Unknown command or option: '#{key}'"
|
99
84
|
end
|
100
85
|
end
|
101
86
|
|
@@ -103,11 +88,11 @@ module ShellOpts
|
|
103
88
|
def key?(key)
|
104
89
|
case object = __grammar__[key]
|
105
90
|
when ::ShellOpts::Grammar::Command
|
106
|
-
object.ident == __subcommand__
|
91
|
+
object.ident == __subcommand__
|
107
92
|
when ::ShellOpts::Grammar::Option
|
108
|
-
|
93
|
+
__option_hash__.key?(object.ident)
|
109
94
|
else
|
110
|
-
|
95
|
+
::Kernel.raise ::ArgumentError, "Unknown command or option: '#{key}'"
|
111
96
|
end
|
112
97
|
end
|
113
98
|
|
@@ -153,13 +138,17 @@ module ShellOpts
|
|
153
138
|
# depending on the option's type. Repeated options options without
|
154
139
|
# arguments have the number of occurences as the value, with arguments
|
155
140
|
# the value is an array of the given values
|
156
|
-
attr_reader :
|
141
|
+
attr_reader :__option_values__
|
157
142
|
|
158
143
|
# List of Option objects for the subcommand in the same order as
|
159
144
|
# given by the user but note that options are reordered to come after
|
160
145
|
# their associated subcommand if float is true. Repeated options are not
|
161
146
|
# collapsed
|
162
147
|
attr_reader :__option_list__
|
148
|
+
|
149
|
+
# Map from identifier to option object or to a list of option objects if
|
150
|
+
# the option is repeatable
|
151
|
+
attr_reader :__option_hash__
|
163
152
|
|
164
153
|
# The subcommand identifier (a Symbol incl. the exclamation mark) or nil
|
165
154
|
# if not present. Use #subcommand!, or the dynamically generated
|
@@ -172,9 +161,10 @@ module ShellOpts
|
|
172
161
|
private
|
173
162
|
def __initialize__(grammar)
|
174
163
|
@__grammar__ = grammar
|
175
|
-
@
|
164
|
+
@__option_values__ = {}
|
176
165
|
@__option_list__ = []
|
177
|
-
@
|
166
|
+
@__option_hash__ = {}
|
167
|
+
@__option_values__ = {}
|
178
168
|
@__subcommand__ = nil
|
179
169
|
|
180
170
|
__define_option_methods__
|
@@ -182,36 +172,34 @@ module ShellOpts
|
|
182
172
|
|
183
173
|
def __define_option_methods__
|
184
174
|
@__grammar__.options.each { |opt|
|
185
|
-
next if opt.attr.nil?
|
186
175
|
if opt.argument? || opt.repeatable?
|
187
176
|
if opt.optional?
|
188
177
|
self.instance_eval %(
|
189
178
|
def #{opt.attr}(default = nil)
|
190
|
-
if @
|
191
|
-
@
|
179
|
+
if @__option_values__.key?(:#{opt.attr})
|
180
|
+
@__option_values__[:#{opt.attr}]
|
192
181
|
else
|
193
|
-
|
182
|
+
default
|
194
183
|
end
|
195
184
|
end
|
196
185
|
)
|
197
|
-
elsif !opt.argument?
|
186
|
+
elsif !opt.argument? # Repeatable w/o argument
|
198
187
|
self.instance_eval %(
|
199
|
-
def #{opt.attr}(default =
|
200
|
-
if @
|
201
|
-
|
202
|
-
value == 0 ? default : value
|
188
|
+
def #{opt.attr}(default = [])
|
189
|
+
if @__option_values__.key?(:#{opt.attr})
|
190
|
+
@__option_values__[:#{opt.attr}]
|
203
191
|
else
|
204
|
-
|
192
|
+
default
|
205
193
|
end
|
206
194
|
end
|
207
195
|
)
|
208
196
|
else
|
209
|
-
self.instance_eval("def #{opt.attr}() @
|
197
|
+
self.instance_eval("def #{opt.attr}() @__option_values__[:#{opt.attr}] end")
|
210
198
|
end
|
211
|
-
self.instance_eval("def #{opt.attr}=(value) @
|
212
|
-
@
|
199
|
+
self.instance_eval("def #{opt.attr}=(value) @__option_values__[:#{opt.attr}] = value end")
|
200
|
+
@__option_values__[opt.attr] = 0 if !opt.argument?
|
213
201
|
end
|
214
|
-
self.instance_eval("def #{opt.attr}?() @
|
202
|
+
self.instance_eval("def #{opt.attr}?() @__option_values__.key?(:#{opt.attr}) end")
|
215
203
|
}
|
216
204
|
|
217
205
|
@__grammar__.commands.each { |cmd|
|
@@ -228,14 +216,15 @@ module ShellOpts
|
|
228
216
|
ident = option.grammar.ident
|
229
217
|
@__option_list__ << option
|
230
218
|
if option.repeatable?
|
219
|
+
(@__option_hash__[ident] ||= []) << option
|
231
220
|
if option.argument?
|
232
|
-
(@
|
221
|
+
(@__option_values__[ident] ||= []) << option.argument
|
233
222
|
else
|
234
|
-
@
|
235
|
-
@__options__[ident] += 1
|
223
|
+
@__option_values__[ident] = (@__option_values__[ident] || 0) + 1
|
236
224
|
end
|
237
225
|
else
|
238
|
-
@
|
226
|
+
@__option_hash__[ident] = option
|
227
|
+
@__option_values__[ident] = option.argument
|
239
228
|
end
|
240
229
|
end
|
241
230
|
|
@@ -254,7 +243,7 @@ module ShellOpts
|
|
254
243
|
|
255
244
|
# Option models an option as given by the user on the subcommand line.
|
256
245
|
# Compiled options (and possibly aggregated) options are stored in the
|
257
|
-
# Command#
|
246
|
+
# Command#__option_values__ array
|
258
247
|
class Option
|
259
248
|
# Associated Grammar::Option object
|
260
249
|
attr_reader :grammar
|
data/lib/shellopts/version.rb
CHANGED
data/lib/shellopts.rb
CHANGED
@@ -102,6 +102,9 @@ module ShellOpts
|
|
102
102
|
attr_accessor :stdopts
|
103
103
|
attr_accessor :msgopts
|
104
104
|
|
105
|
+
# Version of client program. This is only used if +stdopts+ is true
|
106
|
+
attr_reader :version
|
107
|
+
|
105
108
|
# Interpreter flags
|
106
109
|
attr_accessor :float
|
107
110
|
|
@@ -116,14 +119,17 @@ module ShellOpts
|
|
116
119
|
attr_reader :tokens
|
117
120
|
alias_method :ast, :grammar # Oops - defined earlier FIXME
|
118
121
|
|
119
|
-
def initialize(name: nil, stdopts: true, msgopts: false, float: true, exception: false)
|
122
|
+
def initialize(name: nil, stdopts: true, version: nil, msgopts: false, float: true, exception: false)
|
120
123
|
@name = name || File.basename($PROGRAM_NAME)
|
121
|
-
@stdopts, @msgopts, @float, @exception = stdopts, msgopts, float, exception
|
124
|
+
@stdopts, @version, @msgopts, @float, @exception = stdopts, version, msgopts, float, exception
|
122
125
|
end
|
123
126
|
|
124
127
|
# Compile source and return grammar object. Also sets #spec and #grammar.
|
125
128
|
# Returns the grammar
|
126
129
|
def compile(spec)
|
130
|
+
if stdopts
|
131
|
+
spec += "\n--version\n Write version number and exit\n-h,help @ Write help text and exit\n Write help text. -h prints a brief text, --help prints a longer man-style description of the command"
|
132
|
+
end
|
127
133
|
handle_exceptions {
|
128
134
|
@oneline = spec.index("\n").nil?
|
129
135
|
@spec = spec.sub(/^\s*\n/, "")
|
@@ -143,6 +149,20 @@ module ShellOpts
|
|
143
149
|
handle_exceptions {
|
144
150
|
@argv = argv.dup
|
145
151
|
@program, @args = Interpreter.interpret(grammar, argv, float: float, exception: exception)
|
152
|
+
if stdopts
|
153
|
+
if @program.version?
|
154
|
+
version or raise ArgumentError, "Version not specified"
|
155
|
+
puts version
|
156
|
+
exit
|
157
|
+
elsif @program.help?
|
158
|
+
if @program[:help].name == "-h"
|
159
|
+
ShellOpts.brief
|
160
|
+
else
|
161
|
+
ShellOpts.help
|
162
|
+
end
|
163
|
+
exit
|
164
|
+
end
|
165
|
+
end
|
146
166
|
}
|
147
167
|
self
|
148
168
|
end
|
@@ -201,11 +221,12 @@ module ShellOpts
|
|
201
221
|
def brief() Formatter.brief(@grammar) end
|
202
222
|
|
203
223
|
# Print help for the given subject or the full documentation if +subject+
|
204
|
-
# is nil
|
224
|
+
# is nil. Clears the screen beforehand if :clear is true
|
205
225
|
#
|
206
|
-
def help(subject = nil)
|
226
|
+
def help(subject = nil, clear: true)
|
207
227
|
node = (subject ? @grammar[subject] : @grammar) or
|
208
228
|
raise ArgumentError, "No such command: '#{subject&.sub(".", " ")}'"
|
229
|
+
print '[H[2J' if clear
|
209
230
|
Formatter.help(node)
|
210
231
|
end
|
211
232
|
|
@@ -310,6 +331,7 @@ module ShellOpts
|
|
310
331
|
def self.instance?() !@instance.nil? end
|
311
332
|
def self.instance() @instance or raise Error, "ShellOpts is not initialized" end
|
312
333
|
def self.instance=(instance) @instance = instance end
|
334
|
+
def self.shellopts() instance end
|
313
335
|
|
314
336
|
forward_self_to :instance, :error, :failure
|
315
337
|
|
data/main
CHANGED
@@ -7,18 +7,31 @@ require 'shellopts'
|
|
7
7
|
|
8
8
|
include ShellOpts
|
9
9
|
|
10
|
+
VERSION = "1.2.3"
|
10
11
|
|
11
|
-
SPEC =
|
12
|
-
|
13
|
-
|
12
|
+
SPEC = "-a"
|
13
|
+
opts, args = ShellOpts::process(SPEC, ARGV, version: VERSION)
|
14
|
+
#ShellOpts::ShellOpts.help
|
14
15
|
|
15
|
-
-b,beta=ARG
|
16
|
-
@ Alternative style of brief comment
|
17
16
|
|
18
|
-
Longer and more elaborate description of the --beta option
|
19
|
-
)
|
20
17
|
|
21
|
-
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
__END__
|
22
|
+
|
23
|
+
|
24
|
+
#SPEC = %(
|
25
|
+
# -a,alpha @ Brief comment for -a and --alpha options
|
26
|
+
# Longer and more elaborate description of the --alpha option
|
27
|
+
#
|
28
|
+
# -b,beta=ARG
|
29
|
+
# @ Alternative style of brief comment
|
30
|
+
#
|
31
|
+
# Longer and more elaborate description of the --beta option
|
32
|
+
#)
|
33
|
+
#
|
34
|
+
#opts, args = ShellOpts.process(SPEC, ARGV)
|
22
35
|
#puts "opts.alpha?: #{opts.alpha?.inspect}"
|
23
36
|
#puts "opts.alpha: #{opts.alpha.inspect}"
|
24
37
|
#puts "opts.beta?: #{opts.beta?.inspect}"
|
@@ -266,8 +279,9 @@ SPEC4 = %(
|
|
266
279
|
|
267
280
|
SPEC5 = "cmd! cmd!"
|
268
281
|
|
269
|
-
shellopts = ShellOpts::ShellOpts.new(exception:
|
282
|
+
shellopts = ShellOpts::ShellOpts.new(exception: true)
|
270
283
|
#shellopts.compile("cmd! cmd!")
|
284
|
+
|
271
285
|
shellopts.compile(SPEC)
|
272
286
|
#shellopts.compile(SPEC2)
|
273
287
|
#shellopts.compile(SPEC3)
|
@@ -277,9 +291,9 @@ shellopts.compile(SPEC)
|
|
277
291
|
#shellopts.tokens.each(&:dump)
|
278
292
|
#exit
|
279
293
|
|
280
|
-
shellopts.usage
|
294
|
+
#shellopts.usage
|
281
295
|
#shellopts.brief
|
282
|
-
|
296
|
+
shellopts.help
|
283
297
|
#shellopts.help("cmd")
|
284
298
|
#shellopts.help(ARGV.first)
|
285
299
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shellopts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: forward_to
|
@@ -187,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
187
187
|
- !ruby/object:Gem::Version
|
188
188
|
version: '0'
|
189
189
|
requirements: []
|
190
|
-
rubygems_version: 3.
|
190
|
+
rubygems_version: 3.1.4
|
191
191
|
signing_key:
|
192
192
|
specification_version: 4
|
193
193
|
summary: Parse command line options and arguments
|