Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

base fork: myronmarston/vcr
...
head fork: myronmarston/vcr
  • 4 commits
  • 7 files changed
  • 0 commit comments
  • 1 contributor
Commits on Dec 03, 2011
Myron Marston Fix spec to match method name. 2394ca6
Myron Marston Refactor to use a Cassette::Cache interface.
Note that the cache is not yet implemented--it currently just delegates to the file system.  But this gives us the interface that we want.
7304205
Myron Marston Started implementing cassette cache. 70ca447
Myron Marston First pass at pre-caching the cassettes. 0fc42e7
5 lib/vcr.rb
View
@@ -1,6 +1,7 @@
require 'vcr/util/variable_args_block_caller'
require 'vcr/cassette'
+require 'vcr/cassette/cache'
require 'vcr/cassette/serializers'
require 'vcr/configuration'
require 'vcr/deprecations'
@@ -89,6 +90,10 @@ def cassette_serializers
@cassette_serializers ||= Cassette::Serializers.new
end
+ def cassette_cache
+ @cassette_cache ||= Cassette::Cache.new
+ end
+
def configuration
@configuration ||= Configuration.new
end
9 lib/vcr/cassette.rb
View
@@ -44,7 +44,7 @@ def eject
end
def previously_recorded_interactions
- @previously_recorded_interactions ||= if file && File.size?(file)
+ @previously_recorded_interactions ||= if file && VCR.cassette_cache.exists_with_content?(file)
deserialized_hash['http_interactions'].map { |h| HTTPInteraction.from_hash(h) }.tap do |interactions|
invoke_hook(:before_playback, interactions)
@@ -89,7 +89,7 @@ def update_content_length_header?
def recording?
case record_mode
when :none; false
- when :once; file.nil? || !File.size?(file)
+ when :once; file.nil? || !VCR.cassette_cache.exists_with_content?(file)
else true
end
end
@@ -116,7 +116,6 @@ def raise_error_unless_valid_record_mode
def should_re_record?
return false unless @re_record_interval
return false unless earliest_interaction_recorded_at
- return false unless File.exist?(file)
return false unless InternetConnection.available?
earliest_interaction_recorded_at + @re_record_interval < Time.now
@@ -163,9 +162,7 @@ def write_recorded_interactions_to_disk
hash = serializable_hash
return if hash["http_interactions"].none?
- directory = File.dirname(file)
- FileUtils.mkdir_p directory unless File.exist?(directory)
- File.open(file, 'w') { |f| f.write @serializer.serialize(hash) }
+ VCR.cassette_cache[file] = @serializer.serialize(hash)
end
def invoke_hook(type, interactions)
62 lib/vcr/cassette/cache.rb
View
@@ -0,0 +1,62 @@
+require 'thread'
+
+module VCR
+ class Cassette
+ class Cache
+ def initialize
+ @files = Hash.new do |files, file_name|
+ files[file_name] = File.exist?(file_name) ?
+ File.read(file_name) :
+ nil
+ end
+
+ @mutex = Mutex.new
+ @file_queue = Queue.new
+ end
+
+ def [](file_name)
+ @mutex.synchronize do
+ @files[file_name]
+ end
+ end
+
+ def exists_with_content?(file_name)
+ @mutex.synchronize do
+ @files[file_name].to_s.size > 0
+ end
+ end
+
+ # TODO: test me
+ def []=(file_name, content)
+ directory = File.dirname(file_name)
+ FileUtils.mkdir_p directory unless File.exist?(directory)
+ File.open(file_name, 'w') { |f| f.write content }
+
+ @mutex.synchronize do
+ @files[file_name] = content
+ end
+ end
+
+ def prefetch_from(directory)
+ @threads = 20.times.map do
+ Thread.new do
+ loop do
+ file_name = @file_queue.pop
+ break if file_name == :exit
+ @mutex.synchronize do
+ @files[file_name] = File.read(file_name)
+ end
+ end
+ end
+ end
+
+ Dir["#{directory}/**/*.yml"].each do |file_name|
+ @file_queue << file_name
+ end
+
+ 20.times { @file_queue << :exit }
+ end
+ end
+ end
+end
+
2  lib/vcr/cassette/reader.rb
View
@@ -33,7 +33,7 @@ def erb_variables
end
def file_content
- @file_content ||= File.read(@file_name)
+ @file_content ||= VCR.cassette_cache[@file_name]
end
def template
1  lib/vcr/configuration.rb
View
@@ -25,6 +25,7 @@ def initialize
def cassette_library_dir=(cassette_library_dir)
@cassette_library_dir = cassette_library_dir
FileUtils.mkdir_p(cassette_library_dir) if cassette_library_dir
+ VCR.cassette_cache.prefetch_from(cassette_library_dir)
end
attr_reader :default_cassette_options
69 spec/vcr/cassette/cache_spec.rb
View
@@ -0,0 +1,69 @@
+require 'vcr/cassette/cache'
+
+module VCR
+ class Cassette
+ describe Cache do
+ describe "#[]" do
+ let(:content) { "the file content" }
+ let(:file_name) { "file.yml" }
+
+ it 'only reads the file once' do
+ File.stub(:exist?).with(file_name).and_return(true)
+ File.should_receive(:read).with(file_name).once.and_return(content)
+ subject[file_name].should eq(content)
+ subject[file_name].should eq(content)
+ subject[file_name].should eq(content)
+ end
+ end
+
+ describe "#exists_with_content?" do
+ context 'when the file exists with no content' do
+ let(:file_name) { "zero_bytes.yml" }
+
+ before(:each) do
+ File.stub(:exist?).with(file_name).and_return(true)
+ File.stub(:read).with(file_name).and_return("")
+ end
+
+ it 'returns false' do
+ subject.exists_with_content?(file_name).should be_false
+ end
+
+ it 'does not read the file multiple times' do
+ File.should_receive(:read).once
+ subject.exists_with_content?(file_name)
+ subject.exists_with_content?(file_name)
+ subject.exists_with_content?(file_name)
+ end
+
+ it "does not check for the file's existence multiple times" do
+ File.should_receive(:exist?).once
+ subject.exists_with_content?(file_name)
+ subject.exists_with_content?(file_name)
+ subject.exists_with_content?(file_name)
+ end
+ end
+
+ context 'when the file does not exist' do
+ let(:file_name) { "non_existant_file.yml" }
+
+ it 'returns false' do
+ subject.exists_with_content?(file_name).should be_false
+ end
+
+ it 'does not attempt to read the file' do
+ File.should_not_receive(:read)
+ subject.exists_with_content?(file_name)
+ end
+
+ it "does not check for the file's existence multiple times" do
+ File.should_receive(:exist?).once.with(file_name).and_return(false)
+ subject.exists_with_content?(file_name)
+ subject.exists_with_content?(file_name)
+ subject.exists_with_content?(file_name)
+ end
+ end
+ end
+ end
+ end
+end
9 spec/vcr_spec.rb
View
@@ -157,13 +157,20 @@ def insert_cassette(name = :cassette_test)
end
end
- describe '.serializers' do
+ describe '.cassette_serializers' do
it 'always returns the same memoized cassette serializers instance' do
VCR.cassette_serializers.should be_a(VCR::Cassette::Serializers)
VCR.cassette_serializers.should be(VCR.cassette_serializers)
end
end
+ describe '.cassette_cache' do
+ it 'always returns the same memoized cassette cache instance' do
+ VCR.cassette_cache.should be_a(VCR::Cassette::Cache)
+ VCR.cassette_cache.should be(VCR.cassette_cache)
+ end
+ end
+
describe '.configuration' do
it 'returns the configuration object' do
VCR.configuration.should be_a(VCR::Configuration)

No commit comments for this range

Something went wrong with that request. Please try again.