rake-pipeline-web-filters 0.5.0 → 0.7.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 (47) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +1 -0
  3. data/Rakefile +8 -0
  4. data/lib/rake-pipeline-web-filters.rb +17 -3
  5. data/lib/rake-pipeline-web-filters/cache_buster_filter.rb +42 -0
  6. data/lib/rake-pipeline-web-filters/chained_filter.rb +116 -0
  7. data/lib/rake-pipeline-web-filters/coffee_script_filter.rb +41 -0
  8. data/lib/rake-pipeline-web-filters/filter_with_dependencies.rb +27 -0
  9. data/lib/rake-pipeline-web-filters/gzip_filter.rb +59 -0
  10. data/lib/rake-pipeline-web-filters/handlebars_filter.rb +62 -0
  11. data/lib/rake-pipeline-web-filters/helpers.rb +100 -18
  12. data/lib/rake-pipeline-web-filters/iife_filter.rb +38 -0
  13. data/lib/rake-pipeline-web-filters/less_filter.rb +55 -0
  14. data/lib/rake-pipeline-web-filters/markdown_filter.rb +70 -0
  15. data/lib/rake-pipeline-web-filters/minispade_filter.rb +21 -5
  16. data/lib/rake-pipeline-web-filters/neuter_filter.rb +110 -0
  17. data/lib/rake-pipeline-web-filters/sass_filter.rb +87 -0
  18. data/lib/rake-pipeline-web-filters/stylus_filter.rb +59 -0
  19. data/lib/rake-pipeline-web-filters/tilt_filter.rb +16 -3
  20. data/lib/rake-pipeline-web-filters/uglify_filter.rb +66 -0
  21. data/lib/rake-pipeline-web-filters/version.rb +1 -1
  22. data/lib/rake-pipeline-web-filters/yui_css_filter.rb +70 -0
  23. data/lib/rake-pipeline-web-filters/yui_javascript_filter.rb +59 -0
  24. data/rake-pipeline-web-filters.gemspec +10 -1
  25. data/spec/cache_buster_filter_spec.rb +105 -0
  26. data/spec/chained_filter_spec.rb +76 -0
  27. data/spec/coffee_script_filter_spec.rb +110 -0
  28. data/spec/gzip_filter_spec.rb +49 -0
  29. data/spec/handlebars_filter_spec.rb +70 -0
  30. data/spec/helpers_spec.rb +112 -18
  31. data/spec/iife_filter_spec.rb +55 -0
  32. data/spec/less_filter_spec.rb +59 -0
  33. data/spec/markdown_filter_spec.rb +86 -0
  34. data/spec/minispade_filter_spec.rb +47 -15
  35. data/spec/neuter_filter_spec.rb +204 -0
  36. data/spec/sass_filter_spec.rb +147 -0
  37. data/spec/spec_helper.rb +10 -1
  38. data/spec/stylus_filter_spec.rb +69 -0
  39. data/spec/tilt_filter_spec.rb +25 -1
  40. data/spec/uglify_filter_spec.rb +82 -0
  41. data/spec/yui_css_filter_spec.rb +88 -0
  42. data/spec/yui_javascript_filter_spec.rb +68 -0
  43. metadata +225 -19
  44. data/lib/rake-pipeline-web-filters/ordering_concat_filter.rb +0 -38
  45. data/lib/rake-pipeline-web-filters/sass_compiler.rb +0 -53
  46. data/spec/ordering_concat_filter_spec.rb +0 -39
  47. data/spec/sass_compiler_spec.rb +0 -89
@@ -0,0 +1,38 @@
1
+ module Rake::Pipeline::Web::Filters
2
+ # A filter that wraps input files in an IIFE (immediately invoked functional expression)
3
+ #
4
+ #
5
+ # @example
6
+ # !!!ruby
7
+ # Rake::Pipeline.build do
8
+ # input "app/assets", "**/*.js"
9
+ # output "public"
10
+ #
11
+ # # Wrap each file in: (function() { ... })();"
12
+ # filter Rake::Pipeline::Web::Filters::IifeFilter
13
+ # end
14
+ class IifeFilter < Rake::Pipeline::Filter
15
+ # @param [Proc] block a block to use as the Filter's
16
+ # {#output_name_generator}.
17
+ def initialize(&block)
18
+ block ||= proc { |input| input }
19
+ super(&block)
20
+ end
21
+
22
+ # Implement the {#generate_output} method required by
23
+ # the {Filter} API. Wraps each input in an IIFE.
24
+ #
25
+ # @param [Array<FileWrapper>] inputs an Array of
26
+ # {FileWrapper} objects representing the inputs to
27
+ # this filter.
28
+ # @param [FileWrapper] output a single {FileWrapper}
29
+ # object representing the output.
30
+ def generate_output(inputs, output)
31
+ inputs.each do |input|
32
+ output.write "(function() {\n"
33
+ output.write input.read
34
+ output.write "})();"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,55 @@
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 {https://rubygems.org/gems/less-js less-js}
10
+ #
11
+ # @example
12
+ # !!!ruby
13
+ # Rake::Pipeline.build do
14
+ # input "app/assets", "**/*.less"
15
+ # output "public"
16
+ #
17
+ # # Compile each less file with Less.js
18
+ # filter Rake::Pipeline::Web::Filters::LessFilter
19
+ # end
20
+ class LessFilter < Rake::Pipeline::Filter
21
+ include Rake::Pipeline::Web::Filters::FilterWithDependencies
22
+
23
+ # @return [Hash] a hash of options to pass to Less
24
+ # when compiling.
25
+ attr_reader :options
26
+
27
+ # @param [Proc] block a block to use as the Filter's
28
+ # {#output_name_generator}.
29
+ def initialize(options={}, context = nil, &block)
30
+ block ||= proc { |input| input.sub(/\.less$/, '.css') }
31
+ super(&block)
32
+ @options = options
33
+ end
34
+
35
+ # Implement the {#generate_output} method required by
36
+ # the {Filter} API. Attempts to compile each input file
37
+ # with LessJs.
38
+ #
39
+ # @param [Array<FileWrapper>] inputs an Array of
40
+ # {FileWrapper} objects representing the inputs to
41
+ # this filter.
42
+ # @param [FileWrapper] output a single {FileWrapper}
43
+ # object representing the output.
44
+ def generate_output(inputs, output)
45
+ parser = Less::Parser.new options
46
+ inputs.each do |input|
47
+ output.write parser.parse(input.read).to_css
48
+ end
49
+ end
50
+
51
+ def external_dependencies
52
+ [ 'less' ]
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,70 @@
1
+ module Rake::Pipeline::Web::Filters
2
+ # A filter that compiles input files written in Markdown
3
+ # to Markdown using the Redcarpet compiler.
4
+ #
5
+ # @example
6
+ # !!!ruby
7
+ # Rake::Pipeline.build do
8
+ # input "app/assets", "**/*.md"
9
+ # output "public"
10
+ #
11
+ # # Compile each .md file under the app/assets
12
+ # # directory.
13
+ # filter Rake::Pipeline::Web::Filters::MarkdownFilter
14
+ # end
15
+ #
16
+ class MarkdownFilter < Rake::Pipeline::Filter
17
+
18
+ # @param [Hash] options options to pass to the markdown
19
+ # compiler
20
+ # @see http://rubydoc.info/gems/redcarpet/2.0.0/frames for more information
21
+ # about options
22
+ # @option options [#call] :compiler If you wish to use a different
23
+ # Markdown compiler, you can do so by passing anything that responds
24
+ # to `:call`, which will be passed the Markdown text and any
25
+ # options (other than `:compiler`).
26
+ # @option options [Redcarpet::Render::Base] :renderer a
27
+ # Redcarpet renderer. Used only if using the default compiler.
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(/\.(md|mdown|mkdown|markdown)$/, '.html') }
32
+ super(&block)
33
+ @compiler = options.delete(:compiler)
34
+ @options = options
35
+ end
36
+
37
+ # Implement the {#generate_output} method required by
38
+ # the {Filter} API. Compiles each input file with Sass.
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
+ inputs.each do |input|
47
+ output.write compile(input.read)
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def compile(markdown)
54
+ if @compiler
55
+ @compiler.call(markdown, @options)
56
+ else
57
+ default_compiler.render(markdown)
58
+ end
59
+ end
60
+
61
+ def default_compiler
62
+ @default_renderer ||= begin
63
+ require 'redcarpet'
64
+ renderer = @options.delete(:renderer) || Redcarpet::Render::HTML.new
65
+ Redcarpet::Markdown.new(renderer, @options)
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -9,7 +9,7 @@ module Rake::Pipeline::Web::Filters
9
9
  # output "public"
10
10
  #
11
11
  # # Wrap each JS file in a minispade.register closure.
12
- # filter Rake::Pipeleine::Web::Filters::MinispadeFilter
12
+ # filter Rake::Pipeline::Web::Filters::MinispadeFilter
13
13
  # end
14
14
  class MinispadeFilter < Rake::Pipeline::Filter
15
15
 
@@ -18,11 +18,18 @@ module Rake::Pipeline::Web::Filters
18
18
  # each outputted function; defaults to false.
19
19
  # @option options [Proc] :module_id_generator a proc to use to generate
20
20
  # the minispade module id.
21
+ # @option options [Boolean] :rewrite_requires If true, change calls to
22
+ # +require+ in the source to +minispade.require+.
23
+ # @option options [Boolean] :string If true, compiles the output as
24
+ # a String instead of a closure. This means that @sourceURL can be
25
+ # appended for good stack traces and debugging.
21
26
  def initialize(options = {})
22
27
  super()
23
- @use_strict = !!options[:use_strict]
28
+ @use_strict = options[:use_strict]
24
29
  @module_id_generator = options[:module_id_generator] ||
25
30
  proc { |input| input.fullpath.sub(Dir.pwd, '') }
31
+ @rewrite_requires = options[:rewrite_requires]
32
+ @string_module = options[:string]
26
33
  end
27
34
 
28
35
  # Implement the {#generate_output} method required by
@@ -37,9 +44,18 @@ module Rake::Pipeline::Web::Filters
37
44
  def generate_output(inputs, output)
38
45
  inputs.each do |input|
39
46
  code = input.read
40
- code = '"use strict"; ' + code if @use_strict
41
- function = "function() { #{code} }"
42
- ret = "minispade.register('#{@module_id_generator.call(input)}',#{function});"
47
+ code.gsub!(%r{^\s*require\s*\(\s*}, 'minispade.require(') if @rewrite_requires
48
+ code.gsub!(%r{^\s*requireAll\s*\(\s*}, 'minispade.requireAll(') if @rewrite_requires
49
+ code = %["use strict";\n] + code if @use_strict
50
+
51
+ module_id = @module_id_generator.call(input)
52
+
53
+ if @string_module
54
+ contents = %{(function() {#{code}\n})();\n//@ sourceURL=#{module_id}}.to_json
55
+ else
56
+ contents = "function() {#{code}\n}"
57
+ end
58
+ ret = "minispade.register('#{module_id}', #{contents});"
43
59
  output.write ret
44
60
  end
45
61
  end
@@ -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