thor 0.16.0 → 0.17.0
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.
- data/.rspec +1 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.rdoc +8 -0
- data/Gemfile +12 -8
- data/lib/thor.rb +79 -10
- data/lib/thor/actions.rb +13 -13
- data/lib/thor/actions/directory.rb +29 -10
- data/lib/thor/actions/file_manipulation.rb +8 -2
- data/lib/thor/base.rb +24 -11
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +5 -0
- data/lib/thor/group.rb +5 -5
- data/lib/thor/parser/options.rb +63 -25
- data/lib/thor/rake_compat.rb +3 -2
- data/lib/thor/runner.rb +1 -1
- data/lib/thor/shell/basic.rb +16 -16
- data/lib/thor/shell/color.rb +9 -9
- data/lib/thor/shell/html.rb +9 -9
- data/lib/thor/task.rb +2 -2
- data/lib/thor/version.rb +1 -1
- data/spec/actions/create_file_spec.rb +30 -30
- data/spec/actions/create_link_spec.rb +12 -12
- data/spec/actions/directory_spec.rb +34 -27
- data/spec/actions/empty_directory_spec.rb +16 -16
- data/spec/actions/file_manipulation_spec.rb +62 -50
- data/spec/actions/inject_into_file_spec.rb +18 -18
- data/spec/actions_spec.rb +56 -56
- data/spec/base_spec.rb +69 -69
- data/spec/core_ext/hash_with_indifferent_access_spec.rb +19 -14
- data/spec/core_ext/ordered_hash_spec.rb +29 -29
- data/spec/exit_condition_spec.rb +3 -3
- data/spec/fixtures/preserve/script.sh +3 -0
- data/spec/fixtures/script.thor +5 -0
- data/spec/group_spec.rb +55 -55
- data/spec/invocation_spec.rb +26 -26
- data/spec/parser/argument_spec.rb +12 -12
- data/spec/parser/arguments_spec.rb +12 -12
- data/spec/parser/option_spec.rb +47 -47
- data/spec/parser/options_spec.rb +137 -72
- data/spec/rake_compat_spec.rb +11 -11
- data/spec/register_spec.rb +70 -8
- data/spec/runner_spec.rb +38 -38
- data/spec/shell/basic_spec.rb +49 -37
- data/spec/shell/color_spec.rb +13 -13
- data/spec/shell/html_spec.rb +3 -3
- data/spec/shell_spec.rb +7 -7
- data/spec/spec_helper.rb +4 -0
- data/spec/task_spec.rb +11 -11
- data/spec/thor_spec.rb +161 -91
- data/spec/util_spec.rb +42 -42
- data/thor.gemspec +1 -7
- metadata +8 -118
- data/lib/thor/core_ext/dir_escape.rb +0 -0
@@ -16,11 +16,11 @@ describe Thor::Actions::InjectIntoFile do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def invoke!(*args, &block)
|
19
|
-
capture(:stdout){ invoker.insert_into_file(*args, &block) }
|
19
|
+
capture(:stdout) { invoker.insert_into_file(*args, &block) }
|
20
20
|
end
|
21
21
|
|
22
22
|
def revoke!(*args, &block)
|
23
|
-
capture(:stdout){ revoker.insert_into_file(*args, &block) }
|
23
|
+
capture(:stdout) { revoker.insert_into_file(*args, &block) }
|
24
24
|
end
|
25
25
|
|
26
26
|
def file
|
@@ -30,12 +30,12 @@ describe Thor::Actions::InjectIntoFile do
|
|
30
30
|
describe "#invoke!" do
|
31
31
|
it "changes the file adding content after the flag" do
|
32
32
|
invoke! "doc/README", "\nmore content", :after => "__start__"
|
33
|
-
File.read(file).
|
33
|
+
expect(File.read(file)).to eq("__start__\nmore content\nREADME\n__end__\n")
|
34
34
|
end
|
35
35
|
|
36
36
|
it "changes the file adding content before the flag" do
|
37
37
|
invoke! "doc/README", "more content\n", :before => "__end__"
|
38
|
-
File.read(file).
|
38
|
+
expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
|
39
39
|
end
|
40
40
|
|
41
41
|
it "accepts data as a block" do
|
@@ -43,17 +43,17 @@ describe Thor::Actions::InjectIntoFile do
|
|
43
43
|
"more content\n"
|
44
44
|
end
|
45
45
|
|
46
|
-
File.read(file).
|
46
|
+
expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
|
47
47
|
end
|
48
48
|
|
49
49
|
it "logs status" do
|
50
|
-
invoke!("doc/README", "\nmore content", :after => "__start__").
|
50
|
+
expect(invoke!("doc/README", "\nmore content", :after => "__start__")).to eq(" insert doc/README\n")
|
51
51
|
end
|
52
52
|
|
53
53
|
it "does not change the file if pretending" do
|
54
54
|
invoker :pretend => true
|
55
55
|
invoke! "doc/README", "\nmore content", :after => "__start__"
|
56
|
-
File.read(file).
|
56
|
+
expect(File.read(file)).to eq("__start__\nREADME\n__end__\n")
|
57
57
|
end
|
58
58
|
|
59
59
|
it "does not change the file if already include content" do
|
@@ -61,13 +61,13 @@ describe Thor::Actions::InjectIntoFile do
|
|
61
61
|
"more content\n"
|
62
62
|
end
|
63
63
|
|
64
|
-
File.read(file).
|
64
|
+
expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
|
65
65
|
|
66
66
|
invoke! "doc/README", :before => "__end__" do
|
67
67
|
"more content\n"
|
68
68
|
end
|
69
69
|
|
70
|
-
File.read(file).
|
70
|
+
expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
|
71
71
|
end
|
72
72
|
|
73
73
|
it "does change the file if already include content and :force == true" do
|
@@ -75,13 +75,13 @@ describe Thor::Actions::InjectIntoFile do
|
|
75
75
|
"more content\n"
|
76
76
|
end
|
77
77
|
|
78
|
-
File.read(file).
|
78
|
+
expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
|
79
79
|
|
80
80
|
invoke! "doc/README", :before => "__end__", :force => true do
|
81
81
|
"more content\n"
|
82
82
|
end
|
83
83
|
|
84
|
-
File.read(file).
|
84
|
+
expect(File.read(file)).to eq("__start__\nREADME\nmore content\nmore content\n__end__\n")
|
85
85
|
end
|
86
86
|
|
87
87
|
end
|
@@ -90,46 +90,46 @@ describe Thor::Actions::InjectIntoFile do
|
|
90
90
|
it "substracts the destination file after injection" do
|
91
91
|
invoke! "doc/README", "\nmore content", :after => "__start__"
|
92
92
|
revoke! "doc/README", "\nmore content", :after => "__start__"
|
93
|
-
File.read(file).
|
93
|
+
expect(File.read(file)).to eq("__start__\nREADME\n__end__\n")
|
94
94
|
end
|
95
95
|
|
96
96
|
it "substracts the destination file before injection" do
|
97
97
|
invoke! "doc/README", "more content\n", :before => "__start__"
|
98
98
|
revoke! "doc/README", "more content\n", :before => "__start__"
|
99
|
-
File.read(file).
|
99
|
+
expect(File.read(file)).to eq("__start__\nREADME\n__end__\n")
|
100
100
|
end
|
101
101
|
|
102
102
|
it "substracts even with double after injection" do
|
103
103
|
invoke! "doc/README", "\nmore content", :after => "__start__"
|
104
104
|
invoke! "doc/README", "\nanother stuff", :after => "__start__"
|
105
105
|
revoke! "doc/README", "\nmore content", :after => "__start__"
|
106
|
-
File.read(file).
|
106
|
+
expect(File.read(file)).to eq("__start__\nanother stuff\nREADME\n__end__\n")
|
107
107
|
end
|
108
108
|
|
109
109
|
it "substracts even with double before injection" do
|
110
110
|
invoke! "doc/README", "more content\n", :before => "__start__"
|
111
111
|
invoke! "doc/README", "another stuff\n", :before => "__start__"
|
112
112
|
revoke! "doc/README", "more content\n", :before => "__start__"
|
113
|
-
File.read(file).
|
113
|
+
expect(File.read(file)).to eq("another stuff\n__start__\nREADME\n__end__\n")
|
114
114
|
end
|
115
115
|
|
116
116
|
it "substracts when prepending" do
|
117
117
|
invoke! "doc/README", "more content\n", :after => /\A/
|
118
118
|
invoke! "doc/README", "another stuff\n", :after => /\A/
|
119
119
|
revoke! "doc/README", "more content\n", :after => /\A/
|
120
|
-
File.read(file).
|
120
|
+
expect(File.read(file)).to eq("another stuff\n__start__\nREADME\n__end__\n")
|
121
121
|
end
|
122
122
|
|
123
123
|
it "substracts when appending" do
|
124
124
|
invoke! "doc/README", "more content\n", :before => /\z/
|
125
125
|
invoke! "doc/README", "another stuff\n", :before => /\z/
|
126
126
|
revoke! "doc/README", "more content\n", :before => /\z/
|
127
|
-
File.read(file).
|
127
|
+
expect(File.read(file)).to eq("__start__\nREADME\n__end__\nanother stuff\n")
|
128
128
|
end
|
129
129
|
|
130
130
|
it "shows progress information to the user" do
|
131
131
|
invoke!("doc/README", "\nmore content", :after => "__start__")
|
132
|
-
revoke!("doc/README", "\nmore content", :after => "__start__").
|
132
|
+
expect(revoke!("doc/README", "\nmore content", :after => "__start__")).to eq(" subtract doc/README\n")
|
133
133
|
end
|
134
134
|
end
|
135
135
|
end
|
data/spec/actions_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe Thor::Actions do
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def action(*args, &block)
|
9
|
-
capture(:stdout){ runner.send(*args, &block) }
|
9
|
+
capture(:stdout) { runner.send(*args, &block) }
|
10
10
|
end
|
11
11
|
|
12
12
|
def file
|
@@ -15,34 +15,34 @@ describe Thor::Actions do
|
|
15
15
|
|
16
16
|
describe "on include" do
|
17
17
|
it "adds runtime options to the base class" do
|
18
|
-
MyCounter.class_options.keys.
|
19
|
-
MyCounter.class_options.keys.
|
20
|
-
MyCounter.class_options.keys.
|
21
|
-
MyCounter.class_options.keys.
|
18
|
+
expect(MyCounter.class_options.keys).to include(:pretend)
|
19
|
+
expect(MyCounter.class_options.keys).to include(:force)
|
20
|
+
expect(MyCounter.class_options.keys).to include(:quiet)
|
21
|
+
expect(MyCounter.class_options.keys).to include(:skip)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
25
|
describe "#initialize" do
|
26
26
|
it "has default behavior invoke" do
|
27
|
-
runner.behavior.
|
27
|
+
expect(runner.behavior).to eq(:invoke)
|
28
28
|
end
|
29
29
|
|
30
30
|
it "can have behavior revoke" do
|
31
|
-
MyCounter.new([1], {}, :behavior => :revoke).behavior.
|
31
|
+
expect(MyCounter.new([1], {}, :behavior => :revoke).behavior).to eq(:revoke)
|
32
32
|
end
|
33
33
|
|
34
34
|
it "when behavior is set to force, overwrite options" do
|
35
35
|
runner = MyCounter.new([1], { :force => false, :skip => true }, :behavior => :force)
|
36
|
-
runner.behavior.
|
37
|
-
runner.options.force.
|
38
|
-
runner.options.skip.
|
36
|
+
expect(runner.behavior).to eq(:invoke)
|
37
|
+
expect(runner.options.force).to be_true
|
38
|
+
expect(runner.options.skip).not_to be_true
|
39
39
|
end
|
40
40
|
|
41
41
|
it "when behavior is set to skip, overwrite options" do
|
42
42
|
runner = MyCounter.new([1], ["--force"], :behavior => :skip)
|
43
|
-
runner.behavior.
|
44
|
-
runner.options.force.
|
45
|
-
runner.options.skip.
|
43
|
+
expect(runner.behavior).to eq(:invoke)
|
44
|
+
expect(runner.options.force).not_to be_true
|
45
|
+
expect(runner.options.skip).to be_true
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -51,82 +51,82 @@ describe Thor::Actions do
|
|
51
51
|
it "gets the current directory and expands the path to set the root" do
|
52
52
|
base = MyCounter.new([1])
|
53
53
|
base.destination_root = "here"
|
54
|
-
base.destination_root.
|
54
|
+
expect(base.destination_root).to eq(File.expand_path(File.join(File.dirname(__FILE__), "..", "here")))
|
55
55
|
end
|
56
56
|
|
57
57
|
it "does not use the current directory if one is given" do
|
58
58
|
root = File.expand_path("/")
|
59
59
|
base = MyCounter.new([1])
|
60
60
|
base.destination_root = root
|
61
|
-
base.destination_root.
|
61
|
+
expect(base.destination_root).to eq(root)
|
62
62
|
end
|
63
63
|
|
64
64
|
it "uses the current directory if none is given" do
|
65
65
|
base = MyCounter.new([1])
|
66
|
-
base.destination_root.
|
66
|
+
expect(base.destination_root).to eq(File.expand_path(File.join(File.dirname(__FILE__), "..")))
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
70
|
describe "#relative_to_original_destination_root" do
|
71
71
|
it "returns the path relative to the absolute root" do
|
72
|
-
runner.relative_to_original_destination_root(file).
|
72
|
+
expect(runner.relative_to_original_destination_root(file)).to eq("foo")
|
73
73
|
end
|
74
74
|
|
75
75
|
it "does not remove dot if required" do
|
76
|
-
runner.relative_to_original_destination_root(file, false).
|
76
|
+
expect(runner.relative_to_original_destination_root(file, false)).to eq("./foo")
|
77
77
|
end
|
78
78
|
|
79
79
|
it "always use the absolute root" do
|
80
80
|
runner.inside("foo") do
|
81
|
-
runner.relative_to_original_destination_root(file).
|
81
|
+
expect(runner.relative_to_original_destination_root(file)).to eq("foo")
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
85
|
it "creates proper relative paths for absolute file location" do
|
86
|
-
runner.relative_to_original_destination_root('/test/file').
|
86
|
+
expect(runner.relative_to_original_destination_root('/test/file')).to eq("/test/file")
|
87
87
|
end
|
88
88
|
|
89
89
|
it "does not fail with files constaining regexp characters" do
|
90
90
|
runner = MyCounter.new([1], {}, { :destination_root => File.join(destination_root, "fo[o-b]ar") })
|
91
|
-
runner.relative_to_original_destination_root("bar").
|
91
|
+
expect(runner.relative_to_original_destination_root("bar")).to eq("bar")
|
92
92
|
end
|
93
93
|
|
94
94
|
describe "#source_paths_for_search" do
|
95
95
|
it "add source_root to source_paths_for_search" do
|
96
|
-
MyCounter.source_paths_for_search.
|
96
|
+
expect(MyCounter.source_paths_for_search).to include(File.expand_path("fixtures", File.dirname(__FILE__)))
|
97
97
|
end
|
98
98
|
|
99
99
|
it "keeps only current source root in source paths" do
|
100
|
-
ClearCounter.source_paths_for_search.
|
101
|
-
ClearCounter.source_paths_for_search.
|
100
|
+
expect(ClearCounter.source_paths_for_search).to include(File.expand_path("fixtures/bundle", File.dirname(__FILE__)))
|
101
|
+
expect(ClearCounter.source_paths_for_search).not_to include(File.expand_path("fixtures", File.dirname(__FILE__)))
|
102
102
|
end
|
103
103
|
|
104
104
|
it "customized source paths should be before source roots" do
|
105
|
-
ClearCounter.source_paths_for_search[0].
|
106
|
-
ClearCounter.source_paths_for_search[1].
|
105
|
+
expect(ClearCounter.source_paths_for_search[0]).to eq(File.expand_path("fixtures/doc", File.dirname(__FILE__)))
|
106
|
+
expect(ClearCounter.source_paths_for_search[1]).to eq(File.expand_path("fixtures/bundle", File.dirname(__FILE__)))
|
107
107
|
end
|
108
108
|
|
109
109
|
it "keeps inherited source paths at the end" do
|
110
|
-
ClearCounter.source_paths_for_search.last.
|
110
|
+
expect(ClearCounter.source_paths_for_search.last).to eq(File.expand_path("fixtures/broken", File.dirname(__FILE__)))
|
111
111
|
end
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
115
115
|
describe "#find_in_source_paths" do
|
116
116
|
it "raises an error if source path is empty" do
|
117
|
-
|
117
|
+
expect {
|
118
118
|
A.new.find_in_source_paths("foo")
|
119
|
-
}.
|
119
|
+
}.to raise_error(Thor::Error, /Currently you have no source paths/)
|
120
120
|
end
|
121
121
|
|
122
122
|
it "finds a template inside the source path" do
|
123
|
-
runner.find_in_source_paths("doc").
|
124
|
-
|
123
|
+
expect(runner.find_in_source_paths("doc")).to eq(File.expand_path("doc", source_root))
|
124
|
+
expect{ runner.find_in_source_paths("README") }.to raise_error
|
125
125
|
|
126
126
|
new_path = File.join(source_root, "doc")
|
127
127
|
runner.instance_variable_set(:@source_paths, nil)
|
128
128
|
runner.source_paths.unshift(new_path)
|
129
|
-
runner.find_in_source_paths("README").
|
129
|
+
expect(runner.find_in_source_paths("README")).to eq(File.expand_path("README", new_path))
|
130
130
|
end
|
131
131
|
end
|
132
132
|
end
|
@@ -134,49 +134,49 @@ describe Thor::Actions do
|
|
134
134
|
describe "#inside" do
|
135
135
|
it "executes the block inside the given folder" do
|
136
136
|
runner.inside("foo") do
|
137
|
-
Dir.pwd.
|
137
|
+
expect(Dir.pwd).to eq(file)
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
141
141
|
it "changes the base root" do
|
142
142
|
runner.inside("foo") do
|
143
|
-
runner.destination_root.
|
143
|
+
expect(runner.destination_root).to eq(file)
|
144
144
|
end
|
145
145
|
end
|
146
146
|
|
147
147
|
it "creates the directory if it does not exist" do
|
148
148
|
runner.inside("foo") do
|
149
|
-
File.exists?(file).
|
149
|
+
expect(File.exists?(file)).to be_true
|
150
150
|
end
|
151
151
|
end
|
152
152
|
|
153
153
|
describe "when pretending" do
|
154
154
|
it "no directories should be created" do
|
155
155
|
runner.inside("bar", :pretend => true) {}
|
156
|
-
File.exists?("bar").
|
156
|
+
expect(File.exists?("bar")).to be_false
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
160
|
describe "when verbose" do
|
161
161
|
it "logs status" do
|
162
|
-
capture(:stdout)
|
162
|
+
expect(capture(:stdout) {
|
163
163
|
runner.inside("foo", :verbose => true) {}
|
164
|
-
|
164
|
+
}).to match(/inside foo/)
|
165
165
|
end
|
166
166
|
|
167
167
|
it "uses padding in next status" do
|
168
|
-
capture(:stdout)
|
168
|
+
expect(capture(:stdout) {
|
169
169
|
runner.inside("foo", :verbose => true) do
|
170
170
|
runner.say_status :cool, :padding
|
171
171
|
end
|
172
|
-
|
172
|
+
}).to match(/cool padding/)
|
173
173
|
end
|
174
174
|
|
175
175
|
it "removes padding after block" do
|
176
|
-
capture(:stdout)
|
176
|
+
expect(capture(:stdout) {
|
177
177
|
runner.inside("foo", :verbose => true) {}
|
178
178
|
runner.say_status :no, :padding
|
179
|
-
|
179
|
+
}).to match(/no padding/)
|
180
180
|
end
|
181
181
|
end
|
182
182
|
end
|
@@ -184,20 +184,20 @@ describe Thor::Actions do
|
|
184
184
|
describe "#in_root" do
|
185
185
|
it "executes the block in the root folder" do
|
186
186
|
runner.inside("foo") do
|
187
|
-
runner.in_root { Dir.pwd.
|
187
|
+
runner.in_root { expect(Dir.pwd).to eq(destination_root) }
|
188
188
|
end
|
189
189
|
end
|
190
190
|
|
191
191
|
it "changes the base root" do
|
192
192
|
runner.inside("foo") do
|
193
|
-
runner.in_root { runner.destination_root.
|
193
|
+
runner.in_root { expect(runner.destination_root).to eq(destination_root) }
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
197
197
|
it "returns to the previous state" do
|
198
198
|
runner.inside("foo") do
|
199
199
|
runner.in_root { }
|
200
|
-
runner.destination_root.
|
200
|
+
expect(runner.destination_root).to eq(file)
|
201
201
|
end
|
202
202
|
end
|
203
203
|
end
|
@@ -234,21 +234,21 @@ describe Thor::Actions do
|
|
234
234
|
|
235
235
|
it "opens a file and executes its content in the instance binding" do
|
236
236
|
action :apply, @file
|
237
|
-
runner.instance_variable_get("@foo").
|
237
|
+
expect(runner.instance_variable_get("@foo")).to eq("FOO")
|
238
238
|
end
|
239
239
|
|
240
240
|
it "applies padding to the content inside the file" do
|
241
|
-
action(:apply, @file).
|
241
|
+
expect(action(:apply, @file)).to match(/cool padding/)
|
242
242
|
end
|
243
243
|
|
244
244
|
it "logs its status" do
|
245
|
-
action(:apply, @file).
|
245
|
+
expect(action(:apply, @file)).to match(/ apply #{@file}\n/)
|
246
246
|
end
|
247
247
|
|
248
248
|
it "does not log status" do
|
249
249
|
content = action(:apply, @file, :verbose => false)
|
250
|
-
content.
|
251
|
-
content.
|
250
|
+
expect(content).to match(/cool padding/)
|
251
|
+
expect(content).not_to match(/apply http/)
|
252
252
|
end
|
253
253
|
end
|
254
254
|
|
@@ -262,11 +262,11 @@ describe Thor::Actions do
|
|
262
262
|
end
|
263
263
|
|
264
264
|
it "logs status" do
|
265
|
-
action(:run, "ls").
|
265
|
+
expect(action(:run, "ls")).to eq(" run ls from \".\"\n")
|
266
266
|
end
|
267
267
|
|
268
268
|
it "does not log status if required" do
|
269
|
-
action(:run, "ls", :verbose => false).
|
269
|
+
expect(action(:run, "ls", :verbose => false)).to be_empty
|
270
270
|
end
|
271
271
|
|
272
272
|
it "accepts a color as status" do
|
@@ -286,11 +286,11 @@ describe Thor::Actions do
|
|
286
286
|
end
|
287
287
|
|
288
288
|
it "logs status" do
|
289
|
-
action(:run_ruby_script, "script.rb").
|
289
|
+
expect(action(:run_ruby_script, "script.rb")).to eq(" run jruby script.rb from \".\"\n")
|
290
290
|
end
|
291
291
|
|
292
292
|
it "does not log status if required" do
|
293
|
-
action(:run_ruby_script, "script.rb", :verbose => false).
|
293
|
+
expect(action(:run_ruby_script, "script.rb", :verbose => false)).to be_empty
|
294
294
|
end
|
295
295
|
end
|
296
296
|
|
@@ -315,12 +315,12 @@ describe Thor::Actions do
|
|
315
315
|
|
316
316
|
it "logs status" do
|
317
317
|
runner.should_receive(:system).with("thor list")
|
318
|
-
action(:thor, :list).
|
318
|
+
expect(action(:thor, :list)).to eq(" run thor list from \".\"\n")
|
319
319
|
end
|
320
320
|
|
321
321
|
it "does not log status if required" do
|
322
322
|
runner.should_receive(:system).with("thor list --foo 1 2 3")
|
323
|
-
action(:thor, :list, :foo => [1,2,3], :verbose => false).
|
323
|
+
expect(action(:thor, :list, :foo => [1,2,3], :verbose => false)).to be_empty
|
324
324
|
end
|
325
325
|
|
326
326
|
it "captures the output when :capture is given" do
|
data/spec/base_spec.rb
CHANGED
@@ -12,94 +12,94 @@ describe Thor::Base do
|
|
12
12
|
describe "#initialize" do
|
13
13
|
it "sets arguments array" do
|
14
14
|
base = MyCounter.new [1, 2]
|
15
|
-
base.first.
|
16
|
-
base.second.
|
15
|
+
expect(base.first).to eq(1)
|
16
|
+
expect(base.second).to eq(2)
|
17
17
|
end
|
18
18
|
|
19
19
|
it "sets arguments default values" do
|
20
20
|
base = MyCounter.new [1]
|
21
|
-
base.second.
|
21
|
+
expect(base.second).to eq(2)
|
22
22
|
end
|
23
23
|
|
24
24
|
it "sets options default values" do
|
25
25
|
base = MyCounter.new [1, 2]
|
26
|
-
base.options[:third].
|
26
|
+
expect(base.options[:third]).to eq(3)
|
27
27
|
end
|
28
28
|
|
29
29
|
it "allows options to be given as symbols or strings" do
|
30
30
|
base = MyCounter.new [1, 2], :third => 4
|
31
|
-
base.options[:third].
|
31
|
+
expect(base.options[:third]).to eq(4)
|
32
32
|
|
33
33
|
base = MyCounter.new [1, 2], "third" => 4
|
34
|
-
base.options[:third].
|
34
|
+
expect(base.options[:third]).to eq(4)
|
35
35
|
end
|
36
36
|
|
37
37
|
it "creates options with indifferent access" do
|
38
38
|
base = MyCounter.new [1, 2], :third => 3
|
39
|
-
base.options['third'].
|
39
|
+
expect(base.options['third']).to eq(3)
|
40
40
|
end
|
41
41
|
|
42
42
|
it "creates options with magic predicates" do
|
43
43
|
base = MyCounter.new [1, 2], :third => 3
|
44
|
-
base.options.third.
|
44
|
+
expect(base.options.third).to eq(3)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
48
|
describe "#no_tasks" do
|
49
49
|
it "avoids methods being added as tasks" do
|
50
|
-
MyScript.tasks.keys.
|
51
|
-
MyScript.tasks.keys.
|
50
|
+
expect(MyScript.tasks.keys).to include("animal")
|
51
|
+
expect(MyScript.tasks.keys).not_to include("this_is_not_a_task")
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
55
|
describe "#argument" do
|
56
56
|
it "sets a value as required and creates an accessor for it" do
|
57
|
-
MyCounter.start(["1", "2", "--third", "3"])[0].
|
58
|
-
Scripts::MyScript.start(["zoo", "my_special_param", "--param=normal_param"]).
|
57
|
+
expect(MyCounter.start(["1", "2", "--third", "3"])[0]).to eq(1)
|
58
|
+
expect(Scripts::MyScript.start(["zoo", "my_special_param", "--param=normal_param"])).to eq("my_special_param")
|
59
59
|
end
|
60
60
|
|
61
61
|
it "does not set a value in the options hash" do
|
62
|
-
BrokenCounter.start(["1", "2", "--third", "3"])[0].
|
62
|
+
expect(BrokenCounter.start(["1", "2", "--third", "3"])[0]).to be_nil
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
66
|
describe "#arguments" do
|
67
67
|
it "returns the arguments for the class" do
|
68
|
-
MyCounter.arguments.
|
68
|
+
expect(MyCounter.arguments).to have(2).items
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
72
|
describe "#class_option" do
|
73
73
|
it "sets options class wise" do
|
74
|
-
MyCounter.start(["1", "2", "--third", "3"])[2].
|
74
|
+
expect(MyCounter.start(["1", "2", "--third", "3"])[2]).to eq(3)
|
75
75
|
end
|
76
76
|
|
77
77
|
it "does not create an accessor for it" do
|
78
|
-
BrokenCounter.start(["1", "2", "--third", "3"])[3].
|
78
|
+
expect(BrokenCounter.start(["1", "2", "--third", "3"])[3]).to be_false
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
82
|
describe "#class_options" do
|
83
83
|
it "sets default options overwriting superclass definitions" do
|
84
84
|
options = Scripts::MyScript.class_options
|
85
|
-
options[:force].
|
85
|
+
expect(options[:force]).not_to be_required
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
89
|
describe "#remove_argument" do
|
90
90
|
it "removes previous defined arguments from class" do
|
91
|
-
ClearCounter.arguments.
|
91
|
+
expect(ClearCounter.arguments).to be_empty
|
92
92
|
end
|
93
93
|
|
94
94
|
it "undefine accessors if required" do
|
95
|
-
ClearCounter.new.
|
96
|
-
ClearCounter.new.
|
95
|
+
expect(ClearCounter.new).not_to respond_to(:first)
|
96
|
+
expect(ClearCounter.new).not_to respond_to(:second)
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
100
|
describe "#remove_class_option" do
|
101
101
|
it "removes previous defined class option" do
|
102
|
-
ClearCounter.class_options[:third].
|
102
|
+
expect(ClearCounter.class_options[:third]).to be_nil
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
@@ -109,125 +109,125 @@ describe Thor::Base do
|
|
109
109
|
end
|
110
110
|
|
111
111
|
it "shows options description" do
|
112
|
-
@content.
|
112
|
+
expect(@content).to match(/# The third argument/)
|
113
113
|
end
|
114
114
|
|
115
115
|
it "shows usage with banner content" do
|
116
|
-
@content.
|
116
|
+
expect(@content).to match(/\[\-\-third=THREE\]/)
|
117
117
|
end
|
118
118
|
|
119
119
|
it "shows default values below description" do
|
120
|
-
@content.
|
120
|
+
expect(@content).to match(/# Default: 3/)
|
121
121
|
end
|
122
122
|
|
123
123
|
it "shows options in different groups" do
|
124
|
-
@content.
|
125
|
-
@content.
|
126
|
-
@content.
|
124
|
+
expect(@content).to match(/Options\:/)
|
125
|
+
expect(@content).to match(/Runtime options\:/)
|
126
|
+
expect(@content).to match(/\-p, \[\-\-pretend\]/)
|
127
127
|
end
|
128
128
|
|
129
129
|
it "use padding in options that does not have aliases" do
|
130
|
-
@content.
|
131
|
-
@content.
|
130
|
+
expect(@content).to match(/^ -t, \[--third/)
|
131
|
+
expect(@content).to match(/^ \[--fourth/)
|
132
132
|
end
|
133
133
|
|
134
134
|
it "allows extra options to be given" do
|
135
135
|
hash = { "Foo" => B.class_options.values }
|
136
136
|
|
137
137
|
content = capture(:stdout) { MyCounter.send(:class_options_help, Thor::Base.shell.new, hash) }
|
138
|
-
content.
|
139
|
-
content.
|
138
|
+
expect(content).to match(/Foo options\:/)
|
139
|
+
expect(content).to match(/--last-name=LAST_NAME/)
|
140
140
|
end
|
141
141
|
|
142
142
|
it "displays choices for enums" do
|
143
143
|
content = capture(:stdout) { Enum.help(Thor::Base.shell.new) }
|
144
|
-
content.
|
144
|
+
expect(content).to match(/Possible values\: apple, banana/)
|
145
145
|
end
|
146
146
|
end
|
147
147
|
|
148
148
|
describe "#namespace" do
|
149
149
|
it "returns the default class namespace" do
|
150
|
-
Scripts::MyScript.namespace.
|
150
|
+
expect(Scripts::MyScript.namespace).to eq("scripts:my_script")
|
151
151
|
end
|
152
152
|
|
153
153
|
it "sets a namespace to the class" do
|
154
|
-
Scripts::MyDefaults.namespace.
|
154
|
+
expect(Scripts::MyDefaults.namespace).to eq("default")
|
155
155
|
end
|
156
156
|
end
|
157
157
|
|
158
158
|
describe "#group" do
|
159
159
|
it "sets a group" do
|
160
|
-
MyScript.group.
|
160
|
+
expect(MyScript.group).to eq("script")
|
161
161
|
end
|
162
162
|
|
163
163
|
it "inherits the group from parent" do
|
164
|
-
MyChildScript.group.
|
164
|
+
expect(MyChildScript.group).to eq("script")
|
165
165
|
end
|
166
166
|
|
167
167
|
it "defaults to standard if no group is given" do
|
168
|
-
Amazing.group.
|
168
|
+
expect(Amazing.group).to eq("standard")
|
169
169
|
end
|
170
170
|
end
|
171
171
|
|
172
172
|
describe "#subclasses" do
|
173
173
|
it "tracks its subclasses in an Array" do
|
174
|
-
Thor::Base.subclasses.
|
175
|
-
Thor::Base.subclasses.
|
176
|
-
Thor::Base.subclasses.
|
174
|
+
expect(Thor::Base.subclasses).to include(MyScript)
|
175
|
+
expect(Thor::Base.subclasses).to include(MyChildScript)
|
176
|
+
expect(Thor::Base.subclasses).to include(Scripts::MyScript)
|
177
177
|
end
|
178
178
|
end
|
179
179
|
|
180
180
|
describe "#subclass_files" do
|
181
181
|
it "returns tracked subclasses, grouped by the files they come from" do
|
182
182
|
thorfile = File.join(File.dirname(__FILE__), "fixtures", "script.thor")
|
183
|
-
Thor::Base.subclass_files[File.expand_path(thorfile)].
|
183
|
+
expect(Thor::Base.subclass_files[File.expand_path(thorfile)]).to eq([
|
184
184
|
MyScript, MyScript::AnotherScript, MyChildScript, Barn,
|
185
185
|
Scripts::MyScript, Scripts::MyDefaults, Scripts::ChildDefault
|
186
|
-
]
|
186
|
+
])
|
187
187
|
end
|
188
188
|
|
189
189
|
it "tracks a single subclass across multiple files" do
|
190
190
|
thorfile = File.join(File.dirname(__FILE__), "fixtures", "task.thor")
|
191
|
-
Thor::Base.subclass_files[File.expand_path(thorfile)].
|
192
|
-
Thor::Base.subclass_files[File.expand_path(__FILE__)].
|
191
|
+
expect(Thor::Base.subclass_files[File.expand_path(thorfile)]).to include(Amazing)
|
192
|
+
expect(Thor::Base.subclass_files[File.expand_path(__FILE__)]).to include(Amazing)
|
193
193
|
end
|
194
194
|
end
|
195
195
|
|
196
196
|
describe "#tasks" do
|
197
197
|
it "returns a list with all tasks defined in this class" do
|
198
|
-
MyChildScript.new.
|
199
|
-
MyChildScript.tasks.keys.
|
198
|
+
expect(MyChildScript.new).to respond_to("animal")
|
199
|
+
expect(MyChildScript.tasks.keys).to include("animal")
|
200
200
|
end
|
201
201
|
|
202
202
|
it "raises an error if a task with reserved word is defined" do
|
203
|
-
|
203
|
+
expect {
|
204
204
|
klass = Class.new(Thor::Group)
|
205
205
|
klass.class_eval "def shell; end"
|
206
|
-
}.
|
206
|
+
}.to raise_error(RuntimeError, /"shell" is a Thor reserved word and cannot be defined as task/)
|
207
207
|
end
|
208
208
|
end
|
209
209
|
|
210
210
|
describe "#all_tasks" do
|
211
211
|
it "returns a list with all tasks defined in this class plus superclasses" do
|
212
|
-
MyChildScript.new.
|
213
|
-
MyChildScript.all_tasks.keys.
|
212
|
+
expect(MyChildScript.new).to respond_to("foo")
|
213
|
+
expect(MyChildScript.all_tasks.keys).to include("foo")
|
214
214
|
end
|
215
215
|
end
|
216
216
|
|
217
217
|
describe "#remove_task" do
|
218
218
|
it "removes the task from its tasks hash" do
|
219
|
-
MyChildScript.tasks.keys.
|
220
|
-
MyChildScript.tasks.keys.
|
219
|
+
expect(MyChildScript.tasks.keys).not_to include("bar")
|
220
|
+
expect(MyChildScript.tasks.keys).not_to include("boom")
|
221
221
|
end
|
222
222
|
|
223
223
|
it "undefines the method if desired" do
|
224
|
-
MyChildScript.new.
|
224
|
+
expect(MyChildScript.new).not_to respond_to("boom")
|
225
225
|
end
|
226
226
|
end
|
227
227
|
|
228
228
|
describe "#from_superclass" do
|
229
229
|
it "does not send a method to the superclass if the superclass does not respond to it" do
|
230
|
-
MyCounter.get_from_super.
|
230
|
+
expect(MyCounter.get_from_super).to eq(13)
|
231
231
|
end
|
232
232
|
end
|
233
233
|
|
@@ -235,9 +235,9 @@ describe Thor::Base do
|
|
235
235
|
it "raises an error instead of rescueing if THOR_DEBUG=1 is given" do
|
236
236
|
begin
|
237
237
|
ENV["THOR_DEBUG"] = 1
|
238
|
-
|
238
|
+
expect {
|
239
239
|
MyScript.start ["what", "--debug"]
|
240
|
-
}.
|
240
|
+
}.to raise_error(Thor::UndefinedTaskError, 'Could not find task "what" in "my_script" namespace.')
|
241
241
|
rescue
|
242
242
|
ENV["THOR_DEBUG"] = nil
|
243
243
|
end
|
@@ -246,34 +246,34 @@ describe Thor::Base do
|
|
246
246
|
it "does not steal args" do
|
247
247
|
args = ["foo", "bar", "--force", "true"]
|
248
248
|
MyScript.start(args)
|
249
|
-
args.
|
249
|
+
expect(args).to eq(["foo", "bar", "--force", "true"])
|
250
250
|
end
|
251
251
|
|
252
252
|
it "checks unknown options" do
|
253
|
-
capture(:stderr) {
|
253
|
+
expect(capture(:stderr) {
|
254
254
|
MyScript.start(["foo", "bar", "--force", "true", "--unknown", "baz"])
|
255
|
-
}.strip.
|
255
|
+
}.strip).to eq("Unknown switches '--unknown'")
|
256
256
|
end
|
257
257
|
|
258
258
|
it "checks unknown options except specified" do
|
259
|
-
capture(:stderr) {
|
260
|
-
MyScript.start(["with_optional", "NAME", "--omg", "--invalid"]).
|
261
|
-
}.strip.
|
259
|
+
expect(capture(:stderr) {
|
260
|
+
expect(MyScript.start(["with_optional", "NAME", "--omg", "--invalid"])).to eq(["NAME", {}, ["--omg", "--invalid"]])
|
261
|
+
}.strip).to be_empty
|
262
262
|
end
|
263
263
|
end
|
264
264
|
|
265
265
|
describe "attr_*" do
|
266
|
-
it "
|
267
|
-
capture(:stderr){ MyScript.start(["another_attribute"]) }.
|
266
|
+
it "does not add attr_reader as a task" do
|
267
|
+
expect(capture(:stderr){ MyScript.start(["another_attribute"]) }).to match(/Could not find/)
|
268
268
|
end
|
269
269
|
|
270
|
-
it "
|
271
|
-
capture(:stderr){ MyScript.start(["another_attribute=", "foo"]) }.
|
270
|
+
it "does not add attr_writer as a task" do
|
271
|
+
expect(capture(:stderr){ MyScript.start(["another_attribute=", "foo"]) }).to match(/Could not find/)
|
272
272
|
end
|
273
273
|
|
274
|
-
it "
|
275
|
-
capture(:stderr){ MyScript.start(["some_attribute"]) }.
|
276
|
-
capture(:stderr){ MyScript.start(["some_attribute=", "foo"]) }.
|
274
|
+
it "does not add attr_accessor as a task" do
|
275
|
+
expect(capture(:stderr){ MyScript.start(["some_attribute"]) }).to match(/Could not find/)
|
276
|
+
expect(capture(:stderr){ MyScript.start(["some_attribute=", "foo"]) }).to match(/Could not find/)
|
277
277
|
end
|
278
278
|
end
|
279
279
|
end
|