rake-pipeline-fork 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +12 -0
  5. data/.yardopts +2 -0
  6. data/GETTING_STARTED.md +268 -0
  7. data/Gemfile +14 -0
  8. data/LICENSE +20 -0
  9. data/README.markdown +11 -0
  10. data/README.yard +178 -0
  11. data/Rakefile +21 -0
  12. data/bin/rakep +4 -0
  13. data/examples/copying_files.md +12 -0
  14. data/examples/minifying_files.md +37 -0
  15. data/examples/modifying_pipelines.md +67 -0
  16. data/examples/multiple_pipelines.md +77 -0
  17. data/lib/generators/rake/pipeline/install/install_generator.rb +70 -0
  18. data/lib/rake-pipeline.rb +462 -0
  19. data/lib/rake-pipeline/cli.rb +56 -0
  20. data/lib/rake-pipeline/dsl.rb +9 -0
  21. data/lib/rake-pipeline/dsl/pipeline_dsl.rb +246 -0
  22. data/lib/rake-pipeline/dsl/project_dsl.rb +108 -0
  23. data/lib/rake-pipeline/dynamic_file_task.rb +194 -0
  24. data/lib/rake-pipeline/error.rb +17 -0
  25. data/lib/rake-pipeline/file_wrapper.rb +182 -0
  26. data/lib/rake-pipeline/filter.rb +249 -0
  27. data/lib/rake-pipeline/filters.rb +4 -0
  28. data/lib/rake-pipeline/filters/concat_filter.rb +63 -0
  29. data/lib/rake-pipeline/filters/gsub_filter.rb +56 -0
  30. data/lib/rake-pipeline/filters/ordering_concat_filter.rb +38 -0
  31. data/lib/rake-pipeline/filters/pipeline_finalizing_filter.rb +21 -0
  32. data/lib/rake-pipeline/graph.rb +178 -0
  33. data/lib/rake-pipeline/manifest.rb +86 -0
  34. data/lib/rake-pipeline/manifest_entry.rb +34 -0
  35. data/lib/rake-pipeline/matcher.rb +141 -0
  36. data/lib/rake-pipeline/middleware.rb +72 -0
  37. data/lib/rake-pipeline/precompile.rake +8 -0
  38. data/lib/rake-pipeline/project.rb +335 -0
  39. data/lib/rake-pipeline/rails_plugin.rb +10 -0
  40. data/lib/rake-pipeline/railtie.rb +34 -0
  41. data/lib/rake-pipeline/reject_matcher.rb +29 -0
  42. data/lib/rake-pipeline/server.rb +15 -0
  43. data/lib/rake-pipeline/sorted_pipeline.rb +19 -0
  44. data/lib/rake-pipeline/version.rb +6 -0
  45. data/rails/init.rb +2 -0
  46. data/rake-pipeline.gemspec +24 -0
  47. data/spec/cli_spec.rb +71 -0
  48. data/spec/concat_filter_spec.rb +37 -0
  49. data/spec/dsl/pipeline_dsl_spec.rb +165 -0
  50. data/spec/dsl/project_dsl_spec.rb +41 -0
  51. data/spec/dynamic_file_task_spec.rb +119 -0
  52. data/spec/encoding_spec.rb +106 -0
  53. data/spec/file_wrapper_spec.rb +132 -0
  54. data/spec/filter_spec.rb +332 -0
  55. data/spec/graph_spec.rb +56 -0
  56. data/spec/gsub_filter_spec.rb +87 -0
  57. data/spec/manifest_entry_spec.rb +46 -0
  58. data/spec/manifest_spec.rb +67 -0
  59. data/spec/matcher_spec.rb +141 -0
  60. data/spec/middleware_spec.rb +199 -0
  61. data/spec/ordering_concat_filter_spec.rb +42 -0
  62. data/spec/pipeline_spec.rb +232 -0
  63. data/spec/project_spec.rb +295 -0
  64. data/spec/rake_acceptance_spec.rb +738 -0
  65. data/spec/rake_tasks_spec.rb +21 -0
  66. data/spec/reject_matcher_spec.rb +31 -0
  67. data/spec/sorted_pipeline_spec.rb +27 -0
  68. data/spec/spec_helper.rb +38 -0
  69. data/spec/support/spec_helpers/file_utils.rb +35 -0
  70. data/spec/support/spec_helpers/filters.rb +37 -0
  71. data/spec/support/spec_helpers/input_helpers.rb +23 -0
  72. data/spec/support/spec_helpers/memory_file_wrapper.rb +31 -0
  73. data/spec/support/spec_helpers/memory_manifest.rb +19 -0
  74. data/tools/perfs +101 -0
  75. metadata +215 -0
@@ -0,0 +1,42 @@
1
+ describe "OrderingConcatFilter" do
2
+ MemoryFileWrapper ||= Rake::Pipeline::SpecHelpers::MemoryFileWrapper
3
+ MemoryManifest ||= Rake::Pipeline::SpecHelpers::MemoryManifest
4
+
5
+ let(:input_files) {
6
+ [
7
+ MemoryFileWrapper.new("/path/to/input", "first.txt", "UTF-8", "FIRST"),
8
+ MemoryFileWrapper.new("/path/to/input", "second.txt", "UTF-8", "SECOND"),
9
+ MemoryFileWrapper.new("/path/to/input", "last.txt", "UTF-8", "LAST")
10
+ ]
11
+ }
12
+
13
+ let(:output_files) {
14
+ [
15
+ MemoryFileWrapper.new("/path/to/output", "all.txt", "BINARY")
16
+ ]
17
+ }
18
+
19
+ let(:output_file) {
20
+ MemoryFileWrapper.files["/path/to/output/all.txt"]
21
+ }
22
+
23
+ def make_filter(ordering)
24
+ filter = Rake::Pipeline::OrderingConcatFilter.new(ordering, "all.txt")
25
+ filter.manifest = MemoryManifest.new
26
+ filter.last_manifest = MemoryManifest.new
27
+ filter.file_wrapper_class = MemoryFileWrapper
28
+ filter.input_files = input_files
29
+ filter.output_root = "/path/to/output"
30
+ filter.rake_application = Rake::Application.new
31
+ filter.generate_rake_tasks.each(&:invoke)
32
+ filter
33
+ end
34
+
35
+ it "generates output" do
36
+ filter = make_filter(["first.txt", "second.txt"])
37
+
38
+ filter.output_files.should == output_files
39
+ output_file.body.should == "FIRSTSECONDLAST"
40
+ output_file.encoding.should == "BINARY"
41
+ end
42
+ end
@@ -0,0 +1,232 @@
1
+ describe "Rake::Pipeline" do
2
+ ConcatFilter ||= Rake::Pipeline::SpecHelpers::Filters::ConcatFilter
3
+ StripAssertsFilter ||= Rake::Pipeline::SpecHelpers::Filters::StripAssertsFilter
4
+
5
+ let(:project) { Rake::Pipeline::Project.new }
6
+ let(:pipeline) { Rake::Pipeline.new :project => project }
7
+
8
+ it "accepts a input root" do
9
+ pipeline.add_input "app/assets"
10
+ pipeline.inputs["app/assets"].should == '**/*'
11
+ end
12
+
13
+ it "raises an exception on #relative_input_files if input_files are not provided" do
14
+ lambda { pipeline.input_files }.should raise_error(Rake::Pipeline::Error)
15
+ end
16
+
17
+ it "accepts a temporary directory" do
18
+ pipeline.tmpdir = "tmp"
19
+ pipeline.tmpdir.should == File.expand_path("tmp")
20
+ end
21
+
22
+ it "accepts an output directory" do
23
+ pipeline.output_root = "public"
24
+ pipeline.output_root.should == File.expand_path("public")
25
+ end
26
+
27
+ it "accepts a rake application" do
28
+ app = Rake::Application.new
29
+ pipeline.rake_application = app
30
+ pipeline.rake_application.should == app
31
+ end
32
+
33
+ it "defaults the rake application to Rake.application" do
34
+ pipeline.rake_application.should == Rake.application
35
+ end
36
+
37
+ describe ".build" do
38
+ it "evaluates a block against a new Pipeline" do
39
+ pipeline = Rake::Pipeline.build do
40
+ output "octopus"
41
+ end
42
+ pipeline.should be_kind_of(Rake::Pipeline)
43
+ pipeline.output_root.should == File.expand_path("octopus")
44
+ end
45
+ end
46
+
47
+ describe "#build" do
48
+ it "evaluates a block against an existing Pipeline" do
49
+ pipeline = Rake::Pipeline.new
50
+ pipeline.output_root = "octopus"
51
+
52
+ pipeline.build do
53
+ output "squid"
54
+ end
55
+ pipeline.output_root.should == File.expand_path("squid")
56
+ end
57
+ end
58
+
59
+ describe "the constructor" do
60
+ it "accepts an :inputs option" do
61
+ pipeline = Rake::Pipeline.new(:inputs => {"app/assets" => "**/*"})
62
+ pipeline.inputs.should == {"app/assets" => "**/*"}
63
+ end
64
+
65
+ it "accepts a :tmpdir option" do
66
+ pipeline = Rake::Pipeline.new(:tmpdir => "tmp")
67
+ pipeline.tmpdir.should == "tmp"
68
+ end
69
+
70
+ it "accepts an :output_root option" do
71
+ pipeline = Rake::Pipeline.new(:output_root => "public")
72
+ pipeline.output_root.should == File.expand_path("public")
73
+ end
74
+
75
+ it "accepts a :rake_application option" do
76
+ app = Rake::Application.new
77
+ pipeline = Rake::Pipeline.new(:rake_application => app)
78
+ pipeline.rake_application.should == app
79
+ end
80
+ end
81
+
82
+ describe "adding filters" do
83
+ let(:filter) { ConcatFilter.new }
84
+
85
+ it "can have filters added to it" do
86
+ pipeline.add_filter filter
87
+ end
88
+
89
+ it "sets an added filter's rake_application" do
90
+ app = Rake::Application.new
91
+ pipeline.rake_application = app
92
+ pipeline.add_filter filter
93
+ filter.rake_application.should == app
94
+ end
95
+
96
+ it "sets an added filter's pipeline" do
97
+ pipeline.add_filter filter
98
+ filter.pipeline.should == pipeline
99
+ end
100
+ end
101
+
102
+ describe "#copy" do
103
+ it "should copy state" do
104
+ copy = pipeline.copy
105
+ copy.inputs.should == pipeline.inputs
106
+ copy.tmpdir.should == pipeline.tmpdir
107
+ copy.rake_application.should == pipeline.rake_application
108
+ copy.project.should == pipeline.project
109
+ end
110
+ end
111
+
112
+ shared_examples_for "when working with input" do
113
+ include Rake::Pipeline::SpecHelpers::InputHelpers
114
+
115
+ let(:files) do
116
+ %w(javascripts/jquery.js javascripts/sproutcore.js).map do |filename|
117
+ input_file(filename)
118
+ end
119
+ end
120
+
121
+ def setup_roots
122
+ pipeline.add_input "app/assets"
123
+ end
124
+
125
+ before do
126
+ Rake.application = Rake::Application.new
127
+ create_files(files)
128
+ setup_roots
129
+ setup_input(pipeline)
130
+ pipeline.output_root = "public"
131
+ end
132
+
133
+ it "accepts a list of relative input files" do
134
+ pipeline.input_files.should == files
135
+ end
136
+
137
+ it "configures the filters with outputs and inputs with #rake_tasks" do
138
+ concat = ConcatFilter.new
139
+ concat.output_name_generator = proc { |input| "javascripts/application.js" }
140
+
141
+ strip_asserts = StripAssertsFilter.new
142
+ strip_asserts.output_name_generator = proc { |input| input }
143
+
144
+ pipeline.add_filters concat, strip_asserts
145
+ pipeline.setup
146
+
147
+ concat.input_files.should == pipeline.input_files
148
+ strip_asserts.input_files.each { |file| file.root.should == concat.output_root }
149
+
150
+ strip_asserts.input_files.should == [input_file("javascripts/application.js", concat.output_root)]
151
+ strip_asserts.output_root.should == File.expand_path(pipeline.output_root)
152
+ end
153
+
154
+ describe "generating rake tasks" do
155
+ tasks = nil
156
+
157
+ before do
158
+ concat = ConcatFilter.new
159
+ concat.output_name_generator = proc { |input| "javascripts/application.js" }
160
+ pipeline.add_filter concat
161
+ end
162
+
163
+ it "generates rake tasks in Rake.application" do
164
+ pipeline.setup
165
+ tasks = pipeline.rake_tasks
166
+
167
+ tasks.size.should == 1
168
+ task = tasks[0]
169
+ task.name.should == File.join(pipeline.output_root, "javascripts/application.js")
170
+
171
+ deps = task.prerequisites
172
+ deps.size.should == 2
173
+
174
+ root = File.expand_path(pipeline.inputs.keys.first)
175
+
176
+ deps[0].should == File.join(root, "javascripts/jquery.js")
177
+ deps[1].should == File.join(root, "javascripts/sproutcore.js")
178
+
179
+ Rake.application.tasks.size.should == 3
180
+ end
181
+
182
+ it "generates rake tasks is an alternate Rake::Application" do
183
+ app = Rake::Application.new
184
+ pipeline.rake_application = app
185
+ pipeline.setup
186
+ tasks = pipeline.rake_tasks
187
+
188
+ Rake.application.tasks.size.should == 0
189
+ end
190
+ end
191
+ end
192
+
193
+ describe "when using multiple input roots" do
194
+ it_behaves_like "when working with input"
195
+
196
+ def setup_roots
197
+ pipeline.add_input File.join(tmp, 'tmp1', "app/assets"), '**/*.js'
198
+ pipeline.add_input File.join(tmp, 'tmp2', "app/assets"), '**/*.css'
199
+ end
200
+
201
+ def setup_input(pipeline)
202
+ end
203
+
204
+ let(:files) do
205
+ f = []
206
+
207
+ %w(javascripts/jquery.js javascripts/sproutcore.js).map do |filename|
208
+ f << input_file(filename, File.join(tmp, 'tmp1', "app/assets"))
209
+ end
210
+
211
+ %w(stylesheets/jquery.css stylesheets/sproutcore.css).map do |filename|
212
+ f << input_file(filename, File.join(tmp, 'tmp2', "app/assets"))
213
+ end
214
+
215
+ f
216
+ end
217
+ end
218
+
219
+ describe "using an array for input files" do
220
+ it_behaves_like "when working with input"
221
+
222
+ def setup_input(pipeline)
223
+ Dir.chdir("app/assets") do
224
+ files = Dir["javascripts/**/*.js"].sort
225
+ wrappers = files.map do |file|
226
+ Rake::Pipeline::FileWrapper.new(File.join(tmp, "app/assets"), file)
227
+ end
228
+ pipeline.input_files = wrappers
229
+ end
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,295 @@
1
+ describe "Rake::Pipeline::Project" do
2
+ include Rake::Pipeline::SpecHelpers::InputHelpers
3
+
4
+ ASSETFILE_SOURCE = <<-HERE.gsub(/^ {4}/, '')
5
+ require "#{tmp}/../support/spec_helpers/filters"
6
+ tmpdir "tmp"
7
+ output "public"
8
+
9
+ input "app/assets" do
10
+ match "*.js" do
11
+ concat "javascripts/application.js"
12
+ filter Rake::Pipeline::SpecHelpers::Filters::StripAssertsFilter
13
+ end
14
+ end
15
+ HERE
16
+
17
+ MODIFIED_ASSETFILE_SOURCE = <<-HERE.gsub(/^ {4}/, '')
18
+ require "#{tmp}/../support/spec_helpers/filters"
19
+ tmpdir "tmp"
20
+ output "public"
21
+
22
+ input "app/assets" do
23
+ match "*.js" do
24
+ concat "javascripts/app.js"
25
+ filter Rake::Pipeline::SpecHelpers::Filters::StripAssertsFilter
26
+ end
27
+ end
28
+ HERE
29
+
30
+ BAD_ASSETFILE_SOURCE = <<-HERE.gsub(/^ {4}/, '')
31
+ require "#{tmp}/../support/spec_helpers/filters"
32
+ tmpdir "tmp"
33
+ output "public"
34
+
35
+ input "app/assets" do
36
+ method_not_in_dsl_on_line_6
37
+ end
38
+ HERE
39
+
40
+ let(:assetfile_path) { File.join(tmp, "Assetfile") }
41
+
42
+ def assetfile_digest
43
+ (Digest::SHA1.new << File.read(assetfile_path)).to_s
44
+ end
45
+
46
+ let(:unmatched_file) { input_file("junk.txt") }
47
+
48
+ let(:input_files) do
49
+ [input_file("jquery.js"), input_file("ember.js"), unmatched_file]
50
+ end
51
+
52
+ let(:output_files) do
53
+ [output_file("javascripts/application.js")]
54
+ end
55
+
56
+ let(:old_tmpdir) do
57
+ File.join(tmp, "tmp", "rake-pipeline-ad7a83894789")
58
+ end
59
+
60
+ let(:digested_tmpdir) do
61
+ File.join(tmp, "tmp", "rake-pipeline-#{assetfile_digest}")
62
+ end
63
+
64
+ attr_reader :project
65
+
66
+ before do
67
+ File.open(assetfile_path, 'w') { |file| file.write(ASSETFILE_SOURCE) }
68
+ create_files(input_files)
69
+ @project = Rake::Pipeline::Project.new(assetfile_path)
70
+ mkdir_p(old_tmpdir)
71
+ end
72
+
73
+ it "has an assetfile_path" do
74
+ project.assetfile_path.should == assetfile_path
75
+ end
76
+
77
+ it "has an assetfile_digest" do
78
+ project.assetfile_digest.should == assetfile_digest
79
+ end
80
+
81
+ it "has a pipeline" do
82
+ project.should have(1).pipelines
83
+ end
84
+
85
+ describe "constructor" do
86
+ it "creates pipelines from an Assetfile given an Assetfile path" do
87
+ project = Rake::Pipeline::Project.new(assetfile_path)
88
+ project.maps.should == {}
89
+ pipeline = project.pipelines.last
90
+ pipeline.inputs.should == { "app/assets" => "**/*" }
91
+ pipeline.output_root.should == File.join(tmp, "public")
92
+ end
93
+
94
+ it "wraps an existing pipeline" do
95
+ pipeline = Rake::Pipeline::Project.class_eval("build do\n#{File.read(assetfile_path)}\nend", assetfile_path, 1)
96
+ project = Rake::Pipeline::Project.new(pipeline)
97
+ project.pipelines.last.should == pipeline
98
+ end
99
+ end
100
+
101
+ describe "#invoke" do
102
+ def modify_assetfile
103
+ File.open(assetfile_path, 'w') do |file|
104
+ file.write(MODIFIED_ASSETFILE_SOURCE)
105
+ end
106
+ end
107
+
108
+ it "creates output files" do
109
+ output_files.each { |file| file.should_not exist }
110
+ project.invoke
111
+ output_files.each { |file| file.should exist }
112
+ end
113
+
114
+ it "writes temp files to a subdirectory of the tmp dir named after the assetfile digest" do
115
+ project.invoke
116
+ File.exist?(digested_tmpdir).should be_true
117
+ end
118
+
119
+ it "updates the manifest" do
120
+ project.last_manifest.should_receive(:read_manifest)
121
+ project.manifest.should_receive(:write_manifest)
122
+ project.invoke
123
+ end
124
+
125
+ it "rebuilds its pipeline when the Assetfile changes" do
126
+ project.invoke
127
+ original_pipeline = project.pipelines.last
128
+ original_assetfile_digest = assetfile_digest
129
+
130
+ modify_assetfile
131
+ project.invoke
132
+ assetfile_digest.should_not == original_assetfile_digest
133
+ project.pipelines.last.should_not == original_pipeline
134
+ end
135
+ end
136
+
137
+ describe "invalid Assetfile" do
138
+ before do
139
+ File.open(assetfile_path, 'w') { |file| file.write(BAD_ASSETFILE_SOURCE) }
140
+ end
141
+
142
+ it "should raise error with assetfile path on correct line number" do
143
+ lambda {
144
+ Rake::Pipeline::Project.new(assetfile_path)
145
+ }.should raise_error {|error| error.backtrace[0].should match(/Assetfile:6/) }
146
+ end
147
+ end
148
+
149
+ describe "#cleanup_tmpdir" do
150
+ it "cleans old rake-pipeline-* dirs out of the pipeline's tmp dir" do
151
+ File.exist?(old_tmpdir).should be_true
152
+ project.cleanup_tmpdir
153
+ File.exist?(old_tmpdir).should be_false
154
+ end
155
+
156
+ it "leaves the current assetfile-digest tmp dir alone" do
157
+ project.invoke
158
+ File.exist?(digested_tmpdir).should be_true
159
+ project.cleanup_tmpdir
160
+ File.exist?(digested_tmpdir).should be_true
161
+ end
162
+ end
163
+
164
+ describe "#clean" do
165
+ def rakep_tmpdirs
166
+ Dir["#{tmp}/tmp/rake-pipeline-*"]
167
+ end
168
+
169
+ it "cleans all rake-pipeline-* dirs out of the pipeline's tmp dir" do
170
+ project.invoke
171
+ rakep_tmpdirs.should_not be_empty
172
+ project.clean
173
+ rakep_tmpdirs.should be_empty
174
+ end
175
+
176
+ it "removes the pipeline's output files" do
177
+ project.invoke
178
+ output_files.each { |f| f.should exist }
179
+ project.clean
180
+ output_files.each { |f| f.should_not exist }
181
+ end
182
+
183
+ it "leaves the pipeline's unmatched input files alone" do
184
+ project.invoke
185
+ project.clean
186
+ unmatched_file.should exist
187
+ end
188
+ end
189
+
190
+ describe ".add_to_digest" do
191
+ after do
192
+ Rake::Pipeline::Project.digest_additions = []
193
+ end
194
+
195
+ it "appends a string to the generated tmp dir name" do
196
+ Rake::Pipeline::Project.add_to_digest("octopus")
197
+
198
+ File.basename(project.digested_tmpdir).should ==
199
+ "rake-pipeline-#{assetfile_digest}-octopus"
200
+ end
201
+
202
+ it "can be called multiple times" do
203
+ Rake::Pipeline::Project.add_to_digest("a")
204
+ Rake::Pipeline::Project.add_to_digest("b")
205
+
206
+ File.basename(project.digested_tmpdir).should ==
207
+ "rake-pipeline-#{assetfile_digest}-a-b"
208
+ end
209
+ end
210
+
211
+ describe "#build_pipeline" do
212
+ let(:inputs) { {"foo" => "**/*"} }
213
+
214
+ it "returns a pipeline" do
215
+ pipeline = project.build_pipeline(inputs) {}
216
+ pipeline.should be_kind_of(Rake::Pipeline)
217
+ end
218
+
219
+ it "adds the pipeline to the list of pipelines" do
220
+ pipeline = project.build_pipeline(inputs) {}
221
+ project.pipelines.last.should == pipeline
222
+ end
223
+
224
+ it "configures the pipeline with the pipeline DSL" do
225
+ pipeline = project.build_pipeline(inputs) do
226
+ output "bar"
227
+ end
228
+
229
+ pipeline.output_root.should == File.expand_path("bar")
230
+ end
231
+
232
+ it "sets the pipeline's tmpdir to a digest tmpdir" do
233
+ pipeline = project.build_pipeline(inputs) {}
234
+ pipeline.tmpdir.should == project.digested_tmpdir
235
+ end
236
+
237
+ it "sets the pipeline's output_root to the default_output_root" do
238
+ pipeline = project.build_pipeline(inputs) {}
239
+ pipeline.output_root.should == project.default_output_root
240
+ end
241
+
242
+ it "sets the pipeline's project to itself" do
243
+ pipeline = project.build_pipeline(inputs) {}
244
+ pipeline.project.should == project
245
+ end
246
+
247
+ it "creates a pipeline with a given set of inputs" do
248
+ pipeline = project.build_pipeline(inputs) {}
249
+ pipeline.inputs.should == inputs
250
+ end
251
+
252
+ it "can be called with a single path input" do
253
+ pipeline = project.build_pipeline("/path") {}
254
+ pipeline.inputs.should == {"/path" => "**/*"}
255
+ end
256
+
257
+ it "can be called with a path and a glob" do
258
+ pipeline = project.build_pipeline("/path", "*.js") {}
259
+ pipeline.inputs.should == {"/path" => "*.js"}
260
+ end
261
+
262
+ it "can be called with an array of paths" do
263
+ pipeline = project.build_pipeline(["path1", "path2"]) {}
264
+ pipeline.inputs.should have_key("path1")
265
+ pipeline.inputs.should have_key("path2")
266
+ end
267
+
268
+ it "can be called with a hash of path => glob pairs" do
269
+ pipeline = project.build_pipeline({"/path" => "*.css"}) {}
270
+ pipeline.inputs.should == {"/path" => "*.css"}
271
+ end
272
+ end
273
+
274
+ describe "#obsolete_tmpdirs" do
275
+ it "includes tmp directories that don't match the current digest" do
276
+ project.obsolete_tmpdirs.should include(old_tmpdir)
277
+ end
278
+ end
279
+
280
+ describe "#files_to_clean" do
281
+ it "includes a project's output files" do
282
+ output_files.each do |file|
283
+ project.files_to_clean.should include(file.fullpath)
284
+ end
285
+ end
286
+
287
+ it "includes a project's temporary directory" do
288
+ project.files_to_clean.should include(digested_tmpdir)
289
+ end
290
+
291
+ it "includes any old digest tmp dirs" do
292
+ project.files_to_clean.should include(old_tmpdir)
293
+ end
294
+ end
295
+ end