benoit 0.1.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 (164) hide show
  1. data/.gitignore +4 -0
  2. data/.gitmodules +3 -0
  3. data/.rspec +1 -0
  4. data/.rspec-turnip +1 -0
  5. data/.ruby-version +1 -0
  6. data/Assetfile +44 -0
  7. data/Gemfile +5 -0
  8. data/Gemfile.lock +110 -0
  9. data/Rakefile +9 -0
  10. data/benoit.gemspec +50 -0
  11. data/bin/benoit +121 -0
  12. data/bin/bundle-development +1 -0
  13. data/bin/bundle-sandbox +1 -0
  14. data/lib/benoit.rb +36 -0
  15. data/lib/benoit/cadenza.rb +11 -0
  16. data/lib/benoit/cadenza/output_filters.rb +21 -0
  17. data/lib/benoit/cleaner.rb +10 -0
  18. data/lib/benoit/compiler_error.rb +49 -0
  19. data/lib/benoit/configuration.rb +24 -0
  20. data/lib/benoit/current_site.rb +12 -0
  21. data/lib/benoit/file_wrapper_extensions.rb +13 -0
  22. data/lib/benoit/filters.rb +15 -0
  23. data/lib/benoit/filters/base_filter.rb +44 -0
  24. data/lib/benoit/filters/blacklist_filter.rb +18 -0
  25. data/lib/benoit/filters/cadenza_filter.rb +75 -0
  26. data/lib/benoit/filters/content_page_filter.rb +45 -0
  27. data/lib/benoit/filters/markdown_filter.rb +19 -0
  28. data/lib/benoit/filters/metadata_cleaner.rb +30 -0
  29. data/lib/benoit/filters/move_to_root_filter.rb +22 -0
  30. data/lib/benoit/filters/pagination_filter.rb +23 -0
  31. data/lib/benoit/filters/pass_thru_filter.rb +22 -0
  32. data/lib/benoit/filters/sass_filter.rb +74 -0
  33. data/lib/benoit/filters/set_metadata_filter.rb +15 -0
  34. data/lib/benoit/logger.rb +69 -0
  35. data/lib/benoit/page.rb +88 -0
  36. data/lib/benoit/page_metadata.rb +8 -0
  37. data/lib/benoit/page_metadata/container.rb +74 -0
  38. data/lib/benoit/page_metadata/json_converter.rb +28 -0
  39. data/lib/benoit/page_metadata/parser.rb +38 -0
  40. data/lib/benoit/page_metadata/store.rb +75 -0
  41. data/lib/benoit/pipeline.rb +1 -0
  42. data/lib/benoit/pipeline/dsl_extensions.rb +8 -0
  43. data/lib/benoit/pipeline/pagination_matcher.rb +53 -0
  44. data/lib/benoit/pipeline_project.rb +81 -0
  45. data/lib/benoit/site_context.rb +123 -0
  46. data/lib/benoit/utils/finds_layouts_for_template.rb +77 -0
  47. data/lib/benoit/utils/normalizes_path_to_template.rb +43 -0
  48. data/lib/benoit/utils/paginated_list.rb +102 -0
  49. data/lib/benoit/version.rb +3 -0
  50. data/lib/build_notifiers/file_built_notifier.rb +20 -0
  51. data/lib/build_notifiers/progress_notifier.rb +57 -0
  52. data/lib/cli.rb +39 -0
  53. data/spec/.rbenv-gemsets +1 -0
  54. data/spec/Gemfile +9 -0
  55. data/spec/Gemfile.lock +57 -0
  56. data/spec/bin/autospec +16 -0
  57. data/spec/bin/cucumber +16 -0
  58. data/spec/bin/htmldiff +16 -0
  59. data/spec/bin/ldiff +16 -0
  60. data/spec/bin/rspec +16 -0
  61. data/spec/features/build_command.feature +46 -0
  62. data/spec/features/frontmatter_metadata.feature +99 -0
  63. data/spec/features/javascript_files.feature +35 -0
  64. data/spec/features/output_filters.feature +20 -0
  65. data/spec/features/page_layouts.feature +72 -0
  66. data/spec/features/pagination.feature +58 -0
  67. data/spec/features/sass_files.feature +30 -0
  68. data/spec/features/version.feature +5 -0
  69. data/spec/lib/filters/base_filter_spec.rb +141 -0
  70. data/spec/lib/filters/markdown_filter_spec.rb +65 -0
  71. data/spec/lib/filters/sass_filter_spec.rb +73 -0
  72. data/spec/lib/metadata_json_converter_spec.rb +65 -0
  73. data/spec/lib/metadata_store_spec.rb +148 -0
  74. data/spec/lib/page_spec.rb +19 -0
  75. data/spec/lib/site_context_spec.rb +106 -0
  76. data/spec/spec_helper.rb +16 -0
  77. data/spec/steps/output_file_steps.rb +45 -0
  78. data/spec/steps/run_steps.rb +71 -0
  79. data/spec/steps/staticly_steps.rb +194 -0
  80. data/spec/support/aruba/rspec.rb +66 -0
  81. data/spec/support/files/img.png +0 -0
  82. data/spec/support/files/input.css.scss +7 -0
  83. data/spec/support/files/input.scss +7 -0
  84. data/spec/support/spec_helpers/file_helpers.rb +8 -0
  85. data/spec/support/spec_helpers/memory_file_wrapper.rb +43 -0
  86. data/spec/support/spec_helpers/memory_manifest.rb +19 -0
  87. data/spec/turnip_helper.rb +19 -0
  88. data/vendor/frontmatter/frontmatter.gemspec +24 -0
  89. data/vendor/frontmatter/lib/frontmatter.rb +92 -0
  90. data/vendor/frontmatter/lib/frontmatter/version.rb +3 -0
  91. data/vendor/rake-pipeline/.gitignore +18 -0
  92. data/vendor/rake-pipeline/.rspec +1 -0
  93. data/vendor/rake-pipeline/.travis.yml +12 -0
  94. data/vendor/rake-pipeline/.yardopts +2 -0
  95. data/vendor/rake-pipeline/GETTING_STARTED.md +268 -0
  96. data/vendor/rake-pipeline/Gemfile +14 -0
  97. data/vendor/rake-pipeline/LICENSE +20 -0
  98. data/vendor/rake-pipeline/README.markdown +11 -0
  99. data/vendor/rake-pipeline/README.yard +178 -0
  100. data/vendor/rake-pipeline/Rakefile +21 -0
  101. data/vendor/rake-pipeline/bin/rakep +4 -0
  102. data/vendor/rake-pipeline/examples/copying_files.md +12 -0
  103. data/vendor/rake-pipeline/examples/minifying_files.md +37 -0
  104. data/vendor/rake-pipeline/examples/modifying_pipelines.md +67 -0
  105. data/vendor/rake-pipeline/examples/multiple_pipelines.md +77 -0
  106. data/vendor/rake-pipeline/lib/generators/rake/pipeline/install/install_generator.rb +70 -0
  107. data/vendor/rake-pipeline/lib/rake-pipeline.rb +509 -0
  108. data/vendor/rake-pipeline/lib/rake-pipeline/cli.rb +57 -0
  109. data/vendor/rake-pipeline/lib/rake-pipeline/dsl.rb +9 -0
  110. data/vendor/rake-pipeline/lib/rake-pipeline/dsl/pipeline_dsl.rb +246 -0
  111. data/vendor/rake-pipeline/lib/rake-pipeline/dsl/project_dsl.rb +108 -0
  112. data/vendor/rake-pipeline/lib/rake-pipeline/dynamic_file_task.rb +194 -0
  113. data/vendor/rake-pipeline/lib/rake-pipeline/error.rb +17 -0
  114. data/vendor/rake-pipeline/lib/rake-pipeline/file_wrapper.rb +195 -0
  115. data/vendor/rake-pipeline/lib/rake-pipeline/filter.rb +267 -0
  116. data/vendor/rake-pipeline/lib/rake-pipeline/filters.rb +4 -0
  117. data/vendor/rake-pipeline/lib/rake-pipeline/filters/concat_filter.rb +63 -0
  118. data/vendor/rake-pipeline/lib/rake-pipeline/filters/gsub_filter.rb +56 -0
  119. data/vendor/rake-pipeline/lib/rake-pipeline/filters/ordering_concat_filter.rb +38 -0
  120. data/vendor/rake-pipeline/lib/rake-pipeline/filters/pipeline_finalizing_filter.rb +21 -0
  121. data/vendor/rake-pipeline/lib/rake-pipeline/graph.rb +178 -0
  122. data/vendor/rake-pipeline/lib/rake-pipeline/manifest.rb +82 -0
  123. data/vendor/rake-pipeline/lib/rake-pipeline/manifest_entry.rb +34 -0
  124. data/vendor/rake-pipeline/lib/rake-pipeline/matcher.rb +141 -0
  125. data/vendor/rake-pipeline/lib/rake-pipeline/middleware.rb +73 -0
  126. data/vendor/rake-pipeline/lib/rake-pipeline/precompile.rake +8 -0
  127. data/vendor/rake-pipeline/lib/rake-pipeline/project.rb +338 -0
  128. data/vendor/rake-pipeline/lib/rake-pipeline/rails_plugin.rb +10 -0
  129. data/vendor/rake-pipeline/lib/rake-pipeline/railtie.rb +34 -0
  130. data/vendor/rake-pipeline/lib/rake-pipeline/reject_matcher.rb +29 -0
  131. data/vendor/rake-pipeline/lib/rake-pipeline/server.rb +15 -0
  132. data/vendor/rake-pipeline/lib/rake-pipeline/sorted_pipeline.rb +19 -0
  133. data/vendor/rake-pipeline/lib/rake-pipeline/version.rb +6 -0
  134. data/vendor/rake-pipeline/rails/init.rb +2 -0
  135. data/vendor/rake-pipeline/rake-pipeline.gemspec +24 -0
  136. data/vendor/rake-pipeline/spec/cli_spec.rb +73 -0
  137. data/vendor/rake-pipeline/spec/concat_filter_spec.rb +37 -0
  138. data/vendor/rake-pipeline/spec/dsl/pipeline_dsl_spec.rb +165 -0
  139. data/vendor/rake-pipeline/spec/dsl/project_dsl_spec.rb +41 -0
  140. data/vendor/rake-pipeline/spec/dynamic_file_task_spec.rb +119 -0
  141. data/vendor/rake-pipeline/spec/encoding_spec.rb +106 -0
  142. data/vendor/rake-pipeline/spec/file_wrapper_spec.rb +132 -0
  143. data/vendor/rake-pipeline/spec/filter_spec.rb +367 -0
  144. data/vendor/rake-pipeline/spec/graph_spec.rb +56 -0
  145. data/vendor/rake-pipeline/spec/gsub_filter_spec.rb +87 -0
  146. data/vendor/rake-pipeline/spec/manifest_entry_spec.rb +46 -0
  147. data/vendor/rake-pipeline/spec/manifest_spec.rb +67 -0
  148. data/vendor/rake-pipeline/spec/matcher_spec.rb +141 -0
  149. data/vendor/rake-pipeline/spec/middleware_spec.rb +199 -0
  150. data/vendor/rake-pipeline/spec/ordering_concat_filter_spec.rb +42 -0
  151. data/vendor/rake-pipeline/spec/pipeline_spec.rb +232 -0
  152. data/vendor/rake-pipeline/spec/project_spec.rb +295 -0
  153. data/vendor/rake-pipeline/spec/rake_acceptance_spec.rb +720 -0
  154. data/vendor/rake-pipeline/spec/rake_tasks_spec.rb +21 -0
  155. data/vendor/rake-pipeline/spec/reject_matcher_spec.rb +31 -0
  156. data/vendor/rake-pipeline/spec/sorted_pipeline_spec.rb +27 -0
  157. data/vendor/rake-pipeline/spec/spec_helper.rb +38 -0
  158. data/vendor/rake-pipeline/spec/support/spec_helpers/file_utils.rb +35 -0
  159. data/vendor/rake-pipeline/spec/support/spec_helpers/filters.rb +37 -0
  160. data/vendor/rake-pipeline/spec/support/spec_helpers/input_helpers.rb +23 -0
  161. data/vendor/rake-pipeline/spec/support/spec_helpers/memory_file_wrapper.rb +35 -0
  162. data/vendor/rake-pipeline/spec/support/spec_helpers/memory_manifest.rb +19 -0
  163. data/vendor/rake-pipeline/tools/perfs +101 -0
  164. metadata +497 -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
@@ -0,0 +1,367 @@
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
+
119
+ describe "tracking original inputs" do
120
+
121
+ before do
122
+ output_name_generator = proc { |input| "application.js" }
123
+ filter.output_name_generator = output_name_generator
124
+ pipeline.add_filter(filter)
125
+ end
126
+
127
+ let(:original_inputs) {
128
+ input_files.map do |input|
129
+ new_path_name = input.path.gsub(/\.js/, "") + "-dev.js"
130
+ input.original_inputs = [input_file(new_path_name)]
131
+ end.flatten
132
+ }
133
+
134
+ it "keeps inputs' original file names" do
135
+ expected = filter.output_files.map{ |o| o.original_inputs.to_a }.flatten
136
+ expected.should == input_files.to_a
137
+ end
138
+
139
+ it "takes original inputs from inputs if available" do
140
+ filter.input_files = original_inputs
141
+ expected = filter.output_files.map{ |o| o.original_inputs.to_a }.flatten
142
+ expected.should == original_inputs.to_a
143
+ end
144
+
145
+ it "doesn't repeat inputs if called more than once" do
146
+ filter.input_files = original_inputs
147
+ filter.output_files
148
+ filter.output_files.map{|o| o.original_inputs.to_a }.flatten.should == original_inputs.to_a
149
+ end
150
+
151
+ end
152
+
153
+ end
154
+
155
+ describe "generates rake tasks" do
156
+ let(:filter_class) {
157
+ Class.new(Rake::Pipeline::Filter) do
158
+ attr_accessor :generate_output_block
159
+
160
+ def generate_output(inputs, output)
161
+ generate_output_block.call(inputs, output)
162
+ end
163
+ end
164
+ }
165
+ let(:filter) { filter_class.new }
166
+ let(:input_root) { File.join(tmp, "app/assets") }
167
+ let(:output_root) { File.join(tmp, "filter1/app/assets") }
168
+ let(:input_files) do
169
+ %w(jquery.js jquery-ui.js ember.js).map do |file|
170
+ input_file("javascripts/#{file}")
171
+ end
172
+ end
173
+
174
+ before do
175
+ Rake.application = Rake::Application.new
176
+ filter.output_root = output_root
177
+ filter.input_files = input_files
178
+ filter.pipeline = pipeline
179
+ end
180
+
181
+ def output_task(path, app=Rake.application)
182
+ app.define_task(Rake::Pipeline::DynamicFileTask, File.join(output_root, path))
183
+ end
184
+
185
+ def input_task(path)
186
+ Rake::Pipeline::DynamicFileTask.define_task(File.join(input_root, path))
187
+ end
188
+
189
+ it "does not generate Rake tasks onto Rake.application if an alternate application is supplied" do
190
+ app = Rake::Application.new
191
+ filter.rake_application = app
192
+ filter.output_name_generator = proc { |input| input }
193
+ filter.generate_rake_tasks
194
+ tasks = filter.rake_tasks
195
+
196
+ input_files.each do |file|
197
+ task = output_task(file.path, app)
198
+ tasks.include?(task).should == true
199
+ Rake.application.tasks.include?(task).should == false
200
+ app.tasks.include?(task).should == true
201
+ end
202
+ end
203
+
204
+ it "with a simple output_name proc that outputs to a single file" do
205
+ filter_runs = 0
206
+
207
+ filter.output_name_generator = proc { |input| "javascripts/application.js" }
208
+ filter.generate_output_block = proc do |inputs, output|
209
+ inputs.should == input_files
210
+ output.should == output_file("javascripts/application.js")
211
+
212
+ filter_runs += 1
213
+ end
214
+
215
+ filter.generate_rake_tasks
216
+ tasks = filter.rake_tasks
217
+ tasks.should == [output_task("javascripts/application.js")]
218
+
219
+ tasks.each(&:invoke)
220
+
221
+ filter_runs.should == 1
222
+ end
223
+
224
+ it "with an output_name proc that takes two arguments" do
225
+ filter.output_name_generator = proc { |path, input|
226
+ input.path.upcase
227
+ }
228
+
229
+ filter.outputs.keys.map(&:path).should include('JAVASCRIPTS/JQUERY.JS')
230
+ filter.output_files.map(&:path).should include('JAVASCRIPTS/JQUERY.JS')
231
+ end
232
+
233
+ it "with a 1:1 output_name proc" do
234
+ filter_runs = 0
235
+
236
+ filter.output_name_generator = proc { |input| input }
237
+ filter.generate_output_block = proc do |inputs, output|
238
+ inputs.should == [input_file(output.path)]
239
+
240
+ filter_runs += 1
241
+ end
242
+
243
+ filter.generate_rake_tasks
244
+ tasks = filter.rake_tasks
245
+ tasks.sort.should == input_files.map { |file| output_task(file.path) }.sort
246
+ tasks.each do |task|
247
+ name = task.name.sub(/^#{Regexp.escape(output_root)}/, '')
248
+ prereq = File.join(input_root, name)
249
+ task.prerequisites.should == [prereq]
250
+ end
251
+
252
+ tasks.each(&:invoke)
253
+
254
+ filter_runs.should == 3
255
+ end
256
+
257
+ it "with a more complicated proc" do
258
+ filter_runs = 0
259
+
260
+ filter.output_name_generator = proc { |input| input.match(%r{javascripts/[^-.]*})[0] + ".js" }
261
+ filter.generate_output_block = proc do |inputs, output|
262
+ if output.path == "javascripts/jquery.js"
263
+ inputs.should == [input_file("javascripts/jquery.js"), input_file("javascripts/jquery-ui.js")]
264
+ output.should == output_file("javascripts/jquery.js")
265
+ elsif output.path == "javascripts/ember.js"
266
+ inputs.should == [input_file("javascripts/ember.js")]
267
+ output.should == output_file("javascripts/ember.js")
268
+ else
269
+ flunk
270
+ end
271
+
272
+ filter_runs += 1
273
+ end
274
+
275
+ filter.generate_rake_tasks
276
+ tasks = filter.rake_tasks
277
+ tasks.sort.should == [output_task("javascripts/jquery.js"), output_task("javascripts/ember.js")].sort
278
+
279
+ tasks.sort[0].prerequisites.should == [
280
+ File.join(input_root, "javascripts/ember.js"),
281
+ ]
282
+
283
+ tasks.sort[1].prerequisites.should == [
284
+ File.join(input_root, "javascripts/jquery.js"),
285
+ File.join(input_root, "javascripts/jquery-ui.js"),
286
+ ]
287
+
288
+ tasks.each(&:invoke)
289
+
290
+ filter_runs.should == 2
291
+ end
292
+ end
293
+
294
+ describe "a filter with additional_dependencies" do
295
+ let(:include_filter) {
296
+ Class.new(Rake::Pipeline::ConcatFilter) do
297
+ def additional_dependencies(input)
298
+ includes(input)
299
+ end
300
+
301
+ def includes(input)
302
+ input.read.scan(/^#include \"(.*)\"$/).map(&:first).map do |inc|
303
+ File.join(input.root, inc)
304
+ end
305
+ end
306
+
307
+ def generate_output(inputs, output)
308
+ out = ""
309
+ inputs.each do |input|
310
+ includes(input).each { |inc| out += File.read(inc) }
311
+ out += input.read
312
+ output.write out
313
+ end
314
+ end
315
+ end
316
+ }
317
+
318
+ def write_input_file(filename, contents='', root=input_root)
319
+ mkdir_p root
320
+ File.open(File.join(root, filename), 'w') { |f| f.puts contents }
321
+ input_file(filename)
322
+ end
323
+
324
+ def invoke_filter(filter)
325
+ mkdir_p output_root
326
+ filter.pipeline = pipeline
327
+ filter.last_manifest = MemoryManifest.new
328
+ filter.output_root = output_root
329
+ filter.input_files = input_files
330
+ tasks = filter.generate_rake_tasks
331
+ tasks.each(&:invoke)
332
+ tasks
333
+ end
334
+
335
+ let!(:main) { write_input_file('main', '#include "header"') }
336
+ let!(:header) { write_input_file('header', 'header') }
337
+ let!(:main_output) { output_file('main') }
338
+ let(:input_files) { [main] }
339
+ let(:filter) { include_filter.new }
340
+
341
+ it "creates its output files" do
342
+ invoke_filter(filter)
343
+ main_output.exists?.should be_true
344
+ main_output.read.should == %[header\n#include "header"\n]
345
+ end
346
+
347
+ it "rebuilds main file when it changes" do
348
+ invoke_filter(filter)
349
+ sleep 1
350
+ File.open(main.fullpath, 'w') { |f| f.puts 'PEANUTS' }
351
+ filter.rake_tasks.each { |t| t.recursively_reenable(Rake.application) }
352
+ invoke_filter(filter)
353
+ main_output.read.should == %[PEANUTS\n]
354
+ end
355
+
356
+ it "rebuilds the main file when a dynamic dependency changes" do
357
+ invoke_filter(filter)
358
+ sleep 1
359
+ $LATCH = true
360
+ File.open(header.fullpath, 'w') { |f| f.puts 'PEANUTS' }
361
+ filter.rake_tasks.each { |t| t.recursively_reenable(Rake.application) }
362
+ invoke_filter(filter)
363
+ main_output.read.should == %[PEANUTS\n#include "header"\n]
364
+ end
365
+ end
366
+ end
367
+