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
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ node_modules
19
+ .project
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -cfs -r spec_helper.rb
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
4
+
5
+ bundler_args: --without docs
6
+
7
+ before_script: npm install -g jade
8
+
9
+ notifications:
10
+ email:
11
+ - wycats@gmail.com
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --readme README.yard
2
+
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+
3
+ gem "rake-pipeline", :git => "git://github.com/livingsocial/rake-pipeline.git"
4
+
5
+ # Specify your gem's dependencies in rake-pipeline-web-filters.gemspec
6
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,58 @@
1
+ # Rake::Pipeline::Web::Filters [![Build Status](https://secure.travis-ci.org/wycats/rake-pipeline-web-filters.png?branch=master)](http://travis-ci.org/wycats/rake-pipeline-web-filters)
2
+
3
+ This project contains a set of rake-pipeline filters for building web
4
+ apps.
5
+
6
+ It includes these filters:
7
+
8
+ * Cache Buster - Write a fingerprint into each file name
9
+ * Coffescript - Convert Coffeescript to Javascript
10
+ * GZip - Create gzip'd version of your files
11
+ * Handlebars - Process handlebars templates
12
+ * IIFE - Wrap source files in Immediately Invoked Function Expressions
13
+ * Jade - Process Jade templates
14
+ * LESS - Convert LESS to CSS
15
+ * Markdown - Convert Markdown to HTML
16
+ * Minispade - Wrap JS files in Minispade modules
17
+ * Neuter - Require files in a file and generate one single combined file
18
+ * SASS - Convert SASS to CSS
19
+ * Stylus - Convert Stylus to CSS
20
+ * Tilt - Use Tilt to process
21
+ * Uglify - Minify JS
22
+ * YUI CSS - Minify CSS
23
+ * YUI Javascript - Minify JS
24
+
25
+ Here's a quick example of a realistic project's Assetfile:
26
+
27
+ ```ruby
28
+ # Assetfile
29
+ require 'rake-pipeline-web-filters'
30
+
31
+ output "site"
32
+
33
+ input "javascripts" do
34
+ match "**/*.coffee" do
35
+ coffee_script
36
+ end
37
+
38
+ match "**/*.js" do
39
+ minispade
40
+ concat "application.js"
41
+ uglify
42
+ end
43
+ end
44
+
45
+ input "stylesheets" do
46
+ match "**/*.sass" do
47
+ sass
48
+ end
49
+
50
+ match "**/*.css" do
51
+ concat "application.css"
52
+ yui_css
53
+ end
54
+ end
55
+ ```
56
+
57
+ API documentation is hosted at
58
+ <a href="http://rubydoc.info/github/wycats/rake-pipeline-web-filters/master/file/README.yard">rubydoc.info</a>
data/README.yard ADDED
@@ -0,0 +1,25 @@
1
+ = Rake::Pipeline::Web::Filters
2
+
3
+ Rake::Pipeline::Web::Filters is a collection of filters for Rake::Pipeline
4
+ for creating pipelines to generate web content.
5
+
6
+ = Usage
7
+
8
+ In your +Assetfile+:
9
+
10
+ !!!ruby
11
+ require "rake-pipeline-web-filters"
12
+
13
+ input "assets"
14
+ output "public"
15
+
16
+ # Take all JS inputs and wrap each of them in code to
17
+ # register them with the Minispade module loader.
18
+ match "*.js" do
19
+ filter Rake::Pipeline::Web::Filters::MinispadeFilter
20
+ end
21
+
22
+ # Take all SCSS inputs and compile them with Sass
23
+ match "*.scss" do
24
+ filter Rake::Pipeline::Web::Filters::SassCompiler
25
+ end
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "bundler/setup"
4
+
5
+ desc "run the specs"
6
+ task :spec do
7
+ sh "rspec -cfs spec"
8
+ end
9
+
10
+ task :default => :spec
@@ -0,0 +1,31 @@
1
+ require "rake-pipeline"
2
+
3
+ module Rake
4
+ class Pipeline
5
+ module Web
6
+ module Filters
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ require "rake-pipeline-web-filters/version"
13
+ require "rake-pipeline-web-filters/cache_buster_filter"
14
+ require "rake-pipeline-web-filters/filter_with_dependencies"
15
+ require "rake-pipeline-web-filters/markdown_filter"
16
+ require "rake-pipeline-web-filters/minispade_filter"
17
+ require "rake-pipeline-web-filters/neuter_filter"
18
+ require "rake-pipeline-web-filters/sass_filter"
19
+ require "rake-pipeline-web-filters/stylus_filter"
20
+ require "rake-pipeline-web-filters/jade_filter"
21
+ require "rake-pipeline-web-filters/tilt_filter"
22
+ require "rake-pipeline-web-filters/coffee_script_filter"
23
+ require "rake-pipeline-web-filters/yui_javascript_filter"
24
+ require "rake-pipeline-web-filters/yui_css_filter"
25
+ require "rake-pipeline-web-filters/gzip_filter"
26
+ require "rake-pipeline-web-filters/uglify_filter"
27
+ require "rake-pipeline-web-filters/chained_filter"
28
+ require "rake-pipeline-web-filters/less_filter"
29
+ require "rake-pipeline-web-filters/handlebars_filter"
30
+ require "rake-pipeline-web-filters/iife_filter"
31
+ require "rake-pipeline-web-filters/helpers"
@@ -0,0 +1,42 @@
1
+ module Rake::Pipeline::Web::Filters
2
+ # A filter that inserts a cache-busting key into the outputted file name.
3
+ #
4
+ # @example
5
+ # !!!ruby
6
+ # Rake::Pipeline.build do
7
+ # input "app/assets"
8
+ # output "public"
9
+ #
10
+ # filter Rake::Pipeline::Web::Filters::CacheBusterFilter
11
+ # end
12
+ class CacheBusterFilter < Rake::Pipeline::Filter
13
+
14
+ # @return [Proc] the default cache key generator, which
15
+ # takes the MD5 hash of the input's file name and contents.
16
+ DEFAULT_KEY_GENERATOR = proc { |input|
17
+ require 'digest/md5'
18
+ Digest::MD5.new << input.path << input.read
19
+ }
20
+
21
+ # @param [Proc] key_generator a block to use as the Filter's method of
22
+ # turning input file wrappers into cache keys; defaults to
23
+ # +DEFAULT_KEY_GENERATOR+
24
+ def initialize(&key_generator)
25
+ key_generator ||= DEFAULT_KEY_GENERATOR
26
+ output_name_generator = proc { |path, file|
27
+ parts = path.split('.')
28
+ index_to_modify = parts.length > 1 ? -2 : -1
29
+ parts[index_to_modify] << "-#{key_generator.call(file)}"
30
+ parts.join('.')
31
+ }
32
+ super(&output_name_generator)
33
+ end
34
+
35
+ def generate_output(inputs, output)
36
+ inputs.each do |input|
37
+ output.write input.read
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,116 @@
1
+ module Rake::Pipeline::Web::Filters
2
+ # Implement the FileWrapper API. Because filters are defined
3
+ # in terms of the FileWrapper API, we can implement an
4
+ # alternative that doesn't write to disk but still utilizes
5
+ # the same filter definitions.
6
+ class MemoryFileWrapper < Struct.new(:root, :path, :encoding, :body)
7
+ def with_encoding(new_encoding)
8
+ self.class.new(root, path, new_encoding, body)
9
+ end
10
+
11
+ def fullpath
12
+ File.join(root, path)
13
+ end
14
+
15
+ def create
16
+ self.body = ""
17
+ yield
18
+ end
19
+
20
+ alias read body
21
+
22
+ def write(contents)
23
+ self.body << contents
24
+ end
25
+ end
26
+
27
+ # The purpose of ChainedFilter is to enable filters to
28
+ # be applied to files based upon their file extensions.
29
+ #
30
+ # Filters are applied repeatedly to files for each
31
+ # extension.
32
+ #
33
+ # @example
34
+ #
35
+ # filter ChainedFilter, :types => {
36
+ # :erb => ErbFilter,
37
+ # :coffee => CoffeeFilter,
38
+ # :scss => ScssFilter
39
+ # }
40
+ #
41
+ # In this example, files with the extensions +erb+,
42
+ # +coffee+, and +scss+ will be processed using the
43
+ # specified filters. If a file has multiple extensions,
44
+ # all of the filters will be applied.
45
+ #
46
+ # For example, with the above filter specification,
47
+ # a file like +application.js.coffee.erb+ will first
48
+ # apply the +ErbFilter+, then the +CoffeeFilter+, and
49
+ # then output +application.js+.
50
+ #
51
+ # This filter is largely designed for use with the
52
+ # {ProjectHelpers#register register} helper, which
53
+ # will transparently add a ChainedFilter before each
54
+ # input block with the registered extensions.
55
+ class ChainedFilter < Rake::Pipeline::Filter
56
+ attr_reader :filters
57
+
58
+ # @param [Hash] options
59
+ # @option options [Hash] :types
60
+ # A hash of file extensions and their associated
61
+ # filters. See the class description for more
62
+ # information.
63
+ def initialize(options={}, &block)
64
+ @filters = options[:types]
65
+
66
+ keys = @filters.keys
67
+ pattern = keys.map { |key| "\\.#{key}" }.join("|")
68
+ @pattern = Regexp.new("(#{pattern})*$", "i")
69
+
70
+ block ||= proc do |input|
71
+ input.sub(@pattern, '')
72
+ end
73
+
74
+ super(&block)
75
+ end
76
+
77
+ # @private
78
+ #
79
+ # Implement +generate_output+
80
+ def generate_output(inputs, output)
81
+ inputs.each do |input|
82
+ output.write process_filters(input)
83
+ end
84
+ end
85
+
86
+ # @private
87
+ #
88
+ # Process an input file by applying the filter for each
89
+ # extension in the file.
90
+ def process_filters(input)
91
+ keys = input.path.match(@pattern)[0].scan(/(?<=\.)\w+/)
92
+
93
+ filters = keys.reverse_each.map do |key|
94
+ @filters[key.to_sym]
95
+ end
96
+
97
+ filters.each do |filter|
98
+ input = process_with_filter(input, filter)
99
+ end
100
+
101
+ input.read
102
+ end
103
+
104
+ # @private
105
+ #
106
+ # Process an individual file with a filter.
107
+ def process_with_filter(input, filter_class)
108
+ filter = filter_class.new
109
+
110
+ output = MemoryFileWrapper.new("/output", input.path, "UTF-8")
111
+ output.create { filter.generate_output([input], output) }
112
+
113
+ output
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,41 @@
1
+ module Rake::Pipeline::Web::Filters
2
+ # A filter that compiles CoffeeScript to JavaScript.
3
+ class CoffeeScriptFilter < Rake::Pipeline::Filter
4
+ include Rake::Pipeline::Web::Filters::FilterWithDependencies
5
+
6
+ # @return [Hash] a hash of options to pass to CoffeeScript when
7
+ # rendering.
8
+ attr_reader :options
9
+
10
+ # By default, the CoffeeScriptFilter converts inputs
11
+ # with the extension +.coffee+ to +.js+.
12
+ #
13
+ # @param [Hash] options options to pass to the CoffeeScript
14
+ # compiler.
15
+ # @param [Proc] block the output name generator block
16
+ def initialize(options = {}, &block)
17
+ block ||= proc { |input| input.sub(/\.coffee$/, '.js') }
18
+ super(&block)
19
+ @options = options
20
+ end
21
+
22
+ # The body of the filter. Compile each input file into
23
+ # a CoffeeScript compiled output file.
24
+ #
25
+ # @param [Array] inputs an Array of FileWrapper objects.
26
+ # @param [FileWrapper] output a FileWrapper object
27
+ def generate_output(inputs, output)
28
+ inputs.each do |input|
29
+ begin
30
+ output.write CoffeeScript.compile(input, options)
31
+ rescue ExecJS::Error => error
32
+ raise error, "Error compiling #{input.path}. #{error.message}"
33
+ end
34
+ end
35
+ end
36
+
37
+ def external_dependencies
38
+ [ "coffee-script" ]
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ module Rake::Pipeline::Web::Filters
2
+ # A mixin for filters that have dependencies on external
3
+ # libraries. Include this module in the filter class and
4
+ # declare a private `external_dependencies` method that
5
+ # returns an array of strings. Each one will be passed
6
+ # to `Kernel#require` when an instance of the filter
7
+ # is created.
8
+ module FilterWithDependencies
9
+
10
+ def initialize(*args, &block)
11
+ require_dependencies!
12
+ super(*args, &block)
13
+ end
14
+
15
+ private
16
+
17
+ def require_dependencies!
18
+ external_dependencies.each do |d|
19
+ begin
20
+ require d
21
+ rescue LoadError => error
22
+ raise error, "#{self.class} requires #{d}, but it is not available."
23
+ end
24
+ end
25
+ end
26
+ end
27
+ 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 gzips input files using zlib
5
+ #
6
+ #
7
+ # @example
8
+ # !!!ruby
9
+ # Rake::Pipeline.build do
10
+ # input "app/assets", "**/*.js"
11
+ # output "public"
12
+ #
13
+ # # Compress each JS file under the app/assets
14
+ # # directory.
15
+ # filter Rake::Pipeline::Web::Filters::GzipFilter
16
+ # end
17
+ class GzipFilter < Rake::Pipeline::Filter
18
+
19
+ include Rake::Pipeline::Web::Filters::FilterWithDependencies
20
+
21
+ processes_binary_files
22
+
23
+ # @param [Proc] block a block to use as the Filter's
24
+ # {#output_name_generator}.
25
+ def initialize(&block)
26
+ block ||= proc { |input| input.sub(/\.(.*)$/, '.\1.gz') }
27
+ super(&block)
28
+ end
29
+
30
+ # Implement the {#generate_output} method required by
31
+ # the {Filter} API. Compresses each input file with
32
+ # Zlib.GzipWriter.
33
+ #
34
+ # @param [Array<FileWrapper>] inputs an Array of
35
+ # {FileWrapper} objects representing the inputs to
36
+ # this filter.
37
+ # @param [FileWrapper] output a single {FileWrapper}
38
+ # object representing the output.
39
+ def generate_output(inputs, output)
40
+ inputs.each do |input|
41
+ # gzip input file to stream
42
+ fakefile = StringIO.new
43
+ gz = Zlib::GzipWriter.new(fakefile)
44
+ gz.write(input.read)
45
+ gz.close
46
+
47
+ # send gzipped contents to output
48
+ output.write fakefile.string
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def external_dependencies
55
+ [ 'stringio', 'zlib' ]
56
+ end
57
+ end
58
+ end
59
+