optimist 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 335830b11859ca8643cd5fe74d6444f147ab2873
4
+ data.tar.gz: 9a483cf4a178eaf83c6093ea177e29cc0cf63c32
5
+ SHA512:
6
+ metadata.gz: 7f18e81587cb3f617d7dfc26183c1d821a058891a638560c60c85202237fb084e57c77ffdc7b5a245a81e378769852b9e51827e8b41329298c7b7f0a3cb2f395
7
+ data.tar.gz: c6f2d0245b46cb58470b4ff6f31ac7df483c8d7f48c1d0da27cdcd3681fef55dced81a2765dc33035b808e7c7ba9519363019bd486f3496a74ebaa11f011f219
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.swp
13
+ *.o
14
+ *.a
15
+ mkmf.log
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ sudo: false
3
+ rvm:
4
+ - "2.2"
5
+ - "2.3.4"
6
+ - "2.5.1"
7
+ - jruby-head
8
+ matrix:
9
+ allow_failures:
10
+ - rvm: jruby-head
11
+ fast_finish: true
data/FAQ.txt ADDED
@@ -0,0 +1,92 @@
1
+ Optimist FAQ
2
+ -----------
3
+
4
+ Q: Why should I use Optimist?
5
+ A: Because it will take you fewer lines of code to parse commandline arguments
6
+ than anything else out there.
7
+
8
+ Like this:
9
+ opts = Optimist::options do
10
+ opt :monkey, "Use monkey mode"
11
+ opt :goat, "Use goat mode", :default => true
12
+ opt :num_limbs, "Set number of limbs", :default => 4
13
+ end
14
+
15
+ That's it. 'opts' will be a hash and you can do whatever you want with it.
16
+ You don't have to mix processing code with the declarations. You don't have
17
+ to make a class for every option (what is this, Java?). You don't have to
18
+ write more than 1 line of code per option.
19
+
20
+ Plus, you get a beautiful help screen that detects your terminal width and
21
+ wraps appropriately.
22
+
23
+ Q: What is the philosophy behind Optimist?
24
+ A: Optimist does the parsing and gives you a hash table of options. You then
25
+ write whatever fancy constraint logic you need as regular Ruby code operating
26
+ on that hash table.
27
+
28
+ (Optimist does support limited constraints (see #conflicts and #depends), but
29
+ any non-trivial program will probably need to get fancier.)
30
+
31
+ Then if you need to abort and tell the user to fix their command line at any
32
+ point, you can call #die and Optimist will do that for you in a pretty way.
33
+
34
+ Q: What happens to the other stuff on the commandline?
35
+ A: Anything Optimist doesn't recognize as an option or as an option parameter is
36
+ left in ARGV for you to process.
37
+
38
+ Q: Does Optimist support multiple-value arguments?
39
+ A: Yes. If you set the :type of an option to something plural, like ":ints",
40
+ ":strings", ":doubles", ":floats", ":ios", it will accept multiple arguments
41
+ on the commandline, and the value will be an array of the parameters.
42
+
43
+ Q: Does Optimist support arguments that can be given multiple times?
44
+ A: Yes. If you set :multi to true, then the argument can appear multiple times
45
+ on the commandline, and the value will be an array of the parameters.
46
+
47
+ Q: Does Optimist support subcommands?
48
+ A: Yes: you can direct Optimist to stop processing when it encounters certain
49
+ tokens. Then you can re-call Optimist with the subcommand-specific
50
+ configuration to process the rest of the commandline.
51
+
52
+ See the third example on the webpage.
53
+
54
+ (And if you don't know the subcommands ahead of time, you can call
55
+ #stop_on_unknown, which will cause Optimist to stop when it encounters any
56
+ unknown token. This might be more trouble than its worth if you're also
57
+ passing filenames on the commandline.)
58
+
59
+ Q: Why does Optimist disallow numeric short argument names, like '-1' and '-9'?
60
+ A: Because it's ambiguous whether these are arguments or negative integer or
61
+ floating-point parameters to arguments. E.g., is "-f -3" a negative floating
62
+ point parameter to -f, or two separate arguments?
63
+
64
+ Q: What was the big change in version 2.0?
65
+ A: The big change was boolean parameter (aka flag) handling. In pre-2.0,
66
+ not specifying a flag on the commandline would result in the option being set
67
+ to its default value; specifying it on the commandline would result in the
68
+ option being set to the opposite of its default value. This was weird for
69
+ options with a default of true:
70
+ opt :magic, "Use magic", default: true
71
+ Using --magic with the above configuration would result in a :magic => false
72
+ value in the options hash.
73
+
74
+ In 2.0, we introduce the GNU-style notion of a --no-x parameter. Now,
75
+ specifying --x will always set the option :x to true, regardless of its
76
+ default value, and specifying --no-x will always set the option :x to false,
77
+ regardless of its default value. The default value only comes into play when
78
+ neither form is given on the commandline.
79
+
80
+ E.g.:
81
+ opt :magic, "Use magic", :default => true
82
+
83
+ Using --magic will result in :magic => true, and --no-magic will result in
84
+ :magic => false, and neither will result in :magic => true.
85
+
86
+ There is one exception: if the option itself starts with a "no_", then you'll
87
+ get the opposite behavior:
88
+
89
+ opt :no_magic, "Don't use magic", :default => true
90
+
91
+ Using --magic will result in :no_magic => false, and --no-magic will result in
92
+ :no_magic => true, and neither will result in :no_magic => true.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gemspec
4
+ gemspec
@@ -0,0 +1,168 @@
1
+ == [3.0.0] / 2018-08-24
2
+
3
+ * The gem has been officially renamed to optimist
4
+
5
+ == [2.1.3] / 2018-07-05
6
+
7
+ * Refactor each option type into subclasses of Option. Define a registry for the registration of each option. This makes the code more modular and facilitates extension by allowing additional Option subclasses. (thanks @clxy)
8
+ * Fixed implementation of ignore_invalid_options. (thanks @metcalf)
9
+ * Various warning cleanup for ruby 2.1, 2.3, etc. (thanks @nanobowers)
10
+ * Optimist.die can now accept an error code.
11
+ * fixed default (thanks @nanobowers)
12
+ * Change from ruby license to MIT license in the code.
13
+
14
+ == [2.1.2] / 2015-03-10
15
+ * loosen mime-types requirements (for better ruby 1.8.7 support)
16
+ * use io/console gem instead of curses (for better jruby support)
17
+ * fix parsing bug when chronic gem is not available
18
+ * allow default array to be empty if a type is specified
19
+ * better specified license and better spec coverage
20
+
21
+ == [2.1.1] / 2015-01-03
22
+ * Remove curses as a hard dependency. It is optional. This can leverage the gem if it is present.
23
+ * Fix ruby -w warnings
24
+
25
+ == 2.1.0 / 2015-01-02
26
+ * Integer parser now supports underscore separator.
27
+ * Add Parser#usage and Parser#synopsis commands for creating a standard banner
28
+ message. Using Parser#banner directly will override both of those.
29
+ * Add Parser#ignore_invalid_options to prevent erroring on unknown options.
30
+ * Allow flags to act as switches if they have defaults set and no value is
31
+ passed on the commandline
32
+ * Parser#opt learned to accept a block or a :callback option which it will call
33
+ after parsing the option.
34
+ * Add Optimist::educate which displays the help message and dies.
35
+ * Reformat help message to be more GNUish.
36
+ * Fix command name in help message when script has no extension.
37
+ * Fix handling of newlines inside descriptions
38
+ * Documentation and other fixes.
39
+
40
+ == 2.0 / 2012-08-11
41
+ * Change flag logic: --no-X will always be false, and --X will always be true,
42
+ regardless of default.
43
+ * For flags that default to true, display --no-X instead of --X in the help
44
+ menu. Accept both versions on the commandline.
45
+ * Fix a spurious warning
46
+ * Update Rakefile to 1.9
47
+ * Minor documentation fixes
48
+
49
+ == 1.16.2 / 2010-04-06
50
+ * Bugfix in Optimist::options. Thanks to Brian C. Thomas for pointing it out.
51
+
52
+ == 1.16.1 / 2010-04-05
53
+ * Bugfix in Optimist::die method introduced in last release.
54
+
55
+ == 1.16 / 2010-04-01
56
+ * Add Optimist::with_standard_exception_handling method for easing the use of Parser directly.
57
+ * Handle scientific notation in float arguments, thanks to Will Fitzgerald.
58
+ * Drop hoe dependency.
59
+
60
+ == 1.15 / 2009-09-30
61
+ * Don't raise an exception when out of short arguments (thanks to Rafael
62
+ Sevilla for pointing out how dumb this behavior was).
63
+
64
+ == 1.14 / 2009-06-19
65
+ * Make :multi arguments default to [], not nil, when not set on the commandline.
66
+ * Minor commenting and error message improvements
67
+
68
+ == 1.13 / 2009-03-16
69
+ * Fix parsing of "--longarg=<value with spaces>".
70
+
71
+ == 1.12 / 2009-01-30
72
+ * Fix some unit test failures in the last release. Should be more careful.
73
+ * Make default short options only be assigned *after* all user-specified
74
+ short options. Now there's a little less juggling to do when you just
75
+ want to specify a few short options.
76
+
77
+ == 1.11 / 2009-01-29
78
+ * Set <opt>_given keys in the results hash for options that were specified
79
+ on the commandline.
80
+
81
+ == 1.10.2 / 2008-10-23
82
+ * No longer try `stty size` for screen size detection. Just use curses, and
83
+ screen users will have to deal with the screen clearing.
84
+
85
+ == 1.10.1 / 2008-10-22
86
+ * Options hash now responds to method calls as well as standard hash lookup.
87
+ * Default values for multi-occurrence parameters now autoboxed.
88
+ * The relationship between multi-value, multi-occurrence, and default values
89
+ improved and explained.
90
+ * Documentation improvements.
91
+
92
+ == 1.10 / 2008-10-21
93
+ * Added :io type for parameters that point to IO streams (filenames, URIs, etc).
94
+ * For screen size detection, first try `stty size` before loading Curses.
95
+ * Improved documentation.
96
+
97
+ == 1.9 / 2008-08-20
98
+ * Added 'stop_on_unknown' command to stop parsing on any unknown argument.
99
+ This is useful for handling sub-commands when you don't know the entire
100
+ set of commands up front. (E.g. if the initial arguments can change it.)
101
+ * Added a :multi option for parameters, signifying that they can be specified
102
+ multiple times.
103
+ * Added :ints, :strings, :doubles, and :floats option types, which can take
104
+ multiple arguments.
105
+
106
+ == 1.8.2 / 2008-06-25
107
+ * Bugfix for #conflicts and #depends error messages
108
+
109
+ == 1.8.1 / 2008-06-24
110
+ * Bugfix for short option autocreation
111
+ * More aggressive documentation
112
+
113
+ == 1.8 / 2008-06-16
114
+ * Sub-command support via Parser#stop_on
115
+
116
+ == 1.7.2 / 2008-01-16
117
+ * Ruby 1.9-ify. Apparently this means replacing :'s with ;'s.
118
+
119
+ == 1.7.1 / 2008-01-07
120
+ * Documentation improvements
121
+
122
+ == 1.7 / 2007-06-17
123
+ * Fix incorrect error message for multiple missing required arguments
124
+ (thanks to Neill Zero)
125
+
126
+ == 1.6 / 2007-04-01
127
+ * Don't attempt curses screen-width magic unless running on a terminal.
128
+
129
+ == 1.5 / 2007-03-31
130
+ * --help and --version do the right thing even if the rest of the
131
+ command line is incorrect.
132
+ * Added #conflicts and #depends to model dependencies and exclusivity
133
+ between arguments.
134
+ * Minor bugfixes.
135
+
136
+ == 1.4 / 2007-03-26
137
+ * Disable short options with :short => :none.
138
+ * Minor bugfixes and error message improvements.
139
+
140
+ == 1.3 / 2007-01-31
141
+ * Wrap at (screen width - 1) instead of screen width.
142
+ * User can override --help and --version.
143
+ * Bugfix in handling of -v and -h.
144
+ * More tests to confirm the above.
145
+
146
+ == 1.2 / 2007-01-31
147
+ * Minor documentation tweaks.
148
+ * Removed hoe dependency.
149
+
150
+ == 1.1 / 2007-01-30
151
+ * Optimist::options now passes any arguments as block arguments. Since
152
+ instance variables are not properly captured by the block, this
153
+ makes it slightly less noisy to pass them in as local variables.
154
+ (A real-life use for _why's cloaker!)
155
+ * Help display now preserves original argument order.
156
+ * Optimist::die now also has a single string form in case death is not
157
+ due to a single argument.
158
+ * Parser#text now an alias for Parser#banner, and can be called
159
+ multiple times, with the output being placed in the right position
160
+ in the help text.
161
+ * Slightly more indicative formatting for parameterized arguments.
162
+
163
+ == 1.0 / 2007-01-29
164
+ * Initial release.
165
+
166
+ [2.1.3]: https://github.com/ManageIQ/optimist/compare/v2.1.2...v2.1.3
167
+ [2.1.2]: https://github.com/ManageIQ/optimist/compare/v2.1.1...v2.1.2
168
+ [2.1.1]: https://github.com/ManageIQ/optimist/compare/v2.1.0...v2.1.1
@@ -0,0 +1,60 @@
1
+ # optimist
2
+
3
+ http://manageiq.github.io/optimist/
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/optimist.svg)](http://badge.fury.io/rb/optimist)
6
+ [![Build Status](https://travis-ci.org/ManageIQ/optimist.svg)](https://travis-ci.org/ManageIQ/optimist)
7
+ [![Code Climate](https://codeclimate.com/github/ManageIQ/optimist/badges/gpa.svg)](https://codeclimate.com/github/ManageIQ/optimist)
8
+ [![Coverage Status](http://img.shields.io/coveralls/ManageIQ/optimist.svg)](https://coveralls.io/r/ManageIQ/optimist)
9
+ [![Dependency Status](https://gemnasium.com/ManageIQ/optimist.svg)](https://gemnasium.com/ManageIQ/optimist)
10
+
11
+ ## Documentation
12
+
13
+ - Quickstart: See `Optimist.options` and then `Optimist::Parser#opt`.
14
+ - Examples: http://manageiq.github.io/optimist/.
15
+ - Wiki: http://github.com/ManageIQ/optimist/wiki
16
+
17
+ ## Description
18
+
19
+ Optimist is a commandline option parser for Ruby that just gets out of your way.
20
+ One line of code per option is all you need to write. For that, you get a nice
21
+ automatically-generated help page, robust option parsing, and sensible defaults
22
+ for everything you don't specify.
23
+
24
+ ## Features
25
+
26
+ - Dirt-simple usage.
27
+ - Single file. Throw it in lib/ if you don't want to make it a Rubygem dependency.
28
+ - Sensible defaults. No tweaking necessary, much tweaking possible.
29
+ - Support for long options, short options, subcommands, and automatic type validation and
30
+ conversion.
31
+ - Automatic help message generation, wrapped to current screen width.
32
+
33
+ ## Requirements
34
+
35
+ * A burning desire to write less code.
36
+
37
+ ## Install
38
+
39
+ * gem install optimist
40
+
41
+ ## Synopsis
42
+
43
+ ```ruby
44
+ require 'optimist'
45
+ opts = Optimist::options do
46
+ opt :monkey, "Use monkey mode" # flag --monkey, default false
47
+ opt :name, "Monkey name", :type => :string # string --name <s>, default nil
48
+ opt :num_limbs, "Number of limbs", :default => 4 # integer --num-limbs <i>, default to 4
49
+ end
50
+
51
+ p opts # a hash: { :monkey=>false, :name=>nil, :num_limbs=>4, :help=>false }
52
+ ```
53
+
54
+ ## License
55
+
56
+ Copyright &copy; 2008-2014 [William Morgan](http://masanjin.net/).
57
+
58
+ Copyright &copy; 2014 Red Hat, Inc.
59
+
60
+ Optimist is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -0,0 +1,15 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ task :default => :test
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs << 'test'
8
+ t.pattern = "test/**/*_test.rb"
9
+ end
10
+
11
+ begin
12
+ require 'coveralls/rake/task'
13
+ Coveralls::RakeTask.new
14
+ rescue LoadError
15
+ end
@@ -0,0 +1,1014 @@
1
+ # lib/optimist.rb -- optimist command-line processing library
2
+ # Copyright (c) 2008-2014 William Morgan.
3
+ # Copyright (c) 2014 Red Hat, Inc.
4
+ # optimist is licensed under the MIT license.
5
+
6
+ require 'date'
7
+
8
+ module Optimist
9
+ # note: this is duplicated in gemspec
10
+ # please change over there too
11
+ VERSION = "3.0.0"
12
+
13
+ ## Thrown by Parser in the event of a commandline error. Not needed if
14
+ ## you're using the Optimist::options entry.
15
+ class CommandlineError < StandardError
16
+ attr_reader :error_code
17
+
18
+ def initialize(msg, error_code = nil)
19
+ super(msg)
20
+ @error_code = error_code
21
+ end
22
+ end
23
+
24
+ ## Thrown by Parser if the user passes in '-h' or '--help'. Handled
25
+ ## automatically by Optimist#options.
26
+ class HelpNeeded < StandardError
27
+ end
28
+
29
+ ## Thrown by Parser if the user passes in '-v' or '--version'. Handled
30
+ ## automatically by Optimist#options.
31
+ class VersionNeeded < StandardError
32
+ end
33
+
34
+ ## Regex for floating point numbers
35
+ FLOAT_RE = /^-?((\d+(\.\d+)?)|(\.\d+))([eE][-+]?[\d]+)?$/
36
+
37
+ ## Regex for parameters
38
+ PARAM_RE = /^-(-|\.$|[^\d\.])/
39
+
40
+ ## The commandline parser. In typical usage, the methods in this class
41
+ ## will be handled internally by Optimist::options. In this case, only the
42
+ ## #opt, #banner and #version, #depends, and #conflicts methods will
43
+ ## typically be called.
44
+ ##
45
+ ## If you want to instantiate this class yourself (for more complicated
46
+ ## argument-parsing logic), call #parse to actually produce the output hash,
47
+ ## and consider calling it from within
48
+ ## Optimist::with_standard_exception_handling.
49
+ class Parser
50
+
51
+ ## The registry is a class-instance-variable map of option aliases to their subclassed Option class.
52
+ @registry = {}
53
+
54
+ ## The Option subclasses are responsible for registering themselves using this function.
55
+ def self.register(lookup, klass)
56
+ @registry[lookup.to_sym] = klass
57
+ end
58
+
59
+ ## Gets the class from the registry.
60
+ ## Can be given either a class-name, e.g. Integer, a string, e.g "integer", or a symbol, e.g :integer
61
+ def self.registry_getopttype(type)
62
+ return nil unless type
63
+ if type.respond_to?(:name)
64
+ type = type.name
65
+ lookup = type.downcase.to_sym
66
+ else
67
+ lookup = type.to_sym
68
+ end
69
+ raise ArgumentError, "Unsupported argument type '#{type}', registry lookup '#{lookup}'" unless @registry.has_key?(lookup)
70
+ return @registry[lookup].new
71
+ end
72
+
73
+ INVALID_SHORT_ARG_REGEX = /[\d-]/ #:nodoc:
74
+
75
+ ## The values from the commandline that were not interpreted by #parse.
76
+ attr_reader :leftovers
77
+
78
+ ## The complete configuration hashes for each option. (Mainly useful
79
+ ## for testing.)
80
+ attr_reader :specs
81
+
82
+ ## A flag that determines whether or not to raise an error if the parser is passed one or more
83
+ ## options that were not registered ahead of time. If 'true', then the parser will simply
84
+ ## ignore options that it does not recognize.
85
+ attr_accessor :ignore_invalid_options
86
+
87
+ ## Initializes the parser, and instance-evaluates any block given.
88
+ def initialize(*a, &b)
89
+ @version = nil
90
+ @leftovers = []
91
+ @specs = {}
92
+ @long = {}
93
+ @short = {}
94
+ @order = []
95
+ @constraints = []
96
+ @stop_words = []
97
+ @stop_on_unknown = false
98
+ @educate_on_error = false
99
+ @synopsis = nil
100
+ @usage = nil
101
+
102
+ # instance_eval(&b) if b # can't take arguments
103
+ cloaker(&b).bind(self).call(*a) if b
104
+ end
105
+
106
+ ## Define an option. +name+ is the option name, a unique identifier
107
+ ## for the option that you will use internally, which should be a
108
+ ## symbol or a string. +desc+ is a string description which will be
109
+ ## displayed in help messages.
110
+ ##
111
+ ## Takes the following optional arguments:
112
+ ##
113
+ ## [+:long+] Specify the long form of the argument, i.e. the form with two dashes. If unspecified, will be automatically derived based on the argument name by turning the +name+ option into a string, and replacing any _'s by -'s.
114
+ ## [+:short+] Specify the short form of the argument, i.e. the form with one dash. If unspecified, will be automatically derived from +name+. Use :none: to not have a short value.
115
+ ## [+:type+] Require that the argument take a parameter or parameters of type +type+. For a single parameter, the value can be a member of +SINGLE_ARG_TYPES+, or a corresponding Ruby class (e.g. +Integer+ for +:int+). For multiple-argument parameters, the value can be any member of +MULTI_ARG_TYPES+ constant. If unset, the default argument type is +:flag+, meaning that the argument does not take a parameter. The specification of +:type+ is not necessary if a +:default+ is given.
116
+ ## [+:default+] Set the default value for an argument. Without a default value, the hash returned by #parse (and thus Optimist::options) will have a +nil+ value for this key unless the argument is given on the commandline. The argument type is derived automatically from the class of the default value given, so specifying a +:type+ is not necessary if a +:default+ is given. (But see below for an important caveat when +:multi+: is specified too.) If the argument is a flag, and the default is set to +true+, then if it is specified on the the commandline the value will be +false+.
117
+ ## [+:required+] If set to +true+, the argument must be provided on the commandline.
118
+ ## [+:multi+] If set to +true+, allows multiple occurrences of the option on the commandline. Otherwise, only a single instance of the option is allowed. (Note that this is different from taking multiple parameters. See below.)
119
+ ##
120
+ ## Note that there are two types of argument multiplicity: an argument
121
+ ## can take multiple values, e.g. "--arg 1 2 3". An argument can also
122
+ ## be allowed to occur multiple times, e.g. "--arg 1 --arg 2".
123
+ ##
124
+ ## Arguments that take multiple values should have a +:type+ parameter
125
+ ## drawn from +MULTI_ARG_TYPES+ (e.g. +:strings+), or a +:default:+
126
+ ## value of an array of the correct type (e.g. [String]). The
127
+ ## value of this argument will be an array of the parameters on the
128
+ ## commandline.
129
+ ##
130
+ ## Arguments that can occur multiple times should be marked with
131
+ ## +:multi+ => +true+. The value of this argument will also be an array.
132
+ ## In contrast with regular non-multi options, if not specified on
133
+ ## the commandline, the default value will be [], not nil.
134
+ ##
135
+ ## These two attributes can be combined (e.g. +:type+ => +:strings+,
136
+ ## +:multi+ => +true+), in which case the value of the argument will be
137
+ ## an array of arrays.
138
+ ##
139
+ ## There's one ambiguous case to be aware of: when +:multi+: is true and a
140
+ ## +:default+ is set to an array (of something), it's ambiguous whether this
141
+ ## is a multi-value argument as well as a multi-occurrence argument.
142
+ ## In thise case, Optimist assumes that it's not a multi-value argument.
143
+ ## If you want a multi-value, multi-occurrence argument with a default
144
+ ## value, you must specify +:type+ as well.
145
+
146
+ def opt(name, desc = "", opts = {}, &b)
147
+ opts[:callback] ||= b if block_given?
148
+ opts[:desc] ||= desc
149
+
150
+ o = Option.create(name, desc, opts)
151
+
152
+ raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? o.name
153
+ raise ArgumentError, "long option name #{o.long.inspect} is already taken; please specify a (different) :long" if @long[o.long]
154
+ raise ArgumentError, "short option name #{o.short.inspect} is already taken; please specify a (different) :short" if @short[o.short]
155
+ @long[o.long] = o.name
156
+ @short[o.short] = o.name if o.short?
157
+ @specs[o.name] = o
158
+ @order << [:opt, o.name]
159
+ end
160
+
161
+ ## Sets the version string. If set, the user can request the version
162
+ ## on the commandline. Should probably be of the form "<program name>
163
+ ## <version number>".
164
+ def version(s = nil)
165
+ s ? @version = s : @version
166
+ end
167
+
168
+ ## Sets the usage string. If set the message will be printed as the
169
+ ## first line in the help (educate) output and ending in two new
170
+ ## lines.
171
+ def usage(s = nil)
172
+ s ? @usage = s : @usage
173
+ end
174
+
175
+ ## Adds a synopsis (command summary description) right below the
176
+ ## usage line, or as the first line if usage isn't specified.
177
+ def synopsis(s = nil)
178
+ s ? @synopsis = s : @synopsis
179
+ end
180
+
181
+ ## Adds text to the help display. Can be interspersed with calls to
182
+ ## #opt to build a multi-section help page.
183
+ def banner(s)
184
+ @order << [:text, s]
185
+ end
186
+ alias_method :text, :banner
187
+
188
+ ## Marks two (or more!) options as requiring each other. Only handles
189
+ ## undirected (i.e., mutual) dependencies. Directed dependencies are
190
+ ## better modeled with Optimist::die.
191
+ def depends(*syms)
192
+ syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
193
+ @constraints << [:depends, syms]
194
+ end
195
+
196
+ ## Marks two (or more!) options as conflicting.
197
+ def conflicts(*syms)
198
+ syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
199
+ @constraints << [:conflicts, syms]
200
+ end
201
+
202
+ ## Defines a set of words which cause parsing to terminate when
203
+ ## encountered, such that any options to the left of the word are
204
+ ## parsed as usual, and options to the right of the word are left
205
+ ## intact.
206
+ ##
207
+ ## A typical use case would be for subcommand support, where these
208
+ ## would be set to the list of subcommands. A subsequent Optimist
209
+ ## invocation would then be used to parse subcommand options, after
210
+ ## shifting the subcommand off of ARGV.
211
+ def stop_on(*words)
212
+ @stop_words = [*words].flatten
213
+ end
214
+
215
+ ## Similar to #stop_on, but stops on any unknown word when encountered
216
+ ## (unless it is a parameter for an argument). This is useful for
217
+ ## cases where you don't know the set of subcommands ahead of time,
218
+ ## i.e., without first parsing the global options.
219
+ def stop_on_unknown
220
+ @stop_on_unknown = true
221
+ end
222
+
223
+ ## Instead of displaying "Try --help for help." on an error
224
+ ## display the usage (via educate)
225
+ def educate_on_error
226
+ @educate_on_error = true
227
+ end
228
+
229
+ ## Parses the commandline. Typically called by Optimist::options,
230
+ ## but you can call it directly if you need more control.
231
+ ##
232
+ ## throws CommandlineError, HelpNeeded, and VersionNeeded exceptions.
233
+ def parse(cmdline = ARGV)
234
+ vals = {}
235
+ required = {}
236
+
237
+ opt :version, "Print version and exit" if @version && ! (@specs[:version] || @long["version"])
238
+ opt :help, "Show this message" unless @specs[:help] || @long["help"]
239
+
240
+ @specs.each do |sym, opts|
241
+ required[sym] = true if opts.required?
242
+ vals[sym] = opts.default
243
+ vals[sym] = [] if opts.multi && !opts.default # multi arguments default to [], not nil
244
+ end
245
+
246
+ resolve_default_short_options!
247
+
248
+ ## resolve symbols
249
+ given_args = {}
250
+ @leftovers = each_arg cmdline do |arg, params|
251
+ ## handle --no- forms
252
+ arg, negative_given = if arg =~ /^--no-([^-]\S*)$/
253
+ ["--#{$1}", true]
254
+ else
255
+ [arg, false]
256
+ end
257
+
258
+ sym = case arg
259
+ when /^-([^-])$/ then @short[$1]
260
+ when /^--([^-]\S*)$/ then @long[$1] || @long["no-#{$1}"]
261
+ else raise CommandlineError, "invalid argument syntax: '#{arg}'"
262
+ end
263
+
264
+ sym = nil if arg =~ /--no-/ # explicitly invalidate --no-no- arguments
265
+
266
+ next nil if ignore_invalid_options && !sym
267
+ raise CommandlineError, "unknown argument '#{arg}'" unless sym
268
+
269
+ if given_args.include?(sym) && !@specs[sym].multi?
270
+ raise CommandlineError, "option '#{arg}' specified multiple times"
271
+ end
272
+
273
+ given_args[sym] ||= {}
274
+ given_args[sym][:arg] = arg
275
+ given_args[sym][:negative_given] = negative_given
276
+ given_args[sym][:params] ||= []
277
+
278
+ # The block returns the number of parameters taken.
279
+ num_params_taken = 0
280
+
281
+ unless params.empty?
282
+ if @specs[sym].single_arg?
283
+ given_args[sym][:params] << params[0, 1] # take the first parameter
284
+ num_params_taken = 1
285
+ elsif @specs[sym].multi_arg?
286
+ given_args[sym][:params] << params # take all the parameters
287
+ num_params_taken = params.size
288
+ end
289
+ end
290
+
291
+ num_params_taken
292
+ end
293
+
294
+ ## check for version and help args
295
+ raise VersionNeeded if given_args.include? :version
296
+ raise HelpNeeded if given_args.include? :help
297
+
298
+ ## check constraint satisfaction
299
+ @constraints.each do |type, syms|
300
+ constraint_sym = syms.find { |sym| given_args[sym] }
301
+ next unless constraint_sym
302
+
303
+ case type
304
+ when :depends
305
+ syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym].long} requires --#{@specs[sym].long}" unless given_args.include? sym }
306
+ when :conflicts
307
+ syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym].long} conflicts with --#{@specs[sym].long}" if given_args.include?(sym) && (sym != constraint_sym) }
308
+ end
309
+ end
310
+
311
+ required.each do |sym, val|
312
+ raise CommandlineError, "option --#{@specs[sym].long} must be specified" unless given_args.include? sym
313
+ end
314
+
315
+ ## parse parameters
316
+ given_args.each do |sym, given_data|
317
+ arg, params, negative_given = given_data.values_at :arg, :params, :negative_given
318
+
319
+ opts = @specs[sym]
320
+ if params.empty? && !opts.flag?
321
+ raise CommandlineError, "option '#{arg}' needs a parameter" unless opts.default
322
+ params << (opts.array_default? ? opts.default.clone : [opts.default])
323
+ end
324
+
325
+ vals["#{sym}_given".intern] = true # mark argument as specified on the commandline
326
+
327
+ vals[sym] = opts.parse(params, negative_given)
328
+
329
+ if opts.single_arg?
330
+ if opts.multi? # multiple options, each with a single parameter
331
+ vals[sym] = vals[sym].map { |p| p[0] }
332
+ else # single parameter
333
+ vals[sym] = vals[sym][0][0]
334
+ end
335
+ elsif opts.multi_arg? && !opts.multi?
336
+ vals[sym] = vals[sym][0] # single option, with multiple parameters
337
+ end
338
+ # else: multiple options, with multiple parameters
339
+
340
+ opts.callback.call(vals[sym]) if opts.callback
341
+ end
342
+
343
+ ## modify input in place with only those
344
+ ## arguments we didn't process
345
+ cmdline.clear
346
+ @leftovers.each { |l| cmdline << l }
347
+
348
+ ## allow openstruct-style accessors
349
+ class << vals
350
+ def method_missing(m, *_args)
351
+ self[m] || self[m.to_s]
352
+ end
353
+ end
354
+ vals
355
+ end
356
+
357
+ ## Print the help message to +stream+.
358
+ def educate(stream = $stdout)
359
+ width # hack: calculate it now; otherwise we have to be careful not to
360
+ # call this unless the cursor's at the beginning of a line.
361
+
362
+ left = {}
363
+ @specs.each { |name, spec| left[name] = spec.educate }
364
+
365
+ leftcol_width = left.values.map(&:length).max || 0
366
+ rightcol_start = leftcol_width + 6 # spaces
367
+
368
+ unless @order.size > 0 && @order.first.first == :text
369
+ command_name = File.basename($0).gsub(/\.[^.]+$/, '')
370
+ stream.puts "Usage: #{command_name} #{@usage}\n" if @usage
371
+ stream.puts "#{@synopsis}\n" if @synopsis
372
+ stream.puts if @usage || @synopsis
373
+ stream.puts "#{@version}\n" if @version
374
+ stream.puts "Options:"
375
+ end
376
+
377
+ @order.each do |what, opt|
378
+ if what == :text
379
+ stream.puts wrap(opt)
380
+ next
381
+ end
382
+
383
+ spec = @specs[opt]
384
+ stream.printf " %-#{leftcol_width}s ", left[opt]
385
+ desc = spec.description_with_default
386
+
387
+ stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start)
388
+ end
389
+ end
390
+
391
+ def width #:nodoc:
392
+ @width ||= if $stdout.tty?
393
+ begin
394
+ require 'io/console'
395
+ w = IO.console.winsize.last
396
+ w.to_i > 0 ? w : 80
397
+ rescue LoadError, NoMethodError, Errno::ENOTTY, Errno::EBADF, Errno::EINVAL
398
+ legacy_width
399
+ end
400
+ else
401
+ 80
402
+ end
403
+ end
404
+
405
+ def legacy_width
406
+ # Support for older Rubies where io/console is not available
407
+ `tput cols`.to_i
408
+ rescue Errno::ENOENT
409
+ 80
410
+ end
411
+ private :legacy_width
412
+
413
+ def wrap(str, opts = {}) # :nodoc:
414
+ if str == ""
415
+ [""]
416
+ else
417
+ inner = false
418
+ str.split("\n").map do |s|
419
+ line = wrap_line s, opts.merge(:inner => inner)
420
+ inner = true
421
+ line
422
+ end.flatten
423
+ end
424
+ end
425
+
426
+ ## The per-parser version of Optimist::die (see that for documentation).
427
+ def die(arg, msg = nil, error_code = nil)
428
+ msg, error_code = nil, msg if msg.kind_of?(Integer)
429
+ if msg
430
+ $stderr.puts "Error: argument --#{@specs[arg].long} #{msg}."
431
+ else
432
+ $stderr.puts "Error: #{arg}."
433
+ end
434
+ if @educate_on_error
435
+ $stderr.puts
436
+ educate $stderr
437
+ else
438
+ $stderr.puts "Try --help for help."
439
+ end
440
+ exit(error_code || -1)
441
+ end
442
+
443
+ private
444
+
445
+ ## yield successive arg, parameter pairs
446
+ def each_arg(args)
447
+ remains = []
448
+ i = 0
449
+
450
+ until i >= args.length
451
+ return remains += args[i..-1] if @stop_words.member? args[i]
452
+ case args[i]
453
+ when /^--$/ # arg terminator
454
+ return remains += args[(i + 1)..-1]
455
+ when /^--(\S+?)=(.*)$/ # long argument with equals
456
+ num_params_taken = yield "--#{$1}", [$2]
457
+ if num_params_taken.nil?
458
+ remains << args[i]
459
+ if @stop_on_unknown
460
+ return remains += args[i + 1..-1]
461
+ end
462
+ end
463
+ i += 1
464
+ when /^--(\S+)$/ # long argument
465
+ params = collect_argument_parameters(args, i + 1)
466
+ num_params_taken = yield args[i], params
467
+
468
+ if num_params_taken.nil?
469
+ remains << args[i]
470
+ if @stop_on_unknown
471
+ return remains += args[i + 1..-1]
472
+ end
473
+ else
474
+ i += num_params_taken
475
+ end
476
+ i += 1
477
+ when /^-(\S+)$/ # one or more short arguments
478
+ short_remaining = ""
479
+ shortargs = $1.split(//)
480
+ shortargs.each_with_index do |a, j|
481
+ if j == (shortargs.length - 1)
482
+ params = collect_argument_parameters(args, i + 1)
483
+
484
+ num_params_taken = yield "-#{a}", params
485
+ unless num_params_taken
486
+ short_remaining << a
487
+ if @stop_on_unknown
488
+ remains << "-#{short_remaining}"
489
+ return remains += args[i + 1..-1]
490
+ end
491
+ else
492
+ i += num_params_taken
493
+ end
494
+ else
495
+ unless yield "-#{a}", []
496
+ short_remaining << a
497
+ if @stop_on_unknown
498
+ short_remaining += shortargs[j + 1..-1].join
499
+ remains << "-#{short_remaining}"
500
+ return remains += args[i + 1..-1]
501
+ end
502
+ end
503
+ end
504
+ end
505
+
506
+ unless short_remaining.empty?
507
+ remains << "-#{short_remaining}"
508
+ end
509
+ i += 1
510
+ else
511
+ if @stop_on_unknown
512
+ return remains += args[i..-1]
513
+ else
514
+ remains << args[i]
515
+ i += 1
516
+ end
517
+ end
518
+ end
519
+
520
+ remains
521
+ end
522
+
523
+ def collect_argument_parameters(args, start_at)
524
+ params = []
525
+ pos = start_at
526
+ while args[pos] && args[pos] !~ PARAM_RE && !@stop_words.member?(args[pos]) do
527
+ params << args[pos]
528
+ pos += 1
529
+ end
530
+ params
531
+ end
532
+
533
+ def resolve_default_short_options!
534
+ @order.each do |type, name|
535
+ opts = @specs[name]
536
+ next if type != :opt || opts.short
537
+
538
+ c = opts.long.split(//).find { |d| d !~ INVALID_SHORT_ARG_REGEX && !@short.member?(d) }
539
+ if c # found a character to use
540
+ opts.short = c
541
+ @short[c] = name
542
+ end
543
+ end
544
+ end
545
+
546
+ def wrap_line(str, opts = {})
547
+ prefix = opts[:prefix] || 0
548
+ width = opts[:width] || (self.width - 1)
549
+ start = 0
550
+ ret = []
551
+ until start > str.length
552
+ nextt =
553
+ if start + width >= str.length
554
+ str.length
555
+ else
556
+ x = str.rindex(/\s/, start + width)
557
+ x = str.index(/\s/, start) if x && x < start
558
+ x || str.length
559
+ end
560
+ ret << ((ret.empty? && !opts[:inner]) ? "" : " " * prefix) + str[start...nextt]
561
+ start = nextt + 1
562
+ end
563
+ ret
564
+ end
565
+
566
+ ## instance_eval but with ability to handle block arguments
567
+ ## thanks to _why: http://redhanded.hobix.com/inspect/aBlockCostume.html
568
+ def cloaker(&b)
569
+ (class << self; self; end).class_eval do
570
+ define_method :cloaker_, &b
571
+ meth = instance_method :cloaker_
572
+ remove_method :cloaker_
573
+ meth
574
+ end
575
+ end
576
+ end
577
+
578
+ class Option
579
+
580
+ attr_accessor :name, :short, :long, :default
581
+ attr_writer :multi_given
582
+
583
+ def initialize
584
+ @long = nil
585
+ @short = nil
586
+ @name = nil
587
+ @multi_given = false
588
+ @hidden = false
589
+ @default = nil
590
+ @optshash = Hash.new()
591
+ end
592
+
593
+ def opts (key)
594
+ @optshash[key]
595
+ end
596
+
597
+ def opts= (o)
598
+ @optshash = o
599
+ end
600
+
601
+ ## Indicates a flag option, which is an option without an argument
602
+ def flag? ; false ; end
603
+ def single_arg?
604
+ !self.multi_arg? && !self.flag?
605
+ end
606
+
607
+ def multi ; @multi_given ; end
608
+ alias multi? multi
609
+
610
+ ## Indicates that this is a multivalued (Array type) argument
611
+ def multi_arg? ; false ; end
612
+ ## note: Option-Types with both multi_arg? and flag? false are single-parameter (normal) options.
613
+
614
+ def array_default? ; self.default.kind_of?(Array) ; end
615
+
616
+ def short? ; short && short != :none ; end
617
+
618
+ def callback ; opts(:callback) ; end
619
+ def desc ; opts(:desc) ; end
620
+
621
+ def required? ; opts(:required) ; end
622
+
623
+ def parse (_paramlist, _neg_given)
624
+ raise NotImplementedError, "parse must be overridden for newly registered type"
625
+ end
626
+
627
+ # provide type-format string. default to empty, but user should probably override it
628
+ def type_format ; "" ; end
629
+
630
+ def educate
631
+ (short? ? "-#{short}, " : "") + "--#{long}" + type_format + (flag? && default ? ", --no-#{long}" : "")
632
+ end
633
+
634
+ ## Format the educate-line description including the default-value(s)
635
+ def description_with_default
636
+ return desc unless default
637
+ default_s = case default
638
+ when $stdout then '<stdout>'
639
+ when $stdin then '<stdin>'
640
+ when $stderr then '<stderr>'
641
+ when Array
642
+ default.join(', ')
643
+ else
644
+ default.to_s
645
+ end
646
+ defword = desc.end_with?('.') ? 'Default' : 'default'
647
+ return "#{desc} (#{defword}: #{default_s})"
648
+ end
649
+
650
+ ## Provide a way to register symbol aliases to the Parser
651
+ def self.register_alias(*alias_keys)
652
+ alias_keys.each do |alias_key|
653
+ # pass in the alias-key and the class
654
+ Parser.register(alias_key, self)
655
+ end
656
+ end
657
+
658
+ ## Factory class methods ...
659
+
660
+ # Determines which type of object to create based on arguments passed
661
+ # to +Optimist::opt+. This is trickier in Optimist, than other cmdline
662
+ # parsers (e.g. Slop) because we allow the +default:+ to be able to
663
+ # set the option's type.
664
+ def self.create(name, desc="", opts={}, settings={})
665
+
666
+ opttype = Optimist::Parser.registry_getopttype(opts[:type])
667
+ opttype_from_default = get_klass_from_default(opts, opttype)
668
+
669
+ raise ArgumentError, ":type specification and default type don't match (default type is #{opttype_from_default.class})" if opttype && opttype_from_default && (opttype.class != opttype_from_default.class)
670
+
671
+ opt_inst = (opttype || opttype_from_default || Optimist::BooleanOption.new)
672
+
673
+ ## fill in :long
674
+ opt_inst.long = handle_long_opt(opts[:long], name)
675
+
676
+ ## fill in :short
677
+ opt_inst.short = handle_short_opt(opts[:short])
678
+
679
+ ## fill in :multi
680
+ multi_given = opts[:multi] || false
681
+ opt_inst.multi_given = multi_given
682
+
683
+ ## fill in :default for flags
684
+ defvalue = opts[:default] || opt_inst.default
685
+
686
+ ## autobox :default for :multi (multi-occurrence) arguments
687
+ defvalue = [defvalue] if defvalue && multi_given && !defvalue.kind_of?(Array)
688
+ opt_inst.default = defvalue
689
+ opt_inst.name = name
690
+ opt_inst.opts = opts
691
+ opt_inst
692
+ end
693
+
694
+ private
695
+
696
+ def self.get_type_from_disdef(optdef, opttype, disambiguated_default)
697
+ if disambiguated_default.is_a? Array
698
+ return(optdef.first.class.name.downcase + "s") if !optdef.empty?
699
+ if opttype
700
+ raise ArgumentError, "multiple argument type must be plural" unless opttype.multi_arg?
701
+ return nil
702
+ else
703
+ raise ArgumentError, "multiple argument type cannot be deduced from an empty array"
704
+ end
705
+ end
706
+ return disambiguated_default.class.name.downcase
707
+ end
708
+
709
+ def self.get_klass_from_default(opts, opttype)
710
+ ## for options with :multi => true, an array default doesn't imply
711
+ ## a multi-valued argument. for that you have to specify a :type
712
+ ## as well. (this is how we disambiguate an ambiguous situation;
713
+ ## see the docs for Parser#opt for details.)
714
+
715
+ disambiguated_default = if opts[:multi] && opts[:default].is_a?(Array) && opttype.nil?
716
+ opts[:default].first
717
+ else
718
+ opts[:default]
719
+ end
720
+
721
+ return nil if disambiguated_default.nil?
722
+ type_from_default = get_type_from_disdef(opts[:default], opttype, disambiguated_default)
723
+ return Optimist::Parser.registry_getopttype(type_from_default)
724
+ end
725
+
726
+ def self.handle_long_opt(lopt, name)
727
+ lopt = lopt ? lopt.to_s : name.to_s.gsub("_", "-")
728
+ lopt = case lopt
729
+ when /^--([^-].*)$/ then $1
730
+ when /^[^-]/ then lopt
731
+ else raise ArgumentError, "invalid long option name #{lopt.inspect}"
732
+ end
733
+ end
734
+
735
+ def self.handle_short_opt(sopt)
736
+ sopt = sopt.to_s if sopt && sopt != :none
737
+ sopt = case sopt
738
+ when /^-(.)$/ then $1
739
+ when nil, :none, /^.$/ then sopt
740
+ else raise ArgumentError, "invalid short option name '#{sopt.inspect}'"
741
+ end
742
+
743
+ if sopt
744
+ raise ArgumentError, "a short option name can't be a number or a dash" if sopt =~ ::Optimist::Parser::INVALID_SHORT_ARG_REGEX
745
+ end
746
+ return sopt
747
+ end
748
+
749
+ end
750
+
751
+ # Flag option. Has no arguments. Can be negated with "no-".
752
+ class BooleanOption < Option
753
+ register_alias :flag, :bool, :boolean, :trueclass, :falseclass
754
+ def initialize
755
+ super()
756
+ @default = false
757
+ end
758
+ def flag? ; true ; end
759
+ def parse(_paramlist, neg_given)
760
+ return(self.name.to_s =~ /^no_/ ? neg_given : !neg_given)
761
+ end
762
+ end
763
+
764
+ # Floating point number option class.
765
+ class FloatOption < Option
766
+ register_alias :float, :double
767
+ def type_format ; "=<f>" ; end
768
+ def parse(paramlist, _neg_given)
769
+ paramlist.map do |pg|
770
+ pg.map do |param|
771
+ raise CommandlineError, "option '#{self.name}' needs a floating-point number" unless param.is_a?(Numeric) || param =~ FLOAT_RE
772
+ param.to_f
773
+ end
774
+ end
775
+ end
776
+ end
777
+
778
+ # Integer number option class.
779
+ class IntegerOption < Option
780
+ register_alias :int, :integer, :fixnum
781
+ def type_format ; "=<i>" ; end
782
+ def parse(paramlist, _neg_given)
783
+ paramlist.map do |pg|
784
+ pg.map do |param|
785
+ raise CommandlineError, "option '#{self.name}' needs an integer" unless param.is_a?(Numeric) || param =~ /^-?[\d_]+$/
786
+ param.to_i
787
+ end
788
+ end
789
+ end
790
+ end
791
+
792
+ # Option class for handling IO objects and URLs.
793
+ # Note that this will return the file-handle, not the file-name
794
+ # in the case of file-paths given to it.
795
+ class IOOption < Option
796
+ register_alias :io
797
+ def type_format ; "=<filename/uri>" ; end
798
+ def parse(paramlist, _neg_given)
799
+ paramlist.map do |pg|
800
+ pg.map do |param|
801
+ if param =~ /^(stdin|-)$/i
802
+ $stdin
803
+ else
804
+ require 'open-uri'
805
+ begin
806
+ open param
807
+ rescue SystemCallError => e
808
+ raise CommandlineError, "file or url for option '#{self.name}' cannot be opened: #{e.message}"
809
+ end
810
+ end
811
+ end
812
+ end
813
+ end
814
+ end
815
+
816
+ # Option class for handling Strings.
817
+ class StringOption < Option
818
+ register_alias :string
819
+ def type_format ; "=<s>" ; end
820
+ def parse(paramlist, _neg_given)
821
+ paramlist.map { |pg| pg.map(&:to_s) }
822
+ end
823
+ end
824
+
825
+ # Option for dates. Uses Chronic if it exists.
826
+ class DateOption < Option
827
+ register_alias :date
828
+ def type_format ; "=<date>" ; end
829
+ def parse(paramlist, _neg_given)
830
+ paramlist.map do |pg|
831
+ pg.map do |param|
832
+ next param if param.is_a?(Date)
833
+ begin
834
+ begin
835
+ require 'chronic'
836
+ time = Chronic.parse(param)
837
+ rescue LoadError
838
+ # chronic is not available
839
+ end
840
+ time ? Date.new(time.year, time.month, time.day) : Date.parse(param)
841
+ rescue ArgumentError
842
+ raise CommandlineError, "option '#{self.name}' needs a date"
843
+ end
844
+ end
845
+ end
846
+ end
847
+ end
848
+
849
+ ### MULTI_OPT_TYPES :
850
+ ## The set of values that indicate a multiple-parameter option (i.e., that
851
+ ## takes multiple space-separated values on the commandline) when passed as
852
+ ## the +:type+ parameter of #opt.
853
+
854
+ # Option class for handling multiple Integers
855
+ class IntegerArrayOption < IntegerOption
856
+ register_alias :fixnums, :ints, :integers
857
+ def type_format ; "=<i+>" ; end
858
+ def multi_arg? ; true ; end
859
+ end
860
+
861
+ # Option class for handling multiple Floats
862
+ class FloatArrayOption < FloatOption
863
+ register_alias :doubles, :floats
864
+ def type_format ; "=<f+>" ; end
865
+ def multi_arg? ; true ; end
866
+ end
867
+
868
+ # Option class for handling multiple Strings
869
+ class StringArrayOption < StringOption
870
+ register_alias :strings
871
+ def type_format ; "=<s+>" ; end
872
+ def multi_arg? ; true ; end
873
+ end
874
+
875
+ # Option class for handling multiple dates
876
+ class DateArrayOption < DateOption
877
+ register_alias :dates
878
+ def type_format ; "=<date+>" ; end
879
+ def multi_arg? ; true ; end
880
+ end
881
+
882
+ # Option class for handling Files/URLs via 'open'
883
+ class IOArrayOption < IOOption
884
+ register_alias :ios
885
+ def type_format ; "=<filename/uri+>" ; end
886
+ def multi_arg? ; true ; end
887
+ end
888
+
889
+ ## The easy, syntactic-sugary entry method into Optimist. Creates a Parser,
890
+ ## passes the block to it, then parses +args+ with it, handling any errors or
891
+ ## requests for help or version information appropriately (and then exiting).
892
+ ## Modifies +args+ in place. Returns a hash of option values.
893
+ ##
894
+ ## The block passed in should contain zero or more calls to +opt+
895
+ ## (Parser#opt), zero or more calls to +text+ (Parser#text), and
896
+ ## probably a call to +version+ (Parser#version).
897
+ ##
898
+ ## The returned block contains a value for every option specified with
899
+ ## +opt+. The value will be the value given on the commandline, or the
900
+ ## default value if the option was not specified on the commandline. For
901
+ ## every option specified on the commandline, a key "<option
902
+ ## name>_given" will also be set in the hash.
903
+ ##
904
+ ## Example:
905
+ ##
906
+ ## require 'optimist'
907
+ ## opts = Optimist::options do
908
+ ## opt :monkey, "Use monkey mode" # a flag --monkey, defaulting to false
909
+ ## opt :name, "Monkey name", :type => :string # a string --name <s>, defaulting to nil
910
+ ## opt :num_limbs, "Number of limbs", :default => 4 # an integer --num-limbs <i>, defaulting to 4
911
+ ## end
912
+ ##
913
+ ## ## if called with no arguments
914
+ ## p opts # => {:monkey=>false, :name=>nil, :num_limbs=>4, :help=>false}
915
+ ##
916
+ ## ## if called with --monkey
917
+ ## p opts # => {:monkey=>true, :name=>nil, :num_limbs=>4, :help=>false, :monkey_given=>true}
918
+ ##
919
+ ## See more examples at http://optimist.rubyforge.org.
920
+ def options(args = ARGV, *a, &b)
921
+ @last_parser = Parser.new(*a, &b)
922
+ with_standard_exception_handling(@last_parser) { @last_parser.parse args }
923
+ end
924
+
925
+ ## If Optimist::options doesn't do quite what you want, you can create a Parser
926
+ ## object and call Parser#parse on it. That method will throw CommandlineError,
927
+ ## HelpNeeded and VersionNeeded exceptions when necessary; if you want to
928
+ ## have these handled for you in the standard manner (e.g. show the help
929
+ ## and then exit upon an HelpNeeded exception), call your code from within
930
+ ## a block passed to this method.
931
+ ##
932
+ ## Note that this method will call System#exit after handling an exception!
933
+ ##
934
+ ## Usage example:
935
+ ##
936
+ ## require 'optimist'
937
+ ## p = Optimist::Parser.new do
938
+ ## opt :monkey, "Use monkey mode" # a flag --monkey, defaulting to false
939
+ ## opt :goat, "Use goat mode", :default => true # a flag --goat, defaulting to true
940
+ ## end
941
+ ##
942
+ ## opts = Optimist::with_standard_exception_handling p do
943
+ ## o = p.parse ARGV
944
+ ## raise Optimist::HelpNeeded if ARGV.empty? # show help screen
945
+ ## o
946
+ ## end
947
+ ##
948
+ ## Requires passing in the parser object.
949
+
950
+ def with_standard_exception_handling(parser)
951
+ yield
952
+ rescue CommandlineError => e
953
+ parser.die(e.message, nil, e.error_code)
954
+ rescue HelpNeeded
955
+ parser.educate
956
+ exit
957
+ rescue VersionNeeded
958
+ puts parser.version
959
+ exit
960
+ end
961
+
962
+ ## Informs the user that their usage of 'arg' was wrong, as detailed by
963
+ ## 'msg', and dies. Example:
964
+ ##
965
+ ## options do
966
+ ## opt :volume, :default => 0.0
967
+ ## end
968
+ ##
969
+ ## die :volume, "too loud" if opts[:volume] > 10.0
970
+ ## die :volume, "too soft" if opts[:volume] < 0.1
971
+ ##
972
+ ## In the one-argument case, simply print that message, a notice
973
+ ## about -h, and die. Example:
974
+ ##
975
+ ## options do
976
+ ## opt :whatever # ...
977
+ ## end
978
+ ##
979
+ ## Optimist::die "need at least one filename" if ARGV.empty?
980
+ ##
981
+ ## An exit code can be provide if needed
982
+ ##
983
+ ## Optimist::die "need at least one filename", -2 if ARGV.empty?
984
+ def die(arg, msg = nil, error_code = nil)
985
+ if @last_parser
986
+ @last_parser.die arg, msg, error_code
987
+ else
988
+ raise ArgumentError, "Optimist::die can only be called after Optimist::options"
989
+ end
990
+ end
991
+
992
+ ## Displays the help message and dies. Example:
993
+ ##
994
+ ## options do
995
+ ## opt :volume, :default => 0.0
996
+ ## banner <<-EOS
997
+ ## Usage:
998
+ ## #$0 [options] <name>
999
+ ## where [options] are:
1000
+ ## EOS
1001
+ ## end
1002
+ ##
1003
+ ## Optimist::educate if ARGV.empty?
1004
+ def educate
1005
+ if @last_parser
1006
+ @last_parser.educate
1007
+ exit
1008
+ else
1009
+ raise ArgumentError, "Optimist::educate can only be called after Optimist::options"
1010
+ end
1011
+ end
1012
+
1013
+ module_function :options, :die, :educate, :with_standard_exception_handling
1014
+ end # module