Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
abbc14e965 | |||
3518141baa | |||
33c000a6ca | |||
dfb7ff75cb | |||
d011cdc374 | |||
3709cc7fef | |||
e852d2755c | |||
6cf70753f4 | |||
80b2f7b63c | |||
72834425c3 | |||
1b49c06a85 | |||
4c6f8c0250 | |||
8842a855d8 | |||
b79acd049f | |||
0eb754814e | |||
d33d082272 | |||
a78ee7275e | |||
f74253844b | |||
4e18e729c3 | |||
2099aaa6e0 | |||
31c63790f9 | |||
5b07b4da96 | |||
c5ea73acfd | |||
34ee9a1b09 | |||
5eca5e7657 | |||
64e084b0d4 |
22
.gitignore
vendored
22
.gitignore
vendored
@ -1,17 +1,5 @@
|
|||||||
*.gem
|
/.yardoc/
|
||||||
*.rbc
|
/coverage/
|
||||||
.bundle
|
/doc/
|
||||||
.config
|
/pkg/
|
||||||
.yardoc
|
/rdoc/
|
||||||
Gemfile.lock
|
|
||||||
InstalledFiles
|
|
||||||
_yardoc
|
|
||||||
coverage
|
|
||||||
doc/
|
|
||||||
lib/bundler/man
|
|
||||||
pkg
|
|
||||||
rdoc
|
|
||||||
spec/reports
|
|
||||||
test/tmp
|
|
||||||
test/version_tmp
|
|
||||||
tmp
|
|
||||||
|
46
Gemfile.lock
Normal file
46
Gemfile.lock
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
PATH
|
||||||
|
remote: .
|
||||||
|
specs:
|
||||||
|
yawpa (1.2.0)
|
||||||
|
|
||||||
|
GEM
|
||||||
|
remote: https://rubygems.org/
|
||||||
|
specs:
|
||||||
|
diff-lcs (1.3)
|
||||||
|
docile (1.1.5)
|
||||||
|
json (2.1.0)
|
||||||
|
rake (12.0.0)
|
||||||
|
rdoc (5.1.0)
|
||||||
|
rspec (3.6.0)
|
||||||
|
rspec-core (~> 3.6.0)
|
||||||
|
rspec-expectations (~> 3.6.0)
|
||||||
|
rspec-mocks (~> 3.6.0)
|
||||||
|
rspec-core (3.6.0)
|
||||||
|
rspec-support (~> 3.6.0)
|
||||||
|
rspec-expectations (3.6.0)
|
||||||
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
|
rspec-support (~> 3.6.0)
|
||||||
|
rspec-mocks (3.6.0)
|
||||||
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
|
rspec-support (~> 3.6.0)
|
||||||
|
rspec-support (3.6.0)
|
||||||
|
simplecov (0.15.0)
|
||||||
|
docile (~> 1.1.0)
|
||||||
|
json (>= 1.8, < 3)
|
||||||
|
simplecov-html (~> 0.10.0)
|
||||||
|
simplecov-html (0.10.2)
|
||||||
|
yard (0.9.9)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
ruby
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
rake
|
||||||
|
rdoc
|
||||||
|
rspec
|
||||||
|
simplecov
|
||||||
|
yard
|
||||||
|
yawpa!
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
1.10.6
|
152
README.md
152
README.md
@ -2,64 +2,124 @@
|
|||||||
|
|
||||||
Yet Another Way to Parse Arguments is an argument-parsing library for Ruby.
|
Yet Another Way to Parse Arguments is an argument-parsing library for Ruby.
|
||||||
|
|
||||||
|
[](http://badge.fury.io/rb/yawpa)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- POSIX or non-POSIX mode (supports subcommands using POSIX mode)
|
- POSIX or non-POSIX mode (supports subcommands using POSIX mode)
|
||||||
- Options can require an arbitrary number of parameters
|
- Options can require an arbitrary number of parameters
|
||||||
- Options can be defined with a range specifying the allowed number of parameters
|
- Options can be defined with a range specifying the allowed number of parameters
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Add this line to your application's Gemfile:
|
|
||||||
|
|
||||||
gem 'yawpa'
|
|
||||||
|
|
||||||
And then execute:
|
|
||||||
|
|
||||||
$ bundle
|
|
||||||
|
|
||||||
Or install it yourself as:
|
|
||||||
|
|
||||||
$ gem install yawpa
|
|
||||||
|
|
||||||
## Example 1
|
## Example 1
|
||||||
|
|
||||||
require 'yawpa'
|
```ruby
|
||||||
|
require "yawpa"
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
version: {},
|
version: {},
|
||||||
verbose: {short: 'v'},
|
verbose: {short: "v"},
|
||||||
get: {nargs: 1},
|
get: {nargs: 1},
|
||||||
set: {nargs: 2},
|
set: {nargs: 2},
|
||||||
}
|
}
|
||||||
opts, args = Yawpa.parse(ARGV, options)
|
opts, args = Yawpa.parse(ARGV, options)
|
||||||
opts.each_pair do |opt, val|
|
opts.each_pair do |opt, val|
|
||||||
end
|
end
|
||||||
|
```
|
||||||
|
|
||||||
## Example 2
|
## Example 2
|
||||||
|
|
||||||
require 'yawpa'
|
```ruby
|
||||||
|
require "yawpa"
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
version: {},
|
version: {},
|
||||||
help: {short: 'h'},
|
help: {short: "h"},
|
||||||
}
|
}
|
||||||
opts, args = Yawpa.parse(ARGV, options, posix_order: true)
|
opts, args = Yawpa.parse(ARGV, options, posix_order: true)
|
||||||
if opts[:version]
|
if opts[:version]
|
||||||
puts "my app, version 1.2.3"
|
puts "my app, version 1.2.3"
|
||||||
end
|
end
|
||||||
if args[0] == 'subcommand'
|
if args[0] == "subcommand"
|
||||||
subcommand_options = {
|
subcommand_options = {
|
||||||
'server': {nargs: (1..2), short: 's'},
|
"server": {nargs: (1..2), short: "s"},
|
||||||
'dst': {nargs: 1, short: 'd'},
|
"dst": {nargs: 1, short: "d"},
|
||||||
}
|
}
|
||||||
opts, args = Yawpa.parse(args, subcommand_options)
|
opts, args = Yawpa.parse(args, subcommand_options)
|
||||||
end
|
end
|
||||||
|
```
|
||||||
|
|
||||||
## Contributing
|
## Using Yawpa.parse()
|
||||||
|
|
||||||
1. Fork it
|
```ruby
|
||||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
opts, args = Yawpa.parse(params, options, flags = {})
|
||||||
3. Commit your changes (`git commit -am 'Added some feature'`)
|
```
|
||||||
4. Push to the branch (`git push origin my-new-feature`)
|
|
||||||
5. Create new Pull Request
|
Parse input parameters looking for options according to rules given in flags
|
||||||
|
|
||||||
|
- `params` is the list of program parameters to parse.
|
||||||
|
- `options` is a hash containing the long option names as keys, and hashes
|
||||||
|
containing special flags for the options as values (example below).
|
||||||
|
Possible values:
|
||||||
|
- `nil`: No special flags for this option (equivalent to `{}`)
|
||||||
|
- `:boolean`: The option is a toggleable boolean option (equivalent to
|
||||||
|
`{boolean: true}`)
|
||||||
|
- `Hash`: Possible option flags:
|
||||||
|
- `:short`: specify a short option letter to associate with the long option
|
||||||
|
- `:nargs`: specify an exact number or range of possible numbers of
|
||||||
|
arguments to the option
|
||||||
|
- `:boolean`: if true, specify that the option is a toggleable boolean
|
||||||
|
option and allow a prefix of "no" to turn it off.
|
||||||
|
- `flags` is optional. It supports the following keys:
|
||||||
|
- `:posix_order`: Stop processing parameters when a non-option is seen.
|
||||||
|
Set this to `true` if you want to implement subcommands.
|
||||||
|
|
||||||
|
An ArgumentParsingException will be raised if an unknown option is observed
|
||||||
|
or insufficient arguments are present for an option.
|
||||||
|
|
||||||
|
### Example `options`
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
{
|
||||||
|
version: nil,
|
||||||
|
verbose: {short: 'v'},
|
||||||
|
server: {nargs: (1..2)},
|
||||||
|
username: {nargs: 1},
|
||||||
|
password: {nargs: 1},
|
||||||
|
color: :boolean,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The keys of the `options` hash can be either strings or symbols.
|
||||||
|
|
||||||
|
Possible option flags:
|
||||||
|
|
||||||
|
- `:short`: specify a short option letter to associate with the long option
|
||||||
|
- `:nargs`: specify an exact number or range of possible numbers of
|
||||||
|
arguments to the option
|
||||||
|
- `:boolean`: if true, specify that the option is a toggleable boolean
|
||||||
|
option and allow a prefix of "no" to turn it off.
|
||||||
|
|
||||||
|
### Return values
|
||||||
|
|
||||||
|
The returned `opts` value will be a hash with the observed options as
|
||||||
|
keys and any option arguments as values.
|
||||||
|
The returned `args` will be an array of the unprocessed parameters (if
|
||||||
|
`:posix_order` was passed in `flags`, this array might contain further
|
||||||
|
options that were not processed after observing a non-option parameters).
|
||||||
|
|
||||||
|
## Release Notes
|
||||||
|
|
||||||
|
### v1.2.0
|
||||||
|
|
||||||
|
- Always return non-frozen strings
|
||||||
|
|
||||||
|
### v1.1.0
|
||||||
|
|
||||||
|
- Add `:boolean` option flag.
|
||||||
|
- Support `nil` or `:boolean` as shortcut option configuration values.
|
||||||
|
- Update documentation to YARD.
|
||||||
|
- Update specs to RSpec 3.
|
||||||
|
|
||||||
|
### v1.0.0
|
||||||
|
|
||||||
|
- Initial Release
|
||||||
|
13
Rakefile
13
Rakefile
@ -1,13 +0,0 @@
|
|||||||
require "bundler/gem_tasks"
|
|
||||||
require 'rspec/core/rake_task'
|
|
||||||
require "rdoc/task"
|
|
||||||
|
|
||||||
RSpec::Core::RakeTask.new('spec')
|
|
||||||
|
|
||||||
task :default => :spec
|
|
||||||
|
|
||||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
||||||
rdoc.rdoc_dir = 'rdoc'
|
|
||||||
rdoc.title = 'Yet Another Way to Parse Arguments'
|
|
||||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
||||||
end
|
|
18
Rakefile.rb
Normal file
18
Rakefile.rb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
require "bundler"
|
||||||
|
begin
|
||||||
|
Bundler.setup(:default, :development)
|
||||||
|
rescue Bundler::BundlerError => e
|
||||||
|
raise LoadError.new("Unable to setup Bundler; you might need to `bundle install`: #{e.message}")
|
||||||
|
end
|
||||||
|
require "bundler/gem_tasks"
|
||||||
|
require 'rspec/core/rake_task'
|
||||||
|
require "yard"
|
||||||
|
|
||||||
|
RSpec::Core::RakeTask.new('spec')
|
||||||
|
|
||||||
|
task :default => :spec
|
||||||
|
|
||||||
|
YARD::Rake::YardocTask.new do |yard|
|
||||||
|
yard.options = ["--title", "Yet Another Way to Parse Arguments"]
|
||||||
|
yard.files = ["lib/**/*.rb"]
|
||||||
|
end
|
298
lib/yawpa.rb
298
lib/yawpa.rb
@ -7,156 +7,196 @@ require "yawpa/version"
|
|||||||
# it just provides a simple functional interface for parsing options,
|
# it just provides a simple functional interface for parsing options,
|
||||||
# supporting subcommands and arbitrary numbers of arguments for each option.
|
# supporting subcommands and arbitrary numbers of arguments for each option.
|
||||||
#
|
#
|
||||||
# == Features
|
# Features:
|
||||||
#
|
|
||||||
# - POSIX or non-POSIX mode (supports subcommands using POSIX mode)
|
# - POSIX or non-POSIX mode (supports subcommands using POSIX mode)
|
||||||
# - Options can require an arbitrary number of parameters
|
# - Options can require an arbitrary number of parameters
|
||||||
# - Options can be defined with a range specifying the allowed number of parameters
|
# - Options can be defined with a range specifying the allowed number of
|
||||||
|
# parameters
|
||||||
module Yawpa
|
module Yawpa
|
||||||
# Exception class raised when an unknown option is observed
|
|
||||||
|
# Exception class raised when an unknown option is observed.
|
||||||
class ArgumentParsingException < Exception; end
|
class ArgumentParsingException < Exception; end
|
||||||
|
|
||||||
module_function
|
class << self
|
||||||
# :call-seq:
|
|
||||||
# opts, args = parse(params, options, flags = {})
|
# Parse input parameters looking for options according to rules given in
|
||||||
#
|
# flags.
|
||||||
# Parse input parameters looking for options according to rules given in flags
|
# Syntax:
|
||||||
#
|
# opts, args = parse(params, options, flags = {})
|
||||||
# - +params+ is the list of program parameters to parse.
|
#
|
||||||
# - +options+ is a hash containing the long option names as keys, and hashes
|
# An ArgumentParsingException will be raised if an unknown option is
|
||||||
# containing special flags for the options as values (example below).
|
# observed or insufficient arguments are present for an option.
|
||||||
# - +flags+ is optional. It supports the following keys:
|
#
|
||||||
# - +:posix_order+: Stop processing parameters when a non-option is seen.
|
# Example +options+:
|
||||||
# Set this to +true+ if you want to implement subcommands.
|
#
|
||||||
#
|
# {
|
||||||
# An ArgumentParsingException will be raised if an unknown option is observed
|
# version: nil,
|
||||||
# or insufficient arguments are present for an option.
|
# verbose: {short: 'v'},
|
||||||
#
|
# server: {nargs: (1..2)},
|
||||||
# == Example +options+
|
# username: {nargs: 1},
|
||||||
#
|
# password: {nargs: 1},
|
||||||
# {
|
# color: :boolean,
|
||||||
# version: {},
|
# }
|
||||||
# verbose: {short: 'v'},
|
#
|
||||||
# server: {nargs: (1..2)},
|
# The keys of the +options+ Hash can be either strings or symbols.
|
||||||
# username: {nargs: 1},
|
#
|
||||||
# password: {nargs: 1},
|
#
|
||||||
# }
|
# @param params [Array]
|
||||||
#
|
# List of program parameters to parse.
|
||||||
# The keys of the +options+ hash can be either strings or symbols.
|
# @param options [Hash]
|
||||||
#
|
# Hash containing the long option names as keys, and values containing
|
||||||
# Options that have no special flags should have an empty hash as the value.
|
# special flags for the options as values (examples above).
|
||||||
#
|
# Possible values:
|
||||||
# Possible option flags:
|
# +nil+:: No special flags for this option (equivalent to +{}+)
|
||||||
# - +:short+: specify a short option letter to associate with the long option
|
# +:boolean+::
|
||||||
# - +:nargs+: specify an exact number or range of possible numbers of
|
# The option is a toggleable boolean option (equivalent to
|
||||||
# arguments to the option
|
# +{boolean: true}+)
|
||||||
#
|
# Hash::
|
||||||
# == Return values
|
# Possible option flags:
|
||||||
#
|
# - +:short+: specify a short option letter to associate with the long
|
||||||
# The returned +opts+ value will be a hash with the observed options as
|
# option
|
||||||
# keys and any option arguments as values.
|
# - +:nargs+: specify an exact number or range of possible numbers of
|
||||||
# The returned +args+ will be an array of the unprocessed parameters (if
|
# arguments to the option
|
||||||
# +:posix_order+ was passed in +flags+, this array might contain further
|
# - +:boolean+: if true, specify that the option is a toggleable
|
||||||
# options that were not processed after observing a non-option parameters.
|
# boolean option and allow a prefix of "no" to turn it off.
|
||||||
def parse(params, options, flags = {})
|
# @param flags [Hash]
|
||||||
options = _massage_options(options)
|
# Optional flags dictating how {.parse} should do its job.
|
||||||
opts = {}
|
# @option flags [Boolean] :posix_order
|
||||||
args = []
|
# Stop processing parameters when a non-option argument is seen.
|
||||||
i = 0
|
# Set this to +true+ if you want to implement subcommands.
|
||||||
while i < params.length
|
#
|
||||||
param = params[i]
|
# @return [Array]
|
||||||
if param =~ /^--([^=]+)(?:=(.+))?$/
|
# Two-element array containing +opts+ and +args+ return values.
|
||||||
param_name, val = $1, $2
|
# +opts+::
|
||||||
if options[param_name].nil?
|
# The returned +opts+ value will be a Hash with the observed
|
||||||
raise ArgumentParsingException.new("Unknown option '#{param_name}'")
|
# options as keys and any option arguments as values.
|
||||||
end
|
# +args+::
|
||||||
opt_config = options[param_name]
|
# The returned +args+ will be an Array of the unprocessed
|
||||||
param_key = opt_config[:key]
|
# parameters (if +:posix_order+ was passed in +flags+, this array might
|
||||||
if opt_config[:nargs].last == 0
|
# contain further options that were not processed after observing a
|
||||||
opts[param_key] = true
|
# non-option parameters).
|
||||||
else
|
def parse(params, options, flags = {})
|
||||||
opts[param_key] = []
|
options = _massage_options(options)
|
||||||
i += _gather(opt_config[:nargs], i + 1, params, val, param_key, opts[param_key])
|
opts = {}
|
||||||
end
|
args = []
|
||||||
elsif param =~ /^-(.+)$/
|
i = 0
|
||||||
short_flags = $1
|
while i < params.length
|
||||||
short_idx = 0
|
param = params[i]
|
||||||
while short_idx < short_flags.length
|
if param =~ /^--([^=]+)(?:=(.+))?$/
|
||||||
opt_config = _find_opt_config_by_short_name(options, short_flags[short_idx])
|
param_name, val = $1, $2
|
||||||
if opt_config.nil?
|
bool_val = true
|
||||||
raise ArgumentParsingException.new("Unknown option '-#{short_flags[short_idx]}'")
|
if options[param_name].nil?
|
||||||
|
if param_name =~ /^no(.*)$/
|
||||||
|
test_param_name = $1
|
||||||
|
if options[test_param_name]
|
||||||
|
param_name = test_param_name
|
||||||
|
bool_val = false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
opt_config = options[param_name]
|
||||||
|
raise ArgumentParsingException.new("Unknown option '#{param_name}'") unless opt_config
|
||||||
param_key = opt_config[:key]
|
param_key = opt_config[:key]
|
||||||
if opt_config[:nargs].last == 0
|
if opt_config[:boolean]
|
||||||
|
opts[param_key] = bool_val
|
||||||
|
elsif opt_config[:nargs].last == 0
|
||||||
opts[param_key] = true
|
opts[param_key] = true
|
||||||
else
|
else
|
||||||
opts[param_key] = []
|
opts[param_key] = []
|
||||||
i += _gather(opt_config[:nargs], i + 1, params, short_flags[short_idx + 1, short_flags.length], param_key, opts[param_key])
|
i += _gather(opt_config[:nargs], i + 1, params, val, param_key, opts[param_key])
|
||||||
break
|
|
||||||
end
|
end
|
||||||
short_idx += 1
|
elsif param =~ /^-(.+)$/
|
||||||
|
short_flags = $1
|
||||||
|
short_idx = 0
|
||||||
|
while short_idx < short_flags.length
|
||||||
|
opt_config = _find_opt_config_by_short_name(options, short_flags[short_idx])
|
||||||
|
if opt_config.nil?
|
||||||
|
raise ArgumentParsingException.new("Unknown option '-#{short_flags[short_idx]}'")
|
||||||
|
end
|
||||||
|
param_key = opt_config[:key]
|
||||||
|
if opt_config[:nargs].last == 0
|
||||||
|
opts[param_key] = true
|
||||||
|
else
|
||||||
|
opts[param_key] = []
|
||||||
|
i += _gather(opt_config[:nargs],
|
||||||
|
i + 1,
|
||||||
|
params,
|
||||||
|
short_flags[short_idx + 1, short_flags.length],
|
||||||
|
param_key,
|
||||||
|
opts[param_key])
|
||||||
|
break
|
||||||
|
end
|
||||||
|
short_idx += 1
|
||||||
|
end
|
||||||
|
elsif flags[:posix_order]
|
||||||
|
args = params[i, params.length].map(&:dup)
|
||||||
|
break
|
||||||
|
else
|
||||||
|
args << params[i].dup
|
||||||
end
|
end
|
||||||
elsif flags[:posix_order]
|
i += 1
|
||||||
args = params[i, params.length]
|
|
||||||
break
|
|
||||||
else
|
|
||||||
args << params[i]
|
|
||||||
end
|
end
|
||||||
i += 1
|
|
||||||
|
# Condense 1-element arrays of option values to just the element itself
|
||||||
|
opts.each_key do |k|
|
||||||
|
if opts[k].is_a?(Array) and opts[k].length == 1
|
||||||
|
opts[k] = opts[k].first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return [opts, args]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Condense 1-element arrays of option values to just the element itself
|
private
|
||||||
opts.each_key do |k|
|
|
||||||
if opts[k].class == Array and opts[k].length == 1
|
# Internal helper method to gather arguments for an option
|
||||||
opts[k] = opts[k].first
|
def _gather(nargs, start_idx, params, initial, param_key, result)
|
||||||
|
n_gathered = 0
|
||||||
|
if initial and initial != ''
|
||||||
|
result << initial
|
||||||
|
n_gathered += 1
|
||||||
|
end
|
||||||
|
num_indices_used = 0
|
||||||
|
index = start_idx
|
||||||
|
while n_gathered < nargs.last and
|
||||||
|
index < params.length and
|
||||||
|
params[index][0] != '-' do
|
||||||
|
result << params[index].dup
|
||||||
|
index += 1
|
||||||
|
num_indices_used += 1
|
||||||
|
n_gathered += 1
|
||||||
|
end
|
||||||
|
if n_gathered < nargs.first
|
||||||
|
raise ArgumentParsingException.new("Not enough arguments supplied for option '#{param_key}'")
|
||||||
|
end
|
||||||
|
num_indices_used
|
||||||
|
end
|
||||||
|
|
||||||
|
# Internal helper method to format the options in a consistent format
|
||||||
|
def _massage_options(options)
|
||||||
|
{}.tap do |newopts|
|
||||||
|
options.each_pair do |k, v|
|
||||||
|
v = {} if v.nil?
|
||||||
|
v = {boolean: true} if v == :boolean
|
||||||
|
newkey = k.to_s
|
||||||
|
newopts[newkey] = {key: k}
|
||||||
|
nargs = v[:nargs] || 0
|
||||||
|
nargs = (nargs..nargs) if nargs.is_a?(Integer)
|
||||||
|
newopts[newkey][:nargs] = nargs
|
||||||
|
newopts[newkey][:short] = v[:short] || ''
|
||||||
|
newopts[newkey][:boolean] = v[:boolean]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return [opts, args]
|
# Internal helper method to find an option configuration by short name
|
||||||
end
|
def _find_opt_config_by_short_name(options, short_name)
|
||||||
|
|
||||||
# Internal helper method to gather arguments for an option
|
|
||||||
def _gather(nargs, start_idx, params, initial, param_key, result) # :nodoc:
|
|
||||||
n_gathered = 0
|
|
||||||
if initial and initial != ''
|
|
||||||
result << initial
|
|
||||||
n_gathered += 1
|
|
||||||
end
|
|
||||||
num_indices_used = 0
|
|
||||||
index = start_idx
|
|
||||||
while n_gathered < nargs.last and
|
|
||||||
index < params.length and
|
|
||||||
params[index][0] != '-' do
|
|
||||||
result << params[index]
|
|
||||||
index += 1
|
|
||||||
num_indices_used += 1
|
|
||||||
n_gathered += 1
|
|
||||||
end
|
|
||||||
if n_gathered < nargs.first
|
|
||||||
raise ArgumentParsingException.new("Not enough arguments supplied for option '#{param_key}'")
|
|
||||||
end
|
|
||||||
num_indices_used
|
|
||||||
end
|
|
||||||
|
|
||||||
# Internal helper method to format the options in a consistent format
|
|
||||||
def _massage_options(options) # :nodoc:
|
|
||||||
{}.tap do |newopts|
|
|
||||||
options.each_pair do |k, v|
|
options.each_pair do |k, v|
|
||||||
newkey = k.to_s
|
return v if v[:short] == short_name
|
||||||
newopts[newkey] = {key: k}
|
|
||||||
nargs = v[:nargs] || 0
|
|
||||||
nargs = (nargs..nargs) if nargs.class == Fixnum
|
|
||||||
newopts[newkey][:nargs] = nargs
|
|
||||||
newopts[newkey][:short] = v[:short] || ''
|
|
||||||
end
|
end
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Internal helper method to find an option configuration by short name
|
|
||||||
def _find_opt_config_by_short_name(options, short_name) # :nodoc:
|
|
||||||
options.each_pair do |k, v|
|
|
||||||
return v if v[:short] == short_name
|
|
||||||
end
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
module Yawpa
|
module Yawpa
|
||||||
# gem version
|
# gem version
|
||||||
VERSION = "1.0.0"
|
VERSION = "1.3.0"
|
||||||
end
|
end
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
require 'bundler/setup'
|
require "simplecov"
|
||||||
require 'yawpa'
|
|
||||||
|
|
||||||
RSpec.configure do |config|
|
SimpleCov.start do
|
||||||
|
add_filter "/spec/"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
require "yawpa"
|
||||||
|
@ -1,33 +1,31 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe Yawpa do
|
describe Yawpa do
|
||||||
describe 'parse' do
|
describe ".parse" do
|
||||||
it "returns everything as arguments when no options present" do
|
it "returns everything as arguments when no options present" do
|
||||||
options = { }
|
options = { }
|
||||||
params = ['one', 'two', 'three', 'four']
|
params = ['one', 'two', 'three', 'four']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts.should eq({})
|
expect(opts).to eq({})
|
||||||
args.should eq(params)
|
expect(args).to eq(params)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises an exception when an invalid option is passed" do
|
it "raises an exception when an invalid option is passed" do
|
||||||
options = { }
|
options = { }
|
||||||
params = ['one', '--option', 'two']
|
params = ['one', '--option', 'two']
|
||||||
expect { Yawpa.parse(params, options) }.to raise_error
|
expect { Yawpa.parse(params, options) }.to raise_error(Yawpa::ArgumentParsingException, /Unknown option/)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns boolean options which are set" do
|
it "returns boolean options which are set" do
|
||||||
options = {
|
options = {
|
||||||
one: {},
|
one: {},
|
||||||
two: {},
|
two: nil,
|
||||||
three: {},
|
three: {},
|
||||||
}
|
}
|
||||||
params = ['--one', 'arg', '--two', 'arg2']
|
params = ['--one', 'arg', '--two', 'arg2']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts.include?(:one).should be_true
|
expect(opts.include?(:one)).to be_truthy
|
||||||
opts.include?(:two).should be_true
|
expect(opts.include?(:two)).to be_truthy
|
||||||
opts.include?(:three).should be_false
|
expect(opts.include?(:three)).to be_falsey
|
||||||
args.should eq(['arg', 'arg2'])
|
expect(args).to eq(['arg', 'arg2'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns an option's value when nargs = 1" do
|
it "returns an option's value when nargs = 1" do
|
||||||
@ -36,8 +34,8 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['--opt', 'val', 'arg']
|
params = ['--opt', 'val', 'arg']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:opt].should eq('val')
|
expect(opts[:opt]).to eq('val')
|
||||||
args.should eq(['arg'])
|
expect(args).to eq(['arg'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns an option's values when nargs = 2" do
|
it "returns an option's values when nargs = 2" do
|
||||||
@ -46,8 +44,8 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['--opt', 'val1', 'val2']
|
params = ['--opt', 'val1', 'val2']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:opt].should eq(['val1', 'val2'])
|
expect(opts[:opt]).to eq(['val1', 'val2'])
|
||||||
args.should be_empty
|
expect(args).to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises an exception when not enough arguments for an option are given" do
|
it "raises an exception when not enough arguments for an option are given" do
|
||||||
@ -55,7 +53,7 @@ describe Yawpa do
|
|||||||
opt: {nargs: 2},
|
opt: {nargs: 2},
|
||||||
}
|
}
|
||||||
params = ['--opt', 'val']
|
params = ['--opt', 'val']
|
||||||
expect { Yawpa.parse(params, options) }.to raise_error
|
expect { Yawpa.parse(params, options) }.to raise_error(Yawpa::ArgumentParsingException, /Not enough arguments supplied/)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "uses --opt=val syntax for an option's value" do
|
it "uses --opt=val syntax for an option's value" do
|
||||||
@ -64,8 +62,8 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['--opt=thevalue', 'arg']
|
params = ['--opt=thevalue', 'arg']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:opt].should eq('thevalue')
|
expect(opts[:opt]).to eq('thevalue')
|
||||||
args.should eq(['arg'])
|
expect(args).to eq(['arg'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "uses --opt=val for the first option argument when nargs > 1" do
|
it "uses --opt=val for the first option argument when nargs > 1" do
|
||||||
@ -74,8 +72,8 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['--opt=val1', 'val2', 'arg']
|
params = ['--opt=val1', 'val2', 'arg']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:opt].should eq(['val1', 'val2'])
|
expect(opts[:opt]).to eq(['val1', 'val2'])
|
||||||
args.should eq(['arg'])
|
expect(args).to eq(['arg'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the last set value when an option is passed twice" do
|
it "returns the last set value when an option is passed twice" do
|
||||||
@ -84,8 +82,8 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['--opt', 'val1', 'arg1', '--opt', 'val2', 'arg2']
|
params = ['--opt', 'val1', 'arg1', '--opt', 'val2', 'arg2']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:opt].should eq('val2')
|
expect(opts[:opt]).to eq('val2')
|
||||||
args.should eq(['arg1', 'arg2'])
|
expect(args).to eq(['arg1', 'arg2'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "accepts strings as keys for option configuration" do
|
it "accepts strings as keys for option configuration" do
|
||||||
@ -94,8 +92,8 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['xxx', '--crazy-option', 'yyy', 'zzz']
|
params = ['xxx', '--crazy-option', 'yyy', 'zzz']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts['crazy-option'].should eq('yyy')
|
expect(opts['crazy-option']).to eq('yyy')
|
||||||
args.should eq(['xxx', 'zzz'])
|
expect(args).to eq(['xxx', 'zzz'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "accepts short options corresponding to a long option" do
|
it "accepts short options corresponding to a long option" do
|
||||||
@ -104,8 +102,8 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['-o', 'qqq']
|
params = ['-o', 'qqq']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:option].should be_true
|
expect(opts[:option]).to be_truthy
|
||||||
args.should eq(['qqq'])
|
expect(args).to eq(['qqq'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns option argument at next position for a short option" do
|
it "returns option argument at next position for a short option" do
|
||||||
@ -114,8 +112,8 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['-o', 'val', 'rrr']
|
params = ['-o', 'val', 'rrr']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:option].should eq('val')
|
expect(opts[:option]).to eq('val')
|
||||||
args.should eq(['rrr'])
|
expect(args).to eq(['rrr'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns option argument immediately following short option" do
|
it "returns option argument immediately following short option" do
|
||||||
@ -124,8 +122,8 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['-oval', 'rrr']
|
params = ['-oval', 'rrr']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:option].should eq('val')
|
expect(opts[:option]).to eq('val')
|
||||||
args.should eq(['rrr'])
|
expect(args).to eq(['rrr'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "handles globbed-together short options" do
|
it "handles globbed-together short options" do
|
||||||
@ -137,11 +135,11 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['-abc', 'xyz']
|
params = ['-abc', 'xyz']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:a].should be_true
|
expect(opts[:a]).to be_truthy
|
||||||
opts[:b].should be_true
|
expect(opts[:b]).to be_truthy
|
||||||
opts[:c].should be_true
|
expect(opts[:c]).to be_truthy
|
||||||
opts[:d].should be_nil
|
expect(opts[:d]).to be_nil
|
||||||
args.should eq(['xyz'])
|
expect(args).to eq(['xyz'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "handles globbed-together short options with values following" do
|
it "handles globbed-together short options with values following" do
|
||||||
@ -153,11 +151,11 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['-abcfoo', 'bar']
|
params = ['-abcfoo', 'bar']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:a].should be_true
|
expect(opts[:a]).to be_truthy
|
||||||
opts[:b].should be_true
|
expect(opts[:b]).to be_truthy
|
||||||
opts[:c].should eq('foo')
|
expect(opts[:c]).to eq('foo')
|
||||||
opts[:d].should be_nil
|
expect(opts[:d]).to be_nil
|
||||||
args.should eq(['bar'])
|
expect(args).to eq(['bar'])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "handles globbed-together short options with multiple values following" do
|
it "handles globbed-together short options with multiple values following" do
|
||||||
@ -169,11 +167,11 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['-abcfoo', 'bar', 'baz']
|
params = ['-abcfoo', 'bar', 'baz']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:a].should be_true
|
expect(opts[:a]).to be_truthy
|
||||||
opts[:b].should be_true
|
expect(opts[:b]).to be_truthy
|
||||||
opts[:c].should eq(['foo', 'bar', 'baz'])
|
expect(opts[:c]).to eq(['foo', 'bar', 'baz'])
|
||||||
opts[:d].should be_nil
|
expect(opts[:d]).to be_nil
|
||||||
args.should be_empty
|
expect(args).to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises an error on an unknown short option" do
|
it "raises an error on an unknown short option" do
|
||||||
@ -181,7 +179,7 @@ describe Yawpa do
|
|||||||
a: {short: 'a'},
|
a: {short: 'a'},
|
||||||
}
|
}
|
||||||
params = ['-ab']
|
params = ['-ab']
|
||||||
expect { Yawpa.parse(params, options) }.to raise_error
|
expect { Yawpa.parse(params, options) }.to raise_error(Yawpa::ArgumentParsingException, /Unknown option/)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises an error when not enough arguments are given to short option" do
|
it "raises an error when not enough arguments are given to short option" do
|
||||||
@ -189,7 +187,7 @@ describe Yawpa do
|
|||||||
a: {nargs: 1, short: 'a'},
|
a: {nargs: 1, short: 'a'},
|
||||||
}
|
}
|
||||||
params = ['-a']
|
params = ['-a']
|
||||||
expect { Yawpa.parse(params, options) }.to raise_error
|
expect { Yawpa.parse(params, options) }.to raise_error(Yawpa::ArgumentParsingException, /Not enough arguments supplied/)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "overwrites option value when short option used after long" do
|
it "overwrites option value when short option used after long" do
|
||||||
@ -198,20 +196,66 @@ describe Yawpa do
|
|||||||
}
|
}
|
||||||
params = ['--option', 'VALUE', '-o', 'NEW_VALUE']
|
params = ['--option', 'VALUE', '-o', 'NEW_VALUE']
|
||||||
opts, args = Yawpa.parse(params, options)
|
opts, args = Yawpa.parse(params, options)
|
||||||
opts[:option].should eq('NEW_VALUE')
|
expect(opts[:option]).to eq('NEW_VALUE')
|
||||||
args.should be_empty
|
expect(args).to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
it "ignores options after arguments in posix_order mode" do
|
it "ignores options after arguments in posix_order mode" do
|
||||||
options = {
|
options = {
|
||||||
one: {},
|
one: {},
|
||||||
two: {},
|
two: nil,
|
||||||
}
|
}
|
||||||
params = ['--one', 'arg', '--two']
|
params = ['--one', 'arg', '--two']
|
||||||
opts, args = Yawpa.parse(params, options, posix_order: true)
|
opts, args = Yawpa.parse(params, options, posix_order: true)
|
||||||
opts[:one].should be_true
|
expect(opts[:one]).to be_truthy
|
||||||
opts[:two].should be_false
|
expect(opts[:two]).to be_falsey
|
||||||
args.should eq(['arg', '--two'])
|
expect(args).to eq(['arg', '--two'])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "supports :boolean option flag" do
|
||||||
|
options = {
|
||||||
|
push: :boolean,
|
||||||
|
pull: {boolean: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, args = Yawpa.parse(%w[hi], options)
|
||||||
|
expect(opts).to eq({})
|
||||||
|
expect(args).to eq(%w[hi])
|
||||||
|
|
||||||
|
opts, args = Yawpa.parse(%w[--push one two], options)
|
||||||
|
expect(opts).to eq(push: true)
|
||||||
|
expect(args).to eq(%w[one two])
|
||||||
|
|
||||||
|
opts, args = Yawpa.parse(%w[arg --nopush --pull], options)
|
||||||
|
expect(opts).to eq(push: false, pull: true)
|
||||||
|
expect(args).to eq(%w[arg])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns non-frozen strings" do
|
||||||
|
options = {
|
||||||
|
o1: {nargs: 1, short: "1"},
|
||||||
|
o2: {nargs: 1, short: "2"},
|
||||||
|
o3: {nargs: 1, short: "3"},
|
||||||
|
o4: {nargs: 1, short: "4"},
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments = %w[--o1=one --o2 two -3 three -4four arg].map(&:freeze)
|
||||||
|
|
||||||
|
opts, args = Yawpa.parse(arguments, options)
|
||||||
|
expect(opts[:o1].frozen?).to be_falsey
|
||||||
|
expect{opts[:o1].sub!(/./, '-')}.to_not raise_error
|
||||||
|
expect(opts[:o2].frozen?).to be_falsey
|
||||||
|
expect{opts[:o2].sub!(/./, '-')}.to_not raise_error
|
||||||
|
expect(opts[:o3].frozen?).to be_falsey
|
||||||
|
expect{opts[:o3].sub!(/./, '-')}.to_not raise_error
|
||||||
|
expect(opts[:o4].frozen?).to be_falsey
|
||||||
|
expect{opts[:o4].sub!(/./, '-')}.to_not raise_error
|
||||||
|
expect(args[0].frozen?).to be_falsey
|
||||||
|
expect{args[0].sub!(/./, '-')}.to_not raise_error
|
||||||
|
|
||||||
|
opts, args = Yawpa.parse(arguments, options, posix_order: true)
|
||||||
|
expect(args[0].frozen?).to be_falsey
|
||||||
|
expect{args[0].sub!(/./, '-')}.to_not raise_error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -15,5 +15,9 @@ Gem::Specification.new do |gem|
|
|||||||
gem.require_paths = ["lib"]
|
gem.require_paths = ["lib"]
|
||||||
gem.version = Yawpa::VERSION
|
gem.version = Yawpa::VERSION
|
||||||
|
|
||||||
gem.add_development_dependency 'rspec'
|
gem.add_development_dependency "rspec"
|
||||||
|
gem.add_development_dependency "simplecov"
|
||||||
|
gem.add_development_dependency "rake"
|
||||||
|
gem.add_development_dependency "rdoc"
|
||||||
|
gem.add_development_dependency "yard"
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user