cowtech-lib 1.9.8.1 → 2.0.0

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.
@@ -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