yawpa 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NDQxOWYxMWMwMjA3NjU5NjlkOTQ4MTFkM2Y3OTZkNTI5MGVjNzJiZg==
5
+ data.tar.gz: !binary |-
6
+ YzQ1NGE3MDM1MjJkNjRiMjM0MTJjMDFiNmRmNmVhODJiZWNmMjVlMQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MTdjNTBkMTM5NDY5MmNjMTYwY2VmNmU4NjRhMjM0MjVjYTM3YjM3MTY0OWY3
10
+ MjY4M2U1NTI5ZTZlZmM3N2E2MDU2YmE3MTBiYzEyZWQxODA5NzEwOTA2YjM3
11
+ ZDMwNzQzNmJhOTRhN2FlZGZjNDFiNDYyYWM0OTQ4NmNlMjZhNTk=
12
+ data.tar.gz: !binary |-
13
+ OWExNTUyNmE4ODM1YTFiNWMwNTg4YjdmMTU1MWJiOTM2ZmUxNmFiMjc3ZjI1
14
+ YWQxMWU1ZTU2MjZjMTA0NTc2MmFjOWJkOWVhMjk4ZDdlMmQ3ZDk0ZDI2M2Vl
15
+ MzI0NmQ5YmEyNTA3NGIxMjdhYjE4ZTYxZjIzYTgwMDI4YmUxY2I=
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in yawpa.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Josh Holtrop
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # Yawpa
2
+
3
+ Yet Another Way to Parse Arguments is an argument-parsing library for Ruby.
4
+
5
+ ## Features
6
+
7
+ - POSIX or non-POSIX mode (supports subcommands using POSIX mode)
8
+ - Options can require an arbitrary number of parameters
9
+ - Options can be defined with a range specifying the allowed number of parameters
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'yawpa'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install yawpa
24
+
25
+ ## Example 1
26
+
27
+ require 'yawpa'
28
+
29
+ options = {
30
+ version: {},
31
+ verbose: {short: 'v'},
32
+ get: {nargs: 1},
33
+ set: {nargs: 2},
34
+ }
35
+ opts, args = Yawpa.parse(ARGV, options)
36
+ opts.each_pair do |opt, val|
37
+ end
38
+
39
+ ## Example 2
40
+
41
+ require 'yawpa'
42
+
43
+ options = {
44
+ version: {},
45
+ help: {short: 'h'},
46
+ }
47
+ opts, args = Yawpa.parse(ARGV, options, posix_order: true)
48
+ if opts[:version]
49
+ puts "my app, version 1.2.3"
50
+ end
51
+ if args[0] == 'subcommand'
52
+ subcommand_options = {
53
+ 'server': {nargs: (1..2), short: 's'},
54
+ 'dst': {nargs: 1, short: 'd'},
55
+ }
56
+ opts, args = Yawpa.parse(args, subcommand_options)
57
+ end
58
+
59
+ ## Contributing
60
+
61
+ 1. Fork it
62
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
63
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
64
+ 4. Push to the branch (`git push origin my-new-feature`)
65
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+ require "rdoc/task"
4
+
5
+ RSpec::Core::RakeTask.new('spec')
6
+
7
+ task :default => :spec
8
+
9
+ Rake::RDocTask.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Yet Another Way to Parse Arguments'
12
+ rdoc.rdoc_files.include('lib/**/*.rb')
13
+ end
@@ -0,0 +1,4 @@
1
+ module Yawpa
2
+ # gem version
3
+ VERSION = "1.0.0"
4
+ end
data/lib/yawpa.rb ADDED
@@ -0,0 +1,162 @@
1
+ require "yawpa/version"
2
+
3
+ # Yet Another Way to Parse Arguments is an argument-parsing library for Ruby.
4
+ #
5
+ # Yawpa does not try to provide a fancy DSL.
6
+ # It does not require you to define a class or inherit from a class.
7
+ # it just provides a simple functional interface for parsing options,
8
+ # supporting subcommands and arbitrary numbers of arguments for each option.
9
+ #
10
+ # == Features
11
+ #
12
+ # - POSIX or non-POSIX mode (supports subcommands using POSIX mode)
13
+ # - Options can require an arbitrary number of parameters
14
+ # - Options can be defined with a range specifying the allowed number of parameters
15
+ module Yawpa
16
+ # Exception class raised when an unknown option is observed
17
+ class ArgumentParsingException < Exception; end
18
+
19
+ module_function
20
+ # :call-seq:
21
+ # opts, args = parse(params, options, flags = {})
22
+ #
23
+ # Parse input parameters looking for options according to rules given in flags
24
+ #
25
+ # - +params+ is the list of program parameters to parse.
26
+ # - +options+ is a hash containing the long option names as keys, and hashes
27
+ # containing special flags for the options as values (example below).
28
+ # - +flags+ is optional. It supports the following keys:
29
+ # - +:posix_order+: Stop processing parameters when a non-option is seen.
30
+ # Set this to +true+ if you want to implement subcommands.
31
+ #
32
+ # An ArgumentParsingException will be raised if an unknown option is observed
33
+ # or insufficient arguments are present for an option.
34
+ #
35
+ # == Example +options+
36
+ #
37
+ # {
38
+ # version: {},
39
+ # verbose: {short: 'v'},
40
+ # server: {nargs: (1..2)},
41
+ # username: {nargs: 1},
42
+ # password: {nargs: 1},
43
+ # }
44
+ #
45
+ # The keys of the +options+ hash can be either strings or symbols.
46
+ #
47
+ # Options that have no special flags should have an empty hash as the value.
48
+ #
49
+ # Possible option flags:
50
+ # - +:short+: specify a short option letter to associate with the long option
51
+ # - +:nargs+: specify an exact number or range of possible numbers of
52
+ # arguments to the option
53
+ #
54
+ # == Return values
55
+ #
56
+ # The returned +opts+ value will be a hash with the observed options as
57
+ # keys and any option arguments as values.
58
+ # The returned +args+ will be an array of the unprocessed parameters (if
59
+ # +:posix_order+ was passed in +flags+, this array might contain further
60
+ # options that were not processed after observing a non-option parameters.
61
+ def parse(params, options, flags = {})
62
+ options = _massage_options(options)
63
+ opts = {}
64
+ args = []
65
+ i = 0
66
+ while i < params.length
67
+ param = params[i]
68
+ if param =~ /^--([^=]+)(?:=(.+))?$/
69
+ param_name, val = $1, $2
70
+ if options[param_name].nil?
71
+ raise ArgumentParsingException.new("Unknown option '#{param_name}'")
72
+ end
73
+ opt_config = options[param_name]
74
+ param_key = opt_config[:key]
75
+ if opt_config[:nargs].last == 0
76
+ opts[param_key] = true
77
+ else
78
+ opts[param_key] = []
79
+ i += _gather(opt_config[:nargs], i + 1, params, val, param_key, opts[param_key])
80
+ end
81
+ elsif param =~ /^-(.+)$/
82
+ short_flags = $1
83
+ short_idx = 0
84
+ while short_idx < short_flags.length
85
+ opt_config = _find_opt_config_by_short_name(options, short_flags[short_idx])
86
+ if opt_config.nil?
87
+ raise ArgumentParsingException.new("Unknown option '-#{short_flags[short_idx]}'")
88
+ end
89
+ param_key = opt_config[:key]
90
+ if opt_config[:nargs].last == 0
91
+ opts[param_key] = true
92
+ else
93
+ opts[param_key] = []
94
+ i += _gather(opt_config[:nargs], i + 1, params, short_flags[short_idx + 1, short_flags.length], param_key, opts[param_key])
95
+ break
96
+ end
97
+ short_idx += 1
98
+ end
99
+ elsif flags[:posix_order]
100
+ args = params[i, params.length]
101
+ break
102
+ else
103
+ args << params[i]
104
+ end
105
+ i += 1
106
+ end
107
+
108
+ # Condense 1-element arrays of option values to just the element itself
109
+ opts.each_key do |k|
110
+ if opts[k].class == Array and opts[k].length == 1
111
+ opts[k] = opts[k].first
112
+ end
113
+ end
114
+
115
+ return [opts, args]
116
+ end
117
+
118
+ # Internal helper method to gather arguments for an option
119
+ def _gather(nargs, start_idx, params, initial, param_key, result) # :nodoc:
120
+ n_gathered = 0
121
+ if initial and initial != ''
122
+ result << initial
123
+ n_gathered += 1
124
+ end
125
+ num_indices_used = 0
126
+ index = start_idx
127
+ while n_gathered < nargs.last and
128
+ index < params.length and
129
+ params[index][0] != '-' do
130
+ result << params[index]
131
+ index += 1
132
+ num_indices_used += 1
133
+ n_gathered += 1
134
+ end
135
+ if n_gathered < nargs.first
136
+ raise ArgumentParsingException.new("Not enough arguments supplied for option '#{param_key}'")
137
+ end
138
+ num_indices_used
139
+ end
140
+
141
+ # Internal helper method to format the options in a consistent format
142
+ def _massage_options(options) # :nodoc:
143
+ {}.tap do |newopts|
144
+ options.each_pair do |k, v|
145
+ newkey = k.to_s
146
+ newopts[newkey] = {key: k}
147
+ nargs = v[:nargs] || 0
148
+ nargs = (nargs..nargs) if nargs.class == Fixnum
149
+ newopts[newkey][:nargs] = nargs
150
+ newopts[newkey][:short] = v[:short] || ''
151
+ end
152
+ end
153
+ end
154
+
155
+ # Internal helper method to find an option configuration by short name
156
+ def _find_opt_config_by_short_name(options, short_name) # :nodoc:
157
+ options.each_pair do |k, v|
158
+ return v if v[:short] == short_name
159
+ end
160
+ nil
161
+ end
162
+ end
@@ -0,0 +1,5 @@
1
+ require 'bundler/setup'
2
+ require 'yawpa'
3
+
4
+ RSpec.configure do |config|
5
+ end
@@ -0,0 +1,217 @@
1
+ require 'spec_helper'
2
+
3
+ describe Yawpa do
4
+ describe 'parse' do
5
+ it "returns everything as arguments when no options present" do
6
+ options = { }
7
+ params = ['one', 'two', 'three', 'four']
8
+ opts, args = Yawpa.parse(params, options)
9
+ opts.should eq({})
10
+ args.should eq(params)
11
+ end
12
+
13
+ it "raises an exception when an invalid option is passed" do
14
+ options = { }
15
+ params = ['one', '--option', 'two']
16
+ expect { Yawpa.parse(params, options) }.to raise_error
17
+ end
18
+
19
+ it "returns boolean options which are set" do
20
+ options = {
21
+ one: {},
22
+ two: {},
23
+ three: {},
24
+ }
25
+ params = ['--one', 'arg', '--two', 'arg2']
26
+ opts, args = Yawpa.parse(params, options)
27
+ opts.include?(:one).should be_true
28
+ opts.include?(:two).should be_true
29
+ opts.include?(:three).should be_false
30
+ args.should eq(['arg', 'arg2'])
31
+ end
32
+
33
+ it "returns an option's value when nargs = 1" do
34
+ options = {
35
+ opt: {nargs: 1},
36
+ }
37
+ params = ['--opt', 'val', 'arg']
38
+ opts, args = Yawpa.parse(params, options)
39
+ opts[:opt].should eq('val')
40
+ args.should eq(['arg'])
41
+ end
42
+
43
+ it "returns an option's values when nargs = 2" do
44
+ options = {
45
+ opt: {nargs: 2},
46
+ }
47
+ params = ['--opt', 'val1', 'val2']
48
+ opts, args = Yawpa.parse(params, options)
49
+ opts[:opt].should eq(['val1', 'val2'])
50
+ args.should be_empty
51
+ end
52
+
53
+ it "raises an exception when not enough arguments for an option are given" do
54
+ options = {
55
+ opt: {nargs: 2},
56
+ }
57
+ params = ['--opt', 'val']
58
+ expect { Yawpa.parse(params, options) }.to raise_error
59
+ end
60
+
61
+ it "uses --opt=val syntax for an option's value" do
62
+ options = {
63
+ opt: {nargs: 1},
64
+ }
65
+ params = ['--opt=thevalue', 'arg']
66
+ opts, args = Yawpa.parse(params, options)
67
+ opts[:opt].should eq('thevalue')
68
+ args.should eq(['arg'])
69
+ end
70
+
71
+ it "uses --opt=val for the first option argument when nargs > 1" do
72
+ options = {
73
+ opt: {nargs: 2},
74
+ }
75
+ params = ['--opt=val1', 'val2', 'arg']
76
+ opts, args = Yawpa.parse(params, options)
77
+ opts[:opt].should eq(['val1', 'val2'])
78
+ args.should eq(['arg'])
79
+ end
80
+
81
+ it "returns the last set value when an option is passed twice" do
82
+ options = {
83
+ opt: {nargs: 1},
84
+ }
85
+ params = ['--opt', 'val1', 'arg1', '--opt', 'val2', 'arg2']
86
+ opts, args = Yawpa.parse(params, options)
87
+ opts[:opt].should eq('val2')
88
+ args.should eq(['arg1', 'arg2'])
89
+ end
90
+
91
+ it "accepts strings as keys for option configuration" do
92
+ options = {
93
+ 'crazy-option' => {nargs: 1},
94
+ }
95
+ params = ['xxx', '--crazy-option', 'yyy', 'zzz']
96
+ opts, args = Yawpa.parse(params, options)
97
+ opts['crazy-option'].should eq('yyy')
98
+ args.should eq(['xxx', 'zzz'])
99
+ end
100
+
101
+ it "accepts short options corresponding to a long option" do
102
+ options = {
103
+ option: {short: 'o'},
104
+ }
105
+ params = ['-o', 'qqq']
106
+ opts, args = Yawpa.parse(params, options)
107
+ opts[:option].should be_true
108
+ args.should eq(['qqq'])
109
+ end
110
+
111
+ it "returns option argument at next position for a short option" do
112
+ options = {
113
+ option: {nargs: 1, short: 'o'},
114
+ }
115
+ params = ['-o', 'val', 'rrr']
116
+ opts, args = Yawpa.parse(params, options)
117
+ opts[:option].should eq('val')
118
+ args.should eq(['rrr'])
119
+ end
120
+
121
+ it "returns option argument immediately following short option" do
122
+ options = {
123
+ option: {nargs: 1, short: 'o'},
124
+ }
125
+ params = ['-oval', 'rrr']
126
+ opts, args = Yawpa.parse(params, options)
127
+ opts[:option].should eq('val')
128
+ args.should eq(['rrr'])
129
+ end
130
+
131
+ it "handles globbed-together short options" do
132
+ options = {
133
+ a: {short: 'a'},
134
+ b: {short: 'b'},
135
+ c: {short: 'c'},
136
+ d: {short: 'd'},
137
+ }
138
+ params = ['-abc', 'xyz']
139
+ opts, args = Yawpa.parse(params, options)
140
+ opts[:a].should be_true
141
+ opts[:b].should be_true
142
+ opts[:c].should be_true
143
+ opts[:d].should be_nil
144
+ args.should eq(['xyz'])
145
+ end
146
+
147
+ it "handles globbed-together short options with values following" do
148
+ options = {
149
+ a: {short: 'a'},
150
+ b: {short: 'b'},
151
+ c: {nargs: 1, short: 'c'},
152
+ d: {short: 'd'},
153
+ }
154
+ params = ['-abcfoo', 'bar']
155
+ opts, args = Yawpa.parse(params, options)
156
+ opts[:a].should be_true
157
+ opts[:b].should be_true
158
+ opts[:c].should eq('foo')
159
+ opts[:d].should be_nil
160
+ args.should eq(['bar'])
161
+ end
162
+
163
+ it "handles globbed-together short options with multiple values following" do
164
+ options = {
165
+ a: {short: 'a'},
166
+ b: {short: 'b'},
167
+ c: {nargs: 3, short: 'c'},
168
+ d: {short: 'd'},
169
+ }
170
+ params = ['-abcfoo', 'bar', 'baz']
171
+ opts, args = Yawpa.parse(params, options)
172
+ opts[:a].should be_true
173
+ opts[:b].should be_true
174
+ opts[:c].should eq(['foo', 'bar', 'baz'])
175
+ opts[:d].should be_nil
176
+ args.should be_empty
177
+ end
178
+
179
+ it "raises an error on an unknown short option" do
180
+ options = {
181
+ a: {short: 'a'},
182
+ }
183
+ params = ['-ab']
184
+ expect { Yawpa.parse(params, options) }.to raise_error
185
+ end
186
+
187
+ it "raises an error when not enough arguments are given to short option" do
188
+ options = {
189
+ a: {nargs: 1, short: 'a'},
190
+ }
191
+ params = ['-a']
192
+ expect { Yawpa.parse(params, options) }.to raise_error
193
+ end
194
+
195
+ it "overwrites option value when short option used after long" do
196
+ options = {
197
+ option: {nargs: 1, short: 'o'},
198
+ }
199
+ params = ['--option', 'VALUE', '-o', 'NEW_VALUE']
200
+ opts, args = Yawpa.parse(params, options)
201
+ opts[:option].should eq('NEW_VALUE')
202
+ args.should be_empty
203
+ end
204
+
205
+ it "ignores options after arguments in posix_order mode" do
206
+ options = {
207
+ one: {},
208
+ two: {},
209
+ }
210
+ params = ['--one', 'arg', '--two']
211
+ opts, args = Yawpa.parse(params, options, posix_order: true)
212
+ opts[:one].should be_true
213
+ opts[:two].should be_false
214
+ args.should eq(['arg', '--two'])
215
+ end
216
+ end
217
+ end
data/yawpa.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/yawpa/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Josh Holtrop"]
6
+ gem.email = ["jholtrop@gmail.com"]
7
+ gem.description = %q{Yet Another Way to Parse Arguments is an argument-parsing library for Ruby}
8
+ gem.summary = %q{Yet Another Way to Parse Arguments}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "yawpa"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Yawpa::VERSION
17
+
18
+ gem.add_development_dependency 'rspec'
19
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yawpa
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Josh Holtrop
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Yet Another Way to Parse Arguments is an argument-parsing library for
28
+ Ruby
29
+ email:
30
+ - jholtrop@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - .gitignore
36
+ - .rspec
37
+ - Gemfile
38
+ - LICENSE
39
+ - README.md
40
+ - Rakefile
41
+ - lib/yawpa.rb
42
+ - lib/yawpa/version.rb
43
+ - spec/spec_helper.rb
44
+ - spec/yawpa_spec.rb
45
+ - yawpa.gemspec
46
+ homepage: ''
47
+ licenses: []
48
+ metadata: {}
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubyforge_project:
65
+ rubygems_version: 2.0.3
66
+ signing_key:
67
+ specification_version: 4
68
+ summary: Yet Another Way to Parse Arguments
69
+ test_files:
70
+ - spec/spec_helper.rb
71
+ - spec/yawpa_spec.rb