clip 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.1 / 2008-04-03
2
+
3
+ * Initial release for y'all to throw rotten veggies at
4
+
data/README.txt ADDED
@@ -0,0 +1,94 @@
1
+ = clip
2
+
3
+ == DESCRIPTION:
4
+
5
+ Yeah yeah yeah. Why in heaven's name do we need yet another
6
+ command-line parser? Well, OptionParser is all well and good, but
7
+ doesn't grease the skids as much as I'd like. So I wrote this little
8
+ library... driven completely by specs.
9
+
10
+ Cheers!
11
+
12
+ == FEATURES
13
+
14
+ You like command-line parsing, but you hate all of the bloat. Why
15
+ should you have to create a Hash, then create a parser, then fill
16
+ that Hash out then throw the parser away (unless you want to print
17
+ out a usage message) and deal with a Hash? Why, for Pete's sake, should
18
+ the parser and the parsed values be handled by two different objects?
19
+
20
+ Well, now they don't...
21
+
22
+ == SYNOPSIS:
23
+
24
+ And it goes a little something like this...
25
+
26
+ require "rubygems"
27
+ require "clip"
28
+
29
+ parser = Clip do |p|
30
+ p.optional 's', 'server', :desc => 'The server name', :default => 'localhost'
31
+ p.optional 'p', 'port', :desc => 'The port', :default => 8080
32
+ p.required 'f', 'files', :multi => true, :desc => 'Files to send'
33
+ p.flag 'v', 'verbose', :desc => 'Make it chatty'
34
+ end
35
+
36
+ if parser.valid?
37
+ if parser.verbose?
38
+ puts parser.host
39
+ puts parser.port
40
+ puts 'files:'
41
+ parser.files.each do |f|
42
+ puts "\t#{f}"
43
+ end
44
+ end
45
+ else
46
+ # print error message(s) and usage
47
+ $stderr.puts parser.to_s
48
+ end
49
+
50
+ The names of the options and flags that you declare in the block are accessible
51
+ as methods on the returned object, reducing the amount of objects you have to
52
+ deal with when you're parsing command-line parameters.
53
+
54
+ Simply invoking the <tt>to_s</tt> method on a parser instance will dump both the
55
+ correct usage and any errors encountered during parsing. No need for you to manage
56
+ the state of what's required and what isn't by yourself. Also, '--help' and '-h'
57
+ will automatically trigger Clip to dump out usage and exit.
58
+
59
+ Sometimes you have additional arguments you need to process that don't require
60
+ a named option or flag. Whatever remains on the command line that doesn't fit
61
+ either a flag or an option/value pair will be made available via the
62
+ <tt>remainder</tt> method of the returned object.
63
+
64
+ == PROBLEMS/DEFICIENCIES:
65
+
66
+ OK, some of your favorite <tt>OptionParser</tt> features are simply not here.
67
+ You know that cool thing you can do where you tell <tt>OptionParser</tt> the
68
+ class of the kind of object you would like to get for a particular argument?
69
+ Do you like that one? Well, too bad. We don't have that one. Deal with it.
70
+
71
+ == LICENSE:
72
+
73
+ (The MIT License)
74
+
75
+ Copyright (c) 2008 Alex Vollmer
76
+
77
+ Permission is hereby granted, free of charge, to any person obtaining
78
+ a copy of this software and associated documentation files (the
79
+ 'Software'), to deal in the Software without restriction, including
80
+ without limitation the rights to use, copy, modify, merge, publish,
81
+ distribute, sublicense, and/or sell copies of the Software, and to
82
+ permit persons to whom the Software is furnished to do so, subject to
83
+ the following conditions:
84
+
85
+ The above copyright notice and this permission notice shall be
86
+ included in all copies or substantial portions of the Software.
87
+
88
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
89
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
90
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
91
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
92
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
93
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
94
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/bin/sample_parser ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), "../lib/clip")
4
+
5
+ ##
6
+ # This is a very simple example of how to use Clip
7
+ p = Clip do |c|
8
+ c.optional 's', 'server', :desc => 'The server name', :default => 'localhost'
9
+ c.optional 'p', 'port', :desc => 'The port', :default => 8080
10
+ c.optional 'f', 'files', :desc => 'Files to upload', :multi => true
11
+ c.flag 'v', 'verbose', :desc => 'Make it verbose, man'
12
+ end
13
+
14
+ printf("%10s %-20s\n", "attribute", "value")
15
+ [:server, :port, :verbose?].each do |att|
16
+ printf("%10s %-20s\n", att, p.send(att))
17
+ end
18
+ printf("%10s %-20s\n", "files", p.files.inspect)
data/lib/clip.rb ADDED
@@ -0,0 +1,324 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ##
4
+ # Parse arguments (defaults to <tt>ARGV</tt>) with the Clip::Parser
5
+ # configured in the given block. This is the main method you
6
+ # call to get the ball rolling.
7
+ def Clip(args=ARGV)
8
+ parser = Clip::Parser.new
9
+ raise "Dontcha wanna configure your parser?" unless block_given?
10
+ yield parser
11
+ parser.parse(args)
12
+ parser
13
+ end
14
+
15
+ module Clip
16
+ VERSION = "0.0.1"
17
+
18
+ ##
19
+ # Indicates that the parser was incorrectly configured in the
20
+ # block yielded by the +parse+ method.
21
+ class IllegalConfiguration < Exception
22
+ end
23
+
24
+ class Parser
25
+ ##
26
+ # Returns any remaining command line arguments that were not parsed
27
+ # because they were neither flags or option/value pairs
28
+ attr_reader :remainder
29
+
30
+ ##
31
+ # Declare an optional parameter for your parser. This creates an accessor
32
+ # method matching the <tt>long</tt> parameter. The <tt>short</tt> parameter
33
+ # indicates the single-letter equivalent. Options that use the '-'
34
+ # character as a word separator are converted to method names using
35
+ # '_'. For example the name 'exclude-files' would create a method named
36
+ # <tt>exclude_files</tt>.
37
+ #
38
+ # When the <tt>:multi</tt> option is enabled, the associated accessor
39
+ # method will return an <tt>Array</tt> instead of a single scalar value.
40
+ # === options
41
+ # Valid options include:
42
+ # * <tt>desc</tt>: a helpful description (used for printing usage)
43
+ # * <tt>default</tt>: a default value to provide if one is not given
44
+ # * <tt>multi</tt>: indicates that mulitple values are okay for this param.
45
+ #
46
+ # Note that specifying the <tt>:multi</tt> option means that the parameter
47
+ # can be specified several times with different values, or that a single
48
+ # comma-separated value can be specified which will then be broken up into
49
+ # separate tokens.
50
+ def optional(short, long, options={})
51
+ short = short.to_sym
52
+ long = long.to_sym
53
+ check_args(short, long)
54
+
55
+ eval <<-EOF
56
+ def #{long}=(val)
57
+ @#{long} = val
58
+ end
59
+
60
+ def #{long}
61
+ @#{long}
62
+ end
63
+ EOF
64
+
65
+ self.options[long] = Option.new(short, long, options)
66
+ self.options[short] = self.options[long]
67
+ self.order << self.options[long]
68
+ end
69
+
70
+ alias_method :opt, :optional
71
+
72
+ ##
73
+ # Declare a required parameter for your parser. If this parameter
74
+ # is not provided in the parsed content, the parser instance
75
+ # will be invalid (i.e. where valid? returns <tt>false</tt>).
76
+ #
77
+ # This method takes the same options as the optional method.
78
+ def required(short, long, options={})
79
+ optional(short, long, options.merge({ :required => true }))
80
+ end
81
+
82
+ alias_method :req, :required
83
+
84
+ ##
85
+ # Declare a parameter as a simple boolean flag. This declaration
86
+ # will create a "question" method matching the given <tt>long</tt>.
87
+ # For example, declaring with the name of 'verbose' will create a
88
+ # method on your parser called <tt>verbose?</tt>.
89
+ # === options
90
+ # Valid options are:
91
+ # * <tt>desc</tt>: Descriptive text for the flag
92
+ def flag(short, long, options={})
93
+ short = short.to_sym
94
+ long = long.to_sym
95
+
96
+ check_args(short, long)
97
+
98
+ eval <<-EOF
99
+ def flag_#{long}
100
+ @#{long} = true
101
+ end
102
+
103
+ def #{long}?
104
+ return @#{long} || false
105
+ end
106
+ EOF
107
+
108
+ self.options[long] = Flag.new(short, long, options)
109
+ self.options[short] = self.options[long]
110
+ self.order << self.options[long]
111
+ end
112
+
113
+ def initialize # :nodoc:
114
+ @errors = {}
115
+ @valid = true
116
+ end
117
+
118
+ ##
119
+ # Parse the given <tt>args</tt> and set the corresponding instance
120
+ # fields to the given values. If any errors occurred during parsing
121
+ # you can get them from the <tt>Hash</tt> returned by the +errors+ method.
122
+ def parse(args)
123
+ @valid = true
124
+ args = args.split(/\s+/) unless args.kind_of?(Array)
125
+ consumed = []
126
+ if args.member?("--help")
127
+ puts help
128
+ exit 0
129
+ end
130
+ param, value = nil, nil
131
+
132
+ args.each do |token|
133
+ case token
134
+ when /^-(-)?\w/
135
+ consumed << token
136
+ param = token.sub(/^-(-)?/, '').sub('-', '_').to_sym
137
+ value = nil
138
+ else
139
+ if param
140
+ consumed << token
141
+ value = token
142
+ end
143
+ end
144
+
145
+ option = options[param]
146
+ if option
147
+ if (value.nil? && option.kind_of?(Flag)) || value
148
+ option.process(self, value)
149
+ end
150
+ else
151
+ @errors[param] = "Unrecoginzed parameter"
152
+ @valid = false
153
+ next
154
+ end
155
+
156
+ unless value.nil?
157
+ param = nil
158
+ value = nil
159
+ end
160
+ end
161
+
162
+ @remainder = args - consumed
163
+
164
+ # Find required options that are missing arguments
165
+ options.each do |param, opt|
166
+ if opt.kind_of?(Option) and self.send(opt.long).nil?
167
+ if opt.required?
168
+ @valid = false
169
+ @errors[opt.long.to_sym] = "Missing required parameter: #{opt.long}"
170
+ elsif opt.has_default?
171
+ opt.process(self, opt.default)
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ ##
178
+ # Indicates whether or not the parsing process succeeded. If this
179
+ # returns <tt>false</tt> you probably just want to print out a call
180
+ # to the to_s method.
181
+ def valid?
182
+ @valid
183
+ end
184
+
185
+ ##
186
+ # Returns a <tt>Hash</tt> of errors (by the long name) of any errors
187
+ # encountered during parsing. If you simply want to display error
188
+ # messages to the user, you can just print out a call to the
189
+ # to_s method.
190
+ def errors
191
+ @errors
192
+ end
193
+
194
+ ##
195
+ # Returns a formatted <tt>String</tt> indicating the usage of the parser
196
+ def help
197
+ out = ""
198
+ out << "Usage:\n"
199
+ order.each do |option|
200
+ out << "#{option.usage}\n"
201
+ end
202
+ out
203
+ end
204
+
205
+ ##
206
+ # Returns a formatted <tt>String</tt> of the +help+ method prefixed by
207
+ # any parsing errors. Either way you have _one_ method to call to
208
+ # let your users know what to do.
209
+ def to_s
210
+ out = ""
211
+ unless valid?
212
+ out << "Errors:\n"
213
+ errors.each do |field, msg|
214
+ out << "#{field}: #{msg}\n"
215
+ end
216
+ end
217
+ out << help
218
+ end
219
+
220
+ def options # :nodoc:
221
+ (@options ||= {})
222
+ end
223
+
224
+ def order # :nodoc:
225
+ (@order ||= [])
226
+ end
227
+
228
+ private
229
+ def check_args(short, long)
230
+ short = short.to_sym
231
+ long = long.to_sym
232
+
233
+ if long == :help
234
+ raise IllegalConfiguration.new("You cannot override the built-in 'help' parameter")
235
+ end
236
+
237
+ if short == :h
238
+ raise IllegalConfiguration.new("You cannot override the built-in 'h' parameter")
239
+ end
240
+
241
+ if self.options.has_key?(long)
242
+ raise IllegalConfiguration.new("You have already defined a parameter/flag for #{long}")
243
+ end
244
+
245
+ if self.options.has_key?(short)
246
+ raise IllegalConfiguration.new("You already have a defined parameter/flag for the short key '#{short}")
247
+ end
248
+ end
249
+ end
250
+
251
+ class Option # :nodoc:
252
+ attr_accessor :long, :short, :description, :default, :required, :multi
253
+
254
+ def initialize(short, long, options)
255
+ @short = short
256
+ @long = long
257
+ @description = options[:desc]
258
+ @default = options[:default]
259
+ @required = options[:required]
260
+ @multi = options[:multi]
261
+ end
262
+
263
+ def process(parser, value)
264
+ if @multi
265
+ current = parser.send(@long) || []
266
+ current.concat(value.split(','))
267
+ parser.send("#{@long}=".to_sym, current)
268
+ else
269
+ parser.send("#{@long}=".to_sym, value)
270
+ end
271
+ end
272
+
273
+ def required?
274
+ @required == true
275
+ end
276
+
277
+ def has_default?
278
+ not @default.nil?
279
+ end
280
+
281
+ def multi?
282
+ @multi == true
283
+ end
284
+
285
+ def usage
286
+ out = sprintf('-%-2s --%-10s %s',
287
+ @short,
288
+ @long.to_s.gsub('_', '-').to_sym,
289
+ @description)
290
+ out << " (defaults to '#{@default}')" if @default
291
+ out << " REQUIRED" if @required
292
+ out
293
+ end
294
+ end
295
+
296
+ class Flag # :nodoc:
297
+
298
+ attr_accessor :long, :short, :description
299
+
300
+ ##
301
+ # nodoc
302
+ def initialize(short, long, options)
303
+ @short = short
304
+ @long = long
305
+ @description = options[:desc]
306
+ end
307
+
308
+ def process(parser, value)
309
+ parser.send("flag_#{@long}".to_sym)
310
+ end
311
+
312
+ def required?
313
+ false
314
+ end
315
+
316
+ def has_default?
317
+ false
318
+ end
319
+
320
+ def usage
321
+ sprintf('-%-2s --%-10s %s', @short, @long, @description)
322
+ end
323
+ end
324
+ end
data/spec/clip_spec.rb ADDED
@@ -0,0 +1,269 @@
1
+ require "#{File.dirname(__FILE__)}/../lib/clip"
2
+ require "rubygems"
3
+ require "spec"
4
+
5
+ class HaveErrors
6
+
7
+ def matches?(target)
8
+ @target = target
9
+ not @target.errors.empty?
10
+ end
11
+
12
+ def failure_message
13
+ "expected #{@target} to have errors"
14
+ end
15
+
16
+ def negative_failure_message
17
+ "expected #{@target} to have no errors, but... #{@target.errors.inspect}"
18
+ end
19
+ end
20
+
21
+ def have_errors
22
+ HaveErrors.new
23
+ end
24
+
25
+ class HaveErrorsOn
26
+ def initialize(expected)
27
+ @expected = expected
28
+ end
29
+
30
+ def matches?(target)
31
+ @target = target
32
+ not @target.errors[@expected.to_sym].nil?
33
+ end
34
+
35
+ def failure_message
36
+ "expected error message for #{@expected} on #{@target}"
37
+ end
38
+
39
+ def negative_failure_message
40
+ "unexpected error message for #{@expected} on #{@target}"
41
+ end
42
+ end
43
+
44
+ def have_errors_on(expected)
45
+ HaveErrorsOn.new(expected)
46
+ end
47
+
48
+ describe Clip do
49
+
50
+ def parse(line)
51
+ Clip(line) do |p|
52
+ p.flag 'v', 'verbose', :desc => 'Provide verbose output'
53
+ p.optional 's', 'server', :desc => 'The hostname', :default => 'localhost'
54
+ p.optional 'p', 'port', :desc => 'The port number', :default => 8080
55
+ p.required 'f', 'files', :desc => 'Files to upload', :multi => true
56
+ p.optional 'e', 'exclude_from', :desc => 'Directories to exclude'
57
+ end
58
+ end
59
+
60
+ describe "When long command-line parameters are parsed" do
61
+
62
+ it "should create accessor methods for declarations" do
63
+ parser = parse('')
64
+ parser.should respond_to(:server)
65
+ parser.should respond_to(:server=)
66
+ parser.should respond_to(:port)
67
+ parser.should respond_to(:port)
68
+ parser.should respond_to(:files)
69
+ parser.should respond_to(:files=)
70
+ parser.should respond_to(:verbose?)
71
+ parser.should respond_to(:flag_verbose)
72
+ end
73
+
74
+ it "should set fields for flags to 'true'" do
75
+ parser = parse('--verbose --files foo')
76
+ parser.should be_verbose
77
+ parser.should be_valid
78
+ parser.should_not have_errors
79
+ end
80
+
81
+ it "should set fields for flags with the given values" do
82
+ parser = parse('--server localhost --port 8080 --files foo')
83
+ parser.server.should eql("localhost")
84
+ parser.port.should eql("8080")
85
+ parser.should be_valid
86
+ parser.should_not have_errors
87
+ end
88
+
89
+ it "should map flags with '-' to methods with '_'" do
90
+ parser = parse('--exclude-from /Users --files foo')
91
+ parser.exclude_from.should eql("/Users")
92
+ parser.should be_valid
93
+ parser.should_not have_errors
94
+ end
95
+
96
+ it "should be invalid for unknown flags" do
97
+ parser = parse('--non-existent')
98
+ parser.should_not be_valid
99
+ parser.should have_errors_on(:non_existent)
100
+ end
101
+ end
102
+
103
+ describe "When short (single-letter) command-line parse are parsed" do
104
+
105
+ it "should set flags to true" do
106
+ parser = parse("-v --files foo")
107
+ parser.should be_verbose
108
+ parser.should_not have_errors
109
+ parser.should be_valid
110
+ end
111
+
112
+ it "should set fields for short options" do
113
+ parser = parse("-s localhost -p 8080 --files foo")
114
+ parser.should_not have_errors
115
+ parser.should be_valid
116
+ parser.server.should eql("localhost")
117
+ parser.port.should eql("8080")
118
+ parser.should_not be_verbose
119
+ end
120
+ end
121
+
122
+ describe "When parameters are marked as required" do
123
+
124
+ it "should be invalid when there are missing arguments" do
125
+ parser = parse('--server localhost')
126
+ parser.should_not be_valid
127
+ parser.should have_errors_on(:files)
128
+ end
129
+ end
130
+
131
+ describe "When parameters are marked with defaults" do
132
+
133
+ it "should provide default parameter values when none are parsed" do
134
+ parser = parse('--files foo')
135
+ parser.should be_valid
136
+ parser.should_not have_errors
137
+ parser.server.should eql("localhost")
138
+ parser.port.should eql(8080)
139
+ end
140
+ end
141
+
142
+ describe "Multi-valued parameters" do
143
+
144
+ it "should handle multiple value for the same parameter" do
145
+ parser = parse("--files foo --files bar --files baz")
146
+ parser.should be_valid
147
+ parser.should_not have_errors
148
+ parser.files.should == %w[foo bar baz]
149
+ end
150
+
151
+ it "should handle comma-separated values as multiples" do
152
+ parser = parse("--files foo,bar,baz")
153
+ parser.should be_valid
154
+ parser.should_not have_errors
155
+ parser.files.should == %w[foo bar baz]
156
+ end
157
+ end
158
+
159
+ describe "Help output" do
160
+ it "should print out some sensible usage info for to_s" do
161
+ out = parse('--files foo').to_s.split("\n")
162
+ out[0].should match(/Usage/)
163
+ out[1].should match(/-v\s+--verbose\s+Provide verbose output/)
164
+ out[2].should match(/-s\s+--server\s+The hostname.*default.*localhost/)
165
+ out[3].should match(/-p\s+--port\s+The port number/)
166
+ out[4].should match(/-f\s+--files\s+Files to upload.*REQUIRED/)
167
+ out[5].should match(/-e\s+--exclude-from\s+Directories to exclude/)
168
+ end
169
+
170
+ it "should include error messages in to_s" do
171
+ parser = parse('')
172
+ out = parser.to_s.split("\n")
173
+ out[0].should match(/Error/)
174
+ out[1].should match(/missing required.*files/i)
175
+ out[2..-1].join("\n").strip.should == parser.help.strip
176
+ end
177
+ end
178
+
179
+ describe "Additional arguments" do
180
+ it "should be made available" do
181
+ parser = parse('--files foo alpha bravo')
182
+ parser.files.should == %w[foo]
183
+ parser.remainder.should == %w[alpha bravo]
184
+ end
185
+ end
186
+
187
+ describe "Declaring bad options and flags" do
188
+
189
+ def misconfig_parser
190
+ lambda do
191
+ Clip("foo") do |c|
192
+ yield c
193
+ end
194
+ end.should raise_error(Clip::IllegalConfiguration)
195
+ end
196
+
197
+ it "should reject :help as a flag name" do
198
+ misconfig_parser { |c| c.flag 'x', 'help' }
199
+ end
200
+
201
+ it "should reject :help as an optional name" do
202
+ misconfig_parser { |c| c.optional 'x', 'help' }
203
+ end
204
+
205
+ it "should reject 'h' as a short flag name" do
206
+ misconfig_parser { |c| c.flag 'h', 'foo' }
207
+ end
208
+
209
+ it "should reject 'h' as a short parameter name" do
210
+ misconfig_parser { |c| c.optional 'h', 'foo' }
211
+ end
212
+
213
+ it "should reject redefining an existing long name for two options" do
214
+ misconfig_parser do |c|
215
+ c.optional 'f', 'foo'
216
+ c.optional 'x', 'foo'
217
+ end
218
+ end
219
+
220
+ it "should reject redefining an existing long name for an option & flag" do
221
+ misconfig_parser do |c|
222
+ c.optional 'f', 'foo'
223
+ c.flag 'x', 'foo'
224
+ end
225
+ end
226
+
227
+ it "should reject redefining the same flag" do
228
+ misconfig_parser do |c|
229
+ c.flag 'f', 'foo'
230
+ c.flag 'x', 'foo'
231
+ end
232
+ end
233
+
234
+ it "should reject defining a flag with an option" do
235
+ misconfig_parser do |c|
236
+ c.flag 'f', 'foo'
237
+ c.optional 'x', 'foo'
238
+ end
239
+ end
240
+
241
+ it "should reject redefining an existing short name for options" do
242
+ misconfig_parser do |c|
243
+ c.optional 'f', 'foo'
244
+ c.optional 'f', 'files'
245
+ end
246
+ end
247
+
248
+ it "should reject redefining a short option with a flag" do
249
+ misconfig_parser do |c|
250
+ c.optional 'f', 'foo'
251
+ c.flag 'f', 'fail'
252
+ end
253
+ end
254
+
255
+ it "should reject redefining a short flag with a flag" do
256
+ misconfig_parser do |c|
257
+ c.flag 'f', 'fail'
258
+ c.flag 'f', 'foo'
259
+ end
260
+ end
261
+
262
+ it "should reject redefining a flag with an optional" do
263
+ misconfig_parser do |c|
264
+ c.flag 'f', 'fail'
265
+ c.optional 'f', 'foo'
266
+ end
267
+ end
268
+ end
269
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clip
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alex Vollmer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-04-10 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.5.1
23
+ version:
24
+ description: Command-line parsing made short and sweet
25
+ email:
26
+ - alex.vollmer@gmail.com
27
+ executables:
28
+ - sample_parser
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - History.txt
33
+ - README.txt
34
+ files:
35
+ - History.txt
36
+ - README.txt
37
+ - bin/sample_parser
38
+ - lib/clip.rb
39
+ - spec/clip_spec.rb
40
+ has_rdoc: true
41
+ homepage: http://clip.rubyforge.org
42
+ post_install_message:
43
+ rdoc_options:
44
+ - --main
45
+ - README.txt
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ requirements: []
61
+
62
+ rubyforge_project: clip
63
+ rubygems_version: 1.1.0
64
+ signing_key:
65
+ specification_version: 2
66
+ summary: Command-line parsing made short and sweet
67
+ test_files: []
68
+