<commit_before>require 'rspec/support'
RSpec::Support.require_rspec_support "ruby_features"
RSpec::Support.require_rspec_support "matcher_definition"

module RSpec
  module Support
    # Extracts info about the number of arguments and allowed/required
    # keyword args of a given method.
    #
    # @private
    class MethodSignature # rubocop:disable ClassLength
      attr_reader :min_non_kw_args, :max_non_kw_args, :optional_kw_args, :required_kw_args

      def initialize(method)
        @method           = method
        @optional_kw_args = []
        @required_kw_args = []
        classify_parameters
      end

      def non_kw_args_arity_description
        case max_non_kw_args
        when min_non_kw_args then min_non_kw_args.to_s
        when INFINITY then "#{min_non_kw_args} or more"
        else "#{min_non_kw_args} to #{max_non_kw_args}"
        end
      end

      def valid_non_kw_args?(positional_arg_count, optional_max_arg_count=positional_arg_count)
        return true if positional_arg_count.nil?

        min_non_kw_args <= positional_arg_count &&
          optional_max_arg_count <= max_non_kw_args
      end

      def classify_arity(arity=@method.arity)
        if arity < 0
          # `~` inverts the one's complement and gives us the
          # number of required args
          @min_non_kw_args = ~arity
          @max_non_kw_args = INFINITY
        else
          @min_non_kw_args = arity
          @max_non_kw_args = arity
        end
      end

      if RubyFeatures.optional_and_splat_args_supported?
        def description
          @description ||= begin
            parts = []

            unless non_kw_args_arity_description == "0"
              parts << "arity of #{non_kw_args_arity_description}"
            end

            if @optional_kw_args.any?
              parts << "optional keyword args (#{@optional_kw_args.map(&:inspect).join(", ")})"
            end

            if @required_kw_args.any?
              parts << "required keyword args (#{@required_kw_args.map(&:inspect).join(", ")})"
            end

            parts << "any additional keyword args" if @allows_any_kw_args

            parts.join(" and ")
          end
        end

        def missing_kw_args_from(given_kw_args)
          @required_kw_args - given_kw_args
        end

        def invalid_kw_args_from(given_kw_args)
          return [] if @allows_any_kw_args
          given_kw_args - @allowed_kw_args
        end

        def has_kw_args_in?(args)
          Hash === args.last && could_contain_kw_args?(args)
        end

        # Without considering what the last arg is, could it
        # contain keyword arguments?
        def could_contain_kw_args?(args)
          return false if args.count <= min_non_kw_args
          @allows_any_kw_args || @allowed_kw_args.any?
        end

        def arbitrary_kw_args?
          @allows_any_kw_args
        end

        def unlimited_args?
          @max_non_kw_args == INFINITY
        end

        def classify_parameters
          optional_non_kw_args = @min_non_kw_args = 0
          @allows_any_kw_args = false

          @method.parameters.each do |(type, name)|
            case type
            # def foo(a:)
            when :keyreq  then @required_kw_args << name
            # def foo(a: 1)
            when :key     then @optional_kw_args << name
            # def foo(**kw_args)
            when :keyrest then @allows_any_kw_args = true
            # def foo(a)
            when :req     then @min_non_kw_args += 1
            # def foo(a = 1)
            when :opt     then optional_non_kw_args += 1
            # def foo(*a)
            when :rest    then optional_non_kw_args = INFINITY
            end
          end

          @max_non_kw_args = @min_non_kw_args  + optional_non_kw_args
          @allowed_kw_args = @required_kw_args + @optional_kw_args
        end
      else
        def description
          "arity of #{non_kw_args_arity_description}"
        end

        def missing_kw_args_from(_given_kw_args)
          []
        end

        def invalid_kw_args_from(_given_kw_args)
          []
        end

        def has_kw_args_in?(_args)
          false
        end

        def could_contain_kw_args?(*)
          false
        end

        def arbitrary_kw_args?
          false
        end

        def unlimited_args?
          false
        end

        alias_method :classify_parameters, :classify_arity
      end

      INFINITY = 1 / 0.0
    end

    if RSpec::Support::Ruby.jruby?
      # JRuby has only partial support for UnboundMethod#parameters, so we fall back on using #arity
      # https://github.com/jruby/jruby/issues/2816 and https://github.com/jruby/jruby/issues/2817
      if RubyFeatures.optional_and_splat_args_supported? &&
         Java::JavaLang::String.instance_method(:char_at).parameters == []

        class MethodSignature < remove_const(:MethodSignature)
        private

          def classify_parameters
            super
            if (arity = @method.arity) != 0 && @method.parameters.empty?
              classify_arity(arity)
            end
          end
        end
      end

      # JRuby used to always report -1 arity for Java proxy methods.
      # The workaround essentially makes use of Java's introspection to figure
      # out matching methods (which could be more than one partly because Java
      # supports multiple overloads, and partly because JRuby introduces
      # aliases to make method names look more Rubyesque). If there is only a
      # single match, we can use that methods arity directly instead of the
      # default -1 arity.
      if Java::JavaLang::String.instance_method(:char_at).arity == -1
        class MethodSignature < remove_const(:MethodSignature)
        private

          def classify_parameters
            super
            return unless @method.arity == -1 && @method.owner.respond_to?(:java_class)
            java_instance_methods = @method.owner.java_class.java_instance_methods<commit_msg>Adapt JRuby arity workaround to BlockSignature<commit_after>require 'rspec/support'
RSpec::Support.require_rspec_support "ruby_features"
RSpec::Support.require_rspec_support "matcher_definition"

module RSpec
  module Support
    # Extracts info about the number of arguments and allowed/required
    # keyword args of a given method.
    #
    # @private
    class MethodSignature # rubocop:disable ClassLength
      attr_reader :min_non_kw_args, :max_non_kw_args, :optional_kw_args, :required_kw_args

      def initialize(method)
        @method           = method
        @optional_kw_args = []
        @required_kw_args = []
        classify_parameters
      end

      def non_kw_args_arity_description
        case max_non_kw_args
        when min_non_kw_args then min_non_kw_args.to_s
        when INFINITY then "#{min_non_kw_args} or more"
        else "#{min_non_kw_args} to #{max_non_kw_args}"
        end
      end

      def valid_non_kw_args?(positional_arg_count, optional_max_arg_count=positional_arg_count)
        return true if positional_arg_count.nil?

        min_non_kw_args <= positional_arg_count &&
          optional_max_arg_count <= max_non_kw_args
      end

      def classify_arity(arity=@method.arity)
        if arity < 0
          # `~` inverts the one's complement and gives us the
          # number of required args
          @min_non_kw_args = ~arity
          @max_non_kw_args = INFINITY
        else
          @min_non_kw_args = arity
          @max_non_kw_args = arity
        end
      end

      if RubyFeatures.optional_and_splat_args_supported?
        def description
          @description ||= begin
            parts = []

            unless non_kw_args_arity_description == "0"
              parts << "arity of #{non_kw_args_arity_description}"
            end

            if @optional_kw_args.any?
              parts << "optional keyword args (#{@optional_kw_args.map(&:inspect).join(", ")})"
            end

            if @required_kw_args.any?
              parts << "required keyword args (#{@required_kw_args.map(&:inspect).join(", ")})"
            end

            parts << "any additional keyword args" if @allows_any_kw_args

            parts.join(" and ")
          end
        end

        def missing_kw_args_from(given_kw_args)
          @required_kw_args - given_kw_args
        end

        def invalid_kw_args_from(given_kw_args)
          return [] if @allows_any_kw_args
          given_kw_args - @allowed_kw_args
        end

        def has_kw_args_in?(args)
          Hash === args.last && could_contain_kw_args?(args)
        end

        # Without considering what the last arg is, could it
        # contain keyword arguments?
        def could_contain_kw_args?(args)
          return false if args.count <= min_non_kw_args
          @allows_any_kw_args || @allowed_kw_args.any?
        end

        def arbitrary_kw_args?
          @allows_any_kw_args
        end

        def unlimited_args?
          @max_non_kw_args == INFINITY
        end

        def classify_parameters
          optional_non_kw_args = @min_non_kw_args = 0
          @allows_any_kw_args = false

          @method.parameters.each do |(type, name)|
            case type
            # def foo(a:)
            when :keyreq  then @required_kw_args << name
            # def foo(a: 1)
            when :key     then @optional_kw_args << name
            # def foo(**kw_args)
            when :keyrest then @allows_any_kw_args = true
            # def foo(a)
            when :req     then @min_non_kw_args += 1
            # def foo(a = 1)
            when :opt     then optional_non_kw_args += 1
            # def foo(*a)
            when :rest    then optional_non_kw_args = INFINITY
            end
          end

          @max_non_kw_args = @min_non_kw_args  + optional_non_kw_args
          @allowed_kw_args = @required_kw_args + @optional_kw_args
        end
      else
        def description
          "arity of #{non_kw_args_arity_description}"
        end

        def missing_kw_args_from(_given_kw_args)
          []
        end

        def invalid_kw_args_from(_given_kw_args)
          []
        end

        def has_kw_args_in?(_args)
          false
        end

        def could_contain_kw_args?(*)
          false
        end

        def arbitrary_kw_args?
          false
        end

        def unlimited_args?
          false
        end

        alias_method :classify_parameters, :classify_arity
      end

      INFINITY = 1 / 0.0
    end

    if RSpec::Support::Ruby.jruby?
      # JRuby has only partial support for UnboundMethod#parameters, so we fall back on using #arity
      # https://github.com/jruby/jruby/issues/2816 and https://github.com/jruby/jruby/issues/2817
      if RubyFeatures.optional_and_splat_args_supported? &&
         Java::JavaLang::String.instance_method(:char_at).parameters == []

        class MethodSignature < remove_const(:MethodSignature)
        private

          def classify_parameters
            super
            if (arity = @method.arity) != 0 && @method.parameters.empty?
              classify_arity(arity)
            end
          end
        end
      end

      # JRuby used to always report -1 arity for Java proxy methods.
      # The workaround essentially makes use of Java's introspection to figure
      # out matching methods (which could be more than one partly because Java
      # supports multiple overloads, and partly because JRuby introduces
      # aliases to make method names look more Rubyesque). If there is only a
      # single match, we can use that methods arity directly instead of the
      # default -1 arity.
      #
      # This workaround only works for Java proxy methods, and in order to
      # support regular methods and blocks, we need to be careful about calling
      # owner and java_class as they might not be available
      if Java::JavaLang::String.instance_method(:char_at).arity == -1
        class MethodSignature < remove_const(:MethodSignature)
        private

          def classify_parameters
            super
            return unless @method.arity == -1
            return unless @method.respond_to?(:owner)
            return unless @method.owner.respond_to?(:java_class)
            java_instance_methods = @method.owner.java_class.java_instance_methods
{'fraction_non_alphanumeric': 0.06954689146469968, 'fraction_numerical': 0.0037286212207181648, 'mean_word_length': 2.0569871159563924, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 3, 'https://': 4, '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': '5316926', 'n_tokens_mistral': 3676, 'n_tokens_neox': 3515, 'n_words': 888}