thor 0.16.0 → 1.2.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.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +15 -0
- data/README.md +23 -6
- data/bin/thor +1 -1
- data/lib/thor/actions/create_file.rb +34 -35
- data/lib/thor/actions/create_link.rb +9 -5
- data/lib/thor/actions/directory.rb +33 -23
- data/lib/thor/actions/empty_directory.rb +75 -85
- data/lib/thor/actions/file_manipulation.rb +103 -36
- data/lib/thor/actions/inject_into_file.rb +46 -36
- data/lib/thor/actions.rb +90 -68
- data/lib/thor/base.rb +302 -244
- data/lib/thor/command.rb +142 -0
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +52 -24
- data/lib/thor/error.rb +90 -10
- data/lib/thor/group.rb +70 -74
- data/lib/thor/invocation.rb +63 -55
- data/lib/thor/line_editor/basic.rb +37 -0
- data/lib/thor/line_editor/readline.rb +88 -0
- data/lib/thor/line_editor.rb +17 -0
- data/lib/thor/nested_context.rb +29 -0
- data/lib/thor/parser/argument.rb +24 -28
- data/lib/thor/parser/arguments.rb +110 -102
- data/lib/thor/parser/option.rb +53 -15
- data/lib/thor/parser/options.rb +174 -97
- data/lib/thor/parser.rb +4 -4
- data/lib/thor/rake_compat.rb +12 -11
- data/lib/thor/runner.rb +159 -155
- data/lib/thor/shell/basic.rb +216 -93
- data/lib/thor/shell/color.rb +53 -40
- data/lib/thor/shell/html.rb +61 -58
- data/lib/thor/shell.rb +29 -36
- data/lib/thor/util.rb +231 -213
- data/lib/thor/version.rb +1 -1
- data/lib/thor.rb +303 -166
- data/thor.gemspec +27 -24
- metadata +36 -226
- data/.gitignore +0 -44
- data/.rspec +0 -2
- data/.travis.yml +0 -7
- data/CHANGELOG.rdoc +0 -134
- data/Gemfile +0 -15
- data/Thorfile +0 -30
- data/bin/rake2thor +0 -86
- data/lib/thor/core_ext/dir_escape.rb +0 -0
- data/lib/thor/core_ext/file_binary_read.rb +0 -9
- data/lib/thor/core_ext/ordered_hash.rb +0 -100
- data/lib/thor/task.rb +0 -132
- data/spec/actions/create_file_spec.rb +0 -170
- data/spec/actions/create_link_spec.rb +0 -81
- data/spec/actions/directory_spec.rb +0 -149
- data/spec/actions/empty_directory_spec.rb +0 -130
- data/spec/actions/file_manipulation_spec.rb +0 -370
- data/spec/actions/inject_into_file_spec.rb +0 -135
- data/spec/actions_spec.rb +0 -331
- data/spec/base_spec.rb +0 -279
- data/spec/core_ext/hash_with_indifferent_access_spec.rb +0 -43
- data/spec/core_ext/ordered_hash_spec.rb +0 -115
- data/spec/exit_condition_spec.rb +0 -19
- data/spec/fixtures/application.rb +0 -2
- data/spec/fixtures/app{1}/README +0 -3
- data/spec/fixtures/bundle/execute.rb +0 -6
- data/spec/fixtures/bundle/main.thor +0 -1
- data/spec/fixtures/doc/%file_name%.rb.tt +0 -1
- data/spec/fixtures/doc/COMMENTER +0 -10
- data/spec/fixtures/doc/README +0 -3
- data/spec/fixtures/doc/block_helper.rb +0 -3
- data/spec/fixtures/doc/components/.empty_directory +0 -0
- data/spec/fixtures/doc/config.rb +0 -1
- data/spec/fixtures/doc/config.yaml.tt +0 -1
- data/spec/fixtures/enum.thor +0 -10
- data/spec/fixtures/group.thor +0 -114
- data/spec/fixtures/invoke.thor +0 -112
- data/spec/fixtures/path with spaces +0 -0
- data/spec/fixtures/script.thor +0 -190
- data/spec/fixtures/task.thor +0 -10
- data/spec/group_spec.rb +0 -216
- data/spec/invocation_spec.rb +0 -100
- data/spec/parser/argument_spec.rb +0 -53
- data/spec/parser/arguments_spec.rb +0 -66
- data/spec/parser/option_spec.rb +0 -202
- data/spec/parser/options_spec.rb +0 -330
- data/spec/rake_compat_spec.rb +0 -72
- data/spec/register_spec.rb +0 -135
- data/spec/runner_spec.rb +0 -241
- data/spec/shell/basic_spec.rb +0 -300
- data/spec/shell/color_spec.rb +0 -81
- data/spec/shell/html_spec.rb +0 -32
- data/spec/shell_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -59
- data/spec/task_spec.rb +0 -80
- data/spec/thor_spec.rb +0 -418
- data/spec/util_spec.rb +0 -196
data/spec/thor_spec.rb
DELETED
@@ -1,418 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
describe Thor do
|
4
|
-
describe "#method_option" do
|
5
|
-
it "sets options to the next method to be invoked" do
|
6
|
-
args = ["foo", "bar", "--force"]
|
7
|
-
arg, options = MyScript.start(args)
|
8
|
-
options.should == { "force" => true }
|
9
|
-
end
|
10
|
-
|
11
|
-
describe ":lazy_default" do
|
12
|
-
it "is absent when option is not specified" do
|
13
|
-
arg, options = MyScript.start(["with_optional"])
|
14
|
-
options.should == {}
|
15
|
-
end
|
16
|
-
|
17
|
-
it "sets a default that can be overridden for strings" do
|
18
|
-
arg, options = MyScript.start(["with_optional", "--lazy"])
|
19
|
-
options.should == { "lazy" => "yes" }
|
20
|
-
|
21
|
-
arg, options = MyScript.start(["with_optional", "--lazy", "yesyes!"])
|
22
|
-
options.should == { "lazy" => "yesyes!" }
|
23
|
-
end
|
24
|
-
|
25
|
-
it "sets a default that can be overridden for numerics" do
|
26
|
-
arg, options = MyScript.start(["with_optional", "--lazy-numeric"])
|
27
|
-
options.should == { "lazy_numeric" => 42 }
|
28
|
-
|
29
|
-
arg, options = MyScript.start(["with_optional", "--lazy-numeric", 20000])
|
30
|
-
options.should == { "lazy_numeric" => 20000 }
|
31
|
-
end
|
32
|
-
|
33
|
-
it "sets a default that can be overridden for arrays" do
|
34
|
-
arg, options = MyScript.start(["with_optional", "--lazy-array"])
|
35
|
-
options.should == { "lazy_array" => %w[eat at joes] }
|
36
|
-
|
37
|
-
arg, options = MyScript.start(["with_optional", "--lazy-array", "hello", "there"])
|
38
|
-
options.should == { "lazy_array" => %w[hello there] }
|
39
|
-
end
|
40
|
-
|
41
|
-
it "sets a default that can be overridden for hashes" do
|
42
|
-
arg, options = MyScript.start(["with_optional", "--lazy-hash"])
|
43
|
-
options.should == { "lazy_hash" => {'swedish' => 'meatballs'} }
|
44
|
-
|
45
|
-
arg, options = MyScript.start(["with_optional", "--lazy-hash", "polish:sausage"])
|
46
|
-
options.should == { "lazy_hash" => {'polish' => 'sausage'} }
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
describe "when :for is supplied" do
|
51
|
-
it "updates an already defined task" do
|
52
|
-
args, options = MyChildScript.start(["animal", "horse", "--other=fish"])
|
53
|
-
options[:other].should == "fish"
|
54
|
-
end
|
55
|
-
|
56
|
-
describe "and the target is on the parent class" do
|
57
|
-
it "updates an already defined task" do
|
58
|
-
args = ["example_default_task", "my_param", "--new-option=verified"]
|
59
|
-
options = Scripts::MyScript.start(args)
|
60
|
-
options[:new_option].should == "verified"
|
61
|
-
end
|
62
|
-
|
63
|
-
it "adds a task to the tasks list if the updated task is on the parent class" do
|
64
|
-
Scripts::MyScript.tasks["example_default_task"].should be
|
65
|
-
end
|
66
|
-
|
67
|
-
it "clones the parent task" do
|
68
|
-
Scripts::MyScript.tasks["example_default_task"].should_not == MyChildScript.tasks["example_default_task"]
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
describe "#default_task" do
|
75
|
-
it "sets a default task" do
|
76
|
-
MyScript.default_task.should == "example_default_task"
|
77
|
-
end
|
78
|
-
|
79
|
-
it "invokes the default task if no command is specified" do
|
80
|
-
MyScript.start([]).should == "default task"
|
81
|
-
end
|
82
|
-
|
83
|
-
it "invokes the default task if no command is specified even if switches are given" do
|
84
|
-
MyScript.start(["--with", "option"]).should == {"with"=>"option"}
|
85
|
-
end
|
86
|
-
|
87
|
-
it "inherits the default task from parent" do
|
88
|
-
MyChildScript.default_task.should == "example_default_task"
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
describe "#map" do
|
93
|
-
it "calls the alias of a method if one is provided" do
|
94
|
-
MyScript.start(["-T", "fish"]).should == ["fish"]
|
95
|
-
end
|
96
|
-
|
97
|
-
it "calls the alias of a method if several are provided via .map" do
|
98
|
-
MyScript.start(["-f", "fish"]).should == ["fish", {}]
|
99
|
-
MyScript.start(["--foo", "fish"]).should == ["fish", {}]
|
100
|
-
end
|
101
|
-
|
102
|
-
it "inherits all mappings from parent" do
|
103
|
-
MyChildScript.default_task.should == "example_default_task"
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
describe "#desc" do
|
108
|
-
it "provides description for a task" do
|
109
|
-
content = capture(:stdout) { MyScript.start(["help"]) }
|
110
|
-
content.should =~ /thor my_script:zoo\s+# zoo around/m
|
111
|
-
end
|
112
|
-
|
113
|
-
it "provides no namespace if $thor_runner is false" do
|
114
|
-
begin
|
115
|
-
$thor_runner = false
|
116
|
-
content = capture(:stdout) { MyScript.start(["help"]) }
|
117
|
-
content.should =~ /thor zoo\s+# zoo around/m
|
118
|
-
ensure
|
119
|
-
$thor_runner = true
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
describe "when :for is supplied" do
|
124
|
-
it "overwrites a previous defined task" do
|
125
|
-
capture(:stdout) { MyChildScript.start(["help"]) }.should =~ /animal KIND \s+# fish around/m
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
describe "when :hide is supplied" do
|
130
|
-
it "does not show the task in help" do
|
131
|
-
capture(:stdout) { MyScript.start(["help"]) }.should_not =~ /this is hidden/m
|
132
|
-
end
|
133
|
-
|
134
|
-
it "but the task is still invokcable not show the task in help" do
|
135
|
-
MyScript.start(["hidden", "yesyes"]).should == ["yesyes"]
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
describe "#method_options" do
|
141
|
-
it "sets default options if called before an initializer" do
|
142
|
-
options = MyChildScript.class_options
|
143
|
-
options[:force].type.should == :boolean
|
144
|
-
options[:param].type.should == :numeric
|
145
|
-
end
|
146
|
-
|
147
|
-
it "overwrites default options if called on the method scope" do
|
148
|
-
args = ["zoo", "--force", "--param", "feathers"]
|
149
|
-
options = MyChildScript.start(args)
|
150
|
-
options.should == { "force" => true, "param" => "feathers" }
|
151
|
-
end
|
152
|
-
|
153
|
-
it "allows default options to be merged with method options" do
|
154
|
-
args = ["animal", "bird", "--force", "--param", "1.0", "--other", "tweets"]
|
155
|
-
arg, options = MyChildScript.start(args)
|
156
|
-
arg.should == 'bird'
|
157
|
-
options.should == { "force"=>true, "param"=>1.0, "other"=>"tweets" }
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
describe "#start" do
|
162
|
-
it "calls a no-param method when no params are passed" do
|
163
|
-
MyScript.start(["zoo"]).should == true
|
164
|
-
end
|
165
|
-
|
166
|
-
it "calls a single-param method when a single param is passed" do
|
167
|
-
MyScript.start(["animal", "fish"]).should == ["fish"]
|
168
|
-
end
|
169
|
-
|
170
|
-
it "does not set options in attributes" do
|
171
|
-
MyScript.start(["with_optional", "--all"]).should == [nil, { "all" => true }, []]
|
172
|
-
end
|
173
|
-
|
174
|
-
it "raises an error if a required param is not provided" do
|
175
|
-
capture(:stderr) { MyScript.start(["animal"]) }.strip.should == 'thor animal requires at least 1 argument: "thor my_script:animal TYPE".'
|
176
|
-
end
|
177
|
-
|
178
|
-
it "raises an error if the invoked task does not exist" do
|
179
|
-
capture(:stderr) { Amazing.start(["animal"]) }.strip.should == 'Could not find task "animal" in "amazing" namespace.'
|
180
|
-
end
|
181
|
-
|
182
|
-
it "calls method_missing if an unknown method is passed in" do
|
183
|
-
MyScript.start(["unk", "hello"]).should == [:unk, ["hello"]]
|
184
|
-
end
|
185
|
-
|
186
|
-
it "does not call a private method no matter what" do
|
187
|
-
capture(:stderr) { MyScript.start(["what"]) }.strip.should == 'Could not find task "what" in "my_script" namespace.'
|
188
|
-
end
|
189
|
-
|
190
|
-
it "uses task default options" do
|
191
|
-
options = MyChildScript.start(["animal", "fish"]).last
|
192
|
-
options.should == { "other" => "method default" }
|
193
|
-
end
|
194
|
-
|
195
|
-
it "raises when an exception happens within the task call" do
|
196
|
-
lambda { MyScript.start(["call_myself_with_wrong_arity"]) }.should raise_error(ArgumentError)
|
197
|
-
end
|
198
|
-
|
199
|
-
context "when the user enters an unambiguous substring of a command" do
|
200
|
-
it "should invoke a command" do
|
201
|
-
MyScript.start(["z"]).should == MyScript.start(["zoo"])
|
202
|
-
end
|
203
|
-
|
204
|
-
it "should invoke a command, even when there's an alias the resolves to the same command" do
|
205
|
-
MyScript.start(["hi"]).should == MyScript.start(["hidden"])
|
206
|
-
end
|
207
|
-
|
208
|
-
it "should invoke an alias" do
|
209
|
-
MyScript.start(["animal_pri"]).should == MyScript.start(["zoo"])
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
context "when the user enters an ambiguous substring of a command" do
|
214
|
-
it "should raise an exception that explains the ambiguity" do
|
215
|
-
lambda { MyScript.start(["call"]) }.should raise_error(ArgumentError, 'Ambiguous task call matches [call_myself_with_wrong_arity, call_unexistent_method]')
|
216
|
-
end
|
217
|
-
|
218
|
-
it "should raise an exception when there is an alias" do
|
219
|
-
lambda { MyScript.start(["f"]) }.should raise_error(ArgumentError, 'Ambiguous task f matches [foo, fu]')
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
end
|
224
|
-
|
225
|
-
describe "#subcommand" do
|
226
|
-
it "maps a given subcommand to another Thor subclass" do
|
227
|
-
barn_help = capture(:stdout){ Scripts::MyDefaults.start(["barn"]) }
|
228
|
-
barn_help.should include("barn help [COMMAND] # Describe subcommands or one specific subcommand")
|
229
|
-
end
|
230
|
-
|
231
|
-
it "passes commands to subcommand classes" do
|
232
|
-
capture(:stdout){ Scripts::MyDefaults.start(["barn", "open"]) }.strip.should == "Open sesame!"
|
233
|
-
end
|
234
|
-
|
235
|
-
it "passes arguments to subcommand classes" do
|
236
|
-
capture(:stdout){ Scripts::MyDefaults.start(["barn", "open", "shotgun"]) }.strip.should == "That's going to leave a mark."
|
237
|
-
end
|
238
|
-
|
239
|
-
it "ignores unknown options (the subcommand class will handle them)" do
|
240
|
-
capture(:stdout){ Scripts::MyDefaults.start(["barn", "paint", "blue", "--coats", "4"])}.strip.should == "4 coats of blue paint"
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
describe "#help" do
|
245
|
-
def shell
|
246
|
-
@shell ||= Thor::Base.shell.new
|
247
|
-
end
|
248
|
-
|
249
|
-
describe "on general" do
|
250
|
-
before do
|
251
|
-
@content = capture(:stdout){ MyScript.help(shell) }
|
252
|
-
end
|
253
|
-
|
254
|
-
it "provides useful help info for the help method itself" do
|
255
|
-
@content.should =~ /help \[TASK\]\s+# Describe available tasks/
|
256
|
-
end
|
257
|
-
|
258
|
-
it "provides useful help info for a method with params" do
|
259
|
-
@content.should =~ /animal TYPE\s+# horse around/
|
260
|
-
end
|
261
|
-
|
262
|
-
it "uses the maximum terminal size to show tasks" do
|
263
|
-
@shell.should_receive(:terminal_width).and_return(80)
|
264
|
-
content = capture(:stdout){ MyScript.help(shell) }
|
265
|
-
content.should =~ /aaa\.\.\.$/
|
266
|
-
end
|
267
|
-
|
268
|
-
it "provides description for tasks from classes in the same namespace" do
|
269
|
-
@content.should =~ /baz\s+# do some bazing/
|
270
|
-
end
|
271
|
-
|
272
|
-
it "shows superclass tasks" do
|
273
|
-
content = capture(:stdout){ MyChildScript.help(shell) }
|
274
|
-
content.should =~ /foo BAR \s+# do some fooing/
|
275
|
-
end
|
276
|
-
|
277
|
-
it "shows class options information" do
|
278
|
-
content = capture(:stdout){ MyChildScript.help(shell) }
|
279
|
-
content.should =~ /Options\:/
|
280
|
-
content.should =~ /\[\-\-param=N\]/
|
281
|
-
end
|
282
|
-
|
283
|
-
it "injects class arguments into default usage" do
|
284
|
-
content = capture(:stdout){ Scripts::MyScript.help(shell) }
|
285
|
-
content.should =~ /zoo ACCESSOR \-\-param\=PARAM/
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
describe "for a specific task" do
|
290
|
-
it "provides full help info when talking about a specific task" do
|
291
|
-
capture(:stdout) { MyScript.task_help(shell, "foo") }.should == <<-END
|
292
|
-
Usage:
|
293
|
-
thor my_script:foo BAR
|
294
|
-
|
295
|
-
Options:
|
296
|
-
[--force] # Force to do some fooing
|
297
|
-
|
298
|
-
do some fooing
|
299
|
-
This is more info!
|
300
|
-
Everyone likes more info!
|
301
|
-
END
|
302
|
-
end
|
303
|
-
|
304
|
-
it "raises an error if the task can't be found" do
|
305
|
-
lambda {
|
306
|
-
MyScript.task_help(shell, "unknown")
|
307
|
-
}.should raise_error(Thor::UndefinedTaskError, 'Could not find task "unknown" in "my_script" namespace.')
|
308
|
-
end
|
309
|
-
|
310
|
-
it "normalizes names before claiming they don't exist" do
|
311
|
-
capture(:stdout) { MyScript.task_help(shell, "name-with-dashes") }.should =~ /thor my_script:name-with-dashes/
|
312
|
-
end
|
313
|
-
|
314
|
-
it "uses the long description if it exists" do
|
315
|
-
capture(:stdout) { MyScript.task_help(shell, "long_description") }.should == <<-HELP
|
316
|
-
Usage:
|
317
|
-
thor my_script:long_description
|
318
|
-
|
319
|
-
Description:
|
320
|
-
This is a really really really long description. Here you go. So very long.
|
321
|
-
|
322
|
-
It even has two paragraphs.
|
323
|
-
HELP
|
324
|
-
end
|
325
|
-
|
326
|
-
it "doesn't assign the long description to the next task without one" do
|
327
|
-
capture(:stdout) do
|
328
|
-
MyScript.task_help(shell, "name_with_dashes")
|
329
|
-
end.should_not =~ /so very long/i
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
describe "instance method" do
|
334
|
-
it "calls the class method" do
|
335
|
-
capture(:stdout){ MyScript.start(["help"]) }.should =~ /Tasks:/
|
336
|
-
end
|
337
|
-
|
338
|
-
it "calls the class method" do
|
339
|
-
capture(:stdout){ MyScript.start(["help", "foo"]) }.should =~ /Usage:/
|
340
|
-
end
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
describe "when creating tasks" do
|
345
|
-
it "prints a warning if a public method is created without description or usage" do
|
346
|
-
capture(:stdout) {
|
347
|
-
klass = Class.new(Thor)
|
348
|
-
klass.class_eval "def hello_from_thor; end"
|
349
|
-
}.should =~ /\[WARNING\] Attempted to create task "hello_from_thor" without usage or description/
|
350
|
-
end
|
351
|
-
|
352
|
-
it "does not print if overwriting a previous task" do
|
353
|
-
capture(:stdout) {
|
354
|
-
klass = Class.new(Thor)
|
355
|
-
klass.class_eval "def help; end"
|
356
|
-
}.should be_empty
|
357
|
-
end
|
358
|
-
end
|
359
|
-
|
360
|
-
describe "edge-cases" do
|
361
|
-
it "can handle boolean options followed by arguments" do
|
362
|
-
klass = Class.new(Thor) do
|
363
|
-
method_option :loud, :type => :boolean
|
364
|
-
desc "hi NAME", "say hi to name"
|
365
|
-
def hi(name)
|
366
|
-
name.upcase! if options[:loud]
|
367
|
-
"Hi #{name}"
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
klass.start(["hi", "jose"]).should == "Hi jose"
|
372
|
-
klass.start(["hi", "jose", "--loud"]).should == "Hi JOSE"
|
373
|
-
klass.start(["hi", "--loud", "jose"]).should == "Hi JOSE"
|
374
|
-
end
|
375
|
-
|
376
|
-
it "passes through unknown options" do
|
377
|
-
klass = Class.new(Thor) do
|
378
|
-
desc "unknown", "passing unknown options"
|
379
|
-
def unknown(*args)
|
380
|
-
args
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
klass.start(["unknown", "foo", "--bar", "baz", "bat", "--bam"]).should == ["foo", "--bar", "baz", "bat", "--bam"]
|
385
|
-
klass.start(["unknown", "--bar", "baz"]).should == ["--bar", "baz"]
|
386
|
-
end
|
387
|
-
|
388
|
-
it "does not pass through unknown options with strict args" do
|
389
|
-
klass = Class.new(Thor) do
|
390
|
-
strict_args_position!
|
391
|
-
|
392
|
-
desc "unknown", "passing unknown options"
|
393
|
-
def unknown(*args)
|
394
|
-
args
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
klass.start(["unknown", "--bar", "baz"]).should == []
|
399
|
-
klass.start(["unknown", "foo", "--bar", "baz"]).should == ["foo"]
|
400
|
-
end
|
401
|
-
|
402
|
-
it "strict args works in the inheritance chain" do
|
403
|
-
parent = Class.new(Thor) do
|
404
|
-
strict_args_position!
|
405
|
-
end
|
406
|
-
|
407
|
-
klass = Class.new(parent) do
|
408
|
-
desc "unknown", "passing unknown options"
|
409
|
-
def unknown(*args)
|
410
|
-
args
|
411
|
-
end
|
412
|
-
end
|
413
|
-
|
414
|
-
klass.start(["unknown", "--bar", "baz"]).should == []
|
415
|
-
klass.start(["unknown", "foo", "--bar", "baz"]).should == ["foo"]
|
416
|
-
end
|
417
|
-
end
|
418
|
-
end
|
data/spec/util_spec.rb
DELETED
@@ -1,196 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
module Thor::Util
|
4
|
-
def self.clear_user_home!
|
5
|
-
@@user_home = nil
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
describe Thor::Util do
|
10
|
-
describe "#find_by_namespace" do
|
11
|
-
it "returns 'default' if no namespace is given" do
|
12
|
-
Thor::Util.find_by_namespace('').should == Scripts::MyDefaults
|
13
|
-
end
|
14
|
-
|
15
|
-
it "adds 'default' if namespace starts with :" do
|
16
|
-
Thor::Util.find_by_namespace(':child').should == Scripts::ChildDefault
|
17
|
-
end
|
18
|
-
|
19
|
-
it "returns nil if the namespace can't be found" do
|
20
|
-
Thor::Util.find_by_namespace('thor:core_ext:ordered_hash').should be_nil
|
21
|
-
end
|
22
|
-
|
23
|
-
it "returns a class if it matches the namespace" do
|
24
|
-
Thor::Util.find_by_namespace('app:broken:counter').should == BrokenCounter
|
25
|
-
end
|
26
|
-
|
27
|
-
it "matches classes default namespace" do
|
28
|
-
Thor::Util.find_by_namespace('scripts:my_script').should == Scripts::MyScript
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe "#namespace_from_thor_class" do
|
33
|
-
it "replaces constant nesting with task namespacing" do
|
34
|
-
Thor::Util.namespace_from_thor_class("Foo::Bar::Baz").should == "foo:bar:baz"
|
35
|
-
end
|
36
|
-
|
37
|
-
it "snake-cases component strings" do
|
38
|
-
Thor::Util.namespace_from_thor_class("FooBar::BarBaz::BazBoom").should == "foo_bar:bar_baz:baz_boom"
|
39
|
-
end
|
40
|
-
|
41
|
-
it "accepts class and module objects" do
|
42
|
-
Thor::Util.namespace_from_thor_class(Thor::CoreExt::OrderedHash).should == "thor:core_ext:ordered_hash"
|
43
|
-
Thor::Util.namespace_from_thor_class(Thor::Util).should == "thor:util"
|
44
|
-
end
|
45
|
-
|
46
|
-
it "removes Thor::Sandbox namespace" do
|
47
|
-
Thor::Util.namespace_from_thor_class("Thor::Sandbox::Package").should == "package"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
describe "#namespaces_in_content" do
|
52
|
-
it "returns an array of names of constants defined in the string" do
|
53
|
-
list = Thor::Util.namespaces_in_content("class Foo; class Bar < Thor; end; end; class Baz; class Bat; end; end")
|
54
|
-
list.should include("foo:bar")
|
55
|
-
list.should_not include("bar:bat")
|
56
|
-
end
|
57
|
-
|
58
|
-
it "doesn't put the newly-defined constants in the enclosing namespace" do
|
59
|
-
Thor::Util.namespaces_in_content("class Blat; end")
|
60
|
-
defined?(Blat).should_not be
|
61
|
-
defined?(Thor::Sandbox::Blat).should be
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe "#snake_case" do
|
66
|
-
it "preserves no-cap strings" do
|
67
|
-
Thor::Util.snake_case("foo").should == "foo"
|
68
|
-
Thor::Util.snake_case("foo_bar").should == "foo_bar"
|
69
|
-
end
|
70
|
-
|
71
|
-
it "downcases all-caps strings" do
|
72
|
-
Thor::Util.snake_case("FOO").should == "foo"
|
73
|
-
Thor::Util.snake_case("FOO_BAR").should == "foo_bar"
|
74
|
-
end
|
75
|
-
|
76
|
-
it "downcases initial-cap strings" do
|
77
|
-
Thor::Util.snake_case("Foo").should == "foo"
|
78
|
-
end
|
79
|
-
|
80
|
-
it "replaces camel-casing with underscores" do
|
81
|
-
Thor::Util.snake_case("FooBarBaz").should == "foo_bar_baz"
|
82
|
-
Thor::Util.snake_case("Foo_BarBaz").should == "foo_bar_baz"
|
83
|
-
end
|
84
|
-
|
85
|
-
it "places underscores between multiple capitals" do
|
86
|
-
Thor::Util.snake_case("ABClass").should == "a_b_class"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
describe "#find_class_and_task_by_namespace" do
|
91
|
-
it "returns a Thor::Group class if full namespace matches" do
|
92
|
-
Thor::Util.find_class_and_task_by_namespace("my_counter").should == [MyCounter, nil]
|
93
|
-
end
|
94
|
-
|
95
|
-
it "returns a Thor class if full namespace matches" do
|
96
|
-
Thor::Util.find_class_and_task_by_namespace("thor").should == [Thor, nil]
|
97
|
-
end
|
98
|
-
|
99
|
-
it "returns a Thor class and the task name" do
|
100
|
-
Thor::Util.find_class_and_task_by_namespace("thor:help").should == [Thor, "help"]
|
101
|
-
end
|
102
|
-
|
103
|
-
it "falls back in the namespace:task look up even if a full namespace does not match" do
|
104
|
-
Thor.const_set(:Help, Module.new)
|
105
|
-
Thor::Util.find_class_and_task_by_namespace("thor:help").should == [Thor, "help"]
|
106
|
-
Thor.send :remove_const, :Help
|
107
|
-
end
|
108
|
-
|
109
|
-
it "falls back on the default namespace class if nothing else matches" do
|
110
|
-
Thor::Util.find_class_and_task_by_namespace("test").should == [Scripts::MyDefaults, "test"]
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
describe "#thor_classes_in" do
|
115
|
-
it "returns thor classes inside the given class" do
|
116
|
-
Thor::Util.thor_classes_in(MyScript).should == [MyScript::AnotherScript]
|
117
|
-
Thor::Util.thor_classes_in(MyScript::AnotherScript).should be_empty
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
describe "#user_home" do
|
122
|
-
before do
|
123
|
-
ENV.stub!(:[])
|
124
|
-
Thor::Util.clear_user_home!
|
125
|
-
end
|
126
|
-
|
127
|
-
it "returns the user path if none variable is set on the environment" do
|
128
|
-
Thor::Util.user_home.should == File.expand_path("~")
|
129
|
-
end
|
130
|
-
|
131
|
-
it "returns the *unix system path if file cannot be expanded and separator does not exist" do
|
132
|
-
File.should_receive(:expand_path).with("~").and_raise(RuntimeError)
|
133
|
-
previous_value = File::ALT_SEPARATOR
|
134
|
-
capture(:stderr){ File.const_set(:ALT_SEPARATOR, false) }
|
135
|
-
Thor::Util.user_home.should == "/"
|
136
|
-
capture(:stderr){ File.const_set(:ALT_SEPARATOR, previous_value) }
|
137
|
-
end
|
138
|
-
|
139
|
-
it "returns the windows system path if file cannot be expanded and a separator exists" do
|
140
|
-
File.should_receive(:expand_path).with("~").and_raise(RuntimeError)
|
141
|
-
previous_value = File::ALT_SEPARATOR
|
142
|
-
capture(:stderr){ File.const_set(:ALT_SEPARATOR, true) }
|
143
|
-
Thor::Util.user_home.should == "C:/"
|
144
|
-
capture(:stderr){ File.const_set(:ALT_SEPARATOR, previous_value) }
|
145
|
-
end
|
146
|
-
|
147
|
-
it "returns HOME/.thor if set" do
|
148
|
-
ENV.stub!(:[]).with("HOME").and_return("/home/user/")
|
149
|
-
Thor::Util.user_home.should == "/home/user/"
|
150
|
-
end
|
151
|
-
|
152
|
-
it "returns path with HOMEDRIVE and HOMEPATH if set" do
|
153
|
-
ENV.stub!(:[]).with("HOMEDRIVE").and_return("D:/")
|
154
|
-
ENV.stub!(:[]).with("HOMEPATH").and_return("Documents and Settings/James")
|
155
|
-
Thor::Util.user_home.should == "D:/Documents and Settings/James"
|
156
|
-
end
|
157
|
-
|
158
|
-
it "returns APPDATA/.thor if set" do
|
159
|
-
ENV.stub!(:[]).with("APPDATA").and_return("/home/user/")
|
160
|
-
Thor::Util.user_home.should == "/home/user/"
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
describe "#thor_root_glob" do
|
165
|
-
before do
|
166
|
-
ENV.stub!(:[])
|
167
|
-
Thor::Util.clear_user_home!
|
168
|
-
end
|
169
|
-
|
170
|
-
it "escapes globs in path" do
|
171
|
-
ENV.stub!(:[]).with("HOME").and_return("/home/user{1}/")
|
172
|
-
Dir.should_receive(:[]).with("/home/user\\{1\\}/.thor/*").and_return([])
|
173
|
-
Thor::Util.thor_root_glob.should == []
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
describe "#globs_for" do
|
178
|
-
it "escapes globs in path" do
|
179
|
-
Thor::Util.globs_for("/home/apps{1}").should == [
|
180
|
-
"/home/apps\\{1\\}/Thorfile",
|
181
|
-
"/home/apps\\{1\\}/*.thor",
|
182
|
-
"/home/apps\\{1\\}/tasks/*.thor",
|
183
|
-
"/home/apps\\{1\\}/lib/tasks/*.thor"
|
184
|
-
]
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
describe "#escape_globs" do
|
189
|
-
it "escapes ? * { } [ ] glob characters" do
|
190
|
-
Thor::Util.escape_globs("apps?").should == "apps\\?"
|
191
|
-
Thor::Util.escape_globs("apps*").should == "apps\\*"
|
192
|
-
Thor::Util.escape_globs("apps {1}").should == "apps \\{1\\}"
|
193
|
-
Thor::Util.escape_globs("apps [1]").should == "apps \\[1\\]"
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|