rake-pipeline-fork 0.8.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.
- 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
|
+
|