lib/vcr/middleware/rack.rb
module VCR
module Middleware
# Object yielded by VCR's {Rack} middleware that allows you to configure
# the cassette dynamically based on the rack env.
class CassetteArguments
# @private
def initialize
@name = nil
@options = {}
end
# Sets (and gets) the cassette name.
#
# @param [#to_s] name the cassette name
# @return [#to_s] the cassette name
def name(name = nil)
@name = name if name
@name
end
# Sets (and gets) the cassette options.
#
# @param [Hash] options the cassette options
# @return [Hash] the cassette options
def options(options = {})
@options.merge!(options)
end
end
# Rack middleware that uses a VCR cassette for each incoming HTTP request.
#
# @example
# app = Rack::Builder.new do
# use VCR::Middleware::Rack do |cassette, env|
# cassette.name "rack/#{env['SERVER_NAME']}"
# cassette.options :record => :new_episodes
# end
#
# run MyRackApp
# end
#
# @note This will record/replay _outbound_ HTTP requests made by your rack app.
class Rack
include VCR::VariableArgsBlockCaller
# Constructs a new instance of VCR's rack middleware.
#
# @param [#call] app the rack app
# @yield the cassette configuration block
# @yieldparam [CassetteArguments] cassette the cassette configuration object
# @yieldparam [(optional) Hash] env the rack env hash
# @raise [ArgumentError] if no configuration block is provided
def initialize(app, &block)
raise ArgumentError.new("You must provide a block to set the cassette options") unless block
@app, @cassette_arguments_block, @mutex = app, block, Mutex.new
end
# Implements the rack middleware interface.
#
# @param [Hash] env the rack env hash
# @return [Array(Integer, Hash, #each)] the rack response
def call(env)
@mutex.synchronize do
VCR.use_cassette(*cassette_arguments(env)) do
@app.call(env)
end
end
end
private
def cassette_arguments(env)
arguments = CassetteArguments.new
call_block(@cassette_arguments_block, arguments, env)
[arguments.name, arguments.options]
end
end
end
end