diff --git a/Gemfile b/Gemfile index 03edd774..6874e690 100644 --- a/Gemfile +++ b/Gemfile @@ -4,7 +4,6 @@ gemspec group :development, :test do gem "rake", "0.9.2.2" - gem "rails", "2.3.14" gem "cssmin", "1.0.3" gem "jsmin", "1.0.1" gem "yui-compressor", "0.9.6" @@ -17,3 +16,9 @@ group :development do gem "RedCloth", "4.2.9" gem "redgreen", "1.2.2" end + +group :test do + gem 'rspec', '~>2' + gem 'nokogiri' + gem 'rack-test' +end diff --git a/jammit.gemspec b/jammit.gemspec index 1618ec74..9af9040a 100644 --- a/jammit.gemspec +++ b/jammit.gemspec @@ -28,6 +28,7 @@ Gem::Specification.new do |s| s.add_dependency 'cssmin', ['>= 1.0.3'] s.add_dependency 'jsmin', ['>= 1.0.1'] + s.add_dependency "rack", ">= 1.0" s.files = Dir['lib/**/*', 'bin/*', 'rails/*', 'jammit.gemspec', 'LICENSE', 'README'] end diff --git a/lib/jammit.rb b/lib/jammit.rb index c9d6d08e..527e5718 100644 --- a/lib/jammit.rb +++ b/lib/jammit.rb @@ -1,5 +1,8 @@ $LOAD_PATH.push File.expand_path(File.dirname(__FILE__)) +require 'jammit/header_processor' +require 'jammit/controller' + # @Jammit@ is the central namespace for all Jammit classes, and provides access # to all of the configuration options. module Jammit @@ -55,7 +58,7 @@ class << self :embed_assets, :package_assets, :compress_assets, :gzip_assets, :package_path, :mhtml_enabled, :include_jst_script, :config_path, :javascript_compressor, :compressor_options, :css_compressor, - :css_compressor_options, :template_extension, + :css_compressor_options, # :template_extension, # <<--- TODO: activate later :template_extension_matcher, :allow_debugging, :rewrite_relative_paths, :public_root attr_accessor :javascript_compressors, :css_compressors diff --git a/lib/jammit/controller.rb b/lib/jammit/controller.rb index 0ebbd71c..46a0bd50 100644 --- a/lib/jammit/controller.rb +++ b/lib/jammit/controller.rb @@ -1,11 +1,19 @@ -require 'action_controller' +require 'rack' module Jammit - # The JammitController is added to your Rails application when the Gem is - # loaded. It takes responsibility for /assets, and dynamically packages any - # missing or uncached asset packages. - class Controller < ActionController::Base + # defined somewhere else + # but for temporarily development + def self.public_root + '/public' + end + + def self.template_extension + 'js' + end + + + class Request < Rack::Request VALID_FORMATS = [:css, :js] @@ -13,6 +21,47 @@ class Controller < ActionController::Base NOT_FOUND_PATH = "#{Jammit.public_root}/404.html" + def asset_path? + path_info =~ /^\/assets/ + end + + def asset_from_path + path_info =~ /^\/assets\/([\w\.]+)/ + $1 + end + + def extension_from_path + path_info =~ /\.([\w\.]+)$/ + $1 + end + + def path_info + @env['PATH_INFO'] + end + + # Extracts the package name, extension (:css, :js), and variant (:datauri, + # :mhtml) from the incoming URL. + def parse_request + pack = asset_from_path + @extension = extension_from_path.to_sym + puts @extension.inspect + raise PackageNotFound unless (VALID_FORMATS + [Jammit.template_extension.to_sym]).include?(@extension) + if Jammit.embed_assets + suffix_match = pack.match(SUFFIX_STRIPPER) + @variant = Jammit.embed_assets && suffix_match && suffix_match[1].to_sym + pack.sub!(SUFFIX_STRIPPER, '') + end + @package = pack.to_sym + end + + # Tells the Jammit::Packager to cache and gzip an asset package. We can't + # just use the built-in "cache_page" because we need to ensure that + # the timestamp that ends up in the MHTML is also on the cached file. + def cache_package + dir = File.join(page_cache_directory, Jammit.package_path) + Jammit.packager.cache(@package, @extension, @contents, dir, @variant, @mtime) + end + # The "package" action receives all requests for asset packages that haven't # yet been cached. The package will be built, cached, and gzipped. def package @@ -20,28 +69,52 @@ def package template_ext = Jammit.template_extension.to_sym case @extension when :js - render :js => (@contents = Jammit.packager.pack_javascripts(@package)) + puts @package.inspect + (@contents = Jammit.packager.pack_javascripts(@package)) when template_ext - render :js => (@contents = Jammit.packager.pack_templates(@package)) + # (@contents = Jammit.packager.pack_templates(@package)) + 'foo_case2.jst' when :css - render :text => generate_stylesheets, :content_type => 'text/css' + [generate_stylesheets, :content_type => 'text/css'] end - cache_package if perform_caching && (@extension != template_ext) + # cache_package if perform_caching && (@extension != template_ext) rescue Jammit::PackageNotFound package_not_found end + def for_jammit? + get? && # GET on js resource in :hosted_at (fast, check first) + asset_path? + end + end - private - - # Tells the Jammit::Packager to cache and gzip an asset package. We can't - # just use the built-in "cache_page" because we need to ensure that - # the timestamp that ends up in the MHTML is also on the cached file. - def cache_package - dir = File.join(page_cache_directory, Jammit.package_path) - Jammit.packager.cache(@package, @extension, @contents, dir, @variant, @mtime) + class Response < Rack::Response + + # Rack response tuple accessors. + attr_accessor :status, :headers, :body + + def initialize(env, asset) + @env = env + @body = asset + @status = 200 # OK + @headers = Rack::Utils::HeaderHash.new + + headers["Content-Length"] = self.class.content_length(body).to_s end + class << self + + # Calculate appropriate content_length + def content_length(body) + if body.respond_to?(:bytesize) + body.bytesize + else + body.size + end + end + + end + # Generate the complete, timestamped, MHTML url -- if we're rendering a # dynamic MHTML package, we'll need to put one URL in the response, and a # different one into the cached package. @@ -63,19 +136,6 @@ def generate_stylesheets css end - # Extracts the package name, extension (:css, :js), and variant (:datauri, - # :mhtml) from the incoming URL. - def parse_request - pack = params[:package] - @extension = params[:extension].to_sym - raise PackageNotFound unless (VALID_FORMATS + [Jammit.template_extension.to_sym]).include?(@extension) - if Jammit.embed_assets - suffix_match = pack.match(SUFFIX_STRIPPER) - @variant = Jammit.embed_assets && suffix_match && suffix_match[1].to_sym - pack.sub!(SUFFIX_STRIPPER, '') - end - @package = pack.to_sym - end # Render the 404 page, if one exists, for any packages that don't. def package_not_found @@ -83,15 +143,40 @@ def package_not_found render :text => "