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
@@ -2,14 +2,29 @@ require "rake-pipeline/middleware"
2
2
 
3
3
  module Rake
4
4
  class Pipeline
5
+ # Use Rake::Pipeline inside of Rails 3.x. To use, simply add
6
+ # Rake::Pipeline to your +Gemfile+:
7
+ #
8
+ # !!!ruby
9
+ # gem 'rake-pipeline'
10
+ #
11
+ # Then, activate it in development mode. In config/development.rb:
12
+ #
13
+ # !!!ruby
14
+ # config.rake_pipeline_enabled = true
15
+ #
5
16
  class Railtie < ::Rails::Railtie
6
17
  config.rake_pipeline_enabled = false
7
18
  config.rake_pipeline_assetfile = 'Assetfile'
8
19
 
20
+ rake_tasks do
21
+ load "rake-pipeline/precompile.rake"
22
+ end
23
+
9
24
  initializer "rake-pipeline.assetfile" do |app|
10
25
  if config.rake_pipeline_enabled
11
26
  assetfile = File.join(Rails.root, config.rake_pipeline_assetfile)
12
- config.app_middleware.use(Rake::Pipeline::Middleware, assetfile)
27
+ config.app_middleware.insert ActionDispatch::Static, Rake::Pipeline::Middleware, assetfile
13
28
  end
14
29
  end
15
30
  end
@@ -0,0 +1,15 @@
1
+ require "rake-pipeline/middleware"
2
+ require "rack/server"
3
+
4
+ module Rake
5
+ class Pipeline
6
+ class Server < Rack::Server
7
+ def app
8
+ not_found = proc { [404, { "Content-Type" => "text/plain" }, ["not found"]] }
9
+ config = "Assetfile"
10
+
11
+ Middleware.new(not_found, config)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,6 +1,6 @@
1
1
  module Rake
2
2
  class Pipeline
3
- # @version 0.5.0
4
- VERSION = "0.5.0"
3
+ # @version 0.7.0
4
+ VERSION = "0.7.0"
5
5
  end
6
6
  end
@@ -16,6 +16,8 @@ Gem::Specification.new do |gem|
16
16
  gem.version = Rake::Pipeline::VERSION
17
17
 
18
18
  gem.add_dependency "rake", "~> 0.9.0"
19
+ gem.add_dependency "thor"
20
+ gem.add_dependency "json"
19
21
 
20
22
  gem.add_development_dependency "rspec"
21
23
  gem.add_development_dependency "rack-test"
@@ -0,0 +1,71 @@
1
+ describe "Rake::Pipeline::CLI" do
2
+ attr_reader :project, :pipeline
3
+
4
+ before do
5
+ @project = Rake::Pipeline::Project.new
6
+ @project.stub(:clean)
7
+ @project.stub(:invoke)
8
+ @project.stub(:output_files).and_return([])
9
+ Rake::Pipeline::Project.stub(:new).and_return(@project)
10
+ end
11
+
12
+ def rakep(*args)
13
+ Rake::Pipeline::CLI.start(args)
14
+ end
15
+
16
+ describe "build" do
17
+ context "with no arguments" do
18
+ it "invokes a project" do
19
+ project.should_receive :invoke
20
+ rakep "build"
21
+ end
22
+
23
+ it "cleans up the tmpdir" do
24
+ project.should_receive :cleanup_tmpdir
25
+ rakep "build"
26
+ end
27
+ end
28
+
29
+ context "with a --pretend argument" do
30
+ it "doesn't invoke a project" do
31
+ project.should_not_receive :invoke
32
+ rakep "build", "--pretend"
33
+ end
34
+ end
35
+
36
+ context "with a --clean argument" do
37
+ it "cleans a project" do
38
+ project.should_receive :clean
39
+ rakep "build", "--clean"
40
+ end
41
+
42
+ it "invokes a project" do
43
+ project.should_receive :invoke
44
+ rakep "build", "--clean"
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "clean" do
50
+ context "with no arguments" do
51
+ it "cleans a project" do
52
+ project.should_receive :clean
53
+ rakep "clean"
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "server" do
59
+ let(:server) { double "server" }
60
+
61
+ before do
62
+ require 'rake-pipeline/server'
63
+ Rake::Pipeline::Server.stub(:new).and_return(server)
64
+ end
65
+
66
+ it "starts a Rake::Pipeline::Server" do
67
+ server.should_receive :start
68
+ rakep "server"
69
+ end
70
+ end
71
+ end
@@ -1,31 +1,5 @@
1
1
  describe "ConcatFilter" do
2
- class MemoryFileWrapper < Struct.new(:root, :path, :encoding, :body)
3
- @@files = {}
4
-
5
- def self.files
6
- @@files
7
- end
8
-
9
- def with_encoding(new_encoding)
10
- self.class.new(root, path, new_encoding, body)
11
- end
12
-
13
- def fullpath
14
- File.join(root, path)
15
- end
16
-
17
- def create
18
- @@files[fullpath] = self
19
- self.body = ""
20
- yield
21
- end
22
-
23
- alias read body
24
-
25
- def write(contents)
26
- self.body << contents
27
- end
28
- end
2
+ MemoryFileWrapper = Rake::Pipeline::SpecHelpers::MemoryFileWrapper
29
3
 
30
4
  let(:input_files) {
31
5
  [
@@ -1,11 +1,11 @@
1
- describe "Rake::Pipeline::DSL" do
1
+ describe "Rake::Pipeline::PipelineDSL" do
2
2
  ConcatFilter = Rake::Pipeline::SpecHelpers::Filters::ConcatFilter
3
3
 
4
4
  let(:pipeline) { Rake::Pipeline.new }
5
- let(:dsl) { Rake::Pipeline::DSL.new(pipeline) }
5
+ let(:dsl) { Rake::Pipeline::DSL::PipelineDSL.new(pipeline) }
6
6
 
7
- before do
8
- pipeline.input_root = "."
7
+ def filter
8
+ pipeline.filters.last
9
9
  end
10
10
 
11
11
  it "accepts a pipeline in its constructor" do
@@ -13,19 +13,19 @@ describe "Rake::Pipeline::DSL" do
13
13
  end
14
14
 
15
15
  describe "#input" do
16
- it "configures the pipeline's input_root" do
16
+ it "adds an input to the pipeline" do
17
17
  dsl.input "/app"
18
- pipeline.input_root.should == "/app"
18
+ pipeline.inputs["/app"].should == '**/*'
19
19
  end
20
20
 
21
- it "configures the pipeline's input_glob" do
21
+ it "configures the input's glob" do
22
22
  dsl.input "/app", "*.js"
23
- pipeline.input_glob.should == "*.js"
23
+ pipeline.inputs['/app'].should == "*.js"
24
24
  end
25
25
 
26
- it "defaults the pipeline's input_glob to **/*" do
26
+ it "defaults input's glob to **/*" do
27
27
  dsl.input "/app"
28
- pipeline.input_glob.should == "**/*"
28
+ pipeline.inputs['/app'].should == "**/*"
29
29
  end
30
30
  end
31
31
 
@@ -35,13 +35,13 @@ describe "Rake::Pipeline::DSL" do
35
35
  pipeline.filters.should be_empty
36
36
  dsl.filter ConcatFilter
37
37
  pipeline.filters.should_not be_empty
38
- pipeline.filters.last.should be_kind_of(ConcatFilter)
38
+ filter.should be_kind_of(ConcatFilter)
39
39
  end
40
40
 
41
41
  it "takes a block to configure the filter's output file names" do
42
42
  generator = proc { |input| "main.js" }
43
43
  dsl.filter(ConcatFilter, &generator)
44
- pipeline.filters.last.output_name_generator.should == generator
44
+ filter.output_name_generator.should == generator
45
45
  end
46
46
 
47
47
  it "passes any extra arguments to the filter's constructor" do
@@ -53,7 +53,7 @@ describe "Rake::Pipeline::DSL" do
53
53
  end
54
54
 
55
55
  dsl.filter filter_class, "foo", "bar"
56
- pipeline.filters.last.args.should == %w(foo bar)
56
+ filter.args.should == %w(foo bar)
57
57
  end
58
58
  end
59
59
 
@@ -66,7 +66,7 @@ describe "Rake::Pipeline::DSL" do
66
66
 
67
67
  it "adds the new matcher to the pipeline's filters" do
68
68
  matcher = dsl.match("*.glob") {}
69
- pipeline.filters.last.should == matcher
69
+ filter.should == matcher
70
70
  end
71
71
  end
72
72
 
@@ -77,10 +77,24 @@ describe "Rake::Pipeline::DSL" do
77
77
  end
78
78
  end
79
79
 
80
- describe "#tmpdir" do
81
- it "configures the pipeline's tmpdir" do
82
- dsl.tmpdir "/temporary"
83
- pipeline.tmpdir.should == "/temporary"
80
+ describe "#concat" do
81
+ it "creates a ConcatFilter" do
82
+ dsl.concat "octopus"
83
+ filter.should be_kind_of(Rake::Pipeline::ConcatFilter)
84
+ end
85
+
86
+ context "passed an Array first argument" do
87
+ it "creates an OrderingConcatFilter" do
88
+ dsl.concat ["octopus"]
89
+ filter.should be_kind_of(Rake::Pipeline::OrderingConcatFilter)
90
+ end
91
+ end
92
+ end
93
+
94
+ describe "#copy" do
95
+ it "creates a ConcatFilter" do
96
+ dsl.copy
97
+ filter.should be_kind_of(Rake::Pipeline::ConcatFilter)
84
98
  end
85
99
  end
86
100
  end
@@ -0,0 +1,41 @@
1
+ describe "Rake::Pipeline::ProjectDSL" do
2
+ ConcatFilter = Rake::Pipeline::SpecHelpers::Filters::ConcatFilter
3
+
4
+ let(:project) { Rake::Pipeline::Project.new }
5
+ let(:dsl) { Rake::Pipeline::DSL::ProjectDSL.new(project) }
6
+
7
+ it "accepts a project in its constructor" do
8
+ dsl.project.should == project
9
+ end
10
+
11
+ describe "#output" do
12
+ it "configures the project's default_output_root" do
13
+ dsl.output "/path/to/output"
14
+ project.default_output_root.should == "/path/to/output"
15
+ end
16
+ end
17
+
18
+ describe "#tmpdir" do
19
+ it "sets the project's tmpdir" do
20
+ dsl.tmpdir "/path/to/tmpdir"
21
+ project.tmpdir.should == "/path/to/tmpdir"
22
+ end
23
+ end
24
+
25
+ describe "#input" do
26
+ it "uses Project#build_pipeline to add a new pipeline to the project" do
27
+ project.should_receive(:build_pipeline)
28
+ dsl.input("app") {}
29
+ end
30
+ end
31
+
32
+ describe "#map" do
33
+ it "saves the block in a hash on the project" do
34
+ project.maps.keys.size.should == 0
35
+ run_me = lambda { }
36
+ dsl.map("foo", &run_me)
37
+ dsl.project.maps["foo"].should == run_me
38
+ end
39
+ end
40
+ end
41
+
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rake::Pipeline::DynamicFileTask do
4
+ let(:invoked_tasks) { [] }
5
+
6
+ def define_task(deps, klass=Rake::Pipeline::DynamicFileTask, &task_proc)
7
+ task_proc ||= proc do |task|
8
+ touch(task.name)
9
+ invoked_tasks << task
10
+ end
11
+
12
+ klass.define_task(deps, &task_proc)
13
+ end
14
+
15
+ let(:task) { define_task('output') }
16
+
17
+ before do
18
+ # Make sure date conversions happen in UTC, not local time
19
+ ENV['TZ'] = 'UTC'
20
+ end
21
+
22
+ after do
23
+ # Clean out all defined tasks after each test runs
24
+ Rake.application = Rake::Application.new
25
+ end
26
+
27
+ describe "#dynamic" do
28
+ it "saves a block that can be called later with #invoke_dynamic_block" do
29
+ block = proc {}
30
+ task.dynamic(&block)
31
+ block.should_receive(:call).with(task)
32
+ task.invoke_dynamic_block
33
+ end
34
+
35
+ it "returns the task" do
36
+ (task.dynamic {}).should eq(task)
37
+ end
38
+ end
39
+
40
+ describe "#invoke" do
41
+ let(:static) { define_task('static', Rake::FileTask) }
42
+ let!(:dynamic) { define_task('dynamic', Rake::FileTask) }
43
+ let!(:dynamic_task) { define_task('output' => static).dynamic { ['dynamic'] } }
44
+
45
+ it "invokes the task's static and dynamic prerequisites" do
46
+ dynamic_task.invoke
47
+ invoked_tasks.should include(static)
48
+ invoked_tasks.should include(dynamic)
49
+ end
50
+
51
+ it "adds dynamic dependencies to its manifest entry" do
52
+ dynamic_task.invoke
53
+ dynamic_task.manifest_entry.deps.should == {
54
+ 'dynamic' => File.mtime('dynamic')
55
+ }
56
+ end
57
+
58
+ it "adds the current task's mtime to its manifest entry" do
59
+ dynamic_task.invoke
60
+ dynamic_task.manifest_entry.mtime.should == File.mtime('output')
61
+ end
62
+ end
63
+
64
+ describe "#needed?" do
65
+ it "is true if the task has no previous manifest entry" do
66
+ task.last_manifest_entry.should be_nil
67
+ task.should be_needed
68
+ end
69
+ end
70
+
71
+ describe "#dynamic_prerequisites" do
72
+ def make_file(name, mtime=nil)
73
+ touch(name)
74
+ if mtime
75
+ File.utime(mtime, mtime, name)
76
+ end
77
+ end
78
+
79
+ it "returns an empty array if the task has no dynamic block" do
80
+ task.dynamic_prerequisites.should == []
81
+ end
82
+
83
+ it "returns the result of invoking the dynamic block" do
84
+ task.dynamic { %w[blinky] }
85
+ task.dynamic_prerequisites.should == %w[blinky]
86
+ end
87
+
88
+ it "filters the task itself from the list" do
89
+ task.dynamic { %w[output blinky] }
90
+ task.dynamic_prerequisites.should == %w[blinky]
91
+ end
92
+
93
+ it "loads dependency information from the manifest first" do
94
+ time = Time.utc(2000)
95
+ %w[blinky output].each { |f| make_file f, time }
96
+
97
+ manifest_entry = Rake::Pipeline::ManifestEntry.from_hash({
98
+ "deps" => {
99
+ "blinky" => "2000-01-01 00:00:00 +0000"
100
+ },
101
+ "mtime" => "2000-01-01 00:00:00 +0000"
102
+ })
103
+
104
+ task.dynamic { %w[] }
105
+ task.stub(:last_manifest_entry) { manifest_entry }
106
+ task.should_not_receive(:invoke_dynamic_block)
107
+ task.dynamic_prerequisites.should == %w[blinky]
108
+ end
109
+ end
110
+
111
+ end
@@ -57,11 +57,10 @@ if "".respond_to?(:encode)
57
57
  create_files
58
58
 
59
59
  @pipeline = Rake::Pipeline.build do
60
- tmpdir "temporary"
61
- input tmp, "app/javascripts/*.js"
62
- filter Filters::ConcatFilter, "javascripts/application.js"
63
- filter Filters::StripAssertsFilter
64
60
  output "public"
61
+ input "#{tmp}/app/javascripts/", "*.js"
62
+ concat "javascripts/application.js"
63
+ filter Filters::StripAssertsFilter
65
64
  end
66
65
  end
67
66
 
@@ -86,11 +85,10 @@ if "".respond_to?(:encode)
86
85
  let(:encoding) { "EUC-JP" }
87
86
 
88
87
  it "does not raise an exception" do
89
- pipeline = Rake::Pipeline.build do
90
- tmpdir "temporary"
91
- input tmp, "app/javascripts/*.js"
92
- filter Filters::ConcatFilter, "javascripts/application.js"
88
+ pipeline = Rake::Pipeline.build do
93
89
  output "public"
90
+ input "#{tmp}/app/javascripts/", "*.js"
91
+ concat "javascripts/application.js"
94
92
  end
95
93
 
96
94
  pipeline.invoke