rake-pipeline-fork 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/.travis.yml +12 -0
- data/.yardopts +2 -0
- data/GETTING_STARTED.md +268 -0
- data/Gemfile +14 -0
- data/LICENSE +20 -0
- data/README.markdown +11 -0
- data/README.yard +178 -0
- data/Rakefile +21 -0
- data/bin/rakep +4 -0
- data/examples/copying_files.md +12 -0
- data/examples/minifying_files.md +37 -0
- data/examples/modifying_pipelines.md +67 -0
- data/examples/multiple_pipelines.md +77 -0
- data/lib/generators/rake/pipeline/install/install_generator.rb +70 -0
- data/lib/rake-pipeline.rb +462 -0
- data/lib/rake-pipeline/cli.rb +56 -0
- data/lib/rake-pipeline/dsl.rb +9 -0
- data/lib/rake-pipeline/dsl/pipeline_dsl.rb +246 -0
- data/lib/rake-pipeline/dsl/project_dsl.rb +108 -0
- data/lib/rake-pipeline/dynamic_file_task.rb +194 -0
- data/lib/rake-pipeline/error.rb +17 -0
- data/lib/rake-pipeline/file_wrapper.rb +182 -0
- data/lib/rake-pipeline/filter.rb +249 -0
- data/lib/rake-pipeline/filters.rb +4 -0
- data/lib/rake-pipeline/filters/concat_filter.rb +63 -0
- data/lib/rake-pipeline/filters/gsub_filter.rb +56 -0
- data/lib/rake-pipeline/filters/ordering_concat_filter.rb +38 -0
- data/lib/rake-pipeline/filters/pipeline_finalizing_filter.rb +21 -0
- data/lib/rake-pipeline/graph.rb +178 -0
- data/lib/rake-pipeline/manifest.rb +86 -0
- data/lib/rake-pipeline/manifest_entry.rb +34 -0
- data/lib/rake-pipeline/matcher.rb +141 -0
- data/lib/rake-pipeline/middleware.rb +72 -0
- data/lib/rake-pipeline/precompile.rake +8 -0
- data/lib/rake-pipeline/project.rb +335 -0
- data/lib/rake-pipeline/rails_plugin.rb +10 -0
- data/lib/rake-pipeline/railtie.rb +34 -0
- data/lib/rake-pipeline/reject_matcher.rb +29 -0
- data/lib/rake-pipeline/server.rb +15 -0
- data/lib/rake-pipeline/sorted_pipeline.rb +19 -0
- data/lib/rake-pipeline/version.rb +6 -0
- data/rails/init.rb +2 -0
- data/rake-pipeline.gemspec +24 -0
- data/spec/cli_spec.rb +71 -0
- data/spec/concat_filter_spec.rb +37 -0
- data/spec/dsl/pipeline_dsl_spec.rb +165 -0
- data/spec/dsl/project_dsl_spec.rb +41 -0
- data/spec/dynamic_file_task_spec.rb +119 -0
- data/spec/encoding_spec.rb +106 -0
- data/spec/file_wrapper_spec.rb +132 -0
- data/spec/filter_spec.rb +332 -0
- data/spec/graph_spec.rb +56 -0
- data/spec/gsub_filter_spec.rb +87 -0
- data/spec/manifest_entry_spec.rb +46 -0
- data/spec/manifest_spec.rb +67 -0
- data/spec/matcher_spec.rb +141 -0
- data/spec/middleware_spec.rb +199 -0
- data/spec/ordering_concat_filter_spec.rb +42 -0
- data/spec/pipeline_spec.rb +232 -0
- data/spec/project_spec.rb +295 -0
- data/spec/rake_acceptance_spec.rb +738 -0
- data/spec/rake_tasks_spec.rb +21 -0
- data/spec/reject_matcher_spec.rb +31 -0
- data/spec/sorted_pipeline_spec.rb +27 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/support/spec_helpers/file_utils.rb +35 -0
- data/spec/support/spec_helpers/filters.rb +37 -0
- data/spec/support/spec_helpers/input_helpers.rb +23 -0
- data/spec/support/spec_helpers/memory_file_wrapper.rb +31 -0
- data/spec/support/spec_helpers/memory_manifest.rb +19 -0
- data/tools/perfs +101 -0
- metadata +215 -0
@@ -0,0 +1,119 @@
|
|
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
|
+
task = klass.define_task(deps, &task_proc)
|
13
|
+
|
14
|
+
if klass == Rake::Pipeline::DynamicFileTask
|
15
|
+
task.manifest = Rake::Pipeline::Manifest.new
|
16
|
+
end
|
17
|
+
|
18
|
+
task
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:task) { define_task('output') }
|
22
|
+
|
23
|
+
after do
|
24
|
+
# Clean out all defined tasks after each test runs
|
25
|
+
Rake.application = Rake::Application.new
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#dynamic" do
|
29
|
+
it "saves a block that can be called later with #invoke_dynamic_block" do
|
30
|
+
block = proc {}
|
31
|
+
task.dynamic(&block)
|
32
|
+
block.should_receive(:call).with(task)
|
33
|
+
task.invoke_dynamic_block
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns the task" do
|
37
|
+
(task.dynamic {}).should eq(task)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#invoke" do
|
42
|
+
let(:static) { define_task('static', Rake::FileTask) }
|
43
|
+
let!(:dynamic) { define_task('dynamic', Rake::FileTask) }
|
44
|
+
let!(:dynamic_task) { define_task('output' => static).dynamic { ['dynamic'] } }
|
45
|
+
|
46
|
+
it "invokes the task's static and dynamic prerequisites" do
|
47
|
+
dynamic_task.invoke
|
48
|
+
invoked_tasks.should include(static)
|
49
|
+
invoked_tasks.should include(dynamic)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "adds dynamic dependencies to its manifest entry" do
|
53
|
+
dynamic_task.invoke
|
54
|
+
dynamic_task.manifest_entry.deps.should == {
|
55
|
+
'dynamic' => File.mtime('dynamic').to_i
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
it "adds the current task's mtime to its manifest entry" do
|
60
|
+
dynamic_task.invoke
|
61
|
+
dynamic_task.manifest_entry.mtime.should == File.mtime('output').to_i
|
62
|
+
end
|
63
|
+
|
64
|
+
it "raises an error when there is no manifest" do
|
65
|
+
dynamic_task.manifest = nil
|
66
|
+
lambda {
|
67
|
+
dynamic_task.invoke
|
68
|
+
}.should raise_error(Rake::Pipeline::DynamicFileTask::ManifestRequired)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#needed?" do
|
73
|
+
it "is true if the task has manifest entry" do
|
74
|
+
task.manifest_entry.should be_nil
|
75
|
+
task.should be_needed
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#dynamic_prerequisites" do
|
80
|
+
def make_file(name, mtime=nil)
|
81
|
+
touch(name)
|
82
|
+
if mtime
|
83
|
+
File.utime(mtime, mtime, name)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it "returns an empty array if the task has no dynamic block" do
|
88
|
+
task.dynamic_prerequisites.should == []
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns the result of invoking the dynamic block" do
|
92
|
+
task.dynamic { %w[blinky] }
|
93
|
+
task.dynamic_prerequisites.should == %w[blinky]
|
94
|
+
end
|
95
|
+
|
96
|
+
it "filters the task itself from the list" do
|
97
|
+
task.dynamic { %w[output blinky] }
|
98
|
+
task.dynamic_prerequisites.should == %w[blinky]
|
99
|
+
end
|
100
|
+
|
101
|
+
it "loads dependency information from the manifest first" do
|
102
|
+
time = Time.utc(2000)
|
103
|
+
%w[blinky output].each { |f| make_file f, time }
|
104
|
+
|
105
|
+
manifest_entry = Rake::Pipeline::ManifestEntry.from_hash({
|
106
|
+
"deps" => {
|
107
|
+
"blinky" => time.to_i
|
108
|
+
},
|
109
|
+
"mtime" => time.to_i
|
110
|
+
})
|
111
|
+
|
112
|
+
task.dynamic { %w[] }
|
113
|
+
task.stub(:last_manifest_entry) { manifest_entry }
|
114
|
+
task.should_not_receive(:invoke_dynamic_block)
|
115
|
+
task.dynamic_prerequisites.should == %w[blinky]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
if "".respond_to?(:encode)
|
4
|
+
class String
|
5
|
+
def strip_heredoc
|
6
|
+
indent = scan(/^[ \t]*(?=\S)/).min
|
7
|
+
indent = indent ? indent.size : 0
|
8
|
+
gsub(/^[ \t]{#{indent}}/, '')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
inputs = {
|
13
|
+
"app/javascripts/jquery.js" => <<-HERE.strip_heredoc,
|
14
|
+
var jQuery = { japanese: "こんにちは" };
|
15
|
+
HERE
|
16
|
+
|
17
|
+
"app/javascripts/sproutcore.js" => <<-HERE.strip_heredoc,
|
18
|
+
var SC = {};
|
19
|
+
assert(SC);
|
20
|
+
SC.hi = function() { console.log("こんにちは"); };
|
21
|
+
HERE
|
22
|
+
}
|
23
|
+
|
24
|
+
expected_output = <<-HERE.strip_heredoc
|
25
|
+
var jQuery = { japanese: "こんにちは" };
|
26
|
+
var SC = {};
|
27
|
+
|
28
|
+
SC.hi = function() { console.log("こんにちは"); };
|
29
|
+
HERE
|
30
|
+
|
31
|
+
describe "the pipeline's encoding handling" do
|
32
|
+
Filters = Rake::Pipeline::SpecHelpers::Filters
|
33
|
+
|
34
|
+
let(:project) { Rake::Pipeline::Project.new }
|
35
|
+
|
36
|
+
let(:inputs) { inputs }
|
37
|
+
|
38
|
+
def output_should_exist(expected, encoding="UTF-8")
|
39
|
+
output = File.join(tmp, "public/javascripts/application.js")
|
40
|
+
|
41
|
+
File.exists?(output).should be_true
|
42
|
+
output = File.read(output, :encoding => encoding)
|
43
|
+
output.should == expected
|
44
|
+
output.should be_valid_encoding
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_files
|
48
|
+
inputs.each do |name, contents|
|
49
|
+
filename = File.join(tmp, name)
|
50
|
+
mkdir_p File.dirname(filename)
|
51
|
+
|
52
|
+
File.open(filename, "w:#{encoding}") do |file|
|
53
|
+
file.write contents.encode(encoding)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
before do
|
59
|
+
create_files
|
60
|
+
|
61
|
+
@pipeline = Rake::Pipeline.build :project => project do
|
62
|
+
output "public"
|
63
|
+
input "#{tmp}/app/javascripts/", "*.js"
|
64
|
+
concat "javascripts/application.js"
|
65
|
+
filter Filters::StripAssertsFilter
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "when the input is UTF-8" do
|
70
|
+
let(:encoding) { "UTF-8" }
|
71
|
+
|
72
|
+
it "creates the correct file" do
|
73
|
+
@pipeline.invoke
|
74
|
+
output_should_exist(expected_output)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "when the input is not UTF-8" do
|
79
|
+
let(:encoding) { "EUC-JP" }
|
80
|
+
|
81
|
+
it "raises an exception" do
|
82
|
+
lambda { @pipeline.invoke }.should raise_error(Rake::Pipeline::EncodingError, /not valid UTF-8/)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "when dealing with only BINARY-type filters" do
|
87
|
+
let(:encoding) { "EUC-JP" }
|
88
|
+
|
89
|
+
it "does not raise an exception" do
|
90
|
+
pipeline = Rake::Pipeline.build :project => project do
|
91
|
+
output "public"
|
92
|
+
input "#{tmp}/app/javascripts/", "*.js"
|
93
|
+
concat "javascripts/application.js"
|
94
|
+
end
|
95
|
+
|
96
|
+
pipeline.invoke
|
97
|
+
|
98
|
+
expected = inputs.map do |filename, contents|
|
99
|
+
contents.encode("EUC-JP")
|
100
|
+
end.join
|
101
|
+
|
102
|
+
output_should_exist(expected.force_encoding("BINARY"), "BINARY")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
describe "Rake::Pipeline::FileWrapper" do
|
2
|
+
let(:file) { Rake::Pipeline::FileWrapper.new }
|
3
|
+
let(:root) { File.expand_path("app/assets") }
|
4
|
+
let(:jquery) { File.join(root, "javascripts/jquery.js") }
|
5
|
+
|
6
|
+
before do
|
7
|
+
file.root = root
|
8
|
+
file.path = "javascripts/jquery.js"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "is equal to another FileWrapper if the root and path are the same" do
|
12
|
+
other = Rake::Pipeline::FileWrapper.new
|
13
|
+
other.root = root
|
14
|
+
other.path = "javascripts/jquery.js"
|
15
|
+
|
16
|
+
file.should == other
|
17
|
+
file.hash.should == other.hash
|
18
|
+
end
|
19
|
+
|
20
|
+
it "is not equal to another FileWrapper if the root is the same but the path is different" do
|
21
|
+
other = Rake::Pipeline::FileWrapper.new
|
22
|
+
other.root = root
|
23
|
+
other.path = "javascripts/jquery2.js"
|
24
|
+
|
25
|
+
file.should_not == other
|
26
|
+
end
|
27
|
+
|
28
|
+
it "is not equal to another FileWrapper if the root is different but the path is the same" do
|
29
|
+
other = Rake::Pipeline::FileWrapper.new
|
30
|
+
other.root = "/"
|
31
|
+
other.path = "javascripts/jquery.js"
|
32
|
+
|
33
|
+
file.should_not == other
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#fullpath" do
|
37
|
+
it "returns the complete path to the file" do
|
38
|
+
file.fullpath.should == jquery
|
39
|
+
end
|
40
|
+
|
41
|
+
it "raises an error if its root is not a root path" do
|
42
|
+
file.root = 'root'
|
43
|
+
lambda { file.fullpath }.should raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it "doesn't raise an error with a unix root path" do
|
47
|
+
file.root = '/root'
|
48
|
+
lambda { file.fullpath }.should_not raise_error
|
49
|
+
end
|
50
|
+
|
51
|
+
it "doesn't raise an error with a windows root path" do
|
52
|
+
file.root = 'c:\root'
|
53
|
+
lambda { file.fullpath }.should_not raise_error
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#in_directory?" do
|
58
|
+
it "is when the full path starts with the directory" do
|
59
|
+
file.should be_in_directory(file.root)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "is not when full path does not start with the directory" do
|
63
|
+
file.should_not be_in_directory("/foo/bar/baz")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "it knows it doesn't exist when the file doesn't exist" do
|
68
|
+
file.exists?.should == false
|
69
|
+
end
|
70
|
+
|
71
|
+
it "knows it exists when the file exists" do
|
72
|
+
touch_p jquery
|
73
|
+
file.exists?.should == true
|
74
|
+
end
|
75
|
+
|
76
|
+
it "raises an exception if trying to #read a file that doesn't exist" do
|
77
|
+
lambda { file.read }.should raise_error(Errno::ENOENT)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "returns the file's body when invoking #read on a file that does exist" do
|
81
|
+
touch_p jquery
|
82
|
+
body = "This. Is. jQuery!"
|
83
|
+
File.open(jquery, "w") { |file| file.write body }
|
84
|
+
|
85
|
+
file.read.should == body
|
86
|
+
end
|
87
|
+
|
88
|
+
it "creates a file with #create" do
|
89
|
+
new_file = file.create
|
90
|
+
new_file.should be_kind_of File
|
91
|
+
|
92
|
+
File.exists?(jquery).should == true
|
93
|
+
|
94
|
+
new_file.close
|
95
|
+
end
|
96
|
+
|
97
|
+
it "complains if trying to close an unopened file" do
|
98
|
+
lambda { file.close }.should raise_error(IOError)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "closes a file created using #create with #close" do
|
102
|
+
new_file = file.create
|
103
|
+
new_file.closed?.should == false
|
104
|
+
|
105
|
+
file.close
|
106
|
+
new_file.closed?.should == true
|
107
|
+
|
108
|
+
lambda { file.close }.should raise_error(IOError)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "complains if trying to write to a file that was not created" do
|
112
|
+
lambda { file.write "This. Is. jQuery" }.should raise_error(Rake::Pipeline::UnopenedFile)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "supports a block form of create that closes the file at the end" do
|
116
|
+
file.create do |f|
|
117
|
+
f.write "HI"
|
118
|
+
end
|
119
|
+
|
120
|
+
File.exists?(jquery).should == true
|
121
|
+
File.read(jquery).should == "HI"
|
122
|
+
file.closed?.should == true
|
123
|
+
end
|
124
|
+
|
125
|
+
it "writes to the file system if the file was created" do
|
126
|
+
new_file = file.create
|
127
|
+
file.write "This. Is. jQuery"
|
128
|
+
new_file.close
|
129
|
+
|
130
|
+
file.read.should == "This. Is. jQuery"
|
131
|
+
end
|
132
|
+
end
|
data/spec/filter_spec.rb
ADDED
@@ -0,0 +1,332 @@
|
|
1
|
+
describe "Rake::Pipeline::Filter" do
|
2
|
+
MemoryManifest ||= Rake::Pipeline::SpecHelpers::MemoryManifest
|
3
|
+
|
4
|
+
after do
|
5
|
+
# Clean out all defined tasks after each test runs
|
6
|
+
Rake.application = Rake::Application.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def input_file(path, file_root=input_root)
|
10
|
+
Rake::Pipeline::FileWrapper.new(file_root, path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def output_file(path, file_root=output_root)
|
14
|
+
Rake::Pipeline::FileWrapper.new(file_root, path)
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:project) { Rake::Pipeline::Project.new }
|
18
|
+
let(:pipeline) { project.build_pipeline "app" }
|
19
|
+
|
20
|
+
let(:filter) { Rake::Pipeline::Filter.new }
|
21
|
+
let(:input_root) { File.join(tmp, "app/assets") }
|
22
|
+
let(:output_root) { File.join(tmp, "filter1/app/assets") }
|
23
|
+
let(:input_files) do
|
24
|
+
%w(jquery.js jquery-ui.js ember.js).map { |f| input_file(f) }
|
25
|
+
end
|
26
|
+
|
27
|
+
it "accepts a series of FileWrapper objects for the input" do
|
28
|
+
filter.input_files = input_files
|
29
|
+
filter.input_files.should == input_files
|
30
|
+
end
|
31
|
+
|
32
|
+
it "accepts a root directory for the outputs" do
|
33
|
+
path = File.expand_path(tmp, "filter1/app/assets")
|
34
|
+
filter.output_root = path
|
35
|
+
filter.output_root.should == path
|
36
|
+
end
|
37
|
+
|
38
|
+
it "accepts a Rake::Application to install tasks into" do
|
39
|
+
app = Rake::Application.new
|
40
|
+
filter.rake_application = app
|
41
|
+
filter.rake_application.should == app
|
42
|
+
end
|
43
|
+
|
44
|
+
it "makes Rake.application the default rake_application" do
|
45
|
+
filter.rake_application.should == Rake.application
|
46
|
+
end
|
47
|
+
|
48
|
+
it "accepts a proc to convert the input name into an output name" do
|
49
|
+
conversion = proc { |input| input }
|
50
|
+
filter.output_name_generator = conversion
|
51
|
+
filter.output_name_generator.should == conversion
|
52
|
+
end
|
53
|
+
|
54
|
+
it "accepts a block constructor argument to convert the input name into an output name" do
|
55
|
+
conversion = proc { |input| "application.js" }
|
56
|
+
new_filter = Rake::Pipeline::Filter.new(&conversion)
|
57
|
+
new_filter.output_name_generator.should == conversion
|
58
|
+
end
|
59
|
+
|
60
|
+
it "knows about its containing pipeline" do
|
61
|
+
filter = Rake::Pipeline::Filter.new
|
62
|
+
pipeline.add_filter(filter)
|
63
|
+
filter.pipeline.should == pipeline
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "using the output_name proc to converting the input names into a hash" do
|
67
|
+
before do
|
68
|
+
filter.output_root = output_root
|
69
|
+
filter.input_files = input_files
|
70
|
+
end
|
71
|
+
|
72
|
+
it "with a simple output_name proc that outputs to a single file" do
|
73
|
+
output_name_generator = proc { |input| "application.js" }
|
74
|
+
filter.output_name_generator = output_name_generator
|
75
|
+
|
76
|
+
filter.outputs.should == {
|
77
|
+
output_file("application.js") => input_files
|
78
|
+
}
|
79
|
+
|
80
|
+
filter.output_files.should == [output_file("application.js")]
|
81
|
+
end
|
82
|
+
|
83
|
+
it "with more than one output per input" do
|
84
|
+
output_name_generator = proc { |input| [ input, "application.js" ] }
|
85
|
+
filter.output_name_generator = output_name_generator
|
86
|
+
outputs = filter.outputs
|
87
|
+
|
88
|
+
outputs = input_files.inject({}) do |hash, input|
|
89
|
+
hash.merge output_file(input.path) => [ input ]
|
90
|
+
end
|
91
|
+
|
92
|
+
filter.outputs.should == { output_file("application.js") => input_files }.merge(outputs)
|
93
|
+
filter.output_files.sort.should ==
|
94
|
+
([ output_file("application.js") ] + input_files.map { |f| output_file(f.path) }).sort
|
95
|
+
end
|
96
|
+
|
97
|
+
it "with a 1:1 output_name proc" do
|
98
|
+
output_name_generator = proc { |input| input }
|
99
|
+
filter.output_name_generator = output_name_generator
|
100
|
+
outputs = filter.outputs
|
101
|
+
|
102
|
+
outputs.keys.sort.should == input_files.map { |f| output_file(f.path) }.sort
|
103
|
+
outputs.values.flatten.sort.should == input_files.sort
|
104
|
+
|
105
|
+
filter.output_files.should == input_files.map { |file| output_file(file.path) }
|
106
|
+
end
|
107
|
+
|
108
|
+
it "with a more complicated proc" do
|
109
|
+
output_name_generator = proc { |input| input.split(/[-.]/, 2).first + ".js" }
|
110
|
+
filter.output_name_generator = output_name_generator
|
111
|
+
outputs = filter.outputs
|
112
|
+
|
113
|
+
outputs.keys.sort.should == [output_file("ember.js"), output_file("jquery.js")]
|
114
|
+
outputs.values.sort.should == [[input_file("ember.js")], [input_file("jquery.js"), input_file("jquery-ui.js")]]
|
115
|
+
|
116
|
+
filter.output_files.should == [output_file("jquery.js"), output_file("ember.js")]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "generates rake tasks" do
|
121
|
+
let(:filter_class) {
|
122
|
+
Class.new(Rake::Pipeline::Filter) do
|
123
|
+
attr_accessor :generate_output_block
|
124
|
+
|
125
|
+
def generate_output(inputs, output)
|
126
|
+
generate_output_block.call(inputs, output)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
}
|
130
|
+
let(:filter) { filter_class.new }
|
131
|
+
let(:input_root) { File.join(tmp, "app/assets") }
|
132
|
+
let(:output_root) { File.join(tmp, "filter1/app/assets") }
|
133
|
+
let(:input_files) do
|
134
|
+
%w(jquery.js jquery-ui.js ember.js).map do |file|
|
135
|
+
input_file("javascripts/#{file}")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
before do
|
140
|
+
Rake.application = Rake::Application.new
|
141
|
+
filter.output_root = output_root
|
142
|
+
filter.input_files = input_files
|
143
|
+
filter.pipeline = pipeline
|
144
|
+
end
|
145
|
+
|
146
|
+
def output_task(path, app=Rake.application)
|
147
|
+
app.define_task(Rake::Pipeline::DynamicFileTask, File.join(output_root, path))
|
148
|
+
end
|
149
|
+
|
150
|
+
def input_task(path)
|
151
|
+
Rake::Pipeline::DynamicFileTask.define_task(File.join(input_root, path))
|
152
|
+
end
|
153
|
+
|
154
|
+
it "does not generate Rake tasks onto Rake.application if an alternate application is supplied" do
|
155
|
+
app = Rake::Application.new
|
156
|
+
filter.rake_application = app
|
157
|
+
filter.output_name_generator = proc { |input| input }
|
158
|
+
filter.generate_rake_tasks
|
159
|
+
tasks = filter.rake_tasks
|
160
|
+
|
161
|
+
input_files.each do |file|
|
162
|
+
task = output_task(file.path, app)
|
163
|
+
tasks.include?(task).should == true
|
164
|
+
Rake.application.tasks.include?(task).should == false
|
165
|
+
app.tasks.include?(task).should == true
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it "with a simple output_name proc that outputs to a single file" do
|
170
|
+
filter_runs = 0
|
171
|
+
|
172
|
+
filter.output_name_generator = proc { |input| "javascripts/application.js" }
|
173
|
+
filter.generate_output_block = proc do |inputs, output|
|
174
|
+
inputs.should == input_files
|
175
|
+
output.should == output_file("javascripts/application.js")
|
176
|
+
|
177
|
+
filter_runs += 1
|
178
|
+
end
|
179
|
+
|
180
|
+
filter.generate_rake_tasks
|
181
|
+
tasks = filter.rake_tasks
|
182
|
+
tasks.should == [output_task("javascripts/application.js")]
|
183
|
+
|
184
|
+
tasks.each(&:invoke)
|
185
|
+
|
186
|
+
filter_runs.should == 1
|
187
|
+
end
|
188
|
+
|
189
|
+
it "with an output_name proc that takes two arguments" do
|
190
|
+
filter.output_name_generator = proc { |path, input|
|
191
|
+
input.path.upcase
|
192
|
+
}
|
193
|
+
|
194
|
+
filter.outputs.keys.map(&:path).should include('JAVASCRIPTS/JQUERY.JS')
|
195
|
+
filter.output_files.map(&:path).should include('JAVASCRIPTS/JQUERY.JS')
|
196
|
+
end
|
197
|
+
|
198
|
+
it "with a 1:1 output_name proc" do
|
199
|
+
filter_runs = 0
|
200
|
+
|
201
|
+
filter.output_name_generator = proc { |input| input }
|
202
|
+
filter.generate_output_block = proc do |inputs, output|
|
203
|
+
inputs.should == [input_file(output.path)]
|
204
|
+
|
205
|
+
filter_runs += 1
|
206
|
+
end
|
207
|
+
|
208
|
+
filter.generate_rake_tasks
|
209
|
+
tasks = filter.rake_tasks
|
210
|
+
tasks.sort.should == input_files.map { |file| output_task(file.path) }.sort
|
211
|
+
tasks.each do |task|
|
212
|
+
name = task.name.sub(/^#{Regexp.escape(output_root)}/, '')
|
213
|
+
prereq = File.join(input_root, name)
|
214
|
+
task.prerequisites.should == [prereq]
|
215
|
+
end
|
216
|
+
|
217
|
+
tasks.each(&:invoke)
|
218
|
+
|
219
|
+
filter_runs.should == 3
|
220
|
+
end
|
221
|
+
|
222
|
+
it "with a more complicated proc" do
|
223
|
+
filter_runs = 0
|
224
|
+
|
225
|
+
filter.output_name_generator = proc { |input| input.match(%r{javascripts/[^-.]*})[0] + ".js" }
|
226
|
+
filter.generate_output_block = proc do |inputs, output|
|
227
|
+
if output.path == "javascripts/jquery.js"
|
228
|
+
inputs.should == [input_file("javascripts/jquery.js"), input_file("javascripts/jquery-ui.js")]
|
229
|
+
output.should == output_file("javascripts/jquery.js")
|
230
|
+
elsif output.path == "javascripts/ember.js"
|
231
|
+
inputs.should == [input_file("javascripts/ember.js")]
|
232
|
+
output.should == output_file("javascripts/ember.js")
|
233
|
+
else
|
234
|
+
flunk
|
235
|
+
end
|
236
|
+
|
237
|
+
filter_runs += 1
|
238
|
+
end
|
239
|
+
|
240
|
+
filter.generate_rake_tasks
|
241
|
+
tasks = filter.rake_tasks
|
242
|
+
tasks.sort.should == [output_task("javascripts/jquery.js"), output_task("javascripts/ember.js")].sort
|
243
|
+
|
244
|
+
tasks.sort[0].prerequisites.should == [
|
245
|
+
File.join(input_root, "javascripts/ember.js"),
|
246
|
+
]
|
247
|
+
|
248
|
+
tasks.sort[1].prerequisites.should == [
|
249
|
+
File.join(input_root, "javascripts/jquery.js"),
|
250
|
+
File.join(input_root, "javascripts/jquery-ui.js"),
|
251
|
+
]
|
252
|
+
|
253
|
+
tasks.each(&:invoke)
|
254
|
+
|
255
|
+
filter_runs.should == 2
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
describe "a filter with additional_dependencies" do
|
260
|
+
let(:include_filter) {
|
261
|
+
Class.new(Rake::Pipeline::ConcatFilter) do
|
262
|
+
def additional_dependencies(input)
|
263
|
+
includes(input)
|
264
|
+
end
|
265
|
+
|
266
|
+
def includes(input)
|
267
|
+
input.read.scan(/^#include \"(.*)\"$/).map(&:first).map do |inc|
|
268
|
+
File.join(input.root, inc)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def generate_output(inputs, output)
|
273
|
+
out = ""
|
274
|
+
inputs.each do |input|
|
275
|
+
includes(input).each { |inc| out += File.read(inc) }
|
276
|
+
out += input.read
|
277
|
+
output.write out
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
}
|
282
|
+
|
283
|
+
def write_input_file(filename, contents='', root=input_root)
|
284
|
+
mkdir_p root
|
285
|
+
File.open(File.join(root, filename), 'w') { |f| f.puts contents }
|
286
|
+
input_file(filename)
|
287
|
+
end
|
288
|
+
|
289
|
+
def invoke_filter(filter)
|
290
|
+
mkdir_p output_root
|
291
|
+
filter.pipeline = pipeline
|
292
|
+
filter.last_manifest = MemoryManifest.new
|
293
|
+
filter.output_root = output_root
|
294
|
+
filter.input_files = input_files
|
295
|
+
tasks = filter.generate_rake_tasks
|
296
|
+
tasks.each(&:invoke)
|
297
|
+
tasks
|
298
|
+
end
|
299
|
+
|
300
|
+
let!(:main) { write_input_file('main', '#include "header"') }
|
301
|
+
let!(:header) { write_input_file('header', 'header') }
|
302
|
+
let!(:main_output) { output_file('main') }
|
303
|
+
let(:input_files) { [main] }
|
304
|
+
let(:filter) { include_filter.new }
|
305
|
+
|
306
|
+
it "creates its output files" do
|
307
|
+
invoke_filter(filter)
|
308
|
+
main_output.exists?.should be_true
|
309
|
+
main_output.read.should == %[header\n#include "header"\n]
|
310
|
+
end
|
311
|
+
|
312
|
+
it "rebuilds main file when it changes" do
|
313
|
+
invoke_filter(filter)
|
314
|
+
sleep 1
|
315
|
+
File.open(main.fullpath, 'w') { |f| f.puts 'PEANUTS' }
|
316
|
+
filter.rake_tasks.each { |t| t.recursively_reenable(Rake.application) }
|
317
|
+
invoke_filter(filter)
|
318
|
+
main_output.read.should == %[PEANUTS\n]
|
319
|
+
end
|
320
|
+
|
321
|
+
it "rebuilds the main file when a dynamic dependency changes" do
|
322
|
+
invoke_filter(filter)
|
323
|
+
sleep 1
|
324
|
+
$LATCH = true
|
325
|
+
File.open(header.fullpath, 'w') { |f| f.puts 'PEANUTS' }
|
326
|
+
filter.rake_tasks.each { |t| t.recursively_reenable(Rake.application) }
|
327
|
+
invoke_filter(filter)
|
328
|
+
main_output.read.should == %[PEANUTS\n#include "header"\n]
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|