Skip to content

Instantly share code, notes, and snippets.

@robharper
Created May 16, 2012 17:55
Show Gist options
  • Save robharper/2712617 to your computer and use it in GitHub Desktop.
Save robharper/2712617 to your computer and use it in GitHub Desktop.
Using rake-pipeline and a modified 'Neuter' filter for JS library development
require "rake-pipeline-web-filters"
require "neuter_plus_filter"
input 'src' do
output 'build'
match '**/main.js' do
filter(Rake::Pipeline::Web::ExtraFilters::NeuterPlusFilter,
# Possibly depend on JS files within same or subdirectories
:additional_dependencies => proc { |input|
Dir.glob(File.join(File.dirname(input.fullpath),'**','*.js'))
},
# Append .js to module names to resolve filenames
:path_transform => proc { |path, input|
path + '.js'
},
# Output eval'd strings when in development mode
:string_code => development?
) do |filename|
# Use the directory name that contains the main.js for the output filename
filename.gsub('/main.js', '.js')
end
end
end
#
# This is an extension of the neuter filter by Peter Wagenet
# https://github.com/wycats/rake-pipeline-web-filters/blob/master/lib/rake-pipeline-web-filters/neuter_filter.rb
#
# It adds the capability to optionally output eval'd string representations of the code (plus @sourceURL annoations)
# instead of the raw code itself. This makes it possible to output a development version of a neutered library that
# is functionally identical but makes debugging in a webkit/Firefox browser much cleaner by breaking out source files.
#
module Rake::Pipeline::Web::ExtraFilters
class NeuterBatch
def initialize(config={}, known_files)
@config = config
@known_files = known_files
@required = []
end
def file_wrapper(klass, *args)
file = klass.new(*args)
file.extend NeuterWrapper
file.batch(self)
file
end
def required(req)
unless @known_files.include?(req)
warn "Included '#{req}', which is not listed in :additional_dependencies. The pipeline may not invalidate properly."
end
@required << req
end
def required?(req)
@required.include?(req)
end
def strip_requires(source)
requires = []
regexp = @config[:require_regexp] || %r{^\s*require\(['"]([^'"]*)['"]\);?\s*}
# FIXME: This $1 may not be reliable with other regexps
source.gsub!(regexp){ requires << $1; '' }
requires
end
def transform_path(path, input)
@config[:path_transform] ? @config[:path_transform].call(path, input) : path
end
def output_source(filename, source)
code = @config[:closure_wrap] ? "(function() {\n#{source}\n})();\n\n" : source
# TODO Allow a proc for customizing sourceURL paths
@config[:string_code] ? "eval( #{ "#{code}\n\n//@ sourceURL=#{filename.sub(Dir.pwd, '')}".to_json } );" : code
end
def filename_comment(input)
@config[:filename_comment] ? @config[:filename_comment].call(input) + "\n" : ""
end
end
module NeuterWrapper
def batch(batch)
@batch = batch
@batch.required(fullpath)
end
def read
source = super
required_files = @batch.strip_requires(source).map do |req|
req_path = @batch.transform_path(req, self)
if req_path && !@batch.required?(File.expand_path(req_path, root))
@batch.file_wrapper(self.class, root, req_path, encoding).read
else
nil
end
end.compact
file = @batch.filename_comment(self) + @batch.output_source(self.fullpath, source)
(required_files << file).join("\n\n")
end
end
# A filter that takes files with requires and collapses them into a single
# file without requires. Optionally include the required code as eval'd strings
# for handy debugging in webkit/FF.
class NeuterPlusFilter < Rake::Pipeline::ConcatFilter
def initialize(string=nil, config={}, &block)
if string.is_a?(Hash)
config = string
string = nil
end
@config = config
super(string, &block)
end
def generate_output(inputs, output)
inputs.each do |input|
known_files = [input.fullpath] + additional_dependencies(input)
batch = NeuterBatch.new(@config, known_files)
file = batch.file_wrapper(file_wrapper_class, input.root, input.path, input.encoding)
output.write file.read
end
end
def additional_dependencies(input)
method = @config[:additional_dependencies]
method ? method.call(input).map{|p| File.expand_path(p, input.root) } : []
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment