diff --git a/.gitignore b/.gitignore
index 801dd0a..b523b09 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,4 @@ moc_*.*
.DS_Store
hydra-runner.log
jhw-test
+.jhw-cache/
diff --git a/Gemfile b/Gemfile
index fc8fa1e..bfcf6b6 100644
--- a/Gemfile
+++ b/Gemfile
@@ -14,3 +14,4 @@ gem 'rake', '0.8.7'
gem 'mocha', '0.9.12'
gem 'guard-jasmine-headless-webkit'
gem 'facter'
+
diff --git a/lib/jasmine-headless-webkit.rb b/lib/jasmine-headless-webkit.rb
index d5b1fb7..0ca38a4 100644
--- a/lib/jasmine-headless-webkit.rb
+++ b/lib/jasmine-headless-webkit.rb
@@ -1,7 +1,6 @@
module Jasmine
module Headless
- module Webkit
- end
+ autoload :CoffeeScriptCache, 'jasmine/headless/coffee_script_cache'
end
end
diff --git a/lib/jasmine/files_list.rb b/lib/jasmine/files_list.rb
index 0b4db1b..21ed3ce 100644
--- a/lib/jasmine/files_list.rb
+++ b/lib/jasmine/files_list.rb
@@ -1,3 +1,4 @@
+require 'jasmine/headless/coffee_script_cache'
require 'jasmine-core'
require 'iconv'
@@ -66,53 +67,26 @@ module Jasmine
private
def to_html(files)
- coffeescript_run = []
-
files.collect { |file|
- coffeescript_run << file if (ext = File.extname(file)) == '.coffee'
-
- output = []
- if (files.last == file or ext != '.coffee') and !coffeescript_run.empty?
- output << ensure_coffeescript_run!(coffeescript_run)
- end
-
- if ext != '.coffee'
- output << case File.extname(file)
- when '.js'
- %{}
- when '.css'
- %{}
+ case File.extname(file)
+ when '.coffee'
+ begin
+ %{}
+ rescue CoffeeScript::CompilationError => ne
+ puts "[%s] %s: %s" % [ 'coffeescript'.color(:red), file.color(:yellow), ne.message.to_s.color(:white) ]
+ raise ne
+ rescue StandardError => e
+ puts "[%s] Error in compiling one of the followng: %s" % [ 'coffeescript'.color(:red), files.join(' ').color(:yellow) ]
+ raise e
end
+ when '.js'
+ %{}
+ when '.css'
+ %{}
end
-
- output
}.flatten.reject(&:empty?)
end
- def ensure_coffeescript_run!(files)
- data = StringIO.new
- files.each { |file| data << File.read(file) << "\n" }
- data.rewind
-
- %{}
- 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
@spec_filter ||= (@options[:only] ? @options[:only].collect { |path| Dir[path] }.flatten : [])
end
diff --git a/lib/jasmine/headless/coffee_script_cache.rb b/lib/jasmine/headless/coffee_script_cache.rb
new file mode 100644
index 0000000..5a1b103
--- /dev/null
+++ b/lib/jasmine/headless/coffee_script_cache.rb
@@ -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
+
diff --git a/lib/jasmine/headless/options.rb b/lib/jasmine/headless/options.rb
index 7afbd63..fff6302 100644
--- a/lib/jasmine/headless/options.rb
+++ b/lib/jasmine/headless/options.rb
@@ -15,6 +15,7 @@ module Jasmine
:report => false,
:do_list => false,
:full_run => true,
+ :enable_cache => true,
:files => []
}
@@ -42,6 +43,10 @@ module Jasmine
@options[:colors] = true
when '--no-colors', '-nc'
@options[:colors] = false
+ when '--cache'
+ @options[:enable_cache] = true
+ when '--no-cache'
+ @options[:enable_cache] = false
when '--keep'
@options[:remove_html_file] = false
when '--report'
@@ -67,6 +72,8 @@ module Jasmine
command_line_args = GetoptLong.new(
[ '--colors', '-c', GetoptLong::NO_ARGUMENT ],
[ '--no-colors', GetoptLong::NO_ARGUMENT ],
+ [ '--cache', GetoptLong::NO_ARGUMENT ],
+ [ '--no-t stcache', GetoptLong::NO_ARGUMENT ],
[ '--keep', GetoptLong::NO_ARGUMENT ],
[ '--report', GetoptLong::REQUIRED_ARGUMENT ],
[ '--jasmine-config', '-j', GetoptLong::REQUIRED_ARGUMENT ],
diff --git a/lib/jasmine/headless/runner.rb b/lib/jasmine/headless/runner.rb
index f3e4343..7f7613b 100644
--- a/lib/jasmine/headless/runner.rb
+++ b/lib/jasmine/headless/runner.rb
@@ -61,6 +61,8 @@ module Jasmine
end
def run
+ Jasmine::Headless::CoffeeScriptCache.enabled = @options[:enable_cache]
+
files_list = Jasmine::FilesList.new(
:config => jasmine_config,
:only => @options[:files]
diff --git a/spec/lib/jasmine/files_list_spec.rb b/spec/lib/jasmine/files_list_spec.rb
index 26cd34a..9daaade 100644
--- a/spec/lib/jasmine/files_list_spec.rb
+++ b/spec/lib/jasmine/files_list_spec.rb
@@ -147,83 +147,37 @@ describe Jasmine::FilesList do
describe '#.*files_to_html' do
include FakeFS::SpecHelpers
- context 'one coffeescript file' do
- before do
- files_list.instance_variable_set(:@files, [
- 'test.js',
- 'test.coffee',
- 'test.css'
- ])
+ before do
+ files_list.instance_variable_set(:@files, [
+ 'test.js',
+ 'test.coffee',
+ 'test.css'
+ ])
- files_list.instance_variable_set(:@filtered_files, [
- 'test.js',
- 'test.coffee'
- ])
+ files_list.instance_variable_set(:@filtered_files, [
+ 'test.js',
+ '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")
- end
-
- context '#files_to_html' do
- it "should create the right HTML" do
- files_list.files_to_html.should == [
- %{},
- %{},
- %{}
- ]
- end
- end
-
- context '#filtered_files_to_html' do
- it "should create the right HTML" do
- files_list.filtered_files_to_html.should == [
- %{},
- %{}
- ]
- end
+ context '#files_to_html' do
+ it "should create the right HTML" do
+ files_list.files_to_html.should == [
+ %{},
+ %{},
+ %{}
+ ]
end
end
- context 'two coffeescript files' do
- before do
- files_list.instance_variable_set(:@files, [
- 'test.js',
- 'test.coffee',
- '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 == [
- %{},
- %{},
- %{}
- ]
- 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 == [
- %{},
- %{}
- ]
- end
+ context '#filtered_files_to_html' do
+ it "should create the right HTML" do
+ files_list.filtered_files_to_html.should == [
+ %{},
+ %{}
+ ]
end
end
end
diff --git a/spec/lib/jasmine/headless/coffee_script_cache_spec.rb b/spec/lib/jasmine/headless/coffee_script_cache_spec.rb
new file mode 100644
index 0000000..9629a00
--- /dev/null
+++ b/spec/lib/jasmine/headless/coffee_script_cache_spec.rb
@@ -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
+
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 1f9e555..0fcd858 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,3 +1,6 @@
+require 'jasmine-headless-webkit'
+require 'fakefs/spec_helpers'
+
RSpec.configure do |c|
c.mock_with :mocha
end
@@ -10,32 +13,39 @@ if !File.file?(specrunner)
end
end
-RSpec::Matchers.define :be_a_report_containing do |total, fails, used_console|
- match do |filename|
- parts(filename).length.should == 4
- parts[0].should == total.to_s
- parts[1].should == fails.to_s
- parts[2].should == (used_console ? "T" : "F")
- true
+module RSpec::Matchers
+ define :be_a_report_containing do |total, fails, used_console|
+ match do |filename|
+ parts(filename).length.should == 4
+ parts[0].should == total.to_s
+ parts[1].should == fails.to_s
+ 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
- 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})"
+ 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
- def parts(filename = nil)
- @parts ||= File.readlines(filename).first.strip.split('/')
+ define :be_a_file do
+ match do |file|
+ File.file?(file)
+ 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
-