rake-pipeline-web-filters-fork 0.6.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/.gitignore +19 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +11 -0
  4. data/.yardopts +2 -0
  5. data/Gemfile +6 -0
  6. data/README.markdown +58 -0
  7. data/README.yard +25 -0
  8. data/Rakefile +10 -0
  9. data/lib/rake-pipeline-web-filters.rb +31 -0
  10. data/lib/rake-pipeline-web-filters/cache_buster_filter.rb +42 -0
  11. data/lib/rake-pipeline-web-filters/chained_filter.rb +116 -0
  12. data/lib/rake-pipeline-web-filters/coffee_script_filter.rb +41 -0
  13. data/lib/rake-pipeline-web-filters/filter_with_dependencies.rb +27 -0
  14. data/lib/rake-pipeline-web-filters/gzip_filter.rb +59 -0
  15. data/lib/rake-pipeline-web-filters/handlebars_filter.rb +62 -0
  16. data/lib/rake-pipeline-web-filters/helpers.rb +138 -0
  17. data/lib/rake-pipeline-web-filters/iife_filter.rb +38 -0
  18. data/lib/rake-pipeline-web-filters/jade_filter.rb +61 -0
  19. data/lib/rake-pipeline-web-filters/less_filter.rb +55 -0
  20. data/lib/rake-pipeline-web-filters/markdown_filter.rb +70 -0
  21. data/lib/rake-pipeline-web-filters/minispade_filter.rb +63 -0
  22. data/lib/rake-pipeline-web-filters/neuter_filter.rb +110 -0
  23. data/lib/rake-pipeline-web-filters/sass_filter.rb +87 -0
  24. data/lib/rake-pipeline-web-filters/stylus_filter.rb +59 -0
  25. data/lib/rake-pipeline-web-filters/tilt_filter.rb +70 -0
  26. data/lib/rake-pipeline-web-filters/uglify_filter.rb +82 -0
  27. data/lib/rake-pipeline-web-filters/version.rb +9 -0
  28. data/lib/rake-pipeline-web-filters/yui_css_filter.rb +70 -0
  29. data/lib/rake-pipeline-web-filters/yui_javascript_filter.rb +59 -0
  30. data/rake-pipeline-web-filters.gemspec +33 -0
  31. data/spec/cache_buster_filter_spec.rb +108 -0
  32. data/spec/chained_filter_spec.rb +79 -0
  33. data/spec/coffee_script_filter_spec.rb +113 -0
  34. data/spec/gzip_filter_spec.rb +52 -0
  35. data/spec/handlebars_filter_spec.rb +73 -0
  36. data/spec/helpers_spec.rb +146 -0
  37. data/spec/iife_filter_spec.rb +58 -0
  38. data/spec/jade_filter_spec.rb +92 -0
  39. data/spec/less_filter_spec.rb +62 -0
  40. data/spec/markdown_filter_spec.rb +89 -0
  41. data/spec/minispade_filter_spec.rb +82 -0
  42. data/spec/neuter_filter_spec.rb +216 -0
  43. data/spec/sass_filter_spec.rb +152 -0
  44. data/spec/spec_helper.rb +28 -0
  45. data/spec/stylus_filter_spec.rb +72 -0
  46. data/spec/support/spec_helpers/file_utils.rb +33 -0
  47. data/spec/support/spec_helpers/filters.rb +37 -0
  48. data/spec/support/spec_helpers/input_helpers.rb +23 -0
  49. data/spec/support/spec_helpers/memory_file_wrapper.rb +38 -0
  50. data/spec/support/spec_helpers/memory_manifest.rb +19 -0
  51. data/spec/tilt_filter_spec.rb +82 -0
  52. data/spec/uglify_filter_spec.rb +128 -0
  53. data/spec/yui_css_filter_spec.rb +91 -0
  54. data/spec/yui_javascript_filter_spec.rb +71 -0
  55. metadata +308 -0
@@ -0,0 +1,59 @@
1
+ require 'rake-pipeline-web-filters/filter_with_dependencies'
2
+
3
+ module Rake::Pipeline::Web::Filters
4
+ # A filter that compresses JavaScript input files using
5
+ # the YUI JavaScript compressor.
6
+ #
7
+ # Requires {https://rubygems.org/gems/yui-compressor yui-compressor}
8
+ #
9
+ # @example
10
+ # !!!ruby
11
+ # Rake::Pipeline.build do
12
+ # input "app/assets", "**/*.js"
13
+ # output "public"
14
+ #
15
+ # # Compress each JS file under the app/assets
16
+ # # directory.
17
+ # filter Rake::Pipeline::Web::Filters::YUIJavaScriptFilter
18
+ # end
19
+ class YUIJavaScriptFilter < Rake::Pipeline::Filter
20
+ include Rake::Pipeline::Web::Filters::FilterWithDependencies
21
+
22
+ # @return [Hash] a hash of options to pass to the
23
+ # YUI compressor when compressing.
24
+ attr_reader :options
25
+
26
+ # @param [Hash] options options to pass to the YUI
27
+ # JavaScript compressor.
28
+ # @param [Proc] block a block to use as the Filter's
29
+ # {#output_name_generator}.
30
+ def initialize(options={}, &block)
31
+ block ||= proc { |input| input.sub(/\.js$/, '.min.js') }
32
+ super(&block)
33
+ @options = options
34
+ end
35
+
36
+ # Implement the {#generate_output} method required by
37
+ # the {Filter} API. Compresses each input file with
38
+ # the YUI JavaScript compressor.
39
+ #
40
+ # @param [Array<FileWrapper>] inputs an Array of
41
+ # {FileWrapper} objects representing the inputs to
42
+ # this filter.
43
+ # @param [FileWrapper] output a single {FileWrapper}
44
+ # object representing the output.
45
+ def generate_output(inputs, output)
46
+ compressor = YUI::JavaScriptCompressor.new(options)
47
+ inputs.each do |input|
48
+ output.write compressor.compress(input.read)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def external_dependencies
55
+ [ 'yui/compressor' ]
56
+ end
57
+ end
58
+ end
59
+
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/rake-pipeline-web-filters/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Yehuda Katz"]
6
+ gem.email = ["wycats@gmail.com"]
7
+ gem.description = %q{A collection of web filters for rake-pipeline}
8
+ gem.summary = %q{Contributed filters for use in rake-pipeline that are useful for web projects, like asset management}
9
+ gem.homepage = "http://github.com/wycats/rake-pipeline-web-filters"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "rake-pipeline-web-filters-fork"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Rake::Pipeline::Web::Filters::VERSION
17
+
18
+ gem.add_dependency "rake-pipeline", "~> 0.6"
19
+ gem.add_dependency "rack"
20
+
21
+ gem.add_development_dependency "rspec"
22
+ gem.add_development_dependency "tilt"
23
+ gem.add_development_dependency "sass"
24
+ gem.add_development_dependency "compass"
25
+ gem.add_development_dependency "coffee-script"
26
+ gem.add_development_dependency "redcarpet", '~> 2.0'
27
+ gem.add_development_dependency "yui-compressor"
28
+ gem.add_development_dependency "uglifier"
29
+ gem.add_development_dependency "less"
30
+ gem.add_development_dependency "json"
31
+ gem.add_development_dependency "therubyracer"
32
+ gem.add_development_dependency "stylus"
33
+ end
@@ -0,0 +1,108 @@
1
+ describe "CacheBusterFilter" do
2
+ MemoryFileWrapper ||= Rake::Pipeline::SpecHelpers::MemoryFileWrapper
3
+ MemoryManifest ||= Rake::Pipeline::SpecHelpers::MemoryManifest
4
+ CacheBusterFilter ||= Rake::Pipeline::Web::Filters::CacheBusterFilter
5
+
6
+ let(:content) { "it doesn't matter" }
7
+
8
+ let(:input_file) {
9
+ MemoryFileWrapper.new '/path/to/input', 'file.txt', 'UTF-8', content
10
+ }
11
+
12
+ let(:output_root) {
13
+ '/path/to/output'
14
+ }
15
+
16
+ def setup_filter(filter)
17
+ filter.file_wrapper_class = MemoryFileWrapper
18
+ filter.manifest = MemoryManifest.new
19
+ filter.last_manifest = MemoryManifest.new
20
+ filter.input_files = [ input_file ]
21
+ filter.output_root = output_root
22
+ filter.rake_application = Rake::Application.new
23
+ filter
24
+ end
25
+
26
+ describe 'DEFAULT_KEY_GENERATOR' do
27
+
28
+ subject { CacheBusterFilter::DEFAULT_KEY_GENERATOR }
29
+
30
+ it "returns the MD5 hash of the input's file name and contents" do
31
+ expected = Digest::MD5.new << input_file.path << content
32
+ subject.call(input_file).should == expected
33
+ end
34
+
35
+ end
36
+
37
+ describe 'with the default cache key strategy' do
38
+
39
+ let(:output_file) {
40
+ key = CacheBusterFilter::DEFAULT_KEY_GENERATOR.call(input_file)
41
+ MemoryFileWrapper.new output_root, "file-#{key}.txt", 'UTF-8'
42
+ }
43
+
44
+ subject { setup_filter CacheBusterFilter.new }
45
+
46
+ it 'outputs to the MD5 hash of the file name and contents' do
47
+ subject.output_files.should == [ output_file ]
48
+ end
49
+
50
+ it 'passes file contents through unchanged' do
51
+ tasks = subject.generate_rake_tasks
52
+ tasks.each(&:invoke)
53
+ file = MemoryFileWrapper.files[ output_file.fullpath ]
54
+ file.body.should == content
55
+ file.encoding.should == 'UTF-8'
56
+ end
57
+
58
+ end
59
+
60
+ describe 'with a custom key strategy' do
61
+
62
+ let(:output_file) {
63
+ MemoryFileWrapper.new output_root, 'file-foo.txt', 'UTF-8'
64
+ }
65
+
66
+ subject do
67
+ setup_filter(CacheBusterFilter.new() { 'foo' })
68
+ end
69
+
70
+ it 'uses the custom key strategy' do
71
+ subject.output_files.should == [ output_file ]
72
+ end
73
+
74
+ end
75
+
76
+ describe 'for an input file with multiple dots' do
77
+ let(:input_file) {
78
+ MemoryFileWrapper.new '/path/to/input', 'my.text.file.txt', 'UTF-8', content
79
+ }
80
+
81
+ let(:output_file) {
82
+ MemoryFileWrapper.new output_root, "my.text.file-foo.txt", 'UTF-8'
83
+ }
84
+
85
+ subject { setup_filter(CacheBusterFilter.new() { 'foo' }) }
86
+
87
+ it 'appends the busting key to the penultimate part' do
88
+ subject.output_files.should == [ output_file ]
89
+ end
90
+ end
91
+
92
+ describe 'for an input file with no dots' do
93
+ let(:input_file) {
94
+ MemoryFileWrapper.new '/path/to/input', 'my_text_file', 'UTF-8', content
95
+ }
96
+
97
+ let(:output_file) {
98
+ MemoryFileWrapper.new output_root, "my_text_file-foo", 'UTF-8'
99
+ }
100
+
101
+ subject { setup_filter(CacheBusterFilter.new() { 'foo' }) }
102
+
103
+ it 'appends the busting key to the end of the filename' do
104
+ subject.output_files.should == [ output_file ]
105
+ end
106
+ end
107
+
108
+ end
@@ -0,0 +1,79 @@
1
+ describe "ChainedFilter" do
2
+ MemoryFileWrapper ||= Rake::Pipeline::SpecHelpers::MemoryFileWrapper
3
+ MemoryManifest ||= Rake::Pipeline::SpecHelpers::MemoryManifest
4
+ ChainedFilter ||= Rake::Pipeline::Web::Filters::ChainedFilter
5
+
6
+ input_file1 = MemoryFileWrapper.new("/path", "input.js.strip_asserts.erb", "UTF-8", <<-CONTENT)
7
+ assert("must be true", true);
8
+ Input = {};
9
+ <%= $chained_filter_title %> = {};
10
+ CONTENT
11
+
12
+ input_file2 = MemoryFileWrapper.new("/path", "input.js.erb.strip_asserts", "UTF-8", <<-CONTENT)
13
+ assert("must be true", true);
14
+ Input = {};
15
+ <%= $chained_filter_title %> = {};
16
+ CONTENT
17
+
18
+ EXPECTED_OUTPUT = <<-EXPECTED
19
+
20
+ Input = {};
21
+ Chained = {};
22
+ EXPECTED
23
+
24
+ let(:erb_filter) do
25
+ Class.new(Rake::Pipeline::Filter) do
26
+ def generate_output(inputs, output)
27
+ inputs.each do |input|
28
+ output.write ERB.new(input.read).result
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ let(:strip_asserts_filter) do
35
+ Class.new(Rake::Pipeline::Filter) do
36
+ def generate_output(inputs, output)
37
+ inputs.each do |input|
38
+ output.write input.read.gsub(/^assert.*$/, '')
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ before do
45
+ $chained_filter_title = "Chained"
46
+ end
47
+
48
+ after do
49
+ $chained_filter_title = nil
50
+ end
51
+
52
+ [ input_file1, input_file2 ].each do |file_wrapper|
53
+ it "should run through the filters in order" do
54
+ filter = ChainedFilter.new(
55
+ :types => {
56
+ :erb => erb_filter,
57
+ :strip_asserts => strip_asserts_filter
58
+ }
59
+ )
60
+
61
+ filter.file_wrapper_class = MemoryFileWrapper
62
+ filter.manifest = MemoryManifest.new
63
+ filter.last_manifest = MemoryManifest.new
64
+ filter.input_files = [ file_wrapper ]
65
+ filter.output_root = "/output"
66
+ filter.rake_application = Rake::Application.new
67
+
68
+ filter.output_files.should == [ MemoryFileWrapper.new("/output", "input.js", "UTF-8") ]
69
+
70
+ tasks = filter.generate_rake_tasks
71
+ tasks.each(&:invoke)
72
+
73
+ file = MemoryFileWrapper.files["/output/input.js"]
74
+ file.body.should == EXPECTED_OUTPUT
75
+ file.encoding.should == "UTF-8"
76
+ end
77
+ end
78
+
79
+ end
@@ -0,0 +1,113 @@
1
+ describe "CoffeeScriptFilter" do
2
+ CoffeeScriptFilter ||= Rake::Pipeline::Web::Filters::CoffeeScriptFilter
3
+ MemoryFileWrapper ||= Rake::Pipeline::SpecHelpers::MemoryFileWrapper
4
+ MemoryManifest ||= Rake::Pipeline::SpecHelpers::MemoryManifest
5
+
6
+ let(:coffee_input) { <<-COFFEE }
7
+ x = 1;
8
+
9
+ y = ->
10
+ x += 1
11
+ COFFEE
12
+
13
+ let(:expected_coffee_output) { <<-HTML }
14
+ (function() {
15
+ var x, y;
16
+
17
+ x = 1;
18
+
19
+ y = function() {
20
+ return x += 1;
21
+ };
22
+
23
+ }).call(this);
24
+ HTML
25
+
26
+ let(:expected_unwrapped_coffee_output) { <<-HTML }
27
+ var x, y;
28
+
29
+ x = 1;
30
+
31
+ y = function() {
32
+ return x += 1;
33
+ };
34
+ HTML
35
+
36
+ def input_file(name, content)
37
+ MemoryFileWrapper.new("/path/to/input", name, "UTF-8", content)
38
+ end
39
+
40
+ def output_file(name)
41
+ MemoryFileWrapper.new("/path/to/output", name, "UTF-8")
42
+ end
43
+
44
+ def should_match(expected, output)
45
+ "#{expected}\n".gsub(/\n+/, "\n").should == "#{output}\n".gsub(/\n+/, "\n")
46
+ end
47
+
48
+ def setup_filter(filter)
49
+ filter.file_wrapper_class = MemoryFileWrapper
50
+ filter.manifest = MemoryManifest.new
51
+ filter.last_manifest = MemoryManifest.new
52
+ filter.input_files = [input_file("input.coffee", coffee_input)]
53
+ filter.output_root = "/path/to/output"
54
+ filter.rake_application = Rake::Application.new
55
+ filter
56
+ end
57
+
58
+ it "generates output" do
59
+ filter = setup_filter CoffeeScriptFilter.new
60
+
61
+ filter.output_files.should == [output_file("input.js")]
62
+
63
+ tasks = filter.generate_rake_tasks
64
+ tasks.each(&:invoke)
65
+
66
+ file = MemoryFileWrapper.files["/path/to/output/input.js"]
67
+ should_match file.body, expected_coffee_output
68
+ file.encoding.should == "UTF-8"
69
+ end
70
+
71
+ it "generates unwrapped output" do
72
+ filter = setup_filter CoffeeScriptFilter.new(:no_wrap => true)
73
+
74
+ filter.output_files.should == [output_file("input.js")]
75
+
76
+ tasks = filter.generate_rake_tasks
77
+ tasks.each(&:invoke)
78
+
79
+ file = MemoryFileWrapper.files["/path/to/output/input.js"]
80
+ should_match file.body, expected_unwrapped_coffee_output
81
+ file.encoding.should == "UTF-8"
82
+ end
83
+
84
+ describe "naming output files" do
85
+ it "translates .coffee extensions to .js by default" do
86
+ filter = setup_filter CoffeeScriptFilter.new
87
+ filter.output_files.first.path.should == "input.js"
88
+ end
89
+
90
+ it "accepts a block to customize output file names" do
91
+ filter = setup_filter(CoffeeScriptFilter.new { |input| "octopus" })
92
+ filter.output_files.first.path.should == "octopus"
93
+ end
94
+ end
95
+
96
+ describe "invalid input" do
97
+ let(:coffee_input) { <<-COFFEE }
98
+ y = function(){
99
+ return "whoops there javascript in here!"
100
+ }
101
+ COFFEE
102
+
103
+ it "has a useful error message including the input file name" do
104
+ filter = setup_filter CoffeeScriptFilter.new
105
+ tasks = filter.generate_rake_tasks
106
+ lambda {
107
+ tasks.each(&:invoke)
108
+ }.should raise_error(ExecJS::RuntimeError, /Error compiling input.coffee.+line 1/i)
109
+ end
110
+ end
111
+
112
+ end
113
+
@@ -0,0 +1,52 @@
1
+ require 'base64'
2
+ require 'stringio'
3
+ require 'zlib'
4
+
5
+ describe "GzipFilter" do
6
+ GzipFilter ||= Rake::Pipeline::Web::Filters::GzipFilter
7
+ MemoryFileWrapper ||= Rake::Pipeline::SpecHelpers::MemoryFileWrapper
8
+ MemoryManifest ||= Rake::Pipeline::SpecHelpers::MemoryManifest
9
+
10
+ let(:input) { "(function(){console.log('gzip me')})();" }
11
+
12
+ def input_file(name, content)
13
+ MemoryFileWrapper.new("/path/to/input", name, "UTF-8", content)
14
+ end
15
+
16
+ def output_file(name)
17
+ MemoryFileWrapper.new("/path/to/output", name, "BINARY")
18
+ end
19
+
20
+ def setup_filter(filter)
21
+ filter.file_wrapper_class = MemoryFileWrapper
22
+ filter.manifest = MemoryManifest.new
23
+ filter.last_manifest = MemoryManifest.new
24
+ filter.input_files = [input_file("test.js", input)]
25
+ filter.output_root = "/path/to/output"
26
+ filter.rake_application = Rake::Application.new
27
+ filter
28
+ end
29
+
30
+ it "generates output" do
31
+ filter = setup_filter GzipFilter.new
32
+ filter.output_files.should == [output_file("test.js.gz")]
33
+ tasks = filter.generate_rake_tasks
34
+ tasks.each(&:invoke)
35
+ file = MemoryFileWrapper.files["/path/to/output/test.js.gz"]
36
+ Zlib::GzipReader.new(StringIO.new(file.body)).read.should == input
37
+ end
38
+
39
+ describe "naming output files" do
40
+ it "translates extensions to .*.gz by default" do
41
+ filter = setup_filter GzipFilter.new
42
+ filter.output_files.first.path.should == "test.js.gz"
43
+ end
44
+
45
+ it "accepts a block to customize output file names" do
46
+ filter = setup_filter(GzipFilter.new { |input| "octopus" })
47
+ filter.output_files.first.path.should == "octopus"
48
+ end
49
+ end
50
+
51
+ end
52
+