jls-clamp 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Clamp
2
+ VERSION = "0.3.1".freeze
3
+ end
data/lib/clamp.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'clamp/version'
2
+
3
+ require 'clamp/command'
@@ -0,0 +1,267 @@
1
+ require 'spec_helper'
2
+
3
+ describe Clamp::Command do
4
+
5
+ extend CommandFactory
6
+ include OutputCapture
7
+
8
+ describe "with subcommands" do
9
+
10
+ given_command "flipflop" do
11
+
12
+ subcommand "flip", "flip it" do
13
+ def execute
14
+ puts "FLIPPED"
15
+ end
16
+ end
17
+
18
+ subcommand "flop", "flop it\nfor extra flop" do
19
+ def execute
20
+ puts "FLOPPED"
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ it "delegates to sub-commands" do
27
+
28
+ @command.run(["flip"])
29
+ stdout.should =~ /FLIPPED/
30
+
31
+ @command.run(["flop"])
32
+ stdout.should =~ /FLOPPED/
33
+
34
+ end
35
+
36
+ context "executed with no subcommand" do
37
+
38
+ it "triggers help" do
39
+ lambda do
40
+ @command.run([])
41
+ end.should raise_error(Clamp::HelpWanted)
42
+ end
43
+
44
+ end
45
+
46
+ describe "#parse" do
47
+
48
+ describe "with too many arguments" do
49
+
50
+ it "raises a UsageError" do
51
+ lambda do
52
+ @command.parse(["flip", "extra", "args"])
53
+ end.should raise_error(Clamp::UsageError, "too many arguments")
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
60
+ describe "#help" do
61
+
62
+ it "shows subcommand parameters in usage" do
63
+ @command.help.should include("flipflop [OPTIONS] SUBCOMMAND [ARGS] ...")
64
+ end
65
+
66
+ it "lists subcommands" do
67
+ @help = @command.help
68
+ @help.should =~ /Subcommands:/
69
+ @help.should =~ /flip +flip it/
70
+ @help.should =~ /flop +flop it/
71
+ end
72
+
73
+ it "handles new lines in subcommand descriptions" do
74
+ @command.help.should =~ /flop +flop it\n +for extra flop/
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+
81
+ describe "with an aliased subcommand" do
82
+
83
+ given_command "blah" do
84
+
85
+ subcommand ["say", "talk"], "Say something" do
86
+
87
+ parameter "WORD ...", "stuff to say"
88
+
89
+ def execute
90
+ puts word_list
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+
97
+ it "responds to both aliases" do
98
+
99
+ @command.run(["say", "boo"])
100
+ stdout.should =~ /boo/
101
+
102
+ @command.run(["talk", "jive"])
103
+ stdout.should =~ /jive/
104
+
105
+ end
106
+
107
+ describe "#help" do
108
+
109
+ it "lists all aliases" do
110
+ @help = @command.help
111
+ @help.should =~ /say, talk .* Say something/
112
+ end
113
+
114
+ end
115
+
116
+ end
117
+
118
+ describe "with nested subcommands" do
119
+
120
+ given_command "fubar" do
121
+
122
+ subcommand "foo", "Foo!" do
123
+
124
+ subcommand "bar", "Baaaa!" do
125
+ def execute
126
+ puts "FUBAR"
127
+ end
128
+ end
129
+
130
+ end
131
+
132
+ end
133
+
134
+ it "delegates multiple levels" do
135
+ @command.run(["foo", "bar"])
136
+ stdout.should =~ /FUBAR/
137
+ end
138
+
139
+ end
140
+
141
+ describe "with a default subcommand" do
142
+
143
+ given_command "admin" do
144
+
145
+ subcommand "status", "Show status" do
146
+
147
+ def execute
148
+ puts "All good!"
149
+ end
150
+
151
+ end
152
+
153
+ self.default_subcommand = "status"
154
+
155
+ end
156
+
157
+ context "executed with no subcommand" do
158
+
159
+ it "invokes the default subcommand" do
160
+ @command.run([])
161
+ stdout.should =~ /All good/
162
+ end
163
+
164
+ end
165
+
166
+ end
167
+
168
+ describe "with a default subcommand, declared the old way" do
169
+
170
+ given_command "admin" do
171
+
172
+ default_subcommand "status", "Show status" do
173
+
174
+ def execute
175
+ puts "All good!"
176
+ end
177
+
178
+ end
179
+
180
+ end
181
+
182
+ context "executed with no subcommand" do
183
+
184
+ it "invokes the default subcommand" do
185
+ @command.run([])
186
+ stdout.should =~ /All good/
187
+ end
188
+
189
+ end
190
+
191
+ end
192
+
193
+ describe "each subcommand" do
194
+
195
+ before do
196
+
197
+ speed_options = Module.new do
198
+ extend Clamp::Option::Declaration
199
+ option "--speed", "SPEED", "how fast", :default => "slowly"
200
+ end
201
+
202
+ @command_class = Class.new(Clamp::Command) do
203
+
204
+ option "--direction", "DIR", "which way", :default => "home"
205
+
206
+ include speed_options
207
+
208
+ subcommand "move", "move in the appointed direction" do
209
+
210
+ def execute
211
+ motion = context[:motion] || "walking"
212
+ puts "#{motion} #{direction} #{speed}"
213
+ end
214
+
215
+ end
216
+
217
+ end
218
+
219
+ @command = @command_class.new("go")
220
+
221
+ end
222
+
223
+ it "accepts options defined in superclass (specified after the subcommand)" do
224
+ @command.run(["move", "--direction", "north"])
225
+ stdout.should =~ /walking north/
226
+ end
227
+
228
+ it "accepts options defined in superclass (specified before the subcommand)" do
229
+ @command.run(["--direction", "north", "move"])
230
+ stdout.should =~ /walking north/
231
+ end
232
+
233
+ it "accepts options defined in included modules" do
234
+ @command.run(["move", "--speed", "very quickly"])
235
+ stdout.should =~ /walking home very quickly/
236
+ end
237
+
238
+ it "has access to command context" do
239
+ @command = @command_class.new("go", :motion => "wandering")
240
+ @command.run(["move"])
241
+ stdout.should =~ /wandering home/
242
+ end
243
+
244
+ end
245
+
246
+ describe "with a subcommand, with options" do
247
+
248
+ given_command 'weeheehee' do
249
+ option '--json', 'JSON', 'a json blob' do |option|
250
+ print "parsing!"
251
+ option
252
+ end
253
+
254
+ subcommand 'woohoohoo', 'like weeheehee but with more o' do
255
+ def execute
256
+ end
257
+ end
258
+ end
259
+
260
+ it "only parses options once" do
261
+ @command.run(['--json', '{"a":"b"}', 'woohoohoo'])
262
+ stdout.should == 'parsing!'
263
+ end
264
+
265
+ end
266
+
267
+ end