# <!-- rdoc-file=enum.c -->
# ## What's Here
#
# Module Enumerable provides methods that are useful to a collection class for:
#
# *   [Querying](rdoc-ref:Enumerable@Methods+for+Querying)
# *   [Fetching](rdoc-ref:Enumerable@Methods+for+Fetching)
# *   [Searching and
#     Filtering](rdoc-ref:Enumerable@Methods+for+Searching+and+Filtering)
# *   [Sorting](rdoc-ref:Enumerable@Methods+for+Sorting)
# *   [Iterating](rdoc-ref:Enumerable@Methods+for+Iterating)
# *   [And more....](rdoc-ref:Enumerable@Other+Methods)
#
#
# ### Methods for Querying
#
# These methods return information about the Enumerable other than the elements
# themselves:
#
# *   #include?, #member?: Returns `true` if `self == object`, `false`
#     otherwise.
# *   #all?: Returns `true` if all elements meet a specified criterion; `false`
#     otherwise.
# *   #any?: Returns `true` if any element meets a specified criterion; `false`
#     otherwise.
# *   #none?: Returns `true` if no element meets a specified criterion; `false`
#     otherwise.
# *   #one?: Returns `true` if exactly one element meets a specified criterion;
#     `false` otherwise.
# *   #count: Returns the count of elements, based on an argument or block
#     criterion, if given.
# *   #tally: Returns a new Hash containing the counts of occurrences of each
#     element.
#
#
# ### Methods for Fetching
#
# These methods return entries from the Enumerable, without modifying it:
#
# *Leading, trailing, or all elements*:
#
# *   #entries, #to_a: Returns all elements.
# *   #first: Returns the first element or leading elements.
# *   #take: Returns a specified number of leading elements.
# *   #drop: Returns a specified number of trailing elements.
# *   #take_while: Returns leading elements as specified by the given block.
# *   #drop_while: Returns trailing elements as specified by the given block.
#
#
# *Minimum and maximum value elements*:
#
# *   #min: Returns the elements whose values are smallest among the elements,
#     as determined by `<=>` or a given block.
# *   #max: Returns the elements whose values are largest among the elements, as
#     determined by `<=>` or a given block.
# *   #minmax: Returns a 2-element Array containing the smallest and largest
#     elements.
# *   #min_by: Returns the smallest element, as determined by the given block.
# *   #max_by: Returns the largest element, as determined by the given block.
# *   #minmax_by: Returns the smallest and largest elements, as determined by
#     the given block.
#
#
# *Groups, slices, and partitions*:
#
# *   #group_by: Returns a Hash that partitions the elements into groups.
# *   #partition: Returns elements partitioned into two new Arrays, as
#     determined by the given block.
# *   #slice_after: Returns a new Enumerator whose entries are a partition of
#     `self`, based either on a given `object` or a given block.
# *   #slice_before: Returns a new Enumerator whose entries are a partition of
#     `self`, based either on a given `object` or a given block.
# *   #slice_when: Returns a new Enumerator whose entries are a partition of
#     `self` based on the given block.
# *   #chunk: Returns elements organized into chunks as specified by the given
#     block.
# *   #chunk_while: Returns elements organized into chunks as specified by the
#     given block.
#
#
# ### Methods for Searching and Filtering
#
# These methods return elements that meet a specified criterion:
#
# *   #find, #detect: Returns an element selected by the block.
# *   #find_all, #filter, #select: Returns elements selected by the block.
# *   #find_index: Returns the index of an element selected by a given object or
#     block.
# *   #reject: Returns elements not rejected by the block.
# *   #uniq: Returns elements that are not duplicates.
#
#
# ### Methods for Sorting
#
# These methods return elements in sorted order:
#
# *   #sort: Returns the elements, sorted by `<=>` or the given block.
# *   #sort_by: Returns the elements, sorted by the given block.
#
#
# ### Methods for Iterating
#
# *   #each_entry: Calls the block with each successive element (slightly
#     different from #each).
# *   #each_with_index: Calls the block with each successive element and its
#     index.
# *   #each_with_object: Calls the block with each successive element and a
#     given object.
# *   #each_slice: Calls the block with successive non-overlapping slices.
# *   #each_cons: Calls the block with successive overlapping slices. (different
#     from #each_slice).
# *   #reverse_each: Calls the block with each successive element, in reverse
#     order.
#
#
# ### Other Methods
#
# *   #map, #collect: Returns objects returned by the block.
# *   #filter_map: Returns truthy objects returned by the block.
# *   #flat_map, #collect_concat: Returns flattened objects returned by the
#     block.
# *   #grep: Returns elements selected by a given object or objects returned by
#     a given block.
# *   #grep_v: Returns elements selected by a given object or objects returned
#     by a given block.
# *   #reduce, #inject: Returns the object formed by combining all elements.
# *   #sum: Returns the sum of the elements, using method `+`.
# *   #zip: Combines each element with elements from other enumerables; returns
#     the n-tuples or calls the block with each.
# *   #cycle: Calls the block with each element, cycling repeatedly.
#
#
# ## Usage
#
# To use module Enumerable in a collection class:
#
# *   Include it:
#
#         include Enumerable
#
# *   Implement method `#each` which must yield successive elements of the
#     collection. The method will be called by almost any Enumerable method.
#
#
# Example:
#
#     class Foo
#       include Enumerable
#       def each
#         yield 1
#         yield 1, 2
#         yield
#       end
#     end
#     Foo.new.each_entry{ |element| p element }
#
# Output:
#
#     1
#     [1, 2]
#     nil
#
# ## Enumerable in Ruby Classes
#
# These Ruby core classes include (or extend) Enumerable:
#
# *   ARGF
# *   Array
# *   Dir
# *   Enumerator
# *   ENV (extends)
# *   Hash
# *   IO
# *   Range
# *   Struct
#
#
# These Ruby standard library classes include Enumerable:
#
# *   CSV
# *   CSV::Table
# *   CSV::Row
# *   Set
#
#
# Virtually all methods in Enumerable call method `#each` in the including
# class:
#
# *   `Hash#each` yields the next key-value pair as a 2-element Array.
# *   `Struct#each` yields the next name-value pair as a 2-element Array.
# *   For the other classes above, `#each` yields the next object from the
#     collection.
#
#
# ## About the Examples
#
# The example code snippets for the Enumerable methods:
#
# *   Always show the use of one or more Array-like classes (often Array
#     itself).
# *   Sometimes show the use of a Hash-like class. For some methods, though, the
#     usage would not make sense, and so it is not shown.  Example: #tally would
#     find exactly one of each Hash entry.
#
module Enumerable[unchecked out Elem] : _Each[Elem]
  # <!--
  #   rdoc-file=enum.c
  #   - all?                  -> true or false
  #   - all?(pattern)         -> true or false
  #   - all? {|element| ... } -> true or false
  # -->
  # Returns whether every element meets a given criterion.
  #
  # If `self` has no element, returns `true` and argument or block are not used.
  #
  # With no argument and no block, returns whether every element is truthy:
  #
  #     (1..4).all?           # => true
  #     %w[a b c d].all?      # => true
  #     [1, 2, nil].all?      # => false
  #     ['a','b', false].all? # => false
  #     [].all?               # => true
  #
  # With argument `pattern` and no block, returns whether for each element
  # `element`, `pattern === element`:
  #
  #     (1..4).all?(Integer)                 # => true
  #     (1..4).all?(Numeric)                 # => true
  #     (1..4).all?(Float)                   # => false
  #     %w[bar baz bat bam].all?(/ba/)       # => true
  #     %w[bar baz bat bam].all?(/bar/)      # => false
  #     %w[bar baz bat bam].all?('ba')       # => false
  #     {foo: 0, bar: 1, baz: 2}.all?(Array) # => true
  #     {foo: 0, bar: 1, baz: 2}.all?(Hash)  # => false
  #     [].all?(Integer)                     # => true
  #
  # With a block given, returns whether the block returns a truthy value for every
  # element:
  #
  #     (1..4).all? {|element| element < 5 }                    # => true
  #     (1..4).all? {|element| element < 4 }                    # => false
  #     {foo: 0, bar: 1, baz: 2}.all? {|key, value| value < 3 } # => true
  #     {foo: 0, bar: 1, baz: 2}.all? {|key, value| value < 2 } # => false
  #
  # Related: #any?, #none? #one?.
  #
  def all?: () -> bool
          | () { (Elem) -> boolish } -> bool

  # <!--
  #   rdoc-file=enum.c
  #   - any?                  -> true or false
  #   - any?(pattern)         -> true or false
  #   - any? {|element| ... } -> true or false
  # -->
  # Returns whether any element meets a given criterion.
  #
  # If `self` has no element, returns `false` and argument or block are not used.
  #
  # With no argument and no block, returns whether any element is truthy:
  #
  #     (1..4).any?          # => true
  #     %w[a b c d].any?     # => true
  #     [1, false, nil].any? # => true
  #     [].any?              # => false
  #
  # With argument `pattern` and no block, returns whether for any element
  # `element`, `pattern === element`:
  #
  #     [nil, false, 0].any?(Integer)        # => true
  #     [nil, false, 0].any?(Numeric)        # => true
  #     [nil, false, 0].any?(Float)          # => false
  #     %w[bar baz bat bam].any?(/m/)        # => true
  #     %w[bar baz bat bam].any?(/foo/)      # => false
  #     %w[bar baz bat bam].any?('ba')       # => false
  #     {foo: 0, bar: 1, baz: 2}.any?(Array) # => true
  #     {foo: 0, bar: 1, baz: 2}.any?(Hash)  # => false
  #     [].any?(Integer)                     # => false
  #
  # With a block given, returns whether the block returns a truthy value for any
  # element:
  #
  #     (1..4).any? {|element| element < 2 }                    # => true
  #     (1..4).any? {|element| element < 1 }                    # => false
  #     {foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 1 } # => true
  #     {foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 0 } # => false
  #
  # Related: #all?, #none?, #one?.
  #
  def any?: () -> bool
          | () { (Elem) -> boolish } -> bool

  # <!--
  #   rdoc-file=enum.c
  #   - map {|element| ... } -> array
  #   - map -> enumerator
  # -->
  # Returns an array of objects returned by the block.
  #
  # With a block given, calls the block with successive elements; returns an array
  # of the objects returned by the block:
  #
  #     (0..4).map {|i| i*i }                               # => [0, 1, 4, 9, 16]
  #     {foo: 0, bar: 1, baz: 2}.map {|key, value| value*2} # => [0, 2, 4]
  #
  # With no block given, returns an Enumerator.
  #
  def collect: [U] () { (Elem arg0) -> U } -> ::Array[U]
             | () -> ::Enumerator[Elem, ::Array[untyped]]

  # <!-- rdoc-file=enum.c -->
  # Returns an array of flattened objects returned by the block.
  #
  # With a block given, calls the block with successive elements; returns a
  # flattened array of objects returned by the block:
  #
  #     [0, 1, 2, 3].flat_map {|element| -element }                    # => [0, -1, -2, -3]
  #     [0, 1, 2, 3].flat_map {|element| [element, -element] }         # => [0, 0, 1, -1, 2, -2, 3, -3]
  #     [[0, 1], [2, 3]].flat_map {|e| e + [100] }                     # => [0, 1, 100, 2, 3, 100]
  #     {foo: 0, bar: 1, baz: 2}.flat_map {|key, value| [key, value] } # => [:foo, 0, :bar, 1, :baz, 2]
  #
  # With no block given, returns an Enumerator.
  #
  # Alias: #collect_concat.
  #
  def collect_concat: [U] () { (Elem) -> (::Array[U] | U) } -> ::Array[U]
                    | () -> ::Enumerator[Elem, ::Array[untyped]]

  # <!--
  #   rdoc-file=enum.c
  #   - compact -> array
  # -->
  # Returns an array of all non-`nil` elements:
  #
  #     a = [nil, 0, nil, 'a', false, nil, false, nil, 'a', nil, 0, nil]
  #     a.compact # => [0, "a", false, false, "a", 0]
  #
  def compact: () -> Array[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - count -> integer
  #   - count(object) -> integer
  #   - count {|element| ... } -> integer
  # -->
  # Returns the count of elements, based on an argument or block criterion, if
  # given.
  #
  # With no argument and no block given, returns the number of elements:
  #
  #     [0, 1, 2].count                # => 3
  #     {foo: 0, bar: 1, baz: 2}.count # => 3
  #
  # With argument `object` given, returns the number of elements that are `==` to
  # `object`:
  #
  #     [0, 1, 2, 1].count(1)           # => 2
  #
  # With a block given, calls the block with each element and returns the number
  # of elements for which the block returns a truthy value:
  #
  #     [0, 1, 2, 3].count {|element| element < 2}              # => 2
  #     {foo: 0, bar: 1, baz: 2}.count {|key, value| value < 2} # => 2
  #
  def count: () -> Integer
           | (Elem) -> Integer
           | () { (Elem) -> boolish } -> Integer

  # <!--
  #   rdoc-file=enum.c
  #   - cycle(n = nil) {|element| ...} ->  nil
  #   - cycle(n = nil)                 ->  enumerator
  # -->
  # When called with positive integer argument `n` and a block, calls the block
  # with each element, then does so again, until it has done so `n` times; returns
  # `nil`:
  #
  #     a = []
  #     (1..4).cycle(3) {|element| a.push(element) } # => nil
  #     a # => [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
  #     a = []
  #     ('a'..'d').cycle(2) {|element| a.push(element) }
  #     a # => ["a", "b", "c", "d", "a", "b", "c", "d"]
  #     a = []
  #     {foo: 0, bar: 1, baz: 2}.cycle(2) {|element| a.push(element) }
  #     a # => [[:foo, 0], [:bar, 1], [:baz, 2], [:foo, 0], [:bar, 1], [:baz, 2]]
  #
  # If count is zero or negative, does not call the block.
  #
  # When called with a block and `n` is `nil`, cycles forever.
  #
  # When no block is given, returns an Enumerator.
  #
  def cycle: (?Integer n) { (Elem arg0) -> untyped } -> NilClass
           | (?Integer n) -> ::Enumerator[Elem, NilClass]

  # <!-- rdoc-file=enum.c -->
  # Returns the first element for which the block returns a truthy value.
  #
  # With a block given, calls the block with successive elements of the
  # collection; returns the first element for which the block returns a truthy
  # value:
  #
  #     (0..9).find {|element| element > 2}                # => 3
  #
  # If no such element is found, calls `if_none_proc` and returns its return
  # value.
  #
  #     (0..9).find(proc {false}) {|element| element > 12} # => false
  #     {foo: 0, bar: 1, baz: 2}.find {|key, value| key.start_with?('b') }            # => [:bar, 1]
  #     {foo: 0, bar: 1, baz: 2}.find(proc {[]}) {|key, value| key.start_with?('c') } # => []
  #
  # With no block given, returns an Enumerator.
  #
  def detect: (?Proc ifnone) { (Elem) -> boolish } -> Elem?
            | (?Proc ifnone) -> ::Enumerator[Elem, Elem?]

  # <!--
  #   rdoc-file=enum.c
  #   - drop(n) -> array
  # -->
  # For positive integer `n`, returns an array containing all but the first `n`
  # elements:
  #
  #     r = (1..4)
  #     r.drop(3)  # => [4]
  #     r.drop(2)  # => [3, 4]
  #     r.drop(1)  # => [2, 3, 4]
  #     r.drop(0)  # => [1, 2, 3, 4]
  #     r.drop(50) # => []
  #
  #     h = {foo: 0, bar: 1, baz: 2, bat: 3}
  #     h.drop(2) # => [[:baz, 2], [:bat, 3]]
  #
  def drop: (Integer n) -> ::Array[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - drop_while {|element| ... } -> array
  #   - drop_while                  -> enumerator
  # -->
  # Calls the block with successive elements as long as the block returns a truthy
  # value; returns an array of all elements after that point:
  #
  #     (1..4).drop_while{|i| i < 3 } # => [3, 4]
  #     h = {foo: 0, bar: 1, baz: 2}
  #     a = h.drop_while{|element| key, value = *element; value < 2 }
  #     a # => [[:baz, 2]]
  #
  # With no block given, returns an Enumerator.
  #
  def drop_while: () { (Elem) -> boolish } -> ::Array[Elem]
                | () -> ::Enumerator[Elem, ::Array[Elem]]

  # <!--
  #   rdoc-file=enum.c
  #   - each_cons(n) { ... } ->  self
  #   - each_cons(n)         ->  enumerator
  # -->
  # Calls the block with each successive overlapped `n`-tuple of elements; returns
  # `self`:
  #
  #     a = []
  #     (1..5).each_cons(3) {|element| a.push(element) }
  #     a # => [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
  #
  #     a = []
  #     h = {foo: 0,  bar: 1, baz: 2, bam: 3}
  #     h.each_cons(2) {|element| a.push(element) }
  #     a # => [[[:foo, 0], [:bar, 1]], [[:bar, 1], [:baz, 2]], [[:baz, 2], [:bam, 3]]]
  #
  # With no block given, returns an Enumerator.
  #
  def each_cons: (Integer n) { (::Array[Elem]) -> void } -> self
               | (Integer n) -> ::Enumerator[::Array[Elem], self]

  # <!--
  #   rdoc-file=enum.c
  #   - each_with_index(*args) {|element, i| ..... } -> self
  #   - each_with_index(*args)                       -> enumerator
  # -->
  # With a block given, calls the block with each element and its index; returns
  # `self`:
  #
  #     h = {}
  #     (1..4).each_with_index {|element, i| h[element] = i } # => 1..4
  #     h # => {1=>0, 2=>1, 3=>2, 4=>3}
  #
  #     h = {}
  #     %w[a b c d].each_with_index {|element, i| h[element] = i }
  #     # => ["a", "b", "c", "d"]
  #     h # => {"a"=>0, "b"=>1, "c"=>2, "d"=>3}
  #
  #     a = []
  #     h = {foo: 0, bar: 1, baz: 2}
  #     h.each_with_index {|element, i| a.push([i, element]) }
  #     # => {:foo=>0, :bar=>1, :baz=>2}
  #     a # => [[0, [:foo, 0]], [1, [:bar, 1]], [2, [:baz, 2]]]
  #
  # With no block given, returns an Enumerator.
  #
  def each_with_index: () { (Elem, Integer index) -> untyped } -> self
                     | () -> ::Enumerator[[ Elem, Integer ], self]

  # <!--
  #   rdoc-file=enum.c
  #   - each_with_object(object) { |(*args), memo_object| ... }  ->  object
  #   - each_with_object(object)                                 ->  enumerator
  # -->
  # Calls the block once for each element, passing both the element and the given
  # object:
  #
  #     (1..4).each_with_object([]) {|i, a| a.push(i**2) }
  #     # => [1, 4, 9, 16]
  #
  #     {foo: 0, bar: 1, baz: 2}.each_with_object({}) {|(k, v), h| h[v] = k }
  #     # => {0=>:foo, 1=>:bar, 2=>:baz}
  #
  # With no block given, returns an Enumerator.
  #
  def each_with_object: [U] (U obj) { (Elem, U obj) -> untyped } -> U
                      | [U] (U obj) -> ::Enumerator[[ Elem, U ], U]

  # <!-- rdoc-file=enum.c -->
  # Returns an array containing the items in `self`:
  #
  #     (0..4).to_a # => [0, 1, 2, 3, 4]
  #
  def entries: () -> ::Array[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - select {|element| ... } -> array
  #   - select -> enumerator
  # -->
  # Returns an array containing elements selected by the block.
  #
  # With a block given, calls the block with successive elements; returns an array
  # of those elements for which the block returns a truthy value:
  #
  #     (0..9).select {|element| element % 3 == 0 } # => [0, 3, 6, 9]
  #     a = {foo: 0, bar: 1, baz: 2}.select {|key, value| key.start_with?('b') }
  #     a # => {:bar=>1, :baz=>2}
  #
  # With no block given, returns an Enumerator.
  #
  # Related: #reject.
  #
  def find_all: () { (Elem) -> boolish } -> ::Array[Elem]
              | () -> ::Enumerator[Elem, ::Array[Elem]]

  # <!-- rdoc-file=enum.c -->
  # Returns an array containing elements selected by the block.
  #
  # With a block given, calls the block with successive elements; returns an array
  # of those elements for which the block returns a truthy value:
  #
  #     (0..9).select {|element| element % 3 == 0 } # => [0, 3, 6, 9]
  #     a = {foo: 0, bar: 1, baz: 2}.select {|key, value| key.start_with?('b') }
  #     a # => {:bar=>1, :baz=>2}
  #
  # With no block given, returns an Enumerator.
  #
  # Related: #reject.
  #
  alias select find_all

  # <!-- rdoc-file=enum.c -->
  # Returns an array containing elements selected by the block.
  #
  # With a block given, calls the block with successive elements; returns an array
  # of those elements for which the block returns a truthy value:
  #
  #     (0..9).select {|element| element % 3 == 0 } # => [0, 3, 6, 9]
  #     a = {foo: 0, bar: 1, baz: 2}.select {|key, value| key.start_with?('b') }
  #     a # => {:bar=>1, :baz=>2}
  #
  # With no block given, returns an Enumerator.
  #
  # Related: #reject.
  #
  alias filter find_all

  # <!--
  #   rdoc-file=enum.c
  #   - find_index(object) -> integer or nil
  #   - find_index {|element| ... } -> integer or nil
  #   - find_index -> enumerator
  # -->
  # Returns the index of the first element that meets a specified criterion, or
  # `nil` if no such element is found.
  #
  # With argument `object` given, returns the index of the first element that is
  # `==` `object`:
  #
  #     ['a', 'b', 'c', 'b'].find_index('b') # => 1
  #
  # With a block given, calls the block with successive elements; returns the
  # first element for which the block returns a truthy value:
  #
  #     ['a', 'b', 'c', 'b'].find_index {|element| element.start_with?('b') } # => 1
  #     {foo: 0, bar: 1, baz: 2}.find_index {|key, value| value > 1 }         # => 2
  #
  # With no argument and no block given, returns an Enumerator.
  #
  def find_index: (untyped value) -> Integer?
                | () { (Elem) -> boolish } -> Integer?
                | () -> ::Enumerator[Elem, Integer?]

  # <!--
  #   rdoc-file=enum.c
  #   - first    -> element or nil
  #   - first(n) -> array
  # -->
  # Returns the first element or elements.
  #
  # With no argument, returns the first element, or `nil` if there is none:
  #
  #     (1..4).first                   # => 1
  #     %w[a b c].first                # => "a"
  #     {foo: 1, bar: 1, baz: 2}.first # => [:foo, 1]
  #     [].first                       # => nil
  #
  # With integer argument `n`, returns an array containing the first `n` elements
  # that exist:
  #
  #     (1..4).first(2)                   # => [1, 2]
  #     %w[a b c d].first(3)              # => ["a", "b", "c"]
  #     %w[a b c d].first(50)             # => ["a", "b", "c", "d"]
  #     {foo: 1, bar: 1, baz: 2}.first(2) # => [[:foo, 1], [:bar, 1]]
  #     [].first(2)                       # => []
  #
  def first: () -> Elem?
           | (_ToInt n) -> ::Array[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - grep(pattern) -> array
  #   - grep(pattern) {|element| ... } -> array
  # -->
  # Returns an array of objects based elements of `self` that match the given
  # pattern.
  #
  # With no block given, returns an array containing each element for which
  # `pattern === element` is `true`:
  #
  #     a = ['foo', 'bar', 'car', 'moo']
  #     a.grep(/ar/)                   # => ["bar", "car"]
  #     (1..10).grep(3..8)             # => [3, 4, 5, 6, 7, 8]
  #     ['a', 'b', 0, 1].grep(Integer) # => [0, 1]
  #
  # With a block given, calls the block with each matching element and returns an
  # array containing each object returned by the block:
  #
  #     a = ['foo', 'bar', 'car', 'moo']
  #     a.grep(/ar/) {|element| element.upcase } # => ["BAR", "CAR"]
  #
  # Related: #grep_v.
  #
  def grep: (untyped arg0) -> ::Array[Elem]
          | [U] (untyped arg0) { (Elem arg0) -> U } -> ::Array[U]

  # <!--
  #   rdoc-file=enum.c
  #   - grep_v(pattern) -> array
  #   - grep_v(pattern) {|element| ... } -> array
  # -->
  # Returns an array of objects based on elements of `self` that *don't* match the
  # given pattern.
  #
  # With no block given, returns an array containing each element for which
  # `pattern === element` is `false`:
  #
  #     a = ['foo', 'bar', 'car', 'moo']
  #     a.grep_v(/ar/)                   # => ["foo", "moo"]
  #     (1..10).grep_v(3..8)             # => [1, 2, 9, 10]
  #     ['a', 'b', 0, 1].grep_v(Integer) # => ["a", "b"]
  #
  # With a block given, calls the block with each non-matching element and returns
  # an array containing each object returned by the block:
  #
  #     a = ['foo', 'bar', 'car', 'moo']
  #     a.grep_v(/ar/) {|element| element.upcase } # => ["FOO", "MOO"]
  #
  # Related: #grep.
  #
  def grep_v: (untyped) -> ::Array[Elem]
            | [U] (untyped) { (Elem) -> U } -> ::Array[U]

  # <!--
  #   rdoc-file=enum.c
  #   - group_by {|element| ... } -> hash
  #   - group_by                  -> enumerator
  # -->
  # With a block given returns a hash:
  #
  # *   Each key is a return value from the block.
  # *   Each value is an array of those elements for which the block returned that
  #     key.
  #
  #
  # Examples:
  #
  #     g = (1..6).group_by {|i| i%3 }
  #     g # => {1=>[1, 4], 2=>[2, 5], 0=>[3, 6]}
  #     h = {foo: 0, bar: 1, baz: 0, bat: 1}
  #     g = h.group_by {|key, value| value }
  #     g # => {0=>[[:foo, 0], [:baz, 0]], 1=>[[:bar, 1], [:bat, 1]]}
  #
  # With no block given, returns an Enumerator.
  #
  def group_by: [U] () { (Elem arg0) -> U } -> ::Hash[U, ::Array[Elem]]
              | () -> ::Enumerator[Elem, ::Array[Elem]]

  # <!-- rdoc-file=enum.c -->
  # Returns whether for any element `object == element`:
  #
  #     (1..4).include?(2)                       # => true
  #     (1..4).include?(5)                       # => false
  #     (1..4).include?('2')                     # => false
  #     %w[a b c d].include?('b')                # => true
  #     %w[a b c d].include?('2')                # => false
  #     {foo: 0, bar: 1, baz: 2}.include?(:foo)  # => true
  #     {foo: 0, bar: 1, baz: 2}.include?('foo') # => false
  #     {foo: 0, bar: 1, baz: 2}.include?(0)     # => false
  #
  def include?: (Elem arg0) -> bool

  # <!--
  #   rdoc-file=enum.c
  #   - inject(symbol) -> object
  #   - inject(initial_operand, symbol) -> object
  #   - inject {|memo, operand| ... } -> object
  #   - inject(initial_operand) {|memo, operand| ... } -> object
  # -->
  # Returns an object formed from operands via either:
  #
  # *   A method named by `symbol`.
  # *   A block to which each operand is passed.
  #
  #
  # With method-name argument `symbol`, combines operands using the method:
  #
  #     # Sum, without initial_operand.
  #     (1..4).inject(:+)     # => 10
  #     # Sum, with initial_operand.
  #     (1..4).inject(10, :+) # => 20
  #
  # With a block, passes each operand to the block:
  #
  #     # Sum of squares, without initial_operand.
  #     (1..4).inject {|sum, n| sum + n*n }    # => 30
  #     # Sum of squares, with initial_operand.
  #     (1..4).inject(2) {|sum, n| sum + n*n } # => 32
  #
  # **Operands**
  #
  # If argument `initial_operand` is not given, the operands for `inject` are
  # simply the elements of `self`. Example calls and their operands:
  #
  #     `(1..4).inject(:+)`
  # :       `[1, 2, 3, 4]`.
  #
  #     `(1...4).inject(:+)`
  # :       `[1, 2, 3]`.
  #
  #     `('a'..'d').inject(:+)`
  # :       `['a', 'b', 'c', 'd']`.
  #
  #     `('a'...'d').inject(:+)`
  # :       `['a', 'b', 'c']`.
  #
  #
  #
  # Examples with first operand (which is `self.first`) of various types:
  #
  #     # Integer.
  #     (1..4).inject(:+)                # => 10
  #     # Float.
  #     [1.0, 2, 3, 4].inject(:+)        # => 10.0
  #     # Character.
  #     ('a'..'d').inject(:+)            # => "abcd"
  #     # Complex.
  #     [Complex(1, 2), 3, 4].inject(:+) # => (8+2i)
  #
  # If argument `initial_operand` is given, the operands for `inject` are that
  # value plus the elements of `self`. Example calls their operands:
  #
  #     `(1..4).inject(10, :+)`
  # :       `[10, 1, 2, 3, 4]`.
  #
  #     `(1...4).inject(10, :+)`
  # :       `[10, 1, 2, 3]`.
  #
  #     `('a'..'d').inject('e', :+)`
  # :       `['e', 'a', 'b', 'c', 'd']`.
  #
  #     `('a'...'d').inject('e', :+)`
  # :       `['e', 'a', 'b', 'c']`.
  #
  #
  #
  # Examples with `initial_operand` of various types:
  #
  #     # Integer.
  #     (1..4).inject(2, :+)               # => 12
  #     # Float.
  #     (1..4).inject(2.0, :+)             # => 12.0
  #     # String.
  #     ('a'..'d').inject('foo', :+)       # => "fooabcd"
  #     # Array.
  #     %w[a b c].inject(['x'], :push)     # => ["x", "a", "b", "c"]
  #     # Complex.
  #     (1..4).inject(Complex(2, 2), :+)   # => (12+2i)
  #
  # **Combination by Given \Method**
  #
  # If the method-name argument `symbol` is given, the operands are combined by
  # that method:
  #
  # *   The first and second operands are combined.
  # *   That result is combined with the third operand.
  # *   That result is combined with the fourth operand.
  # *   And so on.
  #
  #
  # The return value from `inject` is the result of the last combination.
  #
  # This call to `inject` computes the sum of the operands:
  #
  #     (1..4).inject(:+) # => 10
  #
  # Examples with various methods:
  #
  #     # Integer addition.
  #     (1..4).inject(:+)                # => 10
  #     # Integer multiplication.
  #     (1..4).inject(:*)                # => 24
  #     # Character range concatenation.
  #     ('a'..'d').inject('', :+)        # => "abcd"
  #     # String array concatenation.
  #     %w[foo bar baz].inject('', :+)   # => "foobarbaz"
  #     # Hash update.
  #     h = [{foo: 0, bar: 1}, {baz: 2}, {bat: 3}].inject(:update)
  #     h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
  #     # Hash conversion to nested arrays.
  #     h = {foo: 0, bar: 1}.inject([], :push)
  #     h # => [[:foo, 0], [:bar, 1]]
  #
  # **Combination by Given Block**
  #
  # If a block is given, the operands are passed to the block:
  #
  # *   The first call passes the first and second operands.
  # *   The second call passes the result of the first call, along with the third
  #     operand.
  # *   The third call passes the result of the second call, along with the fourth
  #     operand.
  # *   And so on.
  #
  #
  # The return value from `inject` is the return value from the last block call.
  #
  # This call to `inject` gives a block that writes the memo and element, and also
  # sums the elements:
  #
  #     (1..4).inject do |memo, element|
  #       p "Memo: #{memo}; element: #{element}"
  #       memo + element
  #     end # => 10
  #
  # Output:
  #
  #     "Memo: 1; element: 2"
  #     "Memo: 3; element: 3"
  #     "Memo: 6; element: 4"
  #
  def inject: (untyped init, Symbol method) -> untyped
            | (Symbol method) -> untyped
            | [A] (A initial) { (A, Elem) -> A } -> A
            | () { (Elem, Elem) -> Elem } -> Elem

  # <!--
  #   rdoc-file=enum.c
  #   - max                  -> element
  #   - max(n)               -> array
  #   - max {|a, b| ... }    -> element
  #   - max(n) {|a, b| ... } -> array
  # -->
  # Returns the element with the maximum element according to a given criterion.
  # The ordering of equal elements is indeterminate and may be unstable.
  #
  # With no argument and no block, returns the maximum element, using the
  # elements' own method `<=>` for comparison:
  #
  #     (1..4).max                   # => 4
  #     (-4..-1).max                 # => -1
  #     %w[d c b a].max              # => "d"
  #     {foo: 0, bar: 1, baz: 2}.max # => [:foo, 0]
  #     [].max                       # => nil
  #
  # With positive integer argument `n` given, and no block, returns an array
  # containing the first `n` maximum elements that exist:
  #
  #     (1..4).max(2)                   # => [4, 3]
  #     (-4..-1).max(2)                # => [-1, -2]
  #     %w[d c b a].max(2)              # => ["d", "c"]
  #     {foo: 0, bar: 1, baz: 2}.max(2) # => [[:foo, 0], [:baz, 2]]
  #     [].max(2)                       # => []
  #
  # With a block given, the block determines the maximum elements. The block is
  # called with two elements `a` and `b`, and must return:
  #
  # *   A negative integer if `a < b`.
  # *   Zero if `a == b`.
  # *   A positive integer if `a > b`.
  #
  #
  # With a block given and no argument, returns the maximum element as determined
  # by the block:
  #
  #     %w[xxx x xxxx xx].max {|a, b| a.size <=> b.size } # => "xxxx"
  #     h = {foo: 0, bar: 1, baz: 2}
  #     h.max {|pair1, pair2| pair1[1] <=> pair2[1] }     # => [:baz, 2]
  #     [].max {|a, b| a <=> b }                          # => nil
  #
  # With a block given and positive integer argument `n` given, returns an array
  # containing the first `n` maximum elements that exist, as determined by the
  # block.
  #
  #     %w[xxx x xxxx xx].max(2) {|a, b| a.size <=> b.size } # => ["xxxx", "xxx"]
  #     h = {foo: 0, bar: 1, baz: 2}
  #     h.max(2) {|pair1, pair2| pair1[1] <=> pair2[1] }
  #     # => [[:baz, 2], [:bar, 1]]
  #     [].max(2) {|a, b| a <=> b }                          # => []
  #
  # Related: #min, #minmax, #max_by.
  #
  def max: () -> Elem?
         | () { (Elem arg0, Elem arg1) -> Integer } -> Elem?
         | (Integer arg0) -> ::Array[Elem]
         | (Integer arg0) { (Elem arg0, Elem arg1) -> Integer } -> ::Array[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - max_by {|element| ... }    -> element
  #   - max_by(n) {|element| ... } -> array
  #   - max_by                     -> enumerator
  #   - max_by(n)                  -> enumerator
  # -->
  # Returns the elements for which the block returns the maximum values.
  #
  # With a block given and no argument, returns the element for which the block
  # returns the maximum value:
  #
  #     (1..4).max_by {|element| -element }                    # => 1
  #     %w[a b c d].max_by {|element| -element.ord }           # => "a"
  #     {foo: 0, bar: 1, baz: 2}.max_by {|key, value| -value } # => [:foo, 0]
  #     [].max_by {|element| -element }                        # => nil
  #
  # With a block given and positive integer argument `n` given, returns an array
  # containing the `n` elements for which the block returns maximum values:
  #
  #     (1..4).max_by(2) {|element| -element }
  #     # => [1, 2]
  #     %w[a b c d].max_by(2) {|element| -element.ord }
  #     # => ["a", "b"]
  #     {foo: 0, bar: 1, baz: 2}.max_by(2) {|key, value| -value }
  #     # => [[:foo, 0], [:bar, 1]]
  #     [].max_by(2) {|element| -element }
  #     # => []
  #
  # Returns an Enumerator if no block is given.
  #
  # Related: #max, #minmax, #min_by.
  #
  def max_by: () -> ::Enumerator[Elem, Elem?]
            | () { (Elem arg0) -> (Comparable | ::Array[untyped]) } -> Elem?
            | (Integer arg0) -> ::Enumerator[Elem, ::Array[Elem]]
            | (Integer arg0) { (Elem arg0) -> (Comparable | ::Array[untyped]) } -> ::Array[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - min                  -> element
  #   - min(n)               -> array
  #   - min {|a, b| ... }    -> element
  #   - min(n) {|a, b| ... } -> array
  # -->
  # Returns the element with the minimum element according to a given criterion.
  # The ordering of equal elements is indeterminate and may be unstable.
  #
  # With no argument and no block, returns the minimum element, using the
  # elements' own method `<=>` for comparison:
  #
  #     (1..4).min                   # => 1
  #     (-4..-1).min                 # => -4
  #     %w[d c b a].min              # => "a"
  #     {foo: 0, bar: 1, baz: 2}.min # => [:bar, 1]
  #     [].min                       # => nil
  #
  # With positive integer argument `n` given, and no block, returns an array
  # containing the first `n` minimum elements that exist:
  #
  #     (1..4).min(2)                   # => [1, 2]
  #     (-4..-1).min(2)                 # => [-4, -3]
  #     %w[d c b a].min(2)              # => ["a", "b"]
  #     {foo: 0, bar: 1, baz: 2}.min(2) # => [[:bar, 1], [:baz, 2]]
  #     [].min(2)                       # => []
  #
  # With a block given, the block determines the minimum elements. The block is
  # called with two elements `a` and `b`, and must return:
  #
  # *   A negative integer if `a < b`.
  # *   Zero if `a == b`.
  # *   A positive integer if `a > b`.
  #
  #
  # With a block given and no argument, returns the minimum element as determined
  # by the block:
  #
  #     %w[xxx x xxxx xx].min {|a, b| a.size <=> b.size } # => "x"
  #     h = {foo: 0, bar: 1, baz: 2}
  #     h.min {|pair1, pair2| pair1[1] <=> pair2[1] } # => [:foo, 0]
  #     [].min {|a, b| a <=> b }                          # => nil
  #
  # With a block given and positive integer argument `n` given, returns an array
  # containing the first `n` minimum elements that exist, as determined by the
  # block.
  #
  #     %w[xxx x xxxx xx].min(2) {|a, b| a.size <=> b.size } # => ["x", "xx"]
  #     h = {foo: 0, bar: 1, baz: 2}
  #     h.min(2) {|pair1, pair2| pair1[1] <=> pair2[1] }
  #     # => [[:foo, 0], [:bar, 1]]
  #     [].min(2) {|a, b| a <=> b }                          # => []
  #
  # Related: #min_by, #minmax, #max.
  #
  def min: () -> Elem?
         | () { (Elem arg0, Elem arg1) -> Integer } -> Elem?
         | (Integer arg0) -> ::Array[Elem]
         | (Integer arg0) { (Elem arg0, Elem arg1) -> Integer } -> ::Array[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - min_by {|element| ... }    -> element
  #   - min_by(n) {|element| ... } -> array
  #   - min_by                     -> enumerator
  #   - min_by(n)                  -> enumerator
  # -->
  # Returns the elements for which the block returns the minimum values.
  #
  # With a block given and no argument, returns the element for which the block
  # returns the minimum value:
  #
  #     (1..4).min_by {|element| -element }                    # => 4
  #     %w[a b c d].min_by {|element| -element.ord }           # => "d"
  #     {foo: 0, bar: 1, baz: 2}.min_by {|key, value| -value } # => [:baz, 2]
  #     [].min_by {|element| -element }                        # => nil
  #
  # With a block given and positive integer argument `n` given, returns an array
  # containing the `n` elements for which the block returns minimum values:
  #
  #     (1..4).min_by(2) {|element| -element }
  #     # => [4, 3]
  #     %w[a b c d].min_by(2) {|element| -element.ord }
  #     # => ["d", "c"]
  #     {foo: 0, bar: 1, baz: 2}.min_by(2) {|key, value| -value }
  #     # => [[:baz, 2], [:bar, 1]]
  #     [].min_by(2) {|element| -element }
  #     # => []
  #
  # Returns an Enumerator if no block is given.
  #
  # Related: #min, #minmax, #max_by.
  #
  def min_by: () -> ::Enumerator[Elem, Elem?]
            | () { (Elem arg0) -> (Comparable | ::Array[untyped]) } -> Elem?
            | (Integer arg0) -> ::Enumerator[Elem, ::Array[Elem]]
            | (Integer arg0) { (Elem arg0) -> (Comparable | ::Array[untyped]) } -> ::Array[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - minmax               -> [minimum, maximum]
  #   - minmax {|a, b| ... } -> [minimum, maximum]
  # -->
  # Returns a 2-element array containing the minimum and maximum elements
  # according to a given criterion. The ordering of equal elements is
  # indeterminate and may be unstable.
  #
  # With no argument and no block, returns the minimum and maximum elements, using
  # the elements' own method `<=>` for comparison:
  #
  #     (1..4).minmax                   # => [1, 4]
  #     (-4..-1).minmax                 # => [-4, -1]
  #     %w[d c b a].minmax              # => ["a", "d"]
  #     {foo: 0, bar: 1, baz: 2}.minmax # => [[:bar, 1], [:foo, 0]]
  #     [].minmax                       # => [nil, nil]
  #
  # With a block given, returns the minimum and maximum elements as determined by
  # the block:
  #
  #     %w[xxx x xxxx xx].minmax {|a, b| a.size <=> b.size } # => ["x", "xxxx"]
  #     h = {foo: 0, bar: 1, baz: 2}
  #     h.minmax {|pair1, pair2| pair1[1] <=> pair2[1] }
  #     # => [[:foo, 0], [:baz, 2]]
  #     [].minmax {|a, b| a <=> b }                          # => [nil, nil]
  #
  # Related: #min, #max, #minmax_by.
  #
  def minmax: () -> [ Elem?, Elem? ]
            | () { (Elem arg0, Elem arg1) -> Integer } -> [ Elem?, Elem? ]

  # <!--
  #   rdoc-file=enum.c
  #   - minmax_by {|element| ... } -> [minimum, maximum]
  #   - minmax_by                  -> enumerator
  # -->
  # Returns a 2-element array containing the elements for which the block returns
  # minimum and maximum values:
  #
  #     (1..4).minmax_by {|element| -element }
  #     # => [4, 1]
  #     %w[a b c d].minmax_by {|element| -element.ord }
  #     # => ["d", "a"]
  #     {foo: 0, bar: 1, baz: 2}.minmax_by {|key, value| -value }
  #     # => [[:baz, 2], [:foo, 0]]
  #     [].minmax_by {|element| -element }
  #     # => [nil, nil]
  #
  # Returns an Enumerator if no block is given.
  #
  # Related: #max_by, #minmax, #min_by.
  #
  def minmax_by: () -> [ Elem?, Elem? ]
               | () { (Elem arg0) -> (Comparable | ::Array[untyped]) } -> [ Elem?, Elem? ]

  # <!--
  #   rdoc-file=enum.c
  #   - none?                  -> true or false
  #   - none?(pattern)         -> true or false
  #   - none? {|element| ... } -> true or false
  # -->
  # Returns whether no element meets a given criterion.
  #
  # With no argument and no block, returns whether no element is truthy:
  #
  #     (1..4).none?           # => false
  #     [nil, false].none?     # => true
  #     {foo: 0}.none?         # => false
  #     {foo: 0, bar: 1}.none? # => false
  #     [].none?               # => true
  #
  # With argument `pattern` and no block, returns whether for no element
  # `element`, `pattern === element`:
  #
  #     [nil, false, 1.1].none?(Integer)      # => true
  #     %w[bar baz bat bam].none?(/m/)        # => false
  #     %w[bar baz bat bam].none?(/foo/)      # => true
  #     %w[bar baz bat bam].none?('ba')       # => true
  #     {foo: 0, bar: 1, baz: 2}.none?(Hash)  # => true
  #     {foo: 0}.none?(Array)                 # => false
  #     [].none?(Integer)                     # => true
  #
  # With a block given, returns whether the block returns a truthy value for no
  # element:
  #
  #     (1..4).none? {|element| element < 1 }                     # => true
  #     (1..4).none? {|element| element < 2 }                     # => false
  #     {foo: 0, bar: 1, baz: 2}.none? {|key, value| value < 0 }  # => true
  #     {foo: 0, bar: 1, baz: 2}.none? {|key, value| value < 1 } # => false
  #
  # Related: #one?, #all?, #any?.
  #
  def none?: () -> bool
           | () { (Elem) -> boolish } -> bool

  # <!--
  #   rdoc-file=enum.c
  #   - one?                  -> true or false
  #   - one?(pattern)         -> true or false
  #   - one? {|element| ... } -> true or false
  # -->
  # Returns whether exactly one element meets a given criterion.
  #
  # With no argument and no block, returns whether exactly one element is truthy:
  #
  #     (1..1).one?           # => true
  #     [1, nil, false].one?  # => true
  #     (1..4).one?           # => false
  #     {foo: 0}.one?         # => true
  #     {foo: 0, bar: 1}.one? # => false
  #     [].one?               # => false
  #
  # With argument `pattern` and no block, returns whether for exactly one element
  # `element`, `pattern === element`:
  #
  #     [nil, false, 0].one?(Integer)        # => true
  #     [nil, false, 0].one?(Numeric)        # => true
  #     [nil, false, 0].one?(Float)          # => false
  #     %w[bar baz bat bam].one?(/m/)        # => true
  #     %w[bar baz bat bam].one?(/foo/)      # => false
  #     %w[bar baz bat bam].one?('ba')       # => false
  #     {foo: 0, bar: 1, baz: 2}.one?(Array) # => false
  #     {foo: 0}.one?(Array)                 # => true
  #     [].one?(Integer)                     # => false
  #
  # With a block given, returns whether the block returns a truthy value for
  # exactly one element:
  #
  #     (1..4).one? {|element| element < 2 }                     # => true
  #     (1..4).one? {|element| element < 1 }                     # => false
  #     {foo: 0, bar: 1, baz: 2}.one? {|key, value| value < 1 }  # => true
  #     {foo: 0, bar: 1, baz: 2}.one? {|key, value| value < 2 } # => false
  #
  # Related: #none?, #all?, #any?.
  #
  def one?: () -> bool
          | () { (Elem) -> boolish } -> bool

  # <!--
  #   rdoc-file=enum.c
  #   - partition {|element| ... } -> [true_array, false_array]
  #   - partition -> enumerator
  # -->
  # With a block given, returns an array of two arrays:
  #
  # *   The first having those elements for which the block returns a truthy
  #     value.
  # *   The other having all other elements.
  #
  #
  # Examples:
  #
  #     p = (1..4).partition {|i| i.even? }
  #     p # => [[2, 4], [1, 3]]
  #     p = ('a'..'d').partition {|c| c < 'c' }
  #     p # => [["a", "b"], ["c", "d"]]
  #     h = {foo: 0, bar: 1, baz: 2, bat: 3}
  #     p = h.partition {|key, value| key.start_with?('b') }
  #     p # => [[[:bar, 1], [:baz, 2], [:bat, 3]], [[:foo, 0]]]
  #     p = h.partition {|key, value| value < 2 }
  #     p # => [[[:foo, 0], [:bar, 1]], [[:baz, 2], [:bat, 3]]]
  #
  # With no block given, returns an Enumerator.
  #
  # Related: Enumerable#group_by.
  #
  def partition: () { (Elem) -> boolish } -> [ ::Array[Elem], ::Array[Elem] ]
               | () -> ::Enumerator[Elem, [ ::Array[Elem], ::Array[Elem] ]]

  # <!--
  #   rdoc-file=enum.c
  #   - reject {|element| ... } -> array
  #   - reject -> enumerator
  # -->
  # Returns an array of objects rejected by the block.
  #
  # With a block given, calls the block with successive elements; returns an array
  # of those elements for which the block returns `nil` or `false`:
  #
  #     (0..9).reject {|i| i * 2 if i.even? }                             # => [1, 3, 5, 7, 9]
  #     {foo: 0, bar: 1, baz: 2}.reject {|key, value| key if value.odd? } # => {:foo=>0, :baz=>2}
  #
  # When no block given, returns an Enumerator.
  #
  # Related: #select.
  #
  def reject: () { (Elem) -> boolish } -> ::Array[Elem]
            | () -> ::Enumerator[Elem, ::Array[Elem]]

  # <!--
  #   rdoc-file=enum.c
  #   - reverse_each(*args) {|element| ... } ->  self
  #   - reverse_each(*args)                  ->  enumerator
  # -->
  # With a block given, calls the block with each element, but in reverse order;
  # returns `self`:
  #
  #     a = []
  #     (1..4).reverse_each {|element| a.push(-element) } # => 1..4
  #     a # => [-4, -3, -2, -1]
  #
  #     a = []
  #     %w[a b c d].reverse_each {|element| a.push(element) }
  #     # => ["a", "b", "c", "d"]
  #     a # => ["d", "c", "b", "a"]
  #
  #     a = []
  #     h.reverse_each {|element| a.push(element) }
  #     # => {:foo=>0, :bar=>1, :baz=>2}
  #     a # => [[:baz, 2], [:bar, 1], [:foo, 0]]
  #
  # With no block given, returns an Enumerator.
  #
  def reverse_each: () { (Elem arg0) -> untyped } -> void
                  | () -> ::Enumerator[Elem, void]

  # <!--
  #   rdoc-file=enum.c
  #   - sort               -> array
  #   - sort {|a, b| ... } -> array
  # -->
  # Returns an array containing the sorted elements of `self`. The ordering of
  # equal elements is indeterminate and may be unstable.
  #
  # With no block given, the sort compares using the elements' own method `<=>`:
  #
  #     %w[b c a d].sort              # => ["a", "b", "c", "d"]
  #     {foo: 0, bar: 1, baz: 2}.sort # => [[:bar, 1], [:baz, 2], [:foo, 0]]
  #
  # With a block given, comparisons in the block determine the ordering. The block
  # is called with two elements `a` and `b`, and must return:
  #
  # *   A negative integer if `a < b`.
  # *   Zero if `a == b`.
  # *   A positive integer if `a > b`.
  #
  #
  # Examples:
  #
  #     a = %w[b c a d]
  #     a.sort {|a, b| b <=> a } # => ["d", "c", "b", "a"]
  #     h = {foo: 0, bar: 1, baz: 2}
  #     h.sort {|a, b| b <=> a } # => [[:foo, 0], [:baz, 2], [:bar, 1]]
  #
  # See also #sort_by. It implements a Schwartzian transform which is useful when
  # key computation or comparison is expensive.
  #
  def sort: () -> ::Array[Elem]
          | () { (Elem arg0, Elem arg1) -> Integer } -> ::Array[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - sort_by {|element| ... } -> array
  #   - sort_by                  -> enumerator
  # -->
  # With a block given, returns an array of elements of `self`, sorted according
  # to the value returned by the block for each element. The ordering of equal
  # elements is indeterminate and may be unstable.
  #
  # Examples:
  #
  #     a = %w[xx xxx x xxxx]
  #     a.sort_by {|s| s.size }        # => ["x", "xx", "xxx", "xxxx"]
  #     a.sort_by {|s| -s.size }       # => ["xxxx", "xxx", "xx", "x"]
  #     h = {foo: 2, bar: 1, baz: 0}
  #     h.sort_by{|key, value| value } # => [[:baz, 0], [:bar, 1], [:foo, 2]]
  #     h.sort_by{|key, value| key }   # => [[:bar, 1], [:baz, 0], [:foo, 2]]
  #
  # With no block given, returns an Enumerator.
  #
  # The current implementation of #sort_by generates an array of tuples containing
  # the original collection element and the mapped value. This makes #sort_by
  # fairly expensive when the keysets are simple.
  #
  #     require 'benchmark'
  #
  #     a = (1..100000).map { rand(100000) }
  #
  #     Benchmark.bm(10) do |b|
  #       b.report("Sort")    { a.sort }
  #       b.report("Sort by") { a.sort_by { |a| a } }
  #     end
  #
  # *produces:*
  #
  #     user     system      total        real
  #     Sort        0.180000   0.000000   0.180000 (  0.175469)
  #     Sort by     1.980000   0.040000   2.020000 (  2.013586)
  #
  # However, consider the case where comparing the keys is a non-trivial
  # operation. The following code sorts some files on modification time using the
  # basic #sort method.
  #
  #     files = Dir["*"]
  #     sorted = files.sort { |a, b| File.new(a).mtime <=> File.new(b).mtime }
  #     sorted   #=> ["mon", "tues", "wed", "thurs"]
  #
  # This sort is inefficient: it generates two new File objects during every
  # comparison. A slightly better technique is to use the Kernel#test method to
  # generate the modification times directly.
  #
  #     files = Dir["*"]
  #     sorted = files.sort { |a, b|
  #       test(?M, a) <=> test(?M, b)
  #     }
  #     sorted   #=> ["mon", "tues", "wed", "thurs"]
  #
  # This still generates many unnecessary Time objects. A more efficient technique
  # is to cache the sort keys (modification times in this case) before the sort.
  # Perl users often call this approach a Schwartzian transform, after Randal
  # Schwartz. We construct a temporary array, where each element is an array
  # containing our sort key along with the filename. We sort this array, and then
  # extract the filename from the result.
  #
  #     sorted = Dir["*"].collect { |f|
  #        [test(?M, f), f]
  #     }.sort.collect { |f| f[1] }
  #     sorted   #=> ["mon", "tues", "wed", "thurs"]
  #
  # This is exactly what #sort_by does internally.
  #
  #     sorted = Dir["*"].sort_by { |f| test(?M, f) }
  #     sorted   #=> ["mon", "tues", "wed", "thurs"]
  #
  # To produce the reverse of a specific order, the following can be used:
  #
  #     ary.sort_by { ... }.reverse!
  #
  def sort_by: () { (Elem arg0) -> (Comparable | ::Array[untyped]) } -> ::Array[Elem]
             | () -> ::Enumerator[Elem, ::Array[Elem]]

  # <!--
  #   rdoc-file=enum.c
  #   - take(n) -> array
  # -->
  # For non-negative integer `n`, returns the first `n` elements:
  #
  #     r = (1..4)
  #     r.take(2) # => [1, 2]
  #     r.take(0) # => []
  #
  #     h = {foo: 0, bar: 1, baz: 2, bat: 3}
  #     h.take(2) # => [[:foo, 0], [:bar, 1]]
  #
  def take: (Integer n) -> ::Array[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - take_while {|element| ... } -> array
  #   - take_while                  -> enumerator
  # -->
  # Calls the block with successive elements as long as the block returns a truthy
  # value; returns an array of all elements up to that point:
  #
  #     (1..4).take_while{|i| i < 3 } # => [1, 2]
  #     h = {foo: 0, bar: 1, baz: 2}
  #     h.take_while{|element| key, value = *element; value < 2 }
  #     # => [[:foo, 0], [:bar, 1]]
  #
  # With no block given, returns an Enumerator.
  #
  def take_while: () { (Elem) -> boolish } -> ::Array[Elem]
                | () -> ::Enumerator[Elem, ::Array[Elem]]

  # <!--
  #   rdoc-file=enum.c
  #   - to_h(*args) -> hash
  #   - to_h(*args) {|element| ... }  -> hash
  # -->
  # When `self` consists of 2-element arrays, returns a hash each of whose entries
  # is the key-value pair formed from one of those arrays:
  #
  #     [[:foo, 0], [:bar, 1], [:baz, 2]].to_h # => {:foo=>0, :bar=>1, :baz=>2}
  #
  # When a block is given, the block is called with each element of `self`; the
  # block should return a 2-element array which becomes a key-value pair in the
  # returned hash:
  #
  #     (0..3).to_h {|i| [i, i ** 2]} # => {0=>0, 1=>1, 2=>4, 3=>9}
  #
  # Raises an exception if an element of `self` is not a 2-element array, and a
  # block is not passed.
  #
  def to_h: () -> ::Hash[untyped, untyped]
          | [T, U] () { (Elem) -> [ T, U ] } -> ::Hash[T, U]

  # <!--
  #   rdoc-file=enum.c
  #   - each_slice(n) { ... }  ->  self
  #   - each_slice(n)          ->  enumerator
  # -->
  # Calls the block with each successive disjoint `n`-tuple of elements; returns
  # `self`:
  #
  #     a = []
  #     (1..10).each_slice(3) {|tuple| a.push(tuple) }
  #     a # => [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
  #
  #     a = []
  #     h = {foo: 0, bar: 1, baz: 2, bat: 3, bam: 4}
  #     h.each_slice(2) {|tuple| a.push(tuple) }
  #     a # => [[[:foo, 0], [:bar, 1]], [[:baz, 2], [:bat, 3]], [[:bam, 4]]]
  #
  # With no block given, returns an Enumerator.
  #
  def each_slice: (Integer n) { (::Array[Elem]) -> void } -> self
                | (Integer n) -> ::Enumerator[::Array[Elem], self]

  interface _NotFound[T]
    def call: () -> T
  end

  # <!--
  #   rdoc-file=enum.c
  #   - find(if_none_proc = nil) {|element| ... } -> object or nil
  #   - find(if_none_proc = nil) -> enumerator
  # -->
  # Returns the first element for which the block returns a truthy value.
  #
  # With a block given, calls the block with successive elements of the
  # collection; returns the first element for which the block returns a truthy
  # value:
  #
  #     (0..9).find {|element| element > 2}                # => 3
  #
  # If no such element is found, calls `if_none_proc` and returns its return
  # value.
  #
  #     (0..9).find(proc {false}) {|element| element > 12} # => false
  #     {foo: 0, bar: 1, baz: 2}.find {|key, value| key.start_with?('b') }            # => [:bar, 1]
  #     {foo: 0, bar: 1, baz: 2}.find(proc {[]}) {|key, value| key.start_with?('c') } # => []
  #
  # With no block given, returns an Enumerator.
  #
  def find: () { (Elem) -> boolish } -> Elem?
          | () -> ::Enumerator[Elem, Elem?]
          | [T] (_NotFound[T] ifnone) { (Elem) -> boolish } -> (Elem | T)
          | [T] (_NotFound[T] ifnone) -> ::Enumerator[Elem, Elem | T]

  # <!--
  #   rdoc-file=enum.c
  #   - flat_map {|element| ... } -> array
  #   - flat_map -> enumerator
  # -->
  # Returns an array of flattened objects returned by the block.
  #
  # With a block given, calls the block with successive elements; returns a
  # flattened array of objects returned by the block:
  #
  #     [0, 1, 2, 3].flat_map {|element| -element }                    # => [0, -1, -2, -3]
  #     [0, 1, 2, 3].flat_map {|element| [element, -element] }         # => [0, 0, 1, -1, 2, -2, 3, -3]
  #     [[0, 1], [2, 3]].flat_map {|e| e + [100] }                     # => [0, 1, 100, 2, 3, 100]
  #     {foo: 0, bar: 1, baz: 2}.flat_map {|key, value| [key, value] } # => [:foo, 0, :bar, 1, :baz, 2]
  #
  # With no block given, returns an Enumerator.
  #
  # Alias: #collect_concat.
  #
  def flat_map: [U] () { (Elem) -> (Array[U] | U) } -> Array[U]
              | () -> ::Enumerator[Elem, Array[untyped]]

  # <!-- rdoc-file=enum.c -->
  # Returns an array of objects returned by the block.
  #
  # With a block given, calls the block with successive elements; returns an array
  # of the objects returned by the block:
  #
  #     (0..4).map {|i| i*i }                               # => [0, 1, 4, 9, 16]
  #     {foo: 0, bar: 1, baz: 2}.map {|key, value| value*2} # => [0, 2, 4]
  #
  # With no block given, returns an Enumerator.
  #
  def map: [U] () { (Elem arg0) -> U } -> ::Array[U]
         | () -> ::Enumerator[Elem, ::Array[untyped]]

  # <!--
  #   rdoc-file=enum.c
  #   - include?(object) -> true or false
  # -->
  # Returns whether for any element `object == element`:
  #
  #     (1..4).include?(2)                       # => true
  #     (1..4).include?(5)                       # => false
  #     (1..4).include?('2')                     # => false
  #     %w[a b c d].include?('b')                # => true
  #     %w[a b c d].include?('2')                # => false
  #     {foo: 0, bar: 1, baz: 2}.include?(:foo)  # => true
  #     {foo: 0, bar: 1, baz: 2}.include?('foo') # => false
  #     {foo: 0, bar: 1, baz: 2}.include?(0)     # => false
  #
  def member?: (Elem arg0) -> bool

  # <!-- rdoc-file=enum.c -->
  # Returns an object formed from operands via either:
  #
  # *   A method named by `symbol`.
  # *   A block to which each operand is passed.
  #
  #
  # With method-name argument `symbol`, combines operands using the method:
  #
  #     # Sum, without initial_operand.
  #     (1..4).inject(:+)     # => 10
  #     # Sum, with initial_operand.
  #     (1..4).inject(10, :+) # => 20
  #
  # With a block, passes each operand to the block:
  #
  #     # Sum of squares, without initial_operand.
  #     (1..4).inject {|sum, n| sum + n*n }    # => 30
  #     # Sum of squares, with initial_operand.
  #     (1..4).inject(2) {|sum, n| sum + n*n } # => 32
  #
  # **Operands**
  #
  # If argument `initial_operand` is not given, the operands for `inject` are
  # simply the elements of `self`. Example calls and their operands:
  #
  #     `(1..4).inject(:+)`
  # :       `[1, 2, 3, 4]`.
  #
  #     `(1...4).inject(:+)`
  # :       `[1, 2, 3]`.
  #
  #     `('a'..'d').inject(:+)`
  # :       `['a', 'b', 'c', 'd']`.
  #
  #     `('a'...'d').inject(:+)`
  # :       `['a', 'b', 'c']`.
  #
  #
  #
  # Examples with first operand (which is `self.first`) of various types:
  #
  #     # Integer.
  #     (1..4).inject(:+)                # => 10
  #     # Float.
  #     [1.0, 2, 3, 4].inject(:+)        # => 10.0
  #     # Character.
  #     ('a'..'d').inject(:+)            # => "abcd"
  #     # Complex.
  #     [Complex(1, 2), 3, 4].inject(:+) # => (8+2i)
  #
  # If argument `initial_operand` is given, the operands for `inject` are that
  # value plus the elements of `self`. Example calls their operands:
  #
  #     `(1..4).inject(10, :+)`
  # :       `[10, 1, 2, 3, 4]`.
  #
  #     `(1...4).inject(10, :+)`
  # :       `[10, 1, 2, 3]`.
  #
  #     `('a'..'d').inject('e', :+)`
  # :       `['e', 'a', 'b', 'c', 'd']`.
  #
  #     `('a'...'d').inject('e', :+)`
  # :       `['e', 'a', 'b', 'c']`.
  #
  #
  #
  # Examples with `initial_operand` of various types:
  #
  #     # Integer.
  #     (1..4).inject(2, :+)               # => 12
  #     # Float.
  #     (1..4).inject(2.0, :+)             # => 12.0
  #     # String.
  #     ('a'..'d').inject('foo', :+)       # => "fooabcd"
  #     # Array.
  #     %w[a b c].inject(['x'], :push)     # => ["x", "a", "b", "c"]
  #     # Complex.
  #     (1..4).inject(Complex(2, 2), :+)   # => (12+2i)
  #
  # **Combination by Given \Method**
  #
  # If the method-name argument `symbol` is given, the operands are combined by
  # that method:
  #
  # *   The first and second operands are combined.
  # *   That result is combined with the third operand.
  # *   That result is combined with the fourth operand.
  # *   And so on.
  #
  #
  # The return value from `inject` is the result of the last combination.
  #
  # This call to `inject` computes the sum of the operands:
  #
  #     (1..4).inject(:+) # => 10
  #
  # Examples with various methods:
  #
  #     # Integer addition.
  #     (1..4).inject(:+)                # => 10
  #     # Integer multiplication.
  #     (1..4).inject(:*)                # => 24
  #     # Character range concatenation.
  #     ('a'..'d').inject('', :+)        # => "abcd"
  #     # String array concatenation.
  #     %w[foo bar baz].inject('', :+)   # => "foobarbaz"
  #     # Hash update.
  #     h = [{foo: 0, bar: 1}, {baz: 2}, {bat: 3}].inject(:update)
  #     h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
  #     # Hash conversion to nested arrays.
  #     h = {foo: 0, bar: 1}.inject([], :push)
  #     h # => [[:foo, 0], [:bar, 1]]
  #
  # **Combination by Given Block**
  #
  # If a block is given, the operands are passed to the block:
  #
  # *   The first call passes the first and second operands.
  # *   The second call passes the result of the first call, along with the third
  #     operand.
  # *   The third call passes the result of the second call, along with the fourth
  #     operand.
  # *   And so on.
  #
  #
  # The return value from `inject` is the return value from the last block call.
  #
  # This call to `inject` gives a block that writes the memo and element, and also
  # sums the elements:
  #
  #     (1..4).inject do |memo, element|
  #       p "Memo: #{memo}; element: #{element}"
  #       memo + element
  #     end # => 10
  #
  # Output:
  #
  #     "Memo: 1; element: 2"
  #     "Memo: 3; element: 3"
  #     "Memo: 6; element: 4"
  #
  alias reduce inject

  # <!--
  #   rdoc-file=enum.c
  #   - to_a(*args) -> array
  # -->
  # Returns an array containing the items in `self`:
  #
  #     (0..4).to_a # => [0, 1, 2, 3, 4]
  #
  def to_a: () -> ::Array[Elem]

  # <!--
  #   rdoc-file=enumerator.c
  #   - e.lazy -> lazy_enumerator
  # -->
  # Returns an Enumerator::Lazy, which redefines most Enumerable methods to
  # postpone enumeration and enumerate values only on an as-needed basis.
  #
  # ### Example
  #
  # The following program finds pythagorean triples:
  #
  #     def pythagorean_triples
  #       (1..Float::INFINITY).lazy.flat_map {|z|
  #         (1..z).flat_map {|x|
  #           (x..z).select {|y|
  #             x**2 + y**2 == z**2
  #           }.map {|y|
  #             [x, y, z]
  #           }
  #         }
  #       }
  #     end
  #     # show first ten pythagorean triples
  #     p pythagorean_triples.take(10).force # take is lazy, so force is needed
  #     p pythagorean_triples.first(10)      # first is eager
  #     # show pythagorean triples less than 100
  #     p pythagorean_triples.take_while { |*, z| z < 100 }.force
  #
  def lazy: () -> Enumerator::Lazy[Elem, void]

  # <!--
  #   rdoc-file=enum.c
  #   - uniq                  -> array
  #   - uniq {|element| ... } -> array
  # -->
  # With no block, returns a new array containing only unique elements; the array
  # has no two elements `e0` and `e1` such that `e0.eql?(e1)`:
  #
  #     %w[a b c c b a a b c].uniq       # => ["a", "b", "c"]
  #     [0, 1, 2, 2, 1, 0, 0, 1, 2].uniq # => [0, 1, 2]
  #
  # With a block, returns a new array containing elements only for which the block
  # returns a unique value:
  #
  #     a = [0, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1]
  #     a.uniq {|i| i.even? ? i : 0 } # => [0, 2, 4]
  #     a = %w[a b c d e e d c b a a b c d e]
  #     a.uniq {|c| c < 'c' }         # => ["a", "c"]
  #
  def uniq: () -> ::Array[Elem]
          | () { (Elem item) -> untyped } -> ::Array[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - sum(initial_value = 0)                  -> number
  #   - sum(initial_value = 0) {|element| ... } -> object
  # -->
  # With no block given, returns the sum of `initial_value` and the elements:
  #
  #     (1..100).sum          # => 5050
  #     (1..100).sum(1)       # => 5051
  #     ('a'..'d').sum('foo') # => "fooabcd"
  #
  # Generally, the sum is computed using methods `+` and `each`; for performance
  # optimizations, those methods may not be used, and so any redefinition of those
  # methods may not have effect here.
  #
  # One such optimization: When possible, computes using Gauss's summation formula
  # *n(n+1)/2*:
  #
  #     100 * (100 + 1) / 2 # => 5050
  #
  # With a block given, calls the block with each element; returns the sum of
  # `initial_value` and the block return values:
  #
  #     (1..4).sum {|i| i*i }                        # => 30
  #     (1..4).sum(100) {|i| i*i }                   # => 130
  #     h = {a: 0, b: 1, c: 2, d: 3, e: 4, f: 5}
  #     h.sum {|key, value| value.odd? ? value : 0 } # => 9
  #     ('a'..'f').sum('x') {|c| c < 'd' ? c : '' }  # => "xabc"
  #
  def sum: () -> (Elem | Integer)
         | [T] () { (Elem arg0) -> T } -> (Integer | T)
         | [T] (?T arg0) -> (Elem | T)
         | [U] (?U arg0) { (Elem arg0) -> U } -> U

  # <!--
  #   rdoc-file=enum.c
  #   - filter_map {|element| ... } -> array
  #   - filter_map -> enumerator
  # -->
  # Returns an array containing truthy elements returned by the block.
  #
  # With a block given, calls the block with successive elements; returns an array
  # containing each truthy value returned by the block:
  #
  #     (0..9).filter_map {|i| i * 2 if i.even? }                              # => [0, 4, 8, 12, 16]
  #     {foo: 0, bar: 1, baz: 2}.filter_map {|key, value| key if value.even? } # => [:foo, :baz]
  #
  # When no block given, returns an Enumerator.
  #
  def filter_map: [U] () { (Elem elem) -> (nil | false | U) } -> ::Array[U]
                | () -> ::Enumerator[Elem, ::Array[untyped]]

  # <!--
  #   rdoc-file=enumerator.c
  #   - e.chain(*enums) -> enumerator
  # -->
  # Returns an enumerator object generated from this enumerator and given
  # enumerables.
  #
  #     e = (1..3).chain([4, 5])
  #     e.to_a #=> [1, 2, 3, 4, 5]
  #
  def chain: (*self enumerables) -> ::Enumerator::Chain[Elem]

  # <!--
  #   rdoc-file=enum.c
  #   - tally -> new_hash
  #   - tally(hash) -> hash
  # -->
  # Returns a hash containing the counts of equal elements:
  #
  # *   Each key is an element of `self`.
  # *   Each value is the number elements equal to that key.
  #
  #
  # With no argument:
  #
  #     %w[a b c b c a c b].tally # => {"a"=>2, "b"=>3, "c"=>3}
  #
  # With a hash argument, that hash is used for the tally (instead of a new hash),
  # and is returned; this may be useful for accumulating tallies across multiple
  # enumerables:
  #
  #     hash = {}
  #     hash = %w[a c d b c a].tally(hash)
  #     hash # => {"a"=>2, "c"=>2, "d"=>1, "b"=>1}
  #     hash = %w[b a z].tally(hash)
  #     hash # => {"a"=>3, "c"=>2, "d"=>1, "b"=>2, "z"=>1}
  #     hash = %w[b a m].tally(hash)
  #     hash # => {"a"=>4, "c"=>2, "d"=>1, "b"=>3, "z"=>1, "m"=> 1}
  #
  def tally: (?Hash[Elem, Integer] hash) -> ::Hash[Elem, Integer]

  # <!--
  #   rdoc-file=enum.c
  #   - each_entry(*args) {|element| ... } -> self
  #   - each_entry(*args)                  -> enumerator
  # -->
  # Calls the given block with each element, converting multiple values from yield
  # to an array; returns `self`:
  #
  #     a = []
  #     (1..4).each_entry {|element| a.push(element) } # => 1..4
  #     a # => [1, 2, 3, 4]
  #
  #     a = []
  #     h = {foo: 0, bar: 1, baz:2}
  #     h.each_entry {|element| a.push(element) }
  #     # => {:foo=>0, :bar=>1, :baz=>2}
  #     a # => [[:foo, 0], [:bar, 1], [:baz, 2]]
  #
  #     class Foo
  #       include Enumerable
  #       def each
  #         yield 1
  #         yield 1, 2
  #         yield
  #       end
  #     end
  #     Foo.new.each_entry {|yielded| p yielded }
  #
  # Output:
  #
  #     1
  #     [1, 2]
  #     nil
  #
  # With no block given, returns an Enumerator.
  #
  def each_entry: () -> ::Enumerator[Elem, self]
                | () { (Elem arg0) -> untyped } -> self

  # <!--
  #   rdoc-file=enum.c
  #   - zip(*other_enums) -> array
  #   - zip(*other_enums) {|array| ... } -> nil
  # -->
  # With no block given, returns a new array `new_array` of size self.size whose
  # elements are arrays. Each nested array `new_array[n]` is of size
  # `other_enums.size+1`, and contains:
  #
  # *   The `n`-th element of self.
  # *   The `n`-th element of each of the `other_enums`.
  #
  #
  # If all `other_enums` and self are the same size, all elements are included in
  # the result, and there is no `nil`-filling:
  #
  #     a = [:a0, :a1, :a2, :a3]
  #     b = [:b0, :b1, :b2, :b3]
  #     c = [:c0, :c1, :c2, :c3]
  #     d = a.zip(b, c)
  #     d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
  #
  #     f = {foo: 0, bar: 1, baz: 2}
  #     g = {goo: 3, gar: 4, gaz: 5}
  #     h = {hoo: 6, har: 7, haz: 8}
  #     d = f.zip(g, h)
  #     d # => [
  #       #      [[:foo, 0], [:goo, 3], [:hoo, 6]],
  #       #      [[:bar, 1], [:gar, 4], [:har, 7]],
  #       #      [[:baz, 2], [:gaz, 5], [:haz, 8]]
  #       #    ]
  #
  # If any enumerable in other_enums is smaller than self, fills to `self.size`
  # with `nil`:
  #
  #     a = [:a0, :a1, :a2, :a3]
  #     b = [:b0, :b1, :b2]
  #     c = [:c0, :c1]
  #     d = a.zip(b, c)
  #     d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, nil], [:a3, nil, nil]]
  #
  # If any enumerable in other_enums is larger than self, its trailing elements
  # are ignored:
  #
  #     a = [:a0, :a1, :a2, :a3]
  #     b = [:b0, :b1, :b2, :b3, :b4]
  #     c = [:c0, :c1, :c2, :c3, :c4, :c5]
  #     d = a.zip(b, c)
  #     d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
  #
  # When a block is given, calls the block with each of the sub-arrays (formed as
  # above); returns nil:
  #
  #     a = [:a0, :a1, :a2, :a3]
  #     b = [:b0, :b1, :b2, :b3]
  #     c = [:c0, :c1, :c2, :c3]
  #     a.zip(b, c) {|sub_array| p sub_array} # => nil
  #
  # Output:
  #
  #     [:a0, :b0, :c0]
  #     [:a1, :b1, :c1]
  #     [:a2, :b2, :c2]
  #     [:a3, :b3, :c3]
  #
  def zip: [Elem2] (_Each[Elem2] enum) -> Array[[ Elem, Elem2? ]]
         | (_Each[untyped], *_Each[untyped]) -> Array[Array[untyped]]
         | [Elem2] (_Each[Elem2]) { ([ Elem, Elem2? ]) -> void } -> nil
         | (_Each[untyped], *_Each[untyped]) { (Array[untyped]) -> void } -> nil

  # <!--
  #   rdoc-file=enum.c
  #   - chunk {|array| ... } -> enumerator
  # -->
  # Each element in the returned enumerator is a 2-element array consisting of:
  #
  # *   A value returned by the block.
  # *   An array ("chunk") containing the element for which that value was
  #     returned, and all following elements for which the block returned the same
  #     value:
  #
  #
  # So that:
  #
  # *   Each block return value that is different from its predecessor begins a
  #     new chunk.
  # *   Each block return value that is the same as its predecessor continues the
  #     same chunk.
  #
  #
  # Example:
  #
  #     e = (0..10).chunk {|i| (i / 3).floor } # => #<Enumerator: ...>
  #     # The enumerator elements.
  #     e.next # => [0, [0, 1, 2]]
  #     e.next # => [1, [3, 4, 5]]
  #     e.next # => [2, [6, 7, 8]]
  #     e.next # => [3, [9, 10]]
  #
  # Method `chunk` is especially useful for an enumerable that is already sorted.
  # This example counts words for each initial letter in a large array of words:
  #
  #     # Get sorted words from a web page.
  #     url = 'https://raw.githubusercontent.com/eneko/data-repository/master/data/words.txt'
  #     words = URI::open(url).readlines
  #     # Make chunks, one for each letter.
  #     e = words.chunk {|word| word.upcase[0] } # => #<Enumerator: ...>
  #     # Display 'A' through 'F'.
  #     e.each {|c, words| p [c, words.length]; break if c == 'F' }
  #
  # Output:
  #
  #     ["A", 17096]
  #     ["B", 11070]
  #     ["C", 19901]
  #     ["D", 10896]
  #     ["E", 8736]
  #     ["F", 6860]
  #
  # You can use the special symbol `:_alone` to force an element into its own
  # separate chuck:
  #
  #     a = [0, 0, 1, 1]
  #     e = a.chunk{|i| i.even? ? :_alone : true }
  #     e.to_a # => [[:_alone, [0]], [:_alone, [0]], [true, [1, 1]]]
  #
  # For example, you can put each line that contains a URL into its own chunk:
  #
  #     pattern = /http/
  #     open(filename) { |f|
  #       f.chunk { |line| line =~ pattern ? :_alone : true }.each { |key, lines|
  #         pp lines
  #       }
  #     }
  #
  # You can use the special symbol `:_separator` or `nil` to force an element to
  # be ignored (not included in any chunk):
  #
  #     a = [0, 0, -1, 1, 1]
  #     e = a.chunk{|i| i < 0 ? :_separator : true }
  #     e.to_a # => [[true, [0, 0]], [true, [1, 1]]]
  #
  # Note that the separator does end the chunk:
  #
  #     a = [0, 0, -1, 1, -1, 1]
  #     e = a.chunk{|i| i < 0 ? :_separator : true }
  #     e.to_a # => [[true, [0, 0]], [true, [1]], [true, [1]]]
  #
  # For example, the sequence of hyphens in svn log can be eliminated as follows:
  #
  #     sep = "-"*72 + "\n"
  #     IO.popen("svn log README") { |f|
  #       f.chunk { |line|
  #         line != sep || nil
  #       }.each { |_, lines|
  #         pp lines
  #       }
  #     }
  #     #=> ["r20018 | knu | 2008-10-29 13:20:42 +0900 (Wed, 29 Oct 2008) | 2 lines\n",
  #     #    "\n",
  #     #    "* README, README.ja: Update the portability section.\n",
  #     #    "\n"]
  #     #   ["r16725 | knu | 2008-05-31 23:34:23 +0900 (Sat, 31 May 2008) | 2 lines\n",
  #     #    "\n",
  #     #    "* README, README.ja: Add a note about default C flags.\n",
  #     #    "\n"]
  #     #   ...
  #
  # Paragraphs separated by empty lines can be parsed as follows:
  #
  #     File.foreach("README").chunk { |line|
  #       /\A\s*\z/ !~ line || nil
  #     }.each { |_, lines|
  #       pp lines
  #     }
  #
  def chunk: [U] () { (Elem elt) -> U } -> ::Enumerator[[ U, ::Array[Elem] ], void]
           | () -> ::Enumerator[Elem, ::Enumerator[[ untyped, ::Array[Elem] ], void]]

  # <!--
  #   rdoc-file=enum.c
  #   - enum.chunk_while {|elt_before, elt_after| bool } -> an_enumerator
  # -->
  # Creates an enumerator for each chunked elements. The beginnings of chunks are
  # defined by the block.
  #
  # This method splits each chunk using adjacent elements, *elt_before* and
  # *elt_after*, in the receiver enumerator. This method split chunks between
  # *elt_before* and *elt_after* where the block returns `false`.
  #
  # The block is called the length of the receiver enumerator minus one.
  #
  # The result enumerator yields the chunked elements as an array. So `each`
  # method can be called as follows:
  #
  #     enum.chunk_while { |elt_before, elt_after| bool }.each { |ary| ... }
  #
  # Other methods of the Enumerator class and Enumerable module, such as `to_a`,
  # `map`, etc., are also usable.
  #
  # For example, one-by-one increasing subsequence can be chunked as follows:
  #
  #     a = [1,2,4,9,10,11,12,15,16,19,20,21]
  #     b = a.chunk_while {|i, j| i+1 == j }
  #     p b.to_a #=> [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]]
  #     c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" }
  #     p c #=> [[1, 2], [4], "9-12", [15, 16], "19-21"]
  #     d = c.join(",")
  #     p d #=> "1,2,4,9-12,15,16,19-21"
  #
  # Increasing (non-decreasing) subsequence can be chunked as follows:
  #
  #     a = [0, 9, 2, 2, 3, 2, 7, 5, 9, 5]
  #     p a.chunk_while {|i, j| i <= j }.to_a
  #     #=> [[0, 9], [2, 2, 3], [2, 7], [5, 9], [5]]
  #
  # Adjacent evens and odds can be chunked as follows: (Enumerable#chunk is
  # another way to do it.)
  #
  #     a = [7, 5, 9, 2, 0, 7, 9, 4, 2, 0]
  #     p a.chunk_while {|i, j| i.even? == j.even? }.to_a
  #     #=> [[7, 5, 9], [2, 0], [7, 9], [4, 2, 0]]
  #
  # Enumerable#slice_when does the same, except splitting when the block returns
  # `true` instead of `false`.
  #
  def chunk_while: () { (Elem elt_before, Elem elt_after) -> boolish } -> ::Enumerator[::Array[Elem], void]

  # <!--
  #   rdoc-file=enum.c
  #   - enum.slice_when {|elt_before, elt_after| bool } -> an_enumerator
  # -->
  # Creates an enumerator for each chunked elements. The beginnings of chunks are
  # defined by the block.
  #
  # This method splits each chunk using adjacent elements, *elt_before* and
  # *elt_after*, in the receiver enumerator. This method split chunks between
  # *elt_before* and *elt_after* where the block returns `true`.
  #
  # The block is called the length of the receiver enumerator minus one.
  #
  # The result enumerator yields the chunked elements as an array. So `each`
  # method can be called as follows:
  #
  #     enum.slice_when { |elt_before, elt_after| bool }.each { |ary| ... }
  #
  # Other methods of the Enumerator class and Enumerable module, such as `to_a`,
  # `map`, etc., are also usable.
  #
  # For example, one-by-one increasing subsequence can be chunked as follows:
  #
  #     a = [1,2,4,9,10,11,12,15,16,19,20,21]
  #     b = a.slice_when {|i, j| i+1 != j }
  #     p b.to_a #=> [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]]
  #     c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" }
  #     p c #=> [[1, 2], [4], "9-12", [15, 16], "19-21"]
  #     d = c.join(",")
  #     p d #=> "1,2,4,9-12,15,16,19-21"
  #
  # Near elements (threshold: 6) in sorted array can be chunked as follows:
  #
  #     a = [3, 11, 14, 25, 28, 29, 29, 41, 55, 57]
  #     p a.slice_when {|i, j| 6 < j - i }.to_a
  #     #=> [[3], [11, 14], [25, 28, 29, 29], [41], [55, 57]]
  #
  # Increasing (non-decreasing) subsequence can be chunked as follows:
  #
  #     a = [0, 9, 2, 2, 3, 2, 7, 5, 9, 5]
  #     p a.slice_when {|i, j| i > j }.to_a
  #     #=> [[0, 9], [2, 2, 3], [2, 7], [5, 9], [5]]
  #
  # Adjacent evens and odds can be chunked as follows: (Enumerable#chunk is
  # another way to do it.)
  #
  #     a = [7, 5, 9, 2, 0, 7, 9, 4, 2, 0]
  #     p a.slice_when {|i, j| i.even? != j.even? }.to_a
  #     #=> [[7, 5, 9], [2, 0], [7, 9], [4, 2, 0]]
  #
  # Paragraphs (non-empty lines with trailing empty lines) can be chunked as
  # follows: (See Enumerable#chunk to ignore empty lines.)
  #
  #     lines = ["foo\n", "bar\n", "\n", "baz\n", "qux\n"]
  #     p lines.slice_when {|l1, l2| /\A\s*\z/ =~ l1 && /\S/ =~ l2 }.to_a
  #     #=> [["foo\n", "bar\n", "\n"], ["baz\n", "qux\n"]]
  #
  # Enumerable#chunk_while does the same, except splitting when the block returns
  # `false` instead of `true`.
  #
  def slice_when: () { (Elem elt_before, Elem elt_after) -> boolish } -> ::Enumerator[::Array[Elem], void]

  # <!--
  #   rdoc-file=enum.c
  #   - enum.slice_after(pattern)       -> an_enumerator
  #   - enum.slice_after { |elt| bool } -> an_enumerator
  # -->
  # Creates an enumerator for each chunked elements. The ends of chunks are
  # defined by *pattern* and the block.
  #
  # If *`pattern* === *elt`* returns `true` or the block returns `true` for the
  # element, the element is end of a chunk.
  #
  # The `===` and *block* is called from the first element to the last element of
  # *enum*.
  #
  # The result enumerator yields the chunked elements as an array. So `each`
  # method can be called as follows:
  #
  #     enum.slice_after(pattern).each { |ary| ... }
  #     enum.slice_after { |elt| bool }.each { |ary| ... }
  #
  # Other methods of the Enumerator class and Enumerable module, such as `map`,
  # etc., are also usable.
  #
  # For example, continuation lines (lines end with backslash) can be concatenated
  # as follows:
  #
  #     lines = ["foo\n", "bar\\\n", "baz\n", "\n", "qux\n"]
  #     e = lines.slice_after(/(?<!\\)\n\z/)
  #     p e.to_a
  #     #=> [["foo\n"], ["bar\\\n", "baz\n"], ["\n"], ["qux\n"]]
  #     p e.map {|ll| ll[0...-1].map {|l| l.sub(/\\\n\z/, "") }.join + ll.last }
  #     #=>["foo\n", "barbaz\n", "\n", "qux\n"]
  #
  def slice_after: (untyped pattern) -> ::Enumerator[::Array[Elem], void]
                 | () { (Elem elt) -> boolish } -> ::Enumerator[::Array[Elem], void]

  # <!--
  #   rdoc-file=enum.c
  #   - slice_before(pattern)       -> enumerator
  #   - slice_before {|elt| ... } -> enumerator
  # -->
  # With argument `pattern`, returns an enumerator that uses the pattern to
  # partition elements into arrays ("slices"). An element begins a new slice if
  # `element === pattern` (or if it is the first element).
  #
  #     a = %w[foo bar fop for baz fob fog bam foy]
  #     e = a.slice_before(/ba/) # => #<Enumerator: ...>
  #     e.each {|array| p array }
  #
  # Output:
  #
  #     ["foo"]
  #     ["bar", "fop", "for"]
  #     ["baz", "fob", "fog"]
  #     ["bam", "foy"]
  #
  # With a block, returns an enumerator that uses the block to partition elements
  # into arrays. An element begins a new slice if its block return is a truthy
  # value (or if it is the first element):
  #
  #     e = (1..20).slice_before {|i| i % 4 == 2 } # => #<Enumerator: ...>
  #     e.each {|array| p array }
  #
  # Output:
  #
  #     [1]
  #     [2, 3, 4, 5]
  #     [6, 7, 8, 9]
  #     [10, 11, 12, 13]
  #     [14, 15, 16, 17]
  #     [18, 19, 20]
  #
  # Other methods of the Enumerator class and Enumerable module, such as `to_a`,
  # `map`, etc., are also usable.
  #
  # For example, iteration over ChangeLog entries can be implemented as follows:
  #
  #     # iterate over ChangeLog entries.
  #     open("ChangeLog") { |f|
  #       f.slice_before(/\A\S/).each { |e| pp e }
  #     }
  #
  #     # same as above.  block is used instead of pattern argument.
  #     open("ChangeLog") { |f|
  #       f.slice_before { |line| /\A\S/ === line }.each { |e| pp e }
  #     }
  #
  # "svn proplist -R" produces multiline output for each file. They can be chunked
  # as follows:
  #
  #     IO.popen([{"LC_ALL"=>"C"}, "svn", "proplist", "-R"]) { |f|
  #       f.lines.slice_before(/\AProp/).each { |lines| p lines }
  #     }
  #     #=> ["Properties on '.':\n", "  svn:ignore\n", "  svk:merge\n"]
  #     #   ["Properties on 'goruby.c':\n", "  svn:eol-style\n"]
  #     #   ["Properties on 'complex.c':\n", "  svn:mime-type\n", "  svn:eol-style\n"]
  #     #   ["Properties on 'regparse.c':\n", "  svn:eol-style\n"]
  #     #   ...
  #
  # If the block needs to maintain state over multiple elements, local variables
  # can be used. For example, three or more consecutive increasing numbers can be
  # squashed as follows (see `chunk_while` for a better way):
  #
  #     a = [0, 2, 3, 4, 6, 7, 9]
  #     prev = a[0]
  #     p a.slice_before { |e|
  #       prev, prev2 = e, prev
  #       prev2 + 1 != e
  #     }.map { |es|
  #       es.length <= 2 ? es.join(",") : "#{es.first}-#{es.last}"
  #     }.join(",")
  #     #=> "0,2-4,6,7,9"
  #
  # However local variables should be used carefully if the result enumerator is
  # enumerated twice or more. The local variables should be initialized for each
  # enumeration. Enumerator.new can be used to do it.
  #
  #     # Word wrapping.  This assumes all characters have same width.
  #     def wordwrap(words, maxwidth)
  #       Enumerator.new {|y|
  #         # cols is initialized in Enumerator.new.
  #         cols = 0
  #         words.slice_before { |w|
  #           cols += 1 if cols != 0
  #           cols += w.length
  #           if maxwidth < cols
  #             cols = w.length
  #             true
  #           else
  #             false
  #           end
  #         }.each {|ws| y.yield ws }
  #       }
  #     end
  #     text = (1..20).to_a.join(" ")
  #     enum = wordwrap(text.split(/\s+/), 10)
  #     puts "-"*10
  #     enum.each { |ws| puts ws.join(" ") } # first enumeration.
  #     puts "-"*10
  #     enum.each { |ws| puts ws.join(" ") } # second enumeration generates same result as the first.
  #     puts "-"*10
  #     #=> ----------
  #     #   1 2 3 4 5
  #     #   6 7 8 9 10
  #     #   11 12 13
  #     #   14 15 16
  #     #   17 18 19
  #     #   20
  #     #   ----------
  #     #   1 2 3 4 5
  #     #   6 7 8 9 10
  #     #   11 12 13
  #     #   14 15 16
  #     #   17 18 19
  #     #   20
  #     #   ----------
  #
  # mbox contains series of mails which start with Unix From line. So each mail
  # can be extracted by slice before Unix From line.
  #
  #     # parse mbox
  #     open("mbox") { |f|
  #       f.slice_before { |line|
  #         line.start_with? "From "
  #       }.each { |mail|
  #         unix_from = mail.shift
  #         i = mail.index("\n")
  #         header = mail[0...i]
  #         body = mail[(i+1)..-1]
  #         body.pop if body.last == "\n"
  #         fields = header.slice_before { |line| !" \t".include?(line[0]) }.to_a
  #         p unix_from
  #         pp fields
  #         pp body
  #       }
  #     }
  #
  #     # split mails in mbox (slice before Unix From line after an empty line)
  #     open("mbox") { |f|
  #       emp = true
  #       f.slice_before { |line|
  #         prevemp = emp
  #         emp = line == "\n"
  #         prevemp && line.start_with?("From ")
  #       }.each { |mail|
  #         mail.pop if mail.last == "\n"
  #         pp mail
  #       }
  #     }
  #
  def slice_before: (untyped pattern) -> ::Enumerator[::Array[Elem], void]
                  | () { (Elem elt) -> boolish } -> ::Enumerator[::Array[Elem], void]
end
