clamp 0.6.3 → 0.6.4
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.
- checksums.yaml +6 -14
- data/.autotest +2 -0
- data/.travis.yml +2 -0
- data/CHANGES.md +8 -0
- data/Gemfile +3 -3
- data/README.md +17 -3
- data/Rakefile +1 -1
- data/examples/fubar +1 -1
- data/lib/clamp/attribute/instance.rb +2 -5
- data/lib/clamp/command.rb +10 -0
- data/lib/clamp/errors.rb +12 -0
- data/lib/clamp/version.rb +1 -1
- data/spec/clamp/command_group_spec.rb +31 -31
- data/spec/clamp/command_spec.rb +244 -188
- data/spec/clamp/option/definition_spec.rb +37 -37
- data/spec/clamp/option_module_spec.rb +2 -2
- data/spec/clamp/parameter/definition_spec.rb +37 -37
- data/spec/spec_helper.rb +12 -0
- metadata +11 -13
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
NGFjOTY4MTQ3OTg2NDZhMjA3OWE5MmEzYTVlM2VmMzc0NjAxYWUwNDAxZThi
|
10
|
-
MGY1MDMwNWE2NGY0ZDNhYjZkZTQ4MGEzNWU4Y2RhZTAzMDVkMjEyZjIwNzY1
|
11
|
-
YmMxNWQ3NzY2MTIwMWZjM2UwNGEyMmU5ODllY2I5MGFhMzY2MWM=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
OWNjMTNkOGNkYjZiMjNlNmRiODc4MWFmMzRhOWJmODIwZjBmNDkzNWVhZGQ2
|
14
|
-
MzExZDg3ZTMwNDBjZjkxZDZkZGFiYzU1YzQ5NGM0ZDVhYjAyN2U3NTc0M2Qz
|
15
|
-
MzRiZTVlMTJkOTU4YjkxZTVjMTIxNGIzNWY1OTI5OTVmYmYyODA=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0222cf7a03642506d668988d57a60b992accc073
|
4
|
+
data.tar.gz: 9d0314d698965b297003ebca1ad6a31183c91fac
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c9cbcdeded12d74963a8a00681f715640d185f6a0ee6faa285cf9b03b8f00721115a35664602f06b2ea40e8fd670be3546338f624b24feae7d450f1a659ad9e0
|
7
|
+
data.tar.gz: 4d304f351b33bd4eeb034837b3174d06898dd02eb5349db2142be751634b5885b0bc2160654b7af3a97392582fcab705968c2b7de72b37bb1828b885eef6c76e
|
data/.autotest
CHANGED
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
|
2
|
-
Clamp [](http://travis-ci.org/mdub/clamp)
|
1
|
+
Clamp
|
3
2
|
=====
|
4
3
|
|
4
|
+
[](http://badge.fury.io/rb/clamp)
|
5
|
+
[](http://travis-ci.org/mdub/clamp)
|
6
|
+
|
5
7
|
"Clamp" is a minimal framework for command-line utilities.
|
6
8
|
|
7
9
|
It handles boring stuff like parsing the command-line, and generating help, so you can get on with making your command actually do stuff.
|
@@ -197,7 +199,7 @@ Clamp will verify that all required (ie. non-optional) parameters are present, a
|
|
197
199
|
### Validation
|
198
200
|
|
199
201
|
Both `option` and `parameter` accept an optional block. If present, the block will be
|
200
|
-
called with the raw string argument, and is expected to validate it. The value returned by the block will be assigned to the underlying attribute, so it's also a good place to coerce the String to a different type, if appropriate.
|
202
|
+
called with the raw string argument, and is expected to validate it. The value returned by the block will be assigned to the underlying attribute, so it's also a good place to coerce the String to a different type, if appropriate.
|
201
203
|
|
202
204
|
For example:
|
203
205
|
|
@@ -314,6 +316,18 @@ class InitCommand < Clamp::Command
|
|
314
316
|
end
|
315
317
|
```
|
316
318
|
|
319
|
+
Like options, subcommands may have aliases:
|
320
|
+
|
321
|
+
```ruby
|
322
|
+
Clamp do
|
323
|
+
|
324
|
+
subcommand ["initialize", "init"], "Initialize the repository" do
|
325
|
+
# ...
|
326
|
+
end
|
327
|
+
|
328
|
+
end
|
329
|
+
```
|
330
|
+
|
317
331
|
### Default subcommand
|
318
332
|
|
319
333
|
You can set a default subcommand, at the class level, as follows:
|
data/Rakefile
CHANGED
data/examples/fubar
CHANGED
data/lib/clamp/command.rb
CHANGED
@@ -103,6 +103,13 @@ module Clamp
|
|
103
103
|
raise e
|
104
104
|
end
|
105
105
|
|
106
|
+
def signal_error(message, options = {})
|
107
|
+
status = options.fetch(:status, 1)
|
108
|
+
e = ExecutionError.new(message, self, status)
|
109
|
+
e.set_backtrace(caller)
|
110
|
+
raise e
|
111
|
+
end
|
112
|
+
|
106
113
|
def request_help
|
107
114
|
raise HelpWanted, self
|
108
115
|
end
|
@@ -130,6 +137,9 @@ module Clamp
|
|
130
137
|
exit(1)
|
131
138
|
rescue Clamp::HelpWanted => e
|
132
139
|
puts e.command.help
|
140
|
+
rescue Clamp::ExecutionError => e
|
141
|
+
$stderr.puts "ERROR: #{e.message}"
|
142
|
+
exit(e.status)
|
133
143
|
end
|
134
144
|
end
|
135
145
|
|
data/lib/clamp/errors.rb
CHANGED
@@ -26,4 +26,16 @@ module Clamp
|
|
26
26
|
|
27
27
|
end
|
28
28
|
|
29
|
+
# raise to signal error during execution
|
30
|
+
class ExecutionError < RuntimeError
|
31
|
+
|
32
|
+
def initialize(message, command, status = 1)
|
33
|
+
super(message, command)
|
34
|
+
@status = status
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :status
|
38
|
+
|
39
|
+
end
|
40
|
+
|
29
41
|
end
|
data/lib/clamp/version.rb
CHANGED
@@ -5,7 +5,7 @@ describe Clamp::Command do
|
|
5
5
|
extend CommandFactory
|
6
6
|
include OutputCapture
|
7
7
|
|
8
|
-
|
8
|
+
context "with subcommands" do
|
9
9
|
|
10
10
|
given_command "flipflop" do
|
11
11
|
|
@@ -30,19 +30,19 @@ describe Clamp::Command do
|
|
30
30
|
it "delegates to sub-commands" do
|
31
31
|
|
32
32
|
command.run(["flip"])
|
33
|
-
stdout.
|
33
|
+
expect(stdout).to match /FLIPPED/
|
34
34
|
|
35
35
|
command.run(["flop"])
|
36
|
-
stdout.
|
36
|
+
expect(stdout).to match /FLOPPED/
|
37
37
|
|
38
38
|
end
|
39
39
|
|
40
40
|
context "executed with no subcommand" do
|
41
41
|
|
42
42
|
it "triggers help" do
|
43
|
-
|
43
|
+
expect do
|
44
44
|
command.run([])
|
45
|
-
end.
|
45
|
+
end.to raise_error(Clamp::HelpWanted)
|
46
46
|
end
|
47
47
|
|
48
48
|
end
|
@@ -50,25 +50,25 @@ describe Clamp::Command do
|
|
50
50
|
describe "#help" do
|
51
51
|
|
52
52
|
it "shows subcommand parameters in usage" do
|
53
|
-
command.help.
|
53
|
+
expect(command.help).to include("flipflop [OPTIONS] SUBCOMMAND [ARG] ...")
|
54
54
|
end
|
55
55
|
|
56
56
|
it "lists subcommands" do
|
57
57
|
help = command.help
|
58
|
-
help.
|
59
|
-
help.
|
60
|
-
help.
|
58
|
+
expect(help).to match /Subcommands:/
|
59
|
+
expect(help).to match /flip +flip it/
|
60
|
+
expect(help).to match /flop +flop it/
|
61
61
|
end
|
62
62
|
|
63
63
|
it "handles new lines in subcommand descriptions" do
|
64
|
-
command.help.
|
64
|
+
expect(command.help).to match /flop +flop it\n +for extra flop/
|
65
65
|
end
|
66
66
|
|
67
67
|
end
|
68
68
|
|
69
69
|
end
|
70
70
|
|
71
|
-
|
71
|
+
context "with an aliased subcommand" do
|
72
72
|
|
73
73
|
given_command "blah" do
|
74
74
|
|
@@ -87,10 +87,10 @@ describe Clamp::Command do
|
|
87
87
|
it "responds to both aliases" do
|
88
88
|
|
89
89
|
command.run(["say", "boo"])
|
90
|
-
stdout.
|
90
|
+
expect(stdout).to match /boo/
|
91
91
|
|
92
92
|
command.run(["talk", "jive"])
|
93
|
-
stdout.
|
93
|
+
expect(stdout).to match /jive/
|
94
94
|
|
95
95
|
end
|
96
96
|
|
@@ -98,14 +98,14 @@ describe Clamp::Command do
|
|
98
98
|
|
99
99
|
it "lists all aliases" do
|
100
100
|
help = command.help
|
101
|
-
help.
|
101
|
+
expect(help).to match /say, talk .* Say something/
|
102
102
|
end
|
103
103
|
|
104
104
|
end
|
105
105
|
|
106
106
|
end
|
107
107
|
|
108
|
-
|
108
|
+
context "with nested subcommands" do
|
109
109
|
|
110
110
|
given_command "fubar" do
|
111
111
|
|
@@ -123,12 +123,12 @@ describe Clamp::Command do
|
|
123
123
|
|
124
124
|
it "delegates multiple levels" do
|
125
125
|
command.run(["foo", "bar"])
|
126
|
-
stdout.
|
126
|
+
expect(stdout).to match /FUBAR/
|
127
127
|
end
|
128
128
|
|
129
129
|
end
|
130
130
|
|
131
|
-
|
131
|
+
context "with a default subcommand" do
|
132
132
|
|
133
133
|
given_command "admin" do
|
134
134
|
|
@@ -148,14 +148,14 @@ describe Clamp::Command do
|
|
148
148
|
|
149
149
|
it "invokes the default subcommand" do
|
150
150
|
command.run([])
|
151
|
-
stdout.
|
151
|
+
expect(stdout).to match /All good/
|
152
152
|
end
|
153
153
|
|
154
154
|
end
|
155
155
|
|
156
156
|
end
|
157
157
|
|
158
|
-
|
158
|
+
context "with a default subcommand, declared the old way" do
|
159
159
|
|
160
160
|
given_command "admin" do
|
161
161
|
|
@@ -173,18 +173,18 @@ describe Clamp::Command do
|
|
173
173
|
|
174
174
|
it "invokes the default subcommand" do
|
175
175
|
command.run([])
|
176
|
-
stdout.
|
176
|
+
expect(stdout).to match /All good/
|
177
177
|
end
|
178
178
|
|
179
179
|
end
|
180
180
|
|
181
181
|
end
|
182
182
|
|
183
|
-
|
183
|
+
context "declaring a default subcommand after subcommands" do
|
184
184
|
|
185
185
|
it "is not supported" do
|
186
186
|
|
187
|
-
|
187
|
+
expect do
|
188
188
|
Class.new(Clamp::Command) do
|
189
189
|
|
190
190
|
subcommand "status", "Show status" do
|
@@ -198,13 +198,13 @@ describe Clamp::Command do
|
|
198
198
|
self.default_subcommand = "status"
|
199
199
|
|
200
200
|
end
|
201
|
-
end.
|
201
|
+
end.to raise_error(/default_subcommand must be defined before subcommands/)
|
202
202
|
|
203
203
|
end
|
204
204
|
|
205
205
|
end
|
206
206
|
|
207
|
-
|
207
|
+
context "with subcommands, declared after a parameter" do
|
208
208
|
|
209
209
|
given_command "with" do
|
210
210
|
|
@@ -221,7 +221,7 @@ describe Clamp::Command do
|
|
221
221
|
it "allows the parameter to be specified first" do
|
222
222
|
|
223
223
|
command.run(["dummy", "spit"])
|
224
|
-
stdout.strip.
|
224
|
+
expect(stdout.strip).to eql "spat the dummy"
|
225
225
|
|
226
226
|
end
|
227
227
|
|
@@ -260,28 +260,28 @@ describe Clamp::Command do
|
|
260
260
|
|
261
261
|
it "accepts options defined in superclass (specified after the subcommand)" do
|
262
262
|
command.run(["move", "--direction", "north"])
|
263
|
-
stdout.
|
263
|
+
expect(stdout).to match /walking north/
|
264
264
|
end
|
265
265
|
|
266
266
|
it "accepts options defined in superclass (specified before the subcommand)" do
|
267
267
|
command.run(["--direction", "north", "move"])
|
268
|
-
stdout.
|
268
|
+
expect(stdout).to match /walking north/
|
269
269
|
end
|
270
270
|
|
271
271
|
it "accepts options defined in included modules" do
|
272
272
|
command.run(["move", "--speed", "very quickly"])
|
273
|
-
stdout.
|
273
|
+
expect(stdout).to match /walking home very quickly/
|
274
274
|
end
|
275
275
|
|
276
276
|
it "has access to command context" do
|
277
277
|
command = command_class.new("go", :motion => "wandering")
|
278
278
|
command.run(["move"])
|
279
|
-
stdout.
|
279
|
+
expect(stdout).to match /wandering home/
|
280
280
|
end
|
281
281
|
|
282
282
|
end
|
283
283
|
|
284
|
-
|
284
|
+
context "with a subcommand, with options" do
|
285
285
|
|
286
286
|
given_command 'weeheehee' do
|
287
287
|
option '--json', 'JSON', 'a json blob' do |option|
|
@@ -297,7 +297,7 @@ describe Clamp::Command do
|
|
297
297
|
|
298
298
|
it "only parses options once" do
|
299
299
|
command.run(['--json', '{"a":"b"}', 'woohoohoo'])
|
300
|
-
stdout.
|
300
|
+
expect(stdout).to eql 'parsing!'
|
301
301
|
end
|
302
302
|
|
303
303
|
end
|
data/spec/clamp/command_spec.rb
CHANGED
@@ -5,6 +5,7 @@ describe Clamp::Command do
|
|
5
5
|
|
6
6
|
extend CommandFactory
|
7
7
|
include OutputCapture
|
8
|
+
include SetEnv
|
8
9
|
|
9
10
|
given_command("cmd") do
|
10
11
|
|
@@ -17,7 +18,7 @@ describe Clamp::Command do
|
|
17
18
|
describe "#help" do
|
18
19
|
|
19
20
|
it "describes usage" do
|
20
|
-
command.help.
|
21
|
+
expect(command.help).to match /^Usage:\n cmd.*\n/
|
21
22
|
end
|
22
23
|
|
23
24
|
end
|
@@ -29,7 +30,7 @@ describe Clamp::Command do
|
|
29
30
|
end
|
30
31
|
|
31
32
|
it "executes the #execute method" do
|
32
|
-
stdout.
|
33
|
+
expect(stdout).to_not be_empty
|
33
34
|
end
|
34
35
|
|
35
36
|
end
|
@@ -38,25 +39,25 @@ describe Clamp::Command do
|
|
38
39
|
|
39
40
|
it "declares option argument accessors" do
|
40
41
|
command.class.option "--flavour", "FLAVOUR", "Flavour of the month"
|
41
|
-
command.flavour.
|
42
|
+
expect(command.flavour).to eql nil
|
42
43
|
command.flavour = "chocolate"
|
43
|
-
command.flavour.
|
44
|
+
expect(command.flavour).to eql "chocolate"
|
44
45
|
end
|
45
46
|
|
46
|
-
|
47
|
+
context "with type :flag" do
|
47
48
|
|
48
49
|
before do
|
49
50
|
command.class.option "--verbose", :flag, "Be heartier"
|
50
51
|
end
|
51
52
|
|
52
53
|
it "declares a predicate-style reader" do
|
53
|
-
command.
|
54
|
-
command.
|
54
|
+
expect(command).to respond_to(:verbose?)
|
55
|
+
expect(command).to_not respond_to(:verbose)
|
55
56
|
end
|
56
57
|
|
57
58
|
end
|
58
59
|
|
59
|
-
|
60
|
+
context "with explicit :attribute_name" do
|
60
61
|
|
61
62
|
before do
|
62
63
|
command.class.option "--foo", "FOO", "A foo", :attribute_name => :bar
|
@@ -64,17 +65,17 @@ describe Clamp::Command do
|
|
64
65
|
|
65
66
|
it "uses the specified attribute_name name to name accessors" do
|
66
67
|
command.bar = "chocolate"
|
67
|
-
command.bar.
|
68
|
+
expect(command.bar).to eql "chocolate"
|
68
69
|
end
|
69
70
|
|
70
71
|
it "does not attempt to create the default accessors" do
|
71
|
-
command.
|
72
|
-
command.
|
72
|
+
expect(command).to_not respond_to(:foo)
|
73
|
+
expect(command).to_not respond_to(:foo=)
|
73
74
|
end
|
74
75
|
|
75
76
|
end
|
76
77
|
|
77
|
-
|
78
|
+
context "with default method" do
|
78
79
|
|
79
80
|
before do
|
80
81
|
command.class.option "--port", "PORT", "port"
|
@@ -86,97 +87,95 @@ describe Clamp::Command do
|
|
86
87
|
end
|
87
88
|
|
88
89
|
it "sets the specified default value" do
|
89
|
-
command.port.
|
90
|
+
expect(command.port).to eql 4321
|
90
91
|
end
|
91
92
|
|
92
93
|
end
|
93
94
|
|
94
|
-
|
95
|
+
context "with :default value" do
|
95
96
|
|
96
97
|
before do
|
97
98
|
command.class.option "--port", "PORT", "port to listen on", :default => 4321
|
98
99
|
end
|
99
100
|
|
100
101
|
it "declares default method" do
|
101
|
-
command.default_port.
|
102
|
+
expect(command.default_port).to eql 4321
|
102
103
|
end
|
103
104
|
|
104
105
|
describe "#help" do
|
105
106
|
|
106
107
|
it "describes the default value" do
|
107
|
-
command.help.
|
108
|
+
expect(command.help).to include("port to listen on (default: 4321)")
|
108
109
|
end
|
109
110
|
|
110
111
|
end
|
111
112
|
|
112
113
|
end
|
113
114
|
|
114
|
-
|
115
|
+
context "with :multivalued" do
|
115
116
|
|
116
117
|
before do
|
117
118
|
command.class.option "--flavour", "FLAVOUR", "flavour(s)", :multivalued => true, :attribute_name => :flavours
|
118
119
|
end
|
119
120
|
|
120
121
|
it "defaults to empty array" do
|
121
|
-
command.flavours.
|
122
|
+
expect(command.flavours).to eql []
|
122
123
|
end
|
123
124
|
|
124
125
|
it "supports multiple values" do
|
125
126
|
command.parse(%w(--flavour chocolate --flavour vanilla))
|
126
|
-
command.flavours.
|
127
|
+
expect(command.flavours).to eql %w(chocolate vanilla)
|
127
128
|
end
|
128
129
|
|
129
130
|
it "generates a single-value appender method" do
|
130
131
|
command.append_to_flavours("mud")
|
131
132
|
command.append_to_flavours("pie")
|
132
|
-
command.flavours.
|
133
|
+
expect(command.flavours).to eql %w(mud pie)
|
133
134
|
end
|
134
135
|
|
135
136
|
it "generates a multi-value setter method" do
|
136
137
|
command.append_to_flavours("replaceme")
|
137
138
|
command.flavours = %w(mud pie)
|
138
|
-
command.flavours.
|
139
|
+
expect(command.flavours).to eql %w(mud pie)
|
139
140
|
end
|
140
141
|
|
141
142
|
end
|
142
143
|
|
143
|
-
|
144
|
+
context "with :environment_variable" do
|
145
|
+
|
146
|
+
let(:environment_value) { nil }
|
147
|
+
let(:args) { [] }
|
144
148
|
|
145
149
|
before do
|
146
150
|
command.class.option "--port", "PORT", "port to listen on", :default => 4321, :environment_variable => "PORT" do |value|
|
147
151
|
value.to_i
|
148
152
|
end
|
153
|
+
set_env("PORT", environment_value)
|
154
|
+
command.parse(args)
|
149
155
|
end
|
150
156
|
|
151
157
|
context "when no environment variable is present" do
|
152
158
|
|
153
|
-
before do
|
154
|
-
ENV.delete("PORT")
|
155
|
-
end
|
156
|
-
|
157
159
|
it "uses the default" do
|
158
|
-
command.
|
159
|
-
command.port.should == 4321
|
160
|
+
expect(command.port).to eql 4321
|
160
161
|
end
|
161
162
|
|
162
163
|
end
|
163
164
|
|
164
165
|
context "when environment variable is present" do
|
165
166
|
|
166
|
-
|
167
|
-
ENV["PORT"] = "12345"
|
168
|
-
end
|
167
|
+
let(:environment_value) { "12345" }
|
169
168
|
|
170
169
|
it "uses the environment variable" do
|
171
|
-
command.
|
172
|
-
command.port.should == 12345
|
170
|
+
expect(command.port).to eql 12345
|
173
171
|
end
|
174
172
|
|
175
173
|
context "and a value is specified on the command-line" do
|
176
174
|
|
175
|
+
let(:args) { %w(--port 1500) }
|
176
|
+
|
177
177
|
it "uses command-line value" do
|
178
|
-
command.
|
179
|
-
command.port.should == 1500
|
178
|
+
expect(command.port).to eql 1500
|
180
179
|
end
|
181
180
|
|
182
181
|
end
|
@@ -186,28 +185,27 @@ describe Clamp::Command do
|
|
186
185
|
describe "#help" do
|
187
186
|
|
188
187
|
it "describes the default value and env usage" do
|
189
|
-
command.help.
|
188
|
+
expect(command.help).to include("port to listen on (default: $PORT, or 4321)")
|
190
189
|
end
|
191
190
|
|
192
191
|
end
|
193
192
|
|
194
193
|
end
|
195
194
|
|
196
|
-
|
195
|
+
context "with :environment_variable and type :flag" do
|
196
|
+
|
197
|
+
let(:environment_value) { nil }
|
197
198
|
|
198
199
|
before do
|
199
200
|
command.class.option "--[no-]enable", :flag, "enable?", :default => false, :environment_variable => "ENABLE"
|
201
|
+
set_env("ENABLE", environment_value)
|
202
|
+
command.parse([])
|
200
203
|
end
|
201
204
|
|
202
205
|
context "when no environment variable is present" do
|
203
206
|
|
204
|
-
before do
|
205
|
-
ENV.delete("ENABLE")
|
206
|
-
end
|
207
|
-
|
208
207
|
it "uses the default" do
|
209
|
-
command.
|
210
|
-
command.enable?.should == false
|
208
|
+
expect(command.enable?).to eql false
|
211
209
|
end
|
212
210
|
|
213
211
|
end
|
@@ -216,10 +214,10 @@ describe Clamp::Command do
|
|
216
214
|
|
217
215
|
context "when environment variable is #{truthy_value.inspect}" do
|
218
216
|
|
217
|
+
let(:environment_value) { truthy_value }
|
218
|
+
|
219
219
|
it "sets the flag" do
|
220
|
-
|
221
|
-
command.parse([])
|
222
|
-
command.enable?.should == true
|
220
|
+
expect(command.enable?).to eql true
|
223
221
|
end
|
224
222
|
|
225
223
|
end
|
@@ -230,10 +228,10 @@ describe Clamp::Command do
|
|
230
228
|
|
231
229
|
context "when environment variable is #{falsey_value.inspect}" do
|
232
230
|
|
231
|
+
let(:environment_value) { falsey_value }
|
232
|
+
|
233
233
|
it "clears the flag" do
|
234
|
-
|
235
|
-
command.parse([])
|
236
|
-
command.enable?.should == false
|
234
|
+
expect(command.enable?).to eql false
|
237
235
|
end
|
238
236
|
|
239
237
|
end
|
@@ -242,7 +240,7 @@ describe Clamp::Command do
|
|
242
240
|
|
243
241
|
end
|
244
242
|
|
245
|
-
|
243
|
+
context "with :required" do
|
246
244
|
|
247
245
|
before do
|
248
246
|
command.class.option "--port", "PORT", "port to listen on", :required => true
|
@@ -270,7 +268,7 @@ describe Clamp::Command do
|
|
270
268
|
|
271
269
|
end
|
272
270
|
|
273
|
-
|
271
|
+
context "with a block" do
|
274
272
|
|
275
273
|
before do
|
276
274
|
command.class.option "--port", "PORT", "Port to listen on" do |port|
|
@@ -279,18 +277,18 @@ describe Clamp::Command do
|
|
279
277
|
end
|
280
278
|
|
281
279
|
it "uses the block to validate and convert the option argument" do
|
282
|
-
|
280
|
+
expect do
|
283
281
|
command.port = "blah"
|
284
|
-
end.
|
282
|
+
end.to raise_error(ArgumentError)
|
285
283
|
command.port = "1234"
|
286
|
-
command.port.
|
284
|
+
expect(command.port).to eql 1234
|
287
285
|
end
|
288
286
|
|
289
287
|
end
|
290
288
|
|
291
289
|
end
|
292
290
|
|
293
|
-
|
291
|
+
context "with options declared" do
|
294
292
|
|
295
293
|
before do
|
296
294
|
command.class.option ["-f", "--flavour"], "FLAVOUR", "Flavour of the month"
|
@@ -306,126 +304,126 @@ describe Clamp::Command do
|
|
306
304
|
|
307
305
|
describe "#parse" do
|
308
306
|
|
309
|
-
|
307
|
+
context "with an unrecognised option" do
|
310
308
|
|
311
309
|
it "raises a UsageError" do
|
312
|
-
|
310
|
+
expect do
|
313
311
|
command.parse(%w(--foo bar))
|
314
|
-
end.
|
312
|
+
end.to raise_error(Clamp::UsageError)
|
315
313
|
end
|
316
314
|
|
317
315
|
end
|
318
316
|
|
319
|
-
|
317
|
+
context "with options" do
|
320
318
|
|
321
319
|
before do
|
322
320
|
command.parse(%w(--flavour strawberry --nuts --color blue))
|
323
321
|
end
|
324
322
|
|
325
323
|
it "maps the option values onto the command object" do
|
326
|
-
command.flavour.
|
327
|
-
command.color.
|
328
|
-
command.nuts
|
324
|
+
expect(command.flavour).to eql "strawberry"
|
325
|
+
expect(command.color).to eql "blue"
|
326
|
+
expect(command.nuts?).to eql true
|
329
327
|
end
|
330
328
|
|
331
329
|
end
|
332
330
|
|
333
|
-
|
331
|
+
context "with short options" do
|
334
332
|
|
335
333
|
before do
|
336
334
|
command.parse(%w(-f strawberry -c blue))
|
337
335
|
end
|
338
336
|
|
339
337
|
it "recognises short options as aliases" do
|
340
|
-
command.flavour.
|
341
|
-
command.color.
|
338
|
+
expect(command.flavour).to eql "strawberry"
|
339
|
+
expect(command.color).to eql "blue"
|
342
340
|
end
|
343
341
|
|
344
342
|
end
|
345
343
|
|
346
|
-
|
344
|
+
context "with a value appended to a short option" do
|
347
345
|
|
348
346
|
before do
|
349
347
|
command.parse(%w(-fstrawberry))
|
350
348
|
end
|
351
349
|
|
352
350
|
it "works as though the value were separated" do
|
353
|
-
command.flavour.
|
351
|
+
expect(command.flavour).to eql "strawberry"
|
354
352
|
end
|
355
353
|
|
356
354
|
end
|
357
355
|
|
358
|
-
|
356
|
+
context "with combined short options" do
|
359
357
|
|
360
358
|
before do
|
361
359
|
command.parse(%w(-nf strawberry))
|
362
360
|
end
|
363
361
|
|
364
362
|
it "works as though the options were separate" do
|
365
|
-
command.flavour.
|
366
|
-
command.nuts
|
363
|
+
expect(command.flavour).to eql "strawberry"
|
364
|
+
expect(command.nuts?).to eql true
|
367
365
|
end
|
368
366
|
|
369
367
|
end
|
370
368
|
|
371
|
-
|
369
|
+
context "with option arguments attached using equals sign" do
|
372
370
|
|
373
371
|
before do
|
374
372
|
command.parse(%w(--flavour=strawberry --color=blue))
|
375
373
|
end
|
376
374
|
|
377
375
|
it "works as though the option arguments were separate" do
|
378
|
-
command.flavour.
|
379
|
-
command.color.
|
376
|
+
expect(command.flavour).to eql "strawberry"
|
377
|
+
expect(command.color).to eql "blue"
|
380
378
|
end
|
381
379
|
|
382
380
|
end
|
383
381
|
|
384
|
-
|
382
|
+
context "with option-like things beyond the arguments" do
|
385
383
|
|
386
384
|
it "treats them as positional arguments" do
|
387
385
|
command.parse(%w(a b c --flavour strawberry))
|
388
|
-
command.arguments.
|
386
|
+
expect(command.arguments).to eql %w(a b c --flavour strawberry)
|
389
387
|
end
|
390
388
|
|
391
389
|
end
|
392
390
|
|
393
|
-
|
391
|
+
context "with multi-line arguments that look like options" do
|
394
392
|
|
395
393
|
before do
|
396
394
|
command.parse(["foo\n--flavour=strawberry", "bar\n-cblue"])
|
397
395
|
end
|
398
396
|
|
399
397
|
it "treats them as positional arguments" do
|
400
|
-
command.arguments.
|
401
|
-
command.flavour.
|
402
|
-
command.color.
|
398
|
+
expect(command.arguments).to eql ["foo\n--flavour=strawberry", "bar\n-cblue"]
|
399
|
+
expect(command.flavour).to be_nil
|
400
|
+
expect(command.color).to be_nil
|
403
401
|
end
|
404
402
|
|
405
403
|
end
|
406
404
|
|
407
|
-
|
405
|
+
context "with an option terminator" do
|
408
406
|
|
409
407
|
it "considers everything after the terminator to be an argument" do
|
410
408
|
command.parse(%w(--color blue -- --flavour strawberry))
|
411
|
-
command.arguments.
|
409
|
+
expect(command.arguments).to eql %w(--flavour strawberry)
|
412
410
|
end
|
413
411
|
|
414
412
|
end
|
415
413
|
|
416
|
-
|
414
|
+
context "with --flag" do
|
417
415
|
|
418
416
|
before do
|
419
417
|
command.parse(%w(--nuts))
|
420
418
|
end
|
421
419
|
|
422
420
|
it "sets the flag" do
|
423
|
-
command.nuts
|
421
|
+
expect(command.nuts?).to be true
|
424
422
|
end
|
425
423
|
|
426
424
|
end
|
427
425
|
|
428
|
-
|
426
|
+
context "with --no-flag" do
|
429
427
|
|
430
428
|
before do
|
431
429
|
command.nuts = true
|
@@ -433,48 +431,48 @@ describe Clamp::Command do
|
|
433
431
|
end
|
434
432
|
|
435
433
|
it "clears the flag" do
|
436
|
-
command.nuts
|
434
|
+
expect(command.nuts?).to be false
|
437
435
|
end
|
438
436
|
|
439
437
|
end
|
440
438
|
|
441
|
-
|
439
|
+
context "with --help" do
|
442
440
|
|
443
441
|
it "requests help" do
|
444
|
-
|
442
|
+
expect do
|
445
443
|
command.parse(%w(--help))
|
446
|
-
end.
|
444
|
+
end.to raise_error(Clamp::HelpWanted)
|
447
445
|
end
|
448
446
|
|
449
447
|
end
|
450
448
|
|
451
|
-
|
449
|
+
context "with -h" do
|
452
450
|
|
453
451
|
it "requests help" do
|
454
|
-
|
452
|
+
expect do
|
455
453
|
command.parse(%w(-h))
|
456
|
-
end.
|
454
|
+
end.to raise_error(Clamp::HelpWanted)
|
457
455
|
end
|
458
456
|
|
459
457
|
end
|
460
458
|
|
461
|
-
|
459
|
+
context "when a bad option value is specified on the command-line" do
|
462
460
|
|
463
461
|
it "signals a UsageError" do
|
464
|
-
|
462
|
+
expect do
|
465
463
|
command.parse(%w(--scoops reginald))
|
466
|
-
end.
|
464
|
+
end.to raise_error(Clamp::UsageError, /^option '--scoops': invalid value for Integer/)
|
467
465
|
end
|
468
466
|
|
469
467
|
end
|
470
468
|
|
471
|
-
|
469
|
+
context "when a bad option value is specified in the environment" do
|
472
470
|
|
473
471
|
it "signals a UsageError" do
|
474
472
|
ENV["DEFAULT_SCOOPS"] = "marjorie"
|
475
|
-
|
473
|
+
expect do
|
476
474
|
command.parse([])
|
477
|
-
end.
|
475
|
+
end.to raise_error(Clamp::UsageError, /^\$DEFAULT_SCOOPS: invalid value for Integer/)
|
478
476
|
end
|
479
477
|
|
480
478
|
end
|
@@ -484,44 +482,44 @@ describe Clamp::Command do
|
|
484
482
|
describe "#help" do
|
485
483
|
|
486
484
|
it "indicates that there are options" do
|
487
|
-
command.help.
|
485
|
+
expect(command.help).to include("cmd [OPTIONS]")
|
488
486
|
end
|
489
487
|
|
490
488
|
it "includes option details" do
|
491
|
-
command.help.
|
492
|
-
command.help.
|
489
|
+
expect(command.help).to match %r(--flavour FLAVOUR +Flavour of the month)
|
490
|
+
expect(command.help).to match %r(--color COLOR +Preferred hue)
|
493
491
|
end
|
494
492
|
|
495
493
|
it "handles new lines in option descriptions" do
|
496
|
-
command.help.
|
494
|
+
expect(command.help).to match %r(--\[no-\]nuts +Nuts \(or not\)\n +May include nuts)
|
497
495
|
end
|
498
496
|
|
499
497
|
end
|
500
498
|
|
501
499
|
end
|
502
500
|
|
503
|
-
|
501
|
+
context "with an explicit --help option declared" do
|
504
502
|
|
505
503
|
before do
|
506
504
|
command.class.option ["--help"], :flag, "help wanted"
|
507
505
|
end
|
508
506
|
|
509
507
|
it "does not generate implicit help option" do
|
510
|
-
|
508
|
+
expect do
|
511
509
|
command.parse(%w(--help))
|
512
|
-
end.
|
513
|
-
command.help.
|
510
|
+
end.to_not raise_error
|
511
|
+
expect(command.help?).to be true
|
514
512
|
end
|
515
513
|
|
516
514
|
it "does not recognise -h" do
|
517
|
-
|
515
|
+
expect do
|
518
516
|
command.parse(%w(-h))
|
519
|
-
end.
|
517
|
+
end.to raise_error(Clamp::UsageError)
|
520
518
|
end
|
521
519
|
|
522
520
|
end
|
523
521
|
|
524
|
-
|
522
|
+
context "with an explicit -h option declared" do
|
525
523
|
|
526
524
|
before do
|
527
525
|
command.class.option ["-h", "--humidity"], "PERCENT", "relative humidity" do |n|
|
@@ -530,13 +528,13 @@ describe Clamp::Command do
|
|
530
528
|
end
|
531
529
|
|
532
530
|
it "does not map -h to help" do
|
533
|
-
command.help.
|
531
|
+
expect(command.help).to_not match %r( -h[, ].*help)
|
534
532
|
end
|
535
533
|
|
536
534
|
it "still recognises --help" do
|
537
|
-
|
535
|
+
expect do
|
538
536
|
command.parse(%w(--help))
|
539
|
-
end.
|
537
|
+
end.to raise_error(Clamp::HelpWanted)
|
540
538
|
end
|
541
539
|
|
542
540
|
end
|
@@ -545,12 +543,12 @@ describe Clamp::Command do
|
|
545
543
|
|
546
544
|
it "declares option argument accessors" do
|
547
545
|
command.class.parameter "FLAVOUR", "flavour of the month"
|
548
|
-
command.flavour.
|
546
|
+
expect(command.flavour).to eql nil
|
549
547
|
command.flavour = "chocolate"
|
550
|
-
command.flavour.
|
548
|
+
expect(command.flavour).to eql "chocolate"
|
551
549
|
end
|
552
550
|
|
553
|
-
|
551
|
+
context "with explicit :attribute_name" do
|
554
552
|
|
555
553
|
before do
|
556
554
|
command.class.parameter "FOO", "a foo", :attribute_name => :bar
|
@@ -558,32 +556,32 @@ describe Clamp::Command do
|
|
558
556
|
|
559
557
|
it "uses the specified attribute_name name to name accessors" do
|
560
558
|
command.bar = "chocolate"
|
561
|
-
command.bar.
|
559
|
+
expect(command.bar).to eql "chocolate"
|
562
560
|
end
|
563
561
|
|
564
562
|
end
|
565
563
|
|
566
|
-
|
564
|
+
context "with :default value" do
|
567
565
|
|
568
566
|
before do
|
569
567
|
command.class.parameter "[ORIENTATION]", "direction", :default => "west"
|
570
568
|
end
|
571
569
|
|
572
570
|
it "sets the specified default value" do
|
573
|
-
command.orientation.
|
571
|
+
expect(command.orientation).to eql "west"
|
574
572
|
end
|
575
573
|
|
576
574
|
describe "#help" do
|
577
575
|
|
578
576
|
it "describes the default value" do
|
579
|
-
command.help.
|
577
|
+
expect(command.help).to include("direction (default: \"west\")")
|
580
578
|
end
|
581
579
|
|
582
580
|
end
|
583
581
|
|
584
582
|
end
|
585
583
|
|
586
|
-
|
584
|
+
context "with a block" do
|
587
585
|
|
588
586
|
before do
|
589
587
|
command.class.parameter "PORT", "port to listen on" do |port|
|
@@ -592,16 +590,16 @@ describe Clamp::Command do
|
|
592
590
|
end
|
593
591
|
|
594
592
|
it "uses the block to validate and convert the argument" do
|
595
|
-
|
593
|
+
expect do
|
596
594
|
command.port = "blah"
|
597
|
-
end.
|
595
|
+
end.to raise_error(ArgumentError)
|
598
596
|
command.port = "1234"
|
599
|
-
command.port.
|
597
|
+
expect(command.port).to eql 1234
|
600
598
|
end
|
601
599
|
|
602
600
|
end
|
603
601
|
|
604
|
-
|
602
|
+
context "with ellipsis" do
|
605
603
|
|
606
604
|
before do
|
607
605
|
command.class.parameter "FILE ...", "files"
|
@@ -609,53 +607,83 @@ describe Clamp::Command do
|
|
609
607
|
|
610
608
|
it "accepts multiple arguments" do
|
611
609
|
command.parse(%w(X Y Z))
|
612
|
-
command.file_list.
|
610
|
+
expect(command.file_list).to eql %w(X Y Z)
|
613
611
|
end
|
614
612
|
|
615
613
|
end
|
616
614
|
|
617
|
-
|
615
|
+
context "optional, with ellipsis" do
|
618
616
|
|
619
617
|
before do
|
620
618
|
command.class.parameter "[FILE] ...", "files"
|
621
619
|
end
|
622
620
|
|
623
|
-
it "
|
621
|
+
it "defaults to an empty list" do
|
624
622
|
command.parse([])
|
625
|
-
command.default_file_list.
|
626
|
-
command.file_list.
|
623
|
+
expect(command.default_file_list).to eql []
|
624
|
+
expect(command.file_list).to eql []
|
625
|
+
end
|
626
|
+
|
627
|
+
it "is mutable" do
|
628
|
+
command.parse([])
|
629
|
+
command.file_list << "treasure"
|
630
|
+
expect(command.file_list).to eql ["treasure"]
|
627
631
|
end
|
628
632
|
|
629
633
|
end
|
630
634
|
|
631
|
-
|
635
|
+
context "with :environment_variable" do
|
632
636
|
|
633
637
|
before do
|
634
638
|
command.class.parameter "[FILE]", "a file", :environment_variable => "FILE",
|
635
639
|
:default => "/dev/null"
|
636
640
|
end
|
637
641
|
|
638
|
-
|
639
|
-
|
640
|
-
|
642
|
+
let(:args) { [] }
|
643
|
+
let(:environment_value) { nil }
|
644
|
+
|
645
|
+
|
646
|
+
before do
|
647
|
+
set_env("FILE", environment_value)
|
648
|
+
command.parse(args)
|
641
649
|
end
|
642
650
|
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
651
|
+
context "when neither argument nor environment variable are present" do
|
652
|
+
|
653
|
+
it "uses the default" do
|
654
|
+
expect(command.file).to eql "/dev/null"
|
655
|
+
end
|
656
|
+
|
647
657
|
end
|
648
658
|
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
659
|
+
context "when environment variable is present" do
|
660
|
+
|
661
|
+
let(:environment_value) { "/etc/motd" }
|
662
|
+
|
663
|
+
describe "and no argument is provided" do
|
664
|
+
|
665
|
+
it "uses the environment variable" do
|
666
|
+
expect(command.file).to eql "/etc/motd"
|
667
|
+
end
|
668
|
+
|
669
|
+
end
|
670
|
+
|
671
|
+
describe "and an argument is provided" do
|
672
|
+
|
673
|
+
let(:args) { ["/dev/null"] }
|
674
|
+
|
675
|
+
it "uses the argument" do
|
676
|
+
expect(command.file).to eql "/dev/null"
|
677
|
+
end
|
678
|
+
|
679
|
+
end
|
680
|
+
|
653
681
|
end
|
654
682
|
|
655
683
|
describe "#help" do
|
656
684
|
|
657
685
|
it "describes the default value and env usage" do
|
658
|
-
command.help.
|
686
|
+
expect(command.help).to include(%{ (default: $FILE, or "/dev/null")})
|
659
687
|
end
|
660
688
|
|
661
689
|
end
|
@@ -664,16 +692,16 @@ describe Clamp::Command do
|
|
664
692
|
|
665
693
|
end
|
666
694
|
|
667
|
-
|
695
|
+
context "with no parameters declared" do
|
668
696
|
|
669
697
|
describe "#parse" do
|
670
698
|
|
671
|
-
|
699
|
+
context "with arguments" do
|
672
700
|
|
673
701
|
it "raises a UsageError" do
|
674
|
-
|
702
|
+
expect do
|
675
703
|
command.parse(["crash"])
|
676
|
-
end.
|
704
|
+
end.to raise_error(Clamp::UsageError, "too many arguments")
|
677
705
|
end
|
678
706
|
|
679
707
|
end
|
@@ -682,7 +710,7 @@ describe Clamp::Command do
|
|
682
710
|
|
683
711
|
end
|
684
712
|
|
685
|
-
|
713
|
+
context "with parameters declared" do
|
686
714
|
|
687
715
|
before do
|
688
716
|
command.class.parameter "X", "x\nxx"
|
@@ -692,58 +720,58 @@ describe Clamp::Command do
|
|
692
720
|
|
693
721
|
describe "#parse" do
|
694
722
|
|
695
|
-
|
723
|
+
context "with arguments for all parameters" do
|
696
724
|
|
697
725
|
before do
|
698
726
|
command.parse(["crash", "bang", "wallop"])
|
699
727
|
end
|
700
728
|
|
701
729
|
it "maps arguments onto the command object" do
|
702
|
-
command.x.
|
703
|
-
command.y.
|
704
|
-
command.z.
|
730
|
+
expect(command.x).to eql "crash"
|
731
|
+
expect(command.y).to eql "bang"
|
732
|
+
expect(command.z).to eql "wallop"
|
705
733
|
end
|
706
734
|
|
707
735
|
end
|
708
736
|
|
709
|
-
|
737
|
+
context "with insufficient arguments" do
|
710
738
|
|
711
739
|
it "raises a UsageError" do
|
712
|
-
|
740
|
+
expect do
|
713
741
|
command.parse(["crash"])
|
714
|
-
end.
|
742
|
+
end.to raise_error(Clamp::UsageError, "parameter 'Y': no value provided")
|
715
743
|
end
|
716
744
|
|
717
745
|
end
|
718
746
|
|
719
|
-
|
747
|
+
context "with optional argument omitted" do
|
720
748
|
|
721
749
|
it "defaults the optional argument" do
|
722
750
|
command.parse(["crash", "bang"])
|
723
|
-
command.x.
|
724
|
-
command.y.
|
725
|
-
command.z.
|
751
|
+
expect(command.x).to eql "crash"
|
752
|
+
expect(command.y).to eql "bang"
|
753
|
+
expect(command.z).to eql "ZZZ"
|
726
754
|
end
|
727
755
|
|
728
756
|
end
|
729
757
|
|
730
|
-
|
758
|
+
context "with multi-line arguments" do
|
731
759
|
|
732
760
|
it "parses them correctly" do
|
733
761
|
command.parse(["foo\nhi", "bar", "baz"])
|
734
|
-
command.x.
|
735
|
-
command.y.
|
736
|
-
command.z.
|
762
|
+
expect(command.x).to eql "foo\nhi"
|
763
|
+
expect(command.y).to eql "bar"
|
764
|
+
expect(command.z).to eql "baz"
|
737
765
|
end
|
738
766
|
|
739
767
|
end
|
740
768
|
|
741
|
-
|
769
|
+
context "with too many arguments" do
|
742
770
|
|
743
771
|
it "raises a UsageError" do
|
744
|
-
|
772
|
+
expect do
|
745
773
|
command.parse(["crash", "bang", "wallop", "kapow"])
|
746
|
-
end.
|
774
|
+
end.to raise_error(Clamp::UsageError, "too many arguments")
|
747
775
|
end
|
748
776
|
|
749
777
|
end
|
@@ -753,17 +781,17 @@ describe Clamp::Command do
|
|
753
781
|
describe "#help" do
|
754
782
|
|
755
783
|
it "indicates that there are parameters" do
|
756
|
-
command.help.
|
784
|
+
expect(command.help).to include("cmd [OPTIONS] X Y [Z]")
|
757
785
|
end
|
758
786
|
|
759
787
|
it "includes parameter details" do
|
760
|
-
command.help.
|
761
|
-
command.help.
|
762
|
-
command.help.
|
788
|
+
expect(command.help).to match %r(X +x)
|
789
|
+
expect(command.help).to match %r(Y +y)
|
790
|
+
expect(command.help).to match %r(\[Z\] +z \(default: "ZZZ"\))
|
763
791
|
end
|
764
792
|
|
765
793
|
it "handles new lines in option descriptions" do
|
766
|
-
command.help.
|
794
|
+
expect(command.help).to match %r(X +x\n +xx)
|
767
795
|
end
|
768
796
|
|
769
797
|
end
|
@@ -771,7 +799,7 @@ describe Clamp::Command do
|
|
771
799
|
|
772
800
|
end
|
773
801
|
|
774
|
-
|
802
|
+
context "with explicit usage" do
|
775
803
|
|
776
804
|
given_command("blah") do
|
777
805
|
|
@@ -782,14 +810,14 @@ describe Clamp::Command do
|
|
782
810
|
describe "#help" do
|
783
811
|
|
784
812
|
it "includes the explicit usage" do
|
785
|
-
command.help.
|
813
|
+
expect(command.help).to include("blah FOO BAR ...\n")
|
786
814
|
end
|
787
815
|
|
788
816
|
end
|
789
817
|
|
790
818
|
end
|
791
819
|
|
792
|
-
|
820
|
+
context "with multiple usages" do
|
793
821
|
|
794
822
|
given_command("put") do
|
795
823
|
|
@@ -801,15 +829,15 @@ describe Clamp::Command do
|
|
801
829
|
describe "#help" do
|
802
830
|
|
803
831
|
it "includes both potential usages" do
|
804
|
-
command.help.
|
805
|
-
command.help.
|
832
|
+
expect(command.help).to include("put THIS HERE\n")
|
833
|
+
expect(command.help).to include("put THAT THERE\n")
|
806
834
|
end
|
807
835
|
|
808
836
|
end
|
809
837
|
|
810
838
|
end
|
811
839
|
|
812
|
-
|
840
|
+
context "with a banner" do
|
813
841
|
|
814
842
|
given_command("punt") do
|
815
843
|
|
@@ -825,8 +853,8 @@ describe Clamp::Command do
|
|
825
853
|
describe "#help" do
|
826
854
|
|
827
855
|
it "includes the banner" do
|
828
|
-
command.help.
|
829
|
-
command.help.
|
856
|
+
expect(command.help).to match /^ Punt is an example command/
|
857
|
+
expect(command.help).to match /^ The prefix/
|
830
858
|
end
|
831
859
|
|
832
860
|
end
|
@@ -844,10 +872,10 @@ describe Clamp::Command do
|
|
844
872
|
end
|
845
873
|
@xyz = %w(x y z)
|
846
874
|
command.class.run("cmd", @xyz)
|
847
|
-
stdout.
|
875
|
+
expect(stdout).to eql @xyz.inspect
|
848
876
|
end
|
849
877
|
|
850
|
-
|
878
|
+
context "invoked with a context hash" do
|
851
879
|
|
852
880
|
it "makes the context available within the command" do
|
853
881
|
command.class.class_eval do
|
@@ -856,12 +884,40 @@ describe Clamp::Command do
|
|
856
884
|
end
|
857
885
|
end
|
858
886
|
command.class.run("xyz", [], :foo => "bar")
|
859
|
-
stdout.
|
887
|
+
expect(stdout).to eql "bar"
|
888
|
+
end
|
889
|
+
|
890
|
+
end
|
891
|
+
|
892
|
+
context "when there's a CommandError" do
|
893
|
+
|
894
|
+
before do
|
895
|
+
|
896
|
+
command.class.class_eval do
|
897
|
+
def execute
|
898
|
+
signal_error "Oh crap!", :status => 456
|
899
|
+
end
|
900
|
+
end
|
901
|
+
|
902
|
+
begin
|
903
|
+
command.class.run("cmd", [])
|
904
|
+
rescue SystemExit => e
|
905
|
+
@system_exit = e
|
906
|
+
end
|
907
|
+
|
908
|
+
end
|
909
|
+
|
910
|
+
it "outputs the error message" do
|
911
|
+
expect(stderr).to include "ERROR: Oh crap!"
|
912
|
+
end
|
913
|
+
|
914
|
+
it "exits with the specified status" do
|
915
|
+
expect(@system_exit.status).to eql 456
|
860
916
|
end
|
861
917
|
|
862
918
|
end
|
863
919
|
|
864
|
-
|
920
|
+
context "when there's a UsageError" do
|
865
921
|
|
866
922
|
before do
|
867
923
|
|
@@ -880,25 +936,25 @@ describe Clamp::Command do
|
|
880
936
|
end
|
881
937
|
|
882
938
|
it "outputs the error message" do
|
883
|
-
stderr.
|
939
|
+
expect(stderr).to include "ERROR: bad dog!"
|
884
940
|
end
|
885
941
|
|
886
942
|
it "outputs help" do
|
887
|
-
stderr.
|
943
|
+
expect(stderr).to include "See: 'cmd --help'"
|
888
944
|
end
|
889
945
|
|
890
946
|
it "exits with a non-zero status" do
|
891
|
-
@system_exit.
|
892
|
-
@system_exit.status.
|
947
|
+
expect(@system_exit).to_not be_nil
|
948
|
+
expect(@system_exit.status).to eql 1
|
893
949
|
end
|
894
950
|
|
895
951
|
end
|
896
952
|
|
897
|
-
|
953
|
+
context "when help is requested" do
|
898
954
|
|
899
955
|
it "outputs help" do
|
900
956
|
command.class.run("cmd", ["--help"])
|
901
|
-
stdout.
|
957
|
+
expect(stdout).to include "Usage:"
|
902
958
|
end
|
903
959
|
|
904
960
|
end
|
@@ -919,7 +975,7 @@ describe Clamp::Command do
|
|
919
975
|
|
920
976
|
it "inherits options from it's superclass" do
|
921
977
|
command.parse(["--verbose"])
|
922
|
-
command.
|
978
|
+
expect(command).to be_verbose
|
923
979
|
end
|
924
980
|
|
925
981
|
end
|