easyoptions 2015.2.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/easyoptions.rb +277 -0
  3. metadata +44 -0
@@ -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
@@ -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: []