<commit_before>require 'fileutils'
require 'yaml'
require 'erb'
require 'set'

module VCR
  class Cassette
    class MissingERBVariableError < NameError; end

    VALID_RECORD_MODES = [:all, :none, :new_episodes].freeze

    attr_reader :name, :record_mode, :match_requests_on

    def initialize(name, options = {})
      options = VCR::Config.default_cassette_options.merge(options)
      invalid_options = options.keys - [:record, :erb, :allow_real_http, :match_requests_on, :re_record_interval]

      if invalid_options.size > 0
        raise ArgumentError.new("You passed the following invalid options to VCR::Cassette.new: #{invalid_options.inspect}.")
      end

      @name               = name
      @record_mode        = options[:record]
      @erb                = options[:erb]
      @match_requests_on  = options[:match_requests_on]
      @re_record_interval = options[:re_record_interval]
      @record_mode        = :all if should_re_record?

      deprecate_old_cassette_options(options)
      raise_error_unless_valid_record_mode(record_mode)

      set_http_connections_allowed
      load_recorded_interactions
    end

    def eject
      write_recorded_interactions_to_disk
      VCR.http_stubbing_adapter.restore_stubs_checkpoint(name)
      restore_http_connections_allowed
      restore_ignore_localhost_for_deprecation
    end

    def recorded_interactions
      @recorded_interactions ||= []
    end

    def record_http_interaction(interaction)
      new_recorded_interactions << interaction
    end

    def new_recorded_interactions
      @new_recorded_interactions ||= []
    end

    def file
      File.join(VCR::Config.cassette_library_dir, "#{sanitized_name}.yml") if VCR::Config.cassette_library_dir
    end

    private

    def sanitized_name
      name.to_s.gsub(/[^\w\-\/]+/, '_')
    end

    def raise_error_unless_valid_record_mode(record_mode)
      unless VALID_RECORD_MODES.include?(record_mode)
        raise ArgumentError.new("#{record_mode} is not a valid cassette record mode.  Valid options are: #{VALID_RECORD_MODES.inspect}")
      end
    end

    def should_re_record?
      @re_record_interval &&
      File.exist?(file) &&
      File.stat(file).mtime + @re_record_interval < Time.now &&
      InternetConnection.available?
    end

    def should_allow_http_connections?
      record_mode != :none
    end

    def should_stub_requests?
      record_mode != :all
    end

    def should_remove_matching_existing_interactions?
      record_mode == :all
    end

    def set_http_connections_allowed
      @orig_http_connections_allowed = VCR.http_stubbing_adapter.http_connections_allowed?
      VCR.http_stubbing_adapter.http_connections_allowed = should_allow_http_connections?
    end

    def restore_http_connections_allowed
      VCR.http_stubbing_adapter.http_connections_allowed = @orig_http_connections_allowed
    end

    def load_recorded_interactions
      VCR.http_stubbing_adapter.create_stubs_checkpoint(name)

      if file && File.exist?(file)
        begin
          interactions = YAML.load(raw_yaml_content)

          if VCR.http_stubbing_adapter.ignore_localhost?
            interactions.reject! do |i|
              i.uri.is_a?(String) && VCR::LOCALHOST_ALIASES.include?(URI.parse(i.uri).host)
            end
          end

          recorded_interactions.replace(interactions)
        rescue TypeError
          raise unless raw_yaml_content =~ /VCR::RecordedResponse/
          raise "The VCR cassette #{sanitized_name}.yml uses an old format that is now deprecated.  VCR provides a rake task to migrate your old cassettes to the new format.  See http://github.com/myronmarston/vcr/blob/master/CHANGELOG.md for more info."
        end
      end

      if should_stub_requests?
        VCR.http_stubbing_adapter.stub_requests(recorded_interactions, match_requests_on)
      end
    end

    @@struct_cache = Hash.new do |hash, attributes|
      hash[attributes] = Struct.new(*attributes)
    end

    def raw_yaml_content
      content = File.read(file)
      return content unless @erb

      template = ERB.new(content)

      begin
        return template.result unless @erb.is_a?(Hash)

        # create an object with methods for each desired local variable...
        local_variables = @@struct_cache[@erb.keys].new(*@erb.values)

        # instance_eval seems to be the only way to get the binding for ruby 1.9: http://redmine.ruby-lang.org/issues/show/2161
        template.result(local_variables.instance_eval { binding })
      rescue NameError => e
        var_name = e.message[/undefined local variable or method `(.*)' for/, 1].to_sym
        example_hash = (@erb.is_a?(Hash) ? @erb : {}).merge(var_name => 'some value')

        raise MissingERBVariableError.new(
          "The ERB in the #{sanitized_name}.yml cassette file references undefined variable #{var_name}.  " +
          "Pass it to the cassette using :erb => #{ example_hash.inspect }."
        )
      end
    end

    def merged_interactions
      old_interactions = recorded_interactions

      if should_remove_matching_existing_interactions?
        match_attributes = match_requests_on

        new_request_matchers = Set.new new_recorded_interactions.map do |i|
          i.request.matcher(match_attributes)
        end

        old_interactions = old_interactions.reject do |i|
          new_request_matchers.include?(i.request.matcher(match_attributes))
        end
      end

      old_interactions + new_recorded_interactions
    end<commit_msg>Use NameError#name rather than parsing the name from the message with a regex.<commit_after>require 'fileutils'
require 'yaml'
require 'erb'
require 'set'

module VCR
  class Cassette
    class MissingERBVariableError < NameError; end

    VALID_RECORD_MODES = [:all, :none, :new_episodes].freeze

    attr_reader :name, :record_mode, :match_requests_on

    def initialize(name, options = {})
      options = VCR::Config.default_cassette_options.merge(options)
      invalid_options = options.keys - [:record, :erb, :allow_real_http, :match_requests_on, :re_record_interval]

      if invalid_options.size > 0
        raise ArgumentError.new("You passed the following invalid options to VCR::Cassette.new: #{invalid_options.inspect}.")
      end

      @name               = name
      @record_mode        = options[:record]
      @erb                = options[:erb]
      @match_requests_on  = options[:match_requests_on]
      @re_record_interval = options[:re_record_interval]
      @record_mode        = :all if should_re_record?

      deprecate_old_cassette_options(options)
      raise_error_unless_valid_record_mode(record_mode)

      set_http_connections_allowed
      load_recorded_interactions
    end

    def eject
      write_recorded_interactions_to_disk
      VCR.http_stubbing_adapter.restore_stubs_checkpoint(name)
      restore_http_connections_allowed
      restore_ignore_localhost_for_deprecation
    end

    def recorded_interactions
      @recorded_interactions ||= []
    end

    def record_http_interaction(interaction)
      new_recorded_interactions << interaction
    end

    def new_recorded_interactions
      @new_recorded_interactions ||= []
    end

    def file
      File.join(VCR::Config.cassette_library_dir, "#{sanitized_name}.yml") if VCR::Config.cassette_library_dir
    end

    private

    def sanitized_name
      name.to_s.gsub(/[^\w\-\/]+/, '_')
    end

    def raise_error_unless_valid_record_mode(record_mode)
      unless VALID_RECORD_MODES.include?(record_mode)
        raise ArgumentError.new("#{record_mode} is not a valid cassette record mode.  Valid options are: #{VALID_RECORD_MODES.inspect}")
      end
    end

    def should_re_record?
      @re_record_interval &&
      File.exist?(file) &&
      File.stat(file).mtime + @re_record_interval < Time.now &&
      InternetConnection.available?
    end

    def should_allow_http_connections?
      record_mode != :none
    end

    def should_stub_requests?
      record_mode != :all
    end

    def should_remove_matching_existing_interactions?
      record_mode == :all
    end

    def set_http_connections_allowed
      @orig_http_connections_allowed = VCR.http_stubbing_adapter.http_connections_allowed?
      VCR.http_stubbing_adapter.http_connections_allowed = should_allow_http_connections?
    end

    def restore_http_connections_allowed
      VCR.http_stubbing_adapter.http_connections_allowed = @orig_http_connections_allowed
    end

    def load_recorded_interactions
      VCR.http_stubbing_adapter.create_stubs_checkpoint(name)

      if file && File.exist?(file)
        begin
          interactions = YAML.load(raw_yaml_content)

          if VCR.http_stubbing_adapter.ignore_localhost?
            interactions.reject! do |i|
              i.uri.is_a?(String) && VCR::LOCALHOST_ALIASES.include?(URI.parse(i.uri).host)
            end
          end

          recorded_interactions.replace(interactions)
        rescue TypeError
          raise unless raw_yaml_content =~ /VCR::RecordedResponse/
          raise "The VCR cassette #{sanitized_name}.yml uses an old format that is now deprecated.  VCR provides a rake task to migrate your old cassettes to the new format.  See http://github.com/myronmarston/vcr/blob/master/CHANGELOG.md for more info."
        end
      end

      if should_stub_requests?
        VCR.http_stubbing_adapter.stub_requests(recorded_interactions, match_requests_on)
      end
    end

    @@struct_cache = Hash.new do |hash, attributes|
      hash[attributes] = Struct.new(*attributes)
    end

    def raw_yaml_content
      content = File.read(file)
      return content unless @erb

      template = ERB.new(content)

      begin
        return template.result unless @erb.is_a?(Hash)

        # create an object with methods for each desired local variable...
        local_variables = @@struct_cache[@erb.keys].new(*@erb.values)

        # instance_eval seems to be the only way to get the binding for ruby 1.9: http://redmine.ruby-lang.org/issues/show/2161
        template.result(local_variables.instance_eval { binding })
      rescue NameError => e
        example_hash = (@erb.is_a?(Hash) ? @erb : {}).merge(e.name => 'some value')

        raise MissingERBVariableError.new(
          "The ERB in the #{sanitized_name}.yml cassette file references undefined variable #{e.name}.  " +
          "Pass it to the cassette using :erb => #{ example_hash.inspect }."
        )
      end
    end

    def merged_interactions
      old_interactions = recorded_interactions

      if should_remove_matching_existing_interactions?
        match_attributes = match_requests_on

        new_request_matchers = Set.new new_recorded_interactions.map do |i|
          i.request.matcher(match_attributes)
        end

        old_interactions = old_interactions.reject do |i|
          new_request_matchers.include?(i.request.matcher(match_attributes))
        end
      end

      old_interactions + new_recorded_interactions
    end
{'fraction_non_alphanumeric': 0.07958571817934042, 'fraction_numerical': 0.001362769146906514, 'mean_word_length': 3.0396330275229357, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7617031', 'n_tokens_mistral': 3430, 'n_tokens_neox': 3291, 'n_words': 679}