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