# <!-- rdoc-file=struct.c -->
# Class Struct provides a convenient way to create a simple class that can store
# and fetch values.
#
# This example creates a subclass of `Struct`, `Struct::Customer`; the first
# argument, a string, is the name of the subclass; the other arguments, symbols,
# determine the *members* of the new subclass.
#
#     Customer = Struct.new('Customer', :name, :address, :zip)
#     Customer.name       # => "Struct::Customer"
#     Customer.class      # => Class
#     Customer.superclass # => Struct
#
# Corresponding to each member are two methods, a writer and a reader, that
# store and fetch values:
#
#     methods = Customer.instance_methods false
#     methods # => [:zip, :address=, :zip=, :address, :name, :name=]
#
# An instance of the subclass may be created, and its members assigned values,
# via method `::new`:
#
#     joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
#     joe # => #<struct Struct::Customer name="Joe Smith", address="123 Maple, Anytown NC", zip=12345>
#
# The member values may be managed thus:
#
#     joe.name    # => "Joe Smith"
#     joe.name = 'Joseph Smith'
#     joe.name    # => "Joseph Smith"
#
# And thus; note that member name may be expressed as either a string or a
# symbol:
#
#     joe[:name]  # => "Joseph Smith"
#     joe[:name] = 'Joseph Smith, Jr.'
#     joe['name'] # => "Joseph Smith, Jr."
#
# See Struct::new.
#
# ## What's Here
#
# First, what's elsewhere. Class Struct:
#
# *   Inherits from [class
#     Object](Object.html#class-Object-label-What-27s+Here).
# *   Includes [module
#     Enumerable](Enumerable.html#module-Enumerable-label-What-27s+Here), which
#     provides dozens of additional methods.
#
#
# Here, class Struct provides methods that are useful for:
#
# *   [Creating a Struct
#     Subclass](#class-Struct-label-Methods+for+Creating+a+Struct+Subclass)
# *   [Querying](#class-Struct-label-Methods+for+Querying)
# *   [Comparing](#class-Struct-label-Methods+for+Comparing)
# *   [Fetching](#class-Struct-label-Methods+for+Fetching)
# *   [Assigning](#class-Struct-label-Methods+for+Assigning)
# *   [Iterating](#class-Struct-label-Methods+for+Iterating)
# *   [Converting](#class-Struct-label-Methods+for+Converting)
#
#
# ### Methods for Creating a Struct Subclass
#
# ::new
# :   Returns a new subclass of Struct.
#
#
# ### Methods for Querying
#
# #hash
# :   Returns the integer hash code.
# #length, #size
# :   Returns the number of members.
#
#
# ### Methods for Comparing
#
# [#==](#method-i-3D-3D)
# :   Returns whether a given object is equal to `self`, using `==` to compare
#     member values.
# #eql?
# :   Returns whether a given object is equal to `self`, using `eql?` to compare
#     member values.
#
#
# ### Methods for Fetching
#
# #[]
# :   Returns the value associated with a given member name.
# #to_a, #values, #deconstruct
# :   Returns the member values in `self` as an array.
# #deconstruct_keys
# :   Returns a hash of the name/value pairs for given member names.
# #dig
# :   Returns the object in nested objects that is specified by a given member
#     name and additional arguments.
# #members
# :   Returns an array of the member names.
# #select, #filter
# :   Returns an array of member values from `self`, as selected by the given
#     block.
# #values_at
# :   Returns an array containing values for given member names.
#
#
# ### Methods for Assigning
#
# #[]=
# :   Assigns a given value to a given member name.
#
#
# ### Methods for Iterating
#
# #each
# :   Calls a given block with each member name.
# #each_pair
# :   Calls a given block with each member name/value pair.
#
#
# ### Methods for Converting
#
# #inspect, #to_s
# :   Returns a string representation of `self`.
# #to_h
# :   Returns a hash of the member name/value pairs in `self`.
#
class Struct[Elem] < Object
  include Enumerable[Elem?]

  type attribute_name = Symbol | String

  # <!--
  #   rdoc-file=struct.c
  #   - Struct.new(*member_names, keyword_init: false){|Struct_subclass| ... } -> Struct_subclass
  #   - Struct.new(class_name, *member_names, keyword_init: false){|Struct_subclass| ... } -> Struct_subclass
  #   - Struct_subclass.new(*member_names) -> Struct_subclass_instance
  #   - Struct_subclass.new(**member_names) -> Struct_subclass_instance
  # -->
  # `Struct.new` returns a new subclass of `Struct`.  The new subclass:
  #
  # *   May be anonymous, or may have the name given by `class_name`.
  # *   May have members as given by `member_names`.
  # *   May have initialization via ordinary arguments (the default) or via
  #     keyword arguments (if `keyword_init: true` is given).
  #
  #
  # The new subclass has its own method `::new`; thus:
  #
  #     Foo = Struct.new('Foo', :foo, :bar) # => Struct::Foo
  #     f = Foo.new(0, 1)                   # => #<struct Struct::Foo foo=0, bar=1>
  #
  # **\Class Name**
  #
  # With string argument `class_name`, returns a new subclass of `Struct` named
  # `Struct::*class_name`*:
  #
  #     Foo = Struct.new('Foo', :foo, :bar) # => Struct::Foo
  #     Foo.name                            # => "Struct::Foo"
  #     Foo.superclass                      # => Struct
  #
  # Without string argument `class_name`, returns a new anonymous subclass of
  # `Struct`:
  #
  #     Struct.new(:foo, :bar).name # => nil
  #
  # **Block**
  #
  # With a block given, the created subclass is yielded to the block:
  #
  #     Customer = Struct.new('Customer', :name, :address) do |new_class|
  #       p "The new subclass is #{new_class}"
  #       def greeting
  #         "Hello #{name} at #{address}"
  #       end
  #     end           # => Struct::Customer
  #     dave = Customer.new('Dave', '123 Main')
  #     dave # =>     #<struct Struct::Customer name="Dave", address="123 Main">
  #     dave.greeting # => "Hello Dave at 123 Main"
  #
  # Output, from `Struct.new`:
  #
  #     "The new subclass is Struct::Customer"
  #
  # **Member Names**
  #
  # Symbol arguments `member_names` determines the members of the new subclass:
  #
  #     Struct.new(:foo, :bar).members        # => [:foo, :bar]
  #     Struct.new('Foo', :foo, :bar).members # => [:foo, :bar]
  #
  # The new subclass has instance methods corresponding to `member_names`:
  #
  #     Foo = Struct.new('Foo', :foo, :bar)
  #     Foo.instance_methods(false) # => [:foo, :bar, :foo=, :bar=]
  #     f = Foo.new                 # => #<struct Struct::Foo foo=nil, bar=nil>
  #     f.foo                       # => nil
  #     f.foo = 0                   # => 0
  #     f.bar                       # => nil
  #     f.bar = 1                   # => 1
  #     f                           # => #<struct Struct::Foo foo=0, bar=1>
  #
  # **Singleton Methods**
  #
  # A subclass returned by Struct.new has these singleton methods:
  #
  # *   Method `::new ` creates an instance of the subclass:
  #
  #         Foo.new          # => #<struct Struct::Foo foo=nil, bar=nil>
  #         Foo.new(0)       # => #<struct Struct::Foo foo=0, bar=nil>
  #         Foo.new(0, 1)    # => #<struct Struct::Foo foo=0, bar=1>
  #         Foo.new(0, 1, 2) # Raises ArgumentError: struct size differs
  #
  #     Method `::[]` is an alias for method `::new`.
  #
  # *   Method `:inspect` returns a string representation of the subclass:
  #
  #         Foo.inspect
  #         # => "Struct::Foo"
  #
  # *   Method `::members` returns an array of the member names:
  #
  #         Foo.members # => [:foo, :bar]
  #
  #
  # **Keyword Argument**
  #
  # By default, the arguments for initializing an instance of the new subclass are
  # ordinary arguments (not keyword arguments). With optional keyword argument
  # `keyword_init: true`, the new subclass is initialized with keyword arguments:
  #
  #     # Without keyword_init: true.
  #     Foo = Struct.new('Foo', :foo, :bar)
  #     Foo                     # => Struct::Foo
  #     Foo.new(0, 1)           # => #<struct Struct::Foo foo=0, bar=1>
  #     # With keyword_init: true.
  #     Bar = Struct.new(:foo, :bar, keyword_init: true)
  #     Bar # =>                # => Bar(keyword_init: true)
  #     Bar.new(bar: 1, foo: 0) # => #<struct Bar foo=0, bar=1>
  #
  def initialize: (attribute_name, *attribute_name, ?keyword_init: boolish) ?{ () -> void } -> void

  # <!--
  #   rdoc-file=struct.c
  #   - each {|value| ... } -> self
  #   - each -> enumerator
  # -->
  # Calls the given block with the value of each member; returns `self`:
  #
  #     Customer = Struct.new(:name, :address, :zip)
  #     joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
  #     joe.each {|value| p value }
  #
  # Output:
  #
  #     "Joe Smith"
  #     "123 Maple, Anytown NC"
  #     12345
  #
  # Returns an Enumerator if no block is given.
  #
  # Related: #each_pair.
  #
  def each: () -> ::Enumerator[Elem?, self]
          | () { (Elem? item) -> void } -> self

  # <!--
  #   rdoc-file=struct.c
  #   - StructClass::members -> array_of_symbols
  # -->
  # Returns the member names of the Struct descendant as an array:
  #
  #     Customer = Struct.new(:name, :address, :zip)
  #     Customer.members # => [:name, :address, :zip]
  #
  def self.members: () -> ::Array[Symbol]

  # <!--
  #   rdoc-file=struct.c
  #   - StructClass::keyword_init? -> true or falsy value
  # -->
  # Returns `true` if the class was initialized with `keyword_init: true`.
  # Otherwise returns `nil` or `false`.
  #
  # Examples:
  #     Foo = Struct.new(:a)
  #     Foo.keyword_init? # => nil
  #     Bar = Struct.new(:a, keyword_init: true)
  #     Bar.keyword_init? # => true
  #     Baz = Struct.new(:a, keyword_init: false)
  #     Baz.keyword_init? # => false
  #
  def self.keyword_init?: () -> (true | false | nil)
end
