thor 0.12.2 → 0.12.3
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/CHANGELOG.rdoc +3 -5
- data/bin/thor +1 -0
- data/lib/thor.rb +35 -37
- data/lib/thor/actions.rb +1 -0
- data/lib/thor/actions/create_file.rb +2 -2
- data/lib/thor/actions/file_manipulation.rb +4 -4
- data/lib/thor/actions/inject_into_file.rb +1 -1
- data/lib/thor/core_ext/file_binary_read.rb +9 -0
- data/lib/thor/group.rb +39 -27
- data/lib/thor/runner.rb +40 -40
- data/lib/thor/shell/color.rb +1 -1
- data/lib/thor/task.rb +13 -14
- data/lib/thor/util.rb +4 -22
- data/lib/thor/version.rb +1 -1
- data/spec/actions/create_file_spec.rb +7 -7
- data/spec/actions/directory_spec.rb +1 -1
- data/spec/actions/file_manipulation_spec.rb +15 -15
- data/spec/actions_spec.rb +14 -13
- data/spec/group_spec.rb +1 -7
- data/spec/runner_spec.rb +30 -34
- data/spec/shell/basic_spec.rb +43 -43
- data/spec/shell/color_spec.rb +6 -6
- data/spec/spec_helper.rb +4 -4
- data/spec/task_spec.rb +11 -9
- data/spec/thor_spec.rb +9 -12
- data/spec/util_spec.rb +7 -31
- metadata +3 -29
data/lib/thor/util.rb
CHANGED
@@ -76,8 +76,10 @@ class Thor
|
|
76
76
|
# Returns the thor classes declared inside the given class.
|
77
77
|
#
|
78
78
|
def self.thor_classes_in(klass)
|
79
|
+
stringfied_constants = klass.constants.map { |c| c.to_s }
|
79
80
|
Thor::Base.subclasses.select do |subclass|
|
80
|
-
|
81
|
+
next unless subclass.name
|
82
|
+
stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", ''))
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
@@ -155,7 +157,7 @@ class Thor
|
|
155
157
|
# inside the sandbox to avoid namespacing conflicts.
|
156
158
|
#
|
157
159
|
def self.load_thorfile(path, content=nil)
|
158
|
-
content ||= File.
|
160
|
+
content ||= File.binread(path)
|
159
161
|
|
160
162
|
begin
|
161
163
|
Thor::Sandbox.class_eval(content, path)
|
@@ -164,26 +166,6 @@ class Thor
|
|
164
166
|
end
|
165
167
|
end
|
166
168
|
|
167
|
-
# Receives a yaml (hash) and updates all constants entries to namespace.
|
168
|
-
# This was added to deal with deprecated versions of Thor.
|
169
|
-
#
|
170
|
-
# TODO Deprecate this method in the future.
|
171
|
-
#
|
172
|
-
# ==== Returns
|
173
|
-
# TrueClass|FalseClass:: Returns true if any change to the yaml file was made.
|
174
|
-
#
|
175
|
-
def self.convert_constants_to_namespaces(yaml)
|
176
|
-
yaml_changed = false
|
177
|
-
|
178
|
-
yaml.each do |k, v|
|
179
|
-
next unless v[:constants] && v[:namespaces].nil?
|
180
|
-
yaml_changed = true
|
181
|
-
yaml[k][:namespaces] = v[:constants].map{|c| Thor::Util.namespace_from_thor_class(c)}
|
182
|
-
end
|
183
|
-
|
184
|
-
yaml_changed
|
185
|
-
end
|
186
|
-
|
187
169
|
def self.user_home
|
188
170
|
@@user_home ||= if ENV["HOME"]
|
189
171
|
ENV["HOME"]
|
data/lib/thor/version.rb
CHANGED
@@ -8,7 +8,7 @@ describe Thor::Actions::CreateFile do
|
|
8
8
|
|
9
9
|
def create_file(destination=nil, config={}, options={})
|
10
10
|
@base = MyCounter.new([1,2], options, { :destination_root => destination_root })
|
11
|
-
stub(
|
11
|
+
@base.stub!(:file_name).and_return('rdoc')
|
12
12
|
|
13
13
|
@action = Thor::Actions::CreateFile.new(@base, destination, "CONFIGURATION",
|
14
14
|
{ :verbose => !@silence }.merge(config))
|
@@ -103,7 +103,7 @@ describe Thor::Actions::CreateFile do
|
|
103
103
|
|
104
104
|
it "shows conflict status to ther user" do
|
105
105
|
create_file("doc/config.rb").must_not be_identical
|
106
|
-
|
106
|
+
$stdin.should_receive(:gets).and_return('s')
|
107
107
|
file = File.join(destination_root, 'doc/config.rb')
|
108
108
|
|
109
109
|
content = invoke!
|
@@ -114,21 +114,21 @@ describe Thor::Actions::CreateFile do
|
|
114
114
|
|
115
115
|
it "creates the file if the file collision menu returns true" do
|
116
116
|
create_file("doc/config.rb")
|
117
|
-
|
117
|
+
$stdin.should_receive(:gets).and_return('y')
|
118
118
|
invoke!.must =~ /force doc\/config\.rb/
|
119
119
|
end
|
120
120
|
|
121
121
|
it "skips the file if the file collision menu returns false" do
|
122
122
|
create_file("doc/config.rb")
|
123
|
-
|
123
|
+
$stdin.should_receive(:gets).and_return('n')
|
124
124
|
invoke!.must =~ /skip doc\/config\.rb/
|
125
125
|
end
|
126
126
|
|
127
127
|
it "executes the block given to show file content" do
|
128
128
|
create_file("doc/config.rb")
|
129
|
-
|
130
|
-
|
131
|
-
|
129
|
+
$stdin.should_receive(:gets).and_return('d')
|
130
|
+
$stdin.should_receive(:gets).and_return('n')
|
131
|
+
@base.shell.should_receive(:system).with(/diff -u/)
|
132
132
|
invoke!
|
133
133
|
end
|
134
134
|
end
|
@@ -29,23 +29,23 @@ describe Thor::Actions do
|
|
29
29
|
|
30
30
|
describe "#chmod" do
|
31
31
|
it "executes the command given" do
|
32
|
-
|
32
|
+
FileUtils.should_receive(:chmod_R).with(0755, file)
|
33
33
|
action :chmod, "foo", 0755
|
34
34
|
end
|
35
35
|
|
36
36
|
it "does not execute the command if pretending given" do
|
37
|
-
|
37
|
+
FileUtils.should_not_receive(:chmod_R)
|
38
38
|
runner(:pretend => true)
|
39
39
|
action :chmod, "foo", 0755
|
40
40
|
end
|
41
41
|
|
42
42
|
it "logs status" do
|
43
|
-
|
43
|
+
FileUtils.should_receive(:chmod_R).with(0755, file)
|
44
44
|
action(:chmod, "foo", 0755).must == " chmod foo\n"
|
45
45
|
end
|
46
46
|
|
47
47
|
it "does not log status if required" do
|
48
|
-
|
48
|
+
FileUtils.should_receive(:chmod_R).with(0755, file)
|
49
49
|
action(:chmod, "foo", 0755, :verbose => false).must be_empty
|
50
50
|
end
|
51
51
|
end
|
@@ -123,7 +123,7 @@ describe Thor::Actions do
|
|
123
123
|
end
|
124
124
|
|
125
125
|
it "converts enconded instructions" do
|
126
|
-
|
126
|
+
runner.should_receive(:file_name).and_return("rdoc")
|
127
127
|
action :template, "doc/%file_name%.rb.tt"
|
128
128
|
file = File.join(destination_root, "doc/rdoc.rb.tt")
|
129
129
|
File.exists?(file).must be_true
|
@@ -179,18 +179,18 @@ describe Thor::Actions do
|
|
179
179
|
describe "#gsub_file" do
|
180
180
|
it "replaces the content in the file" do
|
181
181
|
action :gsub_file, "doc/README", "__start__", "START"
|
182
|
-
File.
|
182
|
+
File.binread(file).must == "START\nREADME\n__end__\n"
|
183
183
|
end
|
184
184
|
|
185
185
|
it "does not replace if pretending" do
|
186
186
|
runner(:pretend => true)
|
187
187
|
action :gsub_file, "doc/README", "__start__", "START"
|
188
|
-
File.
|
188
|
+
File.binread(file).must == "__start__\nREADME\n__end__\n"
|
189
189
|
end
|
190
190
|
|
191
191
|
it "accepts a block" do
|
192
192
|
action(:gsub_file, "doc/README", "__start__"){ |match| match.gsub('__', '').upcase }
|
193
|
-
File.
|
193
|
+
File.binread(file).must == "START\nREADME\n__end__\n"
|
194
194
|
end
|
195
195
|
|
196
196
|
it "logs status" do
|
@@ -205,12 +205,12 @@ describe Thor::Actions do
|
|
205
205
|
describe "#append_file" do
|
206
206
|
it "appends content to the file" do
|
207
207
|
action :append_file, "doc/README", "END\n"
|
208
|
-
File.
|
208
|
+
File.binread(file).must == "__start__\nREADME\n__end__\nEND\n"
|
209
209
|
end
|
210
210
|
|
211
211
|
it "accepts a block" do
|
212
212
|
action(:append_file, "doc/README"){ "END\n" }
|
213
|
-
File.
|
213
|
+
File.binread(file).must == "__start__\nREADME\n__end__\nEND\n"
|
214
214
|
end
|
215
215
|
|
216
216
|
it "logs status" do
|
@@ -221,12 +221,12 @@ describe Thor::Actions do
|
|
221
221
|
describe "#prepend_file" do
|
222
222
|
it "prepends content to the file" do
|
223
223
|
action :prepend_file, "doc/README", "START\n"
|
224
|
-
File.
|
224
|
+
File.binread(file).must == "START\n__start__\nREADME\n__end__\n"
|
225
225
|
end
|
226
226
|
|
227
227
|
it "accepts a block" do
|
228
228
|
action(:prepend_file, "doc/README"){ "START\n" }
|
229
|
-
File.
|
229
|
+
File.binread(file).must == "START\n__start__\nREADME\n__end__\n"
|
230
230
|
end
|
231
231
|
|
232
232
|
it "logs status" do
|
@@ -241,12 +241,12 @@ describe Thor::Actions do
|
|
241
241
|
|
242
242
|
it "appends content to a class" do
|
243
243
|
action :inject_into_class, "application.rb", Application, " filter_parameters :password\n"
|
244
|
-
File.
|
244
|
+
File.binread(file).must == "class Application < Base\n filter_parameters :password\nend\n"
|
245
245
|
end
|
246
246
|
|
247
247
|
it "accepts a block" do
|
248
248
|
action(:inject_into_class, "application.rb", Application){ " filter_parameters :password\n" }
|
249
|
-
File.
|
249
|
+
File.binread(file).must == "class Application < Base\n filter_parameters :password\nend\n"
|
250
250
|
end
|
251
251
|
|
252
252
|
it "logs status" do
|
@@ -255,7 +255,7 @@ describe Thor::Actions do
|
|
255
255
|
|
256
256
|
it "does not append if class name does not match" do
|
257
257
|
action :inject_into_class, "application.rb", "App", " filter_parameters :password\n"
|
258
|
-
File.
|
258
|
+
File.binread(file).must == "class Application < Base\nend\n"
|
259
259
|
end
|
260
260
|
end
|
261
261
|
end
|
data/spec/actions_spec.rb
CHANGED
@@ -55,9 +55,10 @@ describe Thor::Actions do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
it "does not use the current directory if one is given" do
|
58
|
+
root = File.expand_path("/")
|
58
59
|
base = MyCounter.new([1])
|
59
|
-
base.destination_root =
|
60
|
-
base.destination_root.must ==
|
60
|
+
base.destination_root = root
|
61
|
+
base.destination_root.must == root
|
61
62
|
end
|
62
63
|
|
63
64
|
it "uses the current directory if none is given" do
|
@@ -194,7 +195,7 @@ describe Thor::Actions do
|
|
194
195
|
@template.instance_eval "def read; self; end" # Make the string respond to read
|
195
196
|
|
196
197
|
@file = "http://gist.github.com/103208.txt"
|
197
|
-
|
198
|
+
runner.should_receive(:open).and_return(@template)
|
198
199
|
end
|
199
200
|
|
200
201
|
it "opens a file and executes its content in the instance binding" do
|
@@ -219,7 +220,7 @@ describe Thor::Actions do
|
|
219
220
|
|
220
221
|
describe "#run" do
|
221
222
|
before(:each) do
|
222
|
-
|
223
|
+
runner.should_receive(:system).with("ls")
|
223
224
|
end
|
224
225
|
|
225
226
|
it "executes the command given" do
|
@@ -235,15 +236,15 @@ describe Thor::Actions do
|
|
235
236
|
end
|
236
237
|
|
237
238
|
it "accepts a color as status" do
|
238
|
-
|
239
|
+
runner.shell.should_receive(:say_status).with(:run, 'ls from "."', :yellow)
|
239
240
|
action :run, "ls", :verbose => :yellow
|
240
241
|
end
|
241
242
|
end
|
242
243
|
|
243
244
|
describe "#run_ruby_script" do
|
244
245
|
before(:each) do
|
245
|
-
|
246
|
-
|
246
|
+
Thor::Util.stub!(:ruby_command).and_return("/opt/jruby")
|
247
|
+
runner.should_receive(:system).with("/opt/jruby script.rb")
|
247
248
|
end
|
248
249
|
|
249
250
|
it "executes the ruby script" do
|
@@ -261,30 +262,30 @@ describe Thor::Actions do
|
|
261
262
|
|
262
263
|
describe "#thor" do
|
263
264
|
it "executes the thor command" do
|
264
|
-
|
265
|
+
runner.should_receive(:system).with("thor list")
|
265
266
|
action :thor, :list, :verbose => true
|
266
267
|
end
|
267
268
|
|
268
269
|
it "converts extra arguments to command arguments" do
|
269
|
-
|
270
|
+
runner.should_receive(:system).with("thor list foo bar")
|
270
271
|
action :thor, :list, "foo", "bar"
|
271
272
|
end
|
272
273
|
|
273
274
|
it "converts options hash to switches" do
|
274
|
-
|
275
|
+
runner.should_receive(:system).with("thor list foo bar --foo")
|
275
276
|
action :thor, :list, "foo", "bar", :foo => true
|
276
277
|
|
277
|
-
|
278
|
+
runner.should_receive(:system).with("thor list --foo 1 2 3")
|
278
279
|
action :thor, :list, :foo => [1,2,3]
|
279
280
|
end
|
280
281
|
|
281
282
|
it "logs status" do
|
282
|
-
|
283
|
+
runner.should_receive(:system).with("thor list")
|
283
284
|
action(:thor, :list).must == " run thor list from \".\"\n"
|
284
285
|
end
|
285
286
|
|
286
287
|
it "does not log status if required" do
|
287
|
-
|
288
|
+
runner.should_receive(:system).with("thor list --foo 1 2 3")
|
288
289
|
action(:thor, :list, :foo => [1,2,3], :verbose => false).must be_empty
|
289
290
|
end
|
290
291
|
end
|
data/spec/group_spec.rb
CHANGED
@@ -29,7 +29,7 @@ describe Thor::Group do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
it "invokes help message if any of the shortcuts is given" do
|
32
|
-
|
32
|
+
MyCounter.should_receive(:help)
|
33
33
|
MyCounter.start(["-h"])
|
34
34
|
end
|
35
35
|
end
|
@@ -66,12 +66,6 @@ describe Thor::Group do
|
|
66
66
|
@content.must =~ /Options/
|
67
67
|
@content.must =~ /\[\-\-third=THREE\]/
|
68
68
|
end
|
69
|
-
|
70
|
-
it "shows only usage if a short help is required" do
|
71
|
-
content = capture(:stdout){ MyCounter.help(Thor::Base.shell.new, :short => true) }
|
72
|
-
content.must =~ /my_counter N \[N\]/
|
73
|
-
content.must_not =~ /Options/
|
74
|
-
end
|
75
69
|
end
|
76
70
|
|
77
71
|
describe "#invoke" do
|
data/spec/runner_spec.rb
CHANGED
@@ -26,11 +26,11 @@ describe Thor::Runner do
|
|
26
26
|
|
27
27
|
it "shows information about a specific Thor group class" do
|
28
28
|
content = capture(:stdout){ Thor::Runner.start(["help", "my_counter"]) }
|
29
|
-
content.must =~ /my_counter N
|
29
|
+
content.must =~ /my_counter N/
|
30
30
|
end
|
31
31
|
|
32
32
|
it "raises error if a class/task cannot be found" do
|
33
|
-
|
33
|
+
Thor::Runner.should_receive(:exit).with(1)
|
34
34
|
content = capture(:stderr){ Thor::Runner.start(["help", "unknown"]) }
|
35
35
|
content.must =~ /could not find Thor class or task 'unknown'/
|
36
36
|
end
|
@@ -39,7 +39,7 @@ describe Thor::Runner do
|
|
39
39
|
describe "#start" do
|
40
40
|
it "invokes a task from Thor::Runner" do
|
41
41
|
ARGV.replace ["list"]
|
42
|
-
capture(:stdout){ Thor::Runner.start }.must =~ /my_counter N
|
42
|
+
capture(:stdout){ Thor::Runner.start }.must =~ /my_counter N/
|
43
43
|
end
|
44
44
|
|
45
45
|
it "invokes a task from a specific Thor class" do
|
@@ -68,7 +68,7 @@ describe Thor::Runner do
|
|
68
68
|
end
|
69
69
|
|
70
70
|
it "raises an error if class/task can't be found" do
|
71
|
-
|
71
|
+
Thor::Runner.should_receive(:exit).with(1)
|
72
72
|
ARGV.replace ["unknown"]
|
73
73
|
capture(:stderr){ Thor::Runner.start }.must =~ /could not find Thor class or task 'unknown'/
|
74
74
|
end
|
@@ -96,14 +96,16 @@ describe Thor::Runner do
|
|
96
96
|
"random" => {
|
97
97
|
:location => @location,
|
98
98
|
:filename => "4a33b894ffce85d7b412fc1b36f88fe0",
|
99
|
-
:
|
99
|
+
:namespaces => ["amazing"]
|
100
100
|
}
|
101
101
|
}
|
102
102
|
|
103
|
+
root_file = File.join(Thor::Util.thor_root, "thor.yml")
|
104
|
+
|
103
105
|
# Stub load and save to avoid thor.yaml from being overwritten
|
104
|
-
stub(
|
105
|
-
stub(
|
106
|
-
stub(
|
106
|
+
YAML.stub!(:load_file).and_return(@original_yaml)
|
107
|
+
File.stub!(:exists?).with(root_file).and_return(true)
|
108
|
+
File.stub!(:open).with(root_file, "w")
|
107
109
|
end
|
108
110
|
|
109
111
|
describe "list" do
|
@@ -115,7 +117,7 @@ describe Thor::Runner do
|
|
115
117
|
|
116
118
|
it "gives a list of the available Thor::Group classes" do
|
117
119
|
ARGV.replace ["list"]
|
118
|
-
capture(:stdout) { Thor::Runner.start }.must =~ /my_counter N
|
120
|
+
capture(:stdout) { Thor::Runner.start }.must =~ /my_counter N/
|
119
121
|
end
|
120
122
|
|
121
123
|
it "can filter a list of the available tasks by --group" do
|
@@ -148,26 +150,12 @@ describe Thor::Runner do
|
|
148
150
|
ARGV.replace [":test"]
|
149
151
|
capture(:stdout) { Thor::Runner.start }.must == "test\n"
|
150
152
|
end
|
151
|
-
|
152
|
-
it "updates the yaml file when invoked" do
|
153
|
-
capture(:stdout) { Thor::Runner.start(["list"]) }
|
154
|
-
@original_yaml["random"][:namespaces].must == ["amazing"]
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
describe "update" do
|
159
|
-
it "updates existing thor files" do
|
160
|
-
mock.instance_of(Thor::Runner).install(@original_yaml["random"][:location]) { true }
|
161
|
-
stub(File).delete(File.join(Thor::Util.thor_root, @original_yaml["random"][:filename]))
|
162
|
-
silence(:stdout) { Thor::Runner.start(["update", "random"]) }
|
163
|
-
end
|
164
153
|
end
|
165
154
|
|
166
155
|
describe "uninstall" do
|
167
156
|
before(:each) do
|
168
|
-
|
169
|
-
|
170
|
-
stub(@original_yaml).delete(anything)
|
157
|
+
path = File.join(Thor::Util.thor_root, @original_yaml["random"][:filename])
|
158
|
+
FileUtils.should_receive(:rm_rf).with(path)
|
171
159
|
end
|
172
160
|
|
173
161
|
it "uninstalls existing thor modules" do
|
@@ -177,7 +165,7 @@ describe Thor::Runner do
|
|
177
165
|
|
178
166
|
describe "installed" do
|
179
167
|
before(:each) do
|
180
|
-
|
168
|
+
Dir.should_receive(:[]).and_return([])
|
181
169
|
end
|
182
170
|
|
183
171
|
it "displays the modules installed in a pretty way" do
|
@@ -187,16 +175,24 @@ describe Thor::Runner do
|
|
187
175
|
end
|
188
176
|
end
|
189
177
|
|
190
|
-
describe "install" do
|
191
|
-
|
192
|
-
|
178
|
+
describe "install/update" do
|
179
|
+
before(:each) do
|
180
|
+
FileUtils.stub!(:mkdir_p)
|
181
|
+
FileUtils.stub!(:touch)
|
182
|
+
$stdin.stub!(:gets).and_return("Y")
|
193
183
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
stub(FileUtils).touch
|
184
|
+
path = File.join(Thor::Util.thor_root, Digest::MD5.hexdigest(@location + "random"))
|
185
|
+
File.should_receive(:open).with(path, "w")
|
186
|
+
end
|
198
187
|
|
199
|
-
|
188
|
+
it "updates existing thor files" do
|
189
|
+
path = File.join(Thor::Util.thor_root, @original_yaml["random"][:filename])
|
190
|
+
File.should_receive(:delete).with(path)
|
191
|
+
silence(:stdout) { Thor::Runner.start(["update", "random"]) }
|
192
|
+
end
|
193
|
+
|
194
|
+
it "installs thor files" do
|
195
|
+
ARGV.replace ["install", @location]
|
200
196
|
silence(:stdout) { Thor::Runner.start }
|
201
197
|
end
|
202
198
|
end
|