easyoptions 2015.2.28
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/easyoptions.rb +277 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1d08b70cbfa1961622109897ef00d7fef0defc23
|
4
|
+
data.tar.gz: 1300aefd50ddb122a1e081bc90938b2acbc30eb2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3d5e7f0926e2e6291c8a24f1f65ff143378e15c62c2f6ebbce0042446a7b9ea4dcb7b73b6f771feef58f5506d91e1d5683ad6806777bc4446dc35a7c83885eb6
|
7
|
+
data.tar.gz: 245258d0faa8c764056f850f6a380d54db2261c57d3ee0e0257b8cae62dd9f6ed4d752e781bfc5470295332ffac67515389e5c80e47bf363d3ed81dbe295b890
|
data/easyoptions.rb
ADDED
@@ -0,0 +1,277 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Encoding: UTF-8
|
3
|
+
|
4
|
+
##
|
5
|
+
## EasyOptions 2015.2.28
|
6
|
+
## Copyright (c) 2013, 2014 Renato Silva
|
7
|
+
## BSD licensed
|
8
|
+
##
|
9
|
+
## This script is supposed to parse command line arguments in a way that,
|
10
|
+
## even though its implementation is not trivial, it should be easy and
|
11
|
+
## smooth to use. For using this script, simply document your target script
|
12
|
+
## using double-hash comments, like this:
|
13
|
+
##
|
14
|
+
## ## Program Name v1.0
|
15
|
+
## ## Copyright (C) Someone
|
16
|
+
## ##
|
17
|
+
## ## This program does something. Usage:
|
18
|
+
## ## @#script.name [option]
|
19
|
+
## ##
|
20
|
+
## ## Options:
|
21
|
+
## ## -h, --help All client scripts have this by default,
|
22
|
+
## ## it shows this double-hash documentation.
|
23
|
+
## ##
|
24
|
+
## ## -o, --option This option will get stored as true value
|
25
|
+
## ## under EasyOptions.options[:option]. Long
|
26
|
+
## ## version is mandatory, and can be specified
|
27
|
+
## ### before or after short version.
|
28
|
+
## ##
|
29
|
+
## ## --some-boolean This will get stored as true value under
|
30
|
+
## ## EasyOptions.options[:some_boolean].
|
31
|
+
## ##
|
32
|
+
## ## --some-value=VALUE This is going to store the VALUE specified
|
33
|
+
## ## under EasyOptions.options[:some_value].
|
34
|
+
## ## The equal sign is optional and can be
|
35
|
+
## ## replaced with blank space when running the
|
36
|
+
## ## target script. If VALUE is composed of
|
37
|
+
## ## digits, it will be converted into an
|
38
|
+
## ## integer, otherwise it will get stored as a
|
39
|
+
## ## string. Short version is not available in
|
40
|
+
## ## this format.
|
41
|
+
##
|
42
|
+
## The above comments work both as source code documentation and as help
|
43
|
+
## text, as well as define the options supported by your script. There is no
|
44
|
+
## duplication of the options specification. The string @#script.name will be
|
45
|
+
## replaced with the actual script name.
|
46
|
+
##
|
47
|
+
## After writing your documentation, you simply require this script. Then all
|
48
|
+
## command line options will get parsed into the EasyOptions.options hash, as
|
49
|
+
## described above. You can then check their values for reacting to them. All
|
50
|
+
## regular arguments will get stored into the EasyOptions.arguments array.
|
51
|
+
##
|
52
|
+
## In fact, this script is an example of itself. You are seeing this help
|
53
|
+
## message either because you are reading the source code, or you have called
|
54
|
+
## the script in command line with the --help option.
|
55
|
+
##
|
56
|
+
## Note: the options and arguments are also available as global variables in
|
57
|
+
## current version, but their use is discouraged and is supposed to be
|
58
|
+
## eventually removed.
|
59
|
+
##
|
60
|
+
## This script can be used from Bash scripts as well. If the $from environment
|
61
|
+
## variable is set, that will be assumed as the source Bash script from which to
|
62
|
+
## parse the documentation and the provided options. Then, instead of parsing
|
63
|
+
## the options into Ruby variables, evaluable assignment statements will be
|
64
|
+
## generated for the corresponding Bash environment variables. For example:
|
65
|
+
##
|
66
|
+
## eval "$(from="$0" @script.name "$@" || echo exit 1)"
|
67
|
+
##
|
68
|
+
## If the script containing this command is documented as in the example above,
|
69
|
+
## and it is executed from command line with the -o and --some-value=10 options,
|
70
|
+
## and one regular argument abc, then the evaluable output would look like this:
|
71
|
+
##
|
72
|
+
## option="yes"
|
73
|
+
## some_value="10"
|
74
|
+
## unset arguments
|
75
|
+
## arguments+=("abc")
|
76
|
+
## arguments
|
77
|
+
##
|
78
|
+
|
79
|
+
module EasyOptions
|
80
|
+
class Option
|
81
|
+
def initialize(long_version, short_version, boolean = true)
|
82
|
+
fail ArgumentError.new('Long version is mandatory') if !long_version || long_version.length < 2
|
83
|
+
@short = short_version.to_sym if short_version
|
84
|
+
@long = long_version.to_s.gsub('-', '_').to_sym
|
85
|
+
@boolean = boolean
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_s
|
89
|
+
"--#{long_dashed}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def in?(string)
|
93
|
+
string =~ /^--#{long_dashed}$/ || (@short && string =~ /^-#{@short}$/)
|
94
|
+
end
|
95
|
+
|
96
|
+
def in_with_value?(string)
|
97
|
+
string =~ /^--#{long_dashed}=.*$/
|
98
|
+
end
|
99
|
+
|
100
|
+
def long_dashed
|
101
|
+
@long.to_s.gsub('_', '-')
|
102
|
+
end
|
103
|
+
attr_accessor :short
|
104
|
+
attr_accessor :long
|
105
|
+
attr_accessor :boolean
|
106
|
+
end
|
107
|
+
|
108
|
+
class Parser
|
109
|
+
def initialize
|
110
|
+
@known_options = [Option.new(:help, :h)]
|
111
|
+
@documentation = parse_doc
|
112
|
+
@arguments = []
|
113
|
+
@options = {}
|
114
|
+
end
|
115
|
+
|
116
|
+
def parse_doc
|
117
|
+
begin
|
118
|
+
doc = File.readlines($PROGRAM_NAME)
|
119
|
+
rescue Errno::ENOENT
|
120
|
+
exit false
|
121
|
+
end
|
122
|
+
doc = doc.find_all do |line|
|
123
|
+
line =~ /^##[^#]*/
|
124
|
+
end
|
125
|
+
doc.map do |line|
|
126
|
+
line.strip!
|
127
|
+
line.sub!(/^## ?/, '')
|
128
|
+
line.gsub!(/@script.name/, File.basename($PROGRAM_NAME))
|
129
|
+
line.gsub(/@#/, '@')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def parse
|
134
|
+
# Parse known options from documentation
|
135
|
+
@documentation.map do |line|
|
136
|
+
line = line.strip
|
137
|
+
case line
|
138
|
+
when /^-h, --help.*/ then next
|
139
|
+
when /^--help, -h.*/ then next
|
140
|
+
when /^-.*, --.*/ then line = line.split(/(^-|,\s--|\s)/); @known_options << Option.new(line[4], line[2])
|
141
|
+
when /^--.*, -.*/ then line = line.split(/(--|,\s-|\s)/); @known_options << Option.new(line[2], line[4])
|
142
|
+
when /^--.*=.*/ then line = line.split(/(--|=|\s)/); @known_options << Option.new(line[2], nil, false)
|
143
|
+
when /^--.* .*/ then line = line.split(/(--|\s)/); @known_options << Option.new(line[2], nil)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Format arguments input
|
148
|
+
raw_arguments = ARGV.map do |argument|
|
149
|
+
if argument =~ /^-[^-].*$/i
|
150
|
+
argument.split('')[1..-1].map { |char| "-#{char}" }
|
151
|
+
else
|
152
|
+
argument
|
153
|
+
end
|
154
|
+
end.flatten
|
155
|
+
|
156
|
+
# Parse the provided options
|
157
|
+
raw_arguments.each_with_index do |argument, index|
|
158
|
+
unknown_option = true
|
159
|
+
@known_options.each do |known_option|
|
160
|
+
|
161
|
+
# Boolean option
|
162
|
+
if known_option.in?(argument) && known_option.boolean
|
163
|
+
@options[known_option.long] = true
|
164
|
+
unknown_option = false
|
165
|
+
break
|
166
|
+
|
167
|
+
# Option with value in next parameter
|
168
|
+
elsif known_option.in?(argument) && !known_option.boolean
|
169
|
+
value = raw_arguments[index + 1]
|
170
|
+
Parser.finish("you must specify a value for #{known_option}") if !value || value.start_with?('-')
|
171
|
+
value = value.to_i if value =~ /^[0-9]+$/
|
172
|
+
@options[known_option.long] = value
|
173
|
+
unknown_option = false
|
174
|
+
break
|
175
|
+
|
176
|
+
# Option with value after equal sign
|
177
|
+
elsif known_option.in_with_value?(argument) && !known_option.boolean
|
178
|
+
value = argument.split('=')[1]
|
179
|
+
value = value.to_i if value =~ /^[0-9]+$/
|
180
|
+
@options[known_option.long] = value
|
181
|
+
unknown_option = false
|
182
|
+
break
|
183
|
+
|
184
|
+
# Long option with unnecessary value
|
185
|
+
elsif known_option.in_with_value?(argument) && known_option.boolean
|
186
|
+
value = argument.split('=')[1]
|
187
|
+
Parser.finish("#{known_option} does not accept a value (you specified \"#{value}\")")
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Unrecognized option
|
192
|
+
Parser.finish("unrecognized option \"#{argument}\"") if unknown_option && argument.start_with?('-')
|
193
|
+
end
|
194
|
+
|
195
|
+
# Help option
|
196
|
+
if @options[:help]
|
197
|
+
if BashOutput
|
198
|
+
print "printf '"
|
199
|
+
puts @documentation
|
200
|
+
puts "'"
|
201
|
+
puts 'exit'
|
202
|
+
else
|
203
|
+
puts @documentation
|
204
|
+
end
|
205
|
+
exit(-1)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Regular arguments
|
209
|
+
next_is_value = false
|
210
|
+
raw_arguments.each do |argument|
|
211
|
+
if argument.start_with?('-')
|
212
|
+
known_option = @known_options.find { |option| option.in?(argument) }
|
213
|
+
next_is_value = (known_option && !known_option.boolean)
|
214
|
+
else
|
215
|
+
arguments << argument unless next_is_value
|
216
|
+
next_is_value = false
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Bash support
|
221
|
+
return unless BashOutput
|
222
|
+
@options.keys.each do |name|
|
223
|
+
puts "#{name}=\"#{@options[name].to_s.sub('true', 'yes')}\""
|
224
|
+
end
|
225
|
+
puts 'unset arguments'
|
226
|
+
arguments.each do |argument|
|
227
|
+
puts "arguments+=(\"#{argument}\")"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def self.finish(error)
|
232
|
+
warn "Error: #{error}."
|
233
|
+
warn 'See --help for usage and options.'
|
234
|
+
puts 'exit 1' if BashOutput
|
235
|
+
exit false
|
236
|
+
end
|
237
|
+
|
238
|
+
def self.check_bash_output
|
239
|
+
$0 = ENV['from'] || $PROGRAM_NAME
|
240
|
+
$PROGRAM_NAME == ENV['from']
|
241
|
+
end
|
242
|
+
|
243
|
+
BashOutput = check_bash_output
|
244
|
+
attr_accessor :documentation
|
245
|
+
attr_accessor :arguments
|
246
|
+
attr_accessor :options
|
247
|
+
end
|
248
|
+
|
249
|
+
class << self
|
250
|
+
@@parser = Parser.new
|
251
|
+
@@parser.parse
|
252
|
+
def options
|
253
|
+
@@parser.options
|
254
|
+
end
|
255
|
+
|
256
|
+
def arguments
|
257
|
+
@@parser.arguments
|
258
|
+
end
|
259
|
+
|
260
|
+
def documentation
|
261
|
+
@@parser.documentation
|
262
|
+
end
|
263
|
+
|
264
|
+
def all
|
265
|
+
[options, arguments, documentation]
|
266
|
+
end
|
267
|
+
|
268
|
+
def finish(error)
|
269
|
+
Parser.finish(error)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# This is supposed to be eventually removed
|
274
|
+
$documentation = @@parser.documentation
|
275
|
+
$arguments = @@parser.arguments
|
276
|
+
$options = @@parser.options
|
277
|
+
end
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: easyoptions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2015.2.28
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Renato Silva
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email: br.renatosilva@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- easyoptions.rb
|
20
|
+
homepage: https://github.com/renatosilva/easyoptions
|
21
|
+
licenses:
|
22
|
+
- BSD
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- "."
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubyforge_project:
|
40
|
+
rubygems_version: 2.2.2
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: Easy option parsing
|
44
|
+
test_files: []
|