Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Data (and struct) syntax #2061

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/process.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -2236,7 +2236,7 @@ end
# <!-- rdoc-file=process.c -->
# Placeholder for rusage
#
class Process::Tms < Struct[Float]
class Process::Tms < Struct{utime: Float, stime: Float, cutime: Float, cstime: Float}
end

class Process::Waiter < Thread
Expand Down
362 changes: 1 addition & 361 deletions core/struct.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,7 @@
# * #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]
include Enumerable[Elem]

class Struct
# The types that can be used when "indexing" into a `Struct` via `[]`, `[]=`, `dig`, and
# `deconstruct_keys`.
#
Expand Down Expand Up @@ -298,48 +296,6 @@ class Struct[Elem]
#
def ==: (untyped other) -> bool

# <!--
# rdoc-file=struct.c
# - eql?(other) -> true or false
# -->
# Returns `true` if and only if the following are true; otherwise returns
# `false`:
#
# * `other.class == self.class`.
# * For each member name `name`, `other.name.eql?(self.name)`.
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe_jr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe_jr.eql?(joe) # => true
# joe_jr[:name] = 'Joe Smith, Jr.'
# joe_jr.eql?(joe) # => false
#
#
# Related: Object#==.
#
def eql?: (untyped other) -> bool

# <!--
# rdoc-file=struct.c
# - hash -> integer
# -->
# Returns the integer hash value for `self`.
#
# Two structs of the same class and with the same content will have the same
# hash code (and will compare using Struct#eql?):
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe_jr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe.hash == joe_jr.hash # => true
# joe_jr[:name] = 'Joe Smith, Jr.'
# joe.hash == joe_jr.hash # => false
#
# Related: Object#hash.
#
def hash: () -> Integer

# <!--
# rdoc-file=struct.c
# - inspect -> string
Expand All @@ -360,320 +316,4 @@ class Struct[Elem]
# joe.inspect # => "#<struct Customer name=\"Joe Smith\", address=\"123 Maple, Anytown NC\", zip=12345>"
#
alias to_s inspect

# <!--
# rdoc-file=struct.c
# - to_a -> array
# -->
# Returns the values in `self` as an array:
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe.to_a # => ["Joe Smith", "123 Maple, Anytown NC", 12345]
#
# Related: #members.
#
def to_a: () -> Array[Elem]

# <!--
# rdoc-file=struct.c
# - to_h -> hash
# - to_h {|name, value| ... } -> hash
# -->
# Returns a hash containing the name and value for each member:
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# h = joe.to_h
# h # => {:name=>"Joe Smith", :address=>"123 Maple, Anytown NC", :zip=>12345}
#
# If a block is given, it is called with each name/value pair; the block should
# return a 2-element array whose elements will become a key/value pair in the
# returned hash:
#
# h = joe.to_h{|name, value| [name.upcase, value.to_s.upcase]}
# h # => {:NAME=>"JOE SMITH", :ADDRESS=>"123 MAPLE, ANYTOWN NC", :ZIP=>"12345"}
#
# Raises ArgumentError if the block returns an inappropriate value.
#
def to_h: () -> Hash[Symbol, Elem]
| [K, V] () { (Symbol key, Elem value) -> [K, V] } -> Hash[K, V]

# <!-- rdoc-file=struct.c -->
# Returns the values in `self` as an array:
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe.to_a # => ["Joe Smith", "123 Maple, Anytown NC", 12345]
#
# Related: #members.
#
alias values to_a

# <!--
# rdoc-file=struct.c
# - size -> integer
# -->
# Returns the number of members.
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe.size #=> 3
#
def size: () -> Integer

# <!-- rdoc-file=struct.c -->
# Returns the number of members.
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe.size #=> 3
#
alias length size

# <!--
# 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 value) -> void } -> self

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

# <!--
# rdoc-file=struct.c
# - struct[name] -> object
# - struct[n] -> object
# -->
# Returns a value from `self`.
#
# With symbol or string argument `name` given, returns the value for the named
# member:
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe[:zip] # => 12345
#
# Raises NameError if `name` is not the name of a member.
#
# With integer argument `n` given, returns `self.values[n]` if `n` is in range;
# see Array@Array+Indexes:
#
# joe[2] # => 12345
# joe[-2] # => "123 Maple, Anytown NC"
#
# Raises IndexError if `n` is out of range.
#
def []: (index name_or_position) -> Elem

# <!--
# rdoc-file=struct.c
# - struct[name] = value -> value
# - struct[n] = value -> value
# -->
# Assigns a value to a member.
#
# With symbol or string argument `name` given, assigns the given `value` to the
# named member; returns `value`:
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe[:zip] = 54321 # => 54321
# joe # => #<struct Customer name="Joe Smith", address="123 Maple, Anytown NC", zip=54321>
#
# Raises NameError if `name` is not the name of a member.
#
# With integer argument `n` given, assigns the given `value` to the `n`-th
# member if `n` is in range; see Array@Array+Indexes:
#
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe[2] = 54321 # => 54321
# joe[-3] = 'Joseph Smith' # => "Joseph Smith"
# joe # => #<struct Customer name="Joseph Smith", address="123 Maple, Anytown NC", zip=54321>
#
# Raises IndexError if `n` is out of range.
#
def []=: (index name_or_position, Elem value) -> Elem

# <!--
# rdoc-file=struct.c
# - select {|value| ... } -> array
# - select -> enumerator
# -->
# With a block given, returns an array of values from `self` for which the block
# returns a truthy value:
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# a = joe.select {|value| value.is_a?(String) }
# a # => ["Joe Smith", "123 Maple, Anytown NC"]
# a = joe.select {|value| value.is_a?(Integer) }
# a # => [12345]
#
# With no block given, returns an Enumerator.
#
def select: () -> Enumerator[Elem, Array[Elem]]
| () { (Elem value) -> boolish } -> Array[Elem]

# <!-- rdoc-file=struct.c -->
# With a block given, returns an array of values from `self` for which the block
# returns a truthy value:
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# a = joe.select {|value| value.is_a?(String) }
# a # => ["Joe Smith", "123 Maple, Anytown NC"]
# a = joe.select {|value| value.is_a?(Integer) }
# a # => [12345]
#
# With no block given, returns an Enumerator.
#
alias filter select

# <!--
# rdoc-file=struct.c
# - values_at(*integers) -> array
# - values_at(integer_range) -> array
# -->
# Returns an array of values from `self`.
#
# With integer arguments `integers` given, returns an array containing each
# value given by one of `integers`:
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe.values_at(0, 2) # => ["Joe Smith", 12345]
# joe.values_at(2, 0) # => [12345, "Joe Smith"]
# joe.values_at(2, 1, 0) # => [12345, "123 Maple, Anytown NC", "Joe Smith"]
# joe.values_at(0, -3) # => ["Joe Smith", "Joe Smith"]
#
# Raises IndexError if any of `integers` is out of range; see
# Array@Array+Indexes.
#
# With integer range argument `integer_range` given, returns an array containing
# each value given by the elements of the range; fills with `nil` values for
# range elements larger than the structure:
#
# joe.values_at(0..2)
# # => ["Joe Smith", "123 Maple, Anytown NC", 12345]
# joe.values_at(-3..-1)
# # => ["Joe Smith", "123 Maple, Anytown NC", 12345]
# joe.values_at(1..4) # => ["123 Maple, Anytown NC", 12345, nil, nil]
#
# Raises RangeError if any element of the range is negative and out of range;
# see Array@Array+Indexes.
#
def values_at: (*int | range[int?] positions) -> Array[Elem]

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

# <!--
# rdoc-file=struct.c
# - dig(name, *identifiers) -> object
# - dig(n, *identifiers) -> object
# -->
# Finds and returns an object among nested objects. The nested objects may be
# instances of various classes. See [Dig Methods](rdoc-ref:dig_methods.rdoc).
#
# Given symbol or string argument `name`, returns the object that is specified
# by `name` and `identifiers`:
#
# Foo = Struct.new(:a)
# f = Foo.new(Foo.new({b: [1, 2, 3]}))
# f.dig(:a) # => #<struct Foo a={:b=>[1, 2, 3]}>
# f.dig(:a, :a) # => {:b=>[1, 2, 3]}
# f.dig(:a, :a, :b) # => [1, 2, 3]
# f.dig(:a, :a, :b, 0) # => 1
# f.dig(:b, 0) # => nil
#
# Given integer argument `n`, returns the object that is specified by `n` and
# `identifiers`:
#
# f.dig(0) # => #<struct Foo a={:b=>[1, 2, 3]}>
# f.dig(0, 0) # => {:b=>[1, 2, 3]}
# f.dig(0, 0, :b) # => [1, 2, 3]
# f.dig(0, 0, :b, 0) # => 1
# f.dig(:b, 0) # => nil
#
def dig: (index name_or_position) -> Elem
| (index name_or_position, untyped, *untyped) -> untyped

# <!-- rdoc-file=struct.c -->
# Returns the values in `self` as an array:
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# joe.to_a # => ["Joe Smith", "123 Maple, Anytown NC", 12345]
#
# Related: #members.
#
alias deconstruct to_a

# <!--
# rdoc-file=struct.c
# - deconstruct_keys(array_of_names) -> hash
# -->
# Returns a hash of the name/value pairs for the given member names.
#
# Customer = Struct.new(:name, :address, :zip)
# joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
# h = joe.deconstruct_keys([:zip, :address])
# h # => {:zip=>12345, :address=>"123 Maple, Anytown NC"}
#
# Returns all names and values if `array_of_names` is `nil`:
#
# h = joe.deconstruct_keys(nil)
# h # => {:name=>"Joseph Smith, Jr.", :address=>"123 Maple, Anytown NC", :zip=>12345}
#
def deconstruct_keys: (Array[index & Hash::_Key]? indices) -> Hash[index & Hash::_Key, Elem]
end
Loading
Loading