Refactored and simplified Sprockets asset caching #153
2
Gemfile
2
Gemfile
@ -23,7 +23,7 @@ gem 'mocha'
|
||||
|
||||
gem 'cucumber'
|
||||
|
||||
gem 'jquery-rails', '~> 1.0.0'
|
||||
gem 'jquery-rails', '> 1.0'
|
||||
gem 'ejs'
|
||||
|
||||
gem 'guard-jasmine-headless-webkit', :git => 'git://github.com/johnbintz/guard-jasmine-headless-webkit.git'
|
||||
|
@ -21,11 +21,6 @@ module Jasmine
|
||||
autoload :TemplateWriter, 'jasmine/headless/template_writer'
|
||||
|
||||
autoload :FileChecker, 'jasmine/headless/file_checker'
|
||||
|
||||
autoload :CoffeeTemplate, 'jasmine/headless/coffee_template'
|
||||
autoload :JSTemplate, 'jasmine/headless/js_template'
|
||||
autoload :JSTTemplate, 'jasmine/headless/jst_template'
|
||||
autoload :CSSTemplate, 'jasmine/headless/css_template'
|
||||
autoload :NilTemplate, 'jasmine/headless/nil_template'
|
||||
|
||||
autoload :Report, 'jasmine/headless/report'
|
||||
|
@ -1,20 +0,0 @@
|
||||
require 'coffee_script'
|
||||
require 'digest/sha1'
|
||||
require 'fileutils'
|
||||
|
||||
module Jasmine
|
||||
module Headless
|
||||
class CoffeeScriptCache < CacheableAction
|
||||
class << self
|
||||
def cache_type
|
||||
"coffee_script"
|
||||
end
|
||||
end
|
||||
|
||||
def action
|
||||
CoffeeScript.compile(File.read(file))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,36 +0,0 @@
|
||||
require 'tilt/template'
|
||||
require 'rainbow'
|
||||
|
||||
module Jasmine::Headless
|
||||
class CoffeeTemplate < Tilt::Template
|
||||
include Jasmine::Headless::FileChecker
|
||||
|
||||
self.default_mime_type = 'application/javascript'
|
||||
|
||||
def prepare ; end
|
||||
|
||||
def evaluate(scope, locals, &block)
|
||||
if bad_format?(file)
|
||||
alert_bad_format(file)
|
||||
return ''
|
||||
end
|
||||
begin
|
||||
cache = Jasmine::Headless::CoffeeScriptCache.new(file)
|
||||
source = cache.handle
|
||||
if cache.cached?
|
||||
%{<script type="text/javascript" src="#{cache.cache_file}"></script>
|
||||
<script type="text/javascript">window.CSTF['#{File.split(cache.cache_file).last}'] = '#{file}';</script>}
|
||||
else
|
||||
%{<script type="text/javascript">#{source}</script>}
|
||||
end
|
||||
rescue CoffeeScript::CompilationError => ne
|
||||
puts "[%s] %s: %s" % [ 'coffeescript'.color(:red), file.color(:yellow), "#{ne.message}".color(:white) ]
|
||||
raise ne
|
||||
rescue StandardError => e
|
||||
puts "[%s] Error in compiling file: %s" % [ 'coffeescript'.color(:red), file.color(:yellow) ]
|
||||
raise e
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,19 +0,0 @@
|
||||
require 'tilt/template'
|
||||
|
||||
module Jasmine::Headless
|
||||
class CSSTemplate < Tilt::Template
|
||||
include Jasmine::Headless::FileChecker
|
||||
self.default_mime_type = 'text/css'
|
||||
|
||||
def prepare ; end
|
||||
|
||||
def evaluate(scope, locals, &block)
|
||||
if bad_format?(file)
|
||||
alert_bad_format(file)
|
||||
return ''
|
||||
end
|
||||
file ? %{<link rel="stylesheet" href="#{file}" type="text/css" />} : data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,3 +1,5 @@
|
||||
require 'rainbow'
|
||||
|
||||
module Jasmine::Headless::FileChecker
|
||||
def excluded_formats
|
||||
::Jasmine::Headless::EXCLUDED_FORMATS
|
||||
|
@ -39,6 +39,10 @@ module Jasmine::Headless
|
||||
@sprockets_environment = nil
|
||||
end
|
||||
|
||||
def sprockets_environment
|
||||
@sprockets_environment ||= Sprockets::Environment.new
|
||||
end
|
||||
|
||||
def registered_engines
|
||||
@registered_engines ||= {}
|
||||
end
|
||||
@ -138,7 +142,7 @@ module Jasmine::Headless
|
||||
def sprockets_environment
|
||||
return @sprockets_environment if @sprockets_environment
|
||||
|
||||
@sprockets_environment = Sprockets::Environment.new
|
||||
@sprockets_environment = self.class.sprockets_environment #|| Sprockets::Environment.new
|
||||
search_paths.each { |path| @sprockets_environment.append_path(path) }
|
||||
|
||||
@sprockets_environment.unregister_postprocessor('application/javascript', Sprockets::SafetyColons)
|
||||
@ -149,11 +153,10 @@ module Jasmine::Headless
|
||||
register_engine ".#{extension}", Jasmine::Headless::NilTemplate
|
||||
end
|
||||
|
||||
register_engine '.coffee', Jasmine::Headless::CoffeeTemplate
|
||||
register_engine '.js', Jasmine::Headless::JSTemplate
|
||||
register_engine '.css', Jasmine::Headless::CSSTemplate
|
||||
register_engine '.jst', Jasmine::Headless::JSTTemplate
|
||||
end
|
||||
|
||||
@sprockets_environment.logger = Logger.new(STDOUT)
|
||||
@sprockets_environment.logger.level = Logger::WARN
|
||||
|
||||
@sprockets_environment
|
||||
end
|
||||
@ -207,7 +210,28 @@ module Jasmine::Headless
|
||||
alert_time = nil
|
||||
end
|
||||
|
||||
sprockets_environment.find_asset(file, :bundle => false).body
|
||||
asset = sprockets_environment.find_asset(file, :bundle => false)
|
||||
cache_file = File.join('.jhw-cache', 'code', asset.logical_path)
|
||||
# Process & cache the asset only if needed
|
||||
unless File.exist?(cache_file) && (File.mtime(file) < File.mtime(cache_file))
|
||||
FileUtils.mkdir_p File.dirname(cache_file)
|
||||
asset.write_to(cache_file)
|
||||
end
|
||||
|
||||
html = ''
|
||||
case asset.content_type
|
||||
when 'application/javascript'
|
||||
html = %{<script type="text/javascript" src="#{File.expand_path(cache_file)}"></script>}
|
||||
# NOTE: In future sprockets versions below could be simplified w/ asset.extensions.include?('.coffee')
|
||||
if asset.pathname.basename.to_s.scan(/\.[^.]+/).include?('.coffee')
|
||||
html += %{\n<script type="text/javascript">window.CSTF['#{File.basename(cache_file)}'] = '#{file}';</script>}
|
||||
end
|
||||
when 'text/css'
|
||||
html = %{<link rel="stylesheet" href="#{File.expand_path(cache_file)}" type="text/css" />}
|
||||
else
|
||||
html = asset.body
|
||||
end
|
||||
html
|
||||
end.compact.reject(&:empty?)
|
||||
end
|
||||
|
||||
@ -270,7 +294,12 @@ module Jasmine::Headless
|
||||
end
|
||||
|
||||
def add_path(path, type = nil)
|
||||
asset = sprockets_environment.find_asset(path)
|
||||
begin
|
||||
asset = sprockets_environment.find_asset(path)
|
||||
rescue => e
|
||||
sprockets_environment.logger.error "#{e.message} (#{e.class})"
|
||||
raise e
|
||||
end
|
||||
|
||||
@required_files << asset
|
||||
|
||||
@ -326,6 +355,10 @@ end
|
||||
module Jasmine::Headless
|
||||
extend self
|
||||
|
||||
def sprockets_environment
|
||||
Jasmine::Headless::FilesList.sprockets_environment
|
||||
end
|
||||
|
||||
def register_engine(file_extension, template_class)
|
||||
Jasmine::Headless::FilesList.register_engine(file_extension, template_class)
|
||||
end
|
||||
|
@ -1,23 +0,0 @@
|
||||
require 'tilt/template'
|
||||
|
||||
module Jasmine::Headless
|
||||
class JSTemplate < Tilt::Template
|
||||
include Jasmine::Headless::FileChecker
|
||||
self.default_mime_type = 'application/javascript'
|
||||
|
||||
def prepare ; end
|
||||
|
||||
def evaluate(scope, locals, &block)
|
||||
if bad_format?(file)
|
||||
alert_bad_format(file)
|
||||
return ''
|
||||
end
|
||||
if data[%r{^<script type="text/javascript"}]
|
||||
data
|
||||
else
|
||||
file ? %{<script type="text/javascript" src="#{file}"></script>} : data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,15 +0,0 @@
|
||||
require 'sprockets/jst_processor'
|
||||
|
||||
module Jasmine::Headless
|
||||
class JSTTemplate < Sprockets::JstProcessor
|
||||
include Jasmine::Headless::FileChecker
|
||||
def evaluate(*args)
|
||||
if bad_format?(file)
|
||||
alert_bad_format(file)
|
||||
return ''
|
||||
end
|
||||
%{<script type="text/javascript">#{super}</script>}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,21 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Jasmine::Headless::CoffeeScriptCache do
|
||||
include FakeFS::SpecHelpers
|
||||
|
||||
describe '#action' do
|
||||
let(:file) { 'file' }
|
||||
let(:data) { 'data' }
|
||||
let(:compiled) { 'compiled' }
|
||||
|
||||
before do
|
||||
CoffeeScript.expects(:compile).with(data).returns(compiled)
|
||||
File.open(file, 'wb') { |fh| fh.print(data) }
|
||||
end
|
||||
|
||||
it 'should compile coffeescript' do
|
||||
described_class.new(file).action.should == compiled
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,55 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Jasmine::Headless::CoffeeTemplate do
|
||||
let(:data) { 'data' }
|
||||
let(:path) { 'path.coffee' }
|
||||
|
||||
let(:template) { described_class.new(path) { data } }
|
||||
|
||||
subject { template.render }
|
||||
|
||||
let(:handle_expectation) { Jasmine::Headless::CoffeeScriptCache.any_instance.stubs(:handle) }
|
||||
|
||||
context 'compilation error' do
|
||||
let(:error) { CoffeeScript::CompilationError.new("fail") }
|
||||
|
||||
before do
|
||||
handle_expectation.raises(error)
|
||||
end
|
||||
|
||||
it 'should pass along the error' do
|
||||
expect { subject }.to raise_error(CoffeeScript::CompilationError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'compiles fine' do
|
||||
let(:source) { 'source' }
|
||||
|
||||
before do
|
||||
Jasmine::Headless::CoffeeScriptCache.any_instance.stubs(:cached?).returns(cache_return)
|
||||
handle_expectation.returns(source)
|
||||
end
|
||||
|
||||
context 'cached' do
|
||||
let(:file_path) { 'dir/file.js' }
|
||||
let(:cache_return) { true }
|
||||
|
||||
before do
|
||||
Jasmine::Headless::CoffeeScriptCache.any_instance.stubs(:cache_file).returns(file_path)
|
||||
end
|
||||
|
||||
it 'should return the cached file' do
|
||||
subject.should include(%{<script type="text/javascript" src="#{file_path}"></script>})
|
||||
end
|
||||
end
|
||||
|
||||
context 'not cached' do
|
||||
let(:cache_return) { false }
|
||||
|
||||
it 'should return the generated js' do
|
||||
subject.should include(%{<script type="text/javascript">#{source}</script>})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,25 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Jasmine::Headless::CSSTemplate do
|
||||
include FakeFS::SpecHelpers
|
||||
|
||||
let(:template) { described_class.new(file) { data } }
|
||||
let(:file) { 'file' }
|
||||
let(:data) { 'data' }
|
||||
|
||||
subject { template.render }
|
||||
|
||||
before do
|
||||
File.open(file, 'wb') if file
|
||||
end
|
||||
|
||||
context "no file'" do
|
||||
let(:file) { nil }
|
||||
|
||||
it { should == data }
|
||||
end
|
||||
|
||||
context 'file' do
|
||||
it { should == %{<link rel="stylesheet" href="#{file}" type="text/css" />} }
|
||||
end
|
||||
end
|
@ -189,6 +189,20 @@ describe Jasmine::Headless::FilesList do
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "#sprockets_environment" do
|
||||
|
||||
before(:each) do
|
||||
Jasmine::Headless::FilesList.reset!
|
||||
end
|
||||
|
||||
it "should return shared class-level sprockets environment that will be used when tests are run" do
|
||||
processor = Object.new
|
||||
described_class.sprockets_environment.register_postprocessor "application/javascript", processor
|
||||
described_class.new.sprockets_environment.postprocessors["application/javascript"].should include(processor)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,31 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Jasmine::Headless::JSTemplate do
|
||||
include FakeFS::SpecHelpers
|
||||
|
||||
let(:template) { described_class.new(file) { data } }
|
||||
let(:file) { 'file' }
|
||||
let(:data) { 'data' }
|
||||
|
||||
subject { template.render }
|
||||
|
||||
before do
|
||||
File.open(file, 'wb') if file
|
||||
end
|
||||
|
||||
context "no file'" do
|
||||
let(:file) { nil }
|
||||
|
||||
it { should == data }
|
||||
end
|
||||
|
||||
context 'file' do
|
||||
it { should == %{<script type="text/javascript" src="#{file}"></script>} }
|
||||
end
|
||||
|
||||
context 'script as first thing' do
|
||||
let(:data) { '<script type="text/javascript"' }
|
||||
|
||||
it { should == data }
|
||||
end
|
||||
end
|
@ -1,21 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Jasmine::Headless::JSTTemplate do
|
||||
include FakeFS::SpecHelpers
|
||||
|
||||
let(:template) { described_class.new(file) }
|
||||
let(:file) { 'file' }
|
||||
let(:data) { 'data' }
|
||||
|
||||
let(:context) { stub(:logical_path => 'path') }
|
||||
|
||||
before do
|
||||
File.open(file, 'wb') { |fh| fh.print data }
|
||||
end
|
||||
|
||||
subject { template.render(context) }
|
||||
|
||||
it { should include(%{<script type="text/javascript">}) }
|
||||
it { should include(data) }
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user