<commit_before>module Spies
  class Spy
    CallLog = Struct.new(:object, :args, :block)

    attr_reader :base_object, :method_name, :calls
    def initialize(object, method_name)
      @base_object, @method_name = object, method_name
      reset!
    end

    def hook(opts = {})
      raise "#{method_name} method has already been hooked" if hooked?
      opts[:force] ||= false
      if method_visibility || !opts[:force]
        @original_method = base_object.method(method_name)
        @arity_range = get_arity_range(@original_method.parameters)
        if base_object.singleton_methods.include?(method_name)
          @base_object.singleton_class.send(:remove_method, method_name)
        end
      end

      __spies_spy = self
      @base_object.define_singleton_method(method_name) do |*args, &block|
        __spies_spy.record(self,args,block)
      end

      opts[:visibility] ||= method_visibility
      @base_object.singleton_class.send(opts[:visibility], method_name) if opts[:visibility]
      @hooked = true
      self
    end

    def unhook
      raise "#{method_name} method has not been hooked" unless hooked?
      @base_object.singleton_class.send(:remove_method, method_name)
      @base_object.define_singleton_method(method_name, @original_method)
      clear_method!
      self
    end

    def hooked?
      @hooked
    end

    def and_return(value = nil, &block)
      if block_given?
        raise ArgumentError.new("value and block conflict. Choose one") if !value.nil?
        @plan = block
      else
        @plan = Proc.new { value }
      end
      self
    end

    def called?
      @calls.size > 0
    end

    def called_with?(*args)
      @calls.any? do |call_log|
        call_log.args == args
      end<commit_msg>don't re-define method if it didn't exist<commit_after>module Spies
  class Spy
    CallLog = Struct.new(:object, :args, :block)

    attr_reader :base_object, :method_name, :calls
    def initialize(object, method_name)
      @base_object, @method_name = object, method_name
      reset!
    end

    def hook(opts = {})
      raise "#{method_name} method has already been hooked" if hooked?
      opts[:force] ||= false
      if method_visibility || !opts[:force]
        @original_method = base_object.method(method_name)
        @arity_range = get_arity_range(@original_method.parameters)
        if base_object.singleton_methods.include?(method_name)
          @base_object.singleton_class.send(:remove_method, method_name)
        end
      end

      __spies_spy = self
      @base_object.define_singleton_method(method_name) do |*args, &block|
        __spies_spy.record(self,args,block)
      end

      opts[:visibility] ||= method_visibility
      @base_object.singleton_class.send(opts[:visibility], method_name) if opts[:visibility]
      @hooked = true
      self
    end

    def unhook
      raise "#{method_name} method has not been hooked" unless hooked?
      @base_object.singleton_class.send(:remove_method, method_name)
      @base_object.define_singleton_method(method_name, @original_method) if @original_method
      clear_method!
      self
    end

    def hooked?
      @hooked
    end

    def and_return(value = nil, &block)
      if block_given?
        raise ArgumentError.new("value and block conflict. Choose one") if !value.nil?
        @plan = block
      else
        @plan = Proc.new { value }
      end
      self
    end

    def called?
      @calls.size > 0
    end

    def called_with?(*args)
      @calls.any? do |call_log|
        call_log.args == args
      end
{'fraction_non_alphanumeric': 0.09473094170403587, 'fraction_numerical': 0.0005605381165919282, 'mean_word_length': 2.7489495798319328, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '2683403', 'n_tokens_mistral': 1136, 'n_tokens_neox': 1097, 'n_words': 255}