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,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
+