class VCR::Cassette

The media VCR uses to store HTTP interactions for later re-use.

Constants

VALID_RECORD_MODES

The supported record modes.

* :all -- Record every HTTP interactions; do not play any back.
* :none -- Do not record any HTTP interactions; play them back.
* :new_episodes -- Playback previously recorded HTTP interactions and record new ones.
* :once -- Record the HTTP interactions if the cassette has not already been recorded;
           otherwise, playback the HTTP interactions.

Attributes

erb[R]

@return [Boolean, Hash] The cassette's ERB option. The file will be treated as an

ERB template if this has a truthy value. A hash, if provided, will be used as local
variables for the ERB template.
match_requests_on[R]

@return [Array<Symbol, call>] List of request matchers. Used to find a response from an

existing HTTP interaction to play back.
name[R]

@return [#to_s] The name of the cassette. Used to determine the cassette's file name. @see file

re_record_interval[R]

@return [Integer, nil] How frequently (in seconds) the cassette should be re-recorded.

record_mode[R]

@return [Symbol] The record mode. Determines whether the cassette records HTTP interactions,

plays them back, or does both.
tags[R]

@return [Array<Symbol>] If set, {VCR::Configuration#before_record} and

{VCR::Configuration#before_playback} hooks with a corresponding tag will apply.

Public Class Methods

const_missing(const) click to toggle source

@private

Calls superclass method
# File lib/vcr/deprecations.rb, line 17
def Cassette.const_missing(const)
  return super unless const == :MissingERBVariableError
  warn "WARNING: `VCR::Cassette::MissingERBVariableError` is deprecated.  Use `VCR::Errors::MissingERBVariableError` instead."
  Errors::MissingERBVariableError
end
new(name, options = {}) click to toggle source

@param (see VCR#insert_cassette) @see VCR#insert_cassette

# File lib/vcr/cassette.rb, line 45
def initialize(name, options = {})
  @name    = name
  @options = VCR.configuration.default_cassette_options.merge(options)

  assert_valid_options!
  extract_options
  raise_error_unless_valid_record_mode

  log "Initialized with options: #{@options.inspect}"
end

Public Instance Methods

eject() click to toggle source

Ejects the current cassette. The cassette will no longer be used. In addition, any newly recorded HTTP interactions will be written to disk.

# File lib/vcr/cassette.rb, line 59
def eject
  write_recorded_interactions_to_disk
  http_interactions.assert_no_unused_interactions! unless @allow_unused_http_interactions
end
file() click to toggle source

@return [String] The file for this cassette. @raise [NotImplementedError] if the configured cassette persister

does not support resolving file paths.

@note VCR will take care of sanitizing the cassette name to make it a valid file name.

# File lib/vcr/cassette.rb, line 89
def file
  unless @persister.respond_to?(:absolute_path_to_file)
    raise NotImplementedError, "The configured cassette persister does not support resolving file paths"
  end
  @persister.absolute_path_to_file(storage_key)
end
http_interactions() click to toggle source

@private

# File lib/vcr/cassette.rb, line 65
def http_interactions
  @http_interactions ||= HTTPInteractionList.new          should_stub_requests? ? previously_recorded_interactions : [],
    match_requests_on,
    @allow_playback_repeats,
    @parent_list,
    log_prefix
end
new_recorded_interactions() click to toggle source

@private

# File lib/vcr/cassette.rb, line 81
def new_recorded_interactions
  @new_recorded_interactions ||= []
end
record_http_interaction(interaction) click to toggle source

@private

# File lib/vcr/cassette.rb, line 75
def record_http_interaction(interaction)
  log "Recorded HTTP interaction #{request_summary(interaction.request)} => #{response_summary(interaction.response)}"
  new_recorded_interactions << interaction
end
recording?() click to toggle source

@return [Boolean] Whether or not the cassette is recording.

# File lib/vcr/cassette.rb, line 97
def recording?
  case record_mode
    when :none; false
    when :once; raw_cassette_bytes.to_s.empty?
    else true
  end
end
serializable_hash() click to toggle source

@return [Hash] The hash that will be serialized when the cassette is written to disk.

# File lib/vcr/cassette.rb, line 106
def serializable_hash
  {
    "http_interactions" => interactions_to_record.map(&:to_hash),
    "recorded_with"     => "VCR #{VCR.version}"
  }
end

Private Instance Methods

assert_valid_options!() click to toggle source
# File lib/vcr/cassette.rb, line 115
def assert_valid_options!
  invalid_options = @options.keys - [
    :record, :erb, :match_requests_on, :re_record_interval, :tag, :tags,
    :update_content_length_header, :allow_playback_repeats, :allow_unused_http_interactions,
    :exclusive, :serialize_with, :preserve_exact_body_bytes, :decode_compressed_response,
    :persist_with
  ]

  if invalid_options.size > 0
    raise ArgumentError.new("You passed the following invalid options to VCR::Cassette.new: #{invalid_options.inspect}.")
  end
end
assign_tags() click to toggle source
# File lib/vcr/cassette.rb, line 143
def assign_tags
  @tags = Array(@options.fetch(:tags) { @options[:tag] })

  [:update_content_length_header, :preserve_exact_body_bytes, :decode_compressed_response].each do |tag|
    @tags << tag if @options[tag]
  end
end
deserialized_hash() click to toggle source
# File lib/vcr/cassette.rb, line 247
def deserialized_hash
  @deserialized_hash ||= @serializer.deserialize(raw_cassette_bytes).tap do |hash|
    unless hash.is_a?(Hash) && hash['http_interactions'].is_a?(Array)
      raise Errors::InvalidCassetteFormatError.new              "#{file} does not appear to be a valid VCR 2.0 cassette. " +
        "VCR 1.x cassettes are not valid with VCR 2.0. When upgrading from " +
        "VCR 1.x, it is recommended that you delete all your existing cassettes and " +
        "re-record them, or use the provided vcr:migrate_cassettes rake task to migrate " +
        "them. For more info, see the VCR upgrade guide."
    end
  end
end
earliest_interaction_recorded_at() click to toggle source
# File lib/vcr/cassette.rb, line 196
def earliest_interaction_recorded_at
  previously_recorded_interactions.map(&:recorded_at).min
end
extract_options() click to toggle source
# File lib/vcr/cassette.rb, line 128
def extract_options
  [:erb, :match_requests_on, :re_record_interval,
   :allow_playback_repeats, :allow_unused_http_interactions, :exclusive].each do |name|
    instance_variable_set("@#{name}", @options[name])
  end

  assign_tags

  @record_mode = @options[:record]
  @serializer  = VCR.cassette_serializers[@options[:serialize_with]]
  @persister   = VCR.cassette_persisters[@options[:persist_with]]
  @record_mode = :all if should_re_record?
  @parent_list = @exclusive ? HTTPInteractionList::NullList : VCR.http_interactions
end
interactions_to_record() click to toggle source
# File lib/vcr/cassette.rb, line 225
def interactions_to_record
  merged_interactions.tap do |interactions|
    invoke_hook(:before_record, interactions)
  end
end
invoke_hook(type, interactions) click to toggle source
# File lib/vcr/cassette.rb, line 239
def invoke_hook(type, interactions)
  interactions.delete_if do |i|
    i.hook_aware.tap do |hw|
      VCR.configuration.invoke_hook(type, hw, self)
    end.ignored?
  end
end
log_prefix() click to toggle source
# File lib/vcr/cassette.rb, line 260
def log_prefix
  @log_prefix ||= "[Cassette: '#{name}'] "
end
merged_interactions() click to toggle source
# File lib/vcr/cassette.rb, line 212
def merged_interactions
  old_interactions = previously_recorded_interactions

  if should_remove_matching_existing_interactions?
    new_interaction_list = HTTPInteractionList.new(new_recorded_interactions, match_requests_on)
    old_interactions = old_interactions.reject do |i|
      new_interaction_list.response_for(i.request)
    end
  end

  old_interactions + new_recorded_interactions
end
previously_recorded_interactions() click to toggle source
# File lib/vcr/cassette.rb, line 151
def previously_recorded_interactions
  @previously_recorded_interactions ||= if !raw_cassette_bytes.to_s.empty?
    deserialized_hash['http_interactions'].map { |h| HTTPInteraction.from_hash(h) }.tap do |interactions|
      invoke_hook(:before_playback, interactions)

      interactions.reject! do |i|
        i.request.uri.is_a?(String) && VCR.request_ignorer.ignore?(i.request)
      end
    end
  else
    []
  end
end
raise_error_unless_valid_record_mode() click to toggle source
# File lib/vcr/cassette.rb, line 169
def raise_error_unless_valid_record_mode
  unless VALID_RECORD_MODES.include?(record_mode)
    raise ArgumentError.new("#{record_mode} is not a valid cassette record mode.  Valid modes are: #{VALID_RECORD_MODES.inspect}")
  end
end
raw_cassette_bytes() click to toggle source
# File lib/vcr/cassette.rb, line 208
def raw_cassette_bytes
  @raw_cassette_bytes ||= VCR::Cassette::ERBRenderer.new(@persister[storage_key], erb, name).render
end
request_summary(request) click to toggle source
Calls superclass method VCR::Logger#request_summary
# File lib/vcr/cassette.rb, line 264
def request_summary(request)
  super(request, match_requests_on)
end
should_re_record?() click to toggle source
# File lib/vcr/cassette.rb, line 175
def should_re_record?
  return false unless @re_record_interval
  previously_recorded_at = earliest_interaction_recorded_at
  return false unless previously_recorded_at

  now = Time.now

  (previously_recorded_at + @re_record_interval < now).tap do |value|
    info = "previously recorded at: '#{previously_recorded_at}'; now: '#{now}'; interval: #{@re_record_interval} seconds"

    if !value
      log "Not re-recording since the interval has not elapsed (#{info})."
    elsif InternetConnection.available?
      log "re-recording (#{info})."
    else
      log "Not re-recording because no internet connection is available (#{info})."
      return false
    end
  end
end
should_remove_matching_existing_interactions?() click to toggle source
# File lib/vcr/cassette.rb, line 204
def should_remove_matching_existing_interactions?
  record_mode == :all
end
should_stub_requests?() click to toggle source
# File lib/vcr/cassette.rb, line 200
def should_stub_requests?
  record_mode != :all
end
storage_key() click to toggle source
# File lib/vcr/cassette.rb, line 165
def storage_key
  @storage_key ||= [name, @serializer.file_extension].join('.')
end
write_recorded_interactions_to_disk() click to toggle source
# File lib/vcr/cassette.rb, line 231
def write_recorded_interactions_to_disk
  return if new_recorded_interactions.none?
  hash = serializable_hash
  return if hash["http_interactions"].none?

  @persister[storage_key] = @serializer.serialize(hash)
end