slop 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+