# <!-- rdoc-file=re.c -->
# MatchData encapsulates the result of matching a Regexp against string. It is
# returned by Regexp#match and String#match, and also stored in a global
# variable returned by Regexp.last_match.
#
# Usage:
#
#     url = 'https://docs.ruby-lang.org/en/2.5.0/MatchData.html'
#     m = url.match(/(\d\.?)+/)   # => #<MatchData "2.5.0" 1:"0">
#     m.string                    # => "https://docs.ruby-lang.org/en/2.5.0/MatchData.html"
#     m.regexp                    # => /(\d\.?)+/
#     # entire matched substring:
#     m[0]                        # => "2.5.0"
#
#     # Working with unnamed captures
#     m = url.match(%r{([^/]+)/([^/]+)\.html$})
#     m.captures                  # => ["2.5.0", "MatchData"]
#     m[1]                        # => "2.5.0"
#     m.values_at(1, 2)           # => ["2.5.0", "MatchData"]
#
#     # Working with named captures
#     m = url.match(%r{(?<version>[^/]+)/(?<module>[^/]+)\.html$})
#     m.captures                  # => ["2.5.0", "MatchData"]
#     m.named_captures            # => {"version"=>"2.5.0", "module"=>"MatchData"}
#     m[:version]                 # => "2.5.0"
#     m.values_at(:version, :module)
#                                 # => ["2.5.0", "MatchData"]
#     # Numerical indexes are working, too
#     m[1]                        # => "2.5.0"
#     m.values_at(1, 2)           # => ["2.5.0", "MatchData"]
#
# ## Global variables equivalence
#
# Parts of last MatchData (returned by Regexp.last_match) are also aliased as
# global variables:
#
# *   `$~` is Regexp.last_match;
# *   `$&` is Regexp.last_match`[ 0 ]`;
# *   `$1`, `$2`, and so on are Regexp.last_match`[ i ]` (captures by number);
# *   `$`` is Regexp.last_match`.pre_match`;
# *   `$'` is Regexp.last_match`.post_match`;
# *   `$+` is Regexp.last_match`[ -1 ]` (the last capture).
#
# See also "Special global variables" section in Regexp documentation.
#
class MatchData
  type capture = String | Symbol | int

  def initialize_copy: (MatchData instance) -> self

  # <!-- rdoc-file=re.c -->
  # Returns `true` if `object` is another MatchData object whose target string,
  # regexp, match, and captures are the same as `self`, `false` otherwise.
  #
  def ==: (MatchData other) -> bool
        | (untyped) -> false

  # <!--
  #   rdoc-file=re.c
  #   - matchdata[index] -> string or nil
  #   - matchdata[start, length] -> array
  #   - matchdata[range] -> array
  #   - matchdata[name] -> string or nil
  # -->
  # When arguments `index`, +start and `length`, or `range` are given, returns
  # match and captures in the style of Array#[]:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m[0] # => "HX1138"
  #     m[1, 2]  # => ["H", "X"]
  #     m[1..3]  # => ["H", "X", "113"]
  #     m[-3, 2] # => ["X", "113"]
  #
  # When string or symbol argument `name` is given, returns the matched substring
  # for the given name:
  #
  #     m = /(?<foo>.)(.)(?<bar>.+)/.match("hoge")
  #     # => #<MatchData "hoge" foo:"h" bar:"ge">
  #     m['foo'] # => "h"
  #     m[:bar]  # => "ge"
  #
  # If multiple captures have the same name, returns the last matched substring.
  #
  #     m = /(?<foo>.)(?<foo>.+)/.match("hoge")
  #     # => #<MatchData "hoge" foo:"h" foo:"oge">
  #     m[:foo] #=> "oge"
  #
  #     m = /\W(?<foo>.+)|\w(?<foo>.+)|(?<foo>.+)/.match("hoge")
  #     #<MatchData "hoge" foo:nil foo:"oge" foo:nil>
  #     m[:foo] #=> "oge"
  #
  def []: (capture backref, ?nil) -> String?
        | (int start, int length) -> Array[String?]
        | (range[int?] range) -> Array[String?]

  # <!--
  #   rdoc-file=re.c
  #   - begin(n) -> integer
  #   - begin(name) -> integer
  # -->
  # Returns the offset (in characters) of the beginning of the specified match.
  #
  # When non-negative integer argument `n` is given, returns the offset of the
  # beginning of the `n`th match:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m[0]       # => "HX1138"
  #     m.begin(0) # => 1
  #     m[3]       # => "113"
  #     m.begin(3) # => 3
  #
  #     m = /(т)(е)(с)/.match('тест')
  #     # => #<MatchData "тес" 1:"т" 2:"е" 3:"с">
  #     m[0]       # => "тес"
  #     m.begin(0) # => 0
  #     m[3]       # => "с"
  #     m.begin(3) # => 2
  #
  # When string or symbol argument `name` is given, returns the offset of the
  # beginning for the named match:
  #
  #     m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
  #     # => #<MatchData "hog" foo:"h" bar:"g">
  #     m[:foo]        # => "h"
  #     m.begin('foo') # => 0
  #     m[:bar]        # => "g"
  #     m.begin(:bar)  # => 2
  #
  # Related: MatchData#end, MatchData#offset, MatchData#byteoffset.
  #
  def begin: (capture backref) -> Integer?

  # <!--
  #   rdoc-file=re.c
  #   - bytebegin(n) -> integer
  #   - bytebegin(name) -> integer
  # -->
  # Returns the offset (in bytes) of the beginning of the specified match.
  #
  # When non-negative integer argument `n` is given, returns the offset of the
  # beginning of the `n`th match:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m[0]       # => "HX1138"
  #     m.bytebegin(0) # => 1
  #     m[3]       # => "113"
  #     m.bytebegin(3) # => 3
  #
  #     m = /(т)(е)(с)/.match('тест')
  #     # => #<MatchData "тес" 1:"т" 2:"е" 3:"с">
  #     m[0]       # => "тес"
  #     m.bytebegin(0) # => 0
  #     m[3]       # => "с"
  #     m.bytebegin(3) # => 4
  #
  # When string or symbol argument `name` is given, returns the offset of the
  # beginning for the named match:
  #
  #     m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
  #     # => #<MatchData "hog" foo:"h" bar:"g">
  #     m[:foo]        # => "h"
  #     m.bytebegin('foo') # => 0
  #     m[:bar]        # => "g"
  #     m.bytebegin(:bar)  # => 2
  #
  # Related: MatchData#byteend, MatchData#byteoffset.
  #
  def bytebegin: (capture backref) -> Integer?

  # <!--
  #   rdoc-file=re.c
  #   - byteend(n) -> integer
  #   - byteend(name) -> integer
  # -->
  # Returns the offset (in bytes) of the end of the specified match.
  #
  # When non-negative integer argument `n` is given, returns the offset of the end
  # of the `n`th match:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m[0]     # => "HX1138"
  #     m.byteend(0) # => 7
  #     m[3]     # => "113"
  #     m.byteend(3) # => 6
  #
  #     m = /(т)(е)(с)/.match('тест')
  #     # => #<MatchData "тес" 1:"т" 2:"е" 3:"с">
  #     m[0]     # => "тес"
  #     m.byteend(0) # => 6
  #     m[3]     # => "с"
  #     m.byteend(3) # => 6
  #
  # When string or symbol argument `name` is given, returns the offset of the end
  # for the named match:
  #
  #     m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
  #     # => #<MatchData "hog" foo:"h" bar:"g">
  #     m[:foo]      # => "h"
  #     m.byteend('foo') # => 1
  #     m[:bar]      # => "g"
  #     m.byteend(:bar)  # => 3
  #
  # Related: MatchData#bytebegin, MatchData#byteoffset.
  #
  def byteend: (capture backref) -> Integer?

  # <!--
  #   rdoc-file=re.c
  #   - mtch.byteoffset(n)   -> array
  # -->
  # Returns a two-element array containing the beginning and ending byte-based
  # offsets of the *n*th match. *n* can be a string or symbol to reference a named
  # capture.
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     m.byteoffset(0)      #=> [1, 7]
  #     m.byteoffset(4)      #=> [6, 7]
  #
  #     m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
  #     p m.byteoffset(:foo) #=> [0, 1]
  #     p m.byteoffset(:bar) #=> [2, 3]
  #
  def byteoffset: (capture backref) -> ([Integer, Integer] | [nil, nil])

  # <!--
  #   rdoc-file=re.c
  #   - captures -> array
  # -->
  # Returns the array of captures, which are all matches except `m[0]`:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m[0]       # => "HX1138"
  #     m.captures # => ["H", "X", "113", "8"]
  #
  # Related: MatchData.to_a.
  #
  def captures: () -> Array[String?]

  # <!-- rdoc-file=re.c -->
  # Returns the array of captures, which are all matches except `m[0]`:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m[0]       # => "HX1138"
  #     m.captures # => ["H", "X", "113", "8"]
  #
  # Related: MatchData.to_a.
  #
  alias deconstruct captures

  # <!--
  #   rdoc-file=re.c
  #   - deconstruct_keys(array_of_names) -> hash
  # -->
  # Returns a hash of the named captures for the given names.
  #
  #     m = /(?<hours>\d{2}):(?<minutes>\d{2}):(?<seconds>\d{2})/.match("18:37:22")
  #     m.deconstruct_keys([:hours, :minutes]) # => {:hours => "18", :minutes => "37"}
  #     m.deconstruct_keys(nil) # => {:hours => "18", :minutes => "37", :seconds => "22"}
  #
  # Returns an empty hash if no named captures were defined:
  #
  #     m = /(\d{2}):(\d{2}):(\d{2})/.match("18:37:22")
  #     m.deconstruct_keys(nil) # => {}
  #
  def deconstruct_keys: (Array[Symbol]? array_of_names) -> Hash[Symbol, String?]

  # <!--
  #   rdoc-file=re.c
  #   - end(n) -> integer
  #   - end(name) -> integer
  # -->
  # Returns the offset (in characters) of the end of the specified match.
  #
  # When non-negative integer argument `n` is given, returns the offset of the end
  # of the `n`th match:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m[0]     # => "HX1138"
  #     m.end(0) # => 7
  #     m[3]     # => "113"
  #     m.end(3) # => 6
  #
  #     m = /(т)(е)(с)/.match('тест')
  #     # => #<MatchData "тес" 1:"т" 2:"е" 3:"с">
  #     m[0]     # => "тес"
  #     m.end(0) # => 3
  #     m[3]     # => "с"
  #     m.end(3) # => 3
  #
  # When string or symbol argument `name` is given, returns the offset of the end
  # for the named match:
  #
  #     m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
  #     # => #<MatchData "hog" foo:"h" bar:"g">
  #     m[:foo]      # => "h"
  #     m.end('foo') # => 1
  #     m[:bar]      # => "g"
  #     m.end(:bar)  # => 3
  #
  # Related: MatchData#begin, MatchData#offset, MatchData#byteoffset.
  #
  def end: (capture backref) -> Integer?

  # <!--
  #   rdoc-file=re.c
  #   - matchdata == object -> true or false
  # -->
  # Returns `true` if `object` is another MatchData object whose target string,
  # regexp, match, and captures are the same as `self`, `false` otherwise.
  #
  alias eql? ==

  # <!--
  #   rdoc-file=re.c
  #   - hash -> integer
  # -->
  # Returns the integer hash value for `self`, based on the target string, regexp,
  # match, and captures.
  #
  # See also Object#hash.
  #
  def hash: () -> Integer

  # <!--
  #   rdoc-file=re.c
  #   - inspect -> string
  # -->
  # Returns a string representation of `self`:
  #
  #     m = /.$/.match("foo")
  #     # => #<MatchData "o">
  #     m.inspect # => "#<MatchData \"o\">"
  #
  #     m = /(.)(.)(.)/.match("foo")
  #     # => #<MatchData "foo" 1:"f" 2:"o" 3:"o">
  #     m.inspect # => "#<MatchData \"foo\" 1:\"f\" 2:\"o\
  #
  #     m = /(.)(.)?(.)/.match("fo")
  #     # => #<MatchData "fo" 1:"f" 2:nil 3:"o">
  #     m.inspect # => "#<MatchData \"fo\" 1:\"f\" 2:nil 3:\"o\">"
  #
  # Related: MatchData#to_s.
  #
  def inspect: () -> String

  # <!-- rdoc-file=re.c -->
  # Returns size of the match array:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m.size # => 5
  #
  alias length size

  # <!--
  #   rdoc-file=re.c
  #   - named_captures(symbolize_names: false) -> hash
  # -->
  # Returns a hash of the named captures; each key is a capture name; each value
  # is its captured string or `nil`:
  #
  #     m = /(?<foo>.)(.)(?<bar>.+)/.match("hoge")
  #     # => #<MatchData "hoge" foo:"h" bar:"ge">
  #     m.named_captures # => {"foo"=>"h", "bar"=>"ge"}
  #
  #     m = /(?<a>.)(?<b>.)/.match("01")
  #     # => #<MatchData "01" a:"0" b:"1">
  #     m.named_captures #=> {"a" => "0", "b" => "1"}
  #
  #     m = /(?<a>.)(?<b>.)?/.match("0")
  #     # => #<MatchData "0" a:"0" b:nil>
  #     m.named_captures #=> {"a" => "0", "b" => nil}
  #
  #     m = /(?<a>.)(?<a>.)/.match("01")
  #     # => #<MatchData "01" a:"0" a:"1">
  #     m.named_captures #=> {"a" => "1"}
  #
  # If keyword argument `symbolize_names` is given a true value, the keys in the
  # resulting hash are Symbols:
  #
  #     m = /(?<a>.)(?<a>.)/.match("01")
  #     # => #<MatchData "01" a:"0" a:"1">
  #     m.named_captures(symbolize_names: true) #=> {:a => "1"}
  #
  def named_captures: () -> Hash[String, String?]
                    | (symbolize_names: true) -> Hash[Symbol, String?]
                    | (symbolize_names: boolish) -> Hash[String | Symbol, String?]

  # <!--
  #   rdoc-file=re.c
  #   - names -> array_of_names
  # -->
  # Returns an array of the capture names (see [Named
  # Captures](rdoc-ref:Regexp@Named+Captures)):
  #
  #     m = /(?<foo>.)(?<bar>.)(?<baz>.)/.match("hoge")
  #     # => #<MatchData "hog" foo:"h" bar:"o" baz:"g">
  #     m.names # => ["foo", "bar", "baz"]
  #
  #     m = /foo/.match('foo') # => #<MatchData "foo">
  #     m.names # => [] # No named captures.
  #
  # Equivalent to:
  #
  #     m = /(?<foo>.)(?<bar>.)(?<baz>.)/.match("hoge")
  #     m.regexp.names # => ["foo", "bar", "baz"]
  #
  def names: () -> Array[String]

  # <!--
  #   rdoc-file=re.c
  #   - match(n) -> string or nil
  #   - match(name) -> string or nil
  # -->
  # Returns the matched substring corresponding to the given argument.
  #
  # When non-negative argument `n` is given, returns the matched substring for the
  # `n`th match:
  #
  #     m = /(.)(.)(\d+)(\d)(\w)?/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8" 5:nil>
  #     m.match(0) # => "HX1138"
  #     m.match(4) # => "8"
  #     m.match(5) # => nil
  #
  # When string or symbol argument `name` is given, returns the matched substring
  # for the given name:
  #
  #     m = /(?<foo>.)(.)(?<bar>.+)/.match("hoge")
  #     # => #<MatchData "hoge" foo:"h" bar:"ge">
  #     m.match('foo') # => "h"
  #     m.match(:bar)  # => "ge"
  #
  def match: (capture backref) -> String?

  # <!--
  #   rdoc-file=re.c
  #   - match_length(n) -> integer or nil
  #   - match_length(name) -> integer or nil
  # -->
  # Returns the length (in characters) of the matched substring corresponding to
  # the given argument.
  #
  # When non-negative argument `n` is given, returns the length of the matched
  # substring for the `n`th match:
  #
  #     m = /(.)(.)(\d+)(\d)(\w)?/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8" 5:nil>
  #     m.match_length(0) # => 6
  #     m.match_length(4) # => 1
  #     m.match_length(5) # => nil
  #
  # When string or symbol argument `name` is given, returns the length of the
  # matched substring for the named match:
  #
  #     m = /(?<foo>.)(.)(?<bar>.+)/.match("hoge")
  #     # => #<MatchData "hoge" foo:"h" bar:"ge">
  #     m.match_length('foo') # => 1
  #     m.match_length(:bar)  # => 2
  #
  def match_length: (capture backref) -> Integer?

  # <!--
  #   rdoc-file=re.c
  #   - offset(n) -> [start_offset, end_offset]
  #   - offset(name) -> [start_offset, end_offset]
  # -->
  # Returns a 2-element array containing the beginning and ending offsets (in
  # characters) of the specified match.
  #
  # When non-negative integer argument `n` is given, returns the starting and
  # ending offsets of the `n`th match:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m[0]        # => "HX1138"
  #     m.offset(0) # => [1, 7]
  #     m[3]        # => "113"
  #     m.offset(3) # => [3, 6]
  #
  #     m = /(т)(е)(с)/.match('тест')
  #     # => #<MatchData "тес" 1:"т" 2:"е" 3:"с">
  #     m[0]        # => "тес"
  #     m.offset(0) # => [0, 3]
  #     m[3]        # => "с"
  #     m.offset(3) # => [2, 3]
  #
  # When string or symbol argument `name` is given, returns the starting and
  # ending offsets for the named match:
  #
  #     m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
  #     # => #<MatchData "hog" foo:"h" bar:"g">
  #     m[:foo]         # => "h"
  #     m.offset('foo') # => [0, 1]
  #     m[:bar]         # => "g"
  #     m.offset(:bar)  # => [2, 3]
  #
  # Related: MatchData#byteoffset, MatchData#begin, MatchData#end.
  #
  def offset: (capture backref) -> ([Integer, Integer] | [nil, nil])

  # <!--
  #   rdoc-file=re.c
  #   - post_match   -> str
  # -->
  # Returns the substring of the target string from the end of the first match in
  # `self` (that is, `self[0]`) to the end of the string; equivalent to regexp
  # global variable `$'`:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138: The Movie")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m[0]         # => "HX1138"
  #     m.post_match # => ": The Movie"\
  #
  # Related: MatchData.pre_match.
  #
  def post_match: () -> String

  # <!--
  #   rdoc-file=re.c
  #   - pre_match -> string
  # -->
  # Returns the substring of the target string from its beginning up to the first
  # match in `self` (that is, `self[0]`); equivalent to regexp global variable
  # `$``:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m[0]        # => "HX1138"
  #     m.pre_match # => "T"
  #
  # Related: MatchData#post_match.
  #
  def pre_match: () -> String

  # <!--
  #   rdoc-file=re.c
  #   - regexp -> regexp
  # -->
  # Returns the regexp that produced the match:
  #
  #     m = /a.*b/.match("abc") # => #<MatchData "ab">
  #     m.regexp                # => /a.*b/
  #
  def regexp: () -> Regexp

  # <!--
  #   rdoc-file=re.c
  #   - size -> integer
  # -->
  # Returns size of the match array:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m.size # => 5
  #
  def size: () -> Integer

  # <!--
  #   rdoc-file=re.c
  #   - string -> string
  # -->
  # Returns the target string if it was frozen; otherwise, returns a frozen copy
  # of the target string:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m.string # => "THX1138."
  #
  def string: () -> String

  # <!--
  #   rdoc-file=re.c
  #   - to_a -> array
  # -->
  # Returns the array of matches:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m.to_a # => ["HX1138", "H", "X", "113", "8"]
  #
  # Related: MatchData#captures.
  #
  def to_a: () -> Array[String?]

  # <!--
  #   rdoc-file=re.c
  #   - to_s -> string
  # -->
  # Returns the matched string:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138.")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m.to_s # => "HX1138"
  #
  #     m = /(?<foo>.)(.)(?<bar>.+)/.match("hoge")
  #     # => #<MatchData "hoge" foo:"h" bar:"ge">
  #     m.to_s # => "hoge"
  #
  # Related: MatchData.inspect.
  #
  def to_s: () -> String

  # <!--
  #   rdoc-file=re.c
  #   - values_at(*indexes) -> array
  # -->
  # Returns match and captures at the given `indexes`, which may include any
  # mixture of:
  #
  # *   Integers.
  # *   Ranges.
  # *   Names (strings and symbols).
  #
  # Examples:
  #
  #     m = /(.)(.)(\d+)(\d)/.match("THX1138: The Movie")
  #     # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
  #     m.values_at(0, 2, -2) # => ["HX1138", "X", "113"]
  #     m.values_at(1..2, -1) # => ["H", "X", "8"]
  #
  #     m = /(?<a>\d+) *(?<op>[+\-*\/]) *(?<b>\d+)/.match("1 + 2")
  #     # => #<MatchData "1 + 2" a:"1" op:"+" b:"2">
  #     m.values_at(0, 1..2, :a, :b, :op)
  #     # => ["1 + 2", "1", "+", "1", "2", "+"]
  #
  def values_at: (*capture | range[int?] backrefs) -> Array[String?]
end
