Compare commits

...

26 Commits

Author SHA1 Message Date
abbc14e965 v1.3.0 2017-09-08 14:01:07 -04:00
3518141baa Use Integer instead of Fixnum 2017-09-08 14:00:25 -04:00
33c000a6ca update several gems 2017-09-08 13:57:56 -04:00
dfb7ff75cb v1.2.0 2016-04-19 08:55:01 -04:00
d011cdc374 add v1.2.0 release notes 2016-04-19 08:54:48 -04:00
3709cc7fef Close #1 - Always return non-frozen strings 2016-04-19 08:52:02 -04:00
e852d2755c clean up class method declaration slightly using class << self syntax 2016-04-19 08:37:39 -04:00
6cf70753f4 update gems; robustify usage of raise_error rspec matcher 2016-04-19 08:33:30 -04:00
80b2f7b63c v1.1.0 2014-06-25 15:33:31 -04:00
72834425c3 add release notes to README.md 2014-06-25 15:31:40 -04:00
1b49c06a85 require spec_helper from .rspec 2014-06-25 15:30:11 -04:00
4c6f8c0250 update README 2014-06-25 15:28:20 -04:00
8842a855d8 add gem badge 2014-06-25 15:24:03 -04:00
b79acd049f allow nil and :boolean to be option configuration values 2014-06-25 15:22:39 -04:00
0eb754814e document :boolean option flag 2014-06-25 15:15:09 -04:00
d33d082272 turn on simplecov 2014-06-25 15:06:33 -04:00
a78ee7275e implement :boolean option flag 2014-06-25 15:05:19 -04:00
f74253844b use .is_a?() instead of .class == 2014-06-25 14:53:22 -04:00
4e18e729c3 switch to YARD for documentation 2014-06-25 14:52:39 -04:00
2099aaa6e0 update to RSpec 3.0 2014-06-25 14:11:39 -04:00
31c63790f9 rename Rakefile -> Rakefile.rb 2014-06-25 14:06:24 -04:00
5b07b4da96 version Gemfile.lock; call Bundler.setup() in Rakefile 2014-06-25 14:06:13 -04:00
c5ea73acfd remove some unnecessary stuff from spec_helper.rb 2013-05-06 13:39:28 -04:00
34ee9a1b09 close parentheses 2013-05-02 11:16:05 -04:00
5eca5e7657 fix example options in README 2013-05-02 11:12:21 -04:00
64e084b0d4 add Yawpa.parse() documentation to README.md 2013-05-02 11:11:00 -04:00
11 changed files with 453 additions and 263 deletions

22
.gitignore vendored
View File

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

1
.rspec
View File

@ -1 +1,2 @@
--color --color
--require spec_helper

46
Gemfile.lock Normal file
View 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
View File

@ -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.
[![Gem Version](https://badge.fury.io/rb/yawpa.png)](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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
module Yawpa module Yawpa
# gem version # gem version
VERSION = "1.0.0" VERSION = "1.3.0"
end end

View File

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

View File

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

View File

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