pyer-options 2.0.1
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 +7 -0
- data/lib/pyer/options.rb +385 -0
- metadata +73 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1156ad00624c00bc48c7c0cac0d09095f64a13fc
|
4
|
+
data.tar.gz: 6b1a39e51bbad51ac75ea03d49e5bfd514fea61a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ade9e22ff0a6967a66b32e1b48a4a636fd20a96748537bfdfcb56799643c883976995c6308fc51526c20a4965c2e0bf4d4cd1a4dfd4ba57647daac1e7b0697ba
|
7
|
+
data.tar.gz: 985d1edffaf989e8c25033d8fe3a107acc78f440eff8c006659ac3a23b73b64c6045f18c9dba0d11fcb3fcdebdb3752a410484645500e7ea82d5594c6cd03920
|
data/lib/pyer/options.rb
ADDED
@@ -0,0 +1,385 @@
|
|
1
|
+
module Pyer
|
2
|
+
class Options
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
# Raised when the command starts whith '-', or is not given
|
6
|
+
class InvalidCommandError < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
# Raised when the command is not defined
|
10
|
+
class UnknownCommandError < StandardError
|
11
|
+
end
|
12
|
+
|
13
|
+
# Raised when an invalid option is found.
|
14
|
+
class InvalidOptionError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
# Raised when an unknown option is found.
|
18
|
+
class UnknownOptionError < StandardError
|
19
|
+
end
|
20
|
+
|
21
|
+
# Raised when an option argument is expected but none are given.
|
22
|
+
class MissingArgumentError < StandardError
|
23
|
+
end
|
24
|
+
|
25
|
+
# Raised when an option argument starts whith '-'
|
26
|
+
class InvalidArgumentError < StandardError
|
27
|
+
end
|
28
|
+
|
29
|
+
# items - The Array of items to extract options from (default: ARGV).
|
30
|
+
# block - An optional block used to add options.
|
31
|
+
#
|
32
|
+
# Examples:
|
33
|
+
#
|
34
|
+
# Options.parse(ARGV) do
|
35
|
+
# value 'name', 'Your username'
|
36
|
+
# flag 'verbose', 'Enable verbose mode'
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# short option is the first letter of long option
|
40
|
+
# Returns a new instance of Options.
|
41
|
+
def self.parse(items = ARGV, &block)
|
42
|
+
new( &block ).parse items
|
43
|
+
end
|
44
|
+
|
45
|
+
# The Array of Options::Command objects tied to this Options instance.
|
46
|
+
attr_reader :commands
|
47
|
+
|
48
|
+
# The Array of Options::Option objects tied to this Options instance.
|
49
|
+
attr_reader :options
|
50
|
+
|
51
|
+
# Create a new instance of Options and optionally build options via a block.
|
52
|
+
#
|
53
|
+
# block - An optional block used to specify options.
|
54
|
+
def initialize(&block)
|
55
|
+
@banner = ""
|
56
|
+
@runner = nil
|
57
|
+
@commands = []
|
58
|
+
@command_name = nil
|
59
|
+
@command_callback = nil
|
60
|
+
@options = []
|
61
|
+
@triggered_options = []
|
62
|
+
@longest_cmd = 0
|
63
|
+
@longest_flag = 0
|
64
|
+
|
65
|
+
# if block_given?
|
66
|
+
# block.arity == 1 ? yield(self) : instance_eval(&block)
|
67
|
+
# end
|
68
|
+
instance_eval(&block) if block_given?
|
69
|
+
end
|
70
|
+
|
71
|
+
# Parse a list of items, executing and gathering options along the way.
|
72
|
+
#
|
73
|
+
# items - The Array of items to extract options from (default: ARGV).
|
74
|
+
# block - An optional block which when used will yield non options.
|
75
|
+
#
|
76
|
+
# Returns an Array of original items with options removed.
|
77
|
+
def parse(items = ARGV, &block)
|
78
|
+
item=items.shift
|
79
|
+
# need some help ?
|
80
|
+
if item == '?' || item == '-h' || item == '--help' || item == 'help' || item.nil?
|
81
|
+
puts self.help
|
82
|
+
exit
|
83
|
+
end
|
84
|
+
# parsing command
|
85
|
+
if !@commands.empty?
|
86
|
+
cmd = commands.find { |cmd| cmd.name == item }
|
87
|
+
raise UnknownCommandError if cmd.nil?
|
88
|
+
@command_name = cmd.name
|
89
|
+
@command_call = cmd.callback
|
90
|
+
item=items.shift
|
91
|
+
end
|
92
|
+
# parsing options
|
93
|
+
until item.nil?
|
94
|
+
#break if item == '--'
|
95
|
+
if item.match(/^--[^-]+$/).nil? && item.match(/^-[^-]$/).nil?
|
96
|
+
raise InvalidOptionError, "invalid #{item} option"
|
97
|
+
end
|
98
|
+
key = item.sub(/\A--?/, '')
|
99
|
+
option = options.find { |opt| opt.name == key || opt.short == key }
|
100
|
+
if option
|
101
|
+
@triggered_options << option
|
102
|
+
if option.expects_argument?
|
103
|
+
option.value = items.shift
|
104
|
+
raise MissingArgumentError, "missing #{item} argument" if option.value.nil?
|
105
|
+
raise InvalidArgumentError, "(#{item}=#{option.value}) argument can't start with '-'" if option.value.start_with?('-')
|
106
|
+
else
|
107
|
+
option.value = true
|
108
|
+
end
|
109
|
+
else
|
110
|
+
raise UnknownOptionError, "unknown #{item} option"
|
111
|
+
end
|
112
|
+
item=items.shift
|
113
|
+
end
|
114
|
+
if @runner.respond_to?(:call)
|
115
|
+
@runner.call(self, items)
|
116
|
+
end
|
117
|
+
# return the Options instance
|
118
|
+
self
|
119
|
+
end
|
120
|
+
|
121
|
+
# Print a handy Options help string.
|
122
|
+
#
|
123
|
+
# Returns the banner followed by available option help strings.
|
124
|
+
def help
|
125
|
+
if @commands.empty?
|
126
|
+
helpstr = "Usage: #{File.basename($0)} [options]\n"
|
127
|
+
else
|
128
|
+
helpstr = "Usage: #{File.basename($0)} command [options]\n"
|
129
|
+
end
|
130
|
+
helpstr << @banner if !@banner.empty?
|
131
|
+
if !@commands.empty?
|
132
|
+
helpstr << "Commands:\n"
|
133
|
+
commands.each { |cmd|
|
134
|
+
tab = ' ' * ( @longest_cmd + 1 - cmd.name.size )
|
135
|
+
helpstr << ' ' + cmd.name + tab + ': ' + cmd.description + "\n"
|
136
|
+
}
|
137
|
+
end
|
138
|
+
helpstr << "Options:\n"
|
139
|
+
options.each { |opt|
|
140
|
+
tab = ' ' * ( @longest_flag + 1 - opt.name.size )
|
141
|
+
if opt.expects_argument?
|
142
|
+
arg = ' <arg>'
|
143
|
+
else
|
144
|
+
arg = ' '
|
145
|
+
end
|
146
|
+
helpstr << ' -' + opt.short + '|--' + opt.name + arg + tab + ': ' + opt.description + "\n"
|
147
|
+
}
|
148
|
+
helpstr
|
149
|
+
end
|
150
|
+
|
151
|
+
# Banner
|
152
|
+
#
|
153
|
+
# Example:
|
154
|
+
# banner 'This is the banner'
|
155
|
+
#
|
156
|
+
def banner( desc = nil )
|
157
|
+
if desc.nil?
|
158
|
+
@banner
|
159
|
+
else
|
160
|
+
@banner += desc +"\n"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Command
|
165
|
+
#
|
166
|
+
# Examples:
|
167
|
+
# command 'run', 'Running'
|
168
|
+
# command :test, 'Testing'
|
169
|
+
#
|
170
|
+
# Returns the created instance of Options::Command.
|
171
|
+
# or returns the command given in argument
|
172
|
+
#
|
173
|
+
def command(name = nil, desc = nil, &block)
|
174
|
+
if !name.nil?
|
175
|
+
@longest_cmd = name.size if name.size > @longest_cmd
|
176
|
+
cmd = Command.new(name, desc, &block)
|
177
|
+
@commands << cmd
|
178
|
+
end
|
179
|
+
@command_name
|
180
|
+
end
|
181
|
+
alias cmd command
|
182
|
+
|
183
|
+
# Call the command callback of the command given in ARGV
|
184
|
+
#
|
185
|
+
# Example:
|
186
|
+
# # show messahe when command is executed (not during parsing)
|
187
|
+
# command 'run', 'Running' do
|
188
|
+
# puts "run in progress"
|
189
|
+
# end
|
190
|
+
#
|
191
|
+
def callback
|
192
|
+
@command_call.call if @command_call.respond_to?(:call)
|
193
|
+
end
|
194
|
+
|
195
|
+
# Add a value to options
|
196
|
+
#
|
197
|
+
# Examples:
|
198
|
+
# value 'user', 'Your username'
|
199
|
+
# value :pass, 'Your password'
|
200
|
+
#
|
201
|
+
# Returns the created instance of Options::Value.
|
202
|
+
#
|
203
|
+
def value(name, desc, &block)
|
204
|
+
@longest_flag = name.size if name.size > @longest_flag
|
205
|
+
option = Value.new(name, desc, &block)
|
206
|
+
@options << option
|
207
|
+
option
|
208
|
+
end
|
209
|
+
|
210
|
+
# Add an flag to options
|
211
|
+
#
|
212
|
+
# Examples:
|
213
|
+
# flag :verbose, 'Enable verbose mode'
|
214
|
+
# flag 'debug', 'Enable debug mode'
|
215
|
+
#
|
216
|
+
# Returns the created instance of Options::Flag.
|
217
|
+
#
|
218
|
+
def flag(name, desc, &block)
|
219
|
+
@longest_flag = name.size if name.size > @longest_flag
|
220
|
+
option = Flag.new(name, desc, &block)
|
221
|
+
@options << option
|
222
|
+
option
|
223
|
+
end
|
224
|
+
|
225
|
+
# Specify code to be executed when these options are parsed.
|
226
|
+
#
|
227
|
+
# Example:
|
228
|
+
#
|
229
|
+
# opts = Options.parse do
|
230
|
+
# flag :v, :verbose
|
231
|
+
#
|
232
|
+
# run do |opts, args|
|
233
|
+
# puts "Arguments: #{args.inspect}" if opts.verbose?
|
234
|
+
# end
|
235
|
+
# end
|
236
|
+
#def run(callable = nil, &block)
|
237
|
+
def run(&block)
|
238
|
+
@runner = block if block_given?
|
239
|
+
end
|
240
|
+
|
241
|
+
# Fetch an options argument value.
|
242
|
+
#
|
243
|
+
# key - The Symbol or String option short or long flag.
|
244
|
+
#
|
245
|
+
# Returns the Object value for this option, or nil.
|
246
|
+
def [](key)
|
247
|
+
key = key.to_s
|
248
|
+
option = options.find { |opt| opt.name == key || opt.short == key }
|
249
|
+
option.value if option
|
250
|
+
end
|
251
|
+
|
252
|
+
# Enumerable interface. Yields each Options::Option.
|
253
|
+
def each(&block)
|
254
|
+
options.each(&block)
|
255
|
+
end
|
256
|
+
|
257
|
+
# Returns a new Hash with option flags as keys and option values as values.
|
258
|
+
#
|
259
|
+
# include_commands - If true, merge options from all sub-commands.
|
260
|
+
def to_hash
|
261
|
+
Hash[options.map { |opt| [opt.name.to_sym, opt.value] }]
|
262
|
+
end
|
263
|
+
alias to_h to_hash
|
264
|
+
|
265
|
+
# Fetch a list of options which were missing from the parsed list.
|
266
|
+
#
|
267
|
+
# Examples:
|
268
|
+
#
|
269
|
+
# opts = Options.new do
|
270
|
+
# value :n, :name
|
271
|
+
# value :p, :password
|
272
|
+
# end
|
273
|
+
#
|
274
|
+
# opts.parse %w[ --name Lee ]
|
275
|
+
# opts.missing #=> ['password']
|
276
|
+
#
|
277
|
+
# Returns an Array of Strings representing missing options.
|
278
|
+
def missing
|
279
|
+
(options - @triggered_options).map(&:name)
|
280
|
+
end
|
281
|
+
|
282
|
+
private
|
283
|
+
# Returns true if this option is present.
|
284
|
+
# If this method does not end with a ? character it will instead
|
285
|
+
# return the value of the option or nil
|
286
|
+
#
|
287
|
+
# Examples:
|
288
|
+
# opts.parse %( --verbose )
|
289
|
+
# opts.verbose? #=> true
|
290
|
+
# opts.other? #=> false
|
291
|
+
#
|
292
|
+
def method_missing(method)
|
293
|
+
meth = method.to_s
|
294
|
+
if meth.end_with?('?')
|
295
|
+
meth.chop!
|
296
|
+
!(@triggered_options.find { |opt| opt.name == meth }).nil?
|
297
|
+
else
|
298
|
+
o = @triggered_options.find { |opt| opt.name == meth }
|
299
|
+
# o.nil? ? super : o.value
|
300
|
+
if o.nil?
|
301
|
+
nil
|
302
|
+
else
|
303
|
+
o.callback.call if o.callback.respond_to?(:call)
|
304
|
+
o.nil? ? nil : o.value
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
class Command
|
310
|
+
attr_reader :name, :description, :callback
|
311
|
+
|
312
|
+
# Incapsulate internal command.
|
313
|
+
#
|
314
|
+
# name - The String or Symbol command name.
|
315
|
+
# description - The String description text.
|
316
|
+
# block - An optional block.
|
317
|
+
def initialize(name, description, &block)
|
318
|
+
@name = name.to_s
|
319
|
+
raise InvalidCommandError, "Command #{@name} is invalid" if @name.start_with?('-')
|
320
|
+
@description = description
|
321
|
+
@callback = (block_given? ? block : nil)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
class Flag
|
326
|
+
attr_reader :short, :name, :description, :callback
|
327
|
+
attr_accessor :value
|
328
|
+
|
329
|
+
# Incapsulate internal option information, mainly used to store
|
330
|
+
# option specific configuration data, most of the meat of this
|
331
|
+
# class is found in the #value method.
|
332
|
+
#
|
333
|
+
# name - The String or Symbol option name.
|
334
|
+
# description - The String description text.
|
335
|
+
# block - An optional block.
|
336
|
+
def initialize(name, description, &block)
|
337
|
+
# Remove leading '-' from name if any
|
338
|
+
@name = name.to_s.gsub(/^--?/, '')
|
339
|
+
raise InvalidOptionError, "Option #{@name} is invalid" if @name.size < 2
|
340
|
+
@expects_argument = false
|
341
|
+
@value = false
|
342
|
+
@short = @name[0]
|
343
|
+
@description = description
|
344
|
+
@callback = (block_given? ? block : nil)
|
345
|
+
end
|
346
|
+
|
347
|
+
# Returns true if this option expects an argument.
|
348
|
+
def expects_argument?
|
349
|
+
@expects_argument
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
class Value
|
354
|
+
attr_reader :short, :name, :description, :callback
|
355
|
+
attr_accessor :value
|
356
|
+
|
357
|
+
# Incapsulate internal option information, mainly used to store
|
358
|
+
# option specific configuration data, most of the meat of this
|
359
|
+
# class is found in the #value method.
|
360
|
+
#
|
361
|
+
# name - The String or Symbol option name.
|
362
|
+
# description - The String description text.
|
363
|
+
# block - An optional block.
|
364
|
+
def initialize(name, description, &block)
|
365
|
+
# Remove leading '-' from name if any
|
366
|
+
@name = name.to_s.gsub(/^--?/, '')
|
367
|
+
raise InvalidOptionError, "Option #{@name} is invalid" if @name.size < 2
|
368
|
+
@expects_argument = true
|
369
|
+
@value = nil
|
370
|
+
@short = @name[0]
|
371
|
+
@description = description
|
372
|
+
@callback = (block_given? ? block : nil)
|
373
|
+
end
|
374
|
+
|
375
|
+
# Returns true if this option expects an argument.
|
376
|
+
def expects_argument?
|
377
|
+
@expects_argument
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
# Backward-compatible alias
|
385
|
+
Options = Pyer::Options
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pyer-options
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pierre BAZONNARD
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 5.4.2
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 5.4.2
|
41
|
+
description: Simple options parser inspired by slop
|
42
|
+
email:
|
43
|
+
- pierre.bazonnard@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- lib/pyer/options.rb
|
49
|
+
homepage: https://github.com/pyer/ruby/tree/master/options
|
50
|
+
licenses:
|
51
|
+
- MIT
|
52
|
+
metadata: {}
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.1.0
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 2.4.5
|
70
|
+
signing_key:
|
71
|
+
specification_version: 4
|
72
|
+
summary: Simple options parser
|
73
|
+
test_files: []
|