thor 0.9.9 → 0.11.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/CHANGELOG.rdoc +29 -4
  2. data/README.rdoc +234 -0
  3. data/Thorfile +57 -0
  4. data/VERSION +1 -0
  5. data/bin/rake2thor +4 -0
  6. data/bin/thor +1 -1
  7. data/lib/thor.rb +216 -119
  8. data/lib/thor/actions.rb +272 -0
  9. data/lib/thor/actions/create_file.rb +102 -0
  10. data/lib/thor/actions/directory.rb +87 -0
  11. data/lib/thor/actions/empty_directory.rb +133 -0
  12. data/lib/thor/actions/file_manipulation.rb +195 -0
  13. data/lib/thor/actions/inject_into_file.rb +78 -0
  14. data/lib/thor/base.rb +510 -0
  15. data/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  16. data/lib/thor/core_ext/ordered_hash.rb +100 -0
  17. data/lib/thor/error.rb +25 -1
  18. data/lib/thor/group.rb +263 -0
  19. data/lib/thor/invocation.rb +178 -0
  20. data/lib/thor/parser.rb +4 -0
  21. data/lib/thor/parser/argument.rb +67 -0
  22. data/lib/thor/parser/arguments.rb +145 -0
  23. data/lib/thor/parser/option.rb +132 -0
  24. data/lib/thor/parser/options.rb +142 -0
  25. data/lib/thor/rake_compat.rb +67 -0
  26. data/lib/thor/runner.rb +232 -242
  27. data/lib/thor/shell.rb +72 -0
  28. data/lib/thor/shell/basic.rb +220 -0
  29. data/lib/thor/shell/color.rb +108 -0
  30. data/lib/thor/task.rb +97 -60
  31. data/lib/thor/util.rb +230 -55
  32. data/spec/actions/create_file_spec.rb +170 -0
  33. data/spec/actions/directory_spec.rb +118 -0
  34. data/spec/actions/empty_directory_spec.rb +91 -0
  35. data/spec/actions/file_manipulation_spec.rb +242 -0
  36. data/spec/actions/inject_into_file_spec.rb +80 -0
  37. data/spec/actions_spec.rb +291 -0
  38. data/spec/base_spec.rb +236 -0
  39. data/spec/core_ext/hash_with_indifferent_access_spec.rb +43 -0
  40. data/spec/core_ext/ordered_hash_spec.rb +115 -0
  41. data/spec/fixtures/bundle/execute.rb +6 -0
  42. data/spec/fixtures/doc/config.rb +1 -0
  43. data/spec/group_spec.rb +177 -0
  44. data/spec/invocation_spec.rb +107 -0
  45. data/spec/parser/argument_spec.rb +47 -0
  46. data/spec/parser/arguments_spec.rb +64 -0
  47. data/spec/parser/option_spec.rb +212 -0
  48. data/spec/parser/options_spec.rb +255 -0
  49. data/spec/rake_compat_spec.rb +64 -0
  50. data/spec/runner_spec.rb +204 -0
  51. data/spec/shell/basic_spec.rb +206 -0
  52. data/spec/shell/color_spec.rb +41 -0
  53. data/spec/shell_spec.rb +25 -0
  54. data/spec/spec_helper.rb +52 -0
  55. data/spec/task_spec.rb +82 -0
  56. data/spec/thor_spec.rb +234 -0
  57. data/spec/util_spec.rb +196 -0
  58. metadata +69 -25
  59. data/README.markdown +0 -76
  60. data/Rakefile +0 -6
  61. data/lib/thor/options.rb +0 -242
  62. data/lib/thor/ordered_hash.rb +0 -64
  63. data/lib/thor/task_hash.rb +0 -22
  64. data/lib/thor/tasks.rb +0 -77
  65. data/lib/thor/tasks/package.rb +0 -18
@@ -0,0 +1,118 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'thor/actions'
3
+
4
+ describe Thor::Actions::Directory do
5
+ before(:each) do
6
+ ::FileUtils.rm_rf(destination_root)
7
+ stub(invoker).file_name{ "rdoc" }
8
+ end
9
+
10
+ def invoker
11
+ @invoker ||= WhinyGenerator.new([1,2], {}, { :destination_root => destination_root })
12
+ end
13
+
14
+ def revoker
15
+ @revoker ||= WhinyGenerator.new([1,2], {}, { :destination_root => destination_root, :behavior => :revoke })
16
+ end
17
+
18
+ def invoke!(*args, &block)
19
+ capture(:stdout){ invoker.directory(*args, &block) }
20
+ end
21
+
22
+ def revoke!(*args, &block)
23
+ capture(:stdout){ revoker.directory(*args, &block) }
24
+ end
25
+
26
+ def exists_and_identical?(source_path, destination_path)
27
+ %w(config.rb README).each do |file|
28
+ source = File.join(source_root, source_path, file)
29
+ destination = File.join(destination_root, destination_path, file)
30
+
31
+ File.exists?(destination).must be_true
32
+ FileUtils.identical?(source, destination).must be_true
33
+ end
34
+ end
35
+
36
+ describe "#invoke!" do
37
+ it "raises an error if the source does not exist" do
38
+ lambda {
39
+ invoke! "unknown"
40
+ }.must raise_error(Thor::Error, /Could not find "unknown" in source paths/)
41
+ end
42
+
43
+ it "copies the whole directory recursively to the default destination" do
44
+ invoke! "doc"
45
+ exists_and_identical?("doc", "doc")
46
+ end
47
+
48
+ it "copies the whole directory recursively to the specified destination" do
49
+ invoke! "doc", "docs"
50
+ exists_and_identical?("doc", "docs")
51
+ end
52
+
53
+ it "copies only the first level files if recursive" do
54
+ invoke! ".", "tasks", :recursive => false
55
+
56
+ file = File.join(destination_root, "tasks", "group.thor")
57
+ File.exists?(file).must be_true
58
+
59
+ file = File.join(destination_root, "tasks", "doc")
60
+ File.exists?(file).must be_false
61
+
62
+ file = File.join(destination_root, "tasks", "doc", "README")
63
+ File.exists?(file).must be_false
64
+ end
65
+
66
+ it "copies files from the source relative to the current path" do
67
+ invoker.inside "doc" do
68
+ invoke! "."
69
+ end
70
+ exists_and_identical?("doc", "doc")
71
+ end
72
+
73
+ it "copies and evaluates templates" do
74
+ invoke! "doc", "docs"
75
+ file = File.join(destination_root, "docs", "rdoc.rb")
76
+ File.exists?(file).must be_true
77
+ File.read(file).must == "FOO = FOO\n"
78
+ end
79
+
80
+ it "copies directories" do
81
+ invoke! "doc", "docs"
82
+ file = File.join(destination_root, "docs", "components")
83
+ File.exists?(file).must be_true
84
+ File.directory?(file).must be_true
85
+ end
86
+
87
+ it "does not copy .empty_diretories files" do
88
+ invoke! "doc", "docs"
89
+ file = File.join(destination_root, "docs", "components", ".empty_directory")
90
+ File.exists?(file).must be_false
91
+ end
92
+
93
+ it "copies directories even if they are empty" do
94
+ invoke! "doc/components", "docs/components"
95
+ file = File.join(destination_root, "docs", "components")
96
+ File.exists?(file).must be_true
97
+ end
98
+
99
+ it "logs status" do
100
+ content = invoke!("doc")
101
+ content.must =~ /create doc\/README/
102
+ content.must =~ /create doc\/config\.rb/
103
+ content.must =~ /create doc\/rdoc\.rb/
104
+ content.must =~ /create doc\/components/
105
+ end
106
+ end
107
+
108
+ describe "#revoke!" do
109
+ it "removes the destination file" do
110
+ invoke! "doc"
111
+ revoke! "doc"
112
+
113
+ File.exists?(File.join(destination_root, "doc", "README")).must be_false
114
+ File.exists?(File.join(destination_root, "doc", "config.rb")).must be_false
115
+ File.exists?(File.join(destination_root, "doc", "components")).must be_false
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,91 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'thor/actions'
3
+
4
+ describe Thor::Actions::EmptyDirectory do
5
+ before(:each) do
6
+ ::FileUtils.rm_rf(destination_root)
7
+ end
8
+
9
+ def empty_directory(destination, options={})
10
+ @action = Thor::Actions::EmptyDirectory.new(base, destination)
11
+ end
12
+
13
+ def invoke!
14
+ capture(:stdout){ @action.invoke! }
15
+ end
16
+
17
+ def revoke!
18
+ capture(:stdout){ @action.revoke! }
19
+ end
20
+
21
+ def base
22
+ @base ||= MyCounter.new([1,2], options, { :destination_root => destination_root })
23
+ end
24
+
25
+ describe "#destination" do
26
+ it "returns the full destination with the destination_root" do
27
+ empty_directory('doc').destination.must == File.join(destination_root, 'doc')
28
+ end
29
+
30
+ it "takes relative root into account" do
31
+ base.inside('doc') do
32
+ empty_directory('contents').destination.must == File.join(destination_root, 'doc', 'contents')
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "#relative_destination" do
38
+ it "returns the relative destination to the original destination root" do
39
+ base.inside('doc') do
40
+ empty_directory('contents').relative_destination.must == 'doc/contents'
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "#given_destination" do
46
+ it "returns the destination supplied by the user" do
47
+ base.inside('doc') do
48
+ empty_directory('contents').given_destination.must == 'contents'
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#invoke!" do
54
+ it "copies the file to the specified destination" do
55
+ empty_directory("doc")
56
+ invoke!
57
+ File.exists?(File.join(destination_root, "doc")).must be_true
58
+ end
59
+
60
+ it "shows created status to the user" do
61
+ empty_directory("doc")
62
+ invoke!.must == " create doc\n"
63
+ end
64
+
65
+ describe "when directory exists" do
66
+ it "shows exist status" do
67
+ empty_directory("doc")
68
+ invoke!
69
+ invoke!.must == " exist doc\n"
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "#revoke!" do
75
+ it "removes the destination file" do
76
+ empty_directory("doc")
77
+ invoke!
78
+ revoke!
79
+ File.exists?(@action.destination).must be_false
80
+ end
81
+ end
82
+
83
+ describe "#exists?" do
84
+ it "returns true if the destination file exists" do
85
+ empty_directory("doc")
86
+ @action.exists?.must be_false
87
+ invoke!
88
+ @action.exists?.must be_true
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,242 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Thor::Actions do
4
+ def runner(options={})
5
+ @runner ||= MyCounter.new([1], options, { :destination_root => destination_root })
6
+ end
7
+
8
+ def action(*args, &block)
9
+ capture(:stdout){ runner.send(*args, &block) }
10
+ end
11
+
12
+ def exists_and_identical?(source, destination)
13
+ destination = File.join(destination_root, destination)
14
+ File.exists?(destination).must be_true
15
+
16
+ source = File.join(source_root, source)
17
+ FileUtils.must be_identical(source, destination)
18
+ end
19
+
20
+ def file
21
+ File.join(destination_root, "foo")
22
+ end
23
+
24
+ before(:each) do
25
+ ::FileUtils.rm_rf(destination_root)
26
+ end
27
+
28
+ describe "#chmod" do
29
+ it "executes the command given" do
30
+ mock(FileUtils).chmod_R(0755, file)
31
+ action :chmod, "foo", 0755
32
+ end
33
+
34
+ it "does not execute the command if pretending given" do
35
+ dont_allow(FileUtils).chmod_R(0755, file)
36
+ runner(:pretend => true)
37
+ action :chmod, "foo", 0755
38
+ end
39
+
40
+ it "logs status" do
41
+ mock(FileUtils).chmod_R(0755, file)
42
+ action(:chmod, "foo", 0755).must == " chmod foo\n"
43
+ end
44
+
45
+ it "does not log status if required" do
46
+ mock(FileUtils).chmod_R(0755, file)
47
+ action(:chmod, "foo", 0755, :verbose => false).must be_empty
48
+ end
49
+ end
50
+
51
+ describe "#copy_file" do
52
+ it "copies file from source to default destination" do
53
+ action :copy_file, "task.thor"
54
+ exists_and_identical?("task.thor", "task.thor")
55
+ end
56
+
57
+ it "copies file from source to the specified destination" do
58
+ action :copy_file, "task.thor", "foo.thor"
59
+ exists_and_identical?("task.thor", "foo.thor")
60
+ end
61
+
62
+ it "copies file from the source relative to the current path" do
63
+ runner.inside("doc") do
64
+ action :copy_file, "README"
65
+ end
66
+
67
+ exists_and_identical?("doc/README", "doc/README")
68
+ end
69
+
70
+ it "logs status" do
71
+ action(:copy_file, "task.thor").must == " create task.thor\n"
72
+ end
73
+ end
74
+
75
+ describe "#get" do
76
+ it "copies file from source to the specified destination" do
77
+ action :get, "doc/README", "docs/README"
78
+ exists_and_identical?("doc/README", "docs/README")
79
+ end
80
+
81
+ it "uses just the source basename as destination if none is specified" do
82
+ action :get, "doc/README"
83
+ exists_and_identical?("doc/README", "README")
84
+ end
85
+
86
+ it "allows the destination to be set as a block result" do
87
+ action(:get, "doc/README"){ |c| "docs/README" }
88
+ exists_and_identical?("doc/README", "docs/README")
89
+ end
90
+
91
+ it "yields file content to a block" do
92
+ action :get, "doc/README" do |content|
93
+ content.must == "__start__\nREADME\n__end__\n"
94
+ end
95
+ end
96
+
97
+ it "logs status" do
98
+ action(:get, "doc/README", "docs/README").must == " create docs/README\n"
99
+ end
100
+ end
101
+
102
+ describe "#template" do
103
+ it "evaluates the template given as source" do
104
+ runner.instance_variable_set("@klass", "Config")
105
+ action :template, "doc/config.rb"
106
+
107
+ file = File.join(destination_root, "doc/config.rb")
108
+ File.read(file).must == "class Config; end\n"
109
+ end
110
+
111
+ it "copies the template to the specified destination" do
112
+ action :template, "doc/config.rb", "doc/configuration.rb"
113
+ file = File.join(destination_root, "doc/configuration.rb")
114
+ File.exists?(file).must be_true
115
+ end
116
+
117
+ it "converts enconded instructions" do
118
+ mock(runner).file_name{ "rdoc" }
119
+ action :template, "doc/%file_name%.rb.tt"
120
+ file = File.join(destination_root, "doc/rdoc.rb.tt")
121
+ File.exists?(file).must be_true
122
+ end
123
+
124
+ it "logs status" do
125
+ capture(:stdout){ runner.template("doc/config.rb") }.must == " create doc/config.rb\n"
126
+ end
127
+ end
128
+
129
+ describe "when changing existent files" do
130
+ before(:each) do
131
+ ::FileUtils.cp_r(source_root, destination_root)
132
+ end
133
+
134
+ def file
135
+ File.join(destination_root, "doc", "README")
136
+ end
137
+
138
+ describe "#remove_file" do
139
+ it "removes the file given" do
140
+ action :remove_file, "doc/README"
141
+ File.exists?(file).must be_false
142
+ end
143
+
144
+ it "removes directories too" do
145
+ action :remove_dir, "doc"
146
+ File.exists?(File.join(destination_root, "doc")).must be_false
147
+ end
148
+
149
+ it "does not remove if pretending" do
150
+ runner(:pretend => true)
151
+ action :remove_file, "doc/README"
152
+ File.exists?(file).must be_true
153
+ end
154
+
155
+ it "logs status" do
156
+ action(:remove_file, "doc/README").must == " remove doc/README\n"
157
+ end
158
+
159
+ it "does not log status if required" do
160
+ action(:remove_file, "doc/README", :verbose => false).must be_empty
161
+ end
162
+ end
163
+
164
+ describe "#gsub_file" do
165
+ it "replaces the content in the file" do
166
+ action :gsub_file, "doc/README", "__start__", "START"
167
+ File.open(file).read.must == "START\nREADME\n__end__\n"
168
+ end
169
+
170
+ it "does not replace if pretending" do
171
+ runner(:pretend => true)
172
+ action :gsub_file, "doc/README", "__start__", "START"
173
+ File.open(file).read.must == "__start__\nREADME\n__end__\n"
174
+ end
175
+
176
+ it "accepts a block" do
177
+ action(:gsub_file, "doc/README", "__start__"){ |match| match.gsub('__', '').upcase }
178
+ File.open(file).read.must == "START\nREADME\n__end__\n"
179
+ end
180
+
181
+ it "logs status" do
182
+ action(:gsub_file, "doc/README", "__start__", "START").must == " gsub doc/README\n"
183
+ end
184
+
185
+ it "does not log status if required" do
186
+ action(:gsub_file, file, "__", :verbose => false){ |match| match * 2 }.must be_empty
187
+ end
188
+ end
189
+
190
+ describe "#append_file" do
191
+ it "appends content to the file" do
192
+ action :append_file, "doc/README", "END\n"
193
+ File.open(file).read.must == "__start__\nREADME\n__end__\nEND\n"
194
+ end
195
+
196
+ it "does not append if pretending" do
197
+ runner(:pretend => true)
198
+ action :append_file, "doc/README", "END\n"
199
+ File.open(file).read.must == "__start__\nREADME\n__end__\n"
200
+ end
201
+
202
+ it "accepts a block" do
203
+ action(:append_file, "doc/README"){ "END\n" }
204
+ File.open(file).read.must == "__start__\nREADME\n__end__\nEND\n"
205
+ end
206
+
207
+ it "logs status" do
208
+ action(:append_file, "doc/README", "END").must == " append doc/README\n"
209
+ end
210
+
211
+ it "does not log status if required" do
212
+ action(:append_file, "doc/README", nil, :verbose => false){ "END" }.must be_empty
213
+ end
214
+ end
215
+
216
+ describe "#prepend_file" do
217
+ it "prepends content to the file" do
218
+ action :prepend_file, "doc/README", "START\n"
219
+ File.open(file).read.must == "START\n__start__\nREADME\n__end__\n"
220
+ end
221
+
222
+ it "does not prepend if pretending" do
223
+ runner(:pretend => true)
224
+ action :prepend_file, "doc/README", "START\n"
225
+ File.open(file).read.must == "__start__\nREADME\n__end__\n"
226
+ end
227
+
228
+ it "accepts a block" do
229
+ action(:prepend_file, "doc/README"){ "START\n" }
230
+ File.open(file).read.must == "START\n__start__\nREADME\n__end__\n"
231
+ end
232
+
233
+ it "logs status" do
234
+ action(:prepend_file, "doc/README", "START").must == " prepend doc/README\n"
235
+ end
236
+
237
+ it "does not log status if required" do
238
+ action(:prepend_file, "doc/README", "START", :verbose => false).must be_empty
239
+ end
240
+ end
241
+ end
242
+ end