clamp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ .yardoc
4
+ doc
5
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem "rake"
7
+ gem "rspec", "~> 2.0.1"
8
+ gem "rr", "~> 1.0.0"
9
+ end
@@ -0,0 +1,30 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ clamp (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.1.2)
10
+ rake (0.8.7)
11
+ rr (1.0.0)
12
+ rspec (2.0.1)
13
+ rspec-core (~> 2.0.1)
14
+ rspec-expectations (~> 2.0.1)
15
+ rspec-mocks (~> 2.0.1)
16
+ rspec-core (2.0.1)
17
+ rspec-expectations (2.0.1)
18
+ diff-lcs (>= 1.1.2)
19
+ rspec-mocks (2.0.1)
20
+ rspec-core (~> 2.0.1)
21
+ rspec-expectations (~> 2.0.1)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ clamp!
28
+ rake
29
+ rr (~> 1.0.0)
30
+ rspec (~> 2.0.1)
@@ -0,0 +1,40 @@
1
+ Clamp
2
+ =====
3
+
4
+ "Clamp" is a minimal framework for command-line utilities.
5
+
6
+ It handles boring stuff like parsing the command-line, and generating help, so you can get on with making your command actually do stuff.
7
+
8
+ Not another one!
9
+ ----------------
10
+
11
+ Yeah, sorry. There are a bunch of existing command-line parsing libraries out there, and Clamp draws inspiration from a variety of sources, including [Thor], [optparse], and [Clip]. In the end, though, I wanted a slightly rounder wheel.
12
+
13
+ [optparse]: http://ruby-doc.org/stdlib/libdoc/optparse/rdoc/index.html
14
+ [Thor]: http://github.com/wycats/thor
15
+ [Clip]: http://clip.rubyforge.org/
16
+
17
+ Quick Start
18
+ -----------
19
+
20
+ Clamp models a command as a Ruby class, and command invocations as instances of that class.
21
+
22
+ "Command classes" are subclasses of `Clamp::Command`. They look like this:
23
+
24
+ class InstallCommand < Clamp::Command
25
+
26
+ option "--force", :flag, ""
27
+
28
+ def execute
29
+ # do something
30
+ end
31
+
32
+ end
33
+
34
+ Class-level methods are available to declare command-line options, and document usage.
35
+
36
+ Clamp commands are invoked like so:
37
+
38
+ InstallCommand.run
39
+
40
+ This will instantiate a new `InstallCommand`, handle command-line args, and finally call the `#execute` method to do the real work.
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ require "rspec/core/rake_task"
6
+
7
+ task "default" => "spec"
8
+
9
+ RSpec::Core::RakeTask.new do |t|
10
+ t.pattern = 'spec/**/*_spec.rb'
11
+ t.rspec_opts = ["--colour", "--format", "nested"]
12
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "clamp/version"
4
+
5
+ Gem::Specification.new do |s|
6
+
7
+ s.name = "clamp"
8
+ s.version = Clamp::VERSION.dup
9
+ s.platform = Gem::Platform::RUBY
10
+ s.authors = ["Mike Williams"]
11
+ s.email = "mdub@dogbiscuit.org"
12
+ s.homepage = "http://github.com/mdub/clamp"
13
+
14
+ s.summary = %q{a minimal framework for command-line utilities}
15
+ s.description = <<EOF
16
+ Clamp makes provides an object-model for command-line utilities.
17
+ It handles parsing of command-line options, and generation of usage help.
18
+ EOF
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ s.require_paths = ["lib"]
23
+
24
+ end
@@ -0,0 +1,35 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require "clamp"
4
+
5
+ class Rename < Clamp::Command
6
+
7
+ usage "[OPTIONS] TRANSFORM FILE ..."
8
+
9
+ argument "TRANSFORM", "a Ruby expression"
10
+ argument "FILE", "a file to rename"
11
+
12
+ option ["-v", "--verbose"], :flag, "be verbose"
13
+
14
+ option ["-n", "--times"], "TIMES", "repetitions" do |n|
15
+ n = Integer(n)
16
+ raise ArgumentError, "too big" if n > 9
17
+ n
18
+ end
19
+
20
+ help_option
21
+
22
+ def initialize(name)
23
+ super
24
+ @times = 1
25
+ end
26
+
27
+ def execute
28
+ @times.times do
29
+ puts "Blah blah blah" if verbose?
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ Rename.run
@@ -0,0 +1,3 @@
1
+ require 'clamp/version'
2
+
3
+ require 'clamp/command'
@@ -0,0 +1,6 @@
1
+ module Clamp
2
+
3
+ class Argument < Struct.new(:name, :description)
4
+ end
5
+
6
+ end
@@ -0,0 +1,196 @@
1
+ require 'clamp/argument'
2
+ require 'clamp/option'
3
+
4
+ module Clamp
5
+
6
+ class Command
7
+
8
+ def initialize(name)
9
+ @name = name
10
+ end
11
+
12
+ attr_reader :name
13
+ attr_reader :arguments
14
+
15
+ def parse(arguments)
16
+ while arguments.first =~ /^-/
17
+ case (switch = arguments.shift)
18
+
19
+ when /\A--\z/
20
+ break
21
+
22
+ else
23
+ option = find_option(switch)
24
+ value = if option.flag?
25
+ option.flag_value(switch)
26
+ else
27
+ arguments.shift
28
+ end
29
+ begin
30
+ send("#{option.attribute_name}=", value)
31
+ rescue ArgumentError => e
32
+ signal_usage_error "option '#{switch}': #{e.message}"
33
+ end
34
+
35
+ end
36
+ end
37
+ @arguments = arguments
38
+ end
39
+
40
+ def execute
41
+ raise "you need to define #execute"
42
+ end
43
+
44
+ def run(arguments)
45
+ parse(arguments)
46
+ execute
47
+ end
48
+
49
+ def help
50
+ self.class.help.gsub("__COMMAND__", name)
51
+ end
52
+
53
+ private
54
+
55
+ def find_option(switch)
56
+ self.class.find_option(switch) ||
57
+ signal_usage_error("Unrecognised option '#{switch}'")
58
+ end
59
+
60
+ def signal_usage_error(message)
61
+ e = UsageError.new(message, self)
62
+ e.set_backtrace(caller)
63
+ raise e
64
+ end
65
+
66
+ class << self
67
+
68
+ def options
69
+ @options ||= []
70
+ end
71
+
72
+ def option(switches, argument_type, description, opts = {}, &block)
73
+ option = Clamp::Option.new(switches, argument_type, description, opts)
74
+ self.options << option
75
+ declare_option_reader(option)
76
+ declare_option_writer(option, &block)
77
+ end
78
+
79
+ def help_option(switches = ["-h", "--help"])
80
+ option(switches, :flag, "print help", :attribute_name => :help_requested) do
81
+ raise Clamp::HelpWanted.new(self)
82
+ end
83
+ end
84
+
85
+ def has_options?
86
+ !options.empty?
87
+ end
88
+
89
+ def find_option(switch)
90
+ options.find { |o| o.handles?(switch) }
91
+ end
92
+
93
+ def usage(usage)
94
+ @usages ||= []
95
+ @usages << usage
96
+ end
97
+
98
+ def arguments
99
+ @arguments ||= []
100
+ end
101
+
102
+ def argument(name, description)
103
+ arguments << Argument.new(name, description)
104
+ end
105
+
106
+ def derived_usage
107
+ parts = arguments.map { |a| a.name }
108
+ parts.unshift("[OPTIONS]") if has_options?
109
+ parts.join(" ")
110
+ end
111
+
112
+ def help
113
+ help = StringIO.new
114
+ help.puts "Usage:"
115
+ usages = @usages || [derived_usage]
116
+ usages.each_with_index do |usage, i|
117
+ help.puts " __COMMAND__ #{usage}".rstrip
118
+ end
119
+ detail_format = " %-29s %s"
120
+ unless arguments.empty?
121
+ help.puts "\nArguments:"
122
+ arguments.each do |argument|
123
+ help.puts detail_format % [argument.name, argument.description]
124
+ end
125
+ end
126
+ unless options.empty?
127
+ help.puts "\nOptions:"
128
+ options.each do |option|
129
+ help.puts detail_format % option.help
130
+ end
131
+ end
132
+ help.string
133
+ end
134
+
135
+ def run(name = $0, args = ARGV)
136
+ begin
137
+ new(name).run(args)
138
+ rescue Clamp::UsageError => e
139
+ $stderr.puts "ERROR: #{e.message}"
140
+ $stderr.puts ""
141
+ $stderr.puts e.command.help
142
+ exit(1)
143
+ rescue Clamp::HelpWanted => e
144
+ puts e.command.help
145
+ end
146
+ end
147
+
148
+ private
149
+
150
+ def declare_option_reader(option)
151
+ reader_name = option.attribute_name
152
+ reader_name += "?" if option.flag?
153
+ class_eval <<-RUBY
154
+ def #{reader_name}
155
+ @#{option.attribute_name}
156
+ end
157
+ RUBY
158
+ end
159
+
160
+ def declare_option_writer(option, &block)
161
+ define_method("#{option.attribute_name}=") do |value|
162
+ if block
163
+ value = instance_exec(value, &block)
164
+ end
165
+ instance_variable_set("@#{option.attribute_name}", value)
166
+ end
167
+ end
168
+
169
+ end
170
+
171
+ end
172
+
173
+ class Error < StandardError
174
+
175
+ def initialize(message, command)
176
+ super(message)
177
+ @command = command
178
+ end
179
+
180
+ attr_reader :command
181
+
182
+ end
183
+
184
+ # raise to signal incorrect command usage
185
+ class UsageError < Error; end
186
+
187
+ # raise to request usage help
188
+ class HelpWanted < Error
189
+
190
+ def initialize(command)
191
+ super("I need help", command)
192
+ end
193
+
194
+ end
195
+
196
+ end
@@ -0,0 +1,54 @@
1
+ module Clamp
2
+
3
+ class Option
4
+
5
+ def initialize(switches, argument_type, description, options = {})
6
+ @switches = Array(switches)
7
+ @argument_type = argument_type
8
+ @description = description
9
+ @attribute_name = options[:attribute_name].to_s if options.has_key?(:attribute_name)
10
+ end
11
+
12
+ attr_reader :switches, :argument_type, :description
13
+
14
+ def attribute_name
15
+ @attribute_name ||= long_switch.sub(/^--(\[no-\])?/, '').tr('-', '_')
16
+ end
17
+
18
+ def long_switch
19
+ switches.find { |switch| switch =~ /^--/ }
20
+ end
21
+
22
+ def handles?(switch)
23
+ recognised_switches.member?(switch)
24
+ end
25
+
26
+ def flag?
27
+ @argument_type == :flag
28
+ end
29
+
30
+ def flag_value(switch)
31
+ !(switch =~ /^--no-(.*)/ && switches.member?("--\[no-\]#{$1}"))
32
+ end
33
+
34
+ def help
35
+ lhs = switches.join(", ")
36
+ lhs += " " + argument_type unless flag?
37
+ [lhs, description]
38
+ end
39
+
40
+ private
41
+
42
+ def recognised_switches
43
+ switches.map do |switch|
44
+ if switch =~ /^--\[no-\](.*)/
45
+ ["--#{$1}", "--no-#{$1}"]
46
+ else
47
+ switch
48
+ end
49
+ end.flatten
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,3 @@
1
+ module Clamp
2
+ VERSION = "0.0.1".freeze
3
+ end
@@ -0,0 +1,385 @@
1
+ require 'spec_helper'
2
+ require 'stringio'
3
+
4
+ describe Clamp::Command do
5
+
6
+ before do
7
+ $stdout = @out = StringIO.new
8
+ $stderr = @err = StringIO.new
9
+ end
10
+
11
+ after do
12
+ $stdout = STDOUT
13
+ $stderr = STDERR
14
+ end
15
+
16
+ def stdout
17
+ @out.string
18
+ end
19
+
20
+ def stderr
21
+ @err.string
22
+ end
23
+
24
+ def self.given_command(name, &block)
25
+ before do
26
+ @command = Class.new(Clamp::Command, &block).new(name)
27
+ end
28
+ end
29
+
30
+ given_command("cmd") do
31
+
32
+ def execute
33
+ print arguments.inspect
34
+ end
35
+
36
+ end
37
+
38
+ describe "#help" do
39
+
40
+ it "describes usage" do
41
+ @command.help.should include("Usage:\n cmd\n")
42
+ end
43
+
44
+ end
45
+
46
+ describe "#parse" do
47
+
48
+ it "sets arguments" do
49
+ @command.parse(%w(a b c))
50
+ @command.arguments.should == %w(a b c)
51
+ end
52
+
53
+ describe "with an unrecognised option" do
54
+
55
+ it "raises a UsageError" do
56
+ lambda do
57
+ @command.parse(%w(--foo bar))
58
+ end.should raise_error(Clamp::UsageError)
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+
65
+ describe "#run" do
66
+
67
+ before do
68
+ @abc = %w(a b c)
69
+ @command.run(@abc)
70
+ end
71
+
72
+ it "executes the #execute method" do
73
+ stdout.should_not be_empty
74
+ end
75
+
76
+ it "provides access to the argument list" do
77
+ stdout.should == @abc.inspect
78
+ end
79
+
80
+ end
81
+
82
+ describe ".option" do
83
+
84
+ before do
85
+ @command.class.option "--flavour", "FLAVOUR", "Flavour of the month"
86
+ end
87
+
88
+ it "declares option argument accessors" do
89
+ @command.flavour.should == nil
90
+ @command.flavour = "chocolate"
91
+ @command.flavour.should == "chocolate"
92
+ end
93
+
94
+ end
95
+
96
+ describe ".option", "with explicit :attribute_name" do
97
+
98
+ before do
99
+ @command.class.option "--foo", "FOO", "A foo", :attribute_name => :bar
100
+ end
101
+
102
+ it "uses the specified attribute_name name to name accessors" do
103
+ @command.bar = "chocolate"
104
+ @command.bar.should == "chocolate"
105
+ end
106
+
107
+ it "does not attempt to create the default accessors" do
108
+ @command.should_not respond_to(:foo)
109
+ @command.should_not respond_to(:foo=)
110
+ end
111
+
112
+ end
113
+
114
+ describe "with options declared" do
115
+
116
+ before do
117
+ @command.class.option "--flavour", "FLAVOUR", "Flavour of the month"
118
+ @command.class.option "--color", "COLOR", "Preferred hue"
119
+ end
120
+
121
+ describe "#parse" do
122
+
123
+ describe "with options" do
124
+
125
+ before do
126
+ @command.parse(%w(--flavour strawberry --color blue a b c))
127
+ end
128
+
129
+ it "extracts the option values" do
130
+ @command.flavour.should == "strawberry"
131
+ @command.color.should == "blue"
132
+ end
133
+
134
+ it "retains unconsumed arguments" do
135
+ @command.arguments.should == %w(a b c)
136
+ end
137
+
138
+ end
139
+
140
+ describe "with option-like things beyond the arguments" do
141
+
142
+ it "treats them as positional arguments" do
143
+ @command.parse(%w(a b c --flavour strawberry))
144
+ @command.arguments.should == %w(a b c --flavour strawberry)
145
+ end
146
+
147
+ end
148
+
149
+ describe "with an option terminator" do
150
+
151
+ it "considers everything after the terminator to be an argument" do
152
+ @command.parse(%w(--color blue -- --flavour strawberry))
153
+ @command.arguments.should == %w(--flavour strawberry)
154
+ end
155
+
156
+ end
157
+
158
+ end
159
+
160
+ describe "#help" do
161
+
162
+ it "indicates that there are options" do
163
+ @command.help.should include("cmd [OPTIONS]")
164
+ end
165
+
166
+ it "includes option details" do
167
+ @command.help.should =~ %r(--flavour FLAVOUR +Flavour of the month)
168
+ @command.help.should =~ %r(--color COLOR +Preferred hue)
169
+ end
170
+
171
+ end
172
+
173
+ end
174
+
175
+ describe "with a flag option declared" do
176
+
177
+ before do
178
+ @command.class.option "--verbose", :flag, "Be heartier"
179
+ end
180
+
181
+ it "declares a predicate-style reader" do
182
+ @command.should respond_to(:verbose?)
183
+ @command.should_not respond_to(:verbose)
184
+ end
185
+
186
+ describe "#parse" do
187
+
188
+ describe "with option" do
189
+
190
+ before do
191
+ @command.parse(%w(--verbose foo))
192
+ end
193
+
194
+ it "sets the flag" do
195
+ @command.should be_verbose
196
+ end
197
+
198
+ it "does not consume an argument" do
199
+ @command.arguments.should == %w(foo)
200
+ end
201
+
202
+ end
203
+
204
+ end
205
+
206
+ end
207
+
208
+ describe "with a negatable flag option declared" do
209
+
210
+ before do
211
+ @command.class.option "--[no-]sync", :flag, "Synchronise"
212
+ end
213
+
214
+ describe "#parse" do
215
+
216
+ describe "with --flag" do
217
+
218
+ before do
219
+ @command.parse(%w(--sync))
220
+ end
221
+
222
+ it "sets the flag" do
223
+ @command.sync?.should be_true
224
+ end
225
+
226
+ end
227
+
228
+ describe "with --no-flag" do
229
+
230
+ before do
231
+ @command.sync = true
232
+ @command.parse(%w(--no-sync))
233
+ end
234
+
235
+ it "clears the flag" do
236
+ @command.sync?.should be_false
237
+ end
238
+
239
+ end
240
+
241
+ end
242
+
243
+ end
244
+
245
+ describe ".option, with a block" do
246
+
247
+ before do
248
+ @command.class.option "--port", "PORT", "Port to listen on" do |port|
249
+ Integer(port)
250
+ end
251
+ end
252
+
253
+ it "uses the block to validate and convert the option argument" do
254
+ lambda do
255
+ @command.port = "blah"
256
+ end.should raise_error(ArgumentError)
257
+ @command.port = "1234"
258
+ @command.port.should == 1234
259
+ end
260
+
261
+ describe "#parse" do
262
+
263
+ describe "with a valid option argument" do
264
+
265
+ it "stores the converted value" do
266
+ @command.parse(%w(--port 4321))
267
+ @command.port.should == 4321
268
+ end
269
+
270
+ end
271
+
272
+ describe "with an invalid option argument" do
273
+
274
+ it "raises a UsageError" do
275
+ lambda do
276
+ @command.parse(%w(--port blah))
277
+ end.should raise_error(Clamp::UsageError, /^option '--port': invalid value/)
278
+ end
279
+
280
+ end
281
+
282
+ end
283
+
284
+ end
285
+
286
+ describe "with explicit usage" do
287
+
288
+ given_command("blah") do
289
+
290
+ usage "FOO BAR ..."
291
+
292
+ end
293
+
294
+ describe "#help" do
295
+
296
+ it "includes the explicit usage" do
297
+ @command.help.should include("blah FOO BAR ...\n")
298
+ end
299
+
300
+ end
301
+
302
+ end
303
+
304
+ describe "with multiple usages" do
305
+
306
+ given_command("put") do
307
+
308
+ usage "THIS HERE"
309
+ usage "THAT THERE"
310
+
311
+ end
312
+
313
+ describe "#help" do
314
+
315
+ it "includes both potential usages" do
316
+ @command.help.should include("put THIS HERE\n")
317
+ @command.help.should include("put THAT THERE\n")
318
+ end
319
+
320
+ end
321
+
322
+ end
323
+
324
+ describe ".run" do
325
+
326
+ it "creates a new Command instance and runs it" do
327
+ @xyz = %w(x y z)
328
+ @command.class.run("cmd", @xyz)
329
+ stdout.should == @xyz.inspect
330
+ end
331
+
332
+ describe "when there's a UsageError" do
333
+
334
+ before do
335
+
336
+ @command.class.class_eval do
337
+ def execute
338
+ signal_usage_error "bad dog!"
339
+ end
340
+ end
341
+
342
+ begin
343
+ @command.class.run("cmd", [])
344
+ rescue SystemExit => e
345
+ @system_exit = e
346
+ end
347
+
348
+ end
349
+
350
+ it "outputs the error message" do
351
+ stderr.should include "ERROR: bad dog!"
352
+ end
353
+
354
+ it "outputs help" do
355
+ stderr.should include "Usage:"
356
+ end
357
+
358
+ it "exits with a non-zero status" do
359
+ @system_exit.should_not be_nil
360
+ @system_exit.status.should == 1
361
+ end
362
+
363
+ end
364
+
365
+ describe "when help is requested" do
366
+
367
+ before do
368
+
369
+ @command.class.class_eval do
370
+ help_option "--help"
371
+ end
372
+
373
+ @command.class.run("cmd", ["--help"])
374
+
375
+ end
376
+
377
+ it "outputs help" do
378
+ stdout.should include "Usage:"
379
+ end
380
+
381
+ end
382
+
383
+ end
384
+
385
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ describe Clamp::Option do
4
+
5
+ describe "with String argument" do
6
+
7
+ before do
8
+ @option = Clamp::Option.new("--key-file", "FILE", "SSH identity")
9
+ end
10
+
11
+ it "has a long_switch" do
12
+ @option.long_switch.should == "--key-file"
13
+ end
14
+
15
+ it "has an argument_type" do
16
+ @option.argument_type.should == "FILE"
17
+ end
18
+
19
+ it "has a description" do
20
+ @option.description.should == "SSH identity"
21
+ end
22
+
23
+ describe "#attribute_name" do
24
+
25
+ it "is derived from the (long) switch" do
26
+ @option.attribute_name.should == "key_file"
27
+ end
28
+
29
+ it "can be overridden" do
30
+ @option = Clamp::Option.new("--key-file", "FILE", "SSH identity", :attribute_name => "ssh_identity")
31
+ @option.attribute_name.should == "ssh_identity"
32
+ end
33
+
34
+ end
35
+
36
+ describe "#help" do
37
+
38
+ it "combines switch, argument_type and description" do
39
+ @option.help.should == ["--key-file FILE", "SSH identity"]
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ describe "flag" do
47
+
48
+ before do
49
+ @option = Clamp::Option.new("--verbose", :flag, "Blah blah blah")
50
+ end
51
+
52
+ describe "#help" do
53
+
54
+ it "excludes option argument" do
55
+ @option.help.should == ["--verbose", "Blah blah blah"]
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
62
+ describe "negatable flag" do
63
+
64
+ before do
65
+ @option = Clamp::Option.new("--[no-]force", :flag, "Force installation")
66
+ end
67
+
68
+ it "handles both positive and negative forms" do
69
+ @option.handles?("--force").should be_true
70
+ @option.handles?("--no-force").should be_true
71
+ end
72
+
73
+ describe "#flag_value" do
74
+
75
+ it "returns true for the positive variant" do
76
+ @option.flag_value("--force").should be_true
77
+ @option.flag_value("--no-force").should be_false
78
+ end
79
+
80
+ end
81
+
82
+ describe "#attribute_name" do
83
+
84
+ it "is derived from the (long) switch" do
85
+ @option.attribute_name.should == "force"
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+
92
+ describe "with both short and long switches" do
93
+
94
+ before do
95
+ @option = Clamp::Option.new(["-k", "--key-file"], "FILE", "SSH identity")
96
+ end
97
+
98
+ it "handles both switches" do
99
+ @option.handles?("--key-file").should be_true
100
+ @option.handles?("-k").should be_true
101
+ end
102
+
103
+ describe "#help" do
104
+
105
+ it "includes both switches" do
106
+ @option.help.should == ["-k, --key-file FILE", "SSH identity"]
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+
113
+ end
@@ -0,0 +1,8 @@
1
+ require "rspec"
2
+ require "clamp"
3
+
4
+ Rspec.configure do |config|
5
+
6
+ config.mock_with :rr
7
+
8
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clamp
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Mike Williams
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-02 00:00:00 +11:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: |
23
+ Clamp makes provides an object-model for command-line utilities.
24
+ It handles parsing of command-line options, and generation of usage help.
25
+
26
+ email: mdub@dogbiscuit.org
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - .gitignore
35
+ - Gemfile
36
+ - Gemfile.lock
37
+ - README.markdown
38
+ - Rakefile
39
+ - clamp.gemspec
40
+ - examples/rename
41
+ - lib/clamp.rb
42
+ - lib/clamp/argument.rb
43
+ - lib/clamp/command.rb
44
+ - lib/clamp/option.rb
45
+ - lib/clamp/version.rb
46
+ - spec/clamp/command_spec.rb
47
+ - spec/clamp/option_spec.rb
48
+ - spec/spec_helper.rb
49
+ has_rdoc: true
50
+ homepage: http://github.com/mdub/clamp
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options: []
55
+
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 3
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.3.7
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: a minimal framework for command-line utilities
83
+ test_files:
84
+ - spec/clamp/command_spec.rb
85
+ - spec/clamp/option_spec.rb
86
+ - spec/spec_helper.rb