shellopts 2.0.2 → 2.0.5
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/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
|