diff --git a/Rakefile b/Rakefile index 5d6ac8f..64fd3a5 100644 --- a/Rakefile +++ b/Rakefile @@ -49,6 +49,7 @@ begin gemspec.homepage = "http://github.com/codespeaks/modulr" gemspec.files = FileList["Rakefile", "README.markdown", "LICENSE", "VERSION", "{lib,bin,assets,example}/**/*", "vendor/rkelly/**/*"] gemspec.executable = "modulrize" + gemspec.add_dependency("coffee_machine") end rescue LoadError puts "Jeweler not available. Install it with: sudo gem install jeweler" diff --git a/bin/modulrize b/bin/modulrize index 0134d6d..fa12333 100755 --- a/bin/modulrize +++ b/bin/modulrize @@ -9,6 +9,9 @@ options = { opts = OptionParser.new do |opts| opts.banner = 'Usage: modulrize program.js [options] > output.js' + opts.separator '' + opts.separator 'Options:' + opts.on('-o', '--output=FILE', 'Write the output to FILE. Defaults to stdout.') do |output| options[:output] = File.open(output, 'w') end @@ -24,10 +27,39 @@ opts = OptionParser.new do |opts| options[:lazy_eval] = modules end - opts.on_tail('-h', '--help', 'Show this message.') do + opts.on('--minify', 'Minify output using YUI Compressor.') do |minify| + options[:minify] = minify + end + + opts.on('-h', '--help', 'Show this message.') do puts opts exit end + + opts.separator '' + opts.separator 'Minification options (these are forwarded to YUI Compressor without the "minify-" prefix):' + + { + 'line-break COLUMN' => 'Insert a line break after the specified column number.', + 'verbose' => 'Display informational messages and warnings.', + 'nomunge' => 'Minify only, do not obfuscate.', + 'preserve-semi' => 'Preserve all semicolons.', + 'disable-optimizations' => 'Disable all micro optimizations.' + }.each do |option, message| + prefixed_option = option.sub(/\A(\[no-\])?/, '--\\1minify-') + + def normalize_option(option) + option.gsub('-', '_').to_sym + end + + opts.on(prefixed_option, message) do |value| + if !options[:minify] || options[:minify] == true + options[:minify] = {} + end + options[:minify][normalize_option(option)] = value + end + end + end opts.parse! diff --git a/lib/modulr.rb b/lib/modulr.rb index 4e176ff..b109a9e 100644 --- a/lib/modulr.rb +++ b/lib/modulr.rb @@ -10,6 +10,7 @@ class ModulrError < StandardError require 'modulr/js_module' require 'modulr/parser' require 'modulr/collector' + require 'modulr/minifier' require 'modulr/version' PATH_TO_MODULR_JS = File.join(LIB_DIR, '..', 'assets', 'modulr.js') @@ -17,6 +18,15 @@ class ModulrError < StandardError def self.ize(input_filename, options = {}) collector = Collector.new(options) collector.parse_file(input_filename) - collector.to_js + minify(collector.to_js, options[:minify]) end + + protected + def self.minify(output, options) + if options + Minifier.minify(output, options == true ? {} : options) + else + output + end + end end diff --git a/lib/modulr/minifier.rb b/lib/modulr/minifier.rb new file mode 100644 index 0000000..ca7c490 --- /dev/null +++ b/lib/modulr/minifier.rb @@ -0,0 +1,41 @@ +module Modulr + class MinifierError < ModulrError + end + + class Minifier + YUI_COMPRESSOR_PATH = File.join(File.dirname(__FILE__), '..', '..', 'vendor', 'yuicompressor-2.4.2.jar').freeze + + def self.minify(input, options = {}) + new(options).minify(input) + end + + def initialize(options = {}) + @options = options + end + + def minify(input) + run_yui_compressor do |pipe, stderr| + pipe.write(input) + pipe.close_write + output, error = pipe.read, stderr.read + raise MinifierError, error unless error.empty? + output + end + end + + protected + def run_yui_compressor(&block) + require 'coffee_machine' + CoffeeMachine.run_jar(YUI_COMPRESSOR_PATH, :args => yui_compressor_args, &block) + end + + def yui_compressor_args + args = ['--type js'] + @options.each do |option, value| + args << "--#{option.to_s.gsub('_', '-')}" + args << value unless value == true || value == false + end + args.join(' ') + end + end +end diff --git a/vendor/yuicompressor-2.4.2.jar b/vendor/yuicompressor-2.4.2.jar new file mode 100644 index 0000000..c29470b Binary files /dev/null and b/vendor/yuicompressor-2.4.2.jar differ