rake-pipeline-web-filters-fork 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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,110 @@
1
+ module Rake::Pipeline::Web::Filters
2
+
3
+ class NeuterBatch
4
+ def initialize(config, known_files)
5
+ @config = config || {}
6
+ @known_files = known_files
7
+ @required = []
8
+ end
9
+
10
+ def file_wrapper(klass, *args)
11
+ file = klass.new(*args)
12
+ file.extend NeuterWrapper
13
+ file.batch(self)
14
+ file
15
+ end
16
+
17
+ def required(req)
18
+ unless @known_files.include?(req)
19
+ warn "Included '#{req}', which is not listed in :additional_dependencies. The pipeline may not invalidate properly."
20
+ end
21
+ @required << req
22
+ end
23
+
24
+ def required?(req)
25
+ @required.include?(req)
26
+ end
27
+
28
+ def strip_requires(source)
29
+ requires = []
30
+ regexp = @config[:require_regexp] || %r{^\s*require\(['"]([^'"]*)['"]\);?\s*}
31
+ # FIXME: This $1 may not be reliable with other regexps
32
+ source.gsub!(regexp){ requires << $1; '' }
33
+ requires
34
+ end
35
+
36
+ def transform_path(path, input)
37
+ @config[:path_transform] ? @config[:path_transform].call(path, input) : path
38
+ end
39
+
40
+ def closure_wrap(source)
41
+ @config[:closure_wrap] ? "(function() {\n#{source}\n})();\n\n" : source
42
+ end
43
+
44
+ def filename_comment(input)
45
+ @config[:filename_comment] ? @config[:filename_comment].call(input) + "\n" : ""
46
+ end
47
+ end
48
+
49
+ module NeuterWrapper
50
+ def batch(batch)
51
+ @batch = batch
52
+ @batch.required(fullpath)
53
+ end
54
+
55
+ def read
56
+ source = super
57
+
58
+ required_files = @batch.strip_requires(source).map do |req|
59
+ req_path = @batch.transform_path(req, self)
60
+ if req_path && !@batch.required?(File.expand_path(req_path, root))
61
+ @batch.file_wrapper(self.class, root, req_path, encoding).read
62
+ else
63
+ nil
64
+ end
65
+ end.compact
66
+
67
+ file = @batch.filename_comment(self) + @batch.closure_wrap(source)
68
+
69
+ (required_files << file).join("\n\n")
70
+ end
71
+ end
72
+
73
+ # A filter that takes files with requires and collapses them into a single
74
+ # file without requires.
75
+ #
76
+ # @example
77
+ # !!!ruby
78
+ # Rake::Pipeline.build do
79
+ # input "app/assets", "**/*.js"
80
+ # output "public"
81
+ #
82
+ # filter Rake::Pipeline::Web::Filters::NeuterFilter, "neutered.js"
83
+ # end
84
+ class NeuterFilter < Rake::Pipeline::ConcatFilter
85
+ def initialize(string=nil, config={}, &block)
86
+ if string.is_a?(Hash)
87
+ config = string
88
+ string = nil
89
+ end
90
+
91
+ @config = config
92
+
93
+ super(string, &block)
94
+ end
95
+
96
+ def generate_output(inputs, output)
97
+ inputs.each do |input|
98
+ known_files = [input.fullpath] + additional_dependencies(input)
99
+ batch = NeuterBatch.new(@config, known_files)
100
+ file = batch.file_wrapper(file_wrapper_class, input.root, input.path, input.encoding)
101
+ output.write file.read
102
+ end
103
+ end
104
+
105
+ def additional_dependencies(input)
106
+ method = @config[:additional_dependencies]
107
+ method ? method.call(input).map{|p| File.expand_path(p, input.root) } : []
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,87 @@
1
+ require 'rake-pipeline-web-filters/filter_with_dependencies'
2
+
3
+ module Rake::Pipeline::Web::Filters
4
+ # A filter that compiles input files written in SCSS
5
+ # to CSS using the Sass compiler and the Compass CSS
6
+ # framework.
7
+ #
8
+ # Requires {http://rubygems.org/gems/sass sass} and
9
+ # {http://rubygems.org/gems/compass compass}
10
+ #
11
+ # @example
12
+ # !!!ruby
13
+ # Rake::Pipeline.build do
14
+ # input "app/assets", "**/*.scss"
15
+ # output "public"
16
+ #
17
+ # # Compile each SCSS file under the app/assets
18
+ # # directory.
19
+ # filter Rake::Pipeline::Web::Filters::SassFilter
20
+ # end
21
+ class SassFilter < Rake::Pipeline::Filter
22
+ include Rake::Pipeline::Web::Filters::FilterWithDependencies
23
+
24
+ # @return [Hash] a hash of options to pass to Sass
25
+ # when compiling.
26
+ attr_reader :options, :additional_load_paths
27
+
28
+ # @param [Hash] options options to pass to the Sass
29
+ # compiler
30
+ # @option options [Array] :additional_load_paths a
31
+ # list of paths to append to Sass's :load_path.
32
+ # @param [Proc] block a block to use as the Filter's
33
+ # {#output_name_generator}.
34
+ def initialize(options={}, &block)
35
+ block ||= proc { |input| input.sub(/\.(scss|sass)$/, '.css') }
36
+ super(&block)
37
+
38
+ @options = compass_options
39
+ @additional_load_paths = Array(options.delete(:additional_load_paths))
40
+ @options[:load_paths].concat(@additional_load_paths)
41
+ @options.merge!(options)
42
+ end
43
+
44
+ # Implement the {#generate_output} method required by
45
+ # the {Filter} API. Compiles each input file with Sass.
46
+ #
47
+ # @param [Array<FileWrapper>] inputs an Array of
48
+ # {FileWrapper} objects representing the inputs to
49
+ # this filter.
50
+ # @param [FileWrapper] output a single {FileWrapper}
51
+ # object representing the output.
52
+ def generate_output(inputs, output)
53
+ inputs.each do |input|
54
+ output.write Sass.compile(input.read, sass_options_for_file(input))
55
+ end
56
+ end
57
+
58
+ def additional_dependencies(input)
59
+ engine = Sass::Engine.new(input.read, sass_options_for_file(input))
60
+ engine.dependencies.map { |dep| dep.options[:filename] }
61
+ end
62
+
63
+ private
64
+
65
+ def external_dependencies
66
+ [ 'sass', 'compass' ]
67
+ end
68
+
69
+ # @return the Sass options for the current Compass
70
+ # configuration.
71
+ def compass_options
72
+ Compass.add_project_configuration
73
+ Compass.configuration.to_sass_engine_options
74
+ end
75
+
76
+ # @return the Sass options for the given +file+.
77
+ # Adds a +:syntax+ option if the filter's options
78
+ # don't already include one.
79
+ def sass_options_for_file(file)
80
+ added_opts = {
81
+ :filename => file.fullpath,
82
+ :syntax => file.path.match(/\.sass$/) ? :sass : :scss
83
+ }
84
+ added_opts.merge(@options)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,59 @@
1
+ require 'rake-pipeline-web-filters/filter_with_dependencies'
2
+
3
+ module Rake::Pipeline::Web::Filters
4
+ # A filter that compiles input files written in Stylus
5
+ # to CSS using the Stylus compiler
6
+ #
7
+ # Requires http://rubygems.org/gems/stylus
8
+ #
9
+ # You will need the `node` command on your runtime
10
+ # for this to work. See https://github.com/lucasmazza/ruby-stylus
11
+ # for more information.
12
+ #
13
+ # @example
14
+ # !!!ruby
15
+ # Rake::Pipeline.build do
16
+ # input "app/assets", "**/*.styl"
17
+ # output "public"
18
+ #
19
+ # # Compile each Stylus file under the app/assets
20
+ # # directory.
21
+ # filter Rake::Pipeline::Web::Filters::StylusFilter
22
+ # end
23
+ class StylusFilter < Rake::Pipeline::Filter
24
+ include Rake::Pipeline::Web::Filters::FilterWithDependencies
25
+
26
+ attr_reader :options
27
+
28
+ # @param [Hash] options options to pass to Stylus
29
+ # @option options [Array] :use Plugins to import from Node
30
+ # @option options [Boolean] :debug Output debug info
31
+ # @param [Proc] block a block to use as the Filter's
32
+ # {#output_name_generator}.
33
+ def initialize(options={}, &block)
34
+ block ||= proc { |input| input.sub(/\.(styl)$/, '.css') }
35
+ super(&block)
36
+ @options = options
37
+ end
38
+
39
+ def generate_output(inputs, output)
40
+ options.each do |key, value|
41
+ if key == :use
42
+ Stylus.send key, *value
43
+ next
44
+ end
45
+ Stylus.send "#{key}=", value
46
+ end
47
+ inputs.each do |input|
48
+ output.write Stylus.compile(input.read)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def external_dependencies
55
+ [ 'stylus' ]
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,70 @@
1
+ require 'rake-pipeline-web-filters/filter_with_dependencies'
2
+
3
+ module Rake::Pipeline::Web::Filters
4
+ # A filter that accepts a series of inputs and translates
5
+ # them using the Tilt template interface, which will attempt
6
+ # to guess which template language to use based on the input
7
+ # file extension.
8
+ #
9
+ # Requires {http://rubygems.org/gems/tilt/ tilt}
10
+ #
11
+ # @example
12
+ # !!!ruby
13
+ # Rake::Pipeline.build do
14
+ # input "app/assets", "**/*.scss"
15
+ # output "public"
16
+ #
17
+ # # Compile each SCSS file using Tilt, replacing the
18
+ # # scss extension with css.
19
+ # filter(Rake::Pipeline::Web::Filters::TiltFilter) do |input|
20
+ # input.sub(/\.scss$/, 'css')
21
+ # end
22
+ # end
23
+ class TiltFilter < Rake::Pipeline::Filter
24
+ include Rake::Pipeline::Web::Filters::FilterWithDependencies
25
+
26
+ # @return [Hash] a hash of options to pass to Tilt
27
+ # when rendering.
28
+ attr_reader :options
29
+
30
+ # @return [Object] an object to use as the rendering
31
+ # context.
32
+ attr_reader :context
33
+
34
+ # @param [Hash] options options to pass to the Tilt
35
+ # template class constructor.
36
+ # @param [Proc] block a block to use as the Filter's
37
+ # {#output_name_generator}.
38
+ def initialize(options={}, context = nil, &block)
39
+ super(&block)
40
+ @options = options
41
+ @context = context || Object.new
42
+ end
43
+
44
+ # Implement the {#generate_output} method required by
45
+ # the {Filter} API. Attempts to compile each input file
46
+ # with Tilt, passing the file through unchanged if Tilt
47
+ # can't find a template class for the file.
48
+ #
49
+ # @param [Array<FileWrapper>] inputs an Array of
50
+ # {FileWrapper} objects representing the inputs to
51
+ # this filter.
52
+ # @param [FileWrapper] output a single {FileWrapper}
53
+ # object representing the output.
54
+ def generate_output(inputs, output)
55
+ inputs.each do |input|
56
+ out = if (template_class = Tilt[input.path])
57
+ template_class.new(nil, 1, options) { |t| input.read }.render(context)
58
+ else
59
+ input.read
60
+ end
61
+
62
+ output.write out
63
+ end
64
+ end
65
+
66
+ def external_dependencies
67
+ [ 'tilt' ]
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,82 @@
1
+ require 'rake-pipeline-web-filters/filter_with_dependencies'
2
+
3
+ module Rake::Pipeline::Web::Filters
4
+ # A filter that uses the Uglify JS compressor to compress
5
+ # JavaScript input files.
6
+ #
7
+ # Requires {http://rubygems.org/gems/uglifier uglifier}.
8
+ #
9
+ # @example
10
+ # !!!ruby
11
+ # Rake::Pipeline.build do
12
+ # input "app/assets", "**/*.js"
13
+ # output "public"
14
+ #
15
+ # # Compile each JS file under the app/assets
16
+ # # directory.
17
+ # filter Rake::Pipeline::Web::Filters::UglifyFilter
18
+ # end
19
+ class UglifyFilter < Rake::Pipeline::Filter
20
+ include Rake::Pipeline::Web::Filters::FilterWithDependencies
21
+
22
+ # @return [Hash] a hash of options to pass to Uglify
23
+ # when compiling.
24
+ attr_reader :options
25
+
26
+ # @param [Hash] options options to pass to Uglify
27
+ # @param [Proc] block a block to use as the Filter's
28
+ # {#output_name_generator}.
29
+ def initialize(options={}, &block)
30
+ block ||= proc { |input|
31
+ if input =~ %r{.min.js$}
32
+ input
33
+ else
34
+ input.sub(/\.js$/, '.min.js')
35
+ end
36
+ }
37
+
38
+ @preserve_input = options.delete :preserve_input
39
+
40
+ super(&block)
41
+ @options = options
42
+ end
43
+
44
+ def should_skip_minify?(input, output)
45
+ (@preserve_input && input.path == output.path) ||
46
+ input.path =~ %r{.min.js$}
47
+ end
48
+
49
+ # Implement the {#generate_output} method required by
50
+ # the {Filter} API. Compiles each input file with Uglify.
51
+ #
52
+ # @param [Array<FileWrapper>] inputs an Array of
53
+ # {FileWrapper} objects representing the inputs to
54
+ # this filter.
55
+ # @param [FileWrapper] output a single {FileWrapper}
56
+ # object representing the output.
57
+ def generate_output(inputs, output)
58
+ inputs.each do |input|
59
+ if should_skip_minify?(input, output)
60
+ output.write input.read
61
+ else
62
+ output.write Uglifier.compile(input.read, options)
63
+ end
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def output_paths(input)
70
+ paths = super(input)
71
+ if @preserve_input
72
+ raise 'cannot preserve unminified input if output path is not different' if paths.include?(input.path)
73
+ paths.unshift(input.path)
74
+ end
75
+ paths
76
+ end
77
+
78
+ def external_dependencies
79
+ [ 'uglifier' ]
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,9 @@
1
+ module Rake
2
+ class Pipeline
3
+ module Web
4
+ module Filters
5
+ VERSION = "0.6.0"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,70 @@
1
+ require 'rake-pipeline-web-filters/filter_with_dependencies'
2
+
3
+ module Rake::Pipeline::Web::Filters
4
+ # A filter that compresses CSS input files using
5
+ # the YUI CSS 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 CSS file under the app/assets
16
+ # # directory.
17
+ # filter Rake::Pipeline::Web::Filters::YUICssFilter
18
+ # end
19
+ class YUICssFilter < 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
+ # CSS 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|
32
+ if input =~ %r{min.css$}
33
+ input
34
+ else
35
+ input.sub /\.css$/, '.min.css'
36
+ end
37
+ }
38
+
39
+ super(&block)
40
+ @options = options
41
+ end
42
+
43
+ # Implement the {#generate_output} method required by
44
+ # the {Filter} API. Compresses each input file with
45
+ # the YUI CSS compressor.
46
+ #
47
+ # @param [Array<FileWrapper>] inputs an Array of
48
+ # {FileWrapper} objects representing the inputs to
49
+ # this filter.
50
+ # @param [FileWrapper] output a single {FileWrapper}
51
+ # object representing the output.
52
+ def generate_output(inputs, output)
53
+ compressor = YUI::CssCompressor.new(options)
54
+ inputs.each do |input|
55
+ if input.path !~ /min\.css/
56
+ output.write compressor.compress(input.read)
57
+ else
58
+ output.write input.read
59
+ end
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def external_dependencies
66
+ [ 'yui/compressor' ]
67
+ end
68
+ end
69
+ end
70
+