slop 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Lee Jarvis
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,101 @@
1
+ Slop
2
+ ====
3
+
4
+ Slop is a simple option parser with an easy to remember syntax and friendly API.
5
+
6
+ **NOTE** This software is still in beta, it contains bugs and lacks core
7
+ features
8
+
9
+ Installation
10
+ ------------
11
+
12
+ ### Rubygems
13
+
14
+ gem install slop
15
+
16
+ ### GitHub
17
+
18
+ git clone git://github.com/injekt/slop.git
19
+ cd slop
20
+ gem build slop.gemspec
21
+ gem install slop-<version>.gem
22
+
23
+ Usage
24
+ -----
25
+
26
+ s = Slop.parse(ARGV) do
27
+ option :v, :verbose, "Enable verbose mode", :default => false
28
+ option :n, :name, "Your name", true # compulsory argument
29
+ option :c, :country, "Your country", argument => true # the same thing
30
+
31
+ option :a, :age, "Your age", true, :optional => true # optional argument
32
+ option :address, "Your address", :optional => true # the same
33
+
34
+ # shortcut option aliases
35
+ opt :height, "Your height"
36
+ o :weight, "Your weight
37
+ end
38
+
39
+ # using `--name Lee -a 100`
40
+ s.options_hash #=> {:verbose=>false, :name=>"Lee", :age=>"100", :address=>nil}
41
+ s.value_for(:name) #=> "Lee"
42
+ option = s.option_for(:name)
43
+ option.description #=> "Your name"
44
+
45
+ # You can also use switch values to set options according to arguments
46
+ s = Slop.parse(ARGV) do
47
+ option :v, :verbose, :default => false, :switch => true
48
+ option :applicable_age, :default => 10, :switch => 20
49
+ end
50
+
51
+ # without `-v`
52
+ s.value_for(:verbose) #=> false
53
+
54
+ # using `-v`
55
+ s.value_for(:verbose) #=> true
56
+
57
+ # using `--applicable_age`
58
+ s.value_for(:applicable_age) #=> 20
59
+
60
+ Casting
61
+ -------
62
+
63
+ If you want to return values of specific types, for example a Symbol or Integer
64
+ you can pass the `:as` attribute to your option.
65
+
66
+ s = Slop.parse("--age 20") do
67
+ opt :age, true, :as => Integer # :int/:integer both also work
68
+ end
69
+ s.value_for(:age) #=> 20 # not "20"
70
+
71
+ Slop will also check your default attributes type to see if it can cast the new
72
+ value to the same type.
73
+
74
+ s = Slop.parse("--port 110") do
75
+ opt :port, true, :default => 80
76
+ end
77
+ s.value_for(:port) #=> 110
78
+
79
+ Lists
80
+ -----
81
+
82
+ You can of course also parse lists into options. Here's how:
83
+
84
+ s = Slop.parse("--people lee,injekt") do
85
+ opt :people, true, :as => Array
86
+ end
87
+ s.value_for(:people) #=> ["lee", "injekt"]
88
+
89
+ You can also change both the split delimiter and limit
90
+
91
+ s = Slop.parse("--people lee:injekt:bob") do
92
+ opt :people, true, :as => Array, :delimiter => ':', :limit => 2
93
+ end
94
+ s.value_for(:people) #=> ["lee", "injekt:bob"]
95
+
96
+ Contributing
97
+ ------------
98
+
99
+ If you'd like to contribute to Slop (it's **really** appreciated) please fork
100
+ the GitHub repository, create your feature/bugfix branch, add specs, and send
101
+ me a pull request. I'd be more than happy to look at it.
@@ -0,0 +1,147 @@
1
+ require 'set'
2
+
3
+ require 'slop/option'
4
+
5
+ class Slop
6
+ VERSION = '0.1.0'
7
+
8
+ class MissingArgumentError < ArgumentError; end
9
+
10
+ # @return [Set]
11
+ attr_reader :options
12
+
13
+ def self.parse(values=[], &blk)
14
+ new(&blk).parse(values)
15
+ end
16
+
17
+ def initialize(&blk)
18
+ @options = Set.new
19
+ instance_eval(&blk) if block_given?
20
+ end
21
+
22
+ # add an option
23
+ def option(*args, &blk)
24
+ opts = args.pop if args.last.is_a?(Hash)
25
+ opts ||= {}
26
+
27
+ if args.size > 4
28
+ raise ArgumentError, "Argument size must be no more than 4"
29
+ end
30
+
31
+ args.unshift nil if args.first.size > 1
32
+ args.push nil if args.size == 2
33
+ args.push false if args.size == 3
34
+ if args[2] == true
35
+ args[2] = nil
36
+ args[3] = true
37
+ end
38
+
39
+ attributes = [:flag, :option, :description, :argument]
40
+ options = Hash[attributes.zip(args)]
41
+ options.merge!(opts)
42
+ options[:as] = options[:default].class if options.key?(:default)
43
+ yield options if block_given?
44
+
45
+ @options << Option.new(options)
46
+ end
47
+ alias :opt :option
48
+ alias :o :option
49
+
50
+ # add an argument
51
+ def argument(*args)
52
+
53
+ end
54
+ alias :arg :argument
55
+ alias :args :argument
56
+ alias :arguments :argument
57
+
58
+ # Parse an Array (usually ARGV) of options
59
+ #
60
+ # @param [Array, #split] Array or String of options to parse
61
+ def parse(values=[])
62
+ values = values.split(/\s+/) if values.respond_to?(:split)
63
+
64
+ values.each do |value|
65
+ if value[1] == '-' or value[0] == '-'
66
+ opt = value.size == 2 ? value[1] : value[2..-1]
67
+ next unless option = option_for(opt) # skip unknown values for now
68
+ index = values.index(value)
69
+
70
+ if option.has_switch?
71
+ option.switch_argument_value
72
+ end
73
+
74
+ if option.requires_argument?
75
+ value = values.at(index + 1)
76
+
77
+ unless option.optional_argument?
78
+ if not value or value[0] == '-' or value[1] == '-'
79
+ raise MissingArgumentError,
80
+ "#{option.key} requires a compulsory argument, none given"
81
+ end
82
+ end
83
+
84
+ unless !value or value[0] == '-' or value[1] == '-'
85
+ option.argument_value = values.delete_at(values.index(value))
86
+ end
87
+ end
88
+ else
89
+ # not a flag or option, parse as an argument
90
+ end
91
+ end
92
+
93
+ self
94
+ end
95
+
96
+ # traverse options
97
+ def each_option
98
+ @options.each {|o| yield o }
99
+ end
100
+
101
+ # A simple Hash of options with option labels or flags as keys
102
+ # and option values as.. values.
103
+ #
104
+ # @return [Hash]
105
+ def options_hash
106
+ out = {}
107
+ each_option do |opt|
108
+ if opt.requires_argument? or opt.has_default?
109
+ out[opt.key] = opt.argument_value || opt.default
110
+ end
111
+ end
112
+ out
113
+ end
114
+ alias :to_hash :options_hash
115
+
116
+ # Find an option using its flag or label
117
+ #
118
+ # @example
119
+ # s = Slop.new do
120
+ # option :n, :name, "Your name"
121
+ # end
122
+ #
123
+ # s.option_for(:name).description #=> "Your name"
124
+ #
125
+ # @return [Option] the option flag or label
126
+ def option_for(flag)
127
+ @options.find do |opt|
128
+ opt.has_flag?(flag) || opt.has_option?(flag)
129
+ end
130
+ end
131
+
132
+ # Find an options argument using the option name.
133
+ # Essentially this is the same as `s.options_hash[:name]`
134
+ #
135
+ # @example When passing --name Lee
136
+ # s = Slop.new do
137
+ # option :n, :name, true
138
+ # end
139
+ #
140
+ # s.value_for(:name) #=> "Lee"
141
+ #
142
+ #
143
+ def value_for(flag)
144
+ return unless option = option_for(flag)
145
+ option.argument_value
146
+ end
147
+ end
@@ -0,0 +1,115 @@
1
+ class Slop
2
+ class Option
3
+
4
+ attr_reader :flag
5
+ attr_reader :option
6
+ attr_reader :description
7
+ attr_reader :argument_value
8
+ attr_reader :default
9
+
10
+ def initialize(options={}, &blk)
11
+ @options = options
12
+ @flag = options[:flag]
13
+ @option = options[:option] || options[:opt]
14
+ @description = options[:description] || options[:desc]
15
+ @argument = options[:argument] || false
16
+ @optional = options[:optional] || options[:optional_argument]
17
+ @argument ||= @optional
18
+ @default = options[:default]
19
+ @as = options[:as]
20
+
21
+ # Array properties
22
+ @delimiter = options[:delimiter] || ','
23
+ @limit = options[:limit] || 1
24
+
25
+ @argument_value = nil
26
+ end
27
+
28
+ # Set the argument value
29
+ # @param [Object] value
30
+ def argument_value=(value)
31
+ @argument_value = value
32
+ end
33
+
34
+ # @return [Object] the argument value after it's been cast
35
+ # according to the `:as` option
36
+ def argument_value
37
+ @argument_value ||= @default
38
+ return unless @argument_value
39
+
40
+ case @as.to_s
41
+ when 'array', 'Array'; @argument_value.split(@delimiter, @limit)
42
+ when 'integer', 'int', 'Integer'; @argument_value.to_i
43
+ when 'symbol', 'sym', 'Symbol' ; @argument_value.to_sym
44
+ else
45
+ @argument_value
46
+ end
47
+ end
48
+
49
+ # @param [to_s] flag
50
+ # @return [Boolean] true if this option contains a flag
51
+ def has_flag?(flag)
52
+ @flag.to_s == flag.to_s
53
+ end
54
+
55
+ # @param [to_s] option
56
+ # @return [Boolean] true if this option contains an option label
57
+ def has_option?(option)
58
+ @option.to_s == option.to_s
59
+ end
60
+
61
+ # @return [Boolean] true if this option has a default value
62
+ def has_default?
63
+ !@default.nil?
64
+ end
65
+
66
+ # @return [Boolean] true if this option has a switch value
67
+ def has_switch?
68
+ !!@options[:switch]
69
+ end
70
+
71
+ # does the option require an argument?
72
+ # @return [Boolean]
73
+ def requires_argument?
74
+ !!@argument
75
+ end
76
+
77
+ # Is the argument optional?
78
+ # @return [Boolean]
79
+ def optional_argument?
80
+ @options[:optional]
81
+ end
82
+
83
+ # Replace options argument value with the switch value supplied, used
84
+ # when supplying the `switch` option making switch flags easy to alter
85
+ #
86
+ # @example
87
+ # option :v, :verbose, :default => false, :switch => true
88
+ #
89
+ # Now when the `-v` or `--verbose` option is supplied, verbose will
90
+ # be set to `true`, rather than the default `false` option
91
+ def switch_argument_value
92
+ @argument_value = @option[:switch]
93
+ end
94
+
95
+ # return a key for an option, prioritize
96
+ # option before flag as it's more descriptive
97
+ def key
98
+ @option || @flag
99
+ end
100
+
101
+ def to_s
102
+ str = "\t"
103
+ str << "-#{@flag}" if @flag
104
+ str << "\t"
105
+ str << "--#{@option}\t\t" if @option
106
+ str << "#{@description}" if @description
107
+ str << "\n"
108
+ end
109
+
110
+ def inspect
111
+ "#<#{self.class}: #{@options}>"
112
+ end
113
+
114
+ end
115
+ end
@@ -0,0 +1,5 @@
1
+ require File.expand_path('../../lib/slop', __FILE__)
2
+
3
+ describe Slop::Option do
4
+
5
+ end
@@ -0,0 +1,104 @@
1
+ require File.expand_path('../../lib/slop', __FILE__)
2
+
3
+ describe Slop do
4
+ before :all do
5
+ @slop = Slop.new do
6
+ option :v, :verbose, "Enable verbose mode"
7
+ end
8
+ end
9
+
10
+ describe "option" do
11
+ it "adds an option" do
12
+ @slop.options.find do |opt|
13
+ opt.flag == :v
14
+ end.should be_kind_of(Slop::Option)
15
+ end
16
+
17
+ it "adds an option with a block to alter option attributes" do
18
+ s = Slop.new do
19
+ option :n, :name, "Set your name!", true do |o|
20
+ o[:default] = "Lee"
21
+ end
22
+ end
23
+ s.option_for(:name).default.should == "Lee"
24
+ end
25
+
26
+ it "takes no more than 4 arguments" do
27
+ lambda do
28
+ Slop.new { option :a, :b, :c, :d, :e }
29
+ end.should raise_error(ArgumentError, "Argument size must be no more than 4")
30
+ end
31
+
32
+ it "does not parse option values unless option.argument is true" do
33
+ Slop.parse("--name Lee") { opt :name }.value_for(:name).should be_nil
34
+ Slop.parse("--name Lee") { opt :name, true }.value_for(:name).should == "Lee"
35
+ Slop.parse("--name Lee") { opt :name, :argument => true }.value_for(:name).should == "Lee"
36
+ end
37
+ end
38
+
39
+ describe "option_for" do
40
+ it "returns an option" do
41
+ @slop.option_for(:v).should be_kind_of(Slop::Option)
42
+ end
43
+
44
+ it "returns nil otherwise" do
45
+ @slop.option_for(:nothing).should be_nil
46
+ end
47
+ end
48
+
49
+ describe "value_for" do
50
+ it "returns the value of an option" do
51
+ s = Slop.parse("--name Lee") do
52
+ opt :n, :name, "Your name", true
53
+ end
54
+ s.value_for(:name).should == "Lee"
55
+ end
56
+
57
+ it "returns a default option if none is given" do
58
+ Slop.new { opt :name, true, :default => "Lee" }.value_for(:name).should == "Lee"
59
+ end
60
+
61
+ it "returns nil if an option does not exist" do
62
+ Slop.new.value_for(:name).should be_nil
63
+ end
64
+ end
65
+
66
+ describe "parse" do
67
+ it "returns self (Slop)" do
68
+ Slop.parse.should be_kind_of(Slop)
69
+ end
70
+
71
+ it "parses a string" do
72
+ Slop.parse("--name Lee") { opt :name, true }.value_for(:name).should == "Lee"
73
+ end
74
+
75
+ it "parses an array" do
76
+ Slop.parse(%w"--name Lee") { opt :name, true }.value_for(:name).should == "Lee"
77
+ end
78
+
79
+ it "raises MissingArgumentError if no argument is given to a compulsory option" do
80
+ lambda { Slop.parse("--name") { opt :name, true } }.should raise_error(Slop::MissingArgumentError, /name/)
81
+ end
82
+
83
+ it "does not raise MissingArgumentError if the optional attribute is true" do
84
+ Slop.parse("--name") { opt :name, true, :optional => true }.value_for(:name).should be_nil
85
+ end
86
+
87
+ it "does not require argument to be true if optional is true" do
88
+ Slop.parse("--name Lee") { opt :name, :optional => true }.value_for(:name).should == "Lee"
89
+ end
90
+ end
91
+
92
+ describe "options" do
93
+ it "returns a set" do
94
+ @slop.options.should be_kind_of Set
95
+ end
96
+
97
+ it "contains a set of Slop::Option" do
98
+ @slop.options.each do |opt|
99
+ opt.should be_kind_of(Slop::Option)
100
+ end
101
+ end
102
+ end
103
+
104
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: slop
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Lee Jarvis
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-11-26 00:00:00 +00:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - "="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 2
30
+ - 1
31
+ - 0
32
+ version: 2.1.0
33
+ type: :development
34
+ version_requirements: *id001
35
+ description: ""
36
+ email: lee@jarvis.co
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - LICENSE
45
+ - README.md
46
+ - lib/slop.rb
47
+ - lib/slop/option.rb
48
+ - spec/slop_spec.rb
49
+ - spec/option_spec.rb
50
+ has_rdoc: true
51
+ homepage: http://rubydoc.info/github/injekt/slop
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 1
66
+ - 9
67
+ - 1
68
+ version: 1.9.1
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ requirements: []
78
+
79
+ rubyforge_project:
80
+ rubygems_version: 1.3.7
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Option parsing made easy
84
+ test_files: []
85
+