%a{annotate:rdoc:skip}
module Gem
  # <!-- rdoc-file=lib/rubygems/version.rb -->
  # The Version class processes string versions into comparable values. A version
  # string should normally be a series of numbers separated by periods. Each part
  # (digits separated by periods) is considered its own number, and these are used
  # for sorting. So for instance, 3.10 sorts higher than 3.2 because ten is
  # greater than two.
  #
  # If any part contains letters (currently only a-z are supported) then that
  # version is considered prerelease. Versions with a prerelease part in the Nth
  # part sort less than versions with N-1 parts. Prerelease parts are sorted
  # alphabetically using the normal Ruby string sorting rules. If a prerelease
  # part contains both letters and numbers, it will be broken into multiple parts
  # to provide expected sort behavior (1.0.a10 becomes 1.0.a.10, and is greater
  # than 1.0.a9).
  #
  # Prereleases sort between real releases (newest to oldest):
  #
  # 1.  1.0
  # 2.  1.0.b1
  # 3.  1.0.a.2
  # 4.  0.9
  #
  # If you want to specify a version restriction that includes both prereleases
  # and regular releases of the 1.x series this is the best way:
  #
  #     s.add_dependency 'example', '>= 1.0.0.a', '< 2.0.0'
  #
  # ## How Software Changes
  #
  # Users expect to be able to specify a version constraint that gives them some
  # reasonable expectation that new versions of a library will work with their
  # software if the version constraint is true, and not work with their software
  # if the version constraint is false.  In other words, the perfect system will
  # accept all compatible versions of the library and reject all incompatible
  # versions.
  #
  # Libraries change in 3 ways (well, more than 3, but stay focused here!).
  #
  # 1.  The change may be an implementation detail only and have no effect on the
  #     client software.
  # 2.  The change may add new features, but do so in a way that client software
  #     written to an earlier version is still compatible.
  # 3.  The change may change the public interface of the library in such a way
  #     that old software is no longer compatible.
  #
  # Some examples are appropriate at this point.  Suppose I have a Stack class
  # that supports a `push` and a `pop` method.
  #
  # ### Examples of Category 1 changes:
  #
  # *   Switch from an array based implementation to a linked-list based
  #     implementation.
  # *   Provide an automatic (and transparent) backing store for large stacks.
  #
  # ### Examples of Category 2 changes might be:
  #
  # *   Add a `depth` method to return the current depth of the stack.
  # *   Add a `top` method that returns the current top of stack (without changing
  #     the stack).
  # *   Change `push` so that it returns the item pushed (previously it had no
  #     usable return value).
  #
  # ### Examples of Category 3 changes might be:
  #
  # *   Changes `pop` so that it no longer returns a value (you must use `top` to
  #     get the top of the stack).
  # *   Rename the methods to `push_item` and `pop_item`.
  #
  # ## RubyGems Rational Versioning
  #
  # *   Versions shall be represented by three non-negative integers, separated by
  #     periods (e.g. 3.1.4).  The first integers is the "major" version number,
  #     the second integer is the "minor" version number, and the third integer is
  #     the "build" number.
  #
  # *   A category 1 change (implementation detail) will increment the build
  #     number.
  #
  # *   A category 2 change (backwards compatible) will increment the minor
  #     version number and reset the build number.
  #
  # *   A category 3 change (incompatible) will increment the major build number
  #     and reset the minor and build numbers.
  #
  # *   Any "public" release of a gem should have a different version.  Normally
  #     that means incrementing the build number.  This means a developer can
  #     generate builds all day long, but as soon as they make a public release,
  #     the version must be updated.
  #
  # ### Examples
  #
  # Let's work through a project lifecycle using our Stack example from above.
  #
  # Version 0.0.1
  # :   The initial Stack class is release.
  #
  # Version 0.0.2
  # :   Switched to a linked=list implementation because it is cooler.
  #
  # Version 0.1.0
  # :   Added a `depth` method.
  #
  # Version 1.0.0
  # :   Added `top` and made `pop` return nil (`pop` used to return the  old top
  #     item).
  #
  # Version 1.1.0
  # :   `push` now returns the value pushed (it used it return nil).
  #
  # Version 1.1.1
  # :   Fixed a bug in the linked list implementation.
  #
  # Version 1.1.2
  # :   Fixed a bug introduced in the last fix.
  #
  #
  # Client A needs a stack with basic push/pop capability.  They write to the
  # original interface (no `top`), so their version constraint looks like:
  #
  #     gem 'stack', '>= 0.0'
  #
  # Essentially, any version is OK with Client A.  An incompatible change to the
  # library will cause them grief, but they are willing to take the chance (we
  # call Client A optimistic).
  #
  # Client B is just like Client A except for two things: (1) They use the `depth`
  # method and (2) they are worried about future incompatibilities, so they write
  # their version constraint like this:
  #
  #     gem 'stack', '~> 0.1'
  #
  # The `depth` method was introduced in version 0.1.0, so that version or
  # anything later is fine, as long as the version stays below version 1.0 where
  # incompatibilities are introduced.  We call Client B pessimistic because they
  # are worried about incompatible future changes (it is OK to be pessimistic!).
  #
  # ## Preventing Version Catastrophe:
  #
  # From:
  # https://www.zenspider.com/ruby/2008/10/rubygems-how-to-preventing-catastrophe.
  # html
  #
  # Let's say you're depending on the fnord gem version 2.y.z. If you specify your
  # dependency as ">= 2.0.0" then, you're good, right? What happens if fnord 3.0
  # comes out and it isn't backwards compatible with 2.y.z? Your stuff will break
  # as a result of using ">=". The better route is to specify your dependency with
  # an "approximate" version specifier ("~>"). They're a tad confusing, so here is
  # how the dependency specifiers work:
  #
  #     Specification From  ... To (exclusive)
  #     ">= 3.0"      3.0   ... &infin;
  #     "~> 3.0"      3.0   ... 4.0
  #     "~> 3.0.0"    3.0.0 ... 3.1
  #     "~> 3.5"      3.5   ... 4.0
  #     "~> 3.5.0"    3.5.0 ... 3.6
  #     "~> 3"        3.0   ... 4.0
  #
  # For the last example, single-digit versions are automatically extended with a
  # zero to give a sensible result.
  #
  class Version
    include Comparable

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - correct?(version)
    # -->
    # True if the `version` string matches RubyGems' requirements.
    #
    def self.correct?: (_ToS version) -> bool

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - create(input)
    # -->
    # Factory method to create a Version object. Input may be a Version or a String.
    # Intended to simplify client code.
    #
    #     ver1 = Version.create('1.3.17')   # -> (Version object)
    #     ver2 = Version.create(ver1)       # -> (ver1)
    #     ver3 = Version.create(nil)        # -> nil
    #
    def self.create: (_ToS | Version input) -> instance
                   | (nil input) -> nil

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - new(version)
    # -->
    # Constructs a Version from the `version` string.  A version string is a series
    # of digits or ASCII letters separated by dots.
    #
    def initialize: (_ToS version) -> void

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - <=>(other)
    # -->
    # Compares this version with `other` returning -1, 0, or 1 if the other version
    # is larger, the same, or smaller than this one. Attempts to compare to
    # something that's not a `Gem::Version` or a valid version String return `nil`.
    #
    def <=>: (untyped other) -> Integer?

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - approximate_recommendation()
    # -->
    # A recommended version for use with a ~> Requirement.
    #
    def approximate_recommendation: () -> String

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - bump()
    # -->
    # Return a new version object where the next to the last revision number is one
    # greater (e.g., 5.3.1 => 5.4).
    #
    # Pre-release (alpha) parts, e.g, 5.3.1.b.2 => 5.4, are ignored.
    #
    def bump: () -> instance

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - canonical_segments()
    # -->
    # remove trailing zeros segments before first letter or at the end of the
    # version
    #
    def canonical_segments: () -> Array[Integer | String]

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - eql?(other)
    # -->
    # A Version is only eql? to another version if it's specified to the same
    # precision. Version "1.0" is not the same as version "1".
    #
    def eql?: (untyped other) -> bool

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - marshal_dump()
    # -->
    # Dump only the raw version string, not the complete object. It's a string for
    # backwards (RubyGems 1.3.5 and earlier) compatibility.
    #
    def marshal_dump: () -> Array[String]

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - marshal_load(array)
    # -->
    # Load custom marshal format. It's a string for backwards (RubyGems 1.3.5 and
    # earlier) compatibility.
    #
    def marshal_load: (Array[String] array) -> void

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - prerelease?()
    # -->
    # A version is considered a prerelease if it contains a letter.
    #
    def prerelease?: () -> bool

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - release()
    # -->
    # The release for this version (e.g. 1.2.0.a -> 1.2.0). Non-prerelease versions
    # return themselves.
    #
    def release: () -> instance

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - version()
    # -->
    # A string representation of this Version.
    #
    def version: () -> String

    # <!--
    #   rdoc-file=lib/rubygems/version.rb
    #   - to_s()
    # -->
    #
    alias to_s version
  end
end
