rake-pipeline 0.5.0 → 0.7.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.
Files changed (55) hide show
  1. data/.travis.yml +12 -0
  2. data/Gemfile +1 -0
  3. data/README.markdown +1 -1
  4. data/README.yard +61 -32
  5. data/Rakefile +9 -0
  6. data/bin/rakep +1 -24
  7. data/lib/generators/rake/pipeline/install/install_generator.rb +70 -0
  8. data/lib/rake-pipeline.rb +117 -53
  9. data/lib/rake-pipeline/cli.rb +56 -0
  10. data/lib/rake-pipeline/dsl.rb +3 -140
  11. data/lib/rake-pipeline/dsl/pipeline_dsl.rb +168 -0
  12. data/lib/rake-pipeline/dsl/project_dsl.rb +108 -0
  13. data/lib/rake-pipeline/dynamic_file_task.rb +188 -0
  14. data/lib/rake-pipeline/file_wrapper.rb +1 -1
  15. data/lib/rake-pipeline/filter.rb +45 -15
  16. data/lib/rake-pipeline/filters.rb +3 -1
  17. data/lib/rake-pipeline/filters/{concat.rb → concat_filter.rb} +0 -0
  18. data/lib/rake-pipeline/filters/ordering_concat_filter.rb +38 -0
  19. data/lib/rake-pipeline/filters/pipeline_finalizing_filter.rb +19 -0
  20. data/lib/rake-pipeline/graph.rb +178 -0
  21. data/lib/rake-pipeline/manifest.rb +63 -0
  22. data/lib/rake-pipeline/manifest_entry.rb +34 -0
  23. data/lib/rake-pipeline/matcher.rb +65 -30
  24. data/lib/rake-pipeline/middleware.rb +15 -12
  25. data/lib/rake-pipeline/precompile.rake +8 -0
  26. data/lib/rake-pipeline/project.rb +280 -0
  27. data/lib/rake-pipeline/railtie.rb +16 -1
  28. data/lib/rake-pipeline/server.rb +15 -0
  29. data/lib/rake-pipeline/version.rb +2 -2
  30. data/rake-pipeline.gemspec +2 -0
  31. data/spec/cli_spec.rb +71 -0
  32. data/spec/concat_filter_spec.rb +1 -27
  33. data/spec/{dsl_spec.rb → dsl/pipeline_dsl_spec.rb} +32 -18
  34. data/spec/dsl/project_dsl_spec.rb +41 -0
  35. data/spec/dynamic_file_task_spec.rb +111 -0
  36. data/spec/encoding_spec.rb +6 -8
  37. data/spec/file_wrapper_spec.rb +19 -2
  38. data/spec/filter_spec.rb +120 -22
  39. data/spec/graph_spec.rb +56 -0
  40. data/spec/manifest_entry_spec.rb +51 -0
  41. data/spec/manifest_spec.rb +67 -0
  42. data/spec/matcher_spec.rb +35 -2
  43. data/spec/middleware_spec.rb +123 -75
  44. data/spec/ordering_concat_filter_spec.rb +39 -0
  45. data/spec/pipeline_spec.rb +95 -34
  46. data/spec/project_spec.rb +293 -0
  47. data/spec/rake_acceptance_spec.rb +307 -67
  48. data/spec/rake_tasks_spec.rb +21 -0
  49. data/spec/spec_helper.rb +11 -48
  50. data/spec/support/spec_helpers/file_utils.rb +35 -0
  51. data/spec/support/spec_helpers/filters.rb +16 -0
  52. data/spec/support/spec_helpers/input_helpers.rb +23 -0
  53. data/spec/support/spec_helpers/memory_file_wrapper.rb +31 -0
  54. data/tools/perfs +107 -0
  55. metadata +100 -12
@@ -5,16 +5,6 @@ require "rack/test"
5
5
  describe "Rake::Pipeline Middleware" do
6
6
  include Rack::Test::Methods
7
7
 
8
- ConcatFilter = Rake::Pipeline::SpecHelpers::Filters::ConcatFilter
9
-
10
- class StripAssertsFilter < Rake::Pipeline::Filter
11
- def generate_output(inputs, output)
12
- inputs.each do |input|
13
- output.write input.read.gsub(%r{^\s*assert\(.*\)\s*;?\s*$}m, '')
14
- end
15
- end
16
- end
17
-
18
8
  inputs = {
19
9
  "app/javascripts/jquery.js" => "var jQuery = {};\n",
20
10
 
@@ -25,8 +15,8 @@ describe "Rake::Pipeline Middleware" do
25
15
  HERE
26
16
 
27
17
  "app/index.html" => "<html>HI</html>",
28
- "app/javascripts/index.html" => "<html>JAVASCRIPT</html>",
29
- "app/empty_dir" => nil
18
+ "app/javascripts/index.html" => "<html>JAVASCRIPT</html>",
19
+ "app/empty_dir" => nil
30
20
  }
31
21
 
32
22
  expected_output = <<-HERE.gsub(/^ {4}/, '')
@@ -36,114 +26,172 @@ describe "Rake::Pipeline Middleware" do
36
26
  SC.hi = function() { console.log("hi"); };
37
27
  HERE
38
28
 
39
- app = middleware = pipeline = nil
40
-
41
- before do
42
- app = lambda { |env| [404, {}, ['not found']] }
29
+ assetfile_source = <<-HERE.gsub(/^ {4}/, '')
30
+ require "#{tmp}/../support/spec_helpers/filters"
31
+ output "public"
43
32
 
44
- pipeline = Rake::Pipeline.build do
45
- input tmp, "app/**/*"
33
+ map "/dynamic-request.js" do
34
+ [200, { "Content-Type" => "text/plain" }, ["I am dynamic!"]]
35
+ end
46
36
 
37
+ input "#{tmp}", "app/**/*" do
47
38
  match "*.js" do
48
- filter(ConcatFilter) { "javascripts/application.js" }
49
- filter(StripAssertsFilter) { |input| input }
39
+ concat "javascripts/application.js"
40
+ filter(Rake::Pipeline::SpecHelpers::Filters::StripAssertsFilter) { |input| input }
50
41
  end
51
42
 
52
43
  # copy the rest
53
- filter(ConcatFilter) { |input| input.sub(/^app\//, '') }
54
-
55
- output "public"
44
+ concat { |input| input.sub(%r|^app/|, '') }
56
45
  end
46
+ HERE
57
47
 
58
- middleware = Rake::Pipeline::Middleware.new(app, pipeline)
48
+ modified_assetfile_source = <<-HERE.gsub(/^ {4}/, '')
49
+ require "#{tmp}/../support/spec_helpers/filters"
50
+ output "public"
59
51
 
60
- inputs.each do |name, string|
61
- path = File.join(tmp, name)
62
- if string
63
- mkdir_p File.dirname(path)
64
- File.open(path, "w") { |file| file.write(string) }
65
- else
66
- mkdir_p path
52
+ input "#{tmp}", "app/**/*" do
53
+ match "*.js" do
54
+ concat { "javascripts/app.js" }
55
+ filter(Rake::Pipeline::SpecHelpers::Filters::StripAssertsFilter) { |input| input }
67
56
  end
57
+
58
+ # copy the rest
59
+ concat { |input| input.sub(%r|^app/|, '') }
68
60
  end
61
+ HERE
69
62
 
70
- get "/javascripts/application.js"
71
- end
63
+ app = middleware = nil
72
64
 
73
65
  let(:app) { middleware }
74
66
 
75
- it "returns files relative to the output directory" do
76
- last_response.should be_ok
67
+ before do
68
+ assetfile_path = File.join(tmp, "Assetfile")
69
+ File.open(assetfile_path, "w") { |file| file.write(assetfile_source) }
77
70
 
78
- last_response.body.should == expected_output
79
- last_response.headers["Content-Type"].should == "application/javascript"
71
+ app = lambda { |env| [404, {}, ['not found']] }
72
+ middleware = Rake::Pipeline::Middleware.new(app, assetfile_path)
80
73
  end
81
74
 
82
- it "updates the output when files change" do
83
- age_existing_files
75
+ describe "dynamic requests" do
76
+ it "returns the value from the given block for paths that have been mapped" do
77
+ get "/dynamic-request.js"
84
78
 
85
- File.open(File.join(tmp, "app/javascripts/jquery.js"), "w") do |file|
86
- file.write "var jQuery = {};\njQuery.trim = function() {};\n"
79
+ last_response.should be_ok
80
+ last_response.headers["Content-Type"].should == "text/plain"
81
+ last_response.body.should == "I am dynamic!"
87
82
  end
83
+ end
84
+
85
+ describe "static requests" do
86
+ before do
87
+ inputs.each do |name, string|
88
+ path = File.join(tmp, name)
89
+ if string
90
+ mkdir_p File.dirname(path)
91
+ File.open(path, "w") { |file| file.write(string) }
92
+ else
93
+ mkdir_p path
94
+ end
95
+ end
96
+
97
+ get "/javascripts/application.js"
98
+ end
99
+
100
+ it "returns files relative to the output directory" do
101
+ last_response.should be_ok
102
+
103
+ last_response.body.should == expected_output
104
+ last_response.headers["Content-Type"].should == "application/javascript"
105
+ end
106
+
107
+ it "updates the output when files change" do
108
+ age_existing_files
88
109
 
89
- expected = <<-HERE.gsub(/^ {6}/, '')
110
+ File.open(File.join(tmp, "app/javascripts/jquery.js"), "w") do |file|
111
+ file.write "var jQuery = {};\njQuery.trim = function() {};\n"
112
+ end
113
+
114
+ expected = <<-HERE.gsub(/^ {6}/, '')
90
115
  var jQuery = {};
91
116
  jQuery.trim = function() {};
92
117
  var SC = {};
93
118
 
94
119
  SC.hi = function() { console.log("hi"); };
95
- HERE
120
+ HERE
96
121
 
97
- get "/javascripts/application.js"
122
+ get "/javascripts/application.js"
98
123
 
99
- last_response.body.should == expected
100
- last_response.headers["Content-Type"].should == "application/javascript"
101
- end
124
+ last_response.body.should == expected
125
+ last_response.headers["Content-Type"].should == "application/javascript"
126
+ end
102
127
 
103
- it "updates the output when new files are added" do
104
- age_existing_files
128
+ it "updates the output when new files are added" do
129
+ age_existing_files
105
130
 
106
- File.open(File.join(tmp, "app/javascripts/history.js"), "w") do |file|
107
- file.write "var History = {};\n"
108
- end
131
+ File.open(File.join(tmp, "app/javascripts/history.js"), "w") do |file|
132
+ file.write "var History = {};\n"
133
+ end
109
134
 
110
- expected = <<-HERE.gsub(/^ {6}/, '')
135
+ expected = <<-HERE.gsub(/^ {6}/, '')
111
136
  var History = {};
112
137
  var jQuery = {};
113
138
  var SC = {};
114
139
 
115
140
  SC.hi = function() { console.log("hi"); };
116
- HERE
141
+ HERE
117
142
 
118
- get "/javascripts/application.js"
143
+ get "/javascripts/application.js"
119
144
 
120
- last_response.body.should == expected
121
- last_response.headers["Content-Type"].should == "application/javascript"
122
- end
145
+ last_response.body.should == expected
146
+ last_response.headers["Content-Type"].should == "application/javascript"
147
+ end
123
148
 
124
- it "returns index.html for directories" do
125
- get "/"
149
+ it "returns index.html for directories" do
150
+ get "/"
126
151
 
127
- last_response.body.should == "<html>HI</html>"
128
- last_response.headers["Content-Type"].should == "text/html"
152
+ last_response.body.should == "<html>HI</html>"
153
+ last_response.headers["Content-Type"].should == "text/html"
129
154
 
130
- get "/javascripts"
155
+ get "/javascripts"
131
156
 
132
- last_response.body.should == "<html>JAVASCRIPT</html>"
133
- last_response.headers["Content-Type"].should == "text/html"
134
- end
157
+ last_response.body.should == "<html>JAVASCRIPT</html>"
158
+ last_response.headers["Content-Type"].should == "text/html"
159
+ end
135
160
 
136
- it "ignores directories without index.html" do
137
- get "/empty_dir"
161
+ it "ignores directories without index.html" do
162
+ get "/empty_dir"
138
163
 
139
- last_response.body.should == "not found"
140
- last_response.status.should == 404
141
- end
164
+ last_response.body.should == "not found"
165
+ last_response.status.should == 404
166
+ end
167
+
168
+ it "falls back to the app" do
169
+ get "/zomg.notfound"
170
+
171
+ last_response.body.should == "not found"
172
+ last_response.status.should == 404
173
+ end
142
174
 
143
- it "falls back to the app" do
144
- get "/zomg.notfound"
175
+ it "recreates the pipeline when the Assetfile changes" do
176
+ get "/javascripts/app.js"
177
+ last_response.body.should == "not found"
178
+ last_response.status.should == 404
145
179
 
146
- last_response.body.should == "not found"
147
- last_response.status.should == 404
180
+ File.open(File.join(tmp, "Assetfile"), "w") do |file|
181
+ file.write(modified_assetfile_source)
182
+ end
183
+
184
+ expected = <<-HERE.gsub(/^ {6}/, '')
185
+ var jQuery = {};
186
+ var SC = {};
187
+
188
+ SC.hi = function() { console.log("hi"); };
189
+ HERE
190
+
191
+ get "/javascripts/app.js"
192
+
193
+ last_response.body.should == expected
194
+ last_response.headers["Content-Type"].should == "application/javascript"
195
+ end
148
196
  end
149
197
  end
@@ -0,0 +1,39 @@
1
+ describe "OrderingConcatFilter" do
2
+ MemoryFileWrapper = Rake::Pipeline::SpecHelpers::MemoryFileWrapper
3
+
4
+ let(:input_files) {
5
+ [
6
+ MemoryFileWrapper.new("/path/to/input", "first.txt", "UTF-8", "FIRST"),
7
+ MemoryFileWrapper.new("/path/to/input", "second.txt", "UTF-8", "SECOND"),
8
+ MemoryFileWrapper.new("/path/to/input", "last.txt", "UTF-8", "LAST")
9
+ ]
10
+ }
11
+
12
+ let(:output_files) {
13
+ [
14
+ MemoryFileWrapper.new("/path/to/output", "all.txt", "BINARY")
15
+ ]
16
+ }
17
+
18
+ let(:output_file) {
19
+ MemoryFileWrapper.files["/path/to/output/all.txt"]
20
+ }
21
+
22
+ def make_filter(ordering)
23
+ filter = Rake::Pipeline::OrderingConcatFilter.new(ordering, "all.txt")
24
+ filter.file_wrapper_class = MemoryFileWrapper
25
+ filter.input_files = input_files
26
+ filter.output_root = "/path/to/output"
27
+ filter.rake_application = Rake::Application.new
28
+ filter.generate_rake_tasks.each(&:invoke)
29
+ filter
30
+ end
31
+
32
+ it "generates output" do
33
+ filter = make_filter(["first.txt", "second.txt"])
34
+
35
+ filter.output_files.should == output_files
36
+ output_file.body.should == "FIRSTSECONDLAST"
37
+ output_file.encoding.should == "BINARY"
38
+ end
39
+ end
@@ -5,17 +5,11 @@ describe "Rake::Pipeline" do
5
5
  let(:pipeline) { Rake::Pipeline.new }
6
6
 
7
7
  it "accepts a input root" do
8
- pipeline.input_root = "app/assets"
9
- pipeline.input_root.should == File.expand_path("app/assets")
8
+ pipeline.add_input "app/assets"
9
+ pipeline.inputs["app/assets"].should == '**/*'
10
10
  end
11
11
 
12
12
  it "raises an exception on #relative_input_files if input_files are not provided" do
13
- pipeline.input_root = "app/assets"
14
- lambda { pipeline.input_files }.should raise_error(Rake::Pipeline::Error)
15
- end
16
-
17
- it "raises an exception on #relative_input_files if input_root is not provided" do
18
- pipeline.input_glob = "app/assets/javascripts/**/*.js"
19
13
  lambda { pipeline.input_files }.should raise_error(Rake::Pipeline::Error)
20
14
  end
21
15
 
@@ -39,15 +33,73 @@ describe "Rake::Pipeline" do
39
33
  pipeline.rake_application.should == Rake.application
40
34
  end
41
35
 
42
- it "can have filters added to it" do
43
- filter = ConcatFilter.new
44
- pipeline.add_filter filter
36
+ describe ".build" do
37
+ it "evaluates a block against a new Pipeline" do
38
+ pipeline = Rake::Pipeline.build do
39
+ output "octopus"
40
+ end
41
+ pipeline.should be_kind_of(Rake::Pipeline)
42
+ pipeline.output_root.should == File.expand_path("octopus")
43
+ end
45
44
  end
46
45
 
47
- shared_examples_for "when working with input" do
48
- def input_file(path, root=File.join(tmp, "app/assets"))
49
- Rake::Pipeline::FileWrapper.new root, path
46
+ describe "#build" do
47
+ it "evaluates a block against an existing Pipeline" do
48
+ pipeline = Rake::Pipeline.new
49
+ pipeline.output_root = "octopus"
50
+
51
+ pipeline.build do
52
+ output "squid"
53
+ end
54
+ pipeline.output_root.should == File.expand_path("squid")
55
+ end
56
+ end
57
+
58
+ describe "the constructor" do
59
+ it "accepts an :inputs option" do
60
+ pipeline = Rake::Pipeline.new(:inputs => {"app/assets" => "**/*"})
61
+ pipeline.inputs.should == {"app/assets" => "**/*"}
62
+ end
63
+
64
+ it "accepts a :tmpdir option" do
65
+ pipeline = Rake::Pipeline.new(:tmpdir => "tmp")
66
+ pipeline.tmpdir.should == "tmp"
67
+ end
68
+
69
+ it "accepts an :output_root option" do
70
+ pipeline = Rake::Pipeline.new(:output_root => "public")
71
+ pipeline.output_root.should == File.expand_path("public")
72
+ end
73
+
74
+ it "accepts a :rake_application option" do
75
+ app = Rake::Application.new
76
+ pipeline = Rake::Pipeline.new(:rake_application => app)
77
+ pipeline.rake_application.should == app
78
+ end
79
+ end
80
+
81
+ describe "adding filters" do
82
+ let(:filter) { ConcatFilter.new }
83
+
84
+ it "can have filters added to it" do
85
+ pipeline.add_filter filter
86
+ end
87
+
88
+ it "sets an added filter's rake_application" do
89
+ app = Rake::Application.new
90
+ pipeline.rake_application = app
91
+ pipeline.add_filter filter
92
+ filter.rake_application.should == app
93
+ end
94
+
95
+ it "sets an added filter's pipeline" do
96
+ pipeline.add_filter filter
97
+ filter.pipeline.should == pipeline
50
98
  end
99
+ end
100
+
101
+ shared_examples_for "when working with input" do
102
+ include Rake::Pipeline::SpecHelpers::InputHelpers
51
103
 
52
104
  let(:files) do
53
105
  %w(javascripts/jquery.js javascripts/sproutcore.js).map do |filename|
@@ -55,18 +107,14 @@ describe "Rake::Pipeline" do
55
107
  end
56
108
  end
57
109
 
110
+ def setup_roots
111
+ pipeline.add_input "app/assets"
112
+ end
113
+
58
114
  before do
59
115
  Rake.application = Rake::Application.new
60
-
61
- files.each do |file|
62
- mkdir_p File.dirname(file.fullpath)
63
-
64
- File.open(file.fullpath, "w") do |file|
65
- file.write "// This is #{file.path}\n"
66
- end
67
- end
68
-
69
- pipeline.input_root = "app/assets"
116
+ create_files(files)
117
+ setup_roots
70
118
  setup_input(pipeline)
71
119
  pipeline.output_root = "public"
72
120
  end
@@ -111,8 +159,11 @@ describe "Rake::Pipeline" do
111
159
 
112
160
  deps = task.prerequisites
113
161
  deps.size.should == 2
114
- deps[0].should == File.join(pipeline.input_root, "javascripts/jquery.js")
115
- deps[1].should == File.join(pipeline.input_root, "javascripts/sproutcore.js")
162
+
163
+ root = File.expand_path(pipeline.inputs.keys.first)
164
+
165
+ deps[0].should == File.join(root, "javascripts/jquery.js")
166
+ deps[1].should == File.join(root, "javascripts/sproutcore.js")
116
167
 
117
168
  Rake.application.tasks.size.should == 3
118
169
  end
@@ -128,19 +179,29 @@ describe "Rake::Pipeline" do
128
179
  end
129
180
  end
130
181
 
131
- describe "using a glob for input files" do
182
+ describe "when using multiple input roots" do
132
183
  it_behaves_like "when working with input"
133
184
 
185
+ def setup_roots
186
+ pipeline.add_input File.join(tmp, 'tmp1', "app/assets"), '**/*.js'
187
+ pipeline.add_input File.join(tmp, 'tmp2', "app/assets"), '**/*.css'
188
+ end
189
+
134
190
  def setup_input(pipeline)
135
- pipeline.input_glob = "javascripts/**/*.js"
136
191
  end
137
- end
138
192
 
139
- describe "using a glob containing directories for input files" do
140
- it_behaves_like "when working with input"
193
+ let(:files) do
194
+ f = []
141
195
 
142
- def setup_input(pipeline)
143
- pipeline.input_glob = "**/*"
196
+ %w(javascripts/jquery.js javascripts/sproutcore.js).map do |filename|
197
+ f << input_file(filename, File.join(tmp, 'tmp1', "app/assets"))
198
+ end
199
+
200
+ %w(stylesheets/jquery.css stylesheets/sproutcore.css).map do |filename|
201
+ f << input_file(filename, File.join(tmp, 'tmp2', "app/assets"))
202
+ end
203
+
204
+ f
144
205
  end
145
206
  end
146
207
 
@@ -149,7 +210,7 @@ describe "Rake::Pipeline" do
149
210
 
150
211
  def setup_input(pipeline)
151
212
  Dir.chdir("app/assets") do
152
- files = Dir["javascripts/**/*.js"]
213
+ files = Dir["javascripts/**/*.js"].sort
153
214
  wrappers = files.map do |file|
154
215
  Rake::Pipeline::FileWrapper.new(File.join(tmp, "app/assets"), file)
155
216
  end