cowtech-lib 1.9.8.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,359 +1,338 @@
1
1
  # encoding: utf-8
2
2
  #
3
- # cowtech-lib
4
- # Author: Shogun <shogun_panda@me.com>
5
- # Copyright © 2011 and above Shogun
6
- # Released under the MIT License, which follows.
7
- #
8
- # The MIT License
9
- # Permission is hereby granted, free of charge, to any person obtaining a copy
10
- # of this software and associated documentation files (the "Software"), to deal
11
- # in the Software without restriction, including without limitation the rights
12
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
- # copies of the Software, and to permit persons to whom the Software is
14
- # furnished to do so, subject to the following conditions:
15
- #
16
- # The above copyright notice and this permission notice shall be included in
17
- # all copies or substantial portions of the Software.
18
- #
19
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
- # THE SOFTWARE.
3
+ # This file is part of the cowtech-lib gem. Copyright (C) 2011 and above Shogun <shogun_panda@me.com>.
4
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
26
5
  #
27
6
 
28
7
  require "getoptlong"
29
8
 
30
9
  module Cowtech
31
- module Lib
32
- # A class which parse commandline options.
33
- # @author Shogun
34
- class OptionParser
35
- # The specified options
36
- attr_accessor :options
37
-
38
- # The full command line provided
39
- attr_reader :cmdline
40
-
41
- # The messages for the help message
42
- attr_reader :messages
43
-
44
- # The other (non-option) provided args
45
- attr_reader :args
46
-
47
- # Add or replace an option to the parser. Every argument is optional (in the form ATTR => VALUE) with the exception of :name, :short and :long.
48
- #
49
- # Arguments:
50
- # * <em>:name</em>: Option name
51
- # * <em>:short</em>: Option short form, can begin with "-"
52
- # * <em>:long</em>: Option long form, can begin with "--"
53
- # * <em>:type</em>: Option type, valid values are:
54
- # * <em>:bool</em>: Boolean option
55
- # * <em>:string</em>: Option with string argument
56
- # * <em>:int</em>: Option with int argument
57
- # * <em>:float</em>: Option with float argument
58
- # * <em>:choice</em>: Option with string argument that must be valitated from a list of patterns
59
- # * <em>:list</em>: Option with a list of string argument
60
- # * <em>:action</em>: Option with an associated action
61
- # * <em>:help</em>: Option description
62
- # * <em>:choices</em>: Option valid choice (list of regexp), only used with the :choice type
63
- # * <em>:action</em>: Option action block, only used with the :action type
64
- # * <em>:meta</em>: Option meta variable for description
65
- # * <em>:default</em>: Option default value
66
- # * <em>:required</em>: Whether the option is required
67
- # * <em>:priority</em>: Priority for the option. Used only on the help message to sort (by increasing priority) the options.
68
- def <<(options)
69
- options = [options] if !options.is_a?(Array)
70
-
71
- options.each do |option|
72
- @console.fatal(:msg => "Every attribute must be an Hash.", :dots => false) if !option.is_a?(Hash)
73
-
74
- # Use symbols for names
75
- option[:name] = option[:name].to_sym
76
-
77
- # Add the default type, which is :string
78
- option[:type] ||= :string
79
-
80
- # Check if type is valid
81
- @console.fatal(:msg => "Invalid option type #{option[:type]} for option #{option[:name]}. Valid type are the following:\n\t#{@@valid_types.keys.join(", ")}.", :dots => false) if !@@valid_types.keys.include?(option[:type])
82
-
83
- # Adjust the default value
84
- case option[:type]
85
- when :bool then
86
- option[:default] = false if !option.has_key?(:default)
87
- when :action then
88
- option[:required] = false
89
- else
90
- option[:default] = @@valid_types[option[:type]][1] if !option.has_key?(:default) || !option[:default].is_a?(@@valid_types[option[:type]][0])
91
- end
92
-
93
- # Adjust priority
94
- option[:priority] = option[:priority].to_s.to_i if !option[:priority].is_a?(Integer)
95
-
96
- # Prepend dashes
97
- option[:short] = "-" + option[:short] if !option[:short] =~ /^-/
98
- while option[:long] !~ /^--/ do option[:long] = "-" + option[:long] end
99
- @console.fatal(:msg => "Invalid short form \"#{option[:short]}\".", :dots => false) if option[:short] !~ /^-[0-9a-z]$/i
100
- @console.fatal(:msg => "Invalid long form \"#{option[:long]}\".", :dots => false) if option[:long] !~ /^--([0-9a-z-]+)$/i
101
-
102
- # Check for choices if the type is choices
103
- if option[:type] == :choice then
104
- if option[:choices] == nil then
105
- @console.fatal(:msg => "Option \"#{option[:name]}\" of type choice requires a valid choices list (every element should be a regular expression).")
106
- else
107
- option[:choices].collect! { |choice| Regexp.new(choice) }
108
- end
109
- end
110
-
111
- # Check that action is a block if the type is action
112
- @console.fatal("Option \"#{option[:name]}\" of type action requires a action block.") if option[:type] == :action && (option[:action] == nil || !option[:action].is_a?(Proc.class))
113
-
114
- # Check for uniqueness of option and its forms
115
- @console.fatal("An option with name \"#{option[:name]}\" already exists.", :dots => false) if @inserted[:name].include?(option[:name])
116
- @console.fatal("An option with short or long form \"#{option[:short]}\" already exists.", :dots => false) if @inserted[:short].include?(option[:short])
117
- @console.fatal("An option with short or long form \"#{option[:long]}\" already exists.", :dots => false) if @inserted[:long].include?(option[:long])
118
-
119
- # Save
120
- @options[option[:name]] = option
121
- @options_map[option[:long]] = option[:name]
122
- @inserted[:name].push(option[:name])
123
- @inserted[:short].push(option[:short])
124
- @inserted[:long].push(option[:long])
125
- end
126
- end
127
-
128
- # Parse the command line.
129
- #
130
- # Arguments:
131
- # * <em>ignore_unknown</em>: Whether ignore unknown options
132
- # * <em>ignore_unknown</em>: Whether ignore help options
133
- def parse(args = nil)
134
- args ||= {}
135
- # Create options
136
- noat = [:bool, :action]
137
- sopts = @options.each_value.collect { |option| [option[:long], option[:short], noat.include?(option[:type]) ? GetoptLong::NO_ARGUMENT : GetoptLong::REQUIRED_ARGUMENT] }
138
-
139
- opts = GetoptLong.new(*sopts)
140
- opts.quiet = true
141
-
142
- # Parse option
143
- begin
144
- opts.each do |given, arg|
145
- optname = @options_map[given]
146
- option = @options[optname]
147
- value = nil
148
-
149
- # VALIDATE ARGUMENT DUE TO CASE
150
- case option[:type]
151
- when :string then
152
- value = arg
153
- when :int then
154
- if arg.strip =~ /^(-?)(\d+)$/ then
155
- value = arg.to_i(10)
156
- else
157
- @console.fatal(:msg => "Argument of option \"#{given}\" must be an integer.", :dots => false)
10
+ module Lib
11
+ # A class which parse commandline options.
12
+ # @author Shogun
13
+ class OptionParser
14
+ # The specified options
15
+ attr_accessor :options
16
+
17
+ # The full command line provided
18
+ attr_reader :cmdline
19
+
20
+ # The messages for the help message
21
+ attr_reader :messages
22
+
23
+ # The other (non-option) provided args
24
+ attr_reader :args
25
+
26
+ # Add or replace an option to the parser. Every argument is optional (in the form ATTR => VALUE) with the exception of :name, :short and :long.
27
+ #
28
+ # Arguments:
29
+ # * <em>:name</em>: Option name
30
+ # * <em>:short</em>: Option short form, can begin with "-"
31
+ # * <em>:long</em>: Option long form, can begin with "--"
32
+ # * <em>:type</em>: Option type, valid values are:
33
+ # * <em>:bool</em>: Boolean option
34
+ # * <em>:string</em>: Option with string argument
35
+ # * <em>:int</em>: Option with int argument
36
+ # * <em>:float</em>: Option with float argument
37
+ # * <em>:choice</em>: Option with string argument that must be valitated from a list of patterns
38
+ # * <em>:list</em>: Option with a list of string argument
39
+ # * <em>:action</em>: Option with an associated action
40
+ # * <em>:help</em>: Option description
41
+ # * <em>:choices</em>: Option valid choice (list of regexp), only used with the :choice type
42
+ # * <em>:action</em>: Option action block, only used with the :action type
43
+ # * <em>:meta</em>: Option meta variable for description
44
+ # * <em>:default</em>: Option default value
45
+ # * <em>:required</em>: Whether the option is required
46
+ # * <em>:priority</em>: Priority for the option. Used only on the help message to sort (by increasing priority) the options.
47
+ def <<(options)
48
+ options = [options] if !options.is_a?(Array)
49
+
50
+ options.each do |option|
51
+ @console.fatal(msg: "Every attribute must be an Hash.", dots: false) if !option.is_a?(Hash)
52
+
53
+ # Use symbols for names
54
+ option[:name] = option[:name].to_sym
55
+
56
+ # Add the default type, which is :string
57
+ option[:type] ||= :string
58
+
59
+ # Check if type is valid
60
+ @console.fatal(msg: "Invalid option type #{option[:type]} for option #{option[:name]}. Valid type are the following:\n\t#{@@valid_types.keys.join(", ")}.", dots: false) if !@@valid_types.keys.include?(option[:type])
61
+
62
+ # Adjust the default value
63
+ case option[:type]
64
+ when :bool then
65
+ option[:default] = false if !option.has_key?(:default)
66
+ when :action then
67
+ option[:required] = false
68
+ else
69
+ option[:default] = @@valid_types[option[:type]][1] if !option.has_key?(:default) || !option[:default].is_a?(@@valid_types[option[:type]][0])
70
+ end
71
+
72
+ # Adjust priority
73
+ option[:priority] = option[:priority].to_s.to_i if !option[:priority].is_a?(Integer)
74
+
75
+ # Prepend dashes
76
+ option[:short] = "-" + option[:short] if !option[:short] =~ /^-/
77
+ while option[:long] !~ /^--/ do option[:long] = "-" + option[:long] end
78
+ @console.fatal(msg: "Invalid short form \"#{option[:short]}\".", dots: false) if option[:short] !~ /^-[0-9a-z]$/i
79
+ @console.fatal(msg: "Invalid long form \"#{option[:long]}\".", dots: false) if option[:long] !~ /^--([0-9a-z-]+)$/i
80
+
81
+ # Check for choices if the type is choices
82
+ if option[:type] == :choice then
83
+ if option[:choices] == nil then
84
+ @console.fatal(msg: "Option \"#{option[:name]}\" of type choice requires a valid choices list (every element should be a regular expression).")
85
+ else
86
+ option[:choices].collect! { |choice| Regexp.new(choice) }
87
+ end
88
+ end
89
+
90
+ # Check that action is a block if the type is action
91
+ @console.fatal("Option \"#{option[:name]}\" of type action requires a action block.") if option[:type] == :action && (option[:action] == nil || !option[:action].is_a?(Proc.class))
92
+
93
+ # Check for uniqueness of option and its forms
94
+ @console.fatal("An option with name \"#{option[:name]}\" already exists.", dots: false) if @inserted[:name].include?(option[:name])
95
+ @console.fatal("An option with short or long form \"#{option[:short]}\" already exists.", dots: false) if @inserted[:short].include?(option[:short])
96
+ @console.fatal("An option with short or long form \"#{option[:long]}\" already exists.", dots: false) if @inserted[:long].include?(option[:long])
97
+
98
+ # Save
99
+ @options[option[:name]] = option
100
+ @options_map[option[:long]] = option[:name]
101
+ @inserted[:name].push(option[:name])
102
+ @inserted[:short].push(option[:short])
103
+ @inserted[:long].push(option[:long])
104
+ end
105
+ end
106
+
107
+ # Parse the command line.
108
+ #
109
+ # Arguments:
110
+ # * <em>ignore_unknown</em>: Whether ignore unknown options
111
+ # * <em>ignore_unknown</em>: Whether ignore help options
112
+ def parse(args = nil)
113
+ args ||= {}
114
+ # Create options
115
+ noat = [:bool, :action]
116
+ sopts = @options.each_value.collect { |option| [option[:long], option[:short], noat.include?(option[:type]) ? GetoptLong::NO_ARGUMENT : GetoptLong::REQUIRED_ARGUMENT] }
117
+
118
+ opts = GetoptLong.new(*sopts)
119
+ opts.quiet = true
120
+
121
+ # Parse option
122
+ begin
123
+ opts.each do |given, arg|
124
+ optname = @options_map[given]
125
+ option = @options[optname]
126
+ value = nil
127
+
128
+ # VALIDATE ARGUMENT DUE TO CASE
129
+ case option[:type]
130
+ when :string then
131
+ value = arg
132
+ when :int then
133
+ if arg.strip =~ /^(-?)(\d+)$/ then
134
+ value = arg.to_i(10)
135
+ else
136
+ @console.fatal(msg: "Argument of option \"#{given}\" must be an integer.", dots: false)
158
137
  end
159
- when :float then
160
- if arg.strip =~ /^(-?)(\d*)(\.(\d+))?$/ && arg.strip() != "." then
161
- value = arg.to_f
162
- else
163
- @console.fatal(:msg => "Argument of option \"#{given}\" must be a float.", :dots => false)
138
+ when :float then
139
+ if arg.strip =~ /^(-?)(\d*)(\.(\d+))?$/ && arg.strip() != "." then
140
+ value = arg.to_f
141
+ else
142
+ @console.fatal(msg: "Argument of option \"#{given}\" must be a float.", dots: false)
164
143
  end
165
- when :choice then
166
- if @options[optname].choices.find_index { |choice| arg =~ choice } then
167
- value = arg
168
- else
169
- @console.fatal(:msg => "Invalid argument (invalid choice) for option \"#{given}\".", :dots => false)
144
+ when :choice then
145
+ if @options[optname].choices.find_index { |choice| arg =~ choice } then
146
+ value = arg
147
+ else
148
+ @console.fatal(msg: "Invalid argument (invalid choice) for option \"#{given}\".", dots: false)
170
149
  end
171
- when :list then
172
- value = arg.split(",")
173
- else
174
- value = true
175
- end
176
-
177
- @options[optname][:value] = value
178
- end
179
- rescue StandardError => exception
180
- if exception.message =~ /.+-- (.+)$/ then
181
- given = $1
182
-
183
- if exception.is_a?(GetoptLong::InvalidOption) then
184
- @console.fatal(:msg => "Unknown option \"#{given}\".", :dots => false) if !args[:ignore_unknown]
185
- elsif exception.is_a?(GetoptLong::MissingArgument) then
186
- @console.fatal(:msg => "Option \"-#{given}\" requires an argument.", :dots => false)
187
- end
188
- else
189
- @console.fatal("Unexpected error: #{exc.message}.")
190
- end
191
- end
192
-
193
- # SET OTHER ARGUMENTS
194
- @args = ARGV
195
-
196
- # CHECK IF HELP WAS REQUESTED
197
- if self.provided?("help") && !args[:ignore_help] then
198
- self.print_help
199
- exit(0)
200
- end
201
-
202
- # NOW CHECK IF SOME REQUIRED OPTION WAS NOT SPECIFIED OR IF WE HAVE TO EXECUTE AN ACTION
203
- @inserted[:name].each do |key|
204
- option = @options[key]
205
-
206
- if option[:required] == true && option[:value] == nil then
207
- @console.fatal(:msg => "Required option \"#{option[:name]}\" not specified.", :dots => false)
208
- elsif option[:value] == true && option[:type] == :action then
209
- option.action.call
210
- end
211
- end
212
- end
213
-
214
- # Check if an option is defined.
215
- # Arguments:
216
- # * <em>name</em>: Option name
217
- # Returns: <em>true</em> if options is defined, <em>false</em> otherwise.
218
- def exists?(name)
219
- name = name.to_sym
220
- @options.keys.include?(name)
221
- end
222
-
223
- # Check if the user provided the option.
224
- # Arguments:
225
- # * <em>name</em>: Option name
226
- # Returns: <em>true</em> if options was provided, <em>false</em> otherwise.
227
- def provided?(name)
228
- name = name.to_sym
229
- (@options[name] || {})[:value] != nil
230
- end
231
-
232
- # Get a list of value for the requested options.
233
- # Arguments:
234
- # * <em>name</em>: Options name
235
- # * <em>name</em>: Default value if option was not provided.
236
- # Returns: The option value
237
- def get(name, default = nil)
238
- name = name.to_sym
239
-
240
- if @options[name][:value] != nil then
241
- @options[name][:value]
242
- elsif default != nil then
243
- default
244
- else
245
- @options[name][:default]
246
- end
247
- end
248
-
249
- # Get a list of value for the requested options.
250
- # Arguments:
251
- # * <em>options</em>: Options list
252
- # Returns: If a single argument is provided, only a value is returned, else an hash (name => value). If no argument is provided, return every option
253
- def [](*options)
254
- options = [options] if !options.is_a?(Array)
255
- options = @options.keys if options.length == 0
256
-
257
- if options.length == 1 then
258
- self.get(options[0])
259
- else
260
- rv = {}
261
- options.each do |option|
262
- rv[option.to_s] = self.get(option) if self.exists?(option)
263
- end
264
- rv
265
- end
266
- end
267
-
268
- # Returns option and non option provided arguments.
269
- def fetch
270
- [self.[], @args]
271
- end
272
-
273
- # Prints the help message.
274
- def print_help
275
- # Print app name
276
- if @app_name then
277
- print "#{@app_name}"
278
- print " #{@app_version}" if @app_version > 0
279
- print " - #{@description}" if @description
280
- print "\n"
281
- end
282
-
283
- # Print usage
284
- print "#{@messages["pre_usage"]}\n" if @messages["pre_usage"]
285
- print "#{@usage ? @usage : "Usage: #{ARGV[0]} [OPTIONS]"}\n"
286
-
287
- # Print pre_options
288
- print "#{@messages["pre_options"]}\n" if @messages["pre_options"]
289
- print "\nValid options are:\n"
290
-
291
- # Order options for printing
292
- @sorted_opts = @inserted[:name].sort do |first, second|
293
- @options[first][:priority] != @options[second][:priority] ? @options[first][:priority] <=> @options[second][:priority] : @inserted[:name].index(first) <=> @inserted[:name].index(second)
294
- end
295
-
296
- # Add options, saving max length
297
- popts = {}
298
- maxlen = -1
299
- @sorted_opts.each do |key|
300
- opt = @options[key]
301
-
302
- popt = "#{[opt[:short], opt[:long]].join(", ")}"
303
- popt += ("=" + (opt[:meta] ? opt[:meta] : "ARG")) if ![:bool, :action].include?(opt[:type])
304
- popts[key] = popt
305
- maxlen = popt.length if popt.length > maxlen
306
- end
307
-
308
- # Print options
309
- @sorted_opts.each do |key|
310
- val = popts[key]
311
- print "\t#{val}#{" " * (5 + (maxlen - val.length))}#{@options[key][:help]}\n"
312
- end
313
-
314
- # Print post_options
315
- print "#{@messages["post_options"]}\n" if @messages["post_options"]
316
- end
317
-
318
- #Creates a new OptionParser.
319
- #
320
- # Arguments:
321
- # * <em>name</em>: Application name
322
- # * <em>version</em>: Application version
323
- # * <em>name</em>: Application description
324
- # * <em>name</em>: Application usage
325
- # * <em>messages</em>: Application message for help switch. Supported keys are
326
- # * <em>:pre_usage</em>: Message to print before the usage string
327
- # * <em>:pre_options</em>: Message to print before the options list
328
- # * <em>:post_options</em>: Message to print after the options list
329
- def initialize(args)
330
- # Initialize types
331
- @@valid_types = {:bool => [], :string => [String, ""], :int => [Integer, 0], :float => [Float, 0.0], :choice => [String, ""], :list => [Array, []], :action => []}
332
-
333
- # Copy arguments
334
- @app_name = args[:name]
335
- @app_version = args[:version]
336
- @description = args[:description]
337
- @usage = args[:usage]
338
-
339
- # Copy messages
340
- messages = args[:messages] || {}
341
- if messages.is_a?(Hash) then
342
- @messages = messages
343
- else
344
- @console.fatal(:msg => "CowtechLib::OptionParser::initialize msgs argument must be an hash.")
150
+ when :list then
151
+ value = arg.split(",")
152
+ else
153
+ value = true
154
+ end
155
+
156
+ @options[optname][:value] = value
157
+ end
158
+ rescue StandardError => exception
159
+ if exception.message =~ /.+-- (.+)$/ then
160
+ given = $1
161
+
162
+ if exception.is_a?(GetoptLong::InvalidOption) then
163
+ @console.fatal(msg: "Unknown option \"#{given}\".", dots: false) if !args[:ignore_unknown]
164
+ elsif exception.is_a?(GetoptLong::MissingArgument) then
165
+ @console.fatal(msg: "Option \"-#{given}\" requires an argument.", dots: false)
166
+ end
167
+ else
168
+ @console.fatal("Unexpected error: #{exc.message}.")
169
+ end
170
+ end
171
+
172
+ # SET OTHER ARGUMENTS
173
+ @args = ARGV
174
+
175
+ # CHECK IF HELP WAS REQUESTED
176
+ if self.provided?("help") && !args[:ignore_help] then
177
+ self.print_help
178
+ exit(0)
179
+ end
180
+
181
+ # NOW CHECK IF SOME REQUIRED OPTION WAS NOT SPECIFIED OR IF WE HAVE TO EXECUTE AN ACTION
182
+ @inserted[:name].each do |key|
183
+ option = @options[key]
184
+
185
+ if option[:required] == true && option[:value] == nil then
186
+ @console.fatal(msg: "Required option \"#{option[:name]}\" not specified.", dots: false)
187
+ elsif option[:value] == true && option[:type] == :action then
188
+ option.action.call
189
+ end
190
+ end
191
+ end
192
+
193
+ # Check if an option is defined.
194
+ # Arguments:
195
+ # * <em>name</em>: Option name
196
+ # Returns: <em>true</em> if options is defined, <em>false</em> otherwise.
197
+ def exists?(name)
198
+ name = name.to_sym
199
+ @options.keys.include?(name)
200
+ end
201
+
202
+ # Check if the user provided the option.
203
+ # Arguments:
204
+ # * <em>name</em>: Option name
205
+ # Returns: <em>true</em> if options was provided, <em>false</em> otherwise.
206
+ def provided?(name)
207
+ name = name.to_sym
208
+ (@options[name] || {})[:value] != nil
209
+ end
210
+
211
+ # Get a list of value for the requested options.
212
+ # Arguments:
213
+ # * <em>name</em>: Options name
214
+ # * <em>name</em>: Default value if option was not provided.
215
+ # Returns: The option value
216
+ def get(name, default = nil)
217
+ name = name.to_sym
218
+
219
+ if @options[name][:value] != nil then
220
+ @options[name][:value]
221
+ elsif default != nil then
222
+ default
223
+ else
224
+ @options[name][:default]
225
+ end
226
+ end
227
+
228
+ # Get a list of value for the requested options.
229
+ # Arguments:
230
+ # * <em>options</em>: Options list
231
+ # Returns: If a single argument is provided, only a value is returned, else an hash (name => value). If no argument is provided, return every option
232
+ def [](*options)
233
+ options = [options] if !options.is_a?(Array)
234
+ options = @options.keys if options.length == 0
235
+
236
+ if options.length == 1 then
237
+ self.get(options[0])
238
+ else
239
+ rv = {}
240
+ options.each do |option|
241
+ rv[option.to_s] = self.get(option) if self.exists?(option)
242
+ end
243
+ rv
244
+ end
245
+ end
246
+
247
+ # Returns option and non option provided arguments.
248
+ def fetch
249
+ [self.[], @args]
250
+ end
251
+
252
+ # Prints the help message.
253
+ def print_help
254
+ # Print app name
255
+ if @app_name then
256
+ print "#{@app_name}"
257
+ print " #{@app_version}" if @app_version > 0
258
+ print " - #{@description}" if @description
259
+ print "\n"
260
+ end
261
+
262
+ # Print usage
263
+ print "#{@messages["pre_usage"]}\n" if @messages["pre_usage"]
264
+ print "#{@usage ? @usage : "Usage: #{ARGV[0]} [OPTIONS]"}\n"
265
+
266
+ # Print pre_options
267
+ print "#{@messages["pre_options"]}\n" if @messages["pre_options"]
268
+ print "\nValid options are:\n"
269
+
270
+ # Order options for printing
271
+ @sorted_opts = @inserted[:name].sort do |first, second|
272
+ @options[first][:priority] != @options[second][:priority] ? @options[first][:priority] <=> @options[second][:priority] : @inserted[:name].index(first) <=> @inserted[:name].index(second)
273
+ end
274
+
275
+ # Add options, saving max length
276
+ popts = {}
277
+ maxlen = -1
278
+ @sorted_opts.each do |key|
279
+ opt = @options[key]
280
+
281
+ popt = "#{[opt[:short], opt[:long]].join(", ")}"
282
+ popt += ("=" + (opt[:meta] ? opt[:meta] : "ARG")) if ![:bool, :action].include?(opt[:type])
283
+ popts[key] = popt
284
+ maxlen = popt.length if popt.length > maxlen
285
+ end
286
+
287
+ # Print options
288
+ @sorted_opts.each do |key|
289
+ val = popts[key]
290
+ print "\t#{val}#{" " * (5 + (maxlen - val.length))}#{@options[key][:help]}\n"
345
291
  end
346
-
347
- # Initialize variables
348
- @console = Console.new
349
- @inserted = {:name => [], :short => [], :long => []}
350
- @options = {}
351
- @options_map = {}
352
- @args = []
353
- @cmdline = ARGV.clone
354
-
355
- self << {:name => "help", :short => "-h", :long => "--help", :type => :bool, :help => "Show this message.", :priority => 1000}
356
- end
357
- end
358
- end
292
+
293
+ # Print post_options
294
+ print "#{@messages["post_options"]}\n" if @messages["post_options"]
295
+ end
296
+
297
+ #Creates a new OptionParser.
298
+ #
299
+ # Arguments:
300
+ # * <em>name</em>: Application name
301
+ # * <em>version</em>: Application version
302
+ # * <em>name</em>: Application description
303
+ # * <em>name</em>: Application usage
304
+ # * <em>messages</em>: Application message for help switch. Supported keys are
305
+ # * <em>:pre_usage</em>: Message to print before the usage string
306
+ # * <em>:pre_options</em>: Message to print before the options list
307
+ # * <em>:post_options</em>: Message to print after the options list
308
+ def initialize(args)
309
+ # Initialize types
310
+ @@valid_types = {bool: [], string: [String, ""], int: [Integer, 0], float: [Float, 0.0], choice: [String, ""], list: [Array, []], action: []}
311
+
312
+ # Copy arguments
313
+ @app_name = args[:name]
314
+ @app_version = args[:version]
315
+ @description = args[:description]
316
+ @usage = args[:usage]
317
+
318
+ # Copy messages
319
+ messages = args[:messages] || {}
320
+ if messages.is_a?(Hash) then
321
+ @messages = messages
322
+ else
323
+ @console.fatal(msg: "CowtechLib::OptionParser::initialize msgs argument must be an hash.")
324
+ end
325
+
326
+ # Initialize variables
327
+ @console = Console.new
328
+ @inserted = {name: [], short: [], long: []}
329
+ @options = {}
330
+ @options_map = {}
331
+ @args = []
332
+ @cmdline = ARGV.clone
333
+
334
+ self << {name: "help", short: "-h", long: "--help", type: :bool, help: "Show this message.", priority: 1000}
335
+ end
336
+ end
337
+ end
359
338
  end