# <!-- rdoc-file=lib/did_you_mean.rb -->
# The `DidYouMean` gem adds functionality to suggest possible method/class names
# upon errors such as `NameError` and `NoMethodError`. In Ruby 2.3 or later, it
# is automatically activated during startup.
#
# @example
#
#     methosd
#     # => NameError: undefined local variable or method `methosd' for main:Object
#     #   Did you mean?  methods
#     #                  method
#
#     OBject
#     # => NameError: uninitialized constant OBject
#     #    Did you mean?  Object
#
#     @full_name = "Yuki Nishijima"
#     first_name, last_name = full_name.split(" ")
#     # => NameError: undefined local variable or method `full_name' for main:Object
#     #    Did you mean?  @full_name
#
#     @@full_name = "Yuki Nishijima"
#     @@full_anme
#     # => NameError: uninitialized class variable @@full_anme in Object
#     #    Did you mean?  @@full_name
#
#     full_name = "Yuki Nishijima"
#     full_name.starts_with?("Y")
#     # => NoMethodError: undefined method `starts_with?' for "Yuki Nishijima":String
#     #    Did you mean?  start_with?
#
#     hash = {foo: 1, bar: 2, baz: 3}
#     hash.fetch(:fooo)
#     # => KeyError: key not found: :fooo
#     #    Did you mean?  :foo
#
# ## Disabling `did_you_mean`
#
# Occasionally, you may want to disable the `did_you_mean` gem for e.g.
# debugging issues in the error object itself. You can disable it entirely by
# specifying `--disable-did_you_mean` option to the `ruby` command:
#
#     $ ruby --disable-did_you_mean -e "1.zeor?"
#     -e:1:in `<main>': undefined method `zeor?' for 1:Integer (NameError)
#
# When you do not have direct access to the `ruby` command (e.g. +rails
# console+, `irb`), you could applyoptions using the `RUBYOPT` environment
# variable:
#
#     $ RUBYOPT='--disable-did_you_mean' irb
#     irb:0> 1.zeor?
#     # => NoMethodError (undefined method `zeor?' for 1:Integer)
#
# ## Getting the original error message
#
# Sometimes, you do not want to disable the gem entirely, but need to get the
# original error message without suggestions (e.g. testing). In this case, you
# could use the `#original_message` method on the error object:
#
#     no_method_error = begin
#                         1.zeor?
#                       rescue NoMethodError => error
#                         error
#                       end
#
#     no_method_error.message
#     # => NoMethodError (undefined method `zeor?' for 1:Integer)
#     #    Did you mean?  zero?
#
#     no_method_error.original_message
#     # => NoMethodError (undefined method `zeor?' for 1:Integer)
#
module DidYouMean
  # <!-- rdoc-file=lib/did_you_mean.rb -->
  # TODO: Remove on 3.3:
  #
  SPELL_CHECKERS: untyped

  NameErrorCheckers: Object

  VERSION: String

  class ClassNameChecker
    class ClassName < ::String
    end
  end

  module Correctable
    SKIP_TO_S_FOR_SUPER_LOOKUP: true

    # <!--
    #   rdoc-file=lib/did_you_mean/core_ext/name_error.rb
    #   - corrections()
    # -->
    #
    def corrections: () -> Array[String]
  end

  # <!-- rdoc-file=lib/did_you_mean/formatter.rb -->
  # The `DidYouMean::Formatter` is the basic, default formatter for the gem. The
  # formatter responds to the `message_for` method and it returns a human readable
  # string.
  #
  class Formatter
    # <!--
    #   rdoc-file=lib/did_you_mean/formatter.rb
    #   - message_for(corrections)
    # -->
    # Returns a human readable string that contains `corrections`. This formatter is
    # designed to be less verbose to not take too much screen space while being
    # helpful enough to the user.
    #
    # @example
    #
    #     formatter = DidYouMean::Formatter.new
    #
    #     # displays suggestions in two lines with the leading empty line
    #     puts formatter.message_for(["methods", "method"])
    #
    #     Did you mean?  methods
    #                     method
    #     # => nil
    #
    #     # displays an empty line
    #     puts formatter.message_for([])
    #
    #     # => nil
    #
    def self.message_for: (Array[String] corrections) -> String
  end

  module JaroWinkler
    WEIGHT: Float

    THRESHOLD: Float

    # <!--
    #   rdoc-file=lib/did_you_mean/jaro_winkler.rb
    #   - distance(str1, str2)
    # -->
    #
    def self?.distance: (String, String) -> Integer
  end

  module Jaro
    # <!--
    #   rdoc-file=lib/did_you_mean/jaro_winkler.rb
    #   - distance(str1, str2)
    # -->
    #
    def self?.distance: (String, String) -> Integer
  end

  class KeyErrorChecker
    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/key_error_checker.rb
    #   - new(key_error)
    # -->
    #
    def initialize: (KeyError[_ToS, Hash[_ToS, untyped]]) -> void

    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/key_error_checker.rb
    #   - corrections()
    # -->
    #
    def corrections: () -> Array[String]
  end

  module Levenshtein
    def self?.distance: (String, String) -> Integer?
  end

  class MethodNameChecker
    NAMES_TO_EXCLUDE: Hash[untyped, Array[Symbol]]

    # <!-- rdoc-file=lib/did_you_mean/spell_checkers/method_name_checker.rb -->
    # `MethodNameChecker::RB_RESERVED_WORDS` is the list of reserved words in Ruby
    # that take an argument. Unlike `VariableNameChecker::RB_RESERVED_WORDS`, these
    # reserved words require an argument, and a `NoMethodError` is raised due to the
    # presence of the argument.
    #
    # The `MethodNameChecker` will use this list to suggest a reversed word if a
    # `NoMethodError` is raised and found closest matches.
    #
    # Also see `VariableNameChecker::RB_RESERVED_WORDS`.
    #
    RB_RESERVED_WORDS: Array[Symbol]

    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/method_name_checker.rb
    #   - new(exception)
    # -->
    #
    def initialize: (NoMethodError[untyped] exception) -> void

    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/method_name_checker.rb
    #   - corrections()
    # -->
    #
    def corrections: () -> Array[Symbol]
  end

  class NullChecker
    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/null_checker.rb
    #   - new(*)
    # -->
    #
    def initialize: (*untyped) -> void

    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/null_checker.rb
    #   - corrections()
    # -->
    #
    def corrections: () -> Array[untyped]
  end

  class PatternKeyNameChecker
    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/pattern_key_name_checker.rb
    #   - new(no_matching_pattern_key_error)
    # -->
    #
    def initialize: (untyped) -> void

    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/pattern_key_name_checker.rb
    #   - corrections()
    # -->
    #
    def corrections: () -> Array[String]
  end

  class RequirePathChecker
    INITIAL_LOAD_PATH: Array[String]
    ENV_SPECIFIC_EXT: String

    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/require_path_checker.rb
    #   - requireables()
    # -->
    #
    def self.requireables: -> Array[String]

    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/require_path_checker.rb
    #   - new(exception)
    # -->
    #
    def initialize: (untyped exception) -> void

    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/require_path_checker.rb
    #   - corrections()
    # -->
    #
    def corrections: () -> Array[String]
  end

  class SpellChecker
    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checker.rb
    #   - new(dictionary:)
    # -->
    #
    def initialize: (dictionary: Array[String | Symbol]) -> void

    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checker.rb
    #   - correct(input)
    # -->
    #
    def correct: (String | Symbol input) -> Array[String]
  end

  # <!-- rdoc-file=lib/did_you_mean/tree_spell_checker.rb -->
  # spell checker for a dictionary that has a tree structure, see
  # doc/tree_spell_checker_api.md
  #
  class TreeSpellChecker
    # <!--
    #   rdoc-file=lib/did_you_mean/tree_spell_checker.rb
    #   - new(dictionary:, separator: '/', augment: nil)
    # -->
    #
    def initialize: (dictionary: Array[String], ?separator: String, ?augment: bool?) -> void

    # <!--
    #   rdoc-file=lib/did_you_mean/tree_spell_checker.rb
    #   - correct(input)
    # -->
    #
    def correct: (String input) -> Array[String]
  end

  class VariableNameChecker
    NAMES_TO_EXCLUDE: Hash[String, Array[Symbol]]

    # <!-- rdoc-file=lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb -->
    # `VariableNameChecker::RB_RESERVED_WORDS` is the list of all reserved words in
    # Ruby. They could be declared like methods are, and a typo would cause Ruby to
    # raise a `NameError` because of the way they are declared.
    #
    # The `:VariableNameChecker` will use this list to suggest a reversed word if a
    # `NameError` is raised and found closest matches, excluding:
    #
    #     * +do+
    #     * +if+
    #     * +in+
    #     * +or+
    #
    # Also see `MethodNameChecker::RB_RESERVED_WORDS`.
    #
    RB_RESERVED_WORDS: Array[Symbol]

    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb
    #   - new(exception)
    # -->
    #
    def initialize: (NameError[untyped]) -> void

    # <!--
    #   rdoc-file=lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb
    #   - corrections()
    # -->
    #
    def corrections: () -> Array[Symbol]
  end
end

%a{annotate:rdoc:skip}
class NameError[T]
  prepend DidYouMean::Correctable
end

%a{annotate:rdoc:skip}
class KeyError[K, R]
  prepend DidYouMean::Correctable
end

%a{annotate:rdoc:skip}
class LoadError
  prepend DidYouMean::Correctable
end
