enable coffeescript cache, step 1 of a big speedup
This commit is contained in:
parent
bd8fa3e536
commit
fa27ee715a
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,3 +11,4 @@ moc_*.*
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
hydra-runner.log
|
hydra-runner.log
|
||||||
jhw-test
|
jhw-test
|
||||||
|
.jhw-cache/
|
||||||
|
1
Gemfile
1
Gemfile
@ -14,3 +14,4 @@ gem 'rake', '0.8.7'
|
|||||||
gem 'mocha', '0.9.12'
|
gem 'mocha', '0.9.12'
|
||||||
gem 'guard-jasmine-headless-webkit'
|
gem 'guard-jasmine-headless-webkit'
|
||||||
gem 'facter'
|
gem 'facter'
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
module Jasmine
|
module Jasmine
|
||||||
module Headless
|
module Headless
|
||||||
module Webkit
|
autoload :CoffeeScriptCache, 'jasmine/headless/coffee_script_cache'
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
require 'jasmine/headless/coffee_script_cache'
|
||||||
require 'jasmine-core'
|
require 'jasmine-core'
|
||||||
require 'iconv'
|
require 'iconv'
|
||||||
|
|
||||||
@ -66,53 +67,26 @@ module Jasmine
|
|||||||
|
|
||||||
private
|
private
|
||||||
def to_html(files)
|
def to_html(files)
|
||||||
coffeescript_run = []
|
|
||||||
|
|
||||||
files.collect { |file|
|
files.collect { |file|
|
||||||
coffeescript_run << file if (ext = File.extname(file)) == '.coffee'
|
case File.extname(file)
|
||||||
|
when '.coffee'
|
||||||
output = []
|
begin
|
||||||
if (files.last == file or ext != '.coffee') and !coffeescript_run.empty?
|
%{<script type="text/javascript">#{Jasmine::Headless::CoffeeScriptCache.for(file)}</script>}
|
||||||
output << ensure_coffeescript_run!(coffeescript_run)
|
rescue CoffeeScript::CompilationError => ne
|
||||||
end
|
puts "[%s] %s: %s" % [ 'coffeescript'.color(:red), file.color(:yellow), ne.message.to_s.color(:white) ]
|
||||||
|
raise ne
|
||||||
if ext != '.coffee'
|
rescue StandardError => e
|
||||||
output << case File.extname(file)
|
puts "[%s] Error in compiling one of the followng: %s" % [ 'coffeescript'.color(:red), files.join(' ').color(:yellow) ]
|
||||||
when '.js'
|
raise e
|
||||||
%{<script type="text/javascript" src="#{file}"></script>}
|
|
||||||
when '.css'
|
|
||||||
%{<link rel="stylesheet" href="#{file}" type="text/css" />}
|
|
||||||
end
|
end
|
||||||
|
when '.js'
|
||||||
|
%{<script type="text/javascript" src="#{file}"></script>}
|
||||||
|
when '.css'
|
||||||
|
%{<link rel="stylesheet" href="#{file}" type="text/css" />}
|
||||||
end
|
end
|
||||||
|
|
||||||
output
|
|
||||||
}.flatten.reject(&:empty?)
|
}.flatten.reject(&:empty?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_coffeescript_run!(files)
|
|
||||||
data = StringIO.new
|
|
||||||
files.each { |file| data << File.read(file) << "\n" }
|
|
||||||
data.rewind
|
|
||||||
|
|
||||||
%{<script type="text/javascript">#{CoffeeScript.compile(data)}</script>}
|
|
||||||
rescue CoffeeScript::CompilationError => e
|
|
||||||
files.each do |file|
|
|
||||||
begin
|
|
||||||
CoffeeScript.compile(fh = File.open(file))
|
|
||||||
rescue CoffeeScript::CompilationError => ne
|
|
||||||
puts "[%s] %s: %s" % [ 'coffeescript'.color(:red), file.color(:yellow), ne.message.to_s.color(:white) ]
|
|
||||||
raise ne
|
|
||||||
ensure
|
|
||||||
fh.close
|
|
||||||
end
|
|
||||||
end
|
|
||||||
rescue StandardError => e
|
|
||||||
puts "[%s] Error in compiling one of the followng: %s" % [ 'coffeescript'.color(:red), files.join(' ').color(:yellow) ]
|
|
||||||
raise e
|
|
||||||
ensure
|
|
||||||
files.clear
|
|
||||||
end
|
|
||||||
|
|
||||||
def spec_filter
|
def spec_filter
|
||||||
@spec_filter ||= (@options[:only] ? @options[:only].collect { |path| Dir[path] }.flatten : [])
|
@spec_filter ||= (@options[:only] ? @options[:only].collect { |path| Dir[path] }.flatten : [])
|
||||||
end
|
end
|
||||||
|
66
lib/jasmine/headless/coffee_script_cache.rb
Normal file
66
lib/jasmine/headless/coffee_script_cache.rb
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
require 'coffee_script'
|
||||||
|
require 'digest/sha1'
|
||||||
|
require 'fileutils'
|
||||||
|
|
||||||
|
module Jasmine
|
||||||
|
module Headless
|
||||||
|
class CoffeeScriptCache
|
||||||
|
class << self
|
||||||
|
def enabled=(bool)
|
||||||
|
@enabled = bool
|
||||||
|
end
|
||||||
|
|
||||||
|
def enabled?
|
||||||
|
@enabled = true if @enabled == nil
|
||||||
|
@enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_dir=(dir)
|
||||||
|
@cache_dir = dir
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_dir
|
||||||
|
@cache_dir ||= '.jhw-cache'
|
||||||
|
end
|
||||||
|
|
||||||
|
def for(file)
|
||||||
|
new(file).handle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :file
|
||||||
|
|
||||||
|
def initialize(file)
|
||||||
|
@file = file
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle
|
||||||
|
if self.class.enabled?
|
||||||
|
if fresh?
|
||||||
|
File.read(cache_file)
|
||||||
|
else
|
||||||
|
result = compile
|
||||||
|
FileUtils.mkdir_p self.class.cache_dir
|
||||||
|
File.open(cache_file, 'wb') { |fh| fh.print result }
|
||||||
|
result
|
||||||
|
end
|
||||||
|
else
|
||||||
|
compile
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_file
|
||||||
|
@cache_file ||= File.join(self.class.cache_dir, Digest::SHA1.hexdigest(file))
|
||||||
|
end
|
||||||
|
|
||||||
|
def fresh?
|
||||||
|
File.exist?(cache_file) && (File.mtime(file) < File.mtime(cache_file))
|
||||||
|
end
|
||||||
|
|
||||||
|
def compile
|
||||||
|
CoffeeScript.compile(File.read(file))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -15,6 +15,7 @@ module Jasmine
|
|||||||
:report => false,
|
:report => false,
|
||||||
:do_list => false,
|
:do_list => false,
|
||||||
:full_run => true,
|
:full_run => true,
|
||||||
|
:enable_cache => true,
|
||||||
:files => []
|
:files => []
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +43,10 @@ module Jasmine
|
|||||||
@options[:colors] = true
|
@options[:colors] = true
|
||||||
when '--no-colors', '-nc'
|
when '--no-colors', '-nc'
|
||||||
@options[:colors] = false
|
@options[:colors] = false
|
||||||
|
when '--cache'
|
||||||
|
@options[:enable_cache] = true
|
||||||
|
when '--no-cache'
|
||||||
|
@options[:enable_cache] = false
|
||||||
when '--keep'
|
when '--keep'
|
||||||
@options[:remove_html_file] = false
|
@options[:remove_html_file] = false
|
||||||
when '--report'
|
when '--report'
|
||||||
@ -67,6 +72,8 @@ module Jasmine
|
|||||||
command_line_args = GetoptLong.new(
|
command_line_args = GetoptLong.new(
|
||||||
[ '--colors', '-c', GetoptLong::NO_ARGUMENT ],
|
[ '--colors', '-c', GetoptLong::NO_ARGUMENT ],
|
||||||
[ '--no-colors', GetoptLong::NO_ARGUMENT ],
|
[ '--no-colors', GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ '--cache', GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ '--no-t stcache', GetoptLong::NO_ARGUMENT ],
|
||||||
[ '--keep', GetoptLong::NO_ARGUMENT ],
|
[ '--keep', GetoptLong::NO_ARGUMENT ],
|
||||||
[ '--report', GetoptLong::REQUIRED_ARGUMENT ],
|
[ '--report', GetoptLong::REQUIRED_ARGUMENT ],
|
||||||
[ '--jasmine-config', '-j', GetoptLong::REQUIRED_ARGUMENT ],
|
[ '--jasmine-config', '-j', GetoptLong::REQUIRED_ARGUMENT ],
|
||||||
|
@ -61,6 +61,8 @@ module Jasmine
|
|||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
|
Jasmine::Headless::CoffeeScriptCache.enabled = @options[:enable_cache]
|
||||||
|
|
||||||
files_list = Jasmine::FilesList.new(
|
files_list = Jasmine::FilesList.new(
|
||||||
:config => jasmine_config,
|
:config => jasmine_config,
|
||||||
:only => @options[:files]
|
:only => @options[:files]
|
||||||
|
@ -147,83 +147,37 @@ describe Jasmine::FilesList do
|
|||||||
describe '#.*files_to_html' do
|
describe '#.*files_to_html' do
|
||||||
include FakeFS::SpecHelpers
|
include FakeFS::SpecHelpers
|
||||||
|
|
||||||
context 'one coffeescript file' do
|
before do
|
||||||
before do
|
files_list.instance_variable_set(:@files, [
|
||||||
files_list.instance_variable_set(:@files, [
|
'test.js',
|
||||||
'test.js',
|
'test.coffee',
|
||||||
'test.coffee',
|
'test.css'
|
||||||
'test.css'
|
])
|
||||||
])
|
|
||||||
|
|
||||||
files_list.instance_variable_set(:@filtered_files, [
|
files_list.instance_variable_set(:@filtered_files, [
|
||||||
'test.js',
|
'test.js',
|
||||||
'test.coffee'
|
'test.coffee'
|
||||||
])
|
])
|
||||||
|
|
||||||
File.open('test.coffee', 'w') { |fh| fh.print "first" }
|
Jasmine::Headless::CoffeeScriptCache.stubs(:for).with('test.coffee').returns("i compiled")
|
||||||
|
end
|
||||||
|
|
||||||
CoffeeScript.stubs(:compile).with() { |field| field.read == "first\n" }.returns("i compiled")
|
context '#files_to_html' do
|
||||||
end
|
it "should create the right HTML" do
|
||||||
|
files_list.files_to_html.should == [
|
||||||
context '#files_to_html' do
|
%{<script type="text/javascript" src="test.js"></script>},
|
||||||
it "should create the right HTML" do
|
%{<script type="text/javascript">i compiled</script>},
|
||||||
files_list.files_to_html.should == [
|
%{<link rel="stylesheet" href="test.css" type="text/css" />}
|
||||||
%{<script type="text/javascript" src="test.js"></script>},
|
]
|
||||||
%{<script type="text/javascript">i compiled</script>},
|
|
||||||
%{<link rel="stylesheet" href="test.css" type="text/css" />}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '#filtered_files_to_html' do
|
|
||||||
it "should create the right HTML" do
|
|
||||||
files_list.filtered_files_to_html.should == [
|
|
||||||
%{<script type="text/javascript" src="test.js"></script>},
|
|
||||||
%{<script type="text/javascript">i compiled</script>}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'two coffeescript files' do
|
context '#filtered_files_to_html' do
|
||||||
before do
|
it "should create the right HTML" do
|
||||||
files_list.instance_variable_set(:@files, [
|
files_list.filtered_files_to_html.should == [
|
||||||
'test.js',
|
%{<script type="text/javascript" src="test.js"></script>},
|
||||||
'test.coffee',
|
%{<script type="text/javascript">i compiled</script>}
|
||||||
'test2.coffee',
|
]
|
||||||
'test.css'
|
|
||||||
])
|
|
||||||
|
|
||||||
files_list.instance_variable_set(:@filtered_files, [
|
|
||||||
'test.js',
|
|
||||||
'test.coffee'
|
|
||||||
])
|
|
||||||
|
|
||||||
File.open('test.coffee', 'w') { |fh| fh.print "first" }
|
|
||||||
File.open('test2.coffee', 'w') { |fh| fh.print "second" }
|
|
||||||
end
|
|
||||||
|
|
||||||
context '#files_to_html' do
|
|
||||||
it "should create the right HTML" do
|
|
||||||
CoffeeScript.stubs(:compile).with() { |field| field.read == "first\nsecond\n" }.returns("i compiled")
|
|
||||||
|
|
||||||
files_list.files_to_html.should == [
|
|
||||||
%{<script type="text/javascript" src="test.js"></script>},
|
|
||||||
%{<script type="text/javascript">i compiled</script>},
|
|
||||||
%{<link rel="stylesheet" href="test.css" type="text/css" />}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '#filtered_files_to_html' do
|
|
||||||
it "should create the right HTML" do
|
|
||||||
CoffeeScript.stubs(:compile).with() { |field| field.read == "first\n" }.returns("i compiled")
|
|
||||||
|
|
||||||
files_list.filtered_files_to_html.should == [
|
|
||||||
%{<script type="text/javascript" src="test.js"></script>},
|
|
||||||
%{<script type="text/javascript">i compiled</script>}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
87
spec/lib/jasmine/headless/coffee_script_cache_spec.rb
Normal file
87
spec/lib/jasmine/headless/coffee_script_cache_spec.rb
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Jasmine::Headless::CoffeeScriptCache do
|
||||||
|
include FakeFS::SpecHelpers
|
||||||
|
|
||||||
|
let(:file) { 'file.coffee' }
|
||||||
|
let(:data) { 'data' }
|
||||||
|
let(:compiled) { 'compiled' }
|
||||||
|
|
||||||
|
before do
|
||||||
|
File.open(file, 'wb') { |fh| fh.print(data) }
|
||||||
|
described_class.cache_dir = cache_dir
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:coffee_script_compiles!) do
|
||||||
|
CoffeeScript.expects(:compile).with(data).returns(compiled)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:cache_dir) { 'cache' }
|
||||||
|
let(:cache_file) { File.join(cache_dir, Digest::SHA1.hexdigest(file)) }
|
||||||
|
let(:cache_file_data) { File.read(cache_file) }
|
||||||
|
|
||||||
|
describe '.for' do
|
||||||
|
context 'cache disabled' do
|
||||||
|
before do
|
||||||
|
described_class.enabled = false
|
||||||
|
p described_class.enabled?
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should compile' do
|
||||||
|
coffee_script_compiles!
|
||||||
|
described_class.for(file).should == compiled
|
||||||
|
cache_file.should_not be_a_file
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'cache enabled' do
|
||||||
|
before do
|
||||||
|
described_class.enabled = true
|
||||||
|
FileUtils.mkdir_p(cache_dir)
|
||||||
|
|
||||||
|
File.stubs(:mtime).with(file).returns(Time.at(10))
|
||||||
|
File.stubs(:mtime).with(cache_file).returns(Time.at(cache_file_mtime))
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'cache empty' do
|
||||||
|
let(:cache_file_mtime) { 0 }
|
||||||
|
|
||||||
|
it 'should compile' do
|
||||||
|
coffee_script_compiles!
|
||||||
|
described_class.for(file).should == compiled
|
||||||
|
|
||||||
|
cache_file_data.should == compiled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'cache fresh' do
|
||||||
|
let(:cache_file_mtime) { 15 }
|
||||||
|
|
||||||
|
before do
|
||||||
|
File.open(cache_file, 'wb') { |fh| fh.print compiled }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should not compile' do
|
||||||
|
coffee_script_compiles!.never
|
||||||
|
|
||||||
|
described_class.for(file).should == compiled
|
||||||
|
|
||||||
|
cache_file_data.should == compiled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'cache stale' do
|
||||||
|
let(:cache_file_mtime) { 5 }
|
||||||
|
|
||||||
|
it 'should compile' do
|
||||||
|
coffee_script_compiles!
|
||||||
|
|
||||||
|
described_class.for(file).should == compiled
|
||||||
|
|
||||||
|
cache_file_data.should == compiled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,3 +1,6 @@
|
|||||||
|
require 'jasmine-headless-webkit'
|
||||||
|
require 'fakefs/spec_helpers'
|
||||||
|
|
||||||
RSpec.configure do |c|
|
RSpec.configure do |c|
|
||||||
c.mock_with :mocha
|
c.mock_with :mocha
|
||||||
end
|
end
|
||||||
@ -10,32 +13,39 @@ if !File.file?(specrunner)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
RSpec::Matchers.define :be_a_report_containing do |total, fails, used_console|
|
module RSpec::Matchers
|
||||||
match do |filename|
|
define :be_a_report_containing do |total, fails, used_console|
|
||||||
parts(filename).length.should == 4
|
match do |filename|
|
||||||
parts[0].should == total.to_s
|
parts(filename).length.should == 4
|
||||||
parts[1].should == fails.to_s
|
parts[0].should == total.to_s
|
||||||
parts[2].should == (used_console ? "T" : "F")
|
parts[1].should == fails.to_s
|
||||||
true
|
parts[2].should == (used_console ? "T" : "F")
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
failure_message_for_should do |filename|
|
||||||
|
parts(filename)
|
||||||
|
"expected #{filename} to be a report containing (#{total}, #{fails}, #{used_console.inspect}), instead it contained (#{parts[0]}, #{parts[1]}, #{(parts[2] == "T").inspect})"
|
||||||
|
end
|
||||||
|
|
||||||
|
def parts(filename = nil)
|
||||||
|
@parts ||= File.readlines(filename).first.strip.split('/')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
failure_message_for_should do |filename|
|
define :contain_a_failing_spec do |*parts|
|
||||||
parts(filename)
|
match do |filename|
|
||||||
"expected #{filename} to be a report containing (#{total}, #{fails}, #{used_console.inspect}), instead it contained (#{parts[0]}, #{parts[1]}, #{(parts[2] == "T").inspect})"
|
report(filename).include?(parts.join("||")).should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
def report(filename)
|
||||||
|
@report ||= File.readlines(filename)[1..-1].collect(&:strip)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parts(filename = nil)
|
define :be_a_file do
|
||||||
@parts ||= File.readlines(filename).first.strip.split('/')
|
match do |file|
|
||||||
|
File.file?(file)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
RSpec::Matchers.define :contain_a_failing_spec do |*parts|
|
|
||||||
match do |filename|
|
|
||||||
report(filename).include?(parts.join("||")).should be_true
|
|
||||||
end
|
|
||||||
|
|
||||||
def report(filename)
|
|
||||||
@report ||= File.readlines(filename)[1..-1].collect(&:strip)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user