jls-clamp 0.3.1

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.
@@ -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