diff --git a/.github/workflows/comments.yml b/.github/workflows/comments.yml index 36a923590..9fc2b96cc 100644 --- a/.github/workflows/comments.yml +++ b/.github/workflows/comments.yml @@ -10,13 +10,13 @@ on: jobs: comments: runs-on: "ubuntu-latest" - # env: - # RUBY_COMMIT: 1b0c46daed9186b82ab4fef1a4ab225afe582ee6 + env: + RUBY_COMMIT: v4.0.0-preview2 steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: - ruby-version: "3.4.1" + ruby-version: "4.0.0-preview2" bundler: none - name: Install dependencies run: | diff --git a/core/array.rbs b/core/array.rbs index a368c1c23..7d01d4a84 100644 --- a/core/array.rbs +++ b/core/array.rbs @@ -151,8 +151,8 @@ # # ## Example Usage # -# In addition to the methods it mixes in through the Enumerable module, the -# `Array` class has proprietary methods for accessing, searching and otherwise +# In addition to the methods it mixes in through the Enumerable module, class +# Array has proprietary methods for accessing, searching and otherwise # manipulating arrays. # # Some of the more common ones are illustrated below. @@ -200,9 +200,9 @@ # # arr.drop(3) #=> [4, 5, 6] # -# ## Obtaining Information about an `Array` +# ## Obtaining Information about an Array # -# Arrays keep track of their own length at all times. To query an array about +# An array keeps track of its own length at all times. To query an array about # the number of elements it contains, use #length, #count or #size. # # browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE'] @@ -217,7 +217,7 @@ # # browsers.include?('Konqueror') #=> false # -# ## Adding Items to Arrays +# ## Adding Items to an Array # # Items can be added to the end of an array by using either #push or #<< # @@ -238,7 +238,7 @@ # arr.insert(3, 'orange', 'pear', 'grapefruit') # #=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6] # -# ## Removing Items from an `Array` +# ## Removing Items from an Array # # The method #pop removes the last element in an array and returns it: # @@ -277,12 +277,12 @@ # arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556] # arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123] # -# ## Iterating over Arrays +# ## Iterating over an Array # -# Like all classes that include the Enumerable module, `Array` has an each +# Like all classes that include the Enumerable module, class Array has an each # method, which defines what elements should be iterated over and how. In case -# of Array's #each, all elements in the `Array` instance are yielded to the -# supplied block in sequence. +# of Array#each, all elements in `self` are yielded to the supplied block in +# sequence. # # Note that this operation leaves the array unchanged. # @@ -307,7 +307,7 @@ # arr.map! {|a| a**2} #=> [1, 4, 9, 16, 25] # arr #=> [1, 4, 9, 16, 25] # -# ## Selecting Items from an `Array` +# ## Selecting Items from an Array # # Elements can be selected from an array according to criteria defined in a # block. The selection can happen in a destructive or a non-destructive manner. @@ -340,13 +340,13 @@ # # ## What's Here # -# First, what's elsewhere. Class `Array`: +# First, what's elsewhere. Class Array: # # * Inherits from [class Object](rdoc-ref:Object@What-27s+Here). # * Includes [module Enumerable](rdoc-ref:Enumerable@What-27s+Here), which # provides dozens of additional methods. # -# Here, class `Array` provides methods that are useful for: +# Here, class Array provides methods that are useful for: # # * [Creating an Array](rdoc-ref:Array@Methods+for+Creating+an+Array) # * [Querying](rdoc-ref:Array@Methods+for+Querying) @@ -359,7 +359,7 @@ # * [Converting](rdoc-ref:Array@Methods+for+Converting) # * [And more....](rdoc-ref:Array@Other+Methods) # -# ### Methods for Creating an `Array` +# ### Methods for Creating an Array # # * ::[]: Returns a new array populated with given objects. # * ::new: Returns a new array. @@ -524,7 +524,7 @@ # return-value. # * #flatten: Returns an array that is a recursive flattening of `self`. # * #inspect (aliased as #to_s): Returns a new String containing the elements. -# * #join: Returns a newsString containing the elements joined by the field +# * #join: Returns a new String containing the elements joined by the field # separator. # * #to_a: Returns `self` or a new array containing all elements. # * #to_ary: Returns `self`. @@ -840,9 +840,8 @@ class Array[unchecked out Elem] < Object # # If `index` is out of range, returns `nil`. # - # When two Integer arguments `start` and `length` are given, returns a new - # `Array` of size `length` containing successive elements beginning at offset - # `start`: + # When two Integer arguments `start` and `length` are given, returns a new array + # of size `length` containing successive elements beginning at offset `start`: # # a = [:foo, 'bar', 2] # a[0, 2] # => [:foo, "bar"] @@ -856,7 +855,7 @@ class Array[unchecked out Elem] < Object # a[1, 3] # => ["bar", 2] # a[2, 2] # => [2] # - # If `start == self.size` and `length >= 0`, returns a new empty `Array`. + # If `start == self.size` and `length >= 0`, returns a new empty array. # # If `length` is negative, returns `nil`. # @@ -867,7 +866,7 @@ class Array[unchecked out Elem] < Object # a[0..1] # => [:foo, "bar"] # a[1..2] # => ["bar", 2] # - # Special case: If `range.start == a.size`, returns a new empty `Array`. + # Special case: If `range.start == a.size`, returns a new empty array. # # If `range.end` is negative, calculates the end index from the end: # @@ -891,7 +890,7 @@ class Array[unchecked out Elem] < Object # a[4..-1] # => nil # # When a single Enumerator::ArithmeticSequence argument `aseq` is given, returns - # an `Array` of elements corresponding to the indexes produced by the sequence. + # an array of elements corresponding to the indexes produced by the sequence. # # a = ['--', 'data1', '--', 'data2', '--', 'data3'] # a[(1..).step(2)] # => ["data1", "data2", "data3"] @@ -976,8 +975,8 @@ class Array[unchecked out Elem] < Object # a # => [:foo, "bar", "two"] # # When Integer arguments `start` and `length` are given and `object` is not an - # `Array`, removes `length - 1` elements beginning at offset `start`, and - # assigns `object` at offset `start`: + # array, removes `length - 1` elements beginning at offset `start`, and assigns + # `object` at offset `start`: # # a = [:foo, 'bar', 2] # a[0, 2] = 'foo' # => "foo" @@ -1010,7 +1009,7 @@ class Array[unchecked out Elem] < Object # a[1, 5] = 'foo' # => "foo" # a # => [:foo, "foo"] # - # When Range argument `range` is given and `object` is not an `Array`, removes + # When Range argument `range` is given and `object` is not an array, removes # `length - 1` elements beginning at offset `start`, and assigns `object` at # offset `start`: # @@ -1274,9 +1273,9 @@ class Array[unchecked out Elem] < Object # # With a block given, calls the block with each element of `self` and replaces @@ -1564,7 +1563,7 @@ class Array[unchecked out Elem] < Object # # Finds and returns the object in nested object specified by `index` and # `identifiers`; the nested objects may be instances of various classes. See @@ -1693,7 +1692,7 @@ class Array[unchecked out Elem] < Object # # Returns `true` if the count of elements in `self` is zero, `false` otherwise. # @@ -1804,10 +1803,10 @@ class Array[unchecked out Elem] < Object # # Replaces selected elements in `self`; may add elements to `self`; always # returns `self` (never a new array). @@ -2300,7 +2299,7 @@ class Array[unchecked out Elem] < Object # # Returns the new string formed by joining the converted elements of `self`; for # each element `element`: @@ -3115,7 +3114,7 @@ class Array[unchecked out Elem] < Object # # The order of the result array is unrelated to the order of `self`. # - # Returns a new empty `Array` if `self` is empty: + # Returns a new empty array if `self` is empty: # # [].sample(4) # => [] # @@ -3320,9 +3319,8 @@ class Array[unchecked out Elem] < Object # # If `index` is out of range, returns `nil`. # - # When two Integer arguments `start` and `length` are given, returns a new - # `Array` of size `length` containing successive elements beginning at offset - # `start`: + # When two Integer arguments `start` and `length` are given, returns a new array + # of size `length` containing successive elements beginning at offset `start`: # # a = [:foo, 'bar', 2] # a[0, 2] # => [:foo, "bar"] @@ -3336,7 +3334,7 @@ class Array[unchecked out Elem] < Object # a[1, 3] # => ["bar", 2] # a[2, 2] # => [2] # - # If `start == self.size` and `length >= 0`, returns a new empty `Array`. + # If `start == self.size` and `length >= 0`, returns a new empty array. # # If `length` is negative, returns `nil`. # @@ -3347,7 +3345,7 @@ class Array[unchecked out Elem] < Object # a[0..1] # => [:foo, "bar"] # a[1..2] # => ["bar", 2] # - # Special case: If `range.start == a.size`, returns a new empty `Array`. + # Special case: If `range.start == a.size`, returns a new empty array. # # If `range.end` is negative, calculates the end index from the end: # @@ -3371,7 +3369,7 @@ class Array[unchecked out Elem] < Object # a[4..-1] # => nil # # When a single Enumerator::ArithmeticSequence argument `aseq` is given, returns - # an `Array` of elements corresponding to the indexes produced by the sequence. + # an array of elements corresponding to the indexes produced by the sequence. # # a = ['--', 'data1', '--', 'data2', '--', 'data3'] # a[(1..).step(2)] # => ["data1", "data2", "data3"] @@ -3518,6 +3516,9 @@ class Array[unchecked out Elem] < Object # When the block returns zero, the order for `a` and `b` is indeterminate, and # may be unstable. # + # See an example in Numeric#nonzero? for the idiom to sort more complex + # structure. + # # Related: see [Methods for Fetching](rdoc-ref:Array@Methods+for+Fetching). # def sort: () -> ::Array[Elem] @@ -3647,7 +3648,7 @@ class Array[unchecked out Elem] < Object # rdoc-file=array.c # - to_a -> self or new_array # --> - # When `self` is an instance of `Array`, returns `self`. + # When `self` is an instance of Array, returns `self`. # # Otherwise, returns a new array containing the elements of `self`: # @@ -3663,7 +3664,7 @@ class Array[unchecked out Elem] < Object # # Returns `self`. # @@ -4008,7 +4009,7 @@ class Array[unchecked out Elem] < Object # [:c3, :b3, :a3]] # # For an **object** in **other_arrays** that is not actually an array, forms the - # the "other array" as `object.to_ary`, if defined, or as `object.each.to_a` + # "other array" as `object.to_ary`, if defined, or as `object.each.to_a` # otherwise. # # Related: see [Methods for Converting](rdoc-ref:Array@Methods+for+Converting). diff --git a/core/dir.rbs b/core/dir.rbs index c10eb9081..2dcb3a728 100644 --- a/core/dir.rbs +++ b/core/dir.rbs @@ -477,8 +477,8 @@ class Dir # # Forms an array *entry_names* of the entry names selected by the arguments. # diff --git a/core/enumerable.rbs b/core/enumerable.rbs index e0368f5c6..676c27a36 100644 --- a/core/enumerable.rbs +++ b/core/enumerable.rbs @@ -114,8 +114,8 @@ # 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. +# * #grep_v: Returns elements not selected by a given object or objects +# returned by a given block. # * #inject (aliased as #reduce): Returns the object formed by combining all # elements. # * #sum: Returns the sum of the elements, using method `+`. @@ -191,6 +191,82 @@ # usage would not make sense, and so it is not shown. Example: #tally would # find exactly one of each Hash entry. # +# ## Extended Methods +# +# A Enumerable class may define extended methods. This section describes the +# standard behavior of extension methods for reference purposes. +# +# ### #size +# +# Enumerator has a #size method. It uses the size function argument passed to +# `Enumerator.new`. +# +# e = Enumerator.new(-> { 3 }) {|y| p y; y.yield :a; y.yield :b; y.yield :c; :z } +# p e.size #=> 3 +# p e.next #=> :a +# p e.next #=> :b +# p e.next #=> :c +# begin +# e.next +# rescue StopIteration +# p $!.result #=> :z +# end +# +# The result of the size function should represent the number of iterations +# (i.e., the number of times Enumerator::Yielder#yield is called). In the above +# example, the block calls #yield three times, and the size function, +-> { 3 +# }+, returns 3 accordingly. The result of the size function can be an integer, +# `Float::INFINITY`, or `nil`. An integer means the exact number of times #yield +# will be called, as shown above. `Float::INFINITY` indicates an infinite number +# of #yield calls. `nil` means the number of #yield calls is difficult or +# impossible to determine. +# +# Many iteration methods return an Enumerator object with an appropriate size +# function if no block is given. +# +# Examples: +# +# ["a", "b", "c"].each.size #=> 3 +# {a: "x", b: "y", c: "z"}.each.size #=> 3 +# (0..20).to_a.permutation.size #=> 51090942171709440000 +# loop.size #=> Float::INFINITY +# (1..100).drop_while.size #=> nil # size depends on the block's behavior +# STDIN.each.size #=> nil # cannot be computed without consuming input +# File.open("/etc/resolv.conf").each.size #=> nil # cannot be computed without reading the file +# +# The behavior of #size for Range-based enumerators depends on the #begin +# element: +# +# * If the #begin element is an Integer, the #size method returns an Integer +# or `Float::INFINITY`. +# * If the #begin element is an object with a #succ method (other than +# Integer), #size returns `nil`. (Computing the size would require +# repeatedly calling #succ, which may be too slow.) +# * If the #begin element does not have a #succ method, #size raises a +# TypeError. +# +# Examples: +# +# (10..42).each.size #=> 33 +# (10..42.9).each.size #=> 33 (the #end element may be a non-integer numeric) +# (10..).each.size #=> Float::INFINITY +# ("a".."z").each.size #=> nil +# ("a"..).each.size #=> nil +# (1.0..9.0).each.size # raises TypeError (Float does not have #succ) +# (..10).each.size # raises TypeError (beginless range has nil as its #begin) +# +# The Enumerable module itself does not define a #size method. A class that +# includes Enumerable may define its own #size method. It is recommended that +# such a #size method be consistent with Enumerator#size. +# +# Array and Hash implement #size and return values consistent with +# Enumerator#size. IO and Dir do not define #size, which is also consistent +# because the corresponding enumerator's size function returns `nil`. +# +# However, it is not strictly required for a class's #size method to match +# Enumerator#size. For example, File#size returns the number of bytes in the +# file, not the number of lines. +# module Enumerable[unchecked out Elem] : _Each[Elem] # +# Raised when matching pattern not found. +# class NoMatchingPatternError < StandardError end +# +# Raised when matching key not found. +# class NoMatchingPatternKeyError[M, K] < NoMatchingPatternError # # If *errno* corresponds to a known system error code, constructs the # appropriate Errno class for that error, otherwise constructs a generic # SystemCallError object. The error number is subsequently available via the # #errno method. # + # If only numeric object is given, it is treated as an Integer *errno*, and + # *msg* is omitted, otherwise the first argument *msg* is used as the additional + # error message. + # + # SystemCallError.new(Errno::EPIPE::Errno) + # #=> # + # + # SystemCallError.new("foo") + # #=> # + # + # SystemCallError.new("foo", Errno::EPIPE::Errno) + # #=> # + # + # If *func* is not `nil`, it is appended to the message with "` @ `". + # + # SystemCallError.new("foo", Errno::EPIPE::Errno, "here") + # #=> # + # + # A subclass of SystemCallError can also be instantiated via the `new` method of + # the subclass. See Errno. + # def initialize: (string msg, Integer errno) -> void # # Returns the string representation of the path # - # File.path(File::NULL) #=> "/dev/null" - # File.path(Pathname.new("/tmp")) #=> "/tmp" + # File.path(File::NULL) #=> "/dev/null" + # File.path(Pathname.new("/tmp")) #=> "/tmp" + # + # If `path` is not a String: + # + # 1. If it has the `to_path` method, that method will be called to coerce to a + # String. + # + # 2. Otherwise, or if the coerced result is not a String too, the standard + # coersion using `to_str` method will take place on that object. (See also + # String.try_convert) + # + # The coerced string must satisfy the following conditions: + # + # 1. It must be in an ASCII-compatible encoding; otherwise, an + # Encoding::CompatibilityError is raised. + # + # 2. It must not contain the NUL character (`\0`); otherwise, an ArgumentError + # is raised. # def self.path: (string | _ToPath path) -> String @@ -2429,10 +2446,8 @@ class File::Stat < Object # - # File::Stat.new(file_name) -> stat - # # Create a File::Stat object for the given file name (raising an exception if # the file doesn't exist). # diff --git a/core/float.rbs b/core/float.rbs index 64f896c38..f93f16bbb 100644 --- a/core/float.rbs +++ b/core/float.rbs @@ -1094,7 +1094,7 @@ Float::MAX_EXP: Integer # Usually defaults to 2.2250738585072014e-308. # # If the platform supports denormalized numbers, there are numbers between zero -# and Float::MIN. 0.0.next_float returns the smallest positive floating point +# and Float::MIN. `0.0.next_float` returns the smallest positive floating point # number including denormalized numbers. # Float::MIN: Float diff --git a/core/gc.rbs b/core/gc.rbs index 8a4b73dbf..98217e265 100644 --- a/core/gc.rbs +++ b/core/gc.rbs @@ -160,81 +160,65 @@ module GC # - # Sets or gets information about the current GC config. + # This method is implementation-specific to CRuby. + # + # Sets or gets information about the current GC configuration. # # Configuration parameters are GC implementation-specific and may change without # notice. # - # This method can be called without parameters to retrieve the current config as - # a `Hash` with `Symbol` keys. - # - # This method can also be called with a `Hash` argument to assign values to - # valid config keys. Config keys missing from the passed `Hash` will be left - # unmodified. - # - # If a key/value pair is passed to this function that does not correspond to a - # valid config key for the GC implementation being used, no config will be - # updated, the key will be present in the returned Hash, and its value will be - # `nil`. This is to facilitate easy migration between GC implementations. - # - # In both call-seqs, the return value of `GC.config` will be a `Hash` containing - # the most recent full configuration, i.e., all keys and values defined by the - # specific GC implementation being used. In the case of a config update, the - # return value will include the new values being updated. - # - # This method is only expected to work on CRuby. + # With no argument given, returns a hash containing the configuration: # - # ### GC Implementation independent values + # GC.config + # # => {rgengc_allow_full_mark: true, implementation: "default"} # - # The `GC.config` hash can also contain keys that are global and read-only. - # These keys are not specific to any one GC library implementation and - # attempting to write to them will raise `ArgumentError`. + # With argument `hash_to_merge` given, merges that hash into the stored + # configuration hash; ignores unknown hash keys; returns the configuration hash: # - # There is currently only one global, read-only key: + # GC.config(rgengc_allow_full_mark: false) + # # => {rgengc_allow_full_mark: false, implementation: "default"} + # GC.config(foo: 'bar') + # # => {rgengc_allow_full_mark: false, implementation: "default"} # - # implementation - # : Returns a `String` containing the name of the currently loaded GC library, - # if one has been loaded using `RUBY_GC_LIBRARY`, and "default" in all other - # cases + # **All-Implementations Configuration** # + # The single read-only entry for all implementations is: # - # ### GC Implementation specific values + # * `:implementation`: the string name of the implementation; for the Ruby + # default implementation, `'default'`. # - # GC libraries are expected to document their own configuration. Valid keys for - # Ruby's default GC implementation are: + # **Implementation-Specific Configuration** # - # rgengc_allow_full_mark - # : Controls whether the GC is allowed to run a full mark (young & old - # objects). + # A GC implementation maintains its own implementation-specific configuration. # - # When `true`, GC interleaves major and minor collections. This is the - # default. GC will function as intended. + # For Ruby's default implementation the single entry is: # - # When `false`, the GC will never trigger a full marking cycle unless - # explicitly requested by user code. Instead, only a minor mark will - # run—only young objects will be marked. When the heap space is exhausted, - # new pages will be allocated immediately instead of running a full mark. + # * `:rgengc_allow_full_mark`: Controls whether the GC is allowed to run a + # full mark (young & old objects): # - # A flag will be set to notify that a full mark has been requested. This - # flag is accessible using `GC.latest_gc_info(:needs_major_by)` - # - # The user can trigger a major collection at any time using - # `GC.start(full_mark: true)` - # - # When `false`, Young to Old object promotion is disabled. For performance - # reasons, it is recommended to warm up an application using - # `Process.warmup` before setting this parameter to `false`. + # * `true` (default): GC interleaves major and minor collections. A flag + # is set to notify GC that a full mark has been requested. This flag is + # accessible via GC.latest_gc_info(:need_major_by). + # * `false`: GC does not initiate a full marking cycle unless explicitly + # directed by user code; see GC.start. Setting this parameter to `false` + # disables young-to-old promotion. For performance reasons, we + # recommended warming up the application using Process.warmup before + # setting this parameter to `false`. # def self.config: () -> Hash[Symbol, untyped] | (Hash[Symbol, untyped]) -> Hash[Symbol, untyped] # - # Returns the number of times GC has occurred since the process started. + # Returns the total number of times garbage collection has occurred: + # + # GC.count # => 385 + # GC.start + # GC.count # => 386 # def self.count: () -> Integer @@ -242,11 +226,12 @@ module GC # rdoc-file=gc.rb # - GC.disable -> true or false # --> - # Disables garbage collection, returning `true` if garbage collection was - # already disabled. + # Disables garbage collection (but GC.start remains potent): returns whether + # garbage collection was already disabled. # - # GC.disable #=> false - # GC.disable #=> true + # GC.enable + # GC.disable # => false + # GC.disable # => true # def self.disable: () -> bool @@ -254,12 +239,11 @@ module GC # rdoc-file=gc.rb # - GC.enable -> true or false # --> - # Enables garbage collection, returning `true` if garbage collection was - # previously disabled. + # Enables garbage collection; returns whether garbage collection was disabled: # - # GC.disable #=> false - # GC.enable #=> true - # GC.enable #=> false + # GC.disable + # GC.enable # => true + # GC.enable # => false # def self.enable: () -> bool @@ -267,161 +251,194 @@ module GC # rdoc-file=gc.rb # - start(full_mark: true, immediate_mark: true, immediate_sweep: true) # --> - # Initiates garbage collection, even if manually disabled. - # - # The `full_mark` keyword argument determines whether or not to perform a major - # garbage collection cycle. When set to `true`, a major garbage collection cycle - # is run, meaning all objects are marked. When set to `false`, a minor garbage - # collection cycle is run, meaning only young objects are marked. - # - # The `immediate_mark` keyword argument determines whether or not to perform - # incremental marking. When set to `true`, marking is completed during the call - # to this method. When set to `false`, marking is performed in steps that are - # interleaved with future Ruby code execution, so marking might not be completed - # during this method call. Note that if `full_mark` is `false`, then marking - # will always be immediate, regardless of the value of `immediate_mark`. - # - # The `immediate_sweep` keyword argument determines whether or not to defer - # sweeping (using lazy sweep). When set to `false`, sweeping is performed in - # steps that are interleaved with future Ruby code execution, so sweeping might - # not be completed during this method call. When set to `true`, sweeping is - # completed during the call to this method. - # - # Note: These keyword arguments are implementation and version-dependent. They - # are not guaranteed to be future-compatible and may be ignored if the - # underlying implementation does not support them. - # - def self.start: (?immediate_sweep: boolish, ?immediate_mark: boolish, ?full_mark: boolish) -> nil - - # - # Returns a Hash containing information about the GC. - # - # The contents of the hash are implementation-specific and may change in the - # future without notice. - # - # The hash includes internal statistics about GC such as: - # - # count - # : The total number of garbage collections run since application start (count - # includes both minor and major garbage collections) - # - # time - # : The total time spent in garbage collections (in milliseconds) - # - # heap_allocated_pages - # : The total number of `:heap_eden_pages` + `:heap_tomb_pages` - # - # heap_sorted_length - # : The number of pages that can fit into the buffer that holds references to - # all pages - # - # heap_allocatable_pages - # : The total number of pages the application could allocate without - # additional GC - # - # heap_available_slots - # : The total number of slots in all `:heap_allocated_pages` - # - # heap_live_slots - # : The total number of slots which contain live objects - # - # heap_free_slots - # : The total number of slots which do not contain live objects - # - # heap_final_slots - # : The total number of slots with pending finalizers to be run - # - # heap_marked_slots - # : The total number of objects marked in the last GC - # - # heap_eden_pages - # : The total number of pages which contain at least one live slot - # - # heap_tomb_pages - # : The total number of pages which do not contain any live slots - # - # total_allocated_pages - # : The cumulative number of pages allocated since application start - # - # total_freed_pages - # : The cumulative number of pages freed since application start - # - # total_allocated_objects - # : The cumulative number of objects allocated since application start - # - # total_freed_objects - # : The cumulative number of objects freed since application start - # - # malloc_increase_bytes - # : Amount of memory allocated on the heap for objects. Decreased by any GC - # - # malloc_increase_bytes_limit - # : When `:malloc_increase_bytes` crosses this limit, GC is triggered - # - # minor_gc_count - # : The total number of minor garbage collections run since process start - # - # major_gc_count - # : The total number of major garbage collections run since process start - # - # compact_count - # : The total number of compactions run since process start - # - # read_barrier_faults - # : The total number of times the read barrier was triggered during compaction - # - # total_moved_objects - # : The total number of objects compaction has moved + # Initiates garbage collection, even if explicitly disabled by GC.disable. # - # remembered_wb_unprotected_objects - # : The total number of objects without write barriers + # Keyword arguments: # - # remembered_wb_unprotected_objects_limit - # : When `:remembered_wb_unprotected_objects` crosses this limit, major GC is - # triggered + # * `full_mark`: its boolean value determines whether to perform a major + # garbage collection cycle: # - # old_objects - # : Number of live, old objects which have survived at least 3 garbage - # collections + # * `true`: initiates a major garbage collection cycle, meaning all + # objects (old and new) are marked. + # * `false`: initiates a minor garbage collection cycle, meaning only + # young objects are marked. # - # old_objects_limit - # : When `:old_objects` crosses this limit, major GC is triggered + # * `immediate_mark`: its boolean value determines whether to perform + # incremental marking: # - # oldmalloc_increase_bytes - # : Amount of memory allocated on the heap for objects. Decreased by major GC + # * `true`: marking is completed before the method returns. + # * `false`: marking is performed by parts, interleaved with program + # execution both before the method returns and afterward; therefore + # marking may not be completed before the return. Note that if + # `full_mark` is `false`, marking will always be immediate, regardless + # of the value of `immediate_mark`. # - # oldmalloc_increase_bytes_limit - # : When `:oldmalloc_increase_bytes` crosses this limit, major GC is triggered + # * `immediate_sweep`: its boolean value determines whether to defer sweeping + # (using lazy sweep): # + # * `true`: sweeping is completed before the method returns. + # * `false`: sweeping is performed by parts, interleaved with program + # execution both before the method returns and afterward; therefore + # sweeping may not be completed before the return. # - # If the optional argument, hash, is given, it is overwritten and returned. This - # is intended to avoid the probe effect. + # Note that these keword arguments are implementation- and version-dependent, + # are not guaranteed to be future-compatible, and may be ignored in some + # implementations. # - # This method is only expected to work on CRuby. + def self.start: (?immediate_sweep: boolish, ?immediate_mark: boolish, ?full_mark: boolish) -> nil + + # + # This method is implementation-specific to CRuby. + # + # Returns GC statistics. The particular statistics are implementation-specific + # and may change in the future without notice. + # + # With no argument given, returns information about the most recent garbage + # collection: + # + # GC.stat + # # => + # {count: 28, + # time: 1, + # marking_time: 1, + # sweeping_time: 0, + # heap_allocated_pages: 521, + # heap_empty_pages: 0, + # heap_allocatable_slots: 0, + # heap_available_slots: 539590, + # heap_live_slots: 422243, + # heap_free_slots: 117347, + # heap_final_slots: 0, + # heap_marked_slots: 264877, + # heap_eden_pages: 521, + # total_allocated_pages: 521, + # total_freed_pages: 0, + # total_allocated_objects: 2246376, + # total_freed_objects: 1824133, + # malloc_increase_bytes: 50982, + # malloc_increase_bytes_limit: 18535172, + # minor_gc_count: 18, + # major_gc_count: 10, + # compact_count: 0, + # read_barrier_faults: 0, + # total_moved_objects: 0, + # remembered_wb_unprotected_objects: 0, + # remembered_wb_unprotected_objects_limit: 2162, + # old_objects: 216365, + # old_objects_limit: 432540, + # oldmalloc_increase_bytes: 1654232, + # oldmalloc_increase_bytes_limit: 16846103} + # + # With symbol argument `key` given, returns the value for that key: + # + # GC.stat(:count) # => 30 + # + # With hash argument `hash` given, returns that hash with GC statistics merged + # into its content; this form may be useful in minimizing [probe + # effects](https://en.wikipedia.org/wiki/Probe_effect): + # + # h = {foo: 0, bar: 1} + # GC.stat(h) + # h.keys.take(5) # => [:foo, :bar, :count, :time, :marking_time] + # + # The hash includes entries such as: + # + # * `:count`: The total number of garbage collections run since application + # start (count includes both minor and major garbage collections). + # * `:time`: The total time spent in garbage collections (in milliseconds). + # * `:heap_allocated_pages`: The total number of `:heap_eden_pages` + + # `:heap_tomb_pages`. + # * `:heap_sorted_length`: The number of pages that can fit into the buffer + # that holds references to all pages. + # * `:heap_allocatable_pages`: The total number of pages the application could + # allocate without additional GC. + # * `:heap_available_slots`: The total number of slots in all + # `:heap_allocated_pages`. + # * `:heap_live_slots`: The total number of slots which contain live objects. + # * `:heap_free_slots`: The total number of slots which do not contain live + # objects. + # * `:heap_final_slots`: The total number of slots with pending finalizers to + # be run. + # * `:heap_marked_slots`: The total number of objects marked in the last GC. + # * `:heap_eden_pages`: The total number of pages which contain at least one + # live slot. + # * `:heap_tomb_pages`: The total number of pages which do not contain any + # live slots. + # * `:total_allocated_pages`: The cumulative number of pages allocated since + # application start. + # * `:total_freed_pages`: The cumulative number of pages freed since + # application start. + # * `:total_allocated_objects`: The cumulative number of objects allocated + # since application start. + # * `:total_freed_objects`: The cumulative number of objects freed since + # application start. + # * `:malloc_increase_bytes`: Amount of memory allocated on the heap for + # objects. Decreased by any GC. + # * `:malloc_increase_bytes_limit`: When `:malloc_increase_bytes` crosses this + # limit, GC is triggered. + # * `:minor_gc_count`: The total number of minor garbage collections run since + # process start. + # * `:major_gc_count`: The total number of major garbage collections run since + # process start. + # * `:compact_count`: The total number of compactions run since process start. + # * `:read_barrier_faults`: The total number of times the read barrier was + # triggered during compaction. + # * `:total_moved_objects`: The total number of objects compaction has moved. + # * `:remembered_wb_unprotected_objects`: The total number of objects without + # write barriers. + # * `:remembered_wb_unprotected_objects_limit`: When + # `:remembered_wb_unprotected_objects` crosses this limit, major GC is + # triggered. + # * `:old_objects`: Number of live, old objects which have survived at least 3 + # garbage collections. + # * `:old_objects_limit`: When `:old_objects` crosses this limit, major GC is + # triggered. + # * `:oldmalloc_increase_bytes`: Amount of memory allocated on the heap for + # objects. Decreased by major GC. + # * `:oldmalloc_increase_bytes_limit`: When `:oldmalloc_increase_bytes` + # crosses this limit, major GC is triggered. # def self.stat: (?Hash[Symbol, untyped]? hash) -> Hash[Symbol, untyped] | (Symbol key) -> Integer # - # Enables measuring GC time. You can get the result with `GC.stat(:time)`. Note - # that GC time measurement can cause some performance overhead. + # Enables or disables GC total time measurement; returns `setting`. See + # GC.total_time. + # + # When argument `object` is `nil` or `false`, disables total time measurement; + # GC.measure_total_time then returns `false`: + # + # GC.measure_total_time = nil # => nil + # GC.measure_total_time # => false + # GC.measure_total_time = false # => false + # GC.measure_total_time # => false + # + # Otherwise, enables total time measurement; GC.measure_total_time then returns + # `true`: + # + # GC.measure_total_time = true # => true + # GC.measure_total_time # => true + # GC.measure_total_time = :foo # => :foo + # GC.measure_total_time # => true + # + # Note that when enabled, total time measurement affects performance. # def self.measure_total_time=: [T] (T enable) -> T # - # Returns the measure_total_time flag (default: `true`). Note that measurement - # can affect the application's performance. + # Returns the setting for GC total time measurement; the initial setting is + # `true`. See GC.total_time. # def self.measure_total_time: () -> bool @@ -447,71 +464,137 @@ module GC # - # Returns information for heaps in the GC. - # - # If the first optional argument, `heap_name`, is passed in and not `nil`, it - # returns a `Hash` containing information about the particular heap. Otherwise, - # it will return a `Hash` with heap names as keys and a `Hash` containing - # information about the heap as values. - # - # If the second optional argument, `hash_or_key`, is given as a `Hash`, it will - # be overwritten and returned. This is intended to avoid the probe effect. - # - # If both optional arguments are passed in and the second optional argument is a - # symbol, it will return a `Numeric` value for the particular heap. - # - # On CRuby, `heap_name` is of the type `Integer` but may be of type `String` on - # other implementations. - # - # The contents of the hash are implementation-specific and may change in the - # future without notice. - # - # If the optional argument, hash, is given, it is overwritten and returned. - # - # This method is only expected to work on CRuby. - # - # The hash includes the following keys about the internal information in the GC: - # - # slot_size - # : The slot size of the heap in bytes. - # - # heap_allocatable_pages - # : The number of pages that can be allocated without triggering a new garbage - # collection cycle. - # - # heap_eden_pages - # : The number of pages in the eden heap. - # - # heap_eden_slots - # : The total number of slots in all of the pages in the eden heap. - # - # heap_tomb_pages - # : The number of pages in the tomb heap. The tomb heap only contains pages - # that do not have any live objects. - # - # heap_tomb_slots - # : The total number of slots in all of the pages in the tomb heap. - # - # total_allocated_pages - # : The total number of pages that have been allocated in the heap. - # - # total_freed_pages - # : The total number of pages that have been freed and released back to the - # system in the heap. - # - # force_major_gc_count - # : The number of times this heap has forced major garbage collection cycles - # to start due to running out of free slots. - # - # force_incremental_marking_finish_count - # : The number of times this heap has forced incremental marking to complete - # due to running out of pooled slots. + # This method is implementation-specific to CRuby. + # + # Returns statistics for GC heaps. The particular statistics are + # implementation-specific and may change in the future without notice. + # + # With no argument given, returns statistics for all heaps: + # + # GC.stat_heap + # # => + # {0 => + # {slot_size: 40, + # heap_eden_pages: 246, + # heap_eden_slots: 402802, + # total_allocated_pages: 246, + # force_major_gc_count: 2, + # force_incremental_marking_finish_count: 1, + # total_allocated_objects: 33867152, + # total_freed_objects: 33520523}, + # 1 => + # {slot_size: 80, + # heap_eden_pages: 84, + # heap_eden_slots: 68746, + # total_allocated_pages: 84, + # force_major_gc_count: 1, + # force_incremental_marking_finish_count: 4, + # total_allocated_objects: 147491, + # total_freed_objects: 90699}, + # 2 => + # {slot_size: 160, + # heap_eden_pages: 157, + # heap_eden_slots: 64182, + # total_allocated_pages: 157, + # force_major_gc_count: 0, + # force_incremental_marking_finish_count: 0, + # total_allocated_objects: 211460, + # total_freed_objects: 190075}, + # 3 => + # {slot_size: 320, + # heap_eden_pages: 8, + # heap_eden_slots: 1631, + # total_allocated_pages: 8, + # force_major_gc_count: 0, + # force_incremental_marking_finish_count: 0, + # total_allocated_objects: 1422, + # total_freed_objects: 700}, + # 4 => + # {slot_size: 640, + # heap_eden_pages: 16, + # heap_eden_slots: 1628, + # total_allocated_pages: 16, + # force_major_gc_count: 0, + # force_incremental_marking_finish_count: 0, + # total_allocated_objects: 1230, + # total_freed_objects: 309}} + # + # In the example above, the keys in the outer hash are the heap identifiers: + # + # GC.stat_heap.keys # => [0, 1, 2, 3, 4] + # + # On CRuby, each heap identifier is an integer; on other implementations, a heap + # identifier may be a string. + # + # With only argument `heap_id` given, returns statistics for the given heap + # identifier: + # + # GC.stat_heap(2) + # # => + # {slot_size: 160, + # heap_eden_pages: 157, + # heap_eden_slots: 64182, + # total_allocated_pages: 157, + # force_major_gc_count: 0, + # force_incremental_marking_finish_count: 0, + # total_allocated_objects: 225018, + # total_freed_objects: 206647} + # + # With arguments `heap_id` and `key` given, returns the value for the given key + # in the given heap: + # + # GC.stat_heap(2, :slot_size) # => 160 + # + # With arguments `nil` and `hash` given, merges the statistics for all heaps + # into the given hash: + # + # h = {foo: 0, bar: 1} + # GC.stat_heap(nil, h).keys # => [:foo, :bar, 0, 1, 2, 3, 4] + # + # With arguments `heap_id` and `hash` given, merges the statistics for the given + # heap into the given hash: + # + # h = {foo: 0, bar: 1} + # GC.stat_heap(2, h).keys + # # => + # [:foo, + # :bar, + # :slot_size, + # :heap_eden_pages, + # :heap_eden_slots, + # :total_allocated_pages, + # :force_major_gc_count, + # :force_incremental_marking_finish_count, + # :total_allocated_objects, + # :total_freed_objects] + # + # The statistics for a heap may include: + # + # * `:slot_size`: The slot size of the heap in bytes. + # * `:heap_allocatable_pages`: The number of pages that can be allocated + # without triggering a new garbage collection cycle. + # * `:heap_eden_pages`: The number of pages in the eden heap. + # * `:heap_eden_slots`: The total number of slots in all of the pages in the + # eden heap. + # * `:heap_tomb_pages`: The number of pages in the tomb heap. The tomb heap + # only contains pages that do not have any live objects. + # * `:heap_tomb_slots`: The total number of slots in all of the pages in the + # tomb heap. + # * `:total_allocated_pages`: The total number of pages that have been + # allocated in the heap. + # * `:total_freed_pages`: The total number of pages that have been freed and + # released back to the system in the heap. + # * `:force_major_gc_count`: The number of times this heap has forced major + # garbage collection cycles to start due to running out of free slots. + # * `:force_incremental_marking_finish_count`: The number of times this heap + # has forced incremental marking to complete due to running out of pooled + # slots. # def self.stat_heap: (?Integer? heap_name, ?Hash[Symbol, untyped]? hash) -> Hash[Symbol, untyped] | (Integer heap_name, Symbol key) -> Integer @@ -532,37 +615,67 @@ module GC # - # Returns the current status of GC stress mode. + # Returns the current GC stress-mode setting, which initially is `false`. + # + # The stress mode may be set by method GC.stress=. # def self.stress: () -> (Integer | bool) # - # Updates the GC stress mode. + # Enables or disables stress mode; enabling stress mode will degrade + # performance; it is only for debugging. + # + # Sets the current GC stress mode to the given value: # - # When stress mode is enabled, the GC is invoked at every GC opportunity: all - # memory and object allocations. + # * If the value is `nil` or `false`, disables stress mode. + # * If the value is an integer, enables stress mode with certain flags; see + # below. + # * Otherwise, enables stress mode; GC is invoked at every GC opportunity: all + # memory and object allocations. # - # Enabling stress mode will degrade performance; it is only for debugging. + # The flags are bits in the given integer: # - # The flag can be true, false, or an integer bitwise-ORed with the following - # flags: - # 0x01:: no major GC - # 0x02:: no immediate sweep - # 0x04:: full mark after malloc/calloc/realloc + # * `0x01`: No major GC. + # * `0x02`: No immediate sweep. + # * `0x04`: Full mark after malloc/calloc/realloc. # def self.stress=: (Integer flag) -> Integer | (bool flag) -> bool # - # Returns the measured GC total time in nanoseconds. + # Returns the GC total time in nanoseconds: + # + # GC.total_time # => 156250 + # + # Note that total time accumulates only when total time measurement is enabled + # (that is, when GC.measure_total_time is `true`): + # + # GC.measure_total_time # => true + # GC.total_time # => 625000 + # GC.start + # GC.total_time # => 937500 + # GC.start + # GC.total_time # => 1093750 + # + # GC.measure_total_time = false + # GC.total_time # => 1250000 + # GC.start + # GC.total_time # => 1250000 + # GC.start + # GC.total_time # => 1250000 + # + # GC.measure_total_time = true + # GC.total_time # => 1250000 + # GC.start + # GC.total_time # => 1406250 # def self.total_time: () -> Integer @@ -619,17 +732,45 @@ module GC # - # Returns information about the most recent garbage collection. - # - # If the argument `hash` is given and is a Hash object, it is overwritten and - # returned. This is intended to avoid the probe effect. - # - # If the argument `key` is given and is a Symbol object, it returns the value - # associated with the key. This is equivalent to `GC.latest_gc_info[key]`. + # With no argument given, returns information about the most recent garbage + # collection: + # + # GC.latest_gc_info + # # => + # {major_by: :force, + # need_major_by: nil, + # gc_by: :method, + # have_finalizer: false, + # immediate_sweep: true, + # state: :none, + # weak_references_count: 0, + # retained_weak_references_count: 0} + # + # With symbol argument `key` given, returns the value for that key: + # + # GC.latest_gc_info(:gc_by) # => :newobj + # + # With hash argument `hash` given, returns that hash with GC information merged + # into its content; this form may be useful in minimizing [probe + # effects](https://en.wikipedia.org/wiki/Probe_effect): + # + # h = {foo: 0, bar: 1} + # GC.latest_gc_info(h) + # # => + # {foo: 0, + # bar: 1, + # major_by: nil, + # need_major_by: nil, + # gc_by: :newobj, + # have_finalizer: false, + # immediate_sweep: false, + # state: :sweeping, + # weak_references_count: 0, + # retained_weak_references_count: 0} # def self.latest_gc_info: (?Hash[Symbol, untyped]? hash) -> Hash[Symbol, untyped] | (Symbol key) -> untyped diff --git a/core/hash.rbs b/core/hash.rbs index df4bbe6c8..c1ab14d31 100644 --- a/core/hash.rbs +++ b/core/hash.rbs @@ -1,67 +1,68 @@ # -# A `Hash` maps each of its unique keys to a specific value. +# A Hash object maps each of its unique keys to a specific value. # -# A `Hash` has certain similarities to an Array, but: -# * An Array index is always an Integer. -# * A `Hash` key can be (almost) any object. +# A hash has certain similarities to an Array, but: # -# ### `Hash` Data Syntax +# * An array index is always an integer. +# * A hash key can be (almost) any object. # -# The older syntax for `Hash` data uses the "hash rocket," `=>`: +# ### Hash Data Syntax +# +# The original syntax for a hash entry uses the "hash rocket," `=>`: # # h = {:foo => 0, :bar => 1, :baz => 2} -# h # => {:foo=>0, :bar=>1, :baz=>2} +# h # => {foo: 0, bar: 1, baz: 2} # -# Alternatively, but only for a `Hash` key that's a Symbol, you can use a newer -# JSON-style syntax, where each bareword becomes a Symbol: +# Alternatively, but only for a key that's a symbol, you can use a newer +# JSON-style syntax, where each bareword becomes a symbol: # # h = {foo: 0, bar: 1, baz: 2} -# h # => {:foo=>0, :bar=>1, :baz=>2} +# h # => {foo: 0, bar: 1, baz: 2} # -# You can also use a String in place of a bareword: +# You can also use a string in place of a bareword: # # h = {'foo': 0, 'bar': 1, 'baz': 2} -# h # => {:foo=>0, :bar=>1, :baz=>2} +# h # => {foo: 0, bar: 1, baz: 2} # # And you can mix the styles: # # h = {foo: 0, :bar => 1, 'baz': 2} -# h # => {:foo=>0, :bar=>1, :baz=>2} +# h # => {foo: 0, bar: 1, baz: 2} # # But it's an error to try the JSON-style syntax for a key that's not a bareword -# or a String: +# or a string: # # # Raises SyntaxError (syntax error, unexpected ':', expecting =>): # h = {0: 'zero'} # -# `Hash` value can be omitted, meaning that value will be fetched from the -# context by the name of the key: +# The value can be omitted, meaning that value will be fetched from the context +# by the name of the key: # # x = 0 # y = 100 # h = {x:, y:} -# h # => {:x=>0, :y=>100} +# h # => {x: 0, y: 100} # # ### Common Uses # -# You can use a `Hash` to give names to objects: +# You can use a hash to give names to objects: # # person = {name: 'Matz', language: 'Ruby'} -# person # => {:name=>"Matz", :language=>"Ruby"} +# person # => {name: "Matz", language: "Ruby"} # -# You can use a `Hash` to give names to method arguments: +# You can use a hash to give names to method arguments: # # def some_method(hash) # p hash # end -# some_method({foo: 0, bar: 1, baz: 2}) # => {:foo=>0, :bar=>1, :baz=>2} +# some_method({foo: 0, bar: 1, baz: 2}) # => {foo: 0, bar: 1, baz: 2} # -# Note: when the last argument in a method call is a `Hash`, the curly braces -# may be omitted: +# Note: when the last argument in a method call is a hash, the curly braces may +# be omitted: # -# some_method(foo: 0, bar: 1, baz: 2) # => {:foo=>0, :bar=>1, :baz=>2} +# some_method(foo: 0, bar: 1, baz: 2) # => {foo: 0, bar: 1, baz: 2} # -# You can use a `Hash` to initialize an object: +# You can use a hash to initialize an object: # # class Dev # attr_accessor :name, :language @@ -73,98 +74,91 @@ # matz = Dev.new(name: 'Matz', language: 'Ruby') # matz # => # # -# ### Creating a `Hash` +# ### Creating a Hash # -# You can create a `Hash` object explicitly with: +# You can create a Hash object explicitly with: # # * A [hash literal](rdoc-ref:syntax/literals.rdoc@Hash+Literals). # -# You can convert certain objects to Hashes with: -# -# * Method #Hash. +# You can convert certain objects to hashes with: # -# You can create a `Hash` by calling method Hash.new. +# * Method Kernel#Hash. # -# Create an empty `Hash`: +# You can create a hash by calling method Hash.new: # +# # Create an empty hash. # h = Hash.new # h # => {} # h.class # => Hash # -# You can create a `Hash` by calling method Hash.[]. -# -# Create an empty `Hash`: +# You can create a hash by calling method Hash.[]: # +# # Create an empty hash. # h = Hash[] # h # => {} -# -# Create a `Hash` with initial entries: -# +# # Create a hash with initial entries. # h = Hash[foo: 0, bar: 1, baz: 2] -# h # => {:foo=>0, :bar=>1, :baz=>2} +# h # => {foo: 0, bar: 1, baz: 2} # -# You can create a `Hash` by using its literal form (curly braces). -# -# Create an empty `Hash`: +# You can create a hash by using its literal form (curly braces): # +# # Create an empty hash. # h = {} # h # => {} -# -# Create a `Hash` with initial entries: -# +# # Create a +Hash+ with initial entries. # h = {foo: 0, bar: 1, baz: 2} -# h # => {:foo=>0, :bar=>1, :baz=>2} +# h # => {foo: 0, bar: 1, baz: 2} # -# ### `Hash` Value Basics +# ### Hash Value Basics # -# The simplest way to retrieve a `Hash` value (instance method #[]): +# The simplest way to retrieve a hash value (instance method #[]): # # h = {foo: 0, bar: 1, baz: 2} # h[:foo] # => 0 # -# The simplest way to create or update a `Hash` value (instance method #[]=): +# The simplest way to create or update a hash value (instance method #[]=): # # h = {foo: 0, bar: 1, baz: 2} # h[:bat] = 3 # => 3 -# h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3} +# h # => {foo: 0, bar: 1, baz: 2, bat: 3} # h[:foo] = 4 # => 4 -# h # => {:foo=>4, :bar=>1, :baz=>2, :bat=>3} +# h # => {foo: 4, bar: 1, baz: 2, bat: 3} # -# The simplest way to delete a `Hash` entry (instance method #delete): +# The simplest way to delete a hash entry (instance method #delete): # # h = {foo: 0, bar: 1, baz: 2} # h.delete(:bar) # => 1 -# h # => {:foo=>0, :baz=>2} +# h # => {foo: 0, baz: 2} # # ### Entry Order # -# A `Hash` object presents its entries in the order of their creation. This is +# A Hash object presents its entries in the order of their creation. This is # seen in: # # * Iterative methods such as `each`, `each_key`, `each_pair`, `each_value`. # * Other order-sensitive methods such as `shift`, `keys`, `values`. -# * The String returned by method `inspect`. +# * The string returned by method `inspect`. # -# A new `Hash` has its initial ordering per the given entries: +# A new hash has its initial ordering per the given entries: # # h = Hash[foo: 0, bar: 1] -# h # => {:foo=>0, :bar=>1} +# h # => {foo: 0, bar: 1} # # New entries are added at the end: # # h[:baz] = 2 -# h # => {:foo=>0, :bar=>1, :baz=>2} +# h # => {foo: 0, bar: 1, baz: 2} # # Updating a value does not affect the order: # # h[:baz] = 3 -# h # => {:foo=>0, :bar=>1, :baz=>3} +# h # => {foo: 0, bar: 1, baz: 3} # # But re-creating a deleted entry can affect the order: # # h.delete(:foo) # h[:foo] = 5 -# h # => {:bar=>1, :baz=>3, :foo=>5} +# h # => {bar: 1, baz: 3, foo: 5} # # ### `Hash` Keys # @@ -257,94 +251,86 @@ # # reviews.length #=> 1 # -# ### Default Values +# ### Key Not Found? # -# The methods #[], #values_at and #dig need to return the value associated to a -# certain key. When that key is not found, that value will be determined by its -# default proc (if any) or else its default (initially `nil`). +# When a method tries to retrieve and return the value for a key and that key +# *is found*, the returned value is the value associated with the key. # -# You can retrieve the default value with method #default: +# But what if the key *is not found*? In that case, certain methods will return +# a default value while other will raise a KeyError. # -# h = Hash.new -# h.default # => nil +# #### Nil Return Value # -# You can set the default value by passing an argument to method Hash.new or -# with method #default= +# If you want `nil` returned for a not-found key, you can call: # -# h = Hash.new(-1) -# h.default # => -1 -# h.default = 0 -# h.default # => 0 +# * #[](key) (usually written as `#[key]`. +# * #assoc(key). +# * #dig(key, *identifiers). +# * #values_at(*keys). # -# This default value is returned for #[], #values_at and #dig when a key is not -# found: +# You can override these behaviors for #[], #dig, and #values_at (but not +# #assoc); see [Hash Default](rdoc-ref:Hash@Hash+Default). # -# counts = {foo: 42} -# counts.default # => nil (default) -# counts[:foo] = 42 -# counts[:bar] # => nil -# counts.default = 0 -# counts[:bar] # => 0 -# counts.values_at(:foo, :bar, :baz) # => [42, 0, 0] -# counts.dig(:bar) # => 0 +# #### KeyError # -# Note that the default value is used without being duplicated. It is not -# advised to set the default value to a mutable object: +# If you want KeyError raised for a not-found key, you can call: # -# synonyms = Hash.new([]) -# synonyms[:hello] # => [] -# synonyms[:hello] << :hi # => [:hi], but this mutates the default! -# synonyms.default # => [:hi] -# synonyms[:world] << :universe -# synonyms[:world] # => [:hi, :universe], oops -# synonyms.keys # => [], oops +# * #fetch(key). +# * #fetch_values(*keys). # -# To use a mutable object as default, it is recommended to use a default proc +# #### Hash Default # -# #### Default Proc +# For certain methods (#[], #dig, and #values_at), the return value for a +# not-found key is determined by two hash properties: # -# When the default proc for a `Hash` is set (i.e., not `nil`), the default value -# returned by method #[] is determined by the default proc alone. +# * *default value*: returned by method #default. +# * *default proc*: returned by method #default_proc. # -# You can retrieve the default proc with method #default_proc: +# In the simple case, both values are `nil`, and the methods return `nil` for a +# not-found key; see [Nil Return Value](rdoc-ref:Hash@Nil+Return+Value) above. # -# h = Hash.new -# h.default_proc # => nil +# Note that this entire section ("Hash Default"): # -# You can set the default proc by calling Hash.new with a block or calling the -# method #default_proc= +# * Applies *only* to methods #[], #dig, and #values_at. +# * Does *not* apply to methods #assoc, #fetch, or #fetch_values, which are +# not affected by the default value or default proc. # -# h = Hash.new { |hash, key| "Default value for #{key}" } -# h.default_proc.class # => Proc -# h.default_proc = proc { |hash, key| "Default value for #{key.inspect}" } -# h.default_proc.class # => Proc +# ##### Any-Key Default # -# When the default proc is set (i.e., not `nil`) and method #[] is called with -# with a non-existent key, #[] calls the default proc with both the `Hash` -# object itself and the missing key, then returns the proc's return value: +# You can define an any-key default for a hash; that is, a value that will be +# returned for *any* not-found key: # -# h = Hash.new { |hash, key| "Default value for #{key}" } -# h[:nosuch] # => "Default value for nosuch" +# * The value of #default_proc *must be* `nil`. +# * The value of #default (which may be any object, including `nil`) will be +# returned for a not-found key. # -# Note that in the example above no entry for key `:nosuch` is created: +# You can set the default value when the hash is created with Hash.new and +# option `default_value`, or later with method #default=. # -# h.include?(:nosuch) # => false +# Note: although the value of #default may be any object, it may not be a good +# idea to use a mutable object. # -# However, the proc itself can add a new entry: +# ##### Per-Key Defaults # -# synonyms = Hash.new { |hash, key| hash[key] = [] } -# synonyms.include?(:hello) # => false -# synonyms[:hello] << :hi # => [:hi] -# synonyms[:world] << :universe # => [:universe] -# synonyms.keys # => [:hello, :world] +# You can define a per-key default for a hash; that is, a Proc that will return +# a value based on the key itself. # -# Note that setting the default proc will clear the default value and vice -# versa. +# You can set the default proc when the hash is created with Hash.new and a +# block, or later with method #default_proc=. # -# Be aware that a default proc that modifies the hash is not thread-safe in the -# sense that multiple threads can call into the default proc concurrently for +# Note that the proc can modify `self`, but modifying `self` in this way is not +# thread-safe; multiple threads can concurrently call into the default proc for # the same key. # +# #### Method Default +# +# For two methods, you can specify a default value for a not-found key that has +# effect only for a single method call (and not for any subsequent calls): +# +# * For method #fetch, you can specify an any-key default: +# * For either method #fetch or method #fetch_values, you can specify a +# per-key default via a block. +# # ### What's Here # # First, what's elsewhere. Class `Hash`: @@ -366,7 +352,6 @@ # * [Converting](rdoc-ref:Hash@Methods+for+Converting) # * [Transforming Keys and # Values](rdoc-ref:Hash@Methods+for+Transforming+Keys+and+Values) -# * [And more....](rdoc-ref:Hash@Other+Methods) # # Class `Hash` also includes methods from module Enumerable. # @@ -422,7 +407,7 @@ # * #keys: Returns an array containing all keys in `self`. # * #rassoc: Returns a 2-element array consisting of the key and value of the # first-found entry having a given value. -# * #values: Returns an array containing all values in `self`/ +# * #values: Returns an array containing all values in `self`. # * #values_at: Returns an array containing values for given keys. # # #### Methods for Assigning @@ -466,6 +451,7 @@ # # #### Methods for Converting # +# * #flatten: Returns an array that is a 1-dimensional flattening of `self`. # * #inspect (aliased as #to_s): Returns a new String containing the hash # entries. # * #to_a: Returns a new array of 2-element arrays; each nested array contains @@ -477,15 +463,12 @@ # # #### Methods for Transforming Keys and Values # +# * #invert: Returns a hash with the each key-value pair inverted. # * #transform_keys: Returns a copy of `self` with modified keys. # * #transform_keys!: Modifies keys in `self` # * #transform_values: Returns a copy of `self` with modified values. # * #transform_values!: Modifies values in `self`. # -# #### Other Methods -# * #flatten: Returns an array that is a 1-dimensional flattening of `self`. -# * #invert: Returns a hash with the each key-value pair inverted. -# class Hash[unchecked out K, unchecked out V] < Object include Enumerable[[ K, V ]] @@ -498,32 +481,38 @@ class Hash[unchecked out K, unchecked out V] < Object # - # Returns a new `Hash` object populated with the given objects, if any. See + # Returns a new Hash object populated with the given objects, if any. See # Hash::new. # - # With no argument, returns a new empty `Hash`. + # With no argument given, returns a new empty hash. # - # When the single given argument is a `Hash`, returns a new `Hash` populated - # with the entries from the given `Hash`, excluding the default value or proc. + # With a single argument `other_hash` given that is a hash, returns a new hash + # initialized with the entries from that hash (but not with its `default` or + # `default_proc`): # # h = {foo: 0, bar: 1, baz: 2} - # Hash[h] # => {:foo=>0, :bar=>1, :baz=>2} + # Hash[h] # => {foo: 0, bar: 1, baz: 2} # - # When the single given argument is an Array of 2-element Arrays, returns a new - # `Hash` object wherein each 2-element array forms a key-value entry: + # With a single argument `2_element_arrays` given that is an array of 2-element + # arrays, returns a new hash wherein each given 2-element array forms a + # key-value entry: # - # Hash[ [ [:foo, 0], [:bar, 1] ] ] # => {:foo=>0, :bar=>1} + # Hash[ [ [:foo, 0], [:bar, 1] ] ] # => {foo: 0, bar: 1} # - # When the argument count is an even number; returns a new `Hash` object wherein - # each successive pair of arguments has become a key-value entry: + # With an even number of arguments `objects` given, returns a new hash wherein + # each successive pair of arguments is a key-value entry: # - # Hash[:foo, 0, :bar, 1] # => {:foo=>0, :bar=>1} + # Hash[:foo, 0, :bar, 1] # => {foo: 0, bar: 1} # - # Raises an exception if the argument list does not conform to any of the above. + # Raises ArgumentError if the argument list does not conform to any of the + # above. + # + # See also [Methods for Creating a + # Hash](rdoc-ref:Hash@Methods+for+Creating+a+Hash). # def self.[]: [U, V] (_ToHash[U, V]) -> ::Hash[U, V] | [U, V] (Array[[ U, V ]]) -> ::Hash[U, V] @@ -531,159 +520,222 @@ class Hash[unchecked out K, unchecked out V] < Object # - # If `obj` is a `Hash` object, returns `obj`. - # - # Otherwise if `obj` responds to `:to_hash`, calls `obj.to_hash` and returns the - # result. + # If `object` is a hash, returns `object`. # - # Returns `nil` if `obj` does not respond to `:to_hash` + # Otherwise if `object` responds to `:to_hash`, calls `object.to_hash`; returns + # the result if it is a hash, or raises TypeError if not. # - # Raises an exception unless `obj.to_hash` returns a `Hash` object. + # Otherwise if `object` does not respond to `:to_hash`, returns `nil`. # def self.try_convert: [U, V] (_ToHash[U, V]) -> ::Hash[U, V] | (untyped) -> (::Hash[untyped, untyped] | nil) # - # Returns `true` if `hash` is a proper subset of `other_hash`, `false` - # otherwise: - # h1 = {foo: 0, bar: 1} - # h2 = {foo: 0, bar: 1, baz: 2} - # h1 < h2 # => true - # h2 < h1 # => false - # h1 < h1 # => false + # Returns `true` if the entries of `self` are a proper subset of the entries of + # `other_hash`, `false` otherwise: + # + # h = {foo: 0, bar: 1} + # h < {foo: 0, bar: 1, baz: 2} # => true # Proper subset. + # h < {baz: 2, bar: 1, foo: 0} # => true # Order may differ. + # h < h # => false # Not a proper subset. + # h < {bar: 1, foo: 0} # => false # Not a proper subset. + # h < {foo: 0, bar: 1, baz: 2} # => false # Different key. + # h < {foo: 0, bar: 1, baz: 2} # => false # Different value. + # + # See [Hash Inclusion](rdoc-ref:hash_inclusion.rdoc). + # + # Raises TypeError if `other_hash` is not a hash and cannot be converted to a + # hash. + # + # Related: see [Methods for Comparing](rdoc-ref:Hash@Methods+for+Comparing). # def <: [A, B] (::Hash[A, B]) -> bool # - # Returns `true` if `hash` is a subset of `other_hash`, `false` otherwise: - # h1 = {foo: 0, bar: 1} - # h2 = {foo: 0, bar: 1, baz: 2} - # h1 <= h2 # => true - # h2 <= h1 # => false - # h1 <= h1 # => true + # Returns `true` if the entries of `self` are a subset of the entries of + # `other_hash`, `false` otherwise: + # + # h0 = {foo: 0, bar: 1} + # h1 = {foo: 0, bar: 1, baz: 2} + # h0 <= h0 # => true + # h0 <= h1 # => true + # h1 <= h0 # => false + # + # See [Hash Inclusion](rdoc-ref:hash_inclusion.rdoc). + # + # Raises TypeError if `other_hash` is not a hash and cannot be converted to a + # hash. + # + # Related: see [Methods for Comparing](rdoc-ref:Hash@Methods+for+Comparing). # def <=: [A, B] (::Hash[A, B]) -> bool # + # Returns whether `self` and `object` are equal. + # # Returns `true` if all of the following are true: - # * `object` is a `Hash` object. - # * `hash` and `object` have the same keys (regardless of order). - # * For each key `key`, `hash[key] == object[key]`. + # + # * `object` is a `Hash` object (or can be converted to one). + # * `self` and `object` have the same keys (regardless of order). + # * For each key `key`, `self[key] == object[key]`. # # Otherwise, returns `false`. # - # Equal: - # h1 = {foo: 0, bar: 1, baz: 2} - # h2 = {foo: 0, bar: 1, baz: 2} - # h1 == h2 # => true - # h3 = {baz: 2, bar: 1, foo: 0} - # h1 == h3 # => true + # Examples: + # + # h = {foo: 0, bar: 1} + # h == {foo: 0, bar: 1} # => true # Equal entries (same order) + # h == {bar: 1, foo: 0} # => true # Equal entries (different order). + # h == 1 # => false # Object not a hash. + # h == {} # => false # Different number of entries. + # h == {foo: 0, bar: 1} # => false # Different key. + # h == {foo: 0, bar: 1} # => false # Different value. + # + # Related: see [Methods for Comparing](rdoc-ref:Hash@Methods+for+Comparing). # def ==: (untyped other) -> bool # - # Returns `true` if `hash` is a proper superset of `other_hash`, `false` - # otherwise: - # h1 = {foo: 0, bar: 1, baz: 2} - # h2 = {foo: 0, bar: 1} - # h1 > h2 # => true - # h2 > h1 # => false - # h1 > h1 # => false + # Returns `true` if the entries of `self` are a proper superset of the entries + # of `other_hash`, `false` otherwise: + # + # h = {foo: 0, bar: 1, baz: 2} + # h > {foo: 0, bar: 1} # => true # Proper superset. + # h > {bar: 1, foo: 0} # => true # Order may differ. + # h > h # => false # Not a proper superset. + # h > {baz: 2, bar: 1, foo: 0} # => false # Not a proper superset. + # h > {foo: 0, bar: 1} # => false # Different key. + # h > {foo: 0, bar: 1} # => false # Different value. + # + # See [Hash Inclusion](rdoc-ref:hash_inclusion.rdoc). + # + # Raises TypeError if `other_hash` is not a hash and cannot be converted to a + # hash. + # + # Related: see [Methods for Comparing](rdoc-ref:Hash@Methods+for+Comparing). # def >: [A, B] (::Hash[A, B]) -> bool # - # Returns `true` if `hash` is a superset of `other_hash`, `false` otherwise: - # h1 = {foo: 0, bar: 1, baz: 2} - # h2 = {foo: 0, bar: 1} - # h1 >= h2 # => true - # h2 >= h1 # => false - # h1 >= h1 # => true + # Returns `true` if the entries of `self` are a superset of the entries of + # `other_hash`, `false` otherwise: + # + # h0 = {foo: 0, bar: 1, baz: 2} + # h1 = {foo: 0, bar: 1} + # h0 >= h1 # => true + # h0 >= h0 # => true + # h1 >= h0 # => false + # + # See [Hash Inclusion](rdoc-ref:hash_inclusion.rdoc). + # + # Raises TypeError if `other_hash` is not a hash and cannot be converted to a + # hash. + # + # Related: see [Methods for Comparing](rdoc-ref:Hash@Methods+for+Comparing). # def >=: [A, B] (::Hash[A, B]) -> bool # - # Returns the value associated with the given `key`, if found: - # h = {foo: 0, bar: 1, baz: 2} - # h[:foo] # => 0 + # Searches for a hash key equivalent to the given `key`; see [Hash Key + # Equivalence](rdoc-ref:Hash@Hash+Key+Equivalence). # - # If `key` is not found, returns a default value (see [Default - # Values](rdoc-ref:Hash@Default+Values)): - # h = {foo: 0, bar: 1, baz: 2} - # h[:nosuch] # => nil + # If the key is found, returns its value: + # + # {foo: 0, bar: 1, baz: 2} + # h[:bar] # => 1 + # + # Otherwise, returns a default value (see [Hash + # Default](rdoc-ref:Hash@Hash+Default)). + # + # Related: #[]=; see also [Methods for + # Fetching](rdoc-ref:Hash@Methods+for+Fetching). # def []: %a{implicitly-returns-nil} (K arg0) -> V # - # Associates the given `value` with the given `key`; returns `value`. + # Associates the given `object` with the given `key`; returns `object`. + # + # Searches for a hash key equivalent to the given `key`; see [Hash Key + # Equivalence](rdoc-ref:Hash@Hash+Key+Equivalence). + # + # If the key is found, replaces its value with the given `object`; the ordering + # is not affected (see [Entry Order](rdoc-ref:Hash@Entry+Order)): # - # If the given `key` exists, replaces its value with the given `value`; the - # ordering is not affected (see [Entry Order](rdoc-ref:Hash@Entry+Order)): # h = {foo: 0, bar: 1} # h[:foo] = 2 # => 2 - # h.store(:bar, 3) # => 3 - # h # => {:foo=>2, :bar=>3} + # h[:foo] # => 2 + # + # If `key` is not found, creates a new entry for the given `key` and `object`; + # the new entry is last in the order (see [Entry + # Order](rdoc-ref:Hash@Entry+Order)): # - # If `key` does not exist, adds the `key` and `value`; the new entry is last in - # the order (see [Entry Order](rdoc-ref:Hash@Entry+Order)): # h = {foo: 0, bar: 1} # h[:baz] = 2 # => 2 - # h.store(:bat, 3) # => 3 - # h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3} + # h[:baz] # => 2 + # h # => {:foo=>0, :bar=>1, :baz=>2} + # + # Related: #[]; see also [Methods for + # Assigning](rdoc-ref:Hash@Methods+for+Assigning). # def []=: (K arg0, V arg1) -> V # # Returns `true` if any element satisfies a given criterion; `false` otherwise. # - # If `self` has no element, returns `false` and argument or block are not used. + # If `self` has no element, returns `false` and argument or block are not used; + # otherwise behaves as below. # - # With no argument and no block, returns `true` if `self` is non-empty; `false` - # if empty. + # With no argument and no block, returns `true` if `self` is non-empty, `false` + # otherwise. + # + # With argument `entry` and no block, returns `true` if for any key `key` + # `self.assoc(key) == entry`, `false` otherwise: # - # With argument `object` and no block, returns `true` if for any key `key` - # `h.assoc(key) == object`: # h = {foo: 0, bar: 1, baz: 2} + # h.assoc(:bar) # => [:bar, 1] # h.any?([:bar, 1]) # => true # h.any?([:bar, 0]) # => false - # h.any?([:baz, 1]) # => false # - # With no argument and a block, calls the block with each key-value pair; - # returns `true` if the block returns any truthy value, `false` otherwise: + # With no argument and a block given, calls the block with each key-value pair; + # returns `true` if the block returns a truthy value, `false` otherwise: + # # h = {foo: 0, bar: 1, baz: 2} # h.any? {|key, value| value < 3 } # => true # h.any? {|key, value| value > 3 } # => false # - # Related: Enumerable#any? + # With both argument `entry` and a block given, issues a warning and ignores the + # block. + # + # Related: Enumerable#any? (which this method overrides); see also [Methods for + # Fetching](rdoc-ref:Hash@Methods+for+Fetching). # def any?: () -> bool | (untyped pattern) -> bool @@ -691,81 +743,99 @@ class Hash[unchecked out K, unchecked out V] < Object # - # If the given `key` is found, returns a 2-element Array containing that key and - # its value: + # If the given `key` is found, returns its entry as a 2-element array containing + # that key and its value: + # # h = {foo: 0, bar: 1, baz: 2} # h.assoc(:bar) # => [:bar, 1] # - # Returns `nil` if key `key` is not found. + # Returns `nil` if the key is not found. + # + # Related: see [Methods for Fetching](rdoc-ref:Hash@Methods+for+Fetching). # def assoc: (K arg0) -> [ K, V ]? # - # Removes all hash entries; returns `self`. + # Removes all entries from `self`; returns emptied `self`. + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def clear: () -> self # # Returns a copy of `self` with all `nil`-valued entries removed: + # # h = {foo: 0, bar: nil, baz: 2, bat: nil} - # h1 = h.compact - # h1 # => {:foo=>0, :baz=>2} + # h.compact # => {foo: 0, baz: 2} + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def compact: () -> ::Hash[K, V] # - # Returns `self` with all its `nil`-valued entries removed (in place): + # If `self` contains any `nil`-valued entries, returns `self` with all + # `nil`-valued entries removed; returns `nil` otherwise: + # # h = {foo: 0, bar: nil, baz: 2, bat: nil} - # h.compact! # => {:foo=>0, :baz=>2} + # h.compact! + # h # => {foo: 0, baz: 2} + # h.compact! # => nil # - # Returns `nil` if no entries were removed. + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def compact!: () -> self? # - # Sets `self` to consider only identity in comparing keys; two keys are - # considered the same only if they are the same object; returns `self`. + # Sets `self` to compare keys using *identity* (rather than mere *equality*); + # returns `self`: + # + # By default, two keys are considered to be the same key if and only if they are + # *equal* objects (per method #eql?): # - # By default, these two object are considered to be the same key, so `s1` will - # overwrite `s0`: - # s0 = 'x' - # s1 = 'x' # h = {} - # h.compare_by_identity? # => false - # h[s0] = 0 - # h[s1] = 1 + # h['x'] = 0 + # h['x'] = 1 # Overwrites. # h # => {"x"=>1} # - # After calling #compare_by_identity, the keys are considered to be different, - # and therefore do not overwrite each other: - # h = {} - # h.compare_by_identity # => {} - # h.compare_by_identity? # => true - # h[s0] = 0 - # h[s1] = 1 - # h # => {"x"=>0, "x"=>1} + # When this method has been called, two keys are considered to be the same key + # if and only if they are the *same* object: + # + # h.compare_by_identity + # h['x'] = 2 # Does not overwrite. + # h # => {"x"=>1, "x"=>2} + # + # Related: #compare_by_identity?; see also [Methods for + # Comparing](rdoc-ref:Hash@Methods+for+Comparing). # def compare_by_identity: () -> self # - # Returns `true` if #compare_by_identity has been called, `false` otherwise. + # Returns whether #compare_by_identity has been called: + # + # h = {} + # h.compare_by_identity? # => false + # h.compare_by_identity + # h.compare_by_identity? # => true + # + # Related: #compare_by_identity; see also [Methods for + # Comparing](rdoc-ref:Hash@Methods+for+Comparing). # def compare_by_identity?: () -> bool @@ -778,12 +848,12 @@ class Hash[unchecked out K, unchecked out V] < Object # # Returns the default value for the given `key`. The returned value will be - # determined either by the default proc or by the default value. See [Default - # Values](rdoc-ref:Hash@Default+Values). + # determined either by the default proc or by the default value. See [Hash + # Default](rdoc-ref:Hash@Hash+Default). # # With no argument, returns the current default value: # h = {} @@ -799,7 +869,7 @@ class Hash[unchecked out K, unchecked out V] < Object # # Sets the default value to `value`; returns `value`: # h = {} @@ -807,16 +877,16 @@ class Hash[unchecked out K, unchecked out V] < Object # h.default = false # => false # h.default # => false # - # See [Default Values](rdoc-ref:Hash@Default+Values). + # See [Hash Default](rdoc-ref:Hash@Hash+Default). # def default=: (V arg0) -> V # - # Returns the default proc for `self` (see [Default - # Values](rdoc-ref:Hash@Default+Values)): + # Returns the default proc for `self` (see [Hash + # Default](rdoc-ref:Hash@Hash+Default)): # h = {} # h.default_proc # => nil # h.default_proc = proc {|hash, key| "Default value for #{key}" } @@ -826,10 +896,10 @@ class Hash[unchecked out K, unchecked out V] < Object # - # Sets the default proc for `self` to `proc` (see [Default - # Values](rdoc-ref:Hash@Default+Values)): + # Sets the default proc for `self` to `proc` (see [Hash + # Default](rdoc-ref:Hash@Hash+Default)): # h = {} # h.default_proc # => nil # h.default_proc = proc { |hash, key| "Default value for #{key}" } @@ -841,208 +911,200 @@ class Hash[unchecked out K, unchecked out V] < Object # - # Deletes the entry for the given `key` and returns its associated value. + # If an entry for the given `key` is found, deletes the entry and returns its + # associated value; otherwise returns `nil` or calls the given block. + # + # With no block given and `key` found, deletes the entry and returns its value: # - # If no block is given and `key` is found, deletes the entry and returns the - # associated value: # h = {foo: 0, bar: 1, baz: 2} # h.delete(:bar) # => 1 - # h # => {:foo=>0, :baz=>2} + # h # => {foo: 0, baz: 2} + # + # With no block given and `key` not found, returns `nil`. # - # If no block given and `key` is not found, returns `nil`. + # With a block given and `key` found, ignores the block, deletes the entry, and + # returns its value: # - # If a block is given and `key` is found, ignores the block, deletes the entry, - # and returns the associated value: # h = {foo: 0, bar: 1, baz: 2} # h.delete(:baz) { |key| raise 'Will never happen'} # => 2 - # h # => {:foo=>0, :bar=>1} + # h # => {foo: 0, bar: 1} # - # If a block is given and `key` is not found, calls the block and returns the + # With a block given and `key` not found, calls the block and returns the # block's return value: + # # h = {foo: 0, bar: 1, baz: 2} # h.delete(:nosuch) { |key| "Key #{key} not found" } # => "Key nosuch not found" - # h # => {:foo=>0, :bar=>1, :baz=>2} + # h # => {foo: 0, bar: 1, baz: 2} + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def delete: (K arg0) -> V? | [U] (K arg0) { (K arg0) -> U } -> (U | V) # - # If a block given, calls the block with each key-value pair; deletes each entry - # for which the block returns a truthy value; returns `self`: - # h = {foo: 0, bar: 1, baz: 2} - # h.delete_if {|key, value| value > 0 } # => {:foo=>0} + # With a block given, calls the block with each key-value pair, deletes each + # entry for which the block returns a truthy value, and returns `self`: # - # If no block given, returns a new Enumerator: # h = {foo: 0, bar: 1, baz: 2} - # e = h.delete_if # => #0, :bar=>1, :baz=>2}:delete_if> - # e.each { |key, value| value > 0 } # => {:foo=>0} + # h.delete_if {|key, value| value > 0 } # => {foo: 0} + # + # With no block given, returns a new Enumerator. + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def delete_if: () { (K, V) -> boolish } -> self | () -> ::Enumerator[[ K, V ], self] # - # Finds and returns the object in nested objects that is specified by `key` and - # `identifiers`. The nested objects may be instances of various classes. See - # [Dig Methods](rdoc-ref:dig_methods.rdoc). + # Finds and returns an object found in nested objects, as specified by `key` and + # `identifiers`. + # + # The nested objects may be instances of various classes. See [Dig + # Methods](rdoc-ref:dig_methods.rdoc). + # + # Nested hashes: # - # Nested Hashes: # h = {foo: {bar: {baz: 2}}} - # h.dig(:foo) # => {:bar=>{:baz=>2}} - # h.dig(:foo, :bar) # => {:baz=>2} + # h.dig(:foo) # => {bar: {baz: 2}} + # h.dig(:foo, :bar) # => {baz: 2} # h.dig(:foo, :bar, :baz) # => 2 # h.dig(:foo, :bar, :BAZ) # => nil # - # Nested Hashes and Arrays: + # Nested hashes and arrays: + # # h = {foo: {bar: [:a, :b, :c]}} # h.dig(:foo, :bar, 2) # => :c # - # This method will use the [default values](rdoc-ref:Hash@Default+Values) for - # keys that are not present: + # If no such object is found, returns the [hash + # default](rdoc-ref:Hash@Hash+Default): + # # h = {foo: {bar: [:a, :b, :c]}} # h.dig(:hello) # => nil # h.default_proc = -> (hash, _key) { hash } - # h.dig(:hello, :world) # => h - # h.dig(:hello, :world, :foo, :bar, 2) # => :c + # h.dig(:hello, :world) + # # => {:foo=>{:bar=>[:a, :b, :c]}} + # + # Related: [Methods for Fetching](rdoc-ref:Hash@Methods+for+Fetching). # def dig: (K, *untyped) -> untyped # - # Calls the given block with each key-value pair; returns `self`: + # With a block given, calls the block with each key-value pair; returns `self`: + # # h = {foo: 0, bar: 1, baz: 2} - # h.each_pair {|key, value| puts "#{key}: #{value}"} # => {:foo=>0, :bar=>1, :baz=>2} + # h.each_pair {|key, value| puts "#{key}: #{value}"} # => {foo: 0, bar: 1, baz: 2} # # Output: + # # foo: 0 # bar: 1 # baz: 2 # - # Returns a new Enumerator if no block given: - # h = {foo: 0, bar: 1, baz: 2} - # e = h.each_pair # => #0, :bar=>1, :baz=>2}:each_pair> - # h1 = e.each {|key, value| puts "#{key}: #{value}"} - # h1 # => {:foo=>0, :bar=>1, :baz=>2} + # With no block given, returns a new Enumerator. # - # Output: - # foo: 0 - # bar: 1 - # baz: 2 + # Related: see [Methods for Iterating](rdoc-ref:Hash@Methods+for+Iterating). # def each: () { ([ K, V ] arg0) -> untyped } -> self | () -> ::Enumerator[[ K, V ], self] # - # Calls the given block with each key; returns `self`: + # With a block given, calls the block with each key; returns `self`: + # # h = {foo: 0, bar: 1, baz: 2} - # h.each_key {|key| puts key } # => {:foo=>0, :bar=>1, :baz=>2} + # h.each_key {|key| puts key } # => {foo: 0, bar: 1, baz: 2} # # Output: # foo # bar # baz # - # Returns a new Enumerator if no block given: - # h = {foo: 0, bar: 1, baz: 2} - # e = h.each_key # => #0, :bar=>1, :baz=>2}:each_key> - # h1 = e.each {|key| puts key } - # h1 # => {:foo=>0, :bar=>1, :baz=>2} + # With no block given, returns a new Enumerator. # - # Output: - # foo - # bar - # baz + # Related: see [Methods for Iterating](rdoc-ref:Hash@Methods+for+Iterating). # def each_key: () { (K arg0) -> untyped } -> ::Hash[K, V] | () -> ::Enumerator[K, self] # - # Calls the given block with each key-value pair; returns `self`: + # With a block given, calls the block with each key-value pair; returns `self`: + # # h = {foo: 0, bar: 1, baz: 2} - # h.each_pair {|key, value| puts "#{key}: #{value}"} # => {:foo=>0, :bar=>1, :baz=>2} + # h.each_pair {|key, value| puts "#{key}: #{value}"} # => {foo: 0, bar: 1, baz: 2} # # Output: + # # foo: 0 # bar: 1 # baz: 2 # - # Returns a new Enumerator if no block given: - # h = {foo: 0, bar: 1, baz: 2} - # e = h.each_pair # => #0, :bar=>1, :baz=>2}:each_pair> - # h1 = e.each {|key, value| puts "#{key}: #{value}"} - # h1 # => {:foo=>0, :bar=>1, :baz=>2} + # With no block given, returns a new Enumerator. # - # Output: - # foo: 0 - # bar: 1 - # baz: 2 + # Related: see [Methods for Iterating](rdoc-ref:Hash@Methods+for+Iterating). # alias each_pair each # - # Calls the given block with each value; returns `self`: + # With a block given, calls the block with each value; returns `self`: + # # h = {foo: 0, bar: 1, baz: 2} - # h.each_value {|value| puts value } # => {:foo=>0, :bar=>1, :baz=>2} + # h.each_value {|value| puts value } # => {foo: 0, bar: 1, baz: 2} # # Output: # 0 # 1 # 2 # - # Returns a new Enumerator if no block given: - # h = {foo: 0, bar: 1, baz: 2} - # e = h.each_value # => #0, :bar=>1, :baz=>2}:each_value> - # h1 = e.each {|value| puts value } - # h1 # => {:foo=>0, :bar=>1, :baz=>2} + # With no block given, returns a new Enumerator. # - # Output: - # 0 - # 1 - # 2 + # Related: see [Methods for Iterating](rdoc-ref:Hash@Methods+for+Iterating). # def each_value: () { (V arg0) -> untyped } -> self | () -> ::Enumerator[V, self] # # Returns `true` if there are no hash entries, `false` otherwise: + # # {}.empty? # => true - # {foo: 0, bar: 1, baz: 2}.empty? # => false + # {foo: 0}.empty? # => false + # + # Related: see [Methods for Querying](rdoc-ref:Hash@Methods+for+Querying). # def empty?: () -> bool # # Returns `true` if all of the following are true: - # * `object` is a `Hash` object. - # * `hash` and `object` have the same keys (regardless of order). - # * For each key `key`, `h[key].eql?(object[key])`. + # + # * The given `object` is a `Hash` object. + # * `self` and `object` have the same keys (regardless of order). + # * For each key `key`, `self[key].eql?(object[key])`. # # Otherwise, returns `false`. # @@ -1052,378 +1114,427 @@ class Hash[unchecked out K, unchecked out V] < Object # h3 = {baz: 2, bar: 1, foo: 0} # h1.eql? h3 # => true # + # Related: see [Methods for Querying](rdoc-ref:Hash@Methods+for+Querying). + # def eql?: (untyped) -> bool # - # Returns a new `Hash` excluding entries for the given `keys`: - # h = { a: 100, b: 200, c: 300 } - # h.except(:a) #=> {:b=>200, :c=>300} + # Returns a copy of `self` that excludes entries for the given `keys`; any + # `keys` that are not found are ignored: # - # Any given `keys` that are not found are ignored. + # h = {foo:0, bar: 1, baz: 2} # => {:foo=>0, :bar=>1, :baz=>2} + # h.except(:baz, :foo) # => {:bar=>1} + # h.except(:bar, :nosuch) # => {:foo=>0, :baz=>2} + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def except: (*K) -> ::Hash[K, V] # - # Returns the value for the given `key`, if found. + # With no block given, returns the value for the given `key`, if found; + # # h = {foo: 0, bar: 1, baz: 2} - # h.fetch(:bar) # => 1 + # h.fetch(:bar) # => 1 # - # If `key` is not found and no block was given, returns `default_value`: - # {}.fetch(:nosuch, :default) # => :default + # If the key is not found, returns `default_value`, if given, or raises KeyError + # otherwise: # - # If `key` is not found and a block was given, yields `key` to the block and - # returns the block's return value: - # {}.fetch(:nosuch) {|key| "No key #{key}"} # => "No key nosuch" + # h.fetch(:nosuch, :default) # => :default + # h.fetch(:nosuch) # Raises KeyError. # - # Raises KeyError if neither `default_value` nor a block was given. + # With a block given, calls the block with `key` and returns the block's return + # value: + # + # {}.fetch(:nosuch) {|key| "No key #{key}"} # => "No key nosuch" # # Note that this method does not use the values of either #default or # #default_proc. # + # Related: see [Methods for Fetching](rdoc-ref:Hash@Methods+for+Fetching). + # def fetch: (K arg0) -> V | [X] (K arg0, X arg1) -> (V | X) | [X] (K arg0) { (K arg0) -> X } -> (V | X) # - # Returns a new Array containing the values associated with the given keys - # *keys: + # When all given `keys` are found, returns a new array containing the values + # associated with the given `keys`: + # # h = {foo: 0, bar: 1, baz: 2} # h.fetch_values(:baz, :foo) # => [2, 0] # - # Returns a new empty Array if no arguments given. + # When any given `keys` are not found and a block is given, calls the block with + # each unfound key and uses the block's return value as the value for that key: # - # When a block is given, calls the block with each missing key, treating the - # block's return value as the value for that key: - # h = {foo: 0, bar: 1, baz: 2} - # values = h.fetch_values(:bar, :foo, :bad, :bam) {|key| key.to_s} - # values # => [1, 0, "bad", "bam"] + # h.fetch_values(:bar, :foo, :bad, :bam) {|key| key.to_s} + # # => [1, 0, "bad", "bam"] # - # When no block is given, raises an exception if any given key is not found. + # When any given `keys` are not found and no block is given, raises KeyError. + # + # Related: see [Methods for Fetching](rdoc-ref:Hash@Methods+for+Fetching). # def fetch_values: (*K) -> ::Array[V] | [X] (*K) { (K) -> X } -> ::Array[V | X] # - # Returns a new `Hash` object whose entries are those for which the block - # returns a truthy value: - # h = {foo: 0, bar: 1, baz: 2} - # h.select {|key, value| value < 2 } # => {:foo=>0, :bar=>1} + # With a block given, calls the block with each entry's key and value; returns a + # new hash whose entries are those for which the block returns a truthy value: # - # Returns a new Enumerator if no block given: # h = {foo: 0, bar: 1, baz: 2} - # e = h.select # => #0, :bar=>1, :baz=>2}:select> - # e.each {|key, value| value < 2 } # => {:foo=>0, :bar=>1} + # h.select {|key, value| value < 2 } # => {foo: 0, bar: 1} + # + # With no block given, returns a new Enumerator. + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def filter: () { (K, V) -> boolish } -> ::Hash[K, V] | () -> ::Enumerator[[ K, V ], ::Hash[K, V]] # - # Returns `self`, whose entries are those for which the block returns a truthy - # value: - # h = {foo: 0, bar: 1, baz: 2} - # h.select! {|key, value| value < 2 } => {:foo=>0, :bar=>1} + # With a block given, calls the block with each entry's key and value; removes + # from `self` each entry for which the block returns `false` or `nil`. # - # Returns `nil` if no entries were removed. + # Returns `self` if any entries were removed, `nil` otherwise: # - # Returns a new Enumerator if no block given: # h = {foo: 0, bar: 1, baz: 2} - # e = h.select! # => #0, :bar=>1, :baz=>2}:select!> - # e.each { |key, value| value < 2 } # => {:foo=>0, :bar=>1} + # h.select! {|key, value| value < 2 } # => {foo: 0, bar: 1} + # h.select! {|key, value| value < 2 } # => nil + # + # With no block given, returns a new Enumerator. + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def filter!: () { (K, V) -> boolish } -> self? | () -> ::Enumerator[[ K, V ], self?] # - # Returns a new Array object that is a 1-dimensional flattening of `self`. + # With positive integer `depth`, returns a new array that is a recursive + # flattening of `self` to the given `depth`. + # + # At each level of recursion: + # + # * Each element whose value is an array is "flattened" (that is, replaced by + # its individual array elements); see Array#flatten. + # * Each element whose value is not an array is unchanged. even if the value + # is an object that has instance method flatten (such as a hash). + # + # Examples; note that entry `foo: {bar: 1, baz: 2}` is never flattened. + # + # h = {foo: {bar: 1, baz: 2}, bat: [:bam, [:bap, [:bah]]]} + # h.flatten(1) # => [:foo, {:bar=>1, :baz=>2}, :bat, [:bam, [:bap, [:bah]]]] + # h.flatten(2) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, [:bap, [:bah]]] + # h.flatten(3) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, [:bah]] + # h.flatten(4) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah] + # h.flatten(5) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah] # - # --- + # With negative integer `depth`, flattens all levels: # - # By default, nested Arrays are not flattened: - # h = {foo: 0, bar: [:bat, 3], baz: 2} - # h.flatten # => [:foo, 0, :bar, [:bat, 3], :baz, 2] + # h.flatten(-1) # => [:foo, {:bar=>1, :baz=>2}, :bat, :bam, :bap, :bah] # - # Takes the depth of recursive flattening from Integer argument `level`: - # h = {foo: 0, bar: [:bat, [:baz, [:bat, ]]]} - # h.flatten(1) # => [:foo, 0, :bar, [:bat, [:baz, [:bat]]]] - # h.flatten(2) # => [:foo, 0, :bar, :bat, [:baz, [:bat]]] - # h.flatten(3) # => [:foo, 0, :bar, :bat, :baz, [:bat]] - # h.flatten(4) # => [:foo, 0, :bar, :bat, :baz, :bat] + # With `depth` zero, returns the equivalent of #to_a: # - # When `level` is negative, flattens all nested Arrays: - # h = {foo: 0, bar: [:bat, [:baz, [:bat, ]]]} - # h.flatten(-1) # => [:foo, 0, :bar, :bat, :baz, :bat] - # h.flatten(-2) # => [:foo, 0, :bar, :bat, :baz, :bat] + # h.flatten(0) # => [[:foo, {:bar=>1, :baz=>2}], [:bat, [:bam, [:bap, [:bah]]]]] # - # When `level` is zero, returns the equivalent of #to_a : - # h = {foo: 0, bar: [:bat, 3], baz: 2} - # h.flatten(0) # => [[:foo, 0], [:bar, [:bat, 3]], [:baz, 2]] - # h.flatten(0) == h.to_a # => true + # Related: see [Methods for Converting](rdoc-ref:Hash@Methods+for+Converting). # def flatten: () -> ::Array[K | V] | (1 level) -> ::Array[K | V] | (Integer level) -> Array[untyped] # - # Returns `true` if `key` is a key in `self`, otherwise `false`. + # Returns whether `key` is a key in `self`: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.include?(:bar) # => true + # h.include?(:BAR) # => false + # + # Related: [Methods for Querying](rdoc-ref:Hash@Methods+for+Querying). # def has_key?: (K arg0) -> bool # - # Returns `true` if `value` is a value in `self`, otherwise `false`. + # Returns whether `value` is a value in `self`. + # + # Related: [Methods for Querying](rdoc-ref:Hash@Methods+for+Querying). # def has_value?: (V arg0) -> bool # - # Returns the Integer hash-code for the hash. + # Returns the integer hash-code for the hash. + # + # Two hashes have the same hash-code if their content is the same (regardless of + # order): # - # Two `Hash` objects have the same hash-code if their content is the same - # (regardless of order): # h1 = {foo: 0, bar: 1, baz: 2} # h2 = {baz: 2, bar: 1, foo: 0} # h2.hash == h1.hash # => true # h2.eql? h1 # => true # + # Related: see [Methods for Querying](rdoc-ref:Hash@Methods+for+Querying). + # def hash: () -> Integer # - # Returns `true` if `key` is a key in `self`, otherwise `false`. + # Returns whether `key` is a key in `self`: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.include?(:bar) # => true + # h.include?(:BAR) # => false + # + # Related: [Methods for Querying](rdoc-ref:Hash@Methods+for+Querying). # alias include? has_key? # - # Returns a new String containing the hash entries: + # Returns a new string containing the hash entries: # # h = {foo: 0, bar: 1, baz: 2} # h.inspect # => "{foo: 0, bar: 1, baz: 2}" # + # Related: see [Methods for Converting](rdoc-ref:Hash@Methods+for+Converting). + # def inspect: () -> String # - # Returns a new `Hash` object with the each key-value pair inverted: + # Returns a new hash with each key-value pair inverted: + # # h = {foo: 0, bar: 1, baz: 2} # h1 = h.invert # h1 # => {0=>:foo, 1=>:bar, 2=>:baz} # - # Overwrites any repeated new keys: (see [Entry + # Overwrites any repeated new keys (see [Entry # Order](rdoc-ref:Hash@Entry+Order)): + # # h = {foo: 0, bar: 0, baz: 0} # h.invert # => {0=>:baz} # + # Related: see [Methods for Transforming Keys and + # Values](rdoc-ref:Hash@Methods+for+Transforming+Keys+and+Values). + # def invert: () -> ::Hash[V, K] # - # Calls the block for each key-value pair; retains the entry if the block - # returns a truthy value; otherwise deletes the entry; returns `self`. - # h = {foo: 0, bar: 1, baz: 2} - # h.keep_if { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2} + # With a block given, calls the block for each key-value pair; retains the entry + # if the block returns a truthy value; otherwise deletes the entry; returns + # `self`: # - # Returns a new Enumerator if no block given: # h = {foo: 0, bar: 1, baz: 2} - # e = h.keep_if # => #0, :bar=>1, :baz=>2}:keep_if> - # e.each { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2} + # h.keep_if { |key, value| key.start_with?('b') } # => {bar: 1, baz: 2} + # + # With no block given, returns a new Enumerator. + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def keep_if: () { (K, V) -> boolish } -> self | () -> ::Enumerator[[ K, V ], self] # # Returns the key for the first-found entry with the given `value` (see [Entry # Order](rdoc-ref:Hash@Entry+Order)): + # # h = {foo: 0, bar: 2, baz: 2} # h.key(0) # => :foo # h.key(2) # => :bar # # Returns `nil` if no such value is found. # + # Related: see [Methods for Fetching](rdoc-ref:Hash@Methods+for+Fetching). + # def key: (V) -> K? # - # Returns `true` if `key` is a key in `self`, otherwise `false`. + # Returns whether `key` is a key in `self`: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.include?(:bar) # => true + # h.include?(:BAR) # => false + # + # Related: [Methods for Querying](rdoc-ref:Hash@Methods+for+Querying). # alias key? has_key? # - # Returns a new Array containing all keys in `self`: + # Returns a new array containing all keys in `self`: + # # h = {foo: 0, bar: 1, baz: 2} # h.keys # => [:foo, :bar, :baz] # + # Related: see [Methods for Fetching](rdoc-ref:Hash@Methods+for+Fetching). + # def keys: () -> ::Array[K] # # Returns the count of entries in `self`: # - # {foo: 0, bar: 1, baz: 2}.length # => 3 + # {foo: 0, bar: 1, baz: 2}.size # => 3 + # + # Related: see [Methods for Querying](rdoc-ref:Hash@Methods+for+Querying). # def length: () -> Integer # - # Returns `true` if `key` is a key in `self`, otherwise `false`. + # Returns whether `key` is a key in `self`: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.include?(:bar) # => true + # h.include?(:BAR) # => false + # + # Related: [Methods for Querying](rdoc-ref:Hash@Methods+for+Querying). # alias member? has_key? # - # Returns the new `Hash` formed by merging each of `other_hashes` into a copy of - # `self`. + # Each argument `other_hash` in `other_hashes` must be a hash. # - # Each argument in `other_hashes` must be a `Hash`. + # With arguments `other_hashes` given and no block, returns the new hash formed + # by merging each successive `other_hash` into a copy of `self`; returns that + # copy; for each successive entry in `other_hash`: # - # --- - # - # With arguments and no block: - # * Returns the new `Hash` object formed by merging each successive `Hash` in - # `other_hashes` into `self`. - # * Each new-key entry is added at the end. - # * Each duplicate-key entry's value overwrites the previous value. + # * For a new key, the entry is added at the end of `self`. + # * For duplicate key, the entry overwrites the entry in `self`, whose + # position is unchanged. # # Example: + # # h = {foo: 0, bar: 1, baz: 2} # h1 = {bat: 3, bar: 4} # h2 = {bam: 5, bat:6} - # h.merge(h1, h2) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5} + # h.merge(h1, h2) # => {foo: 0, bar: 4, baz: 2, bat: 6, bam: 5} # - # With arguments and a block: - # * Returns a new `Hash` object that is the merge of `self` and each given - # hash. - # * The given hashes are merged left to right. - # * Each new-key entry is added at the end. - # * For each duplicate key: - # * Calls the block with the key and the old and new values. - # * The block's return value becomes the new value for the entry. + # With arguments `other_hashes` and a block given, behaves as above except that + # for a duplicate key the overwriting entry takes it value not from the entry in + # `other_hash`, but instead from the block: + # + # * The block is called with the duplicate key and the values from both `self` + # and `other_hash`. + # * The block's return value becomes the new value for the entry in `self`. # # Example: + # # h = {foo: 0, bar: 1, baz: 2} # h1 = {bat: 3, bar: 4} # h2 = {bam: 5, bat:6} - # h3 = h.merge(h1, h2) { |key, old_value, new_value| old_value + new_value } - # h3 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5} + # h.merge(h1, h2) { |key, old_value, new_value| old_value + new_value } + # # => {foo: 0, bar: 5, baz: 2, bat: 9, bam: 5} # - # With no arguments: - # * Returns a copy of `self`. - # * The block, if given, is ignored. + # With no arguments, returns a copy of `self`; the block, if given, is ignored. # - # Example: - # h = {foo: 0, bar: 1, baz: 2} - # h.merge # => {:foo=>0, :bar=>1, :baz=>2} - # h1 = h.merge { |key, old_value, new_value| raise 'Cannot happen' } - # h1 # => {:foo=>0, :bar=>1, :baz=>2} + # Related: see [Methods for Assigning](rdoc-ref:Hash@Methods+for+Assigning). # def merge: [A, B] (*::Hash[A, B] other_hashes) -> ::Hash[A | K, B | V] | [A, B, C] (*::Hash[A, B] other_hashes) { (K key, V oldval, B newval) -> C } -> ::Hash[A | K, B | V | C] # - # Merges each of `other_hashes` into `self`; returns `self`. + # Updates values and/or adds entries to `self`; returns `self`. # - # Each argument in `other_hashes` must be a `Hash`. + # Each argument `other_hash` in `other_hashes` must be a hash. # - # With arguments and no block: - # * Returns `self`, after the given hashes are merged into it. - # * The given hashes are merged left to right. - # * Each new entry is added at the end. - # * Each duplicate-key entry's value overwrites the previous value. + # With no block given, for each successive entry `key`/`new_value` in each + # successive `other_hash`: # - # Example: - # h = {foo: 0, bar: 1, baz: 2} - # h1 = {bat: 3, bar: 4} - # h2 = {bam: 5, bat:6} - # h.merge!(h1, h2) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5} + # * If `key` is in `self`, sets `self[key] = new_value`, whose position is + # unchanged: # - # With arguments and a block: - # * Returns `self`, after the given hashes are merged. - # * The given hashes are merged left to right. - # * Each new-key entry is added at the end. - # * For each duplicate key: - # * Calls the block with the key and the old and new values. - # * The block's return value becomes the new value for the entry. + # h0 = {foo: 0, bar: 1, baz: 2} + # h1 = {bar: 3, foo: -1} + # h0.update(h1) # => {foo: -1, bar: 3, baz: 2} # - # Example: - # h = {foo: 0, bar: 1, baz: 2} - # h1 = {bat: 3, bar: 4} - # h2 = {bam: 5, bat:6} - # h3 = h.merge!(h1, h2) { |key, old_value, new_value| old_value + new_value } - # h3 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5} + # * If `key` is not in `self`, adds the entry at the end of `self`: # - # With no arguments: - # * Returns `self`, unmodified. - # * The block, if given, is ignored. + # h = {foo: 0, bar: 1, baz: 2} + # h.update({bam: 3, bah: 4}) # => {foo: 0, bar: 1, baz: 2, bam: 3, bah: 4} # - # Example: - # h = {foo: 0, bar: 1, baz: 2} - # h.merge # => {:foo=>0, :bar=>1, :baz=>2} - # h1 = h.merge! { |key, old_value, new_value| raise 'Cannot happen' } - # h1 # => {:foo=>0, :bar=>1, :baz=>2} + # With a block given, for each successive entry `key`/`new_value` in each + # successive `other_hash`: + # + # * If `key` is in `self`, fetches `old_value` from `self[key]`, calls the + # block with `key`, `old_value`, and `new_value`, and sets `self[key] = + # new_value`, whose position is unchanged : + # + # season = {AB: 75, H: 20, HR: 3, SO: 17, W: 11, HBP: 3} + # today = {AB: 3, H: 1, W: 1} + # yesterday = {AB: 4, H: 2, HR: 1} + # season.update(yesterday, today) {|key, old_value, new_value| old_value + new_value } + # # => {AB: 82, H: 23, HR: 4, SO: 17, W: 12, HBP: 3} + # + # * If `key` is not in `self`, adds the entry at the end of `self`: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.update({bat: 3}) { fail 'Cannot happen' } + # # => {foo: 0, bar: 1, baz: 2, bat: 3} + # + # Related: see [Methods for Assigning](rdoc-ref:Hash@Methods+for+Assigning). # def merge!: (*::Hash[K, V] other_hashes) -> self | (*::Hash[K, V] other_hashes) { (K key, V oldval, V newval) -> V } -> self # - # Returns a new 2-element Array consisting of the key and value of the - # first-found entry whose value is `==` to value (see [Entry - # Order](rdoc-ref:Hash@Entry+Order)): + # Searches `self` for the first entry whose value is `==` to the given `value`; + # see [Entry Order](rdoc-ref:Hash@Entry+Order). + # + # If the entry is found, returns its key and value as a 2-element array; returns + # `nil` if not found: + # # h = {foo: 0, bar: 1, baz: 1} # h.rassoc(1) # => [:bar, 1] # - # Returns `nil` if no such value found. + # Related: see [Methods for Fetching](rdoc-ref:Hash@Methods+for+Fetching). # def rassoc: (V) -> [ K, V ]? # - # Rebuilds the hash table by recomputing the hash index for each key; returns - # `self`. + # Rebuilds the hash table for `self` by recomputing the hash index for each key; + # returns `self`. Calling this method ensures that the hash table is valid. # # The hash table becomes invalid if the hash value of a key has changed after # the entry was created. See [Modifying an Active Hash @@ -1433,40 +1544,41 @@ class Hash[unchecked out K, unchecked out V] < Object # - # Returns a new `Hash` object whose entries are all those from `self` for which - # the block returns `false` or `nil`: - # h = {foo: 0, bar: 1, baz: 2} - # h1 = h.reject {|key, value| key.start_with?('b') } - # h1 # => {:foo=>0} + # With a block given, returns a copy of `self` with zero or more entries + # removed; calls the block with each key-value pair; excludes the entry in the + # copy if the block returns a truthy value, includes it otherwise: # - # Returns a new Enumerator if no block given: # h = {foo: 0, bar: 1, baz: 2} - # e = h.reject # => #0, :bar=>1, :baz=>2}:reject> - # h1 = e.each {|key, value| key.start_with?('b') } - # h1 # => {:foo=>0} + # h.reject {|key, value| key.start_with?('b') } + # # => {foo: 0} + # + # With no block given, returns a new Enumerator. + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def reject: () -> ::Enumerator[[ K, V ], ::Hash[K, V]] | () { (K, V) -> boolish } -> ::Hash[K, V] # - # Returns `self`, whose remaining entries are those for which the block returns - # `false` or `nil`: - # h = {foo: 0, bar: 1, baz: 2} - # h.reject! {|key, value| value < 2 } # => {:baz=>2} + # With a block given, calls the block with each entry's key and value; removes + # the entry from `self` if the block returns a truthy value. # - # Returns `nil` if no entries are removed. + # Return `self` if any entries were removed, `nil` otherwise: # - # Returns a new Enumerator if no block given: # h = {foo: 0, bar: 1, baz: 2} - # e = h.reject! # => #0, :bar=>1, :baz=>2}:reject!> - # e.each {|key, value| key.start_with?('b') } # => {:foo=>0} + # h.reject! {|key, value| value < 2 } # => {baz: 2} + # h.reject! {|key, value| value < 2 } # => nil + # + # With no block given, returns a new Enumerator. + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def reject!: () -> ::Enumerator[[ K, V ], self?] | () { (K, V) -> boolish } -> self? @@ -1474,147 +1586,182 @@ class Hash[unchecked out K, unchecked out V] < Object # # Replaces the entire contents of `self` with the contents of `other_hash`; # returns `self`: + # # h = {foo: 0, bar: 1, baz: 2} - # h.replace({bat: 3, bam: 4}) # => {:bat=>3, :bam=>4} + # h.replace({bat: 3, bam: 4}) # => {bat: 3, bam: 4} + # + # Also replaces the default value or proc of `self` with the default value or + # proc of `other_hash`. + # + # h = {} + # other = Hash.new(:ok) + # h.replace(other) + # h.default # => :ok + # + # Related: see [Methods for Assigning](rdoc-ref:Hash@Methods+for+Assigning). # def replace: (Hash[K, V]) -> self # - # Returns a new `Hash` object whose entries are those for which the block - # returns a truthy value: - # h = {foo: 0, bar: 1, baz: 2} - # h.select {|key, value| value < 2 } # => {:foo=>0, :bar=>1} + # With a block given, calls the block with each entry's key and value; returns a + # new hash whose entries are those for which the block returns a truthy value: # - # Returns a new Enumerator if no block given: # h = {foo: 0, bar: 1, baz: 2} - # e = h.select # => #0, :bar=>1, :baz=>2}:select> - # e.each {|key, value| value < 2 } # => {:foo=>0, :bar=>1} + # h.select {|key, value| value < 2 } # => {foo: 0, bar: 1} + # + # With no block given, returns a new Enumerator. + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # alias select filter # - # Returns `self`, whose entries are those for which the block returns a truthy - # value: - # h = {foo: 0, bar: 1, baz: 2} - # h.select! {|key, value| value < 2 } => {:foo=>0, :bar=>1} + # With a block given, calls the block with each entry's key and value; removes + # from `self` each entry for which the block returns `false` or `nil`. # - # Returns `nil` if no entries were removed. + # Returns `self` if any entries were removed, `nil` otherwise: # - # Returns a new Enumerator if no block given: # h = {foo: 0, bar: 1, baz: 2} - # e = h.select! # => #0, :bar=>1, :baz=>2}:select!> - # e.each { |key, value| value < 2 } # => {:foo=>0, :bar=>1} + # h.select! {|key, value| value < 2 } # => {foo: 0, bar: 1} + # h.select! {|key, value| value < 2 } # => nil + # + # With no block given, returns a new Enumerator. + # + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # alias select! filter! # - # Removes the first hash entry (see [Entry Order](rdoc-ref:Hash@Entry+Order)); - # returns a 2-element Array containing the removed key and value: + # Removes and returns the first entry of `self` as a 2-element array; see [Entry + # Order](rdoc-ref:Hash@Entry+Order): + # # h = {foo: 0, bar: 1, baz: 2} # h.shift # => [:foo, 0] - # h # => {:bar=>1, :baz=>2} + # h # => {bar: 1, baz: 2} + # + # Returns `nil` if `self` is empty. # - # Returns nil if the hash is empty. + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def shift: () -> [ K, V ]? # # Returns the count of entries in `self`: # - # {foo: 0, bar: 1, baz: 2}.length # => 3 + # {foo: 0, bar: 1, baz: 2}.size # => 3 + # + # Related: see [Methods for Querying](rdoc-ref:Hash@Methods+for+Querying). # alias size length # - # Returns a new `Hash` object containing the entries for the given `keys`: + # Returns a new hash containing the entries from `self` for the given `keys`; + # ignores any keys that are not found: + # # h = {foo: 0, bar: 1, baz: 2} - # h.slice(:baz, :foo) # => {:baz=>2, :foo=>0} + # h.slice(:baz, :foo, :nosuch) # => {baz: 2, foo: 0} # - # Any given `keys` that are not found are ignored. + # Related: see [Methods for Deleting](rdoc-ref:Hash@Methods+for+Deleting). # def slice: (*K) -> ::Hash[K, V] # - # Associates the given `value` with the given `key`; returns `value`. + # Associates the given `object` with the given `key`; returns `object`. + # + # Searches for a hash key equivalent to the given `key`; see [Hash Key + # Equivalence](rdoc-ref:Hash@Hash+Key+Equivalence). + # + # If the key is found, replaces its value with the given `object`; the ordering + # is not affected (see [Entry Order](rdoc-ref:Hash@Entry+Order)): # - # If the given `key` exists, replaces its value with the given `value`; the - # ordering is not affected (see [Entry Order](rdoc-ref:Hash@Entry+Order)): # h = {foo: 0, bar: 1} # h[:foo] = 2 # => 2 - # h.store(:bar, 3) # => 3 - # h # => {:foo=>2, :bar=>3} + # h[:foo] # => 2 + # + # If `key` is not found, creates a new entry for the given `key` and `object`; + # the new entry is last in the order (see [Entry + # Order](rdoc-ref:Hash@Entry+Order)): # - # If `key` does not exist, adds the `key` and `value`; the new entry is last in - # the order (see [Entry Order](rdoc-ref:Hash@Entry+Order)): # h = {foo: 0, bar: 1} # h[:baz] = 2 # => 2 - # h.store(:bat, 3) # => 3 - # h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3} + # h[:baz] # => 2 + # h # => {:foo=>0, :bar=>1, :baz=>2} + # + # Related: #[]; see also [Methods for + # Assigning](rdoc-ref:Hash@Methods+for+Assigning). # alias store []= # - # Returns a new Array of 2-element Array objects; each nested Array contains a - # key-value pair from `self`: + # Returns all elements of `self` as an array of 2-element arrays; each nested + # array contains a key-value pair from `self`: + # # h = {foo: 0, bar: 1, baz: 2} # h.to_a # => [[:foo, 0], [:bar, 1], [:baz, 2]] # + # Related: see [Methods for Converting](rdoc-ref:Hash@Methods+for+Converting). + # def to_a: () -> ::Array[[ K, V ]] # - # For an instance of `Hash`, returns `self`. + # With a block given, returns a new hash whose content is based on the block; + # the block is called with each entry's key and value; the block should return a + # 2-element array containing the key and value to be included in the returned + # array: # - # For a subclass of `Hash`, returns a new `Hash` containing the content of + # h = {foo: 0, bar: 1, baz: 2} + # h.to_h {|key, value| [value, key] } + # # => {0 => :foo, 1 => :bar, 2 => :baz} + # + # With no block given, returns `self` if `self` is an instance of `Hash`; if + # `self` is a subclass of `Hash`, returns a new hash containing the content of # `self`. # - # When a block is given, returns a new `Hash` object whose content is based on - # the block; the block should return a 2-element Array object specifying the - # key-value pair to be included in the returned Array: - # h = {foo: 0, bar: 1, baz: 2} - # h1 = h.to_h {|key, value| [value, key] } - # h1 # => {0=>:foo, 1=>:bar, 2=>:baz} + # Related: see [Methods for Converting](rdoc-ref:Hash@Methods+for+Converting). # def to_h: () -> Hash[K, V] | [A, B] () { (K, V) -> [ A, B ] } -> Hash[A, B] # # Returns `self`. # + # Related: see [Methods for Converting](rdoc-ref:Hash@Methods+for+Converting). + # def to_hash: () -> self # # Returns a Proc object that maps a key to its value: + # # h = {foo: 0, bar: 1, baz: 2} # proc = h.to_proc # proc.class # => Proc @@ -1622,227 +1769,366 @@ class Hash[unchecked out K, unchecked out V] < Object # proc.call(:bar) # => 1 # proc.call(:nosuch) # => nil # + # Related: see [Methods for Converting](rdoc-ref:Hash@Methods+for+Converting). + # def to_proc: () -> ^(K) -> V? # - # Returns a new String containing the hash entries: + # Returns a new string containing the hash entries: # # h = {foo: 0, bar: 1, baz: 2} # h.inspect # => "{foo: 0, bar: 1, baz: 2}" # + # Related: see [Methods for Converting](rdoc-ref:Hash@Methods+for+Converting). + # alias to_s inspect # - # Returns a new `Hash` object; each entry has: - # * A key provided by the block. - # * The value from `self`. + # With an argument, a block, or both given, derives a new hash `new_hash` from + # `self`, the argument, and/or the block; all, some, or none of its keys may be + # different from those in `self`. # - # An optional hash argument can be provided to map keys to new keys. Any key not - # given will be mapped using the provided block, or remain the same if no block - # is given. + # With a block given and no argument, `new_hash` has keys determined only by the + # block. + # + # For each key/value pair `old_key/value` in `self`, calls the block with + # `old_key`; the block's return value becomes `new_key`; sets `new_hash[new_key] + # = value`; a duplicate key overwrites: # - # Transform keys: # h = {foo: 0, bar: 1, baz: 2} - # h1 = h.transform_keys {|key| key.to_s } - # h1 # => {"foo"=>0, "bar"=>1, "baz"=>2} + # h.transform_keys {|old_key| old_key.to_s } + # # => {"foo" => 0, "bar" => 1, "baz" => 2} + # h.transform_keys {|old_key| 'xxx' } + # # => {"xxx" => 2} # - # h.transform_keys(foo: :bar, bar: :foo) - # #=> {bar: 0, foo: 1, baz: 2} + # With argument `other_hash` given and no block, `new_hash` may have new keys + # provided by `other_hash` and unchanged keys provided by `self`. # - # h.transform_keys(foo: :hello, &:to_s) - # #=> {:hello=>0, "bar"=>1, "baz"=>2} + # For each key/value pair `old_key/old_value` in `self`, looks for key `old_key` + # in `other_hash`: # - # Overwrites values for duplicate keys: - # h = {foo: 0, bar: 1, baz: 2} - # h1 = h.transform_keys {|key| :bat } - # h1 # => {:bat=>2} + # * If `old_key` is found, its value `other_hash[old_key]` is taken as + # `new_key`; sets `new_hash[new_key] = value`; a duplicate key overwrites: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys(baz: :BAZ, bar: :BAR, foo: :FOO) + # # => {FOO: 0, BAR: 1, BAZ: 2} + # h.transform_keys(baz: :FOO, bar: :FOO, foo: :FOO) + # # => {FOO: 2} + # + # * If `old_key` is not found, sets `new_hash[old_key] = value`; a duplicate + # key overwrites: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys({}) + # # => {foo: 0, bar: 1, baz: 2} + # h.transform_keys(baz: :foo) + # # => {foo: 2, bar: 1} + # + # Unused keys in `other_hash` are ignored: # - # Returns a new Enumerator if no block given: # h = {foo: 0, bar: 1, baz: 2} - # e = h.transform_keys # => #0, :bar=>1, :baz=>2}:transform_keys> - # h1 = e.each { |key| key.to_s } - # h1 # => {"foo"=>0, "bar"=>1, "baz"=>2} + # h.transform_keys(bat: 3) + # # => {foo: 0, bar: 1, baz: 2} + # + # With both argument `other_hash` and a block given, `new_hash` has new keys + # specified by `other_hash` or by the block, and unchanged keys provided by + # `self`. + # + # For each pair `old_key` and `value` in `self`: + # + # * If `other_hash` has key `old_key` (with value `new_key`), does not call + # the block for that key; sets `new_hash[new_key] = value`; a duplicate key + # overwrites: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys(baz: :BAZ, bar: :BAR, foo: :FOO) {|key| fail 'Not called' } + # # => {FOO: 0, BAR: 1, BAZ: 2} + # + # * If `other_hash` does not have key `old_key`, calls the block with + # `old_key` and takes its return value as `new_key`; sets `new_hash[new_key] + # = value`; a duplicate key overwrites: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys(baz: :BAZ) {|key| key.to_s.reverse } + # # => {"oof" => 0, "rab" => 1, BAZ: 2} + # h.transform_keys(baz: :BAZ) {|key| 'ook' } + # # => {"ook" => 1, BAZ: 2} + # + # With no argument and no block given, returns a new Enumerator. + # + # Related: see [Methods for Transforming Keys and + # Values](rdoc-ref:Hash@Methods+for+Transforming+Keys+and+Values). # def transform_keys: () -> Enumerator[K, Hash[untyped, V]] | [A] () { (K) -> A } -> Hash[A, V] # - # Same as Hash#transform_keys but modifies the receiver in place instead of - # returning a new hash. + # With an argument, a block, or both given, derives keys from the argument, the + # block, and `self`; all, some, or none of the keys in `self` may be changed. + # + # With a block given and no argument, derives keys only from the block; all, + # some, or none of the keys in `self` may be changed. + # + # For each key/value pair `old_key/value` in `self`, calls the block with + # `old_key`; the block's return value becomes `new_key`; removes the entry for + # `old_key`: `self.delete(old_key)`; sets `self[new_key] = value`; a duplicate + # key overwrites: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys! {|old_key| old_key.to_s } + # # => {"foo" => 0, "bar" => 1, "baz" => 2} + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys! {|old_key| 'xxx' } + # # => {"xxx" => 2} + # + # With argument `other_hash` given and no block, derives keys for `self` from + # `other_hash` and `self`; all, some, or none of the keys in `self` may be + # changed. + # + # For each key/value pair `old_key/old_value` in `self`, looks for key `old_key` + # in `other_hash`: + # + # * If `old_key` is found, takes value `other_hash[old_key]` as `new_key`; + # removes the entry for `old_key`: `self.delete(old_key)`; sets + # `self[new_key] = value`; a duplicate key overwrites: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys!(baz: :BAZ, bar: :BAR, foo: :FOO) + # # => {FOO: 0, BAR: 1, BAZ: 2} + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys!(baz: :FOO, bar: :FOO, foo: :FOO) + # # => {FOO: 2} + # + # * If `old_key` is not found, does nothing: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys!({}) + # # => {foo: 0, bar: 1, baz: 2} + # h.transform_keys!(baz: :foo) + # # => {foo: 2, bar: 1} + # + # Unused keys in `other_hash` are ignored: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys!(bat: 3) + # # => {foo: 0, bar: 1, baz: 2} + # + # With both argument `other_hash` and a block given, derives keys from + # `other_hash`, the block, and `self`; all, some, or none of the keys in `self` + # may be changed. + # + # For each pair `old_key` and `value` in `self`: + # + # * If `other_hash` has key `old_key` (with value `new_key`), does not call + # the block for that key; removes the entry for `old_key`: + # `self.delete(old_key)`; sets `self[new_key] = value`; a duplicate key + # overwrites: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys!(baz: :BAZ, bar: :BAR, foo: :FOO) {|key| fail 'Not called' } + # # => {FOO: 0, BAR: 1, BAZ: 2} + # + # * If `other_hash` does not have key `old_key`, calls the block with + # `old_key` and takes its return value as `new_key`; removes the entry for + # `old_key`: `self.delete(old_key)`; sets `self[new_key] = value`; a + # duplicate key overwrites: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys!(baz: :BAZ) {|key| key.to_s.reverse } + # # => {"oof" => 0, "rab" => 1, BAZ: 2} + # h = {foo: 0, bar: 1, baz: 2} + # h.transform_keys!(baz: :BAZ) {|key| 'ook' } + # # => {"ook" => 1, BAZ: 2} + # + # With no argument and no block given, returns a new Enumerator. + # + # Related: see [Methods for Transforming Keys and + # Values](rdoc-ref:Hash@Methods+for+Transforming+Keys+and+Values). # def transform_keys!: () -> Enumerator[K, self] | () { (K) -> K } -> self # - # Returns a new `Hash` object; each entry has: - # * A key from `self`. - # * A value provided by the block. + # With a block given, returns a new hash `new_hash`; for each pair `key`/`value` + # in `self`, calls the block with `value` and captures its return as + # `new_value`; adds to `new_hash` the entry `key`/`new_value`: # - # Transform values: # h = {foo: 0, bar: 1, baz: 2} # h1 = h.transform_values {|value| value * 100} - # h1 # => {:foo=>0, :bar=>100, :baz=>200} + # h1 # => {foo: 0, bar: 100, baz: 200} # - # Returns a new Enumerator if no block given: - # h = {foo: 0, bar: 1, baz: 2} - # e = h.transform_values # => #0, :bar=>1, :baz=>2}:transform_values> - # h1 = e.each { |value| value * 100} - # h1 # => {:foo=>0, :bar=>100, :baz=>200} + # With no block given, returns a new Enumerator. + # + # Related: see [Methods for Transforming Keys and + # Values](rdoc-ref:Hash@Methods+for+Transforming+Keys+and+Values). # def transform_values: () -> Enumerator[V, Hash[K, untyped]] | [A] () { (V) -> A } -> Hash[K, A] # - # Returns `self`, whose keys are unchanged, and whose values are determined by - # the given block. - # h = {foo: 0, bar: 1, baz: 2} - # h.transform_values! {|value| value * 100} # => {:foo=>0, :bar=>100, :baz=>200} + # With a block given, changes the values of `self` as determined by the block; + # returns `self`. + # + # For each entry `key`/`old_value` in `self`, calls the block with `old_value`, + # captures its return value as `new_value`, and sets `self[key] = new_value`: # - # Returns a new Enumerator if no block given: # h = {foo: 0, bar: 1, baz: 2} - # e = h.transform_values! # => #0, :bar=>100, :baz=>200}:transform_values!> - # h1 = e.each {|value| value * 100} - # h1 # => {:foo=>0, :bar=>100, :baz=>200} + # h.transform_values! {|value| value * 100} # => {foo: 0, bar: 100, baz: 200} + # + # With no block given, returns a new Enumerator. + # + # Related: see [Methods for Transforming Keys and + # Values](rdoc-ref:Hash@Methods+for+Transforming+Keys+and+Values). # def transform_values!: () -> Enumerator[V, self] | () { (V) -> V } -> self # - # Merges each of `other_hashes` into `self`; returns `self`. + # Updates values and/or adds entries to `self`; returns `self`. # - # Each argument in `other_hashes` must be a `Hash`. + # Each argument `other_hash` in `other_hashes` must be a hash. # - # With arguments and no block: - # * Returns `self`, after the given hashes are merged into it. - # * The given hashes are merged left to right. - # * Each new entry is added at the end. - # * Each duplicate-key entry's value overwrites the previous value. + # With no block given, for each successive entry `key`/`new_value` in each + # successive `other_hash`: # - # Example: - # h = {foo: 0, bar: 1, baz: 2} - # h1 = {bat: 3, bar: 4} - # h2 = {bam: 5, bat:6} - # h.merge!(h1, h2) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5} + # * If `key` is in `self`, sets `self[key] = new_value`, whose position is + # unchanged: # - # With arguments and a block: - # * Returns `self`, after the given hashes are merged. - # * The given hashes are merged left to right. - # * Each new-key entry is added at the end. - # * For each duplicate key: - # * Calls the block with the key and the old and new values. - # * The block's return value becomes the new value for the entry. + # h0 = {foo: 0, bar: 1, baz: 2} + # h1 = {bar: 3, foo: -1} + # h0.update(h1) # => {foo: -1, bar: 3, baz: 2} # - # Example: - # h = {foo: 0, bar: 1, baz: 2} - # h1 = {bat: 3, bar: 4} - # h2 = {bam: 5, bat:6} - # h3 = h.merge!(h1, h2) { |key, old_value, new_value| old_value + new_value } - # h3 # => {:foo=>0, :bar=>5, :baz=>2, :bat=>9, :bam=>5} + # * If `key` is not in `self`, adds the entry at the end of `self`: # - # With no arguments: - # * Returns `self`, unmodified. - # * The block, if given, is ignored. + # h = {foo: 0, bar: 1, baz: 2} + # h.update({bam: 3, bah: 4}) # => {foo: 0, bar: 1, baz: 2, bam: 3, bah: 4} # - # Example: - # h = {foo: 0, bar: 1, baz: 2} - # h.merge # => {:foo=>0, :bar=>1, :baz=>2} - # h1 = h.merge! { |key, old_value, new_value| raise 'Cannot happen' } - # h1 # => {:foo=>0, :bar=>1, :baz=>2} + # With a block given, for each successive entry `key`/`new_value` in each + # successive `other_hash`: + # + # * If `key` is in `self`, fetches `old_value` from `self[key]`, calls the + # block with `key`, `old_value`, and `new_value`, and sets `self[key] = + # new_value`, whose position is unchanged : + # + # season = {AB: 75, H: 20, HR: 3, SO: 17, W: 11, HBP: 3} + # today = {AB: 3, H: 1, W: 1} + # yesterday = {AB: 4, H: 2, HR: 1} + # season.update(yesterday, today) {|key, old_value, new_value| old_value + new_value } + # # => {AB: 82, H: 23, HR: 4, SO: 17, W: 12, HBP: 3} + # + # * If `key` is not in `self`, adds the entry at the end of `self`: + # + # h = {foo: 0, bar: 1, baz: 2} + # h.update({bat: 3}) { fail 'Cannot happen' } + # # => {foo: 0, bar: 1, baz: 2, bat: 3} + # + # Related: see [Methods for Assigning](rdoc-ref:Hash@Methods+for+Assigning). # alias update merge! # - # Returns `true` if `value` is a value in `self`, otherwise `false`. + # Returns whether `value` is a value in `self`. + # + # Related: [Methods for Querying](rdoc-ref:Hash@Methods+for+Querying). # alias value? has_value? # - # Returns a new Array containing all values in `self`: + # Returns a new array containing all values in `self`: + # # h = {foo: 0, bar: 1, baz: 2} # h.values # => [0, 1, 2] # + # Related: see [Methods for Fetching](rdoc-ref:Hash@Methods+for+Fetching). + # def values: () -> ::Array[V] # - # Returns a new Array containing values for the given `keys`: + # Returns a new array containing values for the given `keys`: + # # h = {foo: 0, bar: 1, baz: 2} # h.values_at(:baz, :foo) # => [2, 0] # - # The [default values](rdoc-ref:Hash@Default+Values) are returned for any keys - # that are not found: + # The [hash default](rdoc-ref:Hash@Hash+Default) is returned for each key that + # is not found: + # # h.values_at(:hello, :foo) # => [nil, 0] # + # Related: see [Methods for Fetching](rdoc-ref:Hash@Methods+for+Fetching). + # def values_at: (*K arg0) -> ::Array[V?] private # - # Returns a new empty `Hash` object. + # Returns a new empty Hash object. # - # The initial default value and initial default proc for the new hash depend on - # which form above was used. See [Default Values](rdoc-ref:Hash@Default+Values). + # Initializes the values of Hash#default and Hash#default_proc, which determine + # the behavior when a given key is not found; see [Key Not + # Found?](rdoc-ref:Hash@Key+Not+Found-3F). # - # If neither an argument nor a block is given, initializes both the default - # value and the default proc to `nil`: - # h = Hash.new - # h.default # => nil - # h.default_proc # => nil + # By default, a hash has `nil` values for both `default` and `default_proc`: # - # If argument `default_value` is given but no block is given, initializes the - # default value to the given `default_value` and the default proc to `nil`: - # h = Hash.new(false) - # h.default # => false - # h.default_proc # => nil + # h = Hash.new # => {} + # h.default # => nil + # h.default_proc # => nil # - # If a block is given but no `default_value`, stores the block as the default - # proc and sets the default value to `nil`: - # h = Hash.new {|hash, key| "Default value for #{key}" } - # h.default # => nil - # h.default_proc.class # => Proc - # h[:nosuch] # => "Default value for nosuch" + # With argument `default_value` given, sets the `default` value for the hash: # - # If both a block and a `default_value` are given, raises an `ArgumentError` + # h = Hash.new(false) # => {} + # h.default # => false + # h.default_proc # => nil # - # If the optional keyword argument `capacity` is given, the hash will be - # allocated with enough capacity to accommodate this many keys without having to - # be resized. + # With a block given, sets the `default_proc` value: + # + # h = Hash.new {|hash, key| "Hash #{hash}: Default value for #{key}" } + # h.default # => nil + # h.default_proc # => # + # h[:nosuch] # => "Hash {}: Default value for nosuch" + # + # Raises ArgumentError if both `default_value` and a block are given. + # + # If optional keyword argument `capacity` is given with a positive integer value + # `n`, initializes the hash with enough capacity to accommodate `n` entries + # without resizing. + # + # See also [Methods for Creating a + # Hash](rdoc-ref:Hash@Methods+for+Creating+a+Hash). # def initialize: (?capacity: int) -> void | (V default, ?capacity: int) -> void @@ -1850,12 +2136,23 @@ class Hash[unchecked out K, unchecked out V] < Object # # Replaces the entire contents of `self` with the contents of `other_hash`; # returns `self`: + # # h = {foo: 0, bar: 1, baz: 2} - # h.replace({bat: 3, bam: 4}) # => {:bat=>3, :bam=>4} + # h.replace({bat: 3, bam: 4}) # => {bat: 3, bam: 4} + # + # Also replaces the default value or proc of `self` with the default value or + # proc of `other_hash`. + # + # h = {} + # other = Hash.new(:ok) + # h.replace(other) + # h.default # => :ok + # + # Related: see [Methods for Assigning](rdoc-ref:Hash@Methods+for+Assigning). # def initialize_copy: (self object) -> self end diff --git a/core/io.rbs b/core/io.rbs index 0284fecde..ec722ecfb 100644 --- a/core/io.rbs +++ b/core/io.rbs @@ -2361,8 +2361,9 @@ class IO < Object # closed (eventually) to avoid resource leaks. # # If a block is given, the stream is passed to the block (again, open for - # reading, writing, or both); when the block exits, the stream is closed, and - # the block's value is assigned to global variable `$?` and returned. + # reading, writing, or both); when the block exits, the stream is closed, the + # block's value is returned, and the global variable `$?` is set to the child's + # exit status. # # Optional argument `mode` may be any valid IO mode. See [Access # Modes](rdoc-ref:File@Access+Modes). @@ -2391,7 +2392,7 @@ class IO < Object # * [Encoding options](rdoc-ref:encodings.rdoc@Encoding+Options). # * Options for Kernel#spawn. # - # **Forked \Process** + # **Forked Process** # # When argument `cmd` is the 1-character string `'-'`, causes the process to # fork: @@ -2785,7 +2786,8 @@ class IO < Object # IO objects. # # Argument `timeout` is a numeric value (such as integer or float) timeout - # interval in seconds. + # interval in seconds. `timeout` can also be `nil` or `Float::INFINITY`. `nil` + # and `Float::INFINITY` means no timeout. # # The method monitors the IO objects given in all three arrays, waiting for some # to be ready; returns a 3-element array whose elements are: diff --git a/core/io/wait.rbs b/core/io/wait.rbs index 476082766..e045f624c 100644 --- a/core/io/wait.rbs +++ b/core/io/wait.rbs @@ -1,9 +1,9 @@ %a{annotate:rdoc:skip} class IO # # Waits until the IO becomes ready for the specified events and returns the # subset of events that become ready, or a falsy value when times out. @@ -11,11 +11,14 @@ class IO # The events can be a bit mask of `IO::READABLE`, `IO::WRITABLE` or # `IO::PRIORITY`. # - # Returns a truthy value immediately when buffered data is available. - # - # Optional parameter `mode` is one of `:read`, `:write`, or `:read_write`. + # Returns an event mask (truthy value) immediately when buffered data is + # available. # - # You must require 'io/wait' to use this method. + # The second form: if one or more event symbols (`:read`, `:write`, or + # `:read_write`) are passed, the event mask is the bit OR of the bitmask + # corresponding to those symbols. In this form, `timeout` is optional, the + # order of the arguments is arbitrary, and returns `io` if any of the events is + # ready. # def wait: (Integer events, ?Time::_Timeout timeout) -> (Integer | false | nil) | (?Time::_Timeout? timeout, *wait_mode mode) -> (self | true | false) @@ -23,7 +26,7 @@ class IO type wait_mode = :read | :r | :readable | :write | :w | :writable | :read_write | :rw | :readable_writable # @@ -31,19 +34,15 @@ class IO # times out. Returns a truthy value immediately when buffered data is # available. # - # You must require 'io/wait' to use this method. - # def wait_readable: (?Time::_Timeout? timeout) -> boolish # # Waits until IO is writable and returns a truthy value or a falsy value when # times out. # - # You must require 'io/wait' to use this method. - # def wait_writable: (?Time::_Timeout? timeout) -> boolish end diff --git a/core/kernel.rbs b/core/kernel.rbs index b50e58111..501ec6ecd 100644 --- a/core/kernel.rbs +++ b/core/kernel.rbs @@ -80,7 +80,7 @@ # * #print: Prints the given objects to standard output without a newline. # * #printf: Prints the string resulting from applying the given format string # to any additional arguments. -# * #putc: Equivalent to for the given object. +# * #putc: Equivalent to `$stdout.putc(object)` for the given object. # * #puts: Equivalent to `$stdout.puts(*objects)` for the given objects. # * #readline: Similar to #gets, but raises an exception at the end of file. # * #readlines: Returns an array of the remaining lines from the current @@ -725,7 +725,7 @@ module Kernel : BasicObject # $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n" # $ `echo oops && exit 99` # => "oops\n" # $ $? # => # - # $ $?.status # => 99> + # $ $?.exitstatus # => 99 # # The built-in syntax `%x{...}` uses this method. # @@ -777,6 +777,8 @@ module Kernel : BasicObject # If *const* is defined as autoload, the file name to be loaded is replaced with # *filename*. If *const* is defined but not as autoload, does nothing. # + # Files that are currently being loaded must not be registered for autoload. + # def self?.autoload: (interned _module, String filename) -> NilClass # + # Returns "exp(x) - 1", `e` raised to the `x` power, minus 1. + # + # * Domain: `[-INFINITY, INFINITY]`. + # * Range: `[-1.0, INFINITY]`. + # + # Examples: + # + # expm1(-INFINITY) # => 0.0 + # expm1(-1.0) # => -0.6321205588285577 # 1.0/E - 1 + # expm1(0.0) # => 0.0 + # expm1(0.5) # => 0.6487212707001282 # sqrt(E) - 1 + # expm1(1.0) # => 1.718281828459045 # E - 1 + # expm1(2.0) # => 6.38905609893065 # E**2 - 1 + # expm1(INFINITY) # => Infinity + # + def self.expm1: (double x) -> Float + # + # Returns "log(x + 1)", the base E + # [logarithm](https://en.wikipedia.org/wiki/Logarithm) of (`x` + 1). + # + # * Domain: `[-1, INFINITY]`. + # * Range: `[-INFINITY, INFINITY]`. + # + # Examples: + # + # log1p(-1.0) # => -Infinity + # log1p(0.0) # => 0.0 + # log1p(E - 1) # => 1.0 + # log1p(INFINITY) # => Infinity + # + def self.log1p: (double x) -> Float + # -# Method objects are created by Object#method, and are associated with a +# `Method` objects are created by Object#method, and are associated with a # particular object (not just with a class). They may be used to invoke the # method within the object, and as a block associated with an iterator. They # may also be unbound from one object (creating an UnboundMethod) and bound to @@ -359,10 +359,18 @@ class Method # - # Returns the Ruby source filename and line number containing this method or nil - # if this method was not defined in Ruby (i.e. native). + # Returns the location where the method was defined. The returned Array + # contains: + # (1) the Ruby source filename + # (2) the line number where the definition starts + # (3) the column number where the definition starts + # (4) the line number where the definition ends + # (5) the column number where the definitions ends + # + # This method will return `nil` if the method was not defined in Ruby (i.e. + # native). # def source_location: () -> [String, Integer]? @@ -370,8 +378,8 @@ class Method # rdoc-file=proc.c # - meth.super_method -> method # --> - # Returns a Method of superclass which would be called when super is used or nil - # if there is no method on superclass. + # Returns a `Method` of superclass which would be called when super is used or + # nil if there is no method on superclass. # def super_method: () -> Method? diff --git a/core/module.rbs b/core/module.rbs index 5ef147f91..cbe46127b 100644 --- a/core/module.rbs +++ b/core/module.rbs @@ -328,6 +328,8 @@ class Module < Object # replaced with *filename*. If *const* is defined but not as autoload, does # nothing. # + # Files that are currently being loaded must not be registered for autoload. + # def autoload: (interned _module, String filename) -> NilClass # - # With no arguments, sets the default visibility for subsequently defined - # methods to protected. With arguments, sets the named methods to have protected - # visibility. String arguments are converted to symbols. An Array of Symbols - # and/or Strings is also accepted. If a single argument is passed, it is - # returned. If no argument is passed, nil is returned. If multiple arguments are - # passed, the arguments are returned as an array. + # Sets the visibility of a section or of a list of method names as protected. + # Accepts no arguments, a splat of method names (symbols or strings) or an array + # of method names. Returns the arguments that it received. + # + # ## Important difference between protected in other languages + # + # Protected methods in Ruby are different from other languages such as Java, + # where methods are marked as protected to give access to subclasses. In Ruby, + # subclasses **already have access to all methods defined in the parent class**, + # even private ones. + # + # Marking a method as protected allows **different objects of the same class** + # to call it. + # + # One use case is for comparison methods, such as `==`, if we want to expose a + # method for comparison between objects of the same class without making the + # method public to objects of other classes. + # + # ## Performance considerations + # + # Protected methods are slower than others because they can't use inline cache. + # + # ## Example + # + # class Account + # # Mark balance as protected, so that we can compare between accounts + # # without making it public. + # attr_reader :balance + # protected :balance + # + # def initialize(balance) + # @balance = balance + # end + # + # def >(other) + # # The invocation to `other.balance` is allowed because `other` is a + # # different object of the same class (Account). + # balance > other.balance + # end + # end # - # If a method has protected visibility, it is callable only where `self` of the - # context is the same as the method. (method definition or instance_eval). This - # behavior is different from Java's protected method. Usually `private` should - # be used. + # account1 = Account.new(100) + # account2 = Account.new(50) # - # Note that a protected method is slow because it can't use inline cache. + # account1 > account2 # => true (works) + # account1.balance # => NoMethodError (fails because balance is not public) # # To show a private method on RDoc, use `:doc:` instead of this. # diff --git a/core/nil_class.rbs b/core/nil_class.rbs index 11d78947e..d422b30df 100644 --- a/core/nil_class.rbs +++ b/core/nil_class.rbs @@ -112,7 +112,7 @@ class NilClass def nil?: () -> true # # Returns zero as a Rational: @@ -134,7 +134,7 @@ class NilClass def to_a: () -> [] # # Returns zero as a Complex: @@ -174,7 +174,7 @@ class NilClass def to_i: () -> 0 # # Returns zero as a Rational: diff --git a/core/numeric.rbs b/core/numeric.rbs index 3cba27149..02a4f881f 100644 --- a/core/numeric.rbs +++ b/core/numeric.rbs @@ -530,17 +530,17 @@ class Numeric # rdoc-file=numeric.c # - nonzero? -> self or nil # --> - # Returns +self+ if +self+ is not a zero value, +nil+ otherwise; - # uses method zero? for the evaluation. + # Returns `self` if `self` is not a zero value, `nil` otherwise; uses method + # `zero?` for the evaluation. # - # The returned +self+ allows the method to be chained: + # The returned `self` allows the method to be chained: # - # a = %w[z Bb bB bb BB a aA Aa AA A] - # a.sort {|a, b| (a.downcase <=> b.downcase).nonzero? || a <=> b } - # # => ["A", "a", "AA", "Aa", "aA", "BB", "Bb", "bB", "bb", "z"] + # a = %w[z Bb bB bb BB a aA Aa AA A] + # a.sort {|a, b| (a.downcase <=> b.downcase).nonzero? || a <=> b } + # # => ["A", "a", "AA", "Aa", "aA", "BB", "Bb", "bB", "bb", "z"] # - # Of the Core and Standard Library classes, - # Integer, Float, Rational, and Complex use this implementation. + # Of the Core and Standard Library classes, Integer, Float, Rational, and + # Complex use this implementation. # # Related: #zero? # diff --git a/core/object.rbs b/core/object.rbs index 5cb73e673..99ad20486 100644 --- a/core/object.rbs +++ b/core/object.rbs @@ -40,7 +40,7 @@ # * #instance_of?: Returns whether `self` is an instance of the given class. # * #instance_variable_defined?: Returns whether the given instance variable # is defined in `self`. -# * #method: Returns the Method object for the given method in `self`. +# * #method: Returns the `Method` object for the given method in `self`. # * #methods: Returns an array of symbol names of public and protected methods # in `self`. # * #nil?: Returns `false`. (Only `nil` responds `true` to method `nil?`.) @@ -50,13 +50,13 @@ # methods in `self`. # * #protected_methods: Returns an array of the symbol names of the protected # methods in `self`. -# * #public_method: Returns the Method object for the given public method in +# * #public_method: Returns the `Method` object for the given public method in # `self`. # * #public_methods: Returns an array of the symbol names of the public # methods in `self`. # * #respond_to?: Returns whether `self` responds to the given method. # * #singleton_class: Returns the singleton class of `self`. -# * #singleton_method: Returns the Method object for the given singleton +# * #singleton_method: Returns the `Method` object for the given singleton # method in `self`. # * #singleton_methods: Returns an array of the symbol names of the singleton # methods in `self`. diff --git a/core/object_space.rbs b/core/object_space.rbs index 9b6152c2c..8e58cefe6 100644 --- a/core/object_space.rbs +++ b/core/object_space.rbs @@ -29,6 +29,7 @@ module ObjectSpace # - _id2ref(p1) # --> # + %a{deprecated} def self._id2ref: (Integer id) -> untyped # +# +# # pathname.rb +# +# Object-Oriented Pathname Class +# +# Author +# : Tanaka Akira +# +# Documentation +# : Author and Gavin Sinclair +# +# +# For documentation, see class Pathname. +# +# # Pathname represents the name of a file or directory on the filesystem, but not # the file itself. # @@ -113,6 +127,13 @@ # ### File property and manipulation methods # # These methods are a facade for File: +# * #each_line(*args, &block) +# * #read(*args) +# * #binread(*args) +# * #readlines(*args) +# * #sysopen(*args) +# * #write(*args) +# * #binwrite(*args) # * #atime # * #birthtime # * #ctime @@ -151,17 +172,6 @@ # * #mkdir(*args) # * #opendir(*args) # -# ### IO -# -# These methods are a facade for IO: -# * #each_line(*args, &block) -# * #read(*args) -# * #binread(*args) -# * #readlines(*args) -# * #sysopen(*args) -# * #write(*args) -# * #binwrite(*args) -# # ### Utilities # # These methods are a mixture of Find, FileUtils, and others: @@ -180,47 +190,31 @@ # class Pathname # - # Returns the current working directory as a Pathname. - # - # Pathname.getwd - # #=> # - # - # See Dir.getwd. + # See `Dir.getwd`. Returns the current working directory as a Pathname. # def self.getwd: () -> Pathname # - # Returns or yields Pathname objects. - # - # Pathname.glob("lib/i*.rb") - # #=> [#, #] - # - # See Dir.glob. + # See `Dir.glob`. Returns or yields Pathname objects. # def self.glob: (String | Array[String] pattern, ?Integer flags) -> Array[Pathname] | (String | Array[String] pattern, ?Integer flags) { (Pathname) -> untyped } -> nil # - # Returns the current working directory as a Pathname. - # - # Pathname.getwd - # #=> # - # - # See Dir.getwd. # def self.pwd: () -> Pathname # # Appends a pathname fragment to `self` to produce a new Pathname object. Since @@ -240,14 +234,14 @@ class Pathname def +: (Pathname | String | _ToStr other) -> Pathname # # alias / + # # Provides a case-sensitive comparison operator for pathnames. @@ -267,8 +261,8 @@ class Pathname | (untyped other) -> nil # # Compare this pathname with `other`. The comparison is string-based. Be aware # that two different paths (`foo.txt` and `./foo.txt`) can refer to the same @@ -276,15 +270,15 @@ class Pathname # def ==: (untyped) -> bool - # - # Compare this pathname with `other`. The comparison is string-based. Be aware - # that two different paths (`foo.txt` and `./foo.txt`) can refer to the same - # file. + # # def ===: (untyped) -> bool # # Predicate method for testing whether a path is absolute. @@ -302,7 +296,7 @@ class Pathname def absolute?: () -> bool # # Iterates over and yields a new Pathname object for each element in the given @@ -334,39 +328,33 @@ class Pathname | () -> Enumerator[Pathname, nil] # - # Returns the last access time for the file. - # - # See File.atime. + # See `File.atime`. Returns last access time. # def atime: () -> Time # - # Returns the last component of the path. - # - # See File.basename. + # See `File.basename`. Returns the last component of the path. # def basename: (?String | _ToStr suffix) -> Pathname # - # Returns all the bytes from the file, or the first `N` if specified. - # - # See File.binread. + # See `File.binread`. Returns all the bytes from the file, or the first `N` if + # specified. # def binread: (?Integer length, ?Integer offset) -> String # # Writes `contents` to the file, opening it in binary mode. # @@ -375,8 +363,8 @@ class Pathname def binwrite: (String, ?Integer offset, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?invalid: :replace ?, ?undef: :replace ?, ?replace: String, ?fallback: Hash[String, String] | Proc | Method, ?xml: :text | :attr, ?universal_newline: true, ?cr_newline: true, ?crlf_newline: true) -> Integer # # Returns the birth time for the file. If the platform doesn't have birthtime, # raises NotImplementedError. @@ -386,23 +374,23 @@ class Pathname def birthtime: () -> Time # - # See FileTest.blockdev?. + # See `FileTest.blockdev?`. # def blockdev?: () -> bool # - # See FileTest.chardev?. + # See `FileTest.chardev?`. # def chardev?: () -> bool # # Returns the children of the directory (files and subdirectories, not @@ -427,27 +415,23 @@ class Pathname def children: (?boolish with_directory) -> Array[Pathname] # - # Changes file permissions. - # - # See File.chmod. + # See `File.chmod`. Changes permissions. # def chmod: (Integer mode_int) -> Integer # - # Change owner and group of the file. - # - # See File.chown. + # See `File.chown`. Change owner and group of file. # def chown: (Integer owner, Integer group) -> Integer # # Returns clean pathname of `self` with consecutive slashes and useless dots @@ -463,24 +447,22 @@ class Pathname def cleanpath: (?boolish consider_symlink) -> Pathname # - # Returns the last change time, using directory information, not the file - # itself. - # - # See File.ctime. + # See `File.ctime`. Returns last (directory entry, not file) change time. # def ctime: () -> Time - # - # Removes a file or directory, using File.unlink if `self` is a file, or - # Dir.unlink as necessary. + # # def delete: () -> Integer # # Iterates over and yields a new Pathname object for each element in the given @@ -512,25 +494,23 @@ class Pathname | () -> Enumerator[Pathname, nil] # - # See FileTest.directory?. + # See `FileTest.directory?`. # def directory?: () -> bool # - # Returns all but the last component of the path. - # - # See File.dirname. + # See `File.dirname`. Returns all but the last component of the path. # def dirname: () -> Pathname # # Iterates over the children of the directory (files and subdirectories, not @@ -573,16 +553,18 @@ class Pathname | (?boolish with_directory) -> Enumerator[Pathname, Array[Pathname]] # - # Iterates over the entries (files and subdirectories) in the directory, - # yielding a Pathname object for each entry. + # Iterates over the entries (files and subdirectories) in the directory. It + # yields a Pathname object for each entry. + # + # This method has existed since 1.8.1. # def each_entry: () { (Pathname) -> untyped } -> nil # # Iterates over each component of the path. @@ -601,14 +583,13 @@ class Pathname | () -> Enumerator[String, nil] # - # Iterates over each line in the file and yields a String object for each. + # #each_line iterates over the line in the file. It yields a String object for + # each line. + # + # This method has existed since 1.8.1. # def each_line: (?String sep, ?Integer limit, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?chomp: boolish) { (String) -> untyped } -> nil | (Integer limit, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?chomp: boolish) { (String) -> untyped } -> nil @@ -616,7 +597,7 @@ class Pathname | (Integer limit, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?chomp: boolish) -> Enumerator[String, nil] # # Tests the file is empty. @@ -626,102 +607,78 @@ class Pathname def empty?: () -> bool # # Return the entries (files and subdirectories) in the directory, each as a # Pathname object. # - # The results contains just the names in the directory, without any trailing - # slashes or recursive look-up. - # - # pp Pathname.new('/usr/local').entries - # #=> [#, - # # #, - # # #, - # # #, - # # #, - # # #, - # # #, - # # #, - # # #, - # # #, - # # #] - # - # The result may contain the current directory `#` and the parent - # directory `#`. - # - # If you don't want `.` and `..` and want directories, consider - # Pathname#children. - # def entries: () -> Array[Pathname] - # - # Compare this pathname with `other`. The comparison is string-based. Be aware - # that two different paths (`foo.txt` and `./foo.txt`) can refer to the same - # file. + # # def eql?: (untyped) -> bool # - # See FileTest.executable?. + # See `FileTest.executable?`. # def executable?: () -> bool # - # See FileTest.executable_real?. + # See `FileTest.executable_real?`. # def executable_real?: () -> bool # - # See FileTest.exist?. + # See `FileTest.exist?`. # def exist?: () -> bool # - # Returns the absolute path for the file. - # - # See File.expand_path. + # See `File.expand_path`. # def expand_path: (?String dir) -> Pathname # - # Returns the file's extension. - # - # See File.extname. + # See `File.extname`. Returns the file's extension. # def extname: () -> String # - # See FileTest.file?. + # See `FileTest.file?`. # def file?: () -> bool # # Iterates over the directory tree in a depth first manner, yielding a Pathname # for each file under "this" directory. # + # Note that you need to require 'pathname' to use this method. + # # Returns an Enumerator if no block is given. # # Since it is implemented by the standard library module Find, Find.prune can be @@ -736,46 +693,39 @@ class Pathname | (?ignore_error: boolish) -> Enumerator[Pathname, nil] # - # Return `true` if the receiver matches the given pattern. - # - # See File.fnmatch. + # See `File.fnmatch`. Return `true` if the receiver matches the given pattern. # def fnmatch: (String pattern, ?Integer flags) -> bool - # - # Return `true` if the receiver matches the given pattern. - # - # See File.fnmatch. + # + # See `File.fnmatch?` (same as #fnmatch). # alias fnmatch? fnmatch # - # Freezes this Pathname. - # - # See Object.freeze. # def freeze: () -> Pathname # - # Returns "type" of file ("file", "directory", etc). - # - # See File.ftype. + # See `File.ftype`. Returns "type" of file ("file", "directory", etc). # def ftype: () -> String # # Returns or yields Pathname objects. # @@ -788,10 +738,10 @@ class Pathname | (String | Array[String] pattern, ?Integer flags) { (Pathname) -> untyped } -> nil # - # See FileTest.grpowned?. + # See `FileTest.grpowned?`. # def grpowned?: () -> bool @@ -800,7 +750,7 @@ class Pathname def inspect: () -> String # # Joins the given pathnames onto `self` to create a new Pathname object. This is @@ -817,36 +767,32 @@ class Pathname def join: (*String | _ToStr | Pathname args) -> Pathname # - # Same as Pathname.chmod, but does not follow symbolic links. - # - # See File.lchmod. + # See `File.lchmod`. # def lchmod: (Integer mode) -> Integer # - # Same as Pathname.chown, but does not follow symbolic links. - # - # See File.lchown. + # See `File.lchown`. # def lchown: (Integer owner, Integer group) -> Integer # - # See File.lstat. + # See `File.lstat`. # def lstat: () -> ::File::Stat # # Update the access and modification times of the file. # @@ -857,37 +803,31 @@ class Pathname def lutime: (Time | Numeric atime, Time | Numeric mtime) -> Integer # - # Creates a hard link at *pathname*. - # - # See File.link. + # See `File.link`. Creates a hard link. # def make_link: (String | Pathname | _ToStr old) -> Integer # - # Creates a symbolic link. - # - # See File.symlink. + # See `File.symlink`. Creates a symbolic link. # def make_symlink: (String | Pathname | _ToStr old) -> Integer # - # Create the referenced directory. - # - # See Dir.mkdir. + # See `Dir.mkdir`. Create the referenced directory. # def mkdir: (?Integer perm) -> Integer # # Creates a full path, including any intermediate directories that don't yet @@ -898,7 +838,7 @@ class Pathname def mkpath: () -> self # # Returns `true` if `self` points to a mountpoint. @@ -906,51 +846,41 @@ class Pathname def mountpoint?: () -> bool # - # Returns the last modified time of the file. - # - # See File.mtime. + # See `File.mtime`. Returns last modification time. # def mtime: () -> Time # - # Opens the file for reading or writing. - # - # See File.open. + # See `File.open`. Opens the file for reading or writing. # def open: (?string | int mode, ?int perm) -> File | [T] (?string | int mode, ?int perm) { (File) -> T } -> T # - # Opens the referenced directory. - # - # See Dir.open. + # See `Dir.open`. # def opendir: () -> Dir | [U] () { (Dir) -> U } -> U # - # See FileTest.owned?. + # See `FileTest.owned?`. # def owned?: () -> bool # # Returns the parent directory. @@ -960,66 +890,58 @@ class Pathname def parent: () -> Pathname # - # See FileTest.pipe?. + # See `FileTest.pipe?`. # def pipe?: () -> bool # - # Returns all data from the file, or the first `N` bytes if specified. - # - # See File.read. + # See `File.read`. Returns all data from the file, or the first `N` bytes if + # specified. # def read: (?Integer length, ?Integer offset, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish) -> String # - # See FileTest.readable?. + # See `FileTest.readable?`. # def readable?: () -> bool # - # See FileTest.readable_real?. + # See `FileTest.readable_real?`. # def readable_real?: () -> bool # - # Returns all the lines from the file. - # - # See File.readlines. + # See `File.readlines`. Returns all the lines from the file. # def readlines: (?String sep, ?Integer limit, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?chomp: boolish) -> Array[String] | (Integer limit, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?chomp: boolish) -> Array[String] # - # Read symbolic link. - # - # See File.readlink. + # See `File.readlink`. Read symbolic link. # def readlink: () -> untyped # # Returns the real (absolute) pathname of `self` in the actual filesystem. # @@ -1030,8 +952,8 @@ class Pathname def realdirpath: (?string | Pathname base_dir) -> Pathname # # Returns the real (absolute) pathname for `self` in the actual filesystem. # @@ -1042,7 +964,7 @@ class Pathname def realpath: (?string | Pathname base_dir) -> Pathname # # The opposite of Pathname#absolute? @@ -1060,7 +982,7 @@ class Pathname def relative?: () -> bool # # Returns a relative path from the given `base_directory` to the receiver. @@ -1079,37 +1001,35 @@ class Pathname def relative_path_from: (Pathname | string base_directory) -> Pathname # - # Rename the file. - # - # See File.rename. + # See `File.rename`. Rename the file. # def rename: (Pathname | string new_name) -> 0 # - # Remove the referenced directory. - # - # See Dir.rmdir. + # See `Dir.rmdir`. Remove the referenced directory. # def rmdir: () -> 0 # # Recursively deletes a directory, including all directories beneath it. # + # Note that you need to require 'pathname' to use this method. + # # See FileUtils.rm_rf # def rmtree: () -> self # # Predicate method for root directories. Returns `true` if the pathname @@ -1121,75 +1041,71 @@ class Pathname def root?: () -> bool # - # See FileTest.setgid?. + # See `FileTest.setgid?`. # def setgid?: () -> bool # - # See FileTest.setuid?. + # See `FileTest.setuid?`. # def setuid?: () -> bool # - # See FileTest.size. + # See `FileTest.size`. # def size: () -> Integer # - # See FileTest.size?. + # See `FileTest.size?`. # def size?: () -> Integer? # - # See FileTest.socket?. + # See `FileTest.socket?`. # def socket?: () -> untyped # - # Returns the #dirname and the #basename in an Array. - # - # See File.split. + # See `File.split`. Returns the #dirname and the #basename in an Array. # def split: () -> [ Pathname, Pathname ] # - # Returns a File::Stat object. - # - # See File.stat. + # See `File.stat`. Returns a `File::Stat` object. # def stat: () -> File::Stat # - # See FileTest.sticky?. + # See `FileTest.sticky?`. # def sticky?: () -> untyped # # Return a pathname which is substituted by String#sub. @@ -1202,8 +1118,8 @@ class Pathname | (Regexp | string pattern) { (String match) -> string } -> Pathname # # Return a pathname with `repl` added as a suffix to the basename. # @@ -1215,18 +1131,18 @@ class Pathname def sub_ext: (string replacement) -> Pathname # - # See FileTest.symlink?. + # See `FileTest.symlink?`. # def symlink?: () -> untyped # - # See IO.sysopen. + # See `File.sysopen`. # def sysopen: (?String mode, ?Integer perm) -> Integer @@ -1246,32 +1162,26 @@ class Pathname def to_path: () -> String # # Return the path as a String. # - # to_path is implemented so Pathname objects are usable with File.open, etc. - # alias to_s to_path # - # Truncates the file to `length` bytes. - # - # See File.truncate. + # See `File.truncate`. Truncate the file to `length` bytes. # def truncate: (Integer length) -> 0 # - # Removes a file or directory, using File.unlink if `self` is a file, or - # Dir.unlink as necessary. + # Removes a file or directory, using `File.unlink` or `Dir.unlink` as necessary. # def unlink: () -> Integer @@ -1284,63 +1194,58 @@ class Pathname def untaint: () -> Pathname # - # Update the access and modification times of the file. - # - # See File.utime. + # See `File.utime`. Update the access and modification times. # def utime: (Integer | Time atime, Integer | Time mtime) -> Integer # - # See FileTest.world_readable?. + # See `FileTest.world_readable?`. # def world_readable?: () -> (Integer | nil) # - # See FileTest.world_writable?. + # See `FileTest.world_writable?`. # def world_writable?: () -> (Integer | nil) # - # See FileTest.writable?. + # See `FileTest.writable?`. # def writable?: () -> bool # - # See FileTest.writable_real?. + # See `FileTest.writable_real?`. # def writable_real?: () -> bool # - # Writes `contents` to the file. - # - # See File.write. + # Writes `contents` to the file. See `File.write`. # def write: (String content, ?Integer offset, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish) -> Integer # - # See FileTest.zero?. + # See `FileTest.zero?`. # def zero?: () -> bool @@ -1359,11 +1264,11 @@ class Pathname def has_trailing_separator?: (untyped path) -> untyped # # Create a Pathname object from the given String (or String-like object). If - # `path` contains a NULL character (`\0`), an ArgumentError is raised. + # `path` contains a NUL character (`\0`), an ArgumentError is raised. # def initialize: (string | Pathname) -> void @@ -1375,8 +1280,14 @@ class Pathname SAME_PATHS: Proc + # + # Separator list string. + # SEPARATOR_LIST: String + # + # Regexp that matches a separator. + # SEPARATOR_PAT: Regexp TO_PATH: Symbol @@ -1387,20 +1298,10 @@ module Kernel private # - # Creates a new Pathname object from the given string, `path`, and returns - # pathname object. - # - # In order to use this constructor, you must first require the Pathname standard - # library extension. - # - # require 'pathname' - # Pathname("/home/zzak") - # #=> # - # - # See also Pathname::new for more information. + # Creates a Pathname object. # def self?.Pathname: (string | Pathname) -> Pathname end diff --git a/core/proc.rbs b/core/proc.rbs index 416fa3ae5..50c6ec880 100644 --- a/core/proc.rbs +++ b/core/proc.rbs @@ -201,8 +201,8 @@ # ["Bob", "Jane"].map(&hi) #=> ["Hi, Bob!", "Hi, Jane!"] # ["Bob", "Jane"].map(&hey) #=> ["Hey, Bob!", "Hey, Jane!"] # -# Of the Ruby core classes, this method is implemented by Symbol, Method, and -# Hash. +# Of the Ruby core classes, this method is implemented by `Symbol`, `Method`, +# and `Hash`. # # :to_s.to_proc.call(1) #=> "1" # [1, 2].map(&:to_s) #=> ["1", "2"] @@ -285,7 +285,7 @@ # [1, 2, 3].each { |x| p it } # # syntax error found (SyntaxError) # # [1, 2, 3].each { |x| p it } -# # ^~ `it` is not allowed when an ordinary parameter is defined +# # ^~ 'it' is not allowed when an ordinary parameter is defined # # But if a local name (variable or method) is available, it would be used: # @@ -302,7 +302,7 @@ # # p = proc { it**2 } # l = lambda { it**2 } -# p.parameters # => [[:opt, nil]] +# p.parameters # => [[:opt]] # p.arity # => 1 # l.parameters # => [[:req]] # l.arity # => 1 @@ -332,7 +332,7 @@ # Numbered parameters can't be mixed with `it` either: # # [10, 20, 30].map { _1 + it } -# # SyntaxError: `it` is not allowed when a numbered parameter is already used +# # SyntaxError: 'it' is not allowed when a numbered parameter is already used # # To avoid conflicts, naming local variables or method arguments `_1`, `_2` and # so on, causes an error. @@ -835,10 +835,17 @@ class Proc # - # Returns the Ruby source filename and line number containing this proc or `nil` - # if this proc was not defined in Ruby (i.e. native). + # Returns the location where the Proc was defined. The returned Array contains: + # (1) the Ruby source filename + # (2) the line number where the definition starts + # (3) the column number where the definition starts + # (4) the line number where the definition ends + # (5) the column number where the definitions ends + # + # This method will return `nil` if the Proc was not defined in Ruby (i.e. + # native). # def source_location: () -> [String, Integer]? diff --git a/core/process.rbs b/core/process.rbs index a58dba2b9..2727c0805 100644 --- a/core/process.rbs +++ b/core/process.rbs @@ -590,7 +590,7 @@ module Process # * `:microsecond`: Number of microseconds as an integer. # * `:millisecond`: Number of milliseconds as an integer. # * `:nanosecond`: Number of nanoseconds as an integer. - # * `::second`: Number of seconds as an integer. + # * `:second`: Number of seconds as an integer. # # Examples: # @@ -2023,7 +2023,7 @@ end # # The Process::Sys module contains UID and GID functions which provide direct # bindings to the system calls of the same names instead of the more-portable -# versions of the same functionality found in the Process, Process::UID, and +# versions of the same functionality found in the `Process`, Process::UID, and # Process::GID modules. # module Process::Sys diff --git a/core/ractor.rbs b/core/ractor.rbs index 7e992d1b1..561e08c21 100644 --- a/core/ractor.rbs +++ b/core/ractor.rbs @@ -1,12 +1,9 @@ # -# Ractor is an Actor-model abstraction for Ruby that provides thread-safe -# parallel execution. -# # Ractor.new makes a new Ractor, which can run in parallel. # # # The simplest ractor # r = Ractor.new {puts "I am in Ractor!"} -# r.take # wait for it to finish +# r.join # wait for it to finish # # Here, "I am in Ractor!" is printed # # Ractors do not share all objects with each other. There are two main benefits @@ -40,55 +37,12 @@ # puts "I am in Ractor! a=#{a_in_ractor}" # end # r.send(a) # pass it -# r.take +# r.join # # Here, "I am in Ractor! a=1" is printed # -# There are two pairs of methods for sending/receiving messages: -# -# * Ractor#send and Ractor.receive for when the *sender* knows the receiver -# (push); -# * Ractor.yield and Ractor#take for when the *receiver* knows the sender -# (pull); -# # In addition to that, any arguments passed to Ractor.new are passed to the # block and available there as if received by Ractor.receive, and the last block -# value is sent outside of the ractor as if sent by Ractor.yield. -# -# A little demonstration of a classic ping-pong: -# -# server = Ractor.new(name: "server") do -# puts "Server starts: #{self.inspect}" -# puts "Server sends: ping" -# Ractor.yield 'ping' # The server doesn't know the receiver and sends to whoever interested -# received = Ractor.receive # The server doesn't know the sender and receives from whoever sent -# puts "Server received: #{received}" -# end -# -# client = Ractor.new(server) do |srv| # The server is sent to the client, and available as srv -# puts "Client starts: #{self.inspect}" -# received = srv.take # The client takes a message from the server -# puts "Client received from " \ -# "#{srv.inspect}: #{received}" -# puts "Client sends to " \ -# "#{srv.inspect}: pong" -# srv.send 'pong' # The client sends a message to the server -# end -# -# [client, server].each(&:take) # Wait until they both finish -# -# This will output something like: -# -# Server starts: # -# Server sends: ping -# Client starts: # -# Client received from #: ping -# Client sends to #: pong -# Server received: pong -# -# Ractors receive their messages via the *incoming port*, and send them to the -# *outgoing port*. Either one can be disabled with Ractor#close_incoming and -# Ractor#close_outgoing, respectively. When a ractor terminates, its ports are -# closed automatically. +# value can be received with Ractor#value. # # ## Shareable and unshareable objects # @@ -128,7 +82,7 @@ # puts "In ractor: #{data2.object_id}, #{data2[0].object_id}, #{data2[1].object_id}" # end # r.send(data) -# r.take +# r.join # puts "Outside : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}" # # This will output something like: @@ -151,7 +105,7 @@ # puts "In ractor: #{data_in_ractor.object_id}, #{data_in_ractor[0].object_id}" # end # r.send(data, move: true) -# r.take +# r.join # puts "Outside: moved? #{Ractor::MovedObject === data}" # puts "Outside: #{data.inspect}" # @@ -164,7 +118,7 @@ # Notice that even `inspect` (and more basic methods like `__id__`) is # inaccessible on a moved object. # -# Class and Module objects are shareable so the class/module definitions are +# `Class` and `Module` objects are shareable so the class/module definitions are # shared between ractors. Ractor objects are also shareable. All operations on # shareable objects are thread-safe, so the thread-safety property will be kept. # We can not define mutable shareable objects in Ruby, but C extensions can @@ -189,7 +143,7 @@ # puts "I can't see #{cls.tricky}" # cls.tricky = true # doesn't get here, but this would also raise an error # end -# r.take +# r.join # # I see C # # can not access instance variables of classes/modules from non-main Ractors (RuntimeError) # @@ -203,7 +157,7 @@ # puts "GOOD=#{GOOD}" # puts "BAD=#{BAD}" # end -# r.take +# r.join # # GOOD=good # # can not access non-shareable objects in constant Object::BAD by non-main Ractor. (NameError) # @@ -213,7 +167,7 @@ # puts "I see #{C}" # puts "I can't see #{C.tricky}" # end -# r.take +# r.join # # I see C # # can not access instance variables of classes/modules from non-main Ractors (RuntimeError) # @@ -229,7 +183,7 @@ # a = 1 # Thread.new {puts "Thread in ractor: a=#{a}"}.join # end -# r.take +# r.join # # Here "Thread in ractor: a=1" will be printed # # ## Note on code examples @@ -242,7 +196,7 @@ # end # # It is **only for demonstration purposes** and shouldn't be used in a real -# code. Most of the time, #take is used to wait for ractors to finish. +# code. Most of the time, #join is used to wait for ractors to finish. # # ## Reference # @@ -280,10 +234,10 @@ class Ractor # Returns the number of Ractors currently running or blocking (waiting). # # Ractor.count #=> 1 - # r = Ractor.new(name: 'example') { Ractor.yield(1) } + # r = Ractor.new(name: 'example') { Ractor.receive } # Ractor.count #=> 2 (main + example ractor) - # r.take # wait for Ractor.yield(1) - # r.take # wait until r will finish + # r << 42 # r's Ractor.receive will resume + # r.join # wait for r's termination # Ractor.count #=> 1 # def self.count: () -> Integer @@ -363,7 +317,7 @@ class Ractor # `self` inside the block will refer to the current Ractor. # # r = Ractor.new { puts "Hi, I am #{self.inspect}" } - # r.take + # r.join # # Prints "Hi, I am #" # # Any `args` passed are propagated to the block arguments by the same rules as @@ -375,14 +329,14 @@ class Ractor # r = Ractor.new(arg) {|received_arg| # puts "Received: #{received_arg} (##{received_arg.object_id})" # } - # r.take + # r.join # # Prints: # # Passing: [1, 2, 3] (#280) # # Received: [1, 2, 3] (#300) # # Ractor's `name` can be set for debugging purposes: # - # r = Ractor.new(name: 'my ractor') {}; r.take + # r = Ractor.new(name: 'my ractor') {}; r.join # p r # #=> # # @@ -390,128 +344,12 @@ class Ractor # - # Receive a message from the incoming port of the current ractor (which was sent - # there by #send from another ractor). - # - # r = Ractor.new do - # v1 = Ractor.receive - # puts "Received: #{v1}" - # end - # r.send('message1') - # r.take - # # Here will be printed: "Received: message1" - # - # Alternatively, the private instance method `receive` may be used: - # - # r = Ractor.new do - # v1 = receive - # puts "Received: #{v1}" - # end - # r.send('message1') - # r.take - # # This prints: "Received: message1" - # - # The method blocks if the queue is empty. - # - # r = Ractor.new do - # puts "Before first receive" - # v1 = Ractor.receive - # puts "Received: #{v1}" - # v2 = Ractor.receive - # puts "Received: #{v2}" - # end - # wait - # puts "Still not received" - # r.send('message1') - # wait - # puts "Still received only one" - # r.send('message2') - # r.take - # - # Output: - # - # Before first receive - # Still not received - # Received: message1 - # Still received only one - # Received: message2 - # - # If close_incoming was called on the ractor, the method raises - # Ractor::ClosedError if there are no more messages in the incoming queue: - # - # Ractor.new do - # close_incoming - # receive - # end - # wait - # # in `receive': The incoming port is already closed => # (Ractor::ClosedError) + # Receive a message from the default port. # def self.receive: () -> untyped - # - # Receive only a specific message. - # - # Instead of Ractor.receive, Ractor.receive_if can be given a pattern (or any - # filter) in a block and you can choose the messages to accept that are - # available in your ractor's incoming queue. - # - # r = Ractor.new do - # p Ractor.receive_if{|msg| msg.match?(/foo/)} #=> "foo3" - # p Ractor.receive_if{|msg| msg.match?(/bar/)} #=> "bar1" - # p Ractor.receive_if{|msg| msg.match?(/baz/)} #=> "baz2" - # end - # r << "bar1" - # r << "baz2" - # r << "foo3" - # r.take - # - # This will output: - # - # foo3 - # bar1 - # baz2 - # - # If the block returns a truthy value, the message is removed from the incoming - # queue and returned. Otherwise, the message remains in the incoming queue and - # the next messages are checked by the given block. - # - # If there are no messages left in the incoming queue, the method will block - # until new messages arrive. - # - # If the block is escaped by break/return/exception/throw, the message is - # removed from the incoming queue as if a truthy value had been returned. - # - # r = Ractor.new do - # val = Ractor.receive_if{|msg| msg.is_a?(Array)} - # puts "Received successfully: #{val}" - # end - # - # r.send(1) - # r.send('test') - # wait - # puts "2 non-matching sent, nothing received" - # r.send([1, 2, 3]) - # wait - # - # Prints: - # - # 2 non-matching sent, nothing received - # Received successfully: [1, 2, 3] - # - # Note that you can not call receive/receive_if in the given block recursively. - # You should not do any tasks in the block other than message filtration. - # - # Ractor.current << true - # Ractor.receive_if{|msg| Ractor.receive} - # #=> `receive': can not call receive/receive_if recursively (Ractor::Error) - # - def self.receive_if: () { (untyped) -> boolish } -> untyped - # - # Wait for any ractor to have something in its outgoing port, read from this - # ractor, and then return that ractor and the object received. - # - # r1 = Ractor.new {Ractor.yield 'from 1'} - # r2 = Ractor.new {Ractor.yield 'from 2'} - # - # r, obj = Ractor.select(r1, r2) + # TBD # - # puts "received #{obj.inspect} from #{r.inspect}" - # # Prints: received "from 1" from # - # # But could just as well print "from r2" here, either prints could be first. - # - # If one of the given ractors is the current ractor, and it is selected, `r` - # will contain the `:receive` symbol instead of the ractor object. - # - # r1 = Ractor.new(Ractor.current) do |main| - # main.send 'to main' - # Ractor.yield 'from 1' - # end - # r2 = Ractor.new do - # Ractor.yield 'from 2' - # end - # - # r, obj = Ractor.select(r1, r2, Ractor.current) - # puts "received #{obj.inspect} from #{r.inspect}" - # # Could print: received "to main" from :receive - # - # If `yield_value` is provided, that value may be yielded if another ractor is - # calling #take. In this case, the pair `[:yield, nil]` is returned: - # - # r1 = Ractor.new(Ractor.current) do |main| - # puts "Received from main: #{main.take}" - # end - # - # puts "Trying to select" - # r, obj = Ractor.select(r1, Ractor.current, yield_value: 123) - # wait - # puts "Received #{obj.inspect} from #{r.inspect}" - # - # This will print: - # - # Trying to select - # Received from main: 123 - # Received nil from :yield - # - # `move` boolean flag defines whether yielded value will be copied (default) or - # moved. - # - def self.select: (*Ractor ractors, ?move: boolish, ?yield_value: untyped) -> [ Ractor | Symbol, untyped ] + def self.select: (?) -> Array[untyped] # + # It returns shareable Proc object. The Proc object is shareable and the self in + # a block will be replaced with the value passed via `self:` keyword. + # + # In a shareable Proc, you can not access to the outer variables. + # + # a = 42 + # Ractor.shareable_proc{ p a } + # #=> can not isolate a Proc because it accesses outer variables (a). (ArgumentError) + # + # The `self` should be a sharable object + # + # Ractor.shareable_proc(self: self){} + # #=> self should be shareable: main (Ractor::IsolationError) + # + def self.shareable_proc: [T] () { (?) [self: nil] -> T } -> ^(?) [self: nil] -> T + | [T, S] (self: S) { (?) [self: S] -> T } -> ^(?) [self: S] -> T + + # + # Same as Ractor.sharable_proc, but returns lambda proc. + # + def self.shareable_lambda: [T] () { (?) [self: nil] -> T } -> ^(?) [self: nil] -> T + | [T, S] (self: S) { (?) [self: S] -> T } -> ^(?) [self: S] -> T + # - # If the correponding value is not set, yield a value with init_block and store + # If the corresponding value is not set, yield a value with init_block and store # the value in thread-safe manner. This method returns corresponding stored # value. # @@ -607,47 +429,7 @@ class Ractor # - # Send a message to the current ractor's outgoing port to be accepted by #take. - # - # r = Ractor.new {Ractor.yield 'Hello from ractor'} - # puts r.take - # # Prints: "Hello from ractor" - # - # This method is blocking, and will return only when somebody consumes the sent - # message. - # - # r = Ractor.new do - # Ractor.yield 'Hello from ractor' - # puts "Ractor: after yield" - # end - # wait - # puts "Still not taken" - # puts r.take - # - # This will print: - # - # Still not taken - # Hello from ractor - # Ractor: after yield - # - # If the outgoing port was closed with #close_outgoing, the method will raise: - # - # r = Ractor.new do - # close_outgoing - # Ractor.yield 'Hello from ractor' - # end - # wait - # # `yield': The outgoing-port is already closed (Ractor::ClosedError) - # - # The meaning of the `move` argument is the same as for #send. - # - def self.yield: (untyped obj, ?move: boolish) -> untyped - - # # alias << send @@ -656,58 +438,50 @@ class Ractor # rdoc-file=ractor.rb # - [](sym) # --> - # get a value from ractor-local storage of current Ractor Obsolete and use + # get a value from ractor-local storage for current Ractor Obsolete and use # Ractor.[] instead. # + %a{deprecated: Use Ractor.[] instead} def []: (interned sym) -> untyped # - # set a value in ractor-local storage of current Ractor Obsolete and use + # set a value in ractor-local storage for current Ractor Obsolete and use # Ractor.[]= instead. # + %a{deprecated: Use Ractor.[]= instead} def []=: [T] (interned sym, T val) -> T # - # Closes the incoming port and returns whether it was already closed. All - # further attempts to Ractor.receive in the ractor, and #send to the ractor will - # fail with Ractor::ClosedError. - # - # r = Ractor.new {sleep(500)} - # r.close_incoming #=> false - # r.close_incoming #=> true - # r.send('test') - # # Ractor::ClosedError (The incoming-port is already closed) + # return default port of the Ractor. # - def close_incoming: () -> bool + def default_port: () -> Port[untyped] # - # Closes the outgoing port and returns whether it was already closed. All - # further attempts to Ractor.yield in the ractor, and #take from the ractor will - # fail with Ractor::ClosedError. # - # r = Ractor.new {sleep(500)} - # r.close_outgoing #=> false - # r.close_outgoing #=> true - # r.take - # # Ractor::ClosedError (The outgoing-port is already closed) - # - def close_outgoing: () -> bool + def inspect: () -> String # + # Wait for the termination of the Ractor. If the Ractor was aborted (terminated + # with an exception), Ractor#value is called to raise an exception. # - def inspect: () -> String + # Ractor.new{}.join #=> ractor + # + # Ractor.new{ raise "foo" }.join + # #=> raise an exception "foo (RuntimeError)" + # + def join: () -> self # - # Send a message to a Ractor's incoming queue to be accepted by Ractor.receive. - # - # r = Ractor.new do - # value = Ractor.receive - # puts "Received #{value}" - # end - # r.send 'message' - # # Prints: "Received: message" - # - # The method is non-blocking (will return immediately even if the ractor is not - # ready to receive anything): + # Register port as a monitoring port. If the ractor terminated, the port + # received a Symbol object. :exited will be sent if the ractor terminated + # without an exception. :aborted will be sent if the ractor terminated with a + # exception. # - # r = Ractor.new {sleep(5)} - # r.send('test') - # puts "Sent successfully" - # # Prints: "Sent successfully" immediately + # r = Ractor.new{ some_task() } + # r.monitor(port = Ractor::Port.new) + # port.receive #=> :exited and r is terminated # - # An attempt to send to a ractor which already finished its execution will raise - # Ractor::ClosedError. + # r = Ractor.new{ raise "foo" } + # r.monitor(port = Ractor::Port.new) + # port.receive #=> :terminated and r is terminated with an exception "foo" # - # r = Ractor.new {} - # r.take - # p r - # # "#" - # r.send('test') - # # Ractor::ClosedError (The incoming-port is already closed) - # - # If close_incoming was called on the ractor, the method also raises - # Ractor::ClosedError. - # - # r = Ractor.new do - # sleep(500) - # receive - # end - # r.close_incoming - # r.send('test') - # # Ractor::ClosedError (The incoming-port is already closed) - # # The error is raised immediately, not when the ractor tries to receive - # - # If the `obj` is unshareable, by default it will be copied into the receiving - # ractor by deep cloning. If `move: true` is passed, the object is *moved* into - # the receiving ractor and becomes inaccessible to the sender. - # - # r = Ractor.new {puts "Received: #{receive}"} - # msg = 'message' - # r.send(msg, move: true) - # r.take - # p msg - # - # This prints: - # - # Received: message - # in `p': undefined method `inspect' for # - # - # All references to the object and its parts will become invalid to the sender. - # - # r = Ractor.new {puts "Received: #{receive}"} - # s = 'message' - # ary = [s] - # copy = ary.dup - # r.send(ary, move: true) - # - # s.inspect - # # Ractor::MovedError (can not send any methods to a moved object) - # ary.class - # # Ractor::MovedError (can not send any methods to a moved object) - # copy.class - # # => Array, it is different object - # copy[0].inspect - # # Ractor::MovedError (can not send any methods to a moved object) - # # ...but its item was still a reference to `s`, which was moved - # - # If the object is shareable, `move: true` has no effect on it: - # - # r = Ractor.new {puts "Received: #{receive}"} - # s = 'message'.freeze - # r.send(s, move: true) - # s.inspect #=> "message", still available + def monitor: [T < Symbol] (Port[T]) -> untyped + + # + # It is equivalent to default_port.send(msg) # def send: (untyped obj, ?move: boolish) -> Ractor # - # Get a message from the ractor's outgoing port, which was put there by - # Ractor.yield or at ractor's termination. - # - # r = Ractor.new do - # Ractor.yield 'explicit yield' - # 'last value' - # end - # puts r.take #=> 'explicit yield' - # puts r.take #=> 'last value' - # puts r.take # Ractor::ClosedError (The outgoing-port is already closed) - # - # The fact that the last value is also sent to the outgoing port means that - # `take` can be used as an analog of Thread#join ("just wait until ractor - # finishes"). However, it will raise if somebody has already consumed that - # message. - # - # If the outgoing port was closed with #close_outgoing, the method will raise - # Ractor::ClosedError. # - # r = Ractor.new do - # sleep(500) - # Ractor.yield 'Hello from ractor' - # end - # r.close_outgoing - # r.take - # # Ractor::ClosedError (The outgoing-port is already closed) - # # The error would be raised immediately, not when ractor will try to receive - # - # If an uncaught exception is raised in the Ractor, it is propagated by take as - # a Ractor::RemoteError. - # - # r = Ractor.new {raise "Something weird happened"} - # - # begin - # r.take - # rescue => e - # p e # => # - # p e.ractor == r # => true - # p e.cause # => # - # end - # - # Ractor::ClosedError is a descendant of StopIteration, so the termination of - # the ractor will break out of any loops that receive this message without - # propagating the error: - # - # r = Ractor.new do - # 3.times {|i| Ractor.yield "message #{i}"} - # "finishing" - # end - # - # loop {puts "Received: " + r.take} - # puts "Continue successfully" - # - # This will print: - # - # Received: message 0 - # Received: message 1 - # Received: message 2 - # Received: finishing - # Continue successfully + alias to_s inspect + + # + # Unregister port from the monitoring ports. # - def take: () -> untyped + def unmonitor: (Port[untyped]) -> self # + # Waits for `ractor` to complete, using #join, and return its value or raise the + # exception which terminated the Ractor. The value will not be copied even if it + # is unshareable object. Therefore at most 1 Ractor can get a value. # - alias to_s inspect + # r = Ractor.new{ [1, 2] } + # r.value #=> [1, 2] (unshareable object) + # + # Ractor.new(r){|r| r.value} #=> Ractor::Error + # + def value: () -> untyped private @@ -938,9 +610,15 @@ class Ractor class ClosedError < StopIteration end + # + # The parent class of Ractor-related error classes. + # class Error < RuntimeError end + # + # Raised on attempt to make a Ractor-unshareable object Ractor-shareable. + # class IsolationError < Ractor::Error end @@ -1037,6 +715,166 @@ class Ractor def method_missing: (*untyped) -> untyped end + # + # Port objects transmit messages between Ractors. + # + class Port[T = untyped] + # + # + alias << send + + # + # Close the port. On the closed port, sending is not prohibited. Receiving is + # also not allowed if there is no sent messages arrived before closing. + # + # port = Ractor::Port.new + # Ractor.new port do |port| + # port.send 1 # OK + # port.send 2 # OK + # port.close + # port.send 3 # raise Ractor::ClosedError + # end + # + # port.receive #=> 1 + # port.receive #=> 2 + # port.receive #=> raise Ractor::ClosedError + # + # Now, only a Ractor which creates the port is allowed to close ports. + # + # port = Ractor::Port.new + # Ractor.new port do |port| + # port.close #=> closing port by other ractors is not allowed (Ractor::Error) + # end.join + # + def close: () -> void + + # + # Return the port is closed or not. + # + def closed?: () -> bool + + # + # + def inspect: () -> String + + # + # Receive a message to the port (which was sent there by Port#send). + # + # port = Ractor::Port.new + # r = Ractor.new port do |port| + # port.send('message1') + # end + # + # v1 = port.receive + # puts "Received: #{v1}" + # r.join + # # Here will be printed: "Received: message1" + # + # The method blocks if the message queue is empty. + # + # port = Ractor::Port.new + # r = Ractor.new port do |port| + # wait + # puts "Still not received" + # port.send('message1') + # wait + # puts "Still received only one" + # port.send('message2') + # end + # puts "Before first receive" + # v1 = port.receive + # puts "Received: #{v1}" + # v2 = port.receive + # puts "Received: #{v2}" + # r.join + # + # Output: + # + # Before first receive + # Still not received + # Received: message1 + # Still received only one + # Received: message2 + # + # If close_incoming was called on the ractor, the method raises + # Ractor::ClosedError if there are no more messages in the message queue: + # + # port = Ractor::Port.new + # port.close + # port.receive #=> raise Ractor::ClosedError + # + def receive: () -> T + + # + # Send a message to a port to be accepted by port.receive. + # + # port = Ractor::Port.new + # r = Ractor.new do + # r.send 'message' + # end + # value = port.receive + # puts "Received #{value}" + # # Prints: "Received: message" + # + # The method is non-blocking (will return immediately even if the ractor is not + # ready to receive anything): + # + # port = Ractor::Port.new + # r = Ractor.new(port) do |port| + # port.send 'test'} + # puts "Sent successfully" + # # Prints: "Sent successfully" immediately + # end + # + # An attempt to send to a port which already closed its execution will raise + # Ractor::ClosedError. + # + # r = Ractor.new {Ractor::Port.new} + # r.join + # p r + # # "#" + # port = r.value + # port.send('test') # raise Ractor::ClosedError + # + # If the `obj` is unshareable, by default it will be copied into the receiving + # ractor by deep cloning. + # + # If the object is shareable, it only send a reference to the object without + # cloning. + # + def send: (T obj, ?move: boolish) -> self + + private + + # + # Returns a new Ractor::Port object. + # + def initialize: () -> void + + def initialize_copy: (untyped) -> untyped + end + # # Raised on attempt to Ractor#take if there was an uncaught exception in the # Ractor. Its `cause` will contain the original exception, and `ractor` is the @@ -1059,6 +897,9 @@ class Ractor def ractor: () -> Ractor end + # + # Raised when Ractor-unsafe C-methods is invoked by a non-main Ractor. + # class UnsafeError < Ractor::Error end diff --git a/core/range.rbs b/core/range.rbs index f881311a3..0f86fcd1e 100644 --- a/core/range.rbs +++ b/core/range.rbs @@ -86,14 +86,14 @@ # end # a # => [2, 4, 6, 8, 10] # -# A range can be both beginless and endless. For literal beginless, endless +# A range can be both beginless and endless. For literal beginless, endless # ranges, at least the beginning or end of the range must be given as an # explicit nil value. It is recommended to use an explicit nil beginning and -# implicit nil end, since that is what Ruby uses for Range#inspect: +# end, since that is what Ruby uses for Range#inspect: # -# (nil..) # => (nil..) -# (..nil) # => (nil..) -# (nil..nil) # => (nil..) +# (nil..) # => (nil..nil) +# (..nil) # => (nil..nil) +# (nil..nil) # => (nil..nil) # # ## Ranges and Other Classes # diff --git a/core/rbs/unnamed/argf.rbs b/core/rbs/unnamed/argf.rbs index e9a599c2b..e3081062e 100644 --- a/core/rbs/unnamed/argf.rbs +++ b/core/rbs/unnamed/argf.rbs @@ -93,7 +93,7 @@ module RBS # * File `t.rb`: # # p "ARGV: #{ARGV}" - # p "Line: #{ARGF.read}" # Read everything from all specified streams. + # p "Read: #{ARGF.read}" # Read everything from all specified streams. # # * Command and output: # diff --git a/core/rbs/unnamed/env_class.rbs b/core/rbs/unnamed/env_class.rbs index 5f69ac49b..8245d3363 100644 --- a/core/rbs/unnamed/env_class.rbs +++ b/core/rbs/unnamed/env_class.rbs @@ -140,7 +140,7 @@ module RBS # # * ::assoc: Returns a 2-element array containing the name and value of the # named environment variable if it exists: - # * ::clone: Returns `ENV` (and issues a warning). + # * ::clone: Raises an exception. # * ::except: Returns a hash of all name/value pairs except those given. # * ::fetch: Returns the value for the given name. # * ::inspect: Returns the contents of `ENV` as a string. diff --git a/core/rbs/unnamed/random.rbs b/core/rbs/unnamed/random.rbs index ec4dd7aab..dc2616691 100644 --- a/core/rbs/unnamed/random.rbs +++ b/core/rbs/unnamed/random.rbs @@ -31,9 +31,11 @@ module RBS # prng.rand(100) # => 42 # # When `max` is a Float, `rand` returns a random floating point number between - # 0.0 and `max`, including 0.0 and excluding `max`. + # 0.0 and `max`, including 0.0 and excluding `max`. Note that it behaves + # differently from Kernel.rand. # - # prng.rand(1.5) # => 1.4600282860034115 + # prng.rand(1.5) # => 1.4600282860034115 + # rand(1.5) # => 0 # # When `range` is a Range, `rand` returns a random number where # `range.member?(number) == true`. diff --git a/core/regexp.rbs b/core/regexp.rbs index 6f5eb1df3..7f6473dd3 100644 --- a/core/regexp.rbs +++ b/core/regexp.rbs @@ -126,6 +126,9 @@ # `nil`. Note that `$0` is quite different; it returns the name of the # currently executing program. # +# These variables, except for `$~`, are shorthands for methods of `$~`. See +# MatchData@Global+variables+equivalence. +# # Examples: # # # Matched string, but no matched groups. @@ -435,6 +438,9 @@ # /(?<=)\w+(?=<\/b>)/.match("Fortune favors the bold.") # # => # # +# The pattern in lookbehind must be fixed-width. But top-level alternatives can +# be of various lengths. ex. (?<=a|bc) is OK. (?<=aaa(?:b|cd)) is not allowed. +# # #### Match-Reset Anchor # # * `\K`: Match reset: the matched content preceding `\K` in the regexp is @@ -495,7 +501,7 @@ # /\w*/.match('x') # # => # # /\w*/.match('xyz') -# # => # +# # => # # # * `+` - Matches one or more times: # @@ -708,7 +714,7 @@ # # 1. The leading subexpression `"` in the pattern matches the first character # `"` in the target string. -# 2. The next subexpression `.*` matches the next substring `Quote“` (including +# 2. The next subexpression `.*` matches the next substring `Quote"` (including # the trailing double-quote). # 3. Now there is nothing left in the target string to match the trailing # subexpression `"` in the pattern; this would cause the overall match to @@ -1248,7 +1254,7 @@ # # Regexp matching can apply an optimization to prevent ReDoS attacks. When the # optimization is applied, matching time increases linearly (not polynomially or -# exponentially) in relation to the input size, and a ReDoS attach is not +# exponentially) in relation to the input size, and a ReDoS attack is not # possible. # # This optimization is applied if the pattern meets these criteria: @@ -1272,21 +1278,14 @@ # # ## References # -# Read (online PDF books): +# Read: # -# * [Mastering Regular -# Expressions](https://ia902508.us.archive.org/10/items/allitebooks-02/Maste -# ring%20Regular%20Expressions%2C%203rd%20Edition.pdf) by Jeffrey E.F. -# Friedl. -# * [Regular Expressions -# Cookbook](https://doc.lagout.org/programmation/Regular%20Expressions/Regul -# ar%20Expressions%20Cookbook_%20Detailed%20Solutions%20in%20Eight%20Program -# ming%20Languages%20%282nd%20ed.%29%20%5BGoyvaerts%20%26%20Levithan%202012- -# 09-06%5D.pdf) by Jan Goyvaerts & Steven Levithan. +# * *Mastering Regular Expressions* by Jeffrey E.F. Friedl. +# * *Regular Expressions Cookbook* by Jan Goyvaerts & Steven Levithan. # -# Explore, test (interactive online editor): +# Explore, test: # -# * [Rubular](https://rubular.com/). +# * [Rubular](https://rubular.com/): interactive online editor. # class Regexp # Represents an object's ability to be converted to a `Regexp`. @@ -1297,6 +1296,9 @@ class Regexp def to_regexp: () -> Regexp end + # + # Raised when regexp matching timed out. + # class TimeoutError < RegexpError end @@ -1658,9 +1660,12 @@ class Regexp # - # Returns the Encoding object that represents the encoding of obj. + # Returns an Encoding object that represents the encoding of `self`; see + # [Encodings](rdoc-ref:encodings.rdoc). + # + # Related: see [Querying](rdoc-ref:String@Querying). # def encoding: () -> Encoding diff --git a/core/ruby_vm.rbs b/core/ruby_vm.rbs index 623790ebc..a990f3dbf 100644 --- a/core/ruby_vm.rbs +++ b/core/ruby_vm.rbs @@ -443,7 +443,7 @@ module RubyVM::AbstractSyntaxTree # # See ::parse for explanation of keyword argument meaning and usage. # - def self.parse_file: (String | ::_ToPath string, ?keep_script_lines: bool, ?error_tolerant: bool, ?keep_tokens: bool) -> Node + def self.parse_file: (path string, ?keep_script_lines: bool, ?error_tolerant: bool, ?keep_tokens: bool) -> Node # # Enable YJIT compilation. `stats` option decides whether to enable YJIT stats - # or not. `compilation_log` decides - # whether to enable YJIT compilation logging or not. + # or not. `log` decides + # whether to enable YJIT compilation logging or not. Optional `mem_size` and + # `call_threshold` can be + # provided to override default configuration. # * `stats`: # * `false`: Don't enable stats. # * `true`: Enable stats. Print stats at exit. diff --git a/core/rubygems/errors.rbs b/core/rubygems/errors.rbs index 986a0b904..50e9b93e8 100644 --- a/core/rubygems/errors.rbs +++ b/core/rubygems/errors.rbs @@ -17,7 +17,7 @@ # Further RubyGems documentation can be found at: # # * [RubyGems Guides](https://guides.rubygems.org) -# * [RubyGems API](https://www.rubydoc.info/github/rubygems/rubygems) (also +# * [RubyGems API](https://www.rubydoc.info/github/ruby/rubygems) (also # available from `gem server`) # # ## RubyGems Plugins @@ -48,7 +48,7 @@ # ## Bugs # # You can submit bugs to the [RubyGems bug -# tracker](https://github.com/rubygems/rubygems/issues) on GitHub +# tracker](https://github.com/ruby/rubygems/issues) on GitHub # # ## Credits # @@ -83,80 +83,13 @@ # # ## License # -# See -# [LICENSE.txt](https://github.com/rubygems/rubygems/blob/master/LICENSE.txt) +# See [LICENSE.txt](https://github.com/ruby/rubygems/blob/master/LICENSE.txt) # for permissions. # # Thanks! # # -The RubyGems Team # -# -# Provides 3 methods for declaring when something is going away. -# -# +deprecate(name, repl, year, month)+: -# Indicate something may be removed on/after a certain date. -# -# +rubygems_deprecate(name, replacement=:none)+: -# Indicate something will be removed in the next major RubyGems version, -# and (optionally) a replacement for it. -# -# `rubygems_deprecate_command`: -# Indicate a RubyGems command (in +lib/rubygems/commands/*.rb+) will be -# removed in the next RubyGems version. -# -# Also provides `skip_during` for temporarily turning off deprecation warnings. -# This is intended to be used in the test suite, so deprecation warnings don't -# cause test failures if you need to make sure stderr is otherwise empty. -# -# Example usage of `deprecate` and `rubygems_deprecate`: -# -# class Legacy -# def self.some_class_method -# # ... -# end -# -# def some_instance_method -# # ... -# end -# -# def some_old_method -# # ... -# end -# -# extend Gem::Deprecate -# deprecate :some_instance_method, "X.z", 2011, 4 -# rubygems_deprecate :some_old_method, "Modern#some_new_method" -# -# class << self -# extend Gem::Deprecate -# deprecate :some_class_method, :none, 2011, 4 -# end -# end -# -# Example usage of `rubygems_deprecate_command`: -# -# class Gem::Commands::QueryCommand < Gem::Command -# extend Gem::Deprecate -# rubygems_deprecate_command -# -# # ... -# end -# -# Example usage of `skip_during`: -# -# class TestSomething < Gem::Testcase -# def test_some_thing_with_deprecations -# Gem::Deprecate.skip_during do -# actual_stdout, actual_stderr = capture_output do -# Gem.something_deprecated -# end -# assert_empty actual_stdout -# assert_equal(expected, actual_stderr) -# end -# end -# end -# module Gem # # Raised when RubyGems is unable to load or activate a gem. Contains the name diff --git a/core/rubygems/rubygems.rbs b/core/rubygems/rubygems.rbs index 8b87aa6ce..b921bc78b 100644 --- a/core/rubygems/rubygems.rbs +++ b/core/rubygems/rubygems.rbs @@ -17,7 +17,7 @@ # Further RubyGems documentation can be found at: # # * [RubyGems Guides](https://guides.rubygems.org) -# * [RubyGems API](https://www.rubydoc.info/github/rubygems/rubygems) (also +# * [RubyGems API](https://www.rubydoc.info/github/ruby/rubygems) (also # available from `gem server`) # # ## RubyGems Plugins @@ -48,7 +48,7 @@ # ## Bugs # # You can submit bugs to the [RubyGems bug -# tracker](https://github.com/rubygems/rubygems/issues) on GitHub +# tracker](https://github.com/ruby/rubygems/issues) on GitHub # # ## Credits # @@ -83,80 +83,13 @@ # # ## License # -# See -# [LICENSE.txt](https://github.com/rubygems/rubygems/blob/master/LICENSE.txt) +# See [LICENSE.txt](https://github.com/ruby/rubygems/blob/master/LICENSE.txt) # for permissions. # # Thanks! # # -The RubyGems Team # -# -# Provides 3 methods for declaring when something is going away. -# -# +deprecate(name, repl, year, month)+: -# Indicate something may be removed on/after a certain date. -# -# +rubygems_deprecate(name, replacement=:none)+: -# Indicate something will be removed in the next major RubyGems version, -# and (optionally) a replacement for it. -# -# `rubygems_deprecate_command`: -# Indicate a RubyGems command (in +lib/rubygems/commands/*.rb+) will be -# removed in the next RubyGems version. -# -# Also provides `skip_during` for temporarily turning off deprecation warnings. -# This is intended to be used in the test suite, so deprecation warnings don't -# cause test failures if you need to make sure stderr is otherwise empty. -# -# Example usage of `deprecate` and `rubygems_deprecate`: -# -# class Legacy -# def self.some_class_method -# # ... -# end -# -# def some_instance_method -# # ... -# end -# -# def some_old_method -# # ... -# end -# -# extend Gem::Deprecate -# deprecate :some_instance_method, "X.z", 2011, 4 -# rubygems_deprecate :some_old_method, "Modern#some_new_method" -# -# class << self -# extend Gem::Deprecate -# deprecate :some_class_method, :none, 2011, 4 -# end -# end -# -# Example usage of `rubygems_deprecate_command`: -# -# class Gem::Commands::QueryCommand < Gem::Command -# extend Gem::Deprecate -# rubygems_deprecate_command -# -# # ... -# end -# -# Example usage of `skip_during`: -# -# class TestSomething < Gem::Testcase -# def test_some_thing_with_deprecations -# Gem::Deprecate.skip_during do -# actual_stdout, actual_stderr = capture_output do -# Gem.something_deprecated -# end -# assert_empty actual_stdout -# assert_equal(expected, actual_stderr) -# end -# end -# end -# module Gem interface _HashLike[K, V] def each_pair: () { ([ K, V ]) -> untyped } -> self @@ -204,7 +137,7 @@ module Gem VERSION: String - # + # # An Array of Regexps that match windows Ruby platforms. # WIN_PATTERNS: Array[Regexp] @@ -251,7 +184,7 @@ module Gem # # The path where gem executables are to be installed. # @@ -509,7 +442,7 @@ module Gem # # Returns a list of paths matching `glob` that can be used by a gem to pick up # features from other gems. For example: @@ -526,7 +459,7 @@ module Gem # # Returns a list of paths matching `glob` from the latest gems that can be used # by a gem to pick up features from other gems. For example: @@ -551,7 +484,7 @@ module Gem # # def self.finish_resolve: (?RequestSet request_set) -> void @@ -804,7 +737,7 @@ module Gem # # The path were rubygems plugins are to be installed. # @@ -1009,8 +942,7 @@ module Gem # - source_date_epoch_string() # --> # If the SOURCE_DATE_EPOCH environment variable is set, returns it's value. - # Otherwise, returns the time that `Gem.source_date_epoch_string` was first - # called in the same format as SOURCE_DATE_EPOCH. + # Otherwise, returns DEFAULT_SOURCE_DATE_EPOCH as a string. # # NOTE(@duckinator): The implementation is a tad weird because we want to: # 1. Make builds reproducible by default, by having this function always @@ -1154,7 +1086,7 @@ module Gem def self.user_home: () -> String # # Is this a windows platform? diff --git a/core/set.rbs b/core/set.rbs index 87af3ce5c..cbe887c51 100644 --- a/core/set.rbs +++ b/core/set.rbs @@ -1,184 +1,188 @@ -# -# This library provides the Set class, which implements a collection -# of unordered values with no duplicates. It is a hybrid of Array's -# intuitive inter-operation facilities and Hash's fast lookup. -# The method `to_set` is added to Enumerable for convenience. -# Set is easy to use with Enumerable objects (implementing `each`). -# Most of the initializer methods and binary operators accept generic -# Enumerable objects besides sets and arrays. An Enumerable object -# can be converted to Set using the `to_set` method. -# Set uses Hash as storage, so you must note the following points: +# +# Copyright (c) 2002-2024 Akinori MUSHA +# +# Documentation by Akinori MUSHA and Gavin Sinclair. +# +# All rights reserved. You can redistribute and/or modify it under the same +# terms as Ruby. +# +# The Set class implements a collection of unordered values with no duplicates. +# It is a hybrid of Array's intuitive inter-operation facilities and Hash's fast +# lookup. +# +# Set is easy to use with Enumerable objects (implementing `each`). Most of the +# initializer methods and binary operators accept generic Enumerable objects +# besides sets and arrays. An Enumerable object can be converted to Set using +# the `to_set` method. +# +# Set uses a data structure similar to Hash for storage, except that it only has +# keys and no values. +# # * Equality of elements is determined according to Object#eql? and -# Object#hash. Use Set#compare_by_identity to make a set compare -# its elements by their identity. -# * Set assumes that the identity of each element does not change -# while it is stored. Modifying an element of a set will render the -# set to an unreliable state. -# * When a string is to be stored, a frozen copy of the string is -# stored instead unless the original string is already frozen. +# Object#hash. Use Set#compare_by_identity to make a set compare its +# elements by their identity. +# * Set assumes that the identity of each element does not change while it is +# stored. Modifying an element of a set will render the set to an +# unreliable state. +# * When a string is to be stored, a frozen copy of the string is stored +# instead unless the original string is already frozen. +# # ## Comparison -# The comparison operators `<`, `>`, `<=`, and `>=` are implemented as -# shorthand for the {proper_,}{subset?,superset?} methods. The `<=>` -# operator reflects this order, or return `nil` for sets that both -# have distinct elements (`{x, y}` vs. `{x, z}` for example). +# +# The comparison operators `<`, `>`, `<=`, and `>=` are implemented as shorthand +# for the {proper_,}{subset?,superset?} methods. The `<=>` operator reflects +# this order, or returns `nil` for sets that both have distinct elements (`{x, +# y}` vs. `{x, z}` for example). +# # ## Example -# require 'set' -# s1 = Set[1, 2] #=> # -# s2 = [1, 2].to_set #=> # -# s1 == s2 #=> true -# s1.add("foo") #=> # -# s1.merge([2, 6]) #=> # -# s1.subset?(s2) #=> false -# s2.subset?(s1) #=> true +# +# s1 = Set[1, 2] #=> # +# s2 = [1, 2].to_set #=> # +# s1 == s2 #=> true +# s1.add("foo") #=> # +# s1.merge([2, 6]) #=> # +# s1.subset?(s2) #=> false +# s2.subset?(s1) #=> true # # ## Contact -# * Akinori MUSHA (current maintainer) +# +# * Akinori MUSHA (current maintainer) +# # ## What's Here -# First, what's elsewhere. Class Set: +# +# First, what's elsewhere. \Class \Set: +# # * Inherits from [class Object](rdoc-ref:Object@What-27s+Here). -# * Includes [module Enumerable](rdoc-ref:Enumerable@What-27s+Here), -# which provides dozens of additional methods. -# In particular, class Set does not have many methods of its own -# for fetching or for iterating. -# Instead, it relies on those in Enumerable. +# * Includes [module Enumerable](rdoc-ref:Enumerable@What-27s+Here), which +# provides dozens of additional methods. +# +# In particular, class Set does not have many methods of its own for fetching or +# for iterating. Instead, it relies on those in Enumerable. +# # Here, class Set provides methods that are useful for: -# * [Creating a Set](#class-Set-label-Methods+for+Creating+a+Set) -# * [Set Operations](#class-Set-label-Methods+for+Set+Operations) -# * [Comparing](#class-Set-label-Methods+for+Comparing) -# * [Querying](#class-Set-label-Methods+for+Querying) -# * [Assigning](#class-Set-label-Methods+for+Assigning) -# * [Deleting](#class-Set-label-Methods+for+Deleting) -# * [Converting](#class-Set-label-Methods+for+Converting) -# * [Iterating](#class-Set-label-Methods+for+Iterating) -# * [And more....](#class-Set-label-Other+Methods) +# +# * [Creating an Array](rdoc-ref:Array@Methods+for+Creating+an+Array) +# * [Creating a Set](rdoc-ref:Set@Methods+for+Creating+a+Set) +# * [Set Operations](rdoc-ref:Set@Methods+for+Set+Operations) +# * [Comparing](rdoc-ref:Array@Methods+for+Comparing) +# * [Querying](rdoc-ref:Array@Methods+for+Querying) +# * [Assigning](rdoc-ref:Array@Methods+for+Assigning) +# * [Deleting](rdoc-ref:Array@Methods+for+Deleting) +# * [Converting](rdoc-ref:Array@Methods+for+Converting) +# * [Iterating](rdoc-ref:Array@Methods+for+Iterating) +# * [And more....](rdoc-ref:Array@Other+Methods) +# # ### Methods for Creating a Set -# * ::[]: -# Returns a new set containing the given objects. -# * ::new: -# Returns a new set containing either the given objects -# (if no block given) or the return values from the called block -# (if a block given). +# +# * ::[]: Returns a new set containing the given objects. +# * ::new: Returns a new set containing either the given objects (if no block +# given) or the return values from the called block (if a block given). +# # ### Methods for Set Operations -# * [|](#method-i-7C) (aliased as #union and #+): -# Returns a new set containing all elements from `self` -# and all elements from a given enumerable (no duplicates). -# * [&](#method-i-26) (aliased as #intersection): -# Returns a new set containing all elements common to `self` -# and a given enumerable. -# * [-](#method-i-2D) (aliased as #difference): -# Returns a copy of `self` with all elements -# in a given enumerable removed. -# * [\^](#method-i-5E): -# Returns a new set containing all elements from `self` -# and a given enumerable except those common to both. +# +# * #| (aliased as #union and #+): Returns a new set containing all elements +# from `self` and all elements from a given enumerable (no duplicates). +# * #& (aliased as #intersection): Returns a new set containing all elements +# common to `self` and a given enumerable. +# * #- (aliased as #difference): Returns a copy of `self` with all elements in +# a given enumerable removed. +# * #^: Returns a new set containing all elements from `self` and a given +# enumerable except those common to both. +# # ### Methods for Comparing -# * [<=>](#method-i-3C-3D-3E): -# Returns -1, 0, or 1 as `self` is less than, equal to, -# or greater than a given object. -# * [==](#method-i-3D-3D): -# Returns whether `self` and a given enumerable are equal, -# as determined by Object#eql?. -# * #compare_by_identity?: -# Returns whether the set considers only identity -# when comparing elements. +# +# * #<=>: Returns -1, 0, or 1 as `self` is less than, equal to, or greater +# than a given object. +# * #==: Returns whether `self` and a given enumerable are equal, as +# determined by Object#eql?. +# * #compare_by_identity?: Returns whether the set considers only identity +# when comparing elements. +# # ### Methods for Querying -# * #length (aliased as #size): -# Returns the count of elements. -# * #empty?: -# Returns whether the set has no elements. -# * #include? (aliased as #member? and #===): -# Returns whether a given object is an element in the set. -# * #subset? (aliased as [<=](#method-i-3C-3D)): -# Returns whether a given object is a subset of the set. -# * #proper_subset? (aliased as [<](#method-i-3C)): -# Returns whether a given enumerable is a proper subset of the set. -# * #superset? (aliased as [>=](#method-i-3E-3D)]): -# Returns whether a given enumerable is a superset of the set. -# * #proper_superset? (aliased as [>](#method-i-3E)): -# Returns whether a given enumerable is a proper superset of the set. -# * #disjoint?: -# Returns `true` if the set and a given enumerable -# have no common elements, `false` otherwise. -# * #intersect?: -# Returns `true` if the set and a given enumerable: -# have any common elements, `false` otherwise. -# * #compare_by_identity?: -# Returns whether the set considers only identity -# when comparing elements. +# +# * #length (aliased as #size): Returns the count of elements. +# * #empty?: Returns whether the set has no elements. +# * #include? (aliased as #member? and #===): Returns whether a given object +# is an element in the set. +# * #subset? (aliased as #<=): Returns whether a given object is a subset of +# the set. +# * #proper_subset? (aliased as #<): Returns whether a given enumerable is a +# proper subset of the set. +# * #superset? (aliased as #>=): Returns whether a given enumerable is a +# superset of the set. +# * #proper_superset? (aliased as #>): Returns whether a given enumerable is a +# proper superset of the set. +# * #disjoint?: Returns `true` if the set and a given enumerable have no +# common elements, `false` otherwise. +# * #intersect?: Returns `true` if the set and a given enumerable: have any +# common elements, `false` otherwise. +# * #compare_by_identity?: Returns whether the set considers only identity +# when comparing elements. +# # ### Methods for Assigning -# * #add (aliased as #<<): -# Adds a given object to the set; returns `self`. -# * #add?: -# If the given object is not an element in the set, -# adds it and returns `self`; otherwise, returns `nil`. -# * #merge: -# Merges the elements of each given enumerable object to the set; returns -# `self`. -# * #replace: -# Replaces the contents of the set with the contents -# of a given enumerable. +# +# * #add (aliased as #<<): Adds a given object to the set; returns `self`. +# * #add?: If the given object is not an element in the set, adds it and +# returns `self`; otherwise, returns `nil`. +# * #merge: Merges the elements of each given enumerable object to the set; +# returns `self`. +# * #replace: Replaces the contents of the set with the contents of a given +# enumerable. +# # ### Methods for Deleting -# * #clear: -# Removes all elements in the set; returns `self`. -# * #delete: -# Removes a given object from the set; returns `self`. -# * #delete?: -# If the given object is an element in the set, -# removes it and returns `self`; otherwise, returns `nil`. -# * #subtract: -# Removes each given object from the set; returns `self`. +# +# * #clear: Removes all elements in the set; returns `self`. +# * #delete: Removes a given object from the set; returns `self`. +# * #delete?: If the given object is an element in the set, removes it and +# returns `self`; otherwise, returns `nil`. +# * #subtract: Removes each given object from the set; returns `self`. # * #delete_if - Removes elements specified by a given block. -# * #select! (aliased as #filter!): -# Removes elements not specified by a given block. -# * #keep_if: -# Removes elements not specified by a given block. -# * #reject! -# Removes elements specified by a given block. +# * #select! (aliased as #filter!): Removes elements not specified by a given +# block. +# * #keep_if: Removes elements not specified by a given block. +# * #reject! Removes elements specified by a given block. +# # ### Methods for Converting -# * #classify: -# Returns a hash that classifies the elements, -# as determined by the given block. -# * #collect! (aliased as #map!): -# Replaces each element with a block return-value. -# * #divide: -# Returns a hash that classifies the elements, -# as determined by the given block; -# differs from #classify in that the block may accept -# either one or two arguments. -# * #flatten: -# Returns a new set that is a recursive flattening of `self`. -# #flatten!: -# Replaces each nested set in `self` with the elements from that set. -# * #inspect (aliased as #to_s): -# Returns a string displaying the elements. -# * #join: -# Returns a string containing all elements, converted to strings -# as needed, and joined by the given record separator. -# * #to_a: -# Returns an array containing all set elements. -# * #to_set: -# Returns `self` if given no arguments and no block; -# with a block given, returns a new set consisting of block -# return values. +# +# * #classify: Returns a hash that classifies the elements, as determined by +# the given block. +# * #collect! (aliased as #map!): Replaces each element with a block +# return-value. +# * #divide: Returns a hash that classifies the elements, as determined by the +# given block; differs from #classify in that the block may accept either +# one or two arguments. +# * #flatten: Returns a new set that is a recursive flattening of `self`. +# * #flatten!: Replaces each nested set in `self` with the elements from that +# set. +# * #inspect (aliased as #to_s): Returns a string displaying the elements. +# * #join: Returns a string containing all elements, converted to strings as +# needed, and joined by the given record separator. +# * #to_a: Returns an array containing all set elements. +# * #to_set: Returns `self` if given no arguments and no block; with a block +# given, returns a new set consisting of block return values. +# # ### Methods for Iterating -# * #each: -# Calls the block with each successive element; returns `self`. +# +# * #each: Calls the block with each successive element; returns `self`. +# # ### Other Methods -# * #reset: -# Resets the internal state; useful if an object -# has been modified while an element in the set. +# +# * #reset: Resets the internal state; useful if an object has been modified +# while an element in the set. # class Set[unchecked out A] include Enumerable[A] # - # Creates a new set containing the elements of the given enumerable - # object. - # If a block is given, the elements of enum are preprocessed by the - # given block. + # Creates a new set containing the elements of the given enumerable object. + # + # If a block is given, the elements of enum are preprocessed by the given block. + # # Set.new([1, 2]) #=> # # Set.new([1, 2, 1]) #=> # # Set.new([1, 'c', :s]) #=> # @@ -190,102 +194,115 @@ class Set[unchecked out A] | (?nil) -> untyped # - # Creates a new set containing the given objects. - # Set[1, 2] # => # - # Set[1, 2, 1] # => # - # Set[1, 'c', :s] # => # + # Returns a new Set object populated with the given objects, See Set::new. # def self.[]: [X] (*X) -> Set[X] # - # Returns a new set containing elements common to the set and the - # given enumerable object. + # Returns a new set containing elements common to the set and the given + # enumerable object. + # # Set[1, 3, 5] & Set[3, 2, 1] #=> # # Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> # # def &: (_Each[A]) -> self - # + # + # Returns a new set containing elements common to the set and the given + # enumerable object. + # + # Set[1, 3, 5] & Set[3, 2, 1] #=> # + # Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> # # alias intersection & # - # Returns a new set built by merging the set and the elements of the - # given enumerable object. + # Returns a new set built by merging the set and the elements of the given + # enumerable object. + # # Set[1, 2, 3] | Set[2, 4, 5] #=> # # Set[1, 5, 'z'] | (1..6) #=> # # def |: (_Each[A]) -> self - # + # + # Returns a new set built by merging the set and the elements of the given + # enumerable object. + # + # Set[1, 2, 3] | Set[2, 4, 5] #=> # + # Set[1, 5, 'z'] | (1..6) #=> # # alias union | - # + # + # Returns a new set built by merging the set and the elements of the given + # enumerable object. + # + # Set[1, 2, 3] | Set[2, 4, 5] #=> # + # Set[1, 5, 'z'] | (1..6) #=> # # alias + | # - # Returns a new set built by duplicating the set, removing every - # element that appears in the given enumerable object. + # Returns a new set built by duplicating the set, removing every element that + # appears in the given enumerable object. + # # Set[1, 3, 5] - Set[1, 5] #=> # # Set['a', 'b', 'z'] - ['a', 'c'] #=> # # def -: (_Each[A]) -> self - # + # + # Returns a new set built by duplicating the set, removing every element that + # appears in the given enumerable object. + # + # Set[1, 3, 5] - Set[1, 5] #=> # + # Set['a', 'b', 'z'] - ['a', 'c'] #=> # # alias difference - # - # Adds the given object to the set and returns self. Use `merge` to - # add many elements at once. + # Adds the given object to the set and returns self. Use `merge` to add many + # elements at once. + # # Set[1, 2].add(3) #=> # # Set[1, 2].add([3, 4]) #=> # # Set[1, 2].add(2) #=> # # def add: (A) -> self - # + # + # Adds the given object to the set and returns self. Use `merge` to add many + # elements at once. + # + # Set[1, 2].add(3) #=> # + # Set[1, 2].add([3, 4]) #=> # + # Set[1, 2].add(2) #=> # # alias << add # - # Adds the given object to the set and returns self. If the - # object is already in the set, returns nil. + # Adds the given object to the set and returns self. If the object is already in + # the set, returns nil. + # # Set[1, 2].add?(3) #=> # # Set[1, 2].add?([3, 4]) #=> # # Set[1, 2].add?(2) #=> nil @@ -293,59 +310,92 @@ class Set[unchecked out A] def add?: (A) -> self? # - # Returns true if the set contains the given object. - # Note that `include?` and `member?` do not test member - # equality using `==` as do other Enumerables. + # Returns true if the set contains the given object: + # + # Set[1, 2, 3].include? 2 #=> true + # Set[1, 2, 3].include? 4 #=> false + # + # Note that `include?` and `member?` do not test member equality using `==` as + # do other Enumerables. + # + # This is aliased to #===, so it is usable in `case` expressions: + # + # case :apple + # when Set[:potato, :carrot] + # "vegetable" + # when Set[:apple, :banana] + # "fruit" + # end + # # => "fruit" + # # See also Enumerable#include? # def include?: (A) -> bool - # + # + # Returns true if the set contains the given object: + # + # Set[1, 2, 3].include? 2 #=> true + # Set[1, 2, 3].include? 4 #=> false + # + # Note that `include?` and `member?` do not test member equality using `==` as + # do other Enumerables. + # + # This is aliased to #===, so it is usable in `case` expressions: + # + # case :apple + # when Set[:potato, :carrot] + # "vegetable" + # when Set[:apple, :banana] + # "fruit" + # end + # # => "fruit" + # + # See also Enumerable#include? # alias member? include? # - # Returns a new set containing elements exclusive between the set - # and the given enumerable object. `(set ^ enum)` is equivalent to - # `((set | enum) - (set & enum))`. + # Returns a new set containing elements exclusive between the set and the given + # enumerable object. `(set ^ enum)` is equivalent to `((set | enum) - (set & + # enum))`. + # # Set[1, 2] ^ Set[2, 3] #=> # # Set[1, 'b', 'c'] ^ ['b', 'd'] #=> # # def ^: (_Each[A]) -> self # - # Classifies the set by the return value of the given block and - # returns a hash of {value => set of elements} pairs. The block is - # called once for each element of the set, passing the element as - # parameter. - # require 'set' + # Classifies the set by the return value of the given block and returns a hash + # of {value => set of elements} pairs. The block is called once for each + # element of the set, passing the element as parameter. + # # files = Set.new(Dir.glob("*.rb")) # hash = files.classify { |f| File.mtime(f).year } - # hash #=> {2000=>#, - # # 2001=>#, - # # 2002=>#} + # hash #=> {2000 => #, + # # 2001 => #, + # # 2002 => #} # # Returns an enumerator if no block is given. # def classify: [X] () { (A) -> X } -> Hash[X, self] # # Removes all elements and returns self. + # # set = Set[1, 'c', :s] #=> # # set.clear #=> # # set #=> # @@ -353,73 +403,83 @@ class Set[unchecked out A] def clear: () -> self # - # Replaces the elements with ones returned by `collect()`. - # Returns an enumerator if no block is given. + # Replaces the elements with ones returned by `collect`. Returns an enumerator + # if no block is given. # def collect!: () { (A) -> A } -> self - # + # + # Replaces the elements with ones returned by `collect`. Returns an enumerator + # if no block is given. # alias map! collect! # - # Deletes the given object from the set and returns self. Use - # `subtract` to delete many items at once. + # Deletes the given object from the set and returns self. Use subtract to delete + # many items at once. # def delete: (A) -> self # - # Deletes the given object from the set and returns self. If the - # object is not in the set, returns nil. + # Deletes the given object from the set and returns self. If the object is not + # in the set, returns nil. # def delete?: (A) -> self? # - # Deletes every element of the set for which block evaluates to - # true, and returns self. Returns an enumerator if no block is - # given. + # Deletes every element of the set for which block evaluates to true, and + # returns self. Returns an enumerator if no block is given. # def delete_if: () { (A) -> untyped } -> self # - # Equivalent to Set#delete_if, but returns nil if no changes were - # made. Returns an enumerator if no block is given. + # Equivalent to Set#delete_if, but returns nil if no changes were made. Returns + # an enumerator if no block is given. # def reject!: () { (A) -> untyped } -> self? # - # Makes the set compare its elements by their identity and returns - # self. This method may not be supported by all subclasses of Set. + # Makes the set compare its elements by their identity and returns self. # def compare_by_identity: () -> self # - # Returns true if the set and the given enumerable have - # no element in common. This method is the opposite of `intersect?`. + # Returns true if the set will compare its elements by their identity. Also see + # Set#compare_by_identity. + # + def compare_by_identity?: () -> bool + + # + # Returns true if the set and the given enumerable have no element in common. + # This method is the opposite of `intersect?`. + # # Set[1, 2, 3].disjoint? Set[3, 4] #=> false # Set[1, 2, 3].disjoint? Set[4, 5] #=> true # Set[1, 2, 3].disjoint? [3, 4] #=> false @@ -428,21 +488,24 @@ class Set[unchecked out A] def disjoint?: (Set[A] | Enumerable[A]) -> bool # - # Divides the set into a set of subsets according to the commonality - # defined by the given block. - # If the arity of the block is 2, elements o1 and o2 are in common - # if block.call(o1, o2) is true. Otherwise, elements o1 and o2 are - # in common if block.call(o1) == block.call(o2). - # require 'set' + # Divides the set into a set of subsets according to the commonality defined by + # the given block. + # + # If the arity of the block is 2, elements o1 and o2 are in common if both + # block.call(o1, o2) and block.call(o2, o1) are true. Otherwise, elements o1 and + # o2 are in common if block.call(o1) == block.call(o2). + # # numbers = Set[1, 3, 4, 6, 9, 10, 11] # set = numbers.divide { |i,j| (i - j).abs == 1 } # set #=> #, - # # #, # # #, # # #}> + # # #, # # Returns an enumerator if no block is given. # @@ -450,39 +513,49 @@ class Set[unchecked out A] | () { (A) -> Hash::_Key } -> Set[self] # - # Calls the given block once for each element in the set, passing - # the element as parameter. Returns an enumerator if no block is - # given. + # Calls the given block once for each element in the set, passing the element as + # parameter. Returns an enumerator if no block is given. # def each: () { (A) -> void } -> self | () -> Enumerator[A, self] # # Returns true if the set contains no elements. # def empty?: () -> bool # - # Returns a new set that is a copy of the set, flattening each - # containing set recursively. + # Returns a new set that is a copy of the set, flattening each containing set + # recursively. # def flatten: () -> Set[untyped] # + # Equivalent to Set#flatten, but replaces the receiver with the result in place. + # Returns nil if no modifications were made. + # + def flatten!: () -> self? + + # - # Returns true if the set and the given enumerable have at least one - # element in common. + # Returns true if the set and the given enumerable have at least one element in + # common. + # # Set[1, 2, 3].intersect? Set[4, 5] #=> false # Set[1, 2, 3].intersect? Set[3, 4] #=> true # Set[1, 2, 3].intersect? 4..5 #=> false @@ -491,77 +564,96 @@ class Set[unchecked out A] def intersect?: (Set[A] | Enumerable[A]) -> bool # - # Deletes every element of the set for which block evaluates to - # false, and returns self. Returns an enumerator if no block is - # given. + # Deletes every element of the set for which block evaluates to false, and + # returns self. Returns an enumerator if no block is given. # def keep_if: () { (A) -> untyped } -> self # # Returns the number of elements. # def size: () -> Integer - # + # + # Returns the number of elements. # alias length size # - # Merges the elements of the given enumerable objects to the set and - # returns self. + # Merges the elements of the given enumerable objects to the set and returns + # self. # def merge: (*_Each[A]) -> self # # Returns true if the set is a subset of the given set. # def subset?: (self) -> bool + # + # Returns true if the set is a subset of the given set. + # + alias <= subset? + # # Returns true if the set is a proper subset of the given set. # def proper_subset?: (self) -> bool + # + # Returns true if the set is a proper subset of the given set. + # + alias < proper_subset? + # # Returns true if the set is a superset of the given set. # def superset?: (self) -> bool + # + # Returns true if the set is a superset of the given set. + # + alias >= superset? + # # Returns true if the set is a proper superset of the given set. # def proper_superset?: (self) -> bool + # + # Returns true if the set is a proper superset of the given set. + # + alias > proper_superset? + # - # Replaces the contents of the set with the contents of the given - # enumerable object and returns self. + # Replaces the contents of the set with the contents of the given enumerable + # object and returns self. + # # set = Set[1, 'c', :s] #=> # # set.replace([1, 2]) #=> # # set #=> # @@ -569,52 +661,67 @@ class Set[unchecked out A] def replace: (_Each[A]) -> self # - # Resets the internal state after modification to existing elements - # and returns self. - # Elements will be reindexed and deduplicated. + # Resets the internal state after modification to existing elements and returns + # self. Elements will be reindexed and deduplicated. # def reset: () -> self # - # Equivalent to Set#keep_if, but returns nil if no changes were - # made. Returns an enumerator if no block is given. + # Equivalent to Set#keep_if, but returns nil if no changes were made. Returns an + # enumerator if no block is given. # def select!: () { (A) -> untyped } -> self? + # + # Equivalent to Set#keep_if, but returns nil if no changes were made. Returns an + # enumerator if no block is given. + # + alias filter! select! + # - # Deletes every element that appears in the given enumerable object - # and returns self. + # Deletes every element that appears in the given enumerable object and returns + # self. # def subtract: (_Each[A]) -> self # # Returns an array containing all elements in the set. + # # Set[1, 2].to_a #=> [1, 2] # Set[1, 'c', :s].to_a #=> [1, "c", :s] # def to_a: () -> Array[A] + + # + # Returns a string created by converting each element of the set to a string. + # + def join: (?string separator) -> String end %a{annotate:rdoc:skip} module Enumerable[unchecked out Elem] # - # Makes a set from the enumerable object with given arguments. - # Needs to `require "set"` to use this method. + # Makes a set from the enumerable object with given arguments. Passing arguments + # to this method is deprecated. # def to_set: () -> Set[Elem] | [T] () { (Elem) -> T } -> Set[T] diff --git a/core/string.rbs b/core/string.rbs index b28e1bb59..eae0f4eec 100644 --- a/core/string.rbs +++ b/core/string.rbs @@ -151,141 +151,478 @@ # * #rstrip, #rstrip!: Strip trailing whitespace. # * #strip, #strip!: Strip leading and trailing whitespace. # -# ## `String` Slices +# ## What's Here +# +# First, what's elsewhere. Class `String`: +# +# * Inherits from the [Object class](rdoc-ref:Object@What-27s+Here). +# * Includes the [Comparable module](rdoc-ref:Comparable@What-27s+Here). +# +# Here, class `String` provides methods that are useful for: +# +# * [Creating a \String](rdoc-ref:String@Creating+a+String). +# * [Freezing/Unfreezing a \String](rdoc-ref:String@Freezing-2FUnfreezing). +# * [Querying a \String](rdoc-ref:String@Querying). +# * [Comparing Strings](rdoc-ref:String@Comparing). +# * [Modifying a \String](rdoc-ref:String@Modifying). +# * [Converting to a new \String](rdoc-ref:String@Converting+to+New+String). +# * [Converting to a +# non-\String](rdoc-ref:String@Converting+to+Non--5CString). +# * [Iterating over a \String](rdoc-ref:String@Iterating). +# +# ### Creating a String +# +# * ::new: Returns a new string. +# * ::try_convert: Returns a new string created from a given object. +# +# ### Freezing/Unfreezing +# +# * #+@: Returns a string that is not frozen: `self` if not frozen; `self.dup` +# otherwise. +# * #-@ (aliased as #dedup): Returns a string that is frozen: `self` if +# already frozen; `self.freeze` otherwise. +# * #freeze: Freezes `self` if not already frozen; returns `self`. +# +# ### Querying +# +# *Counts* +# +# * #length (aliased as #size): Returns the count of characters (not bytes). +# * #empty?: Returns whether the length of `self` is zero. +# * #bytesize: Returns the count of bytes. +# * #count: Returns the count of substrings matching given strings. +# +# *Substrings* +# +# * #=~: Returns the index of the first substring that matches a given Regexp +# or other object; returns `nil` if no match is found. +# * #byteindex: Returns the byte index of the first occurrence of a given +# substring. +# * #byterindex: Returns the byte index of the last occurrence of a given +# substring. +# * #index: Returns the index of the *first* occurrence of a given substring; +# returns `nil` if none found. +# * #rindex: Returns the index of the *last* occurrence of a given substring; +# returns `nil` if none found. +# * #include?: Returns `true` if the string contains a given substring; +# `false` otherwise. +# * #match: Returns a MatchData object if the string matches a given Regexp; +# `nil` otherwise. +# * #match?: Returns `true` if the string matches a given Regexp; `false` +# otherwise. +# * #start_with?: Returns `true` if the string begins with any of the given +# substrings. +# * #end_with?: Returns `true` if the string ends with any of the given +# substrings. +# +# *Encodings* +# +# * #encoding: Returns the Encoding object that represents the encoding of the +# string. +# * #unicode_normalized?: Returns `true` if the string is in Unicode +# normalized form; `false` otherwise. +# * #valid_encoding?: Returns `true` if the string contains only characters +# that are valid for its encoding. +# * #ascii_only?: Returns `true` if the string has only ASCII characters; +# `false` otherwise. +# +# *Other* +# +# * #sum: Returns a basic checksum for the string: the sum of each byte. +# * #hash: Returns the integer hash code. +# +# ### Comparing +# +# * #== (aliased as #===): Returns `true` if a given other string has the same +# content as `self`. +# * #eql?: Returns `true` if the content is the same as the given other +# string. +# * #<=>: Returns -1, 0, or 1 as a given other string is smaller than, equal +# to, or larger than `self`. +# * #casecmp: Ignoring case, returns -1, 0, or 1 as `self` is smaller than, +# equal to, or larger than a given other string. +# * #casecmp?: Ignoring case, returns whether a given other string is equal to +# `self`. +# +# ### Modifying +# +# Each of these methods modifies `self`. +# +# *Insertion* +# +# * #insert: Returns `self` with a given string inserted at a specified +# offset. +# * #<<: Returns `self` concatenated with a given string or integer. +# * #append_as_bytes: Returns `self` concatenated with strings without +# performing any encoding validation or conversion. +# * #prepend: Prefixes to `self` the concatenation of given other strings. +# +# *Substitution* +# +# * #bytesplice: Replaces bytes of `self` with bytes from a given string; +# returns `self`. +# * #sub!: Replaces the first substring that matches a given pattern with a +# given replacement string; returns `self` if any changes, `nil` otherwise. +# * #gsub!: Replaces each substring that matches a given pattern with a given +# replacement string; returns `self` if any changes, `nil` otherwise. +# * #succ! (aliased as #next!): Returns `self` modified to become its own +# successor. +# * #replace: Returns `self` with its entire content replaced by a given +# string. +# * #reverse!: Returns `self` with its characters in reverse order. +# * #setbyte: Sets the byte at a given integer offset to a given value; +# returns the argument. +# * #tr!: Replaces specified characters in `self` with specified replacement +# characters; returns `self` if any changes, `nil` otherwise. +# * #tr_s!: Replaces specified characters in `self` with specified replacement +# characters, removing duplicates from the substrings that were modified; +# returns `self` if any changes, `nil` otherwise. +# +# *Casing* +# +# * #capitalize!: Upcases the initial character and downcases all others; +# returns `self` if any changes, `nil` otherwise. +# * #downcase!: Downcases all characters; returns `self` if any changes, `nil` +# otherwise. +# * #upcase!: Upcases all characters; returns `self` if any changes, `nil` +# otherwise. +# * #swapcase!: Upcases each downcase character and downcases each upcase +# character; returns `self` if any changes, `nil` otherwise. +# +# *Encoding* +# +# * #encode!: Returns `self` with all characters transcoded from one encoding +# to another. +# * #unicode_normalize!: Unicode-normalizes `self`; returns `self`. +# * #scrub!: Replaces each invalid byte with a given character; returns +# `self`. +# * #force_encoding: Changes the encoding to a given encoding; returns `self`. +# +# *Deletion* +# +# * #clear: Removes all content, so that `self` is empty; returns `self`. +# * #slice!, #[]=: Removes a substring determined by a given index, +# start/length, range, regexp, or substring. +# * #squeeze!: Removes contiguous duplicate characters; returns `self`. +# * #delete!: Removes characters as determined by the intersection of +# substring arguments. +# * #delete_prefix!: Removes leading prefix; returns `self` if any changes, +# `nil` otherwise. +# * #delete_suffix!: Removes trailing suffix; returns `self` if any changes, +# `nil` otherwise. +# * #lstrip!: Removes leading whitespace; returns `self` if any changes, `nil` +# otherwise. +# * #rstrip!: Removes trailing whitespace; returns `self` if any changes, +# `nil` otherwise. +# * #strip!: Removes leading and trailing whitespace; returns `self` if any +# changes, `nil` otherwise. +# * #chomp!: Removes the trailing record separator, if found; returns `self` +# if any changes, `nil` otherwise. +# * #chop!: Removes trailing newline characters if found; otherwise removes +# the last character; returns `self` if any changes, `nil` otherwise. +# +# ### Converting to New String +# +# Each of these methods returns a new `String` based on `self`, often just a +# modified copy of `self`. +# +# *Extension* +# +# * #*: Returns the concatenation of multiple copies of `self`. +# * #+: Returns the concatenation of `self` and a given other string. +# * #center: Returns a copy of `self`, centered by specified padding. +# * #concat: Returns the concatenation of `self` with given other strings. +# * #ljust: Returns a copy of `self` of a given length, right-padded with a +# given other string. +# * #rjust: Returns a copy of `self` of a given length, left-padded with a +# given other string. +# +# *Encoding* +# +# * #b: Returns a copy of `self` with ASCII-8BIT encoding. +# * #scrub: Returns a copy of `self` with each invalid byte replaced with a +# given character. +# * #unicode_normalize: Returns a copy of `self` with each character +# Unicode-normalized. +# * #encode: Returns a copy of `self` with all characters transcoded from one +# encoding to another. +# +# *Substitution* +# +# * #dump: Returns a printable version of `self`, enclosed in double-quotes. +# * #undump: Returns a copy of `self` with all `\xNN` notations replaced by +# `\uNNNN` notations and all escaped characters unescaped. +# * #sub: Returns a copy of `self` with the first substring matching a given +# pattern replaced with a given replacement string. +# * #gsub: Returns a copy of `self` with each substring that matches a given +# pattern replaced with a given replacement string. +# * #succ (aliased as #next): Returns the string that is the successor to +# `self`. +# * #reverse: Returns a copy of `self` with its characters in reverse order. +# * #tr: Returns a copy of `self` with specified characters replaced with +# specified replacement characters. +# * #tr_s: Returns a copy of `self` with specified characters replaced with +# specified replacement characters, removing duplicates from the substrings +# that were modified. +# * #%: Returns the string resulting from formatting a given object into +# `self`. +# +# *Casing* +# +# * #capitalize: Returns a copy of `self` with the first character upcased and +# all other characters downcased. +# * #downcase: Returns a copy of `self` with all characters downcased. +# * #upcase: Returns a copy of `self` with all characters upcased. +# * #swapcase: Returns a copy of `self` with all upcase characters downcased +# and all downcase characters upcased. +# +# *Deletion* +# +# * #delete: Returns a copy of `self` with characters removed. +# * #delete_prefix: Returns a copy of `self` with a given prefix removed. +# * #delete_suffix: Returns a copy of `self` with a given suffix removed. +# * #lstrip: Returns a copy of `self` with leading whitespace removed. +# * #rstrip: Returns a copy of `self` with trailing whitespace removed. +# * #strip: Returns a copy of `self` with leading and trailing whitespace +# removed. +# * #chomp: Returns a copy of `self` with a trailing record separator removed, +# if found. +# * #chop: Returns a copy of `self` with trailing newline characters or the +# last character removed. +# * #squeeze: Returns a copy of `self` with contiguous duplicate characters +# removed. +# * #[] (aliased as #slice): Returns a substring determined by a given index, +# start/length, range, regexp, or string. +# * #byteslice: Returns a substring determined by a given index, start/length, +# or range. +# * #chr: Returns the first character. # -# A *slice* of a string is a substring selected by certain criteria. +# *Duplication* # -# These instance methods utilize slicing: +# * #to_s (aliased as #to_str): If `self` is a subclass of `String`, returns +# `self` copied into a `String`; otherwise, returns `self`. # -# * String#[] (aliased as String#slice): Returns a slice copied from `self`. -# * String#[]=: Mutates `self` with the slice replaced. -# * String#slice!: Mutates `self` with the slice removed and returns the -# removed slice. +# ### Converting to Non-String # -# Each of the above methods takes arguments that determine the slice to be -# copied or replaced. +# Each of these methods converts the contents of `self` to a non-`String`. # -# The arguments have several forms. For a string `string`, the forms are: +# *Characters, Bytes, and Clusters* # -# * `string[index]` -# * `string[start, length]` -# * `string[range]` -# * `string[regexp, capture = 0]` -# * `string[substring]` +# * #bytes: Returns an array of the bytes in `self`. +# * #chars: Returns an array of the characters in `self`. +# * #codepoints: Returns an array of the integer ordinals in `self`. +# * #getbyte: Returns the integer byte at the given index in `self`. +# * #grapheme_clusters: Returns an array of the grapheme clusters in `self`. # -# **`string[index]`** +# *Splitting* # -# When a non-negative integer argument `index` is given, the slice is the -# 1-character substring found in `self` at character offset `index`: +# * #lines: Returns an array of the lines in `self`, as determined by a given +# record separator. +# * #partition: Returns a 3-element array determined by the first substring +# that matches a given substring or regexp. +# * #rpartition: Returns a 3-element array determined by the last substring +# that matches a given substring or regexp. +# * #split: Returns an array of substrings determined by a given delimiter -- +# regexp or string -- or, if a block is given, passes those substrings to +# the block. # -# 'bar'[0] # => "b" -# 'bar'[2] # => "r" -# 'bar'[20] # => nil -# 'тест'[2] # => "с" -# 'こんにちは'[4] # => "は" +# *Matching* # -# When a negative integer `index` is given, the slice begins at the offset given -# by counting backward from the end of `self`: +# * #scan: Returns an array of substrings matching a given regexp or string, +# or, if a block is given, passes each matching substring to the block. +# * #unpack: Returns an array of substrings extracted from `self` according to +# a given format. +# * #unpack1: Returns the first substring extracted from `self` according to a +# given format. # -# 'bar'[-3] # => "b" -# 'bar'[-1] # => "r" -# 'bar'[-20] # => nil +# *Numerics* +# +# * #hex: Returns the integer value of the leading characters, interpreted as +# hexadecimal digits. +# * #oct: Returns the integer value of the leading characters, interpreted as +# octal digits. +# * #ord: Returns the integer ordinal of the first character in `self`. +# * #to_c: Returns the complex value of leading characters, interpreted as a +# complex number. +# * #to_i: Returns the integer value of leading characters, interpreted as an +# integer. +# * #to_f: Returns the floating-point value of leading characters, interpreted +# as a floating-point number. +# * #to_r: Returns the rational value of leading characters, interpreted as a +# rational. # -# **`string[start, length]`** +# *Strings and Symbols* # -# When non-negative integer arguments `start` and `length` are given, the slice -# begins at character offset `start`, if it exists, and continues for `length` -# characters, if available: +# * #inspect: Returns a copy of `self`, enclosed in double quotes, with +# special characters escaped. +# * #intern (aliased as #to_sym): Returns the symbol corresponding to `self`. # -# 'foo'[0, 2] # => "fo" -# 'тест'[1, 2] # => "ес" -# 'こんにちは'[2, 2] # => "にち" -# # Zero length. -# 'foo'[2, 0] # => "" -# # Length not entirely available. -# 'foo'[1, 200] # => "oo" -# # Start out of range. -# 'foo'[4, 2] # => nil +# ### Iterating # -# Special case: if `start` equals the length of `self`, the slice is a new empty -# string: +# * #each_byte: Calls the given block with each successive byte in `self`. +# * #each_char: Calls the given block with each successive character in +# `self`. +# * #each_codepoint: Calls the given block with each successive integer +# codepoint in `self`. +# * #each_grapheme_cluster: Calls the given block with each successive +# grapheme cluster in `self`. +# * #each_line: Calls the given block with each successive line in `self`, as +# determined by a given record separator. +# * #upto: Calls the given block with each string value returned by successive +# calls to #succ. # -# 'foo'[3, 2] # => "" -# 'foo'[3, 200] # => "" +# +# A `String` object has an arbitrary sequence of bytes, typically representing +# text or binary data. A `String` object may be created using String::new or as +# literals. # -# When a negative `start` and non-negative `length` are given, the slice begins -# by counting backward from the end of `self`, and continues for `length` -# characters, if available: +# String objects differ from Symbol objects in that Symbol objects are designed +# to be used as identifiers, instead of text or data. # -# 'foo'[-2, 2] # => "oo" -# 'foo'[-2, 200] # => "oo" -# # Start out of range. -# 'foo'[-4, 2] # => nil +# You can create a `String` object explicitly with: # -# When a negative `length` is given, there is no slice: +# * A [string literal](rdoc-ref:syntax/literals.rdoc@String+Literals). +# * A [heredoc literal](rdoc-ref:syntax/literals.rdoc@Here+Document+Literals). # -# 'foo'[1, -1] # => nil -# 'foo'[-2, -1] # => nil +# You can convert certain objects to Strings with: # -# **`string[range]`** +# * Method #String. # -# When a Range argument `range` is given, it creates a substring of `string` -# using the indices in `range`. The slice is then determined as above: +# Some `String` methods modify `self`. Typically, a method whose name ends with +# `!` modifies `self` and returns `self`; often, a similarly named method +# (without the `!`) returns a new string. # -# 'foo'[0..1] # => "fo" -# 'foo'[0, 2] # => "fo" +# In general, if both bang and non-bang versions of a method exist, the bang +# method mutates and the non-bang method does not. However, a method without a +# bang can also mutate, such as String#replace. # -# 'foo'[2...2] # => "" -# 'foo'[2, 0] # => "" +# ## Substitution Methods # -# 'foo'[1..200] # => "oo" -# 'foo'[1, 200] # => "oo" +# These methods perform substitutions: # -# 'foo'[4..5] # => nil -# 'foo'[4, 2] # => nil +# * String#sub: One substitution (or none); returns a new string. +# * String#sub!: One substitution (or none); returns `self` if any changes, +# `nil` otherwise. +# * String#gsub: Zero or more substitutions; returns a new string. +# * String#gsub!: Zero or more substitutions; returns `self` if any changes, +# `nil` otherwise. # -# 'foo'[-4..-3] # => nil -# 'foo'[-4, 2] # => nil +# Each of these methods takes: # -# 'foo'[3..4] # => "" -# 'foo'[3, 2] # => "" +# * A first argument, `pattern` (String or Regexp), that specifies the +# substring(s) to be replaced. # -# 'foo'[-2..-1] # => "oo" -# 'foo'[-2, 2] # => "oo" +# * Either of the following: # -# 'foo'[-2..197] # => "oo" -# 'foo'[-2, 200] # => "oo" +# * A second argument, `replacement` (String or Hash), that determines the +# replacing string. +# * A block that will determine the replacing string. # -# **`string[regexp, capture = 0]`** +# The examples in this section mostly use the String#sub and String#gsub +# methods; the principles illustrated apply to all four substitution methods. # -# When the Regexp argument `regexp` is given, and the `capture` argument is `0`, -# the slice is the first matching substring found in `self`: +# **Argument `pattern`** # -# 'foo'[/o/] # => "o" -# 'foo'[/x/] # => nil -# s = 'hello there' -# s[/[aeiou](.)\1/] # => "ell" -# s[/[aeiou](.)\1/, 0] # => "ell" +# Argument `pattern` is commonly a regular expression: # -# If the argument `capture` is provided and not `0`, it should be either a -# capture group index (integer) or a capture group name (String or Symbol); the -# slice is the specified capture (see Regexp@Groups and Captures): +# s = 'hello' +# s.sub(/[aeiou]/, '*') # => "h*llo" +# s.gsub(/[aeiou]/, '*') # => "h*ll*" +# s.gsub(/[aeiou]/, '') # => "hll" +# s.sub(/ell/, 'al') # => "halo" +# s.gsub(/xyzzy/, '*') # => "hello" +# 'THX1138'.gsub(/\d+/, '00') # => "THX00" # -# s = 'hello there' -# s[/[aeiou](.)\1/, 1] # => "l" -# s[/(?[aeiou])(?[^aeiou])/, "non_vowel"] # => "l" -# s[/(?[aeiou])(?[^aeiou])/, :vowel] # => "e" +# When `pattern` is a string, all its characters are treated as ordinary +# characters (not as Regexp special characters): # -# If an invalid capture group index is given, there is no slice. If an invalid -# capture group name is given, `IndexError` is raised. +# 'THX1138'.gsub('\d+', '00') # => "THX1138" # -# **`string[substring]`** +# **`String` `replacement`** # -# When the single `String` argument `substring` is given, it returns the -# substring from `self` if found, otherwise `nil`: +# If `replacement` is a string, that string determines the replacing string that +# is substituted for the matched text. # -# 'foo'['oo'] # => "oo" -# 'foo'['xx'] # => nil +# Each of the examples above uses a simple string as the replacing string. +# +# `String` `replacement` may contain back-references to the pattern's captures: +# +# * `\n` (*n* is a non-negative integer) refers to `$n`. +# * `\k` refers to the named capture `name`. +# +# See Regexp for details. +# +# Note that within the string `replacement`, a character combination such as +# `$&` is treated as ordinary text, not as a special match variable. However, +# you may refer to some special match variables using these combinations: +# +# * `\&` and `\0` correspond to `$&`, which contains the complete matched +# text. +# * `\'` corresponds to `$'`, which contains the string after the match. +# * `\`` corresponds to `$``, which contains the string before the match. +# * `\+` corresponds to `$+`, which contains the last capture group. +# +# See Regexp for details. +# +# Note that `\\\` is interpreted as an escape, i.e., a single backslash. +# +# Note also that a string literal consumes backslashes. See [String +# Literals](rdoc-ref:syntax/literals.rdoc@String+Literals) for details about +# string literals. +# +# A back-reference is typically preceded by an additional backslash. For +# example, if you want to write a back-reference `\&` in `replacement` with a +# double-quoted string literal, you need to write `"..\\\\&.."`. +# +# If you want to write a non-back-reference string `\&` in `replacement`, you +# need to first escape the backslash to prevent this method from interpreting it +# as a back-reference, and then you need to escape the backslashes again to +# prevent a string literal from consuming them: `"..\\\\\\\\&.."`. +# +# You may want to use the block form to avoid excessive backslashes. +# +# **\Hash `replacement`** +# +# If the argument `replacement` is a hash, and `pattern` matches one of its +# keys, the replacing string is the value for that key: +# +# h = {'foo' => 'bar', 'baz' => 'bat'} +# 'food'.sub('foo', h) # => "bard" +# +# Note that a symbol key does not match: +# +# h = {foo: 'bar', baz: 'bat'} +# 'food'.sub('foo', h) # => "d" +# +# **Block** +# +# In the block form, the current match string is passed to the block; the +# block's return value becomes the replacing string: +# +# s = '@' +# '1234'.gsub(/\d/) { |match| s.succ! } # => "ABCD" +# +# Special match variables such as `$1`, `$2`, `$``, `$&`, and `$'` are set +# appropriately. +# +# ## Whitespace in Strings +# +# In the class `String`, *whitespace* is defined as a contiguous sequence of +# characters consisting of any mixture of the following: +# +# * NL (null): `"\x00"`, `"\u0000"`. +# * HT (horizontal tab): `"\x09"`, `"\t"`. +# * LF (line feed): `"\x0a"`, `"\n"`. +# * VT (vertical tab): `"\x0b"`, `"\v"`. +# * FF (form feed): `"\x0c"`, `"\f"`. +# * CR (carriage return): `"\x0d"`, `"\r"`. +# * SP (space): `"\x20"`, `" "`. +# +# Whitespace is relevant for the following methods: +# +# * #lstrip, #lstrip!: Strip leading whitespace. +# * #rstrip, #rstrip!: Strip trailing whitespace. +# * #strip, #strip!: Strip leading and trailing whitespace. # # ## What's Here # @@ -296,24 +633,22 @@ # # Here, class `String` provides methods that are useful for: # -# * [Creating a String](rdoc-ref:String@Methods+for+Creating+a+String) -# * [Frozen/Unfrozen -# Strings](rdoc-ref:String@Methods+for+a+Frozen-2FUnfrozen+String) -# * [Querying](rdoc-ref:String@Methods+for+Querying) -# * [Comparing](rdoc-ref:String@Methods+for+Comparing) -# * [Modifying a String](rdoc-ref:String@Methods+for+Modifying+a+String) -# * [Converting to New -# String](rdoc-ref:String@Methods+for+Converting+to+New+String) -# * [Converting to -# Non-String](rdoc-ref:String@Methods+for+Converting+to+Non-String) -# * [Iterating](rdoc-ref:String@Methods+for+Iterating) +# * [Creating a \String](rdoc-ref:String@Creating+a+String). +# * [Freezing/Unfreezing a \String](rdoc-ref:String@Freezing-2FUnfreezing). +# * [Querying a \String](rdoc-ref:String@Querying). +# * [Comparing Strings](rdoc-ref:String@Comparing). +# * [Modifying a \String](rdoc-ref:String@Modifying). +# * [Converting to a new \String](rdoc-ref:String@Converting+to+New+String). +# * [Converting to a +# non-\String](rdoc-ref:String@Converting+to+Non--5CString). +# * [Iterating over a \String](rdoc-ref:String@Iterating). # -# ### Methods for Creating a `String` +# ### Creating a String # # * ::new: Returns a new string. # * ::try_convert: Returns a new string created from a given object. # -# ### Methods for a Frozen/Unfrozen String +# ### Freezing/Unfreezing # # * #+@: Returns a string that is not frozen: `self` if not frozen; `self.dup` # otherwise. @@ -321,12 +656,12 @@ # already frozen; `self.freeze` otherwise. # * #freeze: Freezes `self` if not already frozen; returns `self`. # -# ### Methods for Querying +# ### Querying # # *Counts* # # * #length (aliased as #size): Returns the count of characters (not bytes). -# * #empty?: Returns `true` if `self.length` is zero; `false` otherwise. +# * #empty?: Returns whether the length of `self` is zero. # * #bytesize: Returns the count of bytes. # * #count: Returns the count of substrings matching given strings. # @@ -334,6 +669,10 @@ # # * #=~: Returns the index of the first substring that matches a given Regexp # or other object; returns `nil` if no match is found. +# * #byteindex: Returns the byte index of the first occurrence of a given +# substring. +# * #byterindex: Returns the byte index of the last occurrence of a given +# substring. # * #index: Returns the index of the *first* occurrence of a given substring; # returns `nil` if none found. # * #rindex: Returns the index of the *last* occurrence of a given substring; @@ -365,7 +704,7 @@ # * #sum: Returns a basic checksum for the string: the sum of each byte. # * #hash: Returns the integer hash code. # -# ### Methods for Comparing +# ### Comparing # # * #== (aliased as #===): Returns `true` if a given other string has the same # content as `self`. @@ -373,12 +712,12 @@ # string. # * #<=>: Returns -1, 0, or 1 as a given other string is smaller than, equal # to, or larger than `self`. -# * #casecmp: Ignoring case, returns -1, 0, or 1 as a given other string is -# smaller than, equal to, or larger than `self`. -# * #casecmp?: Returns `true` if the string is equal to a given string after -# Unicode case folding; `false` otherwise. +# * #casecmp: Ignoring case, returns -1, 0, or 1 as `self` is smaller than, +# equal to, or larger than a given other string. +# * #casecmp?: Ignoring case, returns whether a given other string is equal to +# `self`. # -# ### Methods for Modifying a `String` +# ### Modifying # # Each of these methods modifies `self`. # @@ -389,17 +728,20 @@ # * #<<: Returns `self` concatenated with a given string or integer. # * #append_as_bytes: Returns `self` concatenated with strings without # performing any encoding validation or conversion. +# * #prepend: Prefixes to `self` the concatenation of given other strings. # # *Substitution* # +# * #bytesplice: Replaces bytes of `self` with bytes from a given string; +# returns `self`. # * #sub!: Replaces the first substring that matches a given pattern with a # given replacement string; returns `self` if any changes, `nil` otherwise. # * #gsub!: Replaces each substring that matches a given pattern with a given # replacement string; returns `self` if any changes, `nil` otherwise. # * #succ! (aliased as #next!): Returns `self` modified to become its own # successor. -# * #initialize_copy (aliased as #replace): Returns `self` with its entire -# content replaced by a given string. +# * #replace: Returns `self` with its entire content replaced by a given +# string. # * #reverse!: Returns `self` with its characters in reverse order. # * #setbyte: Sets the byte at a given integer offset to a given value; # returns the argument. @@ -437,6 +779,10 @@ # * #squeeze!: Removes contiguous duplicate characters; returns `self`. # * #delete!: Removes characters as determined by the intersection of # substring arguments. +# * #delete_prefix!: Removes leading prefix; returns `self` if any changes, +# `nil` otherwise. +# * #delete_suffix!: Removes trailing suffix; returns `self` if any changes, +# `nil` otherwise. # * #lstrip!: Removes leading whitespace; returns `self` if any changes, `nil` # otherwise. # * #rstrip!: Removes trailing whitespace; returns `self` if any changes, @@ -448,7 +794,7 @@ # * #chop!: Removes trailing newline characters if found; otherwise removes # the last character; returns `self` if any changes, `nil` otherwise. # -# ### Methods for Converting to New `String` +# ### Converting to New String # # Each of these methods returns a new `String` based on `self`, often just a # modified copy of `self`. @@ -457,9 +803,8 @@ # # * #*: Returns the concatenation of multiple copies of `self`. # * #+: Returns the concatenation of `self` and a given other string. -# * #center: Returns a copy of `self` centered between pad substrings. +# * #center: Returns a copy of `self`, centered by specified padding. # * #concat: Returns the concatenation of `self` with given other strings. -# * #prepend: Returns the concatenation of a given other string with `self`. # * #ljust: Returns a copy of `self` of a given length, right-padded with a # given other string. # * #rjust: Returns a copy of `self` of a given length, left-padded with a @@ -477,8 +822,7 @@ # # *Substitution* # -# * #dump: Returns a copy of `self` with all non-printing characters replaced -# by xHH notation and all special characters escaped. +# * #dump: Returns a printable version of `self`, enclosed in double-quotes. # * #undump: Returns a copy of `self` with all `\xNN` notations replaced by # `\uNNNN` notations and all escaped characters unescaped. # * #sub: Returns a copy of `self` with the first substring matching a given @@ -531,7 +875,7 @@ # * #to_s (aliased as #to_str): If `self` is a subclass of `String`, returns # `self` copied into a `String`; otherwise, returns `self`. # -# ### Methods for Converting to Non-`String` +# ### Converting to Non-String # # Each of these methods converts the contents of `self` to a non-`String`. # @@ -571,10 +915,14 @@ # * #oct: Returns the integer value of the leading characters, interpreted as # octal digits. # * #ord: Returns the integer ordinal of the first character in `self`. +# * #to_c: Returns the complex value of leading characters, interpreted as a +# complex number. # * #to_i: Returns the integer value of leading characters, interpreted as an # integer. # * #to_f: Returns the floating-point value of leading characters, interpreted # as a floating-point number. +# * #to_r: Returns the rational value of leading characters, interpreted as a +# rational. # # *Strings and Symbols* # @@ -582,7 +930,7 @@ # special characters escaped. # * #intern (aliased as #to_sym): Returns the symbol corresponding to `self`. # -# ### Methods for Iterating +# ### Iterating # # * #each_byte: Calls the given block with each successive byte in `self`. # * #each_char: Calls the given block with each successive character in @@ -606,14 +954,16 @@ class String # rdoc-file=string.c # - String.try_convert(object) -> object, new_string, or nil # --> - # If `object` is a `String` object, returns `object`. + # Attempts to convert the given `object` to a string. + # + # If `object` is already a string, returns `object`, unmodified. # # Otherwise if `object` responds to `:to_str`, calls `object.to_str` and returns # the result. # # Returns `nil` if `object` does not respond to `:to_str`. # - # Raises an exception unless `object.to_str` returns a `String` object. + # Raises an exception unless `object.to_str` returns a string. # def self.try_convert: (String object) -> String # technically will return `object` unchanged. | (_ToStr object) -> String @@ -621,37 +971,41 @@ class String # - # Returns a new String that is a copy of `string`. + # Returns a new String object containing the given `string`. + # + # The `options` are optional keyword options (see below). # - # With no arguments, returns the empty string with the Encoding `ASCII-8BIT`: + # With no argument given and keyword `encoding` also not given, returns an empty + # string with the Encoding `ASCII-8BIT`: # - # s = String.new - # s # => "" - # s.encoding # => # + # s = String.new # => "" + # s.encoding # => # # - # With optional argument `string` and no keyword arguments, returns a copy of - # `string` with the same encoding: + # With argument `string` given and keyword option `encoding` not given, returns + # a new string with the same encoding as `string`: # - # String.new('foo') # => "foo" - # String.new('тест') # => "тест" - # String.new('こんにちは') # => "こんにちは" + # s0 = 'foo'.encode(Encoding::UTF_16) + # s1 = String.new(s0) + # s1.encoding # => # # # (Unlike String.new, a [string # literal](rdoc-ref:syntax/literals.rdoc@String+Literals) like `''` or a [here # document literal](rdoc-ref:syntax/literals.rdoc@Here+Document+Literals) always # has [script encoding](rdoc-ref:encodings.rdoc@Script+Encoding).) # - # With optional keyword argument `encoding`, returns a copy of `string` with the - # specified encoding; the `encoding` may be an Encoding object, an encoding - # name, or an encoding name alias: + # With keyword option `encoding` given, returns a string with the specified + # encoding; the `encoding` may be an Encoding object, an encoding name, or an + # encoding name alias: # + # String.new(encoding: Encoding::US_ASCII).encoding # => # + # String.new('', encoding: Encoding::US_ASCII).encoding # => # # String.new('foo', encoding: Encoding::US_ASCII).encoding # => # # String.new('foo', encoding: 'US-ASCII').encoding # => # # String.new('foo', encoding: 'ASCII').encoding # => # # - # The given encoding need not be valid for the string's content, and that + # The given encoding need not be valid for the string's content, and its # validity is not checked: # # s = String.new('こんにちは', encoding: 'ascii') @@ -661,50 +1015,46 @@ class String # # String.new('foo', encoding: 'bar') # Raises ArgumentError. # - # With optional keyword argument `capacity`, returns a copy of `string` (or an - # empty string, if `string` is not given); the given `capacity` is advisory - # only, and may or may not set the size of the internal buffer, which may in - # turn affect performance: - # - # String.new(capacity: 1) - # String.new('foo', capacity: 4096) + # With keyword option `capacity` given, the given value is advisory only, and + # may or may not set the size of the internal buffer, which may in turn affect + # performance: # - # Note that Ruby strings are null-terminated internally, so the internal buffer - # size will be one or more bytes larger than the requested capacity depending on - # the encoding. - # - # The `string`, `encoding`, and `capacity` arguments may all be used together: - # - # String.new('hello', encoding: 'UTF-8', capacity: 25) + # String.new('foo', capacity: 1) # Buffer size is at least 4 (includes terminal null byte). + # String.new('foo', capacity: 4096) # Buffer size is at least 4; + # # may be equal to, greater than, or less than 4096. # def initialize: (?string source, ?encoding: encoding, ?capacity: int) -> void - # - # Replaces the contents of `self` with the contents of `other_string`: + # + # Replaces the contents of `self` with the contents of `other_string`; returns + # `self`: # # s = 'foo' # => "foo" # s.replace('bar') # => "bar" # + # Related: see [Modifying](rdoc-ref:String@Modifying). + # alias initialize_copy replace # - # Returns the result of formatting `object` into the format specification `self` - # (see Kernel#sprintf for formatting details): + # Returns the result of formatting `object` into the format specifications + # contained in `self` (see [Format + # Specifications](rdoc-ref:format_specifications.rdoc)): + # + # '%05d' % 123 # => "00123" # - # "%05d" % 123 # => "00123" + # If `self` contains multiple format specifications, `object` must be an array + # or hash containing the objects to be formatted: # - # If `self` contains multiple substitutions, `object` must be an Array or Hash - # containing the values to be substituted: + # '%-5s: %016x' % [ 'ID', self.object_id ] # => "ID : 00002b054ec93168" + # 'foo = %{foo}' % {foo: 'bar'} # => "foo = bar" + # 'foo = %{foo}, baz = %{baz}' % {foo: 'bar', baz: 'bat'} # => "foo = bar, baz = bat" # - # "%-5s: %016x" % [ "ID", self.object_id ] # => "ID : 00002b054ec93168" - # "foo = %{foo}" % {foo: 'bar'} # => "foo = bar" - # "foo = %{foo}, baz = %{baz}" % {foo: 'bar', baz: 'bat'} # => "foo = bar, baz = bat" + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def %: (array[untyped] positional_args) -> String | (hash[Symbol, untyped] named_args) -> String @@ -712,22 +1062,28 @@ class String # - # Returns a new `String` containing `integer` copies of `self`: + # Returns a new string containing `n` copies of `self`: # - # "Ho! " * 3 # => "Ho! Ho! Ho! " - # "Ho! " * 0 # => "" + # 'Ho!' * 3 # => "Ho!Ho!Ho!" + # 'No!' * 0 # => "" + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def *: (int amount) -> String # - # Returns a new `String` containing `other_string` concatenated to `self`: + # Returns a new string containing `other_string` concatenated to `self`: + # + # 'Hello from ' + self.to_s # => "Hello from main" # - # "Hello from " + self.to_s # => "Hello from main" + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def +: (string other_string) -> String @@ -740,68 +1096,88 @@ class String # # Otherwise returns `self.dup`, which is not frozen. # + # Related: see [Freezing/Unfreezing](rdoc-ref:String@Freezing-2FUnfreezing). + # def +@: () -> self # - # Returns a frozen, possibly pre-existing copy of the string. + # Returns a frozen string equal to `self`. + # + # The returned string is `self` if and only if all of the following are true: + # + # * `self` is already frozen. + # * `self` is an instance of String (rather than of a subclass of String) + # * `self` has no instance variables set on it. + # + # Otherwise, the returned string is a frozen copy of `self`. + # + # Returning `self`, when possible, saves duplicating `self`; see [Data + # deduplication](https://en.wikipedia.org/wiki/Data_deduplication). + # + # It may also save duplicating other, already-existing, strings: + # + # s0 = 'foo' + # s1 = 'foo' + # s0.object_id == s1.object_id # => false + # (-s0).object_id == (-s1).object_id # => true # - # The returned `String` will be deduplicated as long as it does not have any - # instance variables set on it and is not a String subclass. + # Note that method #-@ is convenient for defining a constant: # - # Note that `-string` variant is more convenient for defining constants: + # FileName = -'config/database.yml' # - # FILENAME = -'config/database.yml' + # While its alias #dedup is better suited for chaining: # - # while `dedup` is better suitable for using the method in chains of - # calculations: + # 'foo'.dedup.gsub!('o') # - # @url_list.concat(urls.map(&:dedup)) + # Related: see [Freezing/Unfreezing](rdoc-ref:String@Freezing-2FUnfreezing). # def -@: () -> self # - # Concatenates `object` to `self` and returns `self`: + # Appends a string representation of `object` to `self`; returns `self`. + # + # If `object` is a string, appends it to `self`: # # s = 'foo' # s << 'bar' # => "foobar" # s # => "foobar" # - # If `object` is an Integer, the value is considered a codepoint and converted - # to a character before concatenation: + # If `object` is an integer, its value is considered a codepoint; converts the + # value to a character before concatenating: # # s = 'foo' # s << 33 # => "foo!" # - # If that codepoint is not representable in the encoding of *string*, RangeError - # is raised. + # Additionally, if the codepoint is in range `0..0xff` and the encoding of + # `self` is Encoding::US_ASCII, changes the encoding to Encoding::ASCII_8BIT: + # + # s = 'foo'.encode(Encoding::US_ASCII) + # s.encoding # => # + # s << 0xff # => "foo\xFF" + # s.encoding # => # + # + # Raises RangeError if that codepoint is not representable in the encoding of + # `self`: # # s = 'foo' # s.encoding # => # s << 0x00110000 # 1114112 out of char range (RangeError) - # s = 'foo'.encode('EUC-JP') + # s = 'foo'.encode(Encoding::EUC_JP) # s << 0x00800080 # invalid codepoint 0x800080 in EUC-JP (RangeError) # - # If the encoding is US-ASCII and the codepoint is 0..0xff, *string* is - # automatically promoted to ASCII-8BIT. - # - # s = 'foo'.encode('US-ASCII') - # s << 0xff - # s.encoding # => # - # - # Related: String#concat, which takes multiple arguments. + # Related: see [Modifying](rdoc-ref:String@Modifying). # def <<: (string | Integer str_or_codepoint) -> self # # Compares `self` and `other_string`, returning: # @@ -812,79 +1188,98 @@ class String # # Examples: # - # 'foo' <=> 'foo' # => 0 + # 'foo' <=> 'foo' # => 0 # 'foo' <=> 'food' # => -1 # 'food' <=> 'foo' # => 1 - # 'FOO' <=> 'foo' # => -1 - # 'foo' <=> 'FOO' # => 1 - # 'foo' <=> 1 # => nil + # 'FOO' <=> 'foo' # => -1 + # 'foo' <=> 'FOO' # => 1 + # 'foo' <=> 1 # => nil + # + # Related: see [Comparing](rdoc-ref:String@Comparing). # def <=>: (string) -> (-1 | 0 | 1) | (untyped) -> (-1 | 0 | 1)? # - # Returns `true` if `object` has the same length and content; as `self`; `false` - # otherwise: + # Returns whether `object` is equal to `self`. + # + # When `object` is a string, returns whether `object` has the same length and + # content as `self`: # # s = 'foo' - # s == 'foo' # => true + # s == 'foo' # => true # s == 'food' # => false - # s == 'FOO' # => false + # s == 'FOO' # => false # # Returns `false` if the two strings' encodings are not compatible: - # "\u{e4 f6 fc}".encode("ISO-8859-1") == ("\u{c4 d6 dc}") # => false # - # If `object` is not an instance of `String` but responds to `to_str`, then the - # two strings are compared using `object.==`. + # "\u{e4 f6 fc}".encode(Encoding::ISO_8859_1) == ("\u{c4 d6 dc}") # => false + # + # When `object` is not a string: + # + # * If `object` responds to method `to_str`, `object == self` is called and + # its return value is returned. + # * If `object` does not respond to `to_str`, `false` is returned. + # + # Related: [Comparing](rdoc-ref:String@Comparing). # def ==: (untyped other) -> bool # - # Returns `true` if `object` has the same length and content; as `self`; `false` - # otherwise: + # Returns whether `object` is equal to `self`. + # + # When `object` is a string, returns whether `object` has the same length and + # content as `self`: # # s = 'foo' - # s == 'foo' # => true + # s == 'foo' # => true # s == 'food' # => false - # s == 'FOO' # => false + # s == 'FOO' # => false # # Returns `false` if the two strings' encodings are not compatible: - # "\u{e4 f6 fc}".encode("ISO-8859-1") == ("\u{c4 d6 dc}") # => false # - # If `object` is not an instance of `String` but responds to `to_str`, then the - # two strings are compared using `object.==`. + # "\u{e4 f6 fc}".encode(Encoding::ISO_8859_1) == ("\u{c4 d6 dc}") # => false + # + # When `object` is not a string: + # + # * If `object` responds to method `to_str`, `object == self` is called and + # its return value is returned. + # * If `object` does not respond to `to_str`, `false` is returned. + # + # Related: [Comparing](rdoc-ref:String@Comparing). # alias === == # - # Returns the Integer index of the first substring that matches the given - # `regexp`, or `nil` if no match found: + # When `object` is a Regexp, returns the index of the first substring in `self` + # matched by `object`, or `nil` if no match is found; updates [Regexp-related + # global variables](rdoc-ref:Regexp@Global+Variables): # # 'foo' =~ /f/ # => 0 + # $~ # => # # 'foo' =~ /o/ # => 1 + # $~ # => # # 'foo' =~ /x/ # => nil - # - # Note: also updates Regexp@Global+Variables. - # - # If the given `object` is not a Regexp, returns the value returned by `object - # =~ self`. + # $~ # => nil # # Note that `string =~ regexp` is different from `regexp =~ string` (see # Regexp#=~): # - # number= nil - # "no. 9" =~ /(?\d+)/ - # number # => nil (not assigned) - # /(?\d+)/ =~ "no. 9" - # number #=> "9" + # number = nil + # 'no. 9' =~ /(?\d+)/ # => 4 + # number # => nil # Not assigned. + # /(?\d+)/ =~ 'no. 9' # => 4 + # number # => "9" # Assigned. + # + # If `object` is not a Regexp, returns the value returned by `object =~ self`. + # + # Related: see [Querying](rdoc-ref:String@Querying). # def =~: (Regexp regex) -> Integer? | [T] (_MatchAgainst[self, T] object) -> T @@ -895,14 +1290,108 @@ class String # - # Returns the substring of `self` specified by the arguments. See examples at - # [String Slices](rdoc-ref:String@String+Slices). + # Returns the substring of `self` specified by the arguments. + # + # **Form `self[index]`** + # + # With non-negative integer argument `index` given, returns the 1-character + # substring found in self at character offset index: + # + # 'hello'[0] # => "h" + # 'hello'[4] # => "o" + # 'hello'[5] # => nil + # 'тест'[2] # => "с" + # 'こんにちは'[4] # => "は" + # + # With negative integer argument `index` given, counts backward from the end of + # `self`: + # + # 'hello'[-1] # => "o" + # 'hello'[-5] # => "h" + # 'hello'[-6] # => nil + # + # **Form `self[start, length]`** + # + # With integer arguments `start` and `length` given, returns a substring of size + # `length` characters (as available) beginning at character offset specified by + # `start`. + # + # If argument `start` is non-negative, the offset is `start`: + # + # 'hello'[0, 1] # => "h" + # 'hello'[0, 5] # => "hello" + # 'hello'[0, 6] # => "hello" + # 'hello'[2, 3] # => "llo" + # 'hello'[2, 0] # => "" + # 'hello'[2, -1] # => nil + # + # If argument `start` is negative, counts backward from the end of `self`: + # + # 'hello'[-1, 1] # => "o" + # 'hello'[-5, 5] # => "hello" + # 'hello'[-1, 0] # => "" + # 'hello'[-6, 5] # => nil + # + # Special case: if `start` equals the length of `self`, returns a new empty + # string: + # + # 'hello'[5, 3] # => "" + # + # **Form `self[range]`** + # + # With Range argument `range` given, forms substring `self[range.start, + # range.size]`: + # + # 'hello'[0..2] # => "hel" + # 'hello'[0, 3] # => "hel" + # + # 'hello'[0...2] # => "he" + # 'hello'[0, 2] # => "he" + # + # 'hello'[0, 0] # => "" + # 'hello'[0...0] # => "" + # + # **Form `self[regexp, capture = 0]`** + # + # With Regexp argument `regexp` given and `capture` as zero, searches for a + # matching substring in `self`; updates [Regexp-related global + # variables](rdoc-ref:Regexp@Global+Variables): + # + # 'hello'[/ell/] # => "ell" + # 'hello'[/l+/] # => "ll" + # 'hello'[//] # => "" + # 'hello'[/nosuch/] # => nil + # + # With `capture` as a positive integer `n`, returns the +n+th matched group: + # + # 'hello'[/(h)(e)(l+)(o)/] # => "hello" + # 'hello'[/(h)(e)(l+)(o)/, 1] # => "h" + # $1 # => "h" + # 'hello'[/(h)(e)(l+)(o)/, 2] # => "e" + # $2 # => "e" + # 'hello'[/(h)(e)(l+)(o)/, 3] # => "ll" + # 'hello'[/(h)(e)(l+)(o)/, 4] # => "o" + # 'hello'[/(h)(e)(l+)(o)/, 5] # => nil + # + # **Form `self[substring]`** + # + # With string argument `substring` given, returns the matching substring of + # `self`, if found: + # + # 'hello'['ell'] # => "ell" + # 'hello'[''] # => "" + # 'hello'['nosuch'] # => nil + # 'тест'['ес'] # => "ес" + # 'こんにちは'['んにち'] # => "んにち" + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def []: (int start, ?int length) -> String? | (range[int?] range) -> String? @@ -911,28 +1400,193 @@ class String # - # Replaces all, some, or none of the contents of `self`; returns `new_string`. - # See [String Slices](rdoc-ref:String@String+Slices). + # Returns `self` with all, a substring, or none of its contents replaced; + # returns the argument `other_string`. # - # A few examples: + # **Form `self[index] = other_string`** # - # s = 'foo' - # s[2] = 'rtune' # => "rtune" - # s # => "fortune" - # s[1, 5] = 'init' # => "init" - # s # => "finite" - # s[3..4] = 'al' # => "al" - # s # => "finale" - # s[/e$/] = 'ly' # => "ly" - # s # => "finally" - # s['lly'] = 'ncial' # => "ncial" - # s # => "financial" + # With non-negative integer argument `index` given, searches for the 1-character + # substring found in self at character offset index: + # + # s = 'hello' + # s[0] = 'foo' # => "foo" + # s # => "fooello" + # + # s = 'hello' + # s[4] = 'foo' # => "foo" + # s # => "hellfoo" + # + # s = 'hello' + # s[5] = 'foo' # => "foo" + # s # => "hellofoo" + # + # s = 'hello' + # s[6] = 'foo' # Raises IndexError: index 6 out of string. + # + # With negative integer argument `index` given, counts backward from the end of + # `self`: + # + # s = 'hello' + # s[-1] = 'foo' # => "foo" + # s # => "hellfoo" + # + # s = 'hello' + # s[-5] = 'foo' # => "foo" + # s # => "fooello" + # + # s = 'hello' + # s[-6] = 'foo' # Raises IndexError: index -6 out of string. + # + # **Form `self[start, length] = other_string`** + # + # With integer arguments `start` and `length` given, searches for a substring of + # size `length` characters (as available) beginning at character offset + # specified by `start`. + # + # If argument `start` is non-negative, the offset is +start': + # + # s = 'hello' + # s[0, 1] = 'foo' # => "foo" + # s # => "fooello" + # + # s = 'hello' + # s[0, 5] = 'foo' # => "foo" + # s # => "foo" + # + # s = 'hello' + # s[0, 9] = 'foo' # => "foo" + # s # => "foo" + # + # s = 'hello' + # s[2, 0] = 'foo' # => "foo" + # s # => "hefoollo" + # + # s = 'hello' + # s[2, -1] = 'foo' # Raises IndexError: negative length -1. + # + # If argument `start` is negative, counts backward from the end of `self`: + # + # s = 'hello' + # s[-1, 1] = 'foo' # => "foo" + # s # => "hellfoo" + # + # s = 'hello' + # s[-1, 9] = 'foo' # => "foo" + # s # => "hellfoo" + # + # s = 'hello' + # s[-5, 2] = 'foo' # => "foo" + # s # => "foollo" + # + # s = 'hello' + # s[-3, 0] = 'foo' # => "foo" + # s # => "hefoollo" + # + # s = 'hello' + # s[-6, 2] = 'foo' # Raises IndexError: index -6 out of string. + # + # Special case: if `start` equals the length of `self`, the argument is appended + # to `self`: + # + # s = 'hello' + # s[5, 3] = 'foo' # => "foo" + # s # => "hellofoo" + # + # **Form `self[range] = other_string`** + # + # With Range argument `range` given, equivalent to `self[range.start, + # range.size] = other_string`: + # + # s0 = 'hello' + # s1 = 'hello' + # s0[0..2] = 'foo' # => "foo" + # s1[0, 3] = 'foo' # => "foo" + # s0 # => "foolo" + # s1 # => "foolo" + # + # s = 'hello' + # s[0...2] = 'foo' # => "foo" + # s # => "foollo" + # + # s = 'hello' + # s[0...0] = 'foo' # => "foo" + # s # => "foohello" + # + # s = 'hello' + # s[9..10] = 'foo' # Raises RangeError: 9..10 out of range + # + # **Form `self[regexp, capture = 0] = other_string`** + # + # With Regexp argument `regexp` given and `capture` as zero, searches for a + # matching substring in `self`; updates [Regexp-related global + # variables](rdoc-ref:Regexp@Global+Variables): + # + # s = 'hello' + # s[/l/] = 'L' # => "L" + # [$`, $&, $'] # => ["he", "l", "lo"] + # s[/eLlo/] = 'owdy' # => "owdy" + # [$`, $&, $'] # => ["h", "eLlo", ""] + # s[/eLlo/] = 'owdy' # Raises IndexError: regexp not matched. + # [$`, $&, $'] # => [nil, nil, nil] + # + # With `capture` as a positive integer `n`, searches for the +n+th matched + # group: + # + # s = 'hello' + # s[/(h)(e)(l+)(o)/] = 'foo' # => "foo" + # [$`, $&, $'] # => ["", "hello", ""] + # + # s = 'hello' + # s[/(h)(e)(l+)(o)/, 1] = 'foo' # => "foo" + # s # => "fooello" + # [$`, $&, $'] # => ["", "hello", ""] + # + # s = 'hello' + # s[/(h)(e)(l+)(o)/, 2] = 'foo' # => "foo" + # s # => "hfoollo" + # [$`, $&, $'] # => ["", "hello", ""] + # + # s = 'hello' + # s[/(h)(e)(l+)(o)/, 4] = 'foo' # => "foo" + # s # => "hellfoo" + # [$`, $&, $'] # => ["", "hello", ""] + # + # s = 'hello' + # # => "hello" + # s[/(h)(e)(l+)(o)/, 5] = 'foo # Raises IndexError: index 5 out of regexp. + # + # s = 'hello' + # s[/nosuch/] = 'foo' # Raises IndexError: regexp not matched. + # + # **Form `self[substring] = other_string`** + # + # With string argument `substring` given: + # + # s = 'hello' + # s['l'] = 'foo' # => "foo" + # s # => "hefoolo" + # + # s = 'hello' + # s['ll'] = 'foo' # => "foo" + # s # => "hefooo" + # + # s = 'тест' + # s['ес'] = 'foo' # => "foo" + # s # => "тfooт" + # + # s = 'こんにちは' + # s['んにち'] = 'foo' # => "foo" + # s # => "こfooは" + # + # s['nosuch'] = 'foo' # Raises IndexError: string not matched. + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # def []=: [T < _ToStr] (int index, T replacement) -> T | [T < _ToStr] (int start, int length, T replacement) -> T @@ -943,25 +1597,26 @@ class String # - # Concatenates each object in `objects` into `self` without any encoding - # validation or conversion and returns `self`: + # Concatenates each object in `objects` into `self`; returns `self`; performs no + # encoding validation or conversion: # # s = 'foo' - # s.append_as_bytes(" \xE2\x82") # => "foo \xE2\x82" - # s.valid_encoding? # => false + # s.append_as_bytes(" \xE2\x82") # => "foo \xE2\x82" + # s.valid_encoding? # => false # s.append_as_bytes("\xAC 12") - # s.valid_encoding? # => true + # s.valid_encoding? # => true # - # For each given object `object` that is an Integer, the value is considered a - # Byte. If the Integer is bigger than one byte, only the lower byte is - # considered, similar to String#setbyte: + # When a given object is an integer, the value is considered an 8-bit byte; if + # the integer occupies more than one byte (i.e,. is greater than 255), appends + # only the low-order byte (similar to String#setbyte): # # s = "" - # s.append_as_bytes(0, 257) # => "\u0000\u0001" + # s.append_as_bytes(0, 257) # => "\u0000\u0001" + # s.bytesize # => 2 # - # Related: String#<<, String#concat, which do an encoding aware concatenation. + # Related: see [Modifying](rdoc-ref:String@Modifying). # def append_as_bytes: (String) -> String @@ -969,16 +1624,18 @@ class String # rdoc-file=string.c # - ascii_only? -> true or false # --> - # Returns `true` if `self` contains only ASCII characters, `false` otherwise: + # Returns whether `self` contains only ASCII characters: # # 'abc'.ascii_only? # => true # "abc\u{6666}".ascii_only? # => false # + # Related: see [Querying](rdoc-ref:String@Querying). + # def ascii_only?: () -> bool # # Returns a copy of `self` that has ASCII-8BIT encoding; the underlying bytes # are not modified: @@ -995,107 +1652,162 @@ class String # t.encoding # => # # t.bytes # => [228, 130, 149] # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). + # def b: () -> String # - # Returns the Integer byte-based index of the first occurrence of the given - # `substring`, or `nil` if none found: + # Returns the 0-based integer index of a substring of `self` specified by + # `object` (a string or Regexp) and `offset`, or `nil` if there is no such + # substring; the returned index is the count of *bytes* (not characters). # - # 'foo'.byteindex('f') # => 0 - # 'foo'.byteindex('o') # => 1 - # 'foo'.byteindex('oo') # => 1 - # 'foo'.byteindex('ooo') # => nil + # When `object` is a string, returns the index of the first found substring + # equal to `object`: # - # Returns the Integer byte-based index of the first match for the given Regexp - # `regexp`, or `nil` if none found: + # s = 'foo' # => "foo" + # s.size # => 3 # Three 1-byte characters. + # s.bytesize # => 3 # Three bytes. + # s.byteindex('f') # => 0 + # s.byteindex('o') # => 1 + # s.byteindex('oo') # => 1 + # s.byteindex('ooo') # => nil # - # 'foo'.byteindex(/f/) # => 0 - # 'foo'.byteindex(/o/) # => 1 - # 'foo'.byteindex(/oo/) # => 1 - # 'foo'.byteindex(/ooo/) # => nil + # When `object` is a Regexp, returns the index of the first found substring + # matching `object`; updates [Regexp-related global + # variables](rdoc-ref:Regexp@Global+Variables): # - # Integer argument `offset`, if given, specifies the byte-based position in the - # string to begin the search: + # s = 'foo' + # s.byteindex(/f/) # => 0 + # $~ # => # + # s.byteindex(/o/) # => 1 + # s.byteindex(/oo/) # => 1 + # s.byteindex(/ooo/) # => nil + # $~ # => nil # - # 'foo'.byteindex('o', 1) # => 1 - # 'foo'.byteindex('o', 2) # => 2 - # 'foo'.byteindex('o', 3) # => nil + # Integer argument `offset`, if given, specifies the 0-based index of the byte + # where searching is to begin. # - # If `offset` is negative, counts backward from the end of `self`: + # When `offset` is non-negative, searching begins at byte position `offset`: # - # 'foo'.byteindex('o', -1) # => 2 - # 'foo'.byteindex('o', -2) # => 1 - # 'foo'.byteindex('o', -3) # => 1 - # 'foo'.byteindex('o', -4) # => nil + # s = 'foo' + # s.byteindex('o', 1) # => 1 + # s.byteindex('o', 2) # => 2 + # s.byteindex('o', 3) # => nil # - # If `offset` does not land on character (codepoint) boundary, `IndexError` is - # raised. + # When `offset` is negative, counts backward from the end of `self`: # - # Related: String#index, String#byterindex. + # s = 'foo' + # s.byteindex('o', -1) # => 2 + # s.byteindex('o', -2) # => 1 + # s.byteindex('o', -3) # => 1 + # s.byteindex('o', -4) # => nil + # + # Raises IndexError if the byte at `offset` is not the first byte of a + # character: + # + # s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF" + # s.size # => 2 # Two 3-byte characters. + # s.bytesize # => 6 # Six bytes. + # s.byteindex("\uFFFF") # => 0 + # s.byteindex("\uFFFF", 1) # Raises IndexError + # s.byteindex("\uFFFF", 2) # Raises IndexError + # s.byteindex("\uFFFF", 3) # => 3 + # s.byteindex("\uFFFF", 4) # Raises IndexError + # s.byteindex("\uFFFF", 5) # Raises IndexError + # s.byteindex("\uFFFF", 6) # => nil + # + # Related: see [Querying](rdoc-ref:String@Querying). # def byteindex: (Regexp | string pattern, ?int offset) -> Integer? # - # Returns the Integer byte-based index of the *last* occurrence of the given - # `substring`, or `nil` if none found: - # - # 'foo'.byterindex('f') # => 0 - # 'foo'.byterindex('o') # => 2 - # 'foo'.byterindex('oo') # => 1 - # 'foo'.byterindex('ooo') # => nil + # Returns the 0-based integer index of a substring of `self` that is the *last* + # match for the given `object` (a string or Regexp) and `offset`, or `nil` if + # there is no such substring; the returned index is the count of *bytes* (not + # characters). + # + # When `object` is a string, returns the index of the *last* found substring + # equal to `object`: + # + # s = 'foo' # => "foo" + # s.size # => 3 # Three 1-byte characters. + # s.bytesize # => 3 # Three bytes. + # s.byterindex('f') # => 0 + # s.byterindex('o') # => 2 + # s.byterindex('oo') # => 1 + # s.byterindex('ooo') # => nil + # + # When `object` is a Regexp, returns the index of the last found substring + # matching `object`; updates [Regexp-related global + # variables](rdoc-ref:Regexp@Global+Variables): # - # Returns the Integer byte-based index of the *last* match for the given Regexp - # `regexp`, or `nil` if none found: - # - # 'foo'.byterindex(/f/) # => 0 - # 'foo'.byterindex(/o/) # => 2 - # 'foo'.byterindex(/oo/) # => 1 - # 'foo'.byterindex(/ooo/) # => nil - # - # The *last* match means starting at the possible last position, not the last of - # longest matches. + # s = 'foo' + # s.byterindex(/f/) # => 0 + # $~ # => # + # s.byterindex(/o/) # => 2 + # s.byterindex(/oo/) # => 1 + # s.byterindex(/ooo/) # => nil + # $~ # => nil # - # 'foo'.byterindex(/o+/) # => 2 - # $~ #=> # + # The last match means starting at the possible last position, not the last of + # the longest matches: # - # To get the last longest match, needs to combine with negative lookbehind. + # s = 'foo' + # s.byterindex(/o+/) # => 2 + # $~ #=> # # - # 'foo'.byterindex(/(? 1 - # $~ #=> # + # To get the last longest match, use a negative lookbehind: # - # Or String#byteindex with negative lookforward. + # s = 'foo' + # s.byterindex(/(? 1 + # $~ # => # # - # 'foo'.byteindex(/o+(?!.*o)/) # => 1 - # $~ #=> # + # Or use method #byteindex with negative lookahead: # - # Integer argument `offset`, if given and non-negative, specifies the maximum - # starting byte-based position in the string to *end* the search: + # s = 'foo' + # s.byteindex(/o+(?!.*o)/) # => 1 + # $~ #=> # # - # 'foo'.byterindex('o', 0) # => nil - # 'foo'.byterindex('o', 1) # => 1 - # 'foo'.byterindex('o', 2) # => 2 - # 'foo'.byterindex('o', 3) # => 2 + # Integer argument `offset`, if given, specifies the 0-based index of the byte + # where searching is to end. # - # If `offset` is a negative Integer, the maximum starting position in the string - # to *end* the search is the sum of the string's length and `offset`: + # When `offset` is non-negative, searching ends at byte position `offset`: # - # 'foo'.byterindex('o', -1) # => 2 - # 'foo'.byterindex('o', -2) # => 1 - # 'foo'.byterindex('o', -3) # => nil - # 'foo'.byterindex('o', -4) # => nil + # s = 'foo' + # s.byterindex('o', 0) # => nil + # s.byterindex('o', 1) # => 1 + # s.byterindex('o', 2) # => 2 + # s.byterindex('o', 3) # => 2 # - # If `offset` does not land on character (codepoint) boundary, `IndexError` is - # raised. + # When `offset` is negative, counts backward from the end of `self`: # - # Related: String#byteindex. + # s = 'foo' + # s.byterindex('o', -1) # => 2 + # s.byterindex('o', -2) # => 1 + # s.byterindex('o', -3) # => nil + # + # Raises IndexError if the byte at `offset` is not the first byte of a + # character: + # + # s = "\uFFFF\uFFFF" # => "\uFFFF\uFFFF" + # s.size # => 2 # Two 3-byte characters. + # s.bytesize # => 6 # Six bytes. + # s.byterindex("\uFFFF") # => 3 + # s.byterindex("\uFFFF", 1) # Raises IndexError + # s.byterindex("\uFFFF", 2) # Raises IndexError + # s.byterindex("\uFFFF", 3) # => 3 + # s.byterindex("\uFFFF", 4) # Raises IndexError + # s.byterindex("\uFFFF", 5) # Raises IndexError + # s.byterindex("\uFFFF", 6) # => nil + # + # Related: see [Querying](rdoc-ref:String@Querying). # def byterindex: (Regexp | string pattern, ?int offset) -> Integer? @@ -1110,6 +1822,9 @@ class String # 'こんにちは'.bytes # # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175] # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). + # def bytes: () -> Array[Integer] | () { (Integer byte) -> void } -> self @@ -1117,42 +1832,48 @@ class String # rdoc-file=string.c # - bytesize -> integer # --> - # Returns the count of bytes (not characters) in `self`: + # Returns the count of bytes in `self`. # - # 'foo'.bytesize # => 3 - # 'тест'.bytesize # => 8 - # 'こんにちは'.bytesize # => 15 + # Note that the byte count may be different from the character count (returned + # by #size): # - # Contrast with String#length: + # s = 'foo' + # s.bytesize # => 3 + # s.size # => 3 + # s = 'тест' + # s.bytesize # => 8 + # s.size # => 4 + # s = 'こんにちは' + # s.bytesize # => 15 + # s.size # => 5 # - # 'foo'.length # => 3 - # 'тест'.length # => 4 - # 'こんにちは'.length # => 5 + # Related: see [Querying](rdoc-ref:String@Querying). # def bytesize: () -> Integer # # Returns a substring of `self`, or `nil` if the substring cannot be # constructed. # - # With integer arguments `index` and `length` given, returns the substring - # beginning at the given `index` of the given `length` (if possible), or `nil` - # if `length` is negative or `index` falls outside of `self`: + # With integer arguments `offset` and `length` given, returns the substring + # beginning at the given `offset` and of the given `length` (as available): # - # s = '0123456789' # => "0123456789" - # s.byteslice(2) # => "2" - # s.byteslice(200) # => nil + # s = '0123456789' # => "0123456789" + # s.byteslice(2) # => "2" + # s.byteslice(200) # => nil # s.byteslice(4, 3) # => "456" # s.byteslice(4, 30) # => "456789" + # + # Returns `nil` if `length` is negative or `offset` falls outside of `self`: + # # s.byteslice(4, -1) # => nil # s.byteslice(40, 2) # => nil # - # In either case above, counts backwards from the end of `self` if `index` is - # negative: + # Counts backwards from the end of `self` if `offset` is negative: # # s = '0123456789' # => "0123456789" # s.byteslice(-4) # => "6" @@ -1167,36 +1888,100 @@ class String # s.byteslice(5..2) # => "" # range.size is zero. # s.byteslice(40..42) # => nil # - # In all cases, a returned string has the same encoding as `self`: + # The starting and ending offsets need not be on character boundaries: # - # s.encoding # => # - # s.byteslice(4).encoding # => # + # s = 'こんにちは' + # s.byteslice(0, 3) # => "こ" + # s.byteslice(1, 3) # => "\x81\x93\xE3" + # + # The encodings of `self` and the returned substring are always the same: + # + # s.encoding # => # + # s.byteslice(0, 3).encoding # => # + # s.byteslice(1, 3).encoding # => # + # + # But, depending on the character boundaries, the encoding of the returned + # substring may not be valid: + # + # s.valid_encoding? # => true + # s.byteslice(0, 3).valid_encoding? # => true + # s.byteslice(1, 3).valid_encoding? # => false + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def byteslice: (int start, ?int length) -> String? | (range[int?] range) -> String? # - # Replaces some or all of the content of `self` with `str`, and returns `self`. - # The portion of the string affected is determined using the same criteria as - # String#byteslice, except that `length` cannot be omitted. If the replacement - # string is not the same length as the text it is replacing, the string will be - # adjusted accordingly. + # Replaces *target bytes* in `self` with *source bytes* from the given string + # `str`; returns `self`. + # + # In the first form, arguments `offset` and `length` determine the target bytes, + # and the source bytes are all of the given `str`: + # + # '0123456789'.bytesplice(0, 3, 'abc') # => "abc3456789" + # '0123456789'.bytesplice(3, 3, 'abc') # => "012abc6789" + # '0123456789'.bytesplice(0, 50, 'abc') # => "abc" + # '0123456789'.bytesplice(50, 3, 'abc') # Raises IndexError. # - # If `str_index` and `str_length`, or `str_range` are given, the content of - # `self` is replaced by str.byteslice(str_index, str_length) or - # str.byteslice(str_range); however the substring of `str` is not allocated as a - # new string. + # The counts of the target bytes and source source bytes may be different: # - # The form that take an Integer will raise an IndexError if the value is out of - # range; the Range form will raise a RangeError. If the beginning or ending - # offset does not land on character (codepoint) boundary, an IndexError will be - # raised. + # '0123456789'.bytesplice(0, 6, 'abc') # => "abc6789" # Shorter source. + # '0123456789'.bytesplice(0, 1, 'abc') # => "abc123456789" # Shorter target. + # + # And either count may be zero (i.e., specifying an empty string): + # + # '0123456789'.bytesplice(0, 3, '') # => "3456789" # Empty source. + # '0123456789'.bytesplice(0, 0, 'abc') # => "abc0123456789" # Empty target. + # + # In the second form, just as in the first, arugments `offset` and `length` + # determine the target bytes; argument `str` *contains* the source bytes, and + # the additional arguments `str_offset` and `str_length` determine the actual + # source bytes: + # + # '0123456789'.bytesplice(0, 3, 'abc', 0, 3) # => "abc3456789" + # '0123456789'.bytesplice(0, 3, 'abc', 1, 1) # => "b3456789" # Shorter source. + # '0123456789'.bytesplice(0, 1, 'abc', 0, 3) # => "abc123456789" # Shorter target. + # '0123456789'.bytesplice(0, 3, 'abc', 1, 0) # => "3456789" # Empty source. + # '0123456789'.bytesplice(0, 0, 'abc', 0, 3) # => "abc0123456789" # Empty target. + # + # In the third form, argument `range` determines the target bytes and the source + # bytes are all of the given `str`: + # + # '0123456789'.bytesplice(0..2, 'abc') # => "abc3456789" + # '0123456789'.bytesplice(3..5, 'abc') # => "012abc6789" + # '0123456789'.bytesplice(0..5, 'abc') # => "abc6789" # Shorter source. + # '0123456789'.bytesplice(0..0, 'abc') # => "abc123456789" # Shorter target. + # '0123456789'.bytesplice(0..2, '') # => "3456789" # Empty source. + # '0123456789'.bytesplice(0...0, 'abc') # => "abc0123456789" # Empty target. + # + # In the fourth form, just as in the third, arugment `range` determines the + # target bytes; argument `str` *contains* the source bytes, and the additional + # argument `str_range` determines the actual source bytes: + # + # '0123456789'.bytesplice(0..2, 'abc', 0..2) # => "abc3456789" + # '0123456789'.bytesplice(3..5, 'abc', 0..2) # => "012abc6789" + # '0123456789'.bytesplice(0..2, 'abc', 0..1) # => "ab3456789" # Shorter source. + # '0123456789'.bytesplice(0..1, 'abc', 0..2) # => "abc23456789" # Shorter target. + # '0123456789'.bytesplice(0..2, 'abc', 0...0) # => "3456789" # Empty source. + # '0123456789'.bytesplice(0...0, 'abc', 0..2) # => "abc0123456789" # Empty target. + # + # In any of the forms, the beginnings and endings of both source and target must + # be on character boundaries. + # + # In these examples, `self` has five 3-byte characters, and so has character + # boundaries at offsets 0, 3, 6, 9, 12, and 15. + # + # 'こんにちは'.bytesplice(0, 3, 'abc') # => "abcんにちは" + # 'こんにちは'.bytesplice(1, 3, 'abc') # Raises IndexError. + # 'こんにちは'.bytesplice(0, 2, 'abc') # Raises IndexError. # def bytesplice: (Integer start, int length, string str) -> String | (int start, int length, string str, int str_start, int str_length) -> String @@ -1204,18 +1989,29 @@ class String # - # Returns a string containing the characters in `self`; the first character is - # upcased; the remaining characters are downcased: + # Returns a string containing the characters in `self`, each with possibly + # changed case: # - # s = 'hello World!' # => "hello World!" - # s.capitalize # => "Hello world!" + # * The first character is upcased. + # * All other characters are downcased. # - # The casing may be affected by the given `options`; see [Case - # Mapping](rdoc-ref:case_mapping.rdoc). + # Examples: + # + # 'hello world'.capitalize # => "Hello world" + # 'HELLO WORLD'.capitalize # => "Hello world" + # + # Some characters do not have upcase and downcase, and so are not changed; see + # [Case Mapping](rdoc-ref:case_mapping.rdoc): + # + # '1, 2, 3, ...'.capitalize # => "1, 2, 3, ..." # - # Related: String#capitalize!. + # The casing is affected by the given `mapping`, which may be `:ascii`, `:fold`, + # or `:turkic`; see [Case Mappings](rdoc-ref:case_mapping.rdoc@Case+Mappings). + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def capitalize: () -> String | (:ascii | :lithuanian | :turkic) -> String @@ -1224,20 +2020,14 @@ class String # - # Upcases the first character in `self`; downcases the remaining characters; - # returns `self` if any changes were made, `nil` otherwise: - # - # s = 'hello World!' # => "hello World!" - # s.capitalize! # => "Hello world!" - # s # => "Hello world!" - # s.capitalize! # => nil + # Like String#capitalize, except that: # - # The casing may be affected by the given `options`; see [Case - # Mapping](rdoc-ref:case_mapping.rdoc). + # * Changes character casings in `self` (not in a copy of `self`). + # * Returns `self` if any changes are made, `nil` otherwise. # - # Related: String#capitalize. + # Related: See [Modifying](rdoc-ref:String@Modifying). # def capitalize!: () -> self? | (:ascii | :lithuanian | :turkic) -> self? @@ -1248,25 +2038,26 @@ class String # rdoc-file=string.c # - casecmp(other_string) -> -1, 0, 1, or nil # --> - # Compares `self.downcase` and `other_string.downcase`; returns: + # Ignoring case, compares `self` and `other_string`; returns: # - # * -1 if `other_string.downcase` is larger. + # * -1 if `self.downcase` is smaller than `other_string.downcase`. # * 0 if the two are equal. - # * 1 if `other_string.downcase` is smaller. + # * 1 if `self.downcase` is larger than `other_string.downcase`. # * `nil` if the two are incomparable. # + # See [Case Mapping](rdoc-ref:case_mapping.rdoc). + # # Examples: # - # 'foo'.casecmp('foo') # => 0 + # 'foo'.casecmp('goo') # => -1 + # 'goo'.casecmp('foo') # => 1 # 'foo'.casecmp('food') # => -1 # 'food'.casecmp('foo') # => 1 - # 'FOO'.casecmp('foo') # => 0 - # 'foo'.casecmp('FOO') # => 0 - # 'foo'.casecmp(1) # => nil - # - # See [Case Mapping](rdoc-ref:case_mapping.rdoc). + # 'FOO'.casecmp('foo') # => 0 + # 'foo'.casecmp('FOO') # => 0 + # 'foo'.casecmp(1) # => nil # - # Related: String#casecmp?. + # Related: see [Comparing](rdoc-ref:String@Comparing). # def casecmp: (string other) -> (-1 | 0 | 1) | (untyped) -> (-1 | 0 | 1)? @@ -1276,21 +2067,21 @@ class String # - casecmp?(other_string) -> true, false, or nil # --> # Returns `true` if `self` and `other_string` are equal after Unicode case - # folding, otherwise `false`: - # - # 'foo'.casecmp?('foo') # => true - # 'foo'.casecmp?('food') # => false - # 'food'.casecmp?('foo') # => false - # 'FOO'.casecmp?('foo') # => true - # 'foo'.casecmp?('FOO') # => true + # folding, `false` if unequal, `nil` if incomparable. # - # Returns `nil` if the two values are incomparable: + # See [Case Mapping](rdoc-ref:case_mapping.rdoc). # - # 'foo'.casecmp?(1) # => nil + # Examples: # - # See [Case Mapping](rdoc-ref:case_mapping.rdoc). + # 'foo'.casecmp?('goo') # => false + # 'goo'.casecmp?('foo') # => false + # 'foo'.casecmp?('food') # => false + # 'food'.casecmp?('foo') # => false + # 'FOO'.casecmp?('foo') # => true + # 'foo'.casecmp?('FOO') # => true + # 'foo'.casecmp?(1) # => nil # - # Related: String#casecmp. + # Related: see [Comparing](rdoc-ref:String@Comparing). # def casecmp?: (string other) -> bool | (untyped) -> bool? @@ -1303,20 +2094,24 @@ class String # # If integer argument `size` is greater than the size (in characters) of `self`, # returns a new string of length `size` that is a copy of `self`, centered and - # padded on both ends with `pad_string`: + # padded on one or both ends with `pad_string`: # - # 'hello'.center(10) # => " hello " - # ' hello'.center(10) # => " hello " - # 'hello'.center(10, 'ab') # => "abhelloaba" - # 'тест'.center(10) # => " тест " - # 'こんにちは'.center(10) # => " こんにちは " + # 'hello'.center(6) # => "hello " # Padded on one end. + # 'hello'.center(10) # => " hello " # Padded on both ends. + # 'hello'.center(20, '-|') # => "-|-|-|-hello-|-|-|-|" # Some padding repeated. + # 'hello'.center(10, 'abcdefg') # => "abhelloabc" # Some padding not used. + # ' hello '.center(13) # => " hello " + # 'тест'.center(10) # => " тест " + # 'こんにちは'.center(10) # => " こんにちは " # Multi-byte characters. # - # If `size` is not greater than the size of `self`, returns a copy of `self`: + # If `size` is less than or equal to the size of `self`, returns an unpadded + # copy of `self`: # - # 'hello'.center(5) # => "hello" - # 'hello'.center(1) # => "hello" + # 'hello'.center(5) # => "hello" + # 'hello'.center(-10) # => "hello" # - # Related: String#ljust, String#rjust. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def center: (int width, ?string pad_string) -> String @@ -1329,6 +2124,10 @@ class String # 'hello'.chars # => ["h", "e", "l", "l", "o"] # 'тест'.chars # => ["т", "е", "с", "т"] # 'こんにちは'.chars # => ["こ", "ん", "に", "ち", "は"] + # ''.chars # => [] + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def chars: () -> Array[String] | () { (String char) -> void } -> self @@ -1363,8 +2162,12 @@ class String # When `line_sep` is neither `"\n"` nor `''`, removes a single trailing line # separator if there is one: # - # 'abcd'.chomp('d') # => "abc" - # 'abcdd'.chomp('d') # => "abcd" + # 'abcd'.chomp('cd') # => "ab" + # 'abcdcd'.chomp('cd') # => "abcd" + # 'abcd'.chomp('xx') # => "abcd" + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def chomp: (?string? separator) -> String @@ -1372,8 +2175,12 @@ class String # rdoc-file=string.c # - chomp!(line_sep = $/) -> self or nil # --> - # Like String#chomp, but modifies `self` in place; returns `nil` if no - # modification made, `self` otherwise. + # Like String#chomp, except that: + # + # * Removes trailing characters from `self` (not from a copy of `self`). + # * Returns `self` if any characters are removed, `nil` otherwise. + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # def chomp!: (nil) -> nil # | (?string separator) -> self? # https://github.com/ruby/rbs/pull/1672#discussion_r1423324796 @@ -1402,16 +2209,21 @@ class String # If you only need to remove the newline separator at the end of the string, # String#chomp is a better alternative. # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). + # def chop: () -> String # - # Like String#chop, but modifies `self` in place; returns `nil` if `self` is - # empty, `self` otherwise. + # Like String#chop, except that: # - # Related: String#chomp!. + # * Removes trailing characters from `self` (not from a copy of `self`). + # * Returns `self` if any characters are removed, `nil` otherwise. + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # def chop!: () -> self? @@ -1421,8 +2233,13 @@ class String # --> # Returns a string containing the first character of `self`: # - # s = 'foo' # => "foo" - # s.chr # => "f" + # 'hello'.chr # => "h" + # 'тест'.chr # => "т" + # 'こんにちは'.chr # => "こ" + # ''.chr # => "" + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def chr: () -> String @@ -1432,8 +2249,11 @@ class String # --> # Removes the contents of `self`: # - # s = 'foo' # => "foo" - # s.clear # => "" + # s = 'foo' + # s.clear # => "" + # s # => "" + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # def clear: () -> self @@ -1447,6 +2267,10 @@ class String # 'hello'.codepoints # => [104, 101, 108, 108, 111] # 'тест'.codepoints # => [1090, 1077, 1089, 1090] # 'こんにちは'.codepoints # => [12371, 12435, 12395, 12385, 12399] + # ''.codepoints # => [] + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def codepoints: () -> Array[Integer] | () { (Integer codepoint) -> void } -> self @@ -1455,19 +2279,19 @@ class String # rdoc-file=string.c # - concat(*objects) -> string # --> - # Concatenates each object in `objects` to `self` and returns `self`: + # Concatenates each object in `objects` to `self`; returns `self`: # - # s = 'foo' - # s.concat('bar', 'baz') # => "foobarbaz" - # s # => "foobarbaz" + # 'foo'.concat('bar', 'baz') # => "foobarbaz" # - # For each given object `object` that is an Integer, the value is considered a + # For each given object `object` that is an integer, the value is considered a # codepoint and converted to a character before concatenation: # - # s = 'foo' - # s.concat(32, 'bar', 32, 'baz') # => "foo bar baz" + # 'foo'.concat(32, 'bar', 32, 'baz') # => "foo bar baz" # Embeds spaces. + # 'те'.concat(1089, 1090) # => "тест" + # 'こん'.concat(12395, 12385, 12399) # => "こんにちは" # - # Related: String#<<, which takes a single argument. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def concat: (*string | Integer string_or_codepoints) -> self @@ -1476,22 +2300,86 @@ class String # - count(*selectors) -> integer # --> # Returns the total number of characters in `self` that are specified by the - # given `selectors` (see [Multiple Character - # Selectors](rdoc-ref:character_selectors.rdoc@Multiple+Character+Selectors)): + # given selectors. + # + # For one 1-character selector, returns the count of instances of that + # character: + # + # s = 'abracadabra' + # s.count('a') # => 5 + # s.count('b') # => 2 + # s.count('x') # => 0 + # s.count('') # => 0 + # + # s = 'тест' + # s.count('т') # => 2 + # s.count('е') # => 1 + # + # s = 'よろしくお願いします' + # s.count('よ') # => 1 + # s.count('し') # => 2 + # + # For one multi-character selector, returns the count of instances for all + # specified characters: # - # a = "hello world" - # a.count "lo" #=> 5 - # a.count "lo", "o" #=> 2 - # a.count "hello", "^l" #=> 4 - # a.count "ej-m" #=> 4 + # s = 'abracadabra' + # s.count('ab') # => 7 + # s.count('abc') # => 8 + # s.count('abcd') # => 9 + # s.count('abcdr') # => 11 + # s.count('abcdrx') # => 11 # - # "hello^world".count "\\^aeiou" #=> 4 - # "hello-world".count "a\\-eo" #=> 4 + # Order and repetition do not matter: # - # c = "hello world\\r\\n" - # c.count "\\" #=> 2 - # c.count "\\A" #=> 0 - # c.count "X-\\w" #=> 3 + # s.count('ba') == s.count('ab') # => true + # s.count('baab') == s.count('ab') # => true + # + # For multiple selectors, forms a single selector that is the intersection of + # characters in all selectors and returns the count of instances for that + # selector: + # + # s = 'abcdefg' + # s.count('abcde', 'dcbfg') == s.count('bcd') # => true + # s.count('abc', 'def') == s.count('') # => true + # + # In a character selector, three characters get special treatment: + # + # * A caret (`'^'`) functions as a *negation* operator for the immediately + # following characters: + # + # s = 'abracadabra' + # s.count('^bc') # => 8 # Count of all except 'b' and 'c'. + # + # * A hyphen (`'-'`) between two other characters defines a *range* of + # characters: + # + # s = 'abracadabra' + # s.count('a-c') # => 8 # Count of all 'a', 'b', and 'c'. + # + # * A backslash (`'\'`) acts as an escape for a caret, a hyphen, or another + # backslash: + # + # s = 'abracadabra' + # s.count('\^bc') # => 3 # Count of '^', 'b', and 'c'. + # s.count('a\-c') # => 6 # Count of 'a', '-', and 'c'. + # 'foo\bar\baz'.count('\\') # => 2 # Count of '\'. + # + # These usages may be mixed: + # + # s = 'abracadabra' + # s.count('a-cq-t') # => 10 # Multiple ranges. + # s.count('ac-d') # => 7 # Range mixed with plain characters. + # s.count('^a-c') # => 3 # Range mixed with negation. + # + # For multiple selectors, all forms may be used, including negations, ranges, + # and escapes. + # + # s = 'abracadabra' + # s.count('^abc', '^def') == s.count('^abcdef') # => true + # s.count('a-e', 'c-g') == s.count('cde') # => true + # s.count('^abc', 'c-g') == s.count('defg') # => true + # + # Related: see [Querying](rdoc-ref:String@Querying). # def count: (selector selector_0, *selector more_selectors) -> Integer @@ -1550,19 +2438,35 @@ class String def crypt: (string salt_str) -> String # - # Returns a frozen, possibly pre-existing copy of the string. + # Returns a frozen string equal to `self`. + # + # The returned string is `self` if and only if all of the following are true: + # + # * `self` is already frozen. + # * `self` is an instance of String (rather than of a subclass of String) + # * `self` has no instance variables set on it. # - # The returned `String` will be deduplicated as long as it does not have any - # instance variables set on it and is not a String subclass. + # Otherwise, the returned string is a frozen copy of `self`. # - # Note that `-string` variant is more convenient for defining constants: + # Returning `self`, when possible, saves duplicating `self`; see [Data + # deduplication](https://en.wikipedia.org/wiki/Data_deduplication). # - # FILENAME = -'config/database.yml' + # It may also save duplicating other, already-existing, strings: # - # while `dedup` is better suitable for using the method in chains of - # calculations: + # s0 = 'foo' + # s1 = 'foo' + # s0.object_id == s1.object_id # => false + # (-s0).object_id == (-s1).object_id # => true # - # @url_list.concat(urls.map(&:dedup)) + # Note that method #-@ is convenient for defining a constant: + # + # FileName = -'config/database.yml' + # + # While its alias #dedup is better suited for chaining: + # + # 'foo'.dedup.gsub!('o') + # + # Related: see [Freezing/Unfreezing](rdoc-ref:String@Freezing-2FUnfreezing). # alias dedup -@ @@ -1570,14 +2474,88 @@ class String # rdoc-file=string.c # - delete(*selectors) -> new_string # --> - # Returns a copy of `self` with characters specified by `selectors` removed (see - # [Multiple Character - # Selectors](rdoc-ref:character_selectors.rdoc@Multiple+Character+Selectors)): + # Returns a new string that is a copy of `self` with certain characters removed; + # the removed characters are all instances of those specified by the given + # string `selectors`. + # + # For one 1-character selector, removes all instances of that character: + # + # s = 'abracadabra' + # s.delete('a') # => "brcdbr" + # s.delete('b') # => "aracadara" + # s.delete('x') # => "abracadabra" + # s.delete('') # => "abracadabra" + # + # s = 'тест' + # s.delete('т') # => "ес" + # s.delete('е') # => "тст" + # + # s = 'よろしくお願いします' + # s.delete('よ') # => "ろしくお願いします" + # s.delete('し') # => "よろくお願います" + # + # For one multi-character selector, removes all instances of the specified + # characters: + # + # s = 'abracadabra' + # s.delete('ab') # => "rcdr" + # s.delete('abc') # => "rdr" + # s.delete('abcd') # => "rr" + # s.delete('abcdr') # => "" + # s.delete('abcdrx') # => "" + # + # Order and repetition do not matter: + # + # s.delete('ba') == s.delete('ab') # => true + # s.delete('baab') == s.delete('ab') # => true + # + # For multiple selectors, forms a single selector that is the intersection of + # characters in all selectors and removes all instances of characters specified + # by that selector: + # + # s = 'abcdefg' + # s.delete('abcde', 'dcbfg') == s.delete('bcd') # => true + # s.delete('abc', 'def') == s.delete('') # => true + # + # In a character selector, three characters get special treatment: # - # "hello".delete "l","lo" #=> "heo" - # "hello".delete "lo" #=> "he" - # "hello".delete "aeiou", "^e" #=> "hell" - # "hello".delete "ej-m" #=> "ho" + # * A caret (`'^'`) functions as a *negation* operator for the immediately + # following characters: + # + # s = 'abracadabra' + # s.delete('^bc') # => "bcb" # Deletes all except 'b' and 'c'. + # + # * A hyphen (`'-'`) between two other characters defines a *range* of + # characters: + # + # s = 'abracadabra' + # s.delete('a-c') # => "rdr" # Deletes all 'a', 'b', and 'c'. + # + # * A backslash (`'\'`) acts as an escape for a caret, a hyphen, or another + # backslash: + # + # s = 'abracadabra' + # s.delete('\^bc') # => "araadara" # Deletes all '^', 'b', and 'c'. + # s.delete('a\-c') # => "brdbr" # Deletes all 'a', '-', and 'c'. + # 'foo\bar\baz'.delete('\\') # => "foobarbaz" # Deletes all '\'. + # + # These usages may be mixed: + # + # s = 'abracadabra' + # s.delete('a-cq-t') # => "d" # Multiple ranges. + # s.delete('ac-d') # => "brbr" # Range mixed with plain characters. + # s.delete('^a-c') # => "abacaaba" # Range mixed with negation. + # + # For multiple selectors, all forms may be used, including negations, ranges, + # and escapes. + # + # s = 'abracadabra' + # s.delete('^abc', '^def') == s.delete('^abcdef') # => true + # s.delete('a-e', 'c-g') == s.delete('cde') # => true + # s.delete('^abc', 'c-g') == s.delete('defg') # => true + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def delete: (selector selector_0, *selector more_selectors) -> String @@ -1585,8 +2563,10 @@ class String # rdoc-file=string.c # - delete!(*selectors) -> self or nil # --> - # Like String#delete, but modifies `self` in place. Returns `self` if any - # changes were made, `nil` otherwise. + # Like String#delete, but modifies `self` in place; returns `self` if any + # characters were deleted, `nil` otherwise. + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # def delete!: (selector selector_0, *selector more_selectors) -> self? @@ -1596,12 +2576,15 @@ class String # --> # Returns a copy of `self` with leading substring `prefix` removed: # - # 'hello'.delete_prefix('hel') # => "lo" - # 'hello'.delete_prefix('llo') # => "hello" + # 'oof'.delete_prefix('o') # => "of" + # 'oof'.delete_prefix('oo') # => "f" + # 'oof'.delete_prefix('oof') # => "" + # 'oof'.delete_prefix('x') # => "oof" # 'тест'.delete_prefix('те') # => "ст" # 'こんにちは'.delete_prefix('こん') # => "にちは" # - # Related: String#delete_prefix!, String#delete_suffix. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def delete_prefix: (string prefix) -> String @@ -1609,9 +2592,11 @@ class String # rdoc-file=string.c # - delete_prefix!(prefix) -> self or nil # --> - # Like String#delete_prefix, except that `self` is modified in place. Returns + # Like String#delete_prefix, except that `self` is modified in place; returns # `self` if the prefix is removed, `nil` otherwise. # + # Related: see [Modifying](rdoc-ref:String@Modifying). + # def delete_prefix!: (string prefix) -> self? # # Returns a copy of `self` with trailing substring `suffix` removed: # - # 'hello'.delete_suffix('llo') # => "he" - # 'hello'.delete_suffix('hel') # => "hello" - # 'тест'.delete_suffix('ст') # => "те" + # 'foo'.delete_suffix('o') # => "fo" + # 'foo'.delete_suffix('oo') # => "f" + # 'foo'.delete_suffix('foo') # => "" + # 'foo'.delete_suffix('f') # => "foo" + # 'foo'.delete_suffix('x') # => "foo" + # 'тест'.delete_suffix('ст') # => "те" # 'こんにちは'.delete_suffix('ちは') # => "こんに" # - # Related: String#delete_suffix!, String#delete_prefix. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def delete_suffix: (string suffix) -> String @@ -1633,24 +2622,30 @@ class String # rdoc-file=string.c # - delete_suffix!(suffix) -> self or nil # --> - # Like String#delete_suffix, except that `self` is modified in place. Returns + # Like String#delete_suffix, except that `self` is modified in place; returns # `self` if the suffix is removed, `nil` otherwise. # + # Related: see [Modifying](rdoc-ref:String@Modifying). + # def delete_suffix!: (string suffix) -> self? # - # Returns a string containing the downcased characters in `self`: + # Returns a new string containing the downcased characters in `self`: # - # s = 'Hello World!' # => "Hello World!" - # s.downcase # => "hello world!" + # 'Hello, World!'.downcase # => "hello, world!" + # 'ТЕСТ'.downcase # => "тест" + # 'よろしくお願いします'.downcase # => "よろしくお願いします" # - # The casing may be affected by the given `options`; see [Case + # Some characters do not have upcased and downcased versions. + # + # The casing may be affected by the given `mapping`; see [Case # Mapping](rdoc-ref:case_mapping.rdoc). # - # Related: String#downcase!, String#upcase, String#upcase!. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def downcase: () -> String | (:ascii | :fold | :lithuanian | :turkic) -> String @@ -1659,20 +2654,14 @@ class String # - # Downcases the characters in `self`; returns `self` if any changes were made, - # `nil` otherwise: + # Like String#downcase, except that: # - # s = 'Hello World!' # => "Hello World!" - # s.downcase! # => "hello world!" - # s # => "hello world!" - # s.downcase! # => nil - # - # The casing may be affected by the given `options`; see [Case - # Mapping](rdoc-ref:case_mapping.rdoc). + # * Changes character casings in `self` (not in a copy of `self`). + # * Returns `self` if any changes are made, `nil` otherwise. # - # Related: String#downcase, String#upcase, String#upcase!. + # Related: See [Modifying](rdoc-ref:String@Modifying). # def downcase!: () -> self? | (:ascii | :fold | :lithuanian | :turkic) -> self? @@ -1681,16 +2670,62 @@ class String # - # Returns a printable version of `self`, enclosed in double-quotes, with special - # characters escaped, and with non-printing characters replaced by hexadecimal - # notation: + # Returns a printable version of `self`, enclosed in double-quotes: + # + # 'hello'.dump # => "\"hello\"" + # + # Certain special characters are rendered with escapes: + # + # '"'.dump # => "\"\\\"\"" + # '\\'.dump # => "\"\\\\\"" + # + # Non-printing characters are rendered with escapes: + # + # s = '' + # s << 7 # Alarm (bell). + # s << 8 # Back space. + # s << 9 # Horizontal tab. + # s << 10 # Line feed. + # s << 11 # Vertical tab. + # s << 12 # Form feed. + # s << 13 # Carriage return. + # s # => "\a\b\t\n\v\f\r" + # s.dump # => "\"\\a\\b\\t\\n\\v\\f\\r\"" # - # "hello \n ''".dump # => "\"hello \\n ''\"" - # "\f\x00\xff\\\"".dump # => "\"\\f\\x00\\xFF\\\\\\\"\"" + # If `self` is encoded in UTF-8 and contains Unicode characters, renders Unicode + # characters in Unicode escape sequence: + # + # 'тест'.dump # => "\"\\u0442\\u0435\\u0441\\u0442\"" + # 'こんにちは'.dump # => "\"\\u3053\\u3093\\u306B\\u3061\\u306F\"" + # + # If the encoding of `self` is not ASCII-compatible (i.e., + # `self.encoding.ascii_compatible?` returns `false`), renders all + # ASCII-compatible bytes as ASCII characters and all other bytes as hexadecimal. + # Appends `.dup.force_encoding(\"encoding\")`, where `` is + # `self.encoding.name`: + # + # s = 'hello' + # s.encoding # => # + # s.dump # => "\"hello\"" + # s.encode('utf-16').dump # => "\"\\xFE\\xFF\\x00h\\x00e\\x00l\\x00l\\x00o\".dup.force_encoding(\"UTF-16\")" + # s.encode('utf-16le').dump # => "\"h\\x00e\\x00l\\x00l\\x00o\\x00\".dup.force_encoding(\"UTF-16LE\")" + # + # s = 'тест' + # s.encoding # => # + # s.dump # => "\"\\u0442\\u0435\\u0441\\u0442\"" + # s.encode('utf-16').dump # => "\"\\xFE\\xFF\\x04B\\x045\\x04A\\x04B\".dup.force_encoding(\"UTF-16\")" + # s.encode('utf-16le').dump # => "\"B\\x045\\x04A\\x04B\\x04\".dup.force_encoding(\"UTF-16LE\")" + # + # s = 'こんにちは' + # s.encoding # => # + # s.dump # => "\"\\u3053\\u3093\\u306B\\u3061\\u306F\"" + # s.encode('utf-16').dump # => "\"\\xFE\\xFF0S0\\x930k0a0o\".dup.force_encoding(\"UTF-16\")" + # s.encode('utf-16le').dump # => "\"S0\\x930k0a0o0\".dup.force_encoding(\"UTF-16LE\")" # - # Related: String#undump (inverse of String#dump). + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def dump: () -> String @@ -1699,109 +2734,136 @@ class String # - each_byte {|byte| ... } -> self # - each_byte -> enumerator # --> - # Calls the given block with each successive byte from `self`; returns `self`: + # With a block given, calls the block with each successive byte from `self`; + # returns `self`: + # + # a = [] + # 'hello'.each_byte {|byte| a.push(byte) } # Five 1-byte characters. + # a # => [104, 101, 108, 108, 111] + # a = [] + # 'тест'.each_byte {|byte| a.push(byte) } # Four 2-byte characters. + # a # => [209, 130, 208, 181, 209, 129, 209, 130] + # a = [] + # 'こんにちは'.each_byte {|byte| a.push(byte) } # Five 3-byte characters. + # a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175] # - # 'hello'.each_byte {|byte| print byte, ' ' } - # print "\n" - # 'тест'.each_byte {|byte| print byte, ' ' } - # print "\n" - # 'こんにちは'.each_byte {|byte| print byte, ' ' } - # print "\n" - # - # Output: - # - # 104 101 108 108 111 - # 209 130 208 181 209 129 209 130 - # 227 129 147 227 130 147 227 129 171 227 129 161 227 129 175 + # With no block given, returns an enumerator. # - # Returns an enumerator if no block is given. + # Related: see [Iterating](rdoc-ref:String@Iterating). # def each_byte: () -> Enumerator[Integer, self] | () { (Integer byte) -> void } -> self # - # Calls the given block with each successive character from `self`; returns - # `self`: - # - # 'hello'.each_char {|char| print char, ' ' } - # print "\n" - # 'тест'.each_char {|char| print char, ' ' } - # print "\n" - # 'こんにちは'.each_char {|char| print char, ' ' } - # print "\n" - # - # Output: + # With a block given, calls the block with each successive character from + # `self`; returns `self`: + # + # a = [] + # 'hello'.each_char do |char| + # a.push(char) + # end + # a # => ["h", "e", "l", "l", "o"] + # a = [] + # 'тест'.each_char do |char| + # a.push(char) + # end + # a # => ["т", "е", "с", "т"] + # a = [] + # 'こんにちは'.each_char do |char| + # a.push(char) + # end + # a # => ["こ", "ん", "に", "ち", "は"] # - # h e l l o - # т е с т - # こ ん に ち は + # With no block given, returns an enumerator. # - # Returns an enumerator if no block is given. + # Related: see [Iterating](rdoc-ref:String@Iterating). # def each_char: () -> Enumerator[String, self] | () { (String char) -> void } -> self # - # Calls the given block with each successive codepoint from `self`; each - # codepoint is the integer value for a character; returns `self`: - # - # 'hello'.each_codepoint {|codepoint| print codepoint, ' ' } - # print "\n" - # 'тест'.each_codepoint {|codepoint| print codepoint, ' ' } - # print "\n" - # 'こんにちは'.each_codepoint {|codepoint| print codepoint, ' ' } - # print "\n" - # - # Output: + # With a block given, calls the block with each successive codepoint from + # `self`; each [codepoint](https://en.wikipedia.org/wiki/Code_point) is the + # integer value for a character; returns `self`: + # + # a = [] + # 'hello'.each_codepoint do |codepoint| + # a.push(codepoint) + # end + # a # => [104, 101, 108, 108, 111] + # a = [] + # 'тест'.each_codepoint do |codepoint| + # a.push(codepoint) + # end + # a # => [1090, 1077, 1089, 1090] + # a = [] + # 'こんにちは'.each_codepoint do |codepoint| + # a.push(codepoint) + # end + # a # => [12371, 12435, 12395, 12385, 12399] # - # 104 101 108 108 111 - # 1090 1077 1089 1090 - # 12371 12435 12395 12385 12399 + # With no block given, returns an enumerator. # - # Returns an enumerator if no block is given. + # Related: see [Iterating](rdoc-ref:String@Iterating). # def each_codepoint: () -> Enumerator[Integer, self] | () { (Integer codepoint) -> void } -> self # - # Calls the given block with each successive grapheme cluster from `self` (see - # [Unicode Grapheme Cluster + # With a block given, calls the given block with each successive grapheme + # cluster from `self` (see [Unicode Grapheme Cluster # Boundaries](https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) # ); returns `self`: # - # s = "\u0061\u0308-pqr-\u0062\u0308-xyz-\u0063\u0308" # => "ä-pqr-b̈-xyz-c̈" - # s.each_grapheme_cluster {|gc| print gc, ' ' } + # a = [] + # 'hello'.each_grapheme_cluster do |grapheme_cluster| + # a.push(grapheme_cluster) + # end + # a # => ["h", "e", "l", "l", "o"] # - # Output: + # a = [] + # 'тест'.each_grapheme_cluster do |grapheme_cluster| + # a.push(grapheme_cluster) + # end + # a # => ["т", "е", "с", "т"] # - # ä - p q r - b̈ - x y z - c̈ + # a = [] + # 'こんにちは'.each_grapheme_cluster do |grapheme_cluster| + # a.push(grapheme_cluster) + # end + # a # => ["こ", "ん", "に", "ち", "は"] + # + # With no block given, returns an enumerator. # - # Returns an enumerator if no block is given. + # Related: see [Iterating](rdoc-ref:String@Iterating). # def each_grapheme_cluster: () -> Enumerator[String, self] | () { (String grapheme_cluter) -> void } -> self # - # With a block given, forms the substrings ("lines") that are the result of - # splitting `self` at each occurrence of the given line separator `line_sep`; - # passes each line to the block; returns `self`: + # With a block given, forms the substrings (lines) that are the result of + # splitting `self` at each occurrence of the given `record_separator`; passes + # each line to the block; returns `self`. # + # With the default `record_separator`: + # + # $/ # => "\n" # s = <<~EOT # This is the first line. # This is line two. @@ -1809,7 +2871,6 @@ class String # This is line four. # This is line five. # EOT - # # s.each_line {|line| p line } # # Output: @@ -1820,9 +2881,10 @@ class String # "This is line four.\n" # "This is line five.\n" # - # With a different `line_sep`: + # With a different `record_separator`: # - # s.each_line(' is ') {|line| p line } + # record_separator = ' is ' + # s.each_line(record_separator) {|line| p line } # # Output: # @@ -1832,7 +2894,8 @@ class String # "line four.\nThis is " # "line five.\n" # - # With `chomp` as `true`, removes the trailing `line_sep` from each line: + # With `chomp` as `true`, removes the trailing `record_separator` from each + # line: # # s.each_line(chomp: true) {|line| p line } # @@ -1844,10 +2907,11 @@ class String # "This is line four." # "This is line five." # - # With an empty string as `line_sep`, forms and passes "paragraphs" by splitting - # at each occurrence of two or more newlines: + # With an empty string as `record_separator`, forms and passes "paragraphs" by + # splitting at each occurrence of two or more newlines: # - # s.each_line('') {|line| p line } + # record_separator = '' + # s.each_line(record_separator) {|line| p line } # # Output: # @@ -1856,6 +2920,8 @@ class String # # With no block given, returns an enumerator. # + # Related: see [Iterating](rdoc-ref:String@Iterating). + # def each_line: (?string? separator, ?chomp: boolish) -> Enumerator[String, self] | (?string? separator, ?chomp: boolish) { (String line) -> void } -> self @@ -1863,11 +2929,13 @@ class String # rdoc-file=string.c # - empty? -> true or false # --> - # Returns `true` if the length of `self` is zero, `false` otherwise: + # Returns whether the length of `self` is zero: + # + # 'hello'.empty? # => false + # ' '.empty? # => false + # ''.empty? # => true # - # "hello".empty? # => false - # " ".empty? # => false - # "".empty? # => true + # Related: see [Querying](rdoc-ref:String@Querying). # def empty?: () -> bool @@ -1876,10 +2944,12 @@ class String # - encode(dst_encoding = Encoding.default_internal, **enc_opts) -> string # - encode(dst_encoding, src_encoding, **enc_opts) -> string # --> - # Returns a copy of `self` transcoded as determined by `dst_encoding`. By - # default, raises an exception if `self` contains an invalid byte or a character - # not defined in `dst_encoding`; that behavior may be modified by encoding - # options; see below. + # Returns a copy of `self` transcoded as determined by `dst_encoding`; see + # [Encodings](rdoc-ref:encodings.rdoc). + # + # By default, raises an exception if `self` contains an invalid byte or a + # character not defined in `dst_encoding`; that behavior may be modified by + # encoding options; see below. # # With no arguments: # @@ -1923,6 +2993,9 @@ class String # without any changes, and no exceptions are raised, even if there are invalid # bytes. # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). + # def encode: ( ?encoding source_encoding, ?encoding? from_encoding, @@ -1949,6 +3022,8 @@ class String # --> # Like #encode, but applies encoding changes to `self`; returns `self`. # + # Related: see [Modifying](rdoc-ref:String@Modifying). + # def encode!: ( ?encoding source_encoding, ?encoding? from_encoding, @@ -1966,9 +3041,12 @@ class String # - # Returns the Encoding object that represents the encoding of obj. + # Returns an Encoding object that represents the encoding of `self`; see + # [Encodings](rdoc-ref:encodings.rdoc). + # + # Related: see [Querying](rdoc-ref:String@Querying). # def encoding: () -> Encoding @@ -1976,17 +3054,16 @@ class String # rdoc-file=string.c # - end_with?(*strings) -> true or false # --> - # Returns whether `self` ends with any of the given `strings`. + # Returns whether `self` ends with any of the given `strings`: # - # Returns `true` if any given string matches the end, `false` otherwise: + # 'foo'.end_with?('oo') # => true + # 'foo'.end_with?('bar', 'oo') # => true + # 'foo'.end_with?('bar', 'baz') # => false + # 'foo'.end_with?('') # => true + # 'тест'.end_with?('т') # => true + # 'こんにちは'.end_with?('は') # => true # - # 'hello'.end_with?('ello') #=> true - # 'hello'.end_with?('heaven', 'ello') #=> true - # 'hello'.end_with?('heaven', 'paradise') #=> false - # 'тест'.end_with?('т') # => true - # 'こんにちは'.end_with?('は') # => true - # - # Related: String#start_with?. + # Related: see [Querying](rdoc-ref:String@Querying). # def end_with?: (*string suffixes) -> bool @@ -1994,17 +3071,24 @@ class String # rdoc-file=string.c # - eql?(object) -> true or false # --> - # Returns `true` if `object` has the same length and content; as `self`; `false` - # otherwise: + # Returns whether `self` and `object` have the same length and content: # # s = 'foo' - # s.eql?('foo') # => true + # s.eql?('foo') # => true # s.eql?('food') # => false - # s.eql?('FOO') # => false + # s.eql?('FOO') # => false # # Returns `false` if the two strings' encodings are not compatible: # - # "\u{e4 f6 fc}".encode("ISO-8859-1").eql?("\u{c4 d6 dc}") # => false + # s0 = "äöü" # => "äöü" + # s1 = s0.encode(Encoding::ISO_8859_1) # => "\xE4\xF6\xFC" + # s0.encoding # => # + # s1.encoding # => # + # s0.eql?(s1) # => false + # + # See [Encodings](rdoc-ref:encodings.rdoc). + # + # Related: see [Querying](rdoc-ref:String@Querying). # def eql?: (untyped other) -> bool @@ -2012,25 +3096,26 @@ class String # rdoc-file=string.c # - force_encoding(encoding) -> self # --> - # Changes the encoding of `self` to `encoding`, which may be a string encoding - # name or an Encoding object; returns self: + # Changes the encoding of `self` to the given `encoding`, which may be a string + # encoding name or an Encoding object; does not change the underlying bytes; + # returns self: # # s = 'łał' # s.bytes # => [197, 130, 97, 197, 130] # s.encoding # => # # s.force_encoding('ascii') # => "\xC5\x82a\xC5\x82" # s.encoding # => # - # - # Does not change the underlying bytes: - # + # s.valid_encoding? # => true # s.bytes # => [197, 130, 97, 197, 130] # # Makes the change even if the given `encoding` is invalid for `self` (as is the # change above): # - # s.valid_encoding? # => false - # s.force_encoding(Encoding::UTF_8) # => "łał" - # s.valid_encoding? # => true + # s.valid_encoding? # => false + # + # See [Encodings](rdoc-ref:encodings.rdoc). + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # def force_encoding: (encoding enc) -> self @@ -2045,15 +3130,33 @@ class String # rdoc-file=string.c # - getbyte(index) -> integer or nil # --> - # Returns the byte at zero-based `index` as an integer, or `nil` if `index` is - # out of range: + # Returns the byte at zero-based `index` as an integer: # - # s = 'abcde' # => "abcde" - # s.getbyte(0) # => 97 - # s.getbyte(-1) # => 101 - # s.getbyte(5) # => nil + # s = 'foo' + # s.getbyte(0) # => 102 + # s.getbyte(1) # => 111 + # s.getbyte(2) # => 111 + # + # Counts backward from the end if `index` is negative: + # + # s.getbyte(-3) # => 102 + # + # Returns `nil` if `index` is out of range: # - # Related: String#setbyte. + # s.getbyte(3) # => nil + # s.getbyte(-4) # => nil + # + # More examples: + # + # s = 'тест' + # s.bytes # => [209, 130, 208, 181, 209, 129, 209, 130] + # s.getbyte(2) # => 208 + # s = 'こんにちは' + # s.bytes # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175] + # s.getbyte(2) # => 147 + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def getbyte: (int index) -> Integer? @@ -2066,10 +3169,24 @@ class String # Boundaries](https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) # ): # - # s = "\u0061\u0308-pqr-\u0062\u0308-xyz-\u0063\u0308" # => "ä-pqr-b̈-xyz-c̈" + # s = "ä-pqr-b̈-xyz-c̈" + # s.size # => 16 + # s.bytesize # => 19 + # s.grapheme_clusters.size # => 13 # s.grapheme_clusters # # => ["ä", "-", "p", "q", "r", "-", "b̈", "-", "x", "y", "z", "-", "c̈"] # + # Details: + # + # s = "ä" + # s.grapheme_clusters # => ["ä"] # One grapheme cluster. + # s.bytes # => [97, 204, 136] # Three bytes. + # s.chars # => ["a", "̈"] # Two characters. + # s.chars.map {|char| char.ord } # => [97, 776] # Their values. + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). + # def grapheme_clusters: () -> Array[String] | () { (String grapheme_cluter) -> void } -> self @@ -2079,13 +3196,39 @@ class String # - gsub(pattern) {|match| ... } -> new_string # - gsub(pattern) -> enumerator # --> - # Returns a copy of `self` with all occurrences of the given `pattern` replaced. + # Returns a copy of `self` with zero or more substrings replaced. + # + # Argument `pattern` may be a string or a Regexp; argument `replacement` may be + # a string or a Hash. Varying types for the argument values makes this method + # very versatile. + # + # Below are some simple examples; for many more examples, see [Substitution + # Methods](rdoc-ref:String@Substitution+Methods). + # + # With arguments `pattern` and string `replacement` given, replaces each + # matching substring with the given `replacement` string: + # + # s = 'abracadabra' + # s.gsub('ab', 'AB') # => "ABracadABra" + # s.gsub(/[a-c]/, 'X') # => "XXrXXXdXXrX" + # + # With arguments `pattern` and hash `replacement` given, replaces each matching + # substring with a value from the given `replacement` hash, or removes it: + # + # h = {'a' => 'A', 'b' => 'B', 'c' => 'C'} + # s.gsub(/[a-c]/, h) # => "ABrACAdABrA" # 'a', 'b', 'c' replaced. + # s.gsub(/[a-d]/, h) # => "ABrACAABrA" # 'd' removed. # - # See [Substitution Methods](rdoc-ref:String@Substitution+Methods). + # With argument `pattern` and a block given, calls the block with each matching + # substring; replaces that substring with the block's return value: # - # Returns an Enumerator if no `replacement` and no block given. + # s.gsub(/[a-d]/) {|substring| substring.upcase } + # # => "ABrACADABrA" # - # Related: String#sub, String#sub!, String#gsub!. + # With argument `pattern` and no block given, returns a new Enumerator. + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def gsub: (Regexp | string pattern, string | hash[String, _ToS] replacement) -> String | (Regexp | string pattern) -> Enumerator[String, String] @@ -2097,14 +3240,12 @@ class String # - gsub!(pattern) {|match| ... } -> self or nil # - gsub!(pattern) -> an_enumerator # --> - # Performs the specified substring replacement(s) on `self`; returns `self` if - # any replacement occurred, `nil` otherwise. - # - # See [Substitution Methods](rdoc-ref:String@Substitution+Methods). + # Like String#gsub, except that: # - # Returns an Enumerator if no `replacement` and no block given. + # * Performs substitutions in `self` (not in a copy of `self`). + # * Returns `self` if any characters are removed, `nil` otherwise. # - # Related: String#sub, String#gsub, String#sub!. + # Related: see [Modifying](rdoc-ref:String@Modifying). # def gsub!: (Regexp | string pattern, string | hash[String, _ToS] replacement) -> self? | (Regexp | string pattern) -> Enumerator[String, self?] @@ -2114,10 +3255,25 @@ class String # rdoc-file=string.c # - hash -> integer # --> - # Returns the integer hash value for `self`. The value is based on the length, - # content and encoding of `self`. + # Returns the integer hash value for `self`. + # + # Two String objects that have identical content and compatible encodings also + # have the same hash value; see Object#hash and + # [Encodings](rdoc-ref:encodings.rdoc): + # + # s = 'foo' + # h = s.hash # => -569050784 + # h == 'foo'.hash # => true + # h == 'food'.hash # => false + # h == 'FOO'.hash # => false + # + # s0 = "äöü" + # s1 = s0.encode(Encoding::ISO_8859_1) + # s0.encoding # => # + # s1.encoding # => # + # s0.hash == s1.hash # => false # - # Related: Object#hash. + # Related: see [Querying](rdoc-ref:String@Querying). # def hash: () -> Integer @@ -2125,16 +3281,48 @@ class String # rdoc-file=string.c # - hex -> integer # --> - # Interprets the leading substring of `self` as a string of hexadecimal digits - # (with an optional sign and an optional `0x`) and returns the corresponding - # number; returns zero if there is no such leading substring: + # Interprets the leading substring of `self` as hexadecimal, possibly signed; + # returns its value as an integer. + # + # The leading substring is interpreted as hexadecimal when it begins with: + # + # * One or more character representing hexadecimal digits (each in one of the + # ranges `'0'..'9'`, `'a'..'f'`, or `'A'..'F'`); the string to be + # interpreted ends at the first character that does not represent a + # hexadecimal digit: + # + # 'f'.hex # => 15 + # '11'.hex # => 17 + # 'FFF'.hex # => 4095 + # 'fffg'.hex # => 4095 + # 'foo'.hex # => 15 # 'f' hexadecimal, 'oo' not. + # 'bar'.hex # => 186 # 'ba' hexadecimal, 'r' not. + # 'deadbeef'.hex # => 3735928559 + # + # * `'0x'` or `'0X'`, followed by one or more hexadecimal digits: + # + # '0xfff'.hex # => 4095 + # '0xfffg'.hex # => 4095 + # + # Any of the above may prefixed with `'-'`, which negates the interpreted value: + # + # '-fff'.hex # => -4095 + # '-0xFFF'.hex # => -4095 + # + # For any substring not described above, returns zero: + # + # 'xxx'.hex # => 0 + # ''.hex # => 0 + # + # Note that, unlike #oct, this method interprets only hexadecimal, and not + # binary, octal, or decimal notations: # - # '0x0a'.hex # => 10 - # '-1234'.hex # => -4660 - # '0'.hex # => 0 - # 'non-numeric'.hex # => 0 + # '0b111'.hex # => 45329 + # '0o777'.hex # => 0 + # '0d999'.hex # => 55705 # - # Related: String#oct. + # Related: See [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def hex: () -> Integer @@ -2142,49 +3330,57 @@ class String # rdoc-file=string.c # - include?(other_string) -> true or false # --> - # Returns `true` if `self` contains `other_string`, `false` otherwise: + # Returns whether `self` contains `other_string`: # - # s = 'foo' - # s.include?('f') # => true - # s.include?('fo') # => true - # s.include?('food') # => false + # s = 'bar' + # s.include?('ba') # => true + # s.include?('ar') # => true + # s.include?('bar') # => true + # s.include?('a') # => true + # s.include?('') # => true + # s.include?('foo') # => false + # + # Related: see [Querying](rdoc-ref:String@Querying). # def include?: (string other_string) -> bool # - # Returns the integer index of the first match for the given argument, or `nil` - # if none found; the search of `self` is forward, and begins at position - # `offset` (in characters). + # Returns the integer position of the first substring that matches the given + # argument `pattern`, or `nil` if none found. # - # With string argument `substring`, returns the index of the first matching - # substring in `self`: + # When `pattern` is a string, returns the index of the first matching substring + # in `self`: # # 'foo'.index('f') # => 0 # 'foo'.index('o') # => 1 # 'foo'.index('oo') # => 1 # 'foo'.index('ooo') # => nil - # 'тест'.index('с') # => 2 - # 'こんにちは'.index('ち') # => 3 + # 'тест'.index('с') # => 2 # Characters, not bytes. + # 'こんにちは'.index('ち') # => 3 # - # With Regexp argument `regexp`, returns the index of the first match in `self`: + # When `pattern` is a Regexp, returns the index of the first match in `self`: # # 'foo'.index(/o./) # => 1 # 'foo'.index(/.o/) # => 0 # - # With positive integer `offset`, begins the search at position `offset`: + # When `offset` is non-negative, begins the search at position `offset`; the + # returned index is relative to the beginning of `self`: # - # 'foo'.index('o', 1) # => 1 - # 'foo'.index('o', 2) # => 2 - # 'foo'.index('o', 3) # => nil + # 'bar'.index('r', 0) # => 2 + # 'bar'.index('r', 1) # => 2 + # 'bar'.index('r', 2) # => 2 + # 'bar'.index('r', 3) # => nil + # 'bar'.index(/[r-z]/, 0) # => 2 # 'тест'.index('с', 1) # => 2 - # 'こんにちは'.index('ち', 2) # => 3 + # 'тест'.index('с', 2) # => 2 + # 'тест'.index('с', 3) # => nil # Offset in characters, not bytes. + # 'こんにちは'.index('ち', 2) # => 3 # - # With negative integer `offset`, selects the search position by counting - # backward from the end of `self`: + # With negative integer argument `offset`, selects the search position by + # counting backward from the end of `self`: # # 'foo'.index('o', -1) # => 2 # 'foo'.index('o', -2) # => 1 @@ -2193,58 +3389,95 @@ class String # 'foo'.index(/o./, -2) # => 1 # 'foo'.index(/.o/, -2) # => 1 # - # Related: String#rindex. + # Related: see [Querying](rdoc-ref:String@Querying). # def index: (Regexp | string pattern, ?int offset) -> Integer? # # Inserts the given `other_string` into `self`; returns `self`. # - # If the Integer `index` is positive, inserts `other_string` at offset `index`: + # If the given `index` is non-negative, inserts `other_string` at offset + # `index`: # - # 'foo'.insert(1, 'bar') # => "fbaroo" + # 'foo'.insert(0, 'bar') # => "barfoo" + # 'foo'.insert(1, 'bar') # => "fbaroo" + # 'foo'.insert(3, 'bar') # => "foobar" + # 'тест'.insert(2, 'bar') # => "теbarст" # Characters, not bytes. + # 'こんにちは'.insert(2, 'bar') # => "こんbarにちは" # - # If the Integer `index` is negative, counts backward from the end of `self` and - # inserts `other_string` at offset `index+1` (that is, *after* `self[index]`): + # If the `index` is negative, counts backward from the end of `self` and inserts + # `other_string` *after* the offset: # # 'foo'.insert(-2, 'bar') # => "fobaro" # + # Related: see [Modifying](rdoc-ref:String@Modifying). + # def insert: (int index, string other_str) -> self # - # Returns a printable version of `self`, enclosed in double-quotes, and with - # special characters escaped: + # Returns a printable version of `self`, enclosed in double-quotes. + # + # Most printable characters are rendered simply as themselves: + # + # 'abc'.inspect # => "\"abc\"" + # '012'.inspect # => "\"012\"" + # ''.inspect # => "\"\"" + # "\u000012".inspect # => "\"\\u000012\"" + # 'тест'.inspect # => "\"тест\"" + # 'こんにちは'.inspect # => "\"こんにちは\"" + # + # But printable characters double-quote (`'"'`) and backslash and (`'\\'`) are + # escaped: + # + # '"'.inspect # => "\"\\\"\"" + # '\\'.inspect # => "\"\\\\\"" + # + # Unprintable characters are the [ASCII + # characters](https://en.wikipedia.org/wiki/ASCII) whose values are in range + # `0..31`, along with the character whose value is `127`. # - # s = "foo\tbar\tbaz\n" - # s.inspect - # # => "\"foo\\tbar\\tbaz\\n\"" + # Most of these characters are rendered thus: + # + # 0.chr.inspect # => "\"\\x00\"" + # 1.chr.inspect # => "\"\\x01\"" + # 2.chr.inspect # => "\"\\x02\"" + # # ... + # + # A few, however, have special renderings: + # + # 7.chr.inspect # => "\"\\a\"" # BEL + # 8.chr.inspect # => "\"\\b\"" # BS + # 9.chr.inspect # => "\"\\t\"" # TAB + # 10.chr.inspect # => "\"\\n\"" # LF + # 11.chr.inspect # => "\"\\v\"" # VT + # 12.chr.inspect # => "\"\\f\"" # FF + # 13.chr.inspect # => "\"\\r\"" # CR + # 27.chr.inspect # => "\"\\e\"" # ESC + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def inspect: () -> String # - # Returns the `Symbol` corresponding to *str*, creating the symbol if it did not - # previously exist. See Symbol#id2name. + # Returns the Symbol object derived from `self`, creating it if it did not + # already exist: # - # "Koala".intern #=> :Koala - # s = 'cat'.to_sym #=> :cat - # s == :cat #=> true - # s = '@cat'.to_sym #=> :@cat - # s == :@cat #=> true + # 'foo'.intern # => :foo + # 'тест'.intern # => :тест + # 'こんにちは'.intern # => :こんにちは # - # This can also be used to create symbols that cannot be represented using the - # `:xxx` notation. - # - # 'cat and dog'.to_sym #=> :"cat and dog" + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def intern: () -> Symbol @@ -2256,48 +3489,91 @@ class String # # 'foo'.length # => 3 # 'тест'.length # => 4 - # 'こんにちは'.length # => 5 + # 'こんにちは'.length # => 5 # # Contrast with String#bytesize: # # 'foo'.bytesize # => 3 # 'тест'.bytesize # => 8 - # 'こんにちは'.bytesize # => 15 + # 'こんにちは'.bytesize # => 15 + # + # Related: see [Querying](rdoc-ref:String@Querying). # def length: () -> Integer # - # Forms substrings ("lines") of `self` according to the given arguments (see - # String#each_line for details); returns the lines in an array. + # Returns substrings ("lines") of `self` according to the given arguments: + # + # s = <<~EOT + # This is the first line. + # This is line two. + # + # This is line four. + # This is line five. + # EOT + # + # With the default argument values: + # + # $/ # => "\n" + # s.lines + # # => + # ["This is the first line.\n", + # "This is line two.\n", + # "\n", + # "This is line four.\n", + # "This is line five.\n"] + # + # With a different `record_separator`: + # + # record_separator = ' is ' + # s.lines(record_separator) + # # => + # ["This is ", + # "the first line.\nThis is ", + # "line two.\n\nThis is ", + # "line four.\nThis is ", + # "line five.\n"] + # + # With keyword argument `chomp` as `true`, removes the trailing newline from + # each line: + # + # s.lines(chomp: true) + # # => + # ["This is the first line.", + # "This is line two.", + # "", + # "This is line four.", + # "This is line five."] + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def lines: (?string? separator, ?chomp: boolish) -> Array[String] | (?string? separator, ?chomp: boolish) { (String line) -> void } -> self # - # Returns a left-justified copy of `self`. - # - # If integer argument `size` is greater than the size (in characters) of `self`, - # returns a new string of length `size` that is a copy of `self`, left justified - # and padded on the right with `pad_string`: + # Returns a copy of `self`, left-justified and, if necessary, right-padded with + # the `pad_string`: # # 'hello'.ljust(10) # => "hello " # ' hello'.ljust(10) # => " hello " # 'hello'.ljust(10, 'ab') # => "helloababa" # 'тест'.ljust(10) # => "тест " - # 'こんにちは'.ljust(10) # => "こんにちは " + # 'こんにちは'.ljust(10) # => "こんにちは " # - # If `size` is not greater than the size of `self`, returns a copy of `self`: + # If `width <= self.length`, returns a copy of `self`: # # 'hello'.ljust(5) # => "hello" - # 'hello'.ljust(1) # => "hello" + # 'hello'.ljust(1) # => "hello" # Does not truncate to width. # - # Related: String#rjust, String#center. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def ljust: (int size, ?string pad_string) -> String @@ -2310,10 +3586,12 @@ class String # # whitespace = "\x00\t\n\v\f\r " # s = whitespace + 'abc' + whitespace - # s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r " - # s.lstrip # => "abc\u0000\t\n\v\f\r " + # # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r " + # s.lstrip + # # => "abc\u0000\t\n\v\f\r " # - # Related: String#rstrip, String#strip. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def lstrip: () -> String @@ -2321,10 +3599,12 @@ class String # rdoc-file=string.c # - lstrip! -> self or nil # --> - # Like String#lstrip, except that any modifications are made in `self`; returns - # `self` if any modification are made, `nil` otherwise. + # Like String#lstrip, except that: + # + # * Performs stripping in `self` (not in a copy of `self`). + # * Returns `self` if any characters are stripped, `nil` otherwise. # - # Related: String#rstrip!, String#strip!. + # Related: see [Modifying](rdoc-ref:String@Modifying). # def lstrip!: () -> self? @@ -2333,34 +3613,36 @@ class String # - match(pattern, offset = 0) -> matchdata or nil # - match(pattern, offset = 0) {|matchdata| ... } -> object # --> - # Returns a MatchData object (or `nil`) based on `self` and the given `pattern`. - # - # Note: also updates Regexp@Global+Variables. + # Creates a MatchData object based on `self` and the given arguments; updates + # [Regexp Global Variables](rdoc-ref:Regexp@Global+Variables). # # * Computes `regexp` by converting `pattern` (if not already a Regexp). + # # regexp = Regexp.new(pattern) # # * Computes `matchdata`, which will be either a MatchData object or `nil` # (see Regexp#match): - # matchdata = regexp.match(self) # - # With no block given, returns the computed `matchdata`: + # matchdata = regexp.match(self[offset..]) # - # 'foo'.match('f') # => # - # 'foo'.match('o') # => # - # 'foo'.match('x') # => nil - # - # If Integer argument `offset` is given, the search begins at index `offset`: + # With no block given, returns the computed `matchdata` or `nil`: # + # 'foo'.match('f') # => # + # 'foo'.match('o') # => # + # 'foo'.match('x') # => nil # 'foo'.match('f', 1) # => nil # 'foo'.match('o', 1) # => # # - # With a block given, calls the block with the computed `matchdata` and returns - # the block's return value: + # With a block given and computed `matchdata` non-nil, calls the block with + # `matchdata`; returns the block's return value: # # 'foo'.match(/o/) {|matchdata| matchdata } # => # - # 'foo'.match(/x/) {|matchdata| matchdata } # => nil - # 'foo'.match(/f/, 1) {|matchdata| matchdata } # => nil + # + # With a block given and `nil` `matchdata`, does not call the block: + # + # 'foo'.match(/x/) {|matchdata| fail 'Cannot happen' } # => nil + # + # Related: see [Querying](rdoc-ref:String@Querying). # def match: (Regexp | string pattern, ?int offset) -> MatchData? | [T] (Regexp | string pattern, ?int offset) { (MatchData matchdata) -> T } -> T? @@ -2369,25 +3651,24 @@ class String # rdoc-file=string.c # - match?(pattern, offset = 0) -> true or false # --> - # Returns `true` or `false` based on whether a match is found for `self` and - # `pattern`. + # Returns whether a match is found for `self` and the given arguments; does not + # update [Regexp Global Variables](rdoc-ref:Regexp@Global+Variables). # - # Note: does not update Regexp@Global+Variables. + # Computes `regexp` by converting `pattern` (if not already a Regexp): # - # Computes `regexp` by converting `pattern` (if not already a Regexp). # regexp = Regexp.new(pattern) # - # Returns `true` if `self+.match(regexp)` returns a MatchData object, `false` - # otherwise: + # Returns `true` if `self[offset..].match(regexp)` returns a MatchData object, + # `false` otherwise: # # 'foo'.match?(/o/) # => true # 'foo'.match?('o') # => true # 'foo'.match?(/x/) # => false - # - # If Integer argument `offset` is given, the search begins at index `offset`: # 'foo'.match?('f', 1) # => false # 'foo'.match?('o', 1) # => true # + # Related: see [Querying](rdoc-ref:String@Querying). + # def match?: (Regexp | string pattern, ?int offset) -> bool # @@ -2397,9 +3678,11 @@ class String # The first character to be incremented is the rightmost alphanumeric: or, if no # alphanumerics, the rightmost character: # - # 'THX1138'.succ # => "THX1139" + # 'THX1138'.succ # => "THX1139" # '<>'.succ # => "<>" - # '***'.succ # => '**+' + # '***'.succ # => '**+' + # 'тест'.succ # => "тесу" + # 'こんにちは'.succ # => "こんにちば" # # The successor to a digit is another digit, "carrying" to the next-left # character for a "rollover" from 9 to 0, and prepending another digit if @@ -2424,28 +3707,31 @@ class String # underlying character set's collating sequence, carrying to the next-left # character for a rollover, and prepending another character if necessary: # - # s = 0.chr * 3 - # s # => "\x00\x00\x00" - # s.succ # => "\x00\x00\x01" - # s = 255.chr * 3 - # s # => "\xFF\xFF\xFF" - # s.succ # => "\x01\x00\x00\x00" + # s = 0.chr * 3 # => "\x00\x00\x00" + # s.succ # => "\x00\x00\x01" + # s = 255.chr * 3 # => "\xFF\xFF\xFF" + # s.succ # => "\x01\x00\x00\x00" # # Carrying can occur between and among mixtures of alphanumeric characters: # - # s = 'zz99zz99' - # s.succ # => "aaa00aa00" - # s = '99zz99zz' - # s.succ # => "100aa00aa" + # s = 'zz99zz99' # => "zz99zz99" + # s.succ # => "aaa00aa00" + # s = '99zz99zz' # => "99zz99zz" + # s.succ # => "100aa00aa" # # The successor to an empty `String` is a new empty `String`: # # ''.succ # => "" # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). + # alias next succ # - # Equivalent to String#succ, but modifies `self` in place; returns `self`. + # Like String#succ, but modifies `self` in place; returns `self`. + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # alias next! succ! @@ -2453,18 +3739,81 @@ class String # rdoc-file=string.c # - oct -> integer # --> - # Interprets the leading substring of `self` as a string of octal digits (with - # an optional sign) and returns the corresponding number; returns zero if there - # is no such leading substring: + # Interprets the leading substring of `self` as octal, binary, decimal, or + # hexadecimal, possibly signed; returns their value as an integer. + # + # In brief: + # + # # Interpreted as octal. + # '777'.oct # => 511 + # '777x'.oct # => 511 + # '0777'.oct # => 511 + # '0o777'.oct # => 511 + # '-777'.oct # => -511 + # # Not interpreted as octal. + # '0b111'.oct # => 7 # Interpreted as binary. + # '0d999'.oct # => 999 # Interpreted as decimal. + # '0xfff'.oct # => 4095 # Interpreted as hexadecimal. + # + # The leading substring is interpreted as octal when it begins with: + # + # * One or more character representing octal digits (each in the range + # `'0'..'7'`); the string to be interpreted ends at the first character that + # does not represent an octal digit: + # + # '7'.oct @ => 7 + # '11'.oct # => 9 + # '777'.oct # => 511 + # '0777'.oct # => 511 + # '7778'.oct # => 511 + # '777x'.oct # => 511 + # + # * `'0o'`, followed by one or more octal digits: + # + # '0o777'.oct # => 511 + # '0o7778'.oct # => 511 + # + # The leading substring is *not* interpreted as octal when it begins with: + # + # * `'0b'`, followed by one or more characters representing binary digits + # (each in the range `'0'..'1'`); the string to be interpreted ends at the + # first character that does not represent a binary digit. the string is + # interpreted as binary digits (base 2): + # + # '0b111'.oct # => 7 + # '0b1112'.oct # => 7 # - # '123'.oct # => 83 - # '-377'.oct # => -255 - # '0377non-numeric'.oct # => 255 - # 'non-numeric'.oct # => 0 + # * `'0d'`, followed by one or more characters representing decimal digits + # (each in the range `'0'..'9'`); the string to be interpreted ends at the + # first character that does not represent a decimal digit. the string is + # interpreted as decimal digits (base 10): # - # If `self` starts with `0`, radix indicators are honored; see Kernel#Integer. + # '0d999'.oct # => 999 + # '0d999x'.oct # => 999 # - # Related: String#hex. + # * `'0x'`, followed by one or more characters representing hexadecimal digits + # (each in one of the ranges `'0'..'9'`, `'a'..'f'`, or `'A'..'F'`); the + # string to be interpreted ends at the first character that does not + # represent a hexadecimal digit. the string is interpreted as hexadecimal + # digits (base 16): + # + # '0xfff'.oct # => 4095 + # '0xfffg'.oct # => 4095 + # + # Any of the above may prefixed with `'-'`, which negates the interpreted value: + # + # '-777'.oct # => -511 + # '-0777'.oct # => -511 + # '-0b111'.oct # => -7 + # '-0xfff'.oct # => -4095 + # + # For any substring not described above, returns zero: + # + # 'foo'.oct # => 0 + # ''.oct # => 0 + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def oct: () -> Integer @@ -2479,67 +3828,105 @@ class String # 'тест'.ord # => 1090 # 'こんにちは'.ord # => 12371 # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). + # def ord: () -> Integer # # Returns a 3-element array of substrings of `self`. # - # Matches a pattern against `self`, scanning from the beginning. The pattern is: + # If `pattern` is matched, returns the array: + # + # [pre_match, first_match, post_match] # - # * `string_or_regexp` itself, if it is a Regexp. - # * `Regexp.quote(string_or_regexp)`, if `string_or_regexp` is a string. + # where: # - # If the pattern is matched, returns pre-match, first-match, post-match: + # * `first_match` is the first-found matching substring. + # * `pre_match` and `post_match` are the preceding and following substrings. # - # 'hello'.partition('l') # => ["he", "l", "lo"] - # 'hello'.partition('ll') # => ["he", "ll", "o"] - # 'hello'.partition('h') # => ["", "h", "ello"] - # 'hello'.partition('o') # => ["hell", "o", ""] - # 'hello'.partition(/l+/) #=> ["he", "ll", "o"] - # 'hello'.partition('') # => ["", "", "hello"] - # 'тест'.partition('т') # => ["", "т", "ест"] - # 'こんにちは'.partition('に') # => ["こん", "に", "ちは"] + # If `pattern` is not matched, returns the array: # - # If the pattern is not matched, returns a copy of `self` and two empty strings: + # [self.dup, "", ""] # - # 'hello'.partition('x') # => ["hello", "", ""] + # Note that in the examples below, a returned string `'hello'` is a copy of + # `self`, not `self`. # - # Related: String#rpartition, String#split. + # If `pattern` is a Regexp, performs the equivalent of `self.match(pattern)` + # (also setting [pattern-matching global + # variables](rdoc-ref:globals.md@Pattern+Matching)): + # + # 'hello'.partition(/h/) # => ["", "h", "ello"] + # 'hello'.partition(/l/) # => ["he", "l", "lo"] + # 'hello'.partition(/l+/) # => ["he", "ll", "o"] + # 'hello'.partition(/o/) # => ["hell", "o", ""] + # 'hello'.partition(/^/) # => ["", "", "hello"] + # 'hello'.partition(//) # => ["", "", "hello"] + # 'hello'.partition(/$/) # => ["hello", "", ""] + # 'hello'.partition(/x/) # => ["hello", "", ""] + # + # If `pattern` is not a Regexp, converts it to a string (if it is not already + # one), then performs the equivalent of `self.index(pattern)` (and does *not* + # set [pattern-matching global + # variables](rdoc-ref:globals.md@Pattern+Matching)): + # + # 'hello'.partition('h') # => ["", "h", "ello"] + # 'hello'.partition('l') # => ["he", "l", "lo"] + # 'hello'.partition('ll') # => ["he", "ll", "o"] + # 'hello'.partition('o') # => ["hell", "o", ""] + # 'hello'.partition('') # => ["", "", "hello"] + # 'hello'.partition('x') # => ["hello", "", ""] + # 'тест'.partition('т') # => ["", "т", "ест"] + # 'こんにちは'.partition('に') # => ["こん", "に", "ちは"] + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def partition: (Regexp | string pattern) -> [String, String, String] # - # Prepends each string in `other_strings` to `self` and returns `self`: + # Prefixes to `self` the concatenation of the given `other_strings`; returns + # `self`: # - # s = 'foo' - # s.prepend('bar', 'baz') # => "barbazfoo" - # s # => "barbazfoo" + # 'baz'.prepend('foo', 'bar') # => "foobarbaz" # - # Related: String#concat. + # Related: see [Modifying](rdoc-ref:String@Modifying). # def prepend: (*string other_strings) -> self - # - # Replaces the contents of `self` with the contents of `other_string`: + # + # Replaces the contents of `self` with the contents of `other_string`; returns + # `self`: # # s = 'foo' # => "foo" # s.replace('bar') # => "bar" # + # Related: see [Modifying](rdoc-ref:String@Modifying). + # def replace: (string other_string) -> self # # Returns a new string with the characters from `self` in reverse order. # - # 'stressed'.reverse # => "desserts" + # 'drawer'.reverse # => "reward" + # 'reviled'.reverse # => "deliver" + # 'stressed'.reverse # => "desserts" + # 'semordnilaps'.reverse # => "spalindromes" + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def reverse: () -> String @@ -2549,77 +3936,83 @@ class String # --> # Returns `self` with its characters reversed: # - # s = 'stressed' - # s.reverse! # => "desserts" - # s # => "desserts" + # 'drawer'.reverse! # => "reward" + # 'reviled'.reverse! # => "deliver" + # 'stressed'.reverse! # => "desserts" + # 'semordnilaps'.reverse! # => "spalindromes" + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # def reverse!: () -> self # - # Returns the Integer index of the *last* occurrence of the given `substring`, - # or `nil` if none found: - # - # 'foo'.rindex('f') # => 0 - # 'foo'.rindex('o') # => 2 - # 'foo'.rindex('oo') # => 1 - # 'foo'.rindex('ooo') # => nil + # Returns the integer position of the *last* substring that matches the given + # argument `pattern`, or `nil` if none found. # - # Returns the Integer index of the *last* match for the given Regexp `regexp`, - # or `nil` if none found: + # When `pattern` is a string, returns the index of the last matching substring + # in self: # - # 'foo'.rindex(/f/) # => 0 - # 'foo'.rindex(/o/) # => 2 - # 'foo'.rindex(/oo/) # => 1 - # 'foo'.rindex(/ooo/) # => nil - # - # The *last* match means starting at the possible last position, not the last of - # longest matches. - # - # 'foo'.rindex(/o+/) # => 2 - # $~ #=> # + # 'foo'.rindex('f') # => 0 + # 'foo'.rindex('o') # => 2 + # 'foo'.rindex('oo' # => 1 + # 'foo'.rindex('ooo') # => nil + # 'тест'.rindex('т') # => 3 + # 'こんにちは'.rindex('ち') # => 3 # - # To get the last longest match, needs to combine with negative lookbehind. - # - # 'foo'.rindex(/(? 1 - # $~ #=> # - # - # Or String#index with negative lookforward. + # When `pattern` is a Regexp, returns the index of the last match in self: # - # 'foo'.index(/o+(?!.*o)/) # => 1 - # $~ #=> # + # 'foo'.rindex(/f/) # => 0 + # 'foo'.rindex(/o/) # => 2 + # 'foo'.rindex(/oo/) # => 1 + # 'foo'.rindex(/ooo/) # => nil # - # Integer argument `offset`, if given and non-negative, specifies the maximum - # starting position in the string to *end* the search: + # When `offset` is non-negative, it specifies the maximum starting position in + # the string to end the search: # # 'foo'.rindex('o', 0) # => nil # 'foo'.rindex('o', 1) # => 1 # 'foo'.rindex('o', 2) # => 2 # 'foo'.rindex('o', 3) # => 2 # - # If `offset` is a negative Integer, the maximum starting position in the string - # to *end* the search is the sum of the string's length and `offset`: + # With negative integer argument `offset`, selects the search position by + # counting backward from the end of `self`: # # 'foo'.rindex('o', -1) # => 2 # 'foo'.rindex('o', -2) # => 1 # 'foo'.rindex('o', -3) # => nil # 'foo'.rindex('o', -4) # => nil # - # Related: String#index. + # The last match means starting at the possible last position, not the last of + # longest matches: + # + # 'foo'.rindex(/o+/) # => 2 + # $~ # => # + # + # To get the last longest match, combine with negative lookbehind: + # + # 'foo'.rindex(/(? 1 + # $~ # => # + # + # Or String#index with negative lookforward. + # + # 'foo'.index(/o+(?!.*o)/) # => 1 + # $~ # => # + # + # Related: see [Querying](rdoc-ref:String@Querying). # def rindex: (Regexp | string pattern, ?int offset) -> Integer? # # Returns a right-justified copy of `self`. # - # If integer argument `size` is greater than the size (in characters) of `self`, - # returns a new string of length `size` that is a copy of `self`, right + # If integer argument `width` is greater than the size (in characters) of + # `self`, returns a new string of length `width` that is a copy of `self`, right # justified and padded on the left with `pad_string`: # # 'hello'.rjust(10) # => " hello" @@ -2628,43 +4021,72 @@ class String # 'тест'.rjust(10) # => " тест" # 'こんにちは'.rjust(10) # => " こんにちは" # - # If `size` is not greater than the size of `self`, returns a copy of `self`: + # If `width <= self.size`, returns a copy of `self`: # # 'hello'.rjust(5, 'ab') # => "hello" # 'hello'.rjust(1, 'ab') # => "hello" # - # Related: String#ljust, String#center. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def rjust: (int size, ?string pad_string) -> String # # Returns a 3-element array of substrings of `self`. # - # Matches a pattern against `self`, scanning backwards from the end. The pattern - # is: + # Searches `self` for a match of `pattern`, seeking the *last* match. + # + # If `pattern` is not matched, returns the array: + # + # ["", "", self.dup] + # + # If `pattern` is matched, returns the array: # - # * `string_or_regexp` itself, if it is a Regexp. - # * `Regexp.quote(string_or_regexp)`, if `string_or_regexp` is a string. + # [pre_match, last_match, post_match] # - # If the pattern is matched, returns pre-match, last-match, post-match: + # where: # - # 'hello'.rpartition('l') # => ["hel", "l", "o"] - # 'hello'.rpartition('ll') # => ["he", "ll", "o"] - # 'hello'.rpartition('h') # => ["", "h", "ello"] - # 'hello'.rpartition('o') # => ["hell", "o", ""] - # 'hello'.rpartition(/l+/) # => ["hel", "l", "o"] - # 'hello'.rpartition('') # => ["hello", "", ""] - # 'тест'.rpartition('т') # => ["тес", "т", ""] - # 'こんにちは'.rpartition('に') # => ["こん", "に", "ちは"] + # * `last_match` is the last-found matching substring. + # * `pre_match` and `post_match` are the preceding and following substrings. # - # If the pattern is not matched, returns two empty strings and a copy of `self`: + # The pattern used is: # - # 'hello'.rpartition('x') # => ["", "", "hello"] + # * `pattern` itself, if it is a Regexp. + # * `Regexp.quote(pattern)`, if `pattern` is a string. # - # Related: String#partition, String#split. + # Note that in the examples below, a returned string `'hello'` is a copy of + # `self`, not `self`. + # + # If `pattern` is a Regexp, searches for the last matching substring (also + # setting [pattern-matching global + # variables](rdoc-ref:globals.md@Pattern+Matching)): + # + # 'hello'.rpartition(/l/) # => ["hel", "l", "o"] + # 'hello'.rpartition(/ll/) # => ["he", "ll", "o"] + # 'hello'.rpartition(/h/) # => ["", "h", "ello"] + # 'hello'.rpartition(/o/) # => ["hell", "o", ""] + # 'hello'.rpartition(//) # => ["hello", "", ""] + # 'hello'.rpartition(/x/) # => ["", "", "hello"] + # 'тест'.rpartition(/т/) # => ["тес", "т", ""] + # 'こんにちは'.rpartition(/に/) # => ["こん", "に", "ちは"] + # + # If `pattern` is not a Regexp, converts it to a string (if it is not already + # one), then searches for the last matching substring (and does *not* set + # [pattern-matching global variables](rdoc-ref:globals.md@Pattern+Matching)): + # + # 'hello'.rpartition('l') # => ["hel", "l", "o"] + # 'hello'.rpartition('ll') # => ["he", "ll", "o"] + # 'hello'.rpartition('h') # => ["", "h", "ello"] + # 'hello'.rpartition('o') # => ["hell", "o", ""] + # 'hello'.rpartition('') # => ["hello", "", ""] + # 'тест'.rpartition('т') # => ["тес", "т", ""] + # 'こんにちは'.rpartition('に') # => ["こん", "に", "ちは"] + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def rpartition: (Regexp | string pattern) -> [String, String, String] @@ -2672,15 +4094,16 @@ class String # rdoc-file=string.c # - rstrip -> new_string # --> - # Returns a copy of the receiver with trailing whitespace removed; see - # [Whitespace in Strings](rdoc-ref:String@Whitespace+in+Strings): + # Returns a copy of `self` with trailing whitespace removed; see [Whitespace in + # Strings](rdoc-ref:String@Whitespace+in+Strings): # # whitespace = "\x00\t\n\v\f\r " # s = whitespace + 'abc' + whitespace # s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r " # s.rstrip # => "\u0000\t\n\v\f\r abc" # - # Related: String#lstrip, String#strip. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def rstrip: () -> String @@ -2688,49 +4111,57 @@ class String # rdoc-file=string.c # - rstrip! -> self or nil # --> - # Like String#rstrip, except that any modifications are made in `self`; returns - # `self` if any modification are made, `nil` otherwise. + # Like String#rstrip, except that: + # + # * Performs stripping in `self` (not in a copy of `self`). + # * Returns `self` if any characters are stripped, `nil` otherwise. # - # Related: String#lstrip!, String#strip!. + # Related: see [Modifying](rdoc-ref:String@Modifying). # def rstrip!: () -> self? # - # Matches a pattern against `self`; the pattern is: + # Matches a pattern against `self`: # - # * `string_or_regexp` itself, if it is a Regexp. - # * `Regexp.quote(string_or_regexp)`, if `string_or_regexp` is a string. + # * If `pattern` is a Regexp, the pattern used is `pattern` itself. + # * If `pattern` is a string, the pattern used is `Regexp.quote(pattern)`. # - # Iterates through `self`, generating a collection of matching results: + # Generates a collection of matching results and updates [regexp-related global + # variables](rdoc-ref:Regexp@Global+Variables): # - # * If the pattern contains no groups, each result is the matched string, - # `$&`. - # * If the pattern contains groups, each result is an array containing one - # entry per group. + # * If the pattern contains no groups, each result is a matched substring. + # * If the pattern contains groups, each result is an array containing a + # matched substring for each group. # # With no block given, returns an array of the results: # - # s = 'cruel world' - # s.scan(/\w+/) # => ["cruel", "world"] - # s.scan(/.../) # => ["cru", "el ", "wor"] - # s.scan(/(...)/) # => [["cru"], ["el "], ["wor"]] - # s.scan(/(..)(..)/) # => [["cr", "ue"], ["l ", "wo"]] + # 'cruel world'.scan(/\w+/) # => ["cruel", "world"] + # 'cruel world'.scan(/.../) # => ["cru", "el ", "wor"] + # 'cruel world'.scan(/(...)/) # => [["cru"], ["el "], ["wor"]] + # 'cruel world'.scan(/(..)(..)/) # => [["cr", "ue"], ["l ", "wo"]] + # 'тест'.scan(/../) # => ["те", "ст"] + # 'こんにちは'.scan(/../) # => ["こん", "にち"] + # 'abracadabra'.scan('ab') # => ["ab", "ab"] + # 'abracadabra'.scan('nosuch') # => [] # # With a block given, calls the block with each result; returns `self`: # - # s.scan(/\w+/) {|w| print "<<#{w}>> " } - # print "\n" - # s.scan(/(.)(.)/) {|x,y| print y, x } - # print "\n" + # 'cruel world'.scan(/\w+/) {|w| p w } + # # => "cruel" + # # => "world" + # 'cruel world'.scan(/(.)(.)/) {|x, y| p [x, y] } + # # => ["c", "r"] + # # => ["u", "e"] + # # => ["l", " "] + # # => ["w", "o"] + # # => ["r", "l"] # - # Output: - # - # <> <> - # rceu lowlr + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def scan: (Regexp pattern) -> Array[String | Array[String?]] | (Regexp pattern) { (String | Array[String?] matches) -> void } -> self @@ -2739,44 +4170,47 @@ class String # # Returns a copy of `self` with each invalid byte sequence replaced by the given # `replacement_string`. # - # With no block given and no argument, replaces each invalid sequence with the - # default replacement string (`"�"` for a Unicode encoding, `'?'` otherwise): - # - # s = "foo\x81\x81bar" - # s.scrub # => "foo��bar" - # - # With no block given and argument `replacement_string` given, replaces each - # invalid sequence with that string: + # With no block given, replaces each invalid sequence with the given + # `default_replacement_string` (by default, `"�"` for a Unicode encoding, `'?'` + # otherwise): # - # "foo\x81\x81bar".scrub('xyzzy') # => "fooxyzzyxyzzybar" + # "foo\x81\x81bar"scrub # => "foo��bar" + # "foo\x81\x81bar".force_encoding('US-ASCII').scrub # => "foo??bar" + # "foo\x81\x81bar".scrub('xyzzy') # => "fooxyzzyxyzzybar" # - # With a block given, replaces each invalid sequence with the value of the - # block: + # With a block given, calls the block with each invalid sequence, and replaces + # that sequence with the return value of the block: # - # "foo\x81\x81bar".scrub {|bytes| p bytes; 'XYZZY' } - # # => "fooXYZZYXYZZYbar" + # "foo\x81\x81bar".scrub {|sequence| p sequence; 'XYZZY' } # => "fooXYZZYXYZZYbar" # - # Output: + # Output : # # "\x81" # "\x81" # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). + # def scrub: (?string? replacement) -> String | (?nil) { (String bytes) -> string } -> String # - # Like String#scrub, except that any replacements are made in `self`. + # Like String#scrub, except that: + # + # * Any replacements are made in `self`. + # * Returns `self`. + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # def scrub!: (?string? replacement) -> self | (?nil) { (String bytes) -> string } -> self @@ -2785,13 +4219,14 @@ class String # rdoc-file=string.c # - setbyte(index, integer) -> integer # --> - # Sets the byte at zero-based `index` to `integer`; returns `integer`: + # Sets the byte at zero-based offset `index` to the value of the given + # `integer`; returns `integer`: # - # s = 'abcde' # => "abcde" - # s.setbyte(0, 98) # => 98 - # s # => "bbcde" + # s = 'xyzzy' + # s.setbyte(2, 129) # => 129 + # s # => "xy\x81zy" # - # Related: String#getbyte. + # Related: see [Modifying](rdoc-ref:String@Modifying). # def setbyte: [T < _ToInt] (int index, T byte) -> T @@ -2800,19 +4235,115 @@ class String # # 'foo'.length # => 3 # 'тест'.length # => 4 - # 'こんにちは'.length # => 5 + # 'こんにちは'.length # => 5 # # Contrast with String#bytesize: # # 'foo'.bytesize # => 3 # 'тест'.bytesize # => 8 - # 'こんにちは'.bytesize # => 15 + # 'こんにちは'.bytesize # => 15 + # + # Related: see [Querying](rdoc-ref:String@Querying). # alias size length # - # Returns the substring of `self` specified by the arguments. See examples at - # [String Slices](rdoc-ref:String@String+Slices). + # Returns the substring of `self` specified by the arguments. + # + # **Form `self[index]`** + # + # With non-negative integer argument `index` given, returns the 1-character + # substring found in self at character offset index: + # + # 'hello'[0] # => "h" + # 'hello'[4] # => "o" + # 'hello'[5] # => nil + # 'тест'[2] # => "с" + # 'こんにちは'[4] # => "は" + # + # With negative integer argument `index` given, counts backward from the end of + # `self`: + # + # 'hello'[-1] # => "o" + # 'hello'[-5] # => "h" + # 'hello'[-6] # => nil + # + # **Form `self[start, length]`** + # + # With integer arguments `start` and `length` given, returns a substring of size + # `length` characters (as available) beginning at character offset specified by + # `start`. + # + # If argument `start` is non-negative, the offset is `start`: + # + # 'hello'[0, 1] # => "h" + # 'hello'[0, 5] # => "hello" + # 'hello'[0, 6] # => "hello" + # 'hello'[2, 3] # => "llo" + # 'hello'[2, 0] # => "" + # 'hello'[2, -1] # => nil + # + # If argument `start` is negative, counts backward from the end of `self`: + # + # 'hello'[-1, 1] # => "o" + # 'hello'[-5, 5] # => "hello" + # 'hello'[-1, 0] # => "" + # 'hello'[-6, 5] # => nil + # + # Special case: if `start` equals the length of `self`, returns a new empty + # string: + # + # 'hello'[5, 3] # => "" + # + # **Form `self[range]`** + # + # With Range argument `range` given, forms substring `self[range.start, + # range.size]`: + # + # 'hello'[0..2] # => "hel" + # 'hello'[0, 3] # => "hel" + # + # 'hello'[0...2] # => "he" + # 'hello'[0, 2] # => "he" + # + # 'hello'[0, 0] # => "" + # 'hello'[0...0] # => "" + # + # **Form `self[regexp, capture = 0]`** + # + # With Regexp argument `regexp` given and `capture` as zero, searches for a + # matching substring in `self`; updates [Regexp-related global + # variables](rdoc-ref:Regexp@Global+Variables): + # + # 'hello'[/ell/] # => "ell" + # 'hello'[/l+/] # => "ll" + # 'hello'[//] # => "" + # 'hello'[/nosuch/] # => nil + # + # With `capture` as a positive integer `n`, returns the +n+th matched group: + # + # 'hello'[/(h)(e)(l+)(o)/] # => "hello" + # 'hello'[/(h)(e)(l+)(o)/, 1] # => "h" + # $1 # => "h" + # 'hello'[/(h)(e)(l+)(o)/, 2] # => "e" + # $2 # => "e" + # 'hello'[/(h)(e)(l+)(o)/, 3] # => "ll" + # 'hello'[/(h)(e)(l+)(o)/, 4] # => "o" + # 'hello'[/(h)(e)(l+)(o)/, 5] # => nil + # + # **Form `self[substring]`** + # + # With string argument `substring` given, returns the matching substring of + # `self`, if found: + # + # 'hello'['ell'] # => "ell" + # 'hello'[''] # => "" + # 'hello'['nosuch'] # => nil + # 'тест'['ес'] # => "ес" + # 'こんにちは'['んにち'] # => "んにち" + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # alias slice [] @@ -2824,17 +4355,21 @@ class String # - slice!(regexp, capture = 0) -> new_string or nil # - slice!(substring) -> new_string or nil # --> - # Removes and returns the substring of `self` specified by the arguments. See - # [String Slices](rdoc-ref:String@String+Slices). + # Like String#[] (and its alias String#slice), except that: + # + # * Performs substitutions in `self` (not in a copy of `self`). + # * Returns the removed substring if any modifications were made, `nil` + # otherwise. # # A few examples: # - # string = "This is a string" - # string.slice!(2) #=> "i" - # string.slice!(3..6) #=> " is " - # string.slice!(/s.*t/) #=> "sa st" - # string.slice!("r") #=> "r" - # string #=> "Thing" + # s = 'hello' + # s.slice!('e') # => "e" + # s # => "hllo" + # s.slice!('e') # => nil + # s # => "hllo" + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # def slice!: (int index, ?int length) -> String? | (range[int?] range) -> String? @@ -2843,86 +4378,108 @@ class String # - # Returns an array of substrings of `self` that are the result of splitting - # `self` at each occurrence of the given field separator `field_sep`. + # Creates an array of substrings by splitting `self` at each occurrence of the + # given field separator `field_sep`. # - # When `field_sep` is `$;`: + # With no arguments given, splits using the field separator `$;`, whose default + # value is `nil`. # - # * If `$;` is `nil` (its default value), the split occurs just as if - # `field_sep` were given as a space character (see below). + # With no block given, returns the array of substrings: # - # * If `$;` is a string, the split occurs just as if `field_sep` were given as - # that string (see below). + # 'abracadabra'.split('a') # => ["", "br", "c", "d", "br"] # - # When `field_sep` is `' '` and `limit` is `0` (its default value), the split - # occurs at each sequence of whitespace: + # When `field_sep` is `nil` or `' '` (a single space), splits at each sequence + # of whitespace: # - # 'abc def ghi'.split(' ') => ["abc", "def", "ghi"] - # "abc \n\tdef\t\n ghi".split(' ') # => ["abc", "def", "ghi"] - # 'abc def ghi'.split(' ') => ["abc", "def", "ghi"] - # ''.split(' ') => [] + # 'foo bar baz'.split(nil) # => ["foo", "bar", "baz"] + # 'foo bar baz'.split(' ') # => ["foo", "bar", "baz"] + # "foo \n\tbar\t\n baz".split(' ') # => ["foo", "bar", "baz"] + # 'foo bar baz'.split(' ') # => ["foo", "bar", "baz"] + # ''.split(' ') # => [] # - # When `field_sep` is a string different from `' '` and `limit` is `0`, the - # split occurs at each occurrence of `field_sep`; trailing empty substrings are - # not returned: + # When `field_sep` is an empty string, splits at every character: # - # 'abracadabra'.split('ab') => ["", "racad", "ra"] - # 'aaabcdaaa'.split('a') => ["", "", "", "bcd"] - # ''.split('a') => [] - # '3.14159'.split('1') => ["3.", "4", "59"] - # '!@#$%^$&*($)_+'.split('$') # => ["!@#", "%^", "&*(", ")_+"] - # 'тест'.split('т') => ["", "ес"] - # 'こんにちは'.split('に') => ["こん", "ちは"] + # 'abracadabra'.split('') # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"] + # ''.split('') # => [] + # 'тест'.split('') # => ["т", "е", "с", "т"] + # 'こんにちは'.split('') # => ["こ", "ん", "に", "ち", "は"] # - # When `field_sep` is a Regexp and `limit` is `0`, the split occurs at each - # occurrence of a match; trailing empty substrings are not returned: + # When `field_sep` is a non-empty string and different from `' '` (a single + # space), uses that string as the separator: + # + # 'abracadabra'.split('a') # => ["", "br", "c", "d", "br"] + # 'abracadabra'.split('ab') # => ["", "racad", "ra"] + # ''.split('a') # => [] + # 'тест'.split('т') # => ["", "ес"] + # 'こんにちは'.split('に') # => ["こん", "ちは"] + # + # When `field_sep` is a Regexp, splits at each occurrence of a matching + # substring: # # 'abracadabra'.split(/ab/) # => ["", "racad", "ra"] - # 'aaabcdaaa'.split(/a/) => ["", "", "", "bcd"] - # 'aaabcdaaa'.split(//) => ["a", "a", "a", "b", "c", "d", "a", "a", "a"] # '1 + 1 == 2'.split(/\W+/) # => ["1", "1", "2"] + # 'abracadabra'.split(//) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"] # - # If the Regexp contains groups, their matches are also included in the returned + # If the Regexp contains groups, their matches are included in the returned # array: # # '1:2:3'.split(/(:)()()/, 2) # => ["1", ":", "", "", "2:3"] # - # As seen above, if `limit` is `0`, trailing empty substrings are not returned: + # Argument `limit` sets a limit on the size of the returned array; it also + # determines whether trailing empty strings are included in the returned array. # - # 'aaabcdaaa'.split('a') => ["", "", "", "bcd"] + # When `limit` is zero, there is no limit on the size of the array, but trailing + # empty strings are omitted: # - # If `limit` is positive integer `n`, no more than `n - 1-` splits occur, so - # that at most `n` substrings are returned, and trailing empty substrings are - # included: + # 'abracadabra'.split('', 0) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a"] + # 'abracadabra'.split('a', 0) # => ["", "br", "c", "d", "br"] # Empty string after last 'a' omitted. # - # 'aaabcdaaa'.split('a', 1) # => ["aaabcdaaa"] - # 'aaabcdaaa'.split('a', 2) # => ["", "aabcdaaa"] - # 'aaabcdaaa'.split('a', 5) # => ["", "", "", "bcd", "aa"] - # 'aaabcdaaa'.split('a', 7) # => ["", "", "", "bcd", "", "", ""] - # 'aaabcdaaa'.split('a', 8) # => ["", "", "", "bcd", "", "", ""] + # When `limit` is a positive integer, there is a limit on the size of the array + # (no more than `n - 1` splits occur), and trailing empty strings are included: # - # Note that if `field_sep` is a Regexp containing groups, their matches are in - # the returned array, but do not count toward the limit. + # 'abracadabra'.split('', 3) # => ["a", "b", "racadabra"] + # 'abracadabra'.split('a', 3) # => ["", "br", "cadabra"] + # 'abracadabra'.split('', 30) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a", ""] + # 'abracadabra'.split('a', 30) # => ["", "br", "c", "d", "br", ""] + # 'abracadabra'.split('', 1) # => ["abracadabra"] + # 'abracadabra'.split('a', 1) # => ["abracadabra"] # - # If `limit` is negative, it behaves the same as if `limit` was zero, meaning - # that there is no limit, and trailing empty substrings are included: + # When `limit` is negative, there is no limit on the size of the array, and + # trailing empty strings are omitted: # - # 'aaabcdaaa'.split('a', -1) # => ["", "", "", "bcd", "", "", ""] + # 'abracadabra'.split('', -1) # => ["a", "b", "r", "a", "c", "a", "d", "a", "b", "r", "a", ""] + # 'abracadabra'.split('a', -1) # => ["", "br", "c", "d", "br", ""] # - # If a block is given, it is called with each substring: + # If a block is given, it is called with each substring and returns `self`: # - # 'abc def ghi'.split(' ') {|substring| p substring } + # 'foo bar baz'.split(' ') {|substring| p substring } # - # Output: + # Output : + # + # "foo" + # "bar" + # "baz" + # + # Note that the above example is functionally equivalent to: + # + # 'foo bar baz'.split(' ').each {|substring| p substring } + # + # Output : + # + # "foo" + # "bar" + # "baz" # - # "abc" - # "def" - # "ghi" + # But the latter: # - # Related: String#partition, String#rpartition. + # * Has poorer performance because it creates an intermediate array. + # * Returns an array (instead of `self`). + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def split: (?Regexp | string | nil pattern, ?int limit) -> Array[String] | (?Regexp | string | nil pattern, ?int limit) { (String substring) -> void } -> self @@ -2931,17 +4488,40 @@ class String # rdoc-file=string.c # - squeeze(*selectors) -> new_string # --> - # Returns a copy of `self` with characters specified by `selectors` "squeezed" - # (see [Multiple Character - # Selectors](rdoc-ref:character_selectors.rdoc@Multiple+Character+Selectors)): + # Returns a copy of `self` with each tuple (doubling, tripling, etc.) of + # specified characters "squeezed" down to a single character. # - # "Squeezed" means that each multiple-character run of a selected character is - # squeezed down to a single character; with no arguments given, squeezes all - # characters: + # The tuples to be squeezed are specified by arguments `selectors`, each of + # which is a string; see [Character + # Selectors](rdoc-ref:character_selectors.rdoc@Character+Selectors). + # + # A single argument may be a single character: + # + # 'Noooooo!'.squeeze('o') # => "No!" + # 'foo bar baz'.squeeze(' ') # => "foo bar baz" + # 'Mississippi'.squeeze('s') # => "Misisippi" + # 'Mississippi'.squeeze('p') # => "Mississipi" + # 'Mississippi'.squeeze('x') # => "Mississippi" # Unused selector character is ignored. + # 'бессонница'.squeeze('с') # => "бесонница" + # 'бессонница'.squeeze('н') # => "бессоница" + # + # A single argument may be a string of characters: + # + # 'Mississippi'.squeeze('sp') # => "Misisipi" + # 'Mississippi'.squeeze('ps') # => "Misisipi" # Order doesn't matter. + # 'Mississippi'.squeeze('nonsense') # => "Misisippi" # Unused selector characters are ignored. + # + # A single argument may be a range of characters: + # + # 'Mississippi'.squeeze('a-p') # => "Mississipi" + # 'Mississippi'.squeeze('q-z') # => "Misisippi" + # 'Mississippi'.squeeze('a-z') # => "Misisipi" # - # "yellow moon".squeeze #=> "yelow mon" - # " now is the".squeeze(" ") #=> " now is the" - # "putters shoot balls".squeeze("m-z") #=> "puters shot balls" + # Multiple arguments are allowed; see [Multiple Character + # Selectors](rdoc-ref:character_selectors.rdoc@Multiple+Character+Selectors). + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def squeeze: (*selector selectors) -> String @@ -2949,22 +4529,25 @@ class String # rdoc-file=string.c # - squeeze!(*selectors) -> self or nil # --> - # Like String#squeeze, but modifies `self` in place. Returns `self` if any - # changes were made, `nil` otherwise. + # Like String#squeeze, except that: + # + # * Characters are squeezed in `self` (not in a copy of `self`). + # * Returns `self` if any changes are made, `nil` otherwise. + # + # Related: See [Modifying](rdoc-ref:String@Modifying). # def squeeze!: (*selector selectors) -> self? # - # Returns whether `self` starts with any of the given `string_or_regexp`. + # Returns whether `self` starts with any of the given `patterns`. # - # Matches patterns against the beginning of `self`. For each given - # `string_or_regexp`, the pattern is: + # For each argument, the pattern used is: # - # * `string_or_regexp` itself, if it is a Regexp. - # * `Regexp.quote(string_or_regexp)`, if `string_or_regexp` is a string. + # * The pattern itself, if it is a Regexp. + # * `Regexp.quote(pattern)`, if it is a string. # # Returns `true` if any pattern matches the beginning, `false` otherwise: # @@ -2975,7 +4558,7 @@ class String # 'тест'.start_with?('т') # => true # 'こんにちは'.start_with?('こ') # => true # - # Related: String#end_with?. + # Related: see [Querying](rdoc-ref:String@Querying). # def start_with?: (*Regexp | string prefixes) -> bool @@ -2983,15 +4566,16 @@ class String # rdoc-file=string.c # - strip -> new_string # --> - # Returns a copy of the receiver with leading and trailing whitespace removed; - # see [Whitespace in Strings](rdoc-ref:String@Whitespace+in+Strings): + # Returns a copy of `self` with leading and trailing whitespace removed; see + # [Whitespace in Strings](rdoc-ref:String@Whitespace+in+Strings): # # whitespace = "\x00\t\n\v\f\r " # s = whitespace + 'abc' + whitespace - # s # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r " + # # => "\u0000\t\n\v\f\r abc\u0000\t\n\v\f\r " # s.strip # => "abc" # - # Related: String#lstrip, String#rstrip. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def strip: () -> String @@ -2999,10 +4583,12 @@ class String # rdoc-file=string.c # - strip! -> self or nil # --> - # Like String#strip, except that any modifications are made in `self`; returns - # `self` if any modification are made, `nil` otherwise. + # Like String#strip, except that: # - # Related: String#lstrip!, String#strip!. + # * Any modifications are made to `self`. + # * Returns `self` if any modification are made, `nil` otherwise. + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # def strip!: () -> self? @@ -3011,12 +4597,40 @@ class String # - sub(pattern, replacement) -> new_string # - sub(pattern) {|match| ... } -> new_string # --> - # Returns a copy of `self` with only the first occurrence (not all occurrences) - # of the given `pattern` replaced. + # Returns a copy of self, possibly with a substring replaced. + # + # Argument `pattern` may be a string or a Regexp; argument `replacement` may be + # a string or a Hash. + # + # Varying types for the argument values makes this method very versatile. + # + # Below are some simple examples; for many more examples, see [Substitution + # Methods](rdoc-ref:String@Substitution+Methods). # - # See [Substitution Methods](rdoc-ref:String@Substitution+Methods). + # With arguments `pattern` and string `replacement` given, replaces the first + # matching substring with the given replacement string: # - # Related: String#sub!, String#gsub, String#gsub!. + # s = 'abracadabra' # => "abracadabra" + # s.sub('bra', 'xyzzy') # => "axyzzycadabra" + # s.sub(/bra/, 'xyzzy') # => "axyzzycadabra" + # s.sub('nope', 'xyzzy') # => "abracadabra" + # + # With arguments `pattern` and hash `replacement` given, replaces the first + # matching substring with a value from the given replacement hash, or removes + # it: + # + # h = {'a' => 'A', 'b' => 'B', 'c' => 'C'} + # s.sub('b', h) # => "aBracadabra" + # s.sub(/b/, h) # => "aBracadabra" + # s.sub(/d/, h) # => "abracaabra" # 'd' removed. + # + # With argument `pattern` and a block given, calls the block with each matching + # substring; replaces that substring with the block’s return value: + # + # s.sub('b') {|match| match.upcase } # => "aBracadabra" + # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def sub: (Regexp | string pattern, string | hash[String, _ToS] replacement) -> String | (Regexp | string pattern) { (String match) -> _ToS } -> String @@ -3026,12 +4640,12 @@ class String # - sub!(pattern, replacement) -> self or nil # - sub!(pattern) {|match| ... } -> self or nil # --> - # Replaces the first occurrence (not all occurrences) of the given `pattern` on - # `self`; returns `self` if a replacement occurred, `nil` otherwise. + # Like String#sub, except that: # - # See [Substitution Methods](rdoc-ref:String@Substitution+Methods). + # * Changes are made to `self`, not to copy of `self`. + # * Returns `self` if any changes are made, `nil` otherwise. # - # Related: String#sub, String#gsub, String#gsub!. + # Related: see [Modifying](rdoc-ref:String@Modifying). # def sub!: (Regexp | string pattern, string | hash[String, _ToS] replacement) -> self? | (Regexp | string pattern) { (String match) -> _ToS } -> self? @@ -3046,9 +4660,11 @@ class String # The first character to be incremented is the rightmost alphanumeric: or, if no # alphanumerics, the rightmost character: # - # 'THX1138'.succ # => "THX1139" + # 'THX1138'.succ # => "THX1139" # '<>'.succ # => "<>" - # '***'.succ # => '**+' + # '***'.succ # => '**+' + # 'тест'.succ # => "тесу" + # 'こんにちは'.succ # => "こんにちば" # # The successor to a digit is another digit, "carrying" to the next-left # character for a "rollover" from 9 to 0, and prepending another digit if @@ -3073,31 +4689,34 @@ class String # underlying character set's collating sequence, carrying to the next-left # character for a rollover, and prepending another character if necessary: # - # s = 0.chr * 3 - # s # => "\x00\x00\x00" - # s.succ # => "\x00\x00\x01" - # s = 255.chr * 3 - # s # => "\xFF\xFF\xFF" - # s.succ # => "\x01\x00\x00\x00" + # s = 0.chr * 3 # => "\x00\x00\x00" + # s.succ # => "\x00\x00\x01" + # s = 255.chr * 3 # => "\xFF\xFF\xFF" + # s.succ # => "\x01\x00\x00\x00" # # Carrying can occur between and among mixtures of alphanumeric characters: # - # s = 'zz99zz99' - # s.succ # => "aaa00aa00" - # s = '99zz99zz' - # s.succ # => "100aa00aa" + # s = 'zz99zz99' # => "zz99zz99" + # s.succ # => "aaa00aa00" + # s = '99zz99zz' # => "99zz99zz" + # s.succ # => "100aa00aa" # # The successor to an empty `String` is a new empty `String`: # # ''.succ # => "" # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). + # def succ: () -> String # - # Equivalent to String#succ, but modifies `self` in place; returns `self`. + # Like String#succ, but modifies `self` in place; returns `self`. + # + # Related: see [Modifying](rdoc-ref:String@Modifying). # def succ!: () -> self @@ -3105,8 +4724,9 @@ class String # rdoc-file=string.c # - sum(n = 16) -> integer # --> - # Returns a basic `n`-bit checksum of the characters in `self`; the checksum is - # the sum of the binary value of each byte in `self`, modulo `2**n - 1`: + # Returns a basic `n`-bit [checksum](https://en.wikipedia.org/wiki/Checksum) of + # the characters in `self`; the checksum is the sum of the binary value of each + # byte in `self`, modulo `2**n - 1`: # # 'hello'.sum # => 532 # 'hello'.sum(4) # => 4 @@ -3116,22 +4736,34 @@ class String # # This is not a particularly strong checksum. # + # Related: see [Querying](rdoc-ref:String@Querying). + # def sum: (?int bits) -> Integer # - # Returns a string containing the characters in `self`, with cases reversed; - # each uppercase character is downcased; each lowercase character is upcased: + # Returns a string containing the characters in `self`, with cases reversed: # - # s = 'Hello World!' # => "Hello World!" - # s.swapcase # => "hELLO wORLD!" + # * Each uppercase character is downcased. + # * Each lowercase character is upcased. + # + # Examples: + # + # 'Hello World!'.swapcase # => "hELLO wORLD!" + # 'тест'.swapcase # => "ТЕСТ" # - # The casing may be affected by the given `options`; see [Case + # Some characters (and even character sets) do not have casing: + # + # '12345'.swapcase # => "12345" + # 'こんにちは'.swapcase # => "こんにちは" + # + # The casing may be affected by the given `mapping`; see [Case # Mapping](rdoc-ref:case_mapping.rdoc). # - # Related: String#swapcase!. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def swapcase: () -> String | (:ascii | :lithuanian | :turkic) -> String @@ -3140,20 +4772,14 @@ class String # - # Upcases each lowercase character in `self`; downcases uppercase character; - # returns `self` if any changes were made, `nil` otherwise: - # - # s = 'Hello World!' # => "Hello World!" - # s.swapcase! # => "hELLO wORLD!" - # s # => "hELLO wORLD!" - # ''.swapcase! # => nil + # Like String#swapcase, except that: # - # The casing may be affected by the given `options`; see [Case - # Mapping](rdoc-ref:case_mapping.rdoc). + # * Changes are made to `self`, not to copy of `self`. + # * Returns `self` if any changes are made, `nil` otherwise. # - # Related: String#swapcase. + # Related: see [Modifying](rdoc-ref:String@Modifying). # def swapcase!: () -> self? | (:ascii | :lithuanian | :turkic) -> self? @@ -3164,28 +4790,152 @@ class String # rdoc-file=complex.c # - to_c -> complex # --> - # Returns `self` interpreted as a Complex object; leading whitespace and - # trailing garbage are ignored: - # - # '9'.to_c # => (9+0i) - # '2.5'.to_c # => (2.5+0i) - # '2.5/1'.to_c # => ((5/2)+0i) - # '-3/2'.to_c # => ((-3/2)+0i) - # '-i'.to_c # => (0-1i) - # '45i'.to_c # => (0+45i) - # '3-4i'.to_c # => (3-4i) - # '-4e2-4e-2i'.to_c # => (-400.0-0.04i) - # '-0.0-0.0i'.to_c # => (-0.0-0.0i) - # '1/2+3/4i'.to_c # => ((1/2)+(3/4)*i) - # '1.0@0'.to_c # => (1+0.0i) + # Returns a Complex object: parses the leading substring of `self` to extract + # two numeric values that become the coordinates of the complex object. + # + # The substring is interpreted as containing either rectangular coordinates + # (real and imaginary parts) or polar coordinates (magnitude and angle parts), + # depending on an included or implied "separator" character: + # + # * `'+'`, `'-'`, or no separator: rectangular coordinates. + # * `'@'`: polar coordinates. + # + # **In Brief** + # + # In these examples, we use method Complex#rect to display rectangular + # coordinates, and method Complex#polar to display polar coordinates. + # + # # Rectangular coordinates. + # + # # Real-only: no separator; imaginary part is zero. + # '9'.to_c.rect # => [9, 0] # Integer. + # '-9'.to_c.rect # => [-9, 0] # Integer (negative). + # '2.5'.to_c.rect # => [2.5, 0] # Float. + # '1.23e-14'.to_c.rect # => [1.23e-14, 0] # Float with exponent. + # '2.5/1'.to_c.rect # => [(5/2), 0] # Rational. + # + # # Some things are ignored. + # 'foo1'.to_c.rect # => [0, 0] # Unparsed entire substring. + # '1foo'.to_c.rect # => [1, 0] # Unparsed trailing substring. + # ' 1 '.to_c.rect # => [1, 0] # Leading and trailing whitespace. + # * + # # Imaginary only: trailing 'i' required; real part is zero. + # '9i'.to_c.rect # => [0, 9] + # '-9i'.to_c.rect # => [0, -9] + # '2.5i'.to_c.rect # => [0, 2.5] + # '1.23e-14i'.to_c.rect # => [0, 1.23e-14] + # '2.5/1i'.to_c.rect # => [0, (5/2)] + # + # # Real and imaginary; '+' or '-' separator; trailing 'i' required. + # '2+3i'.to_c.rect # => [2, 3] + # '-2-3i'.to_c.rect # => [-2, -3] + # '2.5+3i'.to_c.rect # => [2.5, 3] + # '2.5+3/2i'.to_c.rect # => [2.5, (3/2)] + # + # # Polar coordinates; '@' separator; magnitude required. + # '1.0@0'.to_c.polar # => [1.0, 0.0] + # '1.0@'.to_c.polar # => [1.0, 0.0] + # "1.0@#{Math::PI}".to_c.polar # => [1.0, 3.141592653589793] + # "1.0@#{Math::PI/2}".to_c.polar # => [1.0, 1.5707963267948966] + # + # **Parsed Values** + # + # The parsing may be thought of as searching for numeric literals embedded in + # the substring. + # + # This section shows how the method parses numeric values from leading + # substrings. The examples show real-only or imaginary-only parsing; the parsing + # is the same for each part. + # + # '1foo'.to_c # => (1+0i) # Ignores trailing unparsed characters. + # ' 1 '.to_c # => (1+0i) # Ignores leading and trailing whitespace. + # 'x1'.to_c # => (0+0i) # Finds no leading numeric. + # + # # Integer literal embedded in the substring. + # '1'.to_c # => (1+0i) + # '-1'.to_c # => (-1+0i) + # '1i'.to_c # => (0+1i) + # + # # Integer literals that don't work. + # '0b100'.to_c # => (0+0i) # Not parsed as binary. + # '0o100'.to_c # => (0+0i) # Not parsed as octal. + # '0d100'.to_c # => (0+0i) # Not parsed as decimal. + # '0x100'.to_c # => (0+0i) # Not parsed as hexadecimal. + # '010'.to_c # => (10+0i) # Not parsed as octal. + # + # # Float literals: + # '3.14'.to_c # => (3.14+0i) + # '3.14i'.to_c # => (0+3.14i) + # '1.23e4'.to_c # => (12300.0+0i) + # '1.23e+4'.to_c # => (12300.0+0i) + # '1.23e-4'.to_c # => (0.000123+0i) + # + # # Rational literals: + # '1/2'.to_c # => ((1/2)+0i) + # '-1/2'.to_c # => ((-1/2)+0i) + # '1/2r'.to_c # => ((1/2)+0i) + # '-1/2r'.to_c # => ((-1/2)+0i) + # + # **Rectangular Coordinates** + # + # With separator `'+'` or `'-'`, or with no separator, interprets the values as + # rectangular coordinates: real and imaginary. + # + # With no separator, assigns a single value to either the real or the imaginary + # part: + # + # ''.to_c # => (0+0i) # Defaults to zero. + # '1'.to_c # => (1+0i) # Real (no trailing 'i'). + # '1i'.to_c # => (0+1i) # Imaginary (trailing 'i'). + # 'i'.to_c # => (0+1i) # Special case (imaginary 1). + # + # With separator `'+'`, both parts positive (or zero): + # + # # Without trailing 'i'. + # '+'.to_c # => (0+0i) # No values: defaults to zero. + # '+1'.to_c # => (1+0i) # Value after '+': real only. + # '1+'.to_c # => (1+0i) # Value before '+': real only. + # '2+1'.to_c # => (2+0i) # Values before and after '+': real and imaginary. + # # With trailing 'i'. + # '+1i'.to_c # => (0+1i) # Value after '+': imaginary only. + # '2+i'.to_c # => (2+1i) # Value before '+': real and imaginary 1. + # '2+1i'.to_c # => (2+1i) # Values before and after '+': real and imaginary. + # + # With separator `'-'`, negative imaginary part: + # + # # Without trailing 'i'. + # '-'.to_c # => (0+0i) # No values: defaults to zero. + # '-1'.to_c # => (-1+0i) # Value after '-': negative real, zero imaginary. + # '1-'.to_c # => (1+0i) # Value before '-': positive real, zero imaginary. + # '2-1'.to_c # => (2+0i) # Values before and after '-': positive real, zero imaginary. + # # With trailing 'i'. + # '-1i'.to_c # => (0-1i) # Value after '-': negative real, zero imaginary. + # '2-i'.to_c # => (2-1i) # Value before '-': positive real, negative imaginary. + # '2-1i'.to_c # => (2-1i) # Values before and after '-': positive real, negative imaginary. + # + # Note that the suffixed character `'i'` may instead be one of `'I'`, `'j'`, or + # `'J'`, with the same effect. + # + # **Polar Coordinates** + # + # With separator `'@'`) interprets the values as polar coordinates: magnitude + # and angle. + # + # '2@'.to_c.polar # => [2, 0.0] # Value before '@': magnitude only. + # # Values before and after '@': magnitude and angle. + # '2@1'.to_c.polar # => [2.0, 1.0] # "1.0@#{Math::PI/2}".to_c # => (0.0+1i) # "1.0@#{Math::PI}".to_c # => (-1+0.0i) + # # Magnitude not given: defaults to zero. + # '@'.to_c.polar # => [0, 0.0] + # '@1'.to_c.polar # => [0, 0.0] # - # Returns Complex zero if the string cannot be converted: + # '1.0@0'.to_c # => (1+0.0i) # - # 'ruby'.to_c # => (0+0i) + # Note that in all cases, the suffixed character `'i'` may instead be one of + # `'I'`, `'j'`, `'J'`, with the same effect. # - # See Kernel#Complex. + # See [Converting to Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def to_c: () -> Complex @@ -3193,18 +4943,20 @@ class String # rdoc-file=string.c # - to_f -> float # --> - # Returns the result of interpreting leading characters in `self` as a Float: + # Returns the result of interpreting leading characters in +self+ as a Float: # - # '3.14159'.to_f # => 3.14159 - # '1.234e-2'.to_f # => 0.01234 + # '3.14159'.to_f # => 3.14159 + # '1.234e-2'.to_f # => 0.01234 # - # Characters past a leading valid number (in the given `base`) are ignored: + # Characters past a leading valid number are ignored: # - # '3.14 (pi to two places)'.to_f # => 3.14 + # '3.14 (pi to two places)'.to_f # => 3.14 # - # Returns zero if there is no leading valid number: + # Returns zero if there is no leading valid number: + # + # 'abcdef'.to_f # => 0.0 # - # 'abcdef'.to_f # => 0.0 + # See [Converting to Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def to_f: () -> Float @@ -3213,13 +4965,13 @@ class String # - to_i(base = 10) -> integer # --> # Returns the result of interpreting leading characters in `self` as an integer - # in the given `base` (which must be in (0, 2..36)): + # in the given `base`; `base` must be either `0` or in range `(2..36)`: # # '123456'.to_i # => 123456 # '123def'.to_i(16) # => 1195503 # - # With `base` zero, string `object` may contain leading characters to specify - # the actual base: + # With `base` zero given, string `object` may contain leading characters to + # specify the actual base: # # '123def'.to_i(0) # => 123 # '0123def'.to_i(0) # => 83 @@ -3238,66 +4990,74 @@ class String # 'abcdef'.to_i # => 0 # '2'.to_i(2) # => 0 # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). + # def to_i: (?int radix) -> Integer # - # Returns the result of interpreting leading characters in `str` as a rational. - # Leading whitespace and extraneous characters past the end of a valid number - # are ignored. Digit sequences can be separated by an underscore. If there is - # not a valid number at the start of `str`, zero is returned. This method never - # raises an exception. + # Returns the result of interpreting leading characters in `self` as a rational + # value: + # + # '123'.to_r # => (123/1) # Integer literal. + # '300/2'.to_r # => (150/1) # Rational literal. + # '-9.2'.to_r # => (-46/5) # Float literal. + # '-9.2e2'.to_r # => (-920/1) # Float literal. # - # ' 2 '.to_r #=> (2/1) - # '300/2'.to_r #=> (150/1) - # '-9.2'.to_r #=> (-46/5) - # '-9.2e2'.to_r #=> (-920/1) - # '1_234_567'.to_r #=> (1234567/1) - # '21 June 09'.to_r #=> (21/1) - # '21/06/09'.to_r #=> (7/2) - # 'BWV 1079'.to_r #=> (0/1) + # Ignores leading and trailing whitespace, and trailing non-numeric characters: # - # NOTE: "0.3".to_r isn't the same as 0.3.to_r. The former is equivalent to - # "3/10".to_r, but the latter isn't so. + # ' 2 '.to_r # => (2/1) + # '21-Jun-09'.to_r # => (21/1) # - # "0.3".to_r == 3/10r #=> true - # 0.3.to_r == 3/10r #=> false + # Returns Rational zero if there are no leading numeric characters. # - # See also Kernel#Rational. + # 'BWV 1079'.to_r # => (0/1) + # + # NOTE: `'0.3'.to_r` is equivalent to `3/10r`, but is different from `0.3.to_r`: + # + # '0.3'.to_r # => (3/10) + # 3/10r # => (3/10) + # 0.3.to_r # => (5404319552844595/18014398509481984) + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def to_r: () -> Rational # # Returns `self` if `self` is a `String`, or `self` converted to a `String` if # `self` is a subclass of `String`. # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). + # def to_s: () -> String # # Returns `self` if `self` is a `String`, or `self` converted to a `String` if # `self` is a subclass of `String`. # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). + # alias to_str to_s # - # Returns the `Symbol` corresponding to *str*, creating the symbol if it did not - # previously exist. See Symbol#id2name. - # - # "Koala".intern #=> :Koala - # s = 'cat'.to_sym #=> :cat - # s == :cat #=> true - # s = '@cat'.to_sym #=> :@cat - # s == :@cat #=> true + # Returns the Symbol object derived from `self`, creating it if it did not + # already exist: # - # This can also be used to create symbols that cannot be represented using the - # `:xxx` notation. + # 'foo'.intern # => :foo + # 'тест'.intern # => :тест + # 'こんにちは'.intern # => :こんにちは # - # 'cat and dog'.to_sym #=> :"cat and dog" + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # alias to_sym intern @@ -3327,40 +5087,50 @@ class String # # Arguments `selector` and `replacements` must be valid character selectors (see # [Character Selectors](rdoc-ref:character_selectors.rdoc)), and may use any of - # its valid forms, including negation, ranges, and escaping: + # its valid forms, including negation, ranges, and escapes: # - # # Negation. - # 'hello'.tr('^aeiou', '-') # => "-e--o" - # # Ranges. - # 'ibm'.tr('b-z', 'a-z') # => "hal" - # # Escapes. + # 'hello'.tr('^aeiou', '-') # => "-e--o" # Negation. + # 'ibm'.tr('b-z', 'a-z') # => "hal" # Range. # 'hel^lo'.tr('\^aeiou', '-') # => "h-l-l-" # Escaped leading caret. # 'i-b-m'.tr('b\-z', 'a-z') # => "ibabm" # Escaped embedded hyphen. # 'foo\\bar'.tr('ab\\', 'XYZ') # => "fooZYXr" # Escaped backslash. # + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). + # def tr: (selector source, string relpacement) -> String # - # Like String#tr, but modifies `self` in place. Returns `self` if any changes - # were made, `nil` otherwise. + # Like String#tr, except: + # + # * Performs substitutions in `self` (not in a copy of `self`). + # * Returns `self` if any modifications were made, `nil` otherwise. + # + # Related: [Modifying](rdoc-ref:String@Modifying). # def tr!: (selector source, string relpacement) -> self? # - # Like String#tr, but also squeezes the modified portions of the translated - # string; returns a new string (translated and squeezed). + # Like String#tr, except: + # + # * Also squeezes the modified portions of the translated string; see + # String#squeeze. + # * Returns the translated and squeezed string. + # + # Examples: # # 'hello'.tr_s('l', 'r') #=> "hero" # 'hello'.tr_s('el', '-') #=> "h-o" # 'hello'.tr_s('el', 'hx') #=> "hhxo" # - # Related: String#squeeze. + # Related: see [Converting to New + # String](rdoc-ref:String@Converting+to+New+String). # def tr_s: (selector source, string replacement) -> String @@ -3368,10 +5138,12 @@ class String # rdoc-file=string.c # - tr_s!(selector, replacements) -> self or nil # --> - # Like String#tr_s, but modifies `self` in place. Returns `self` if any changes - # were made, `nil` otherwise. + # Like String#tr_s, except: # - # Related: String#squeeze!. + # * Modifies `self` in place (not a copy of `self`). + # * Returns `self` if any changes were made, `nil` otherwise. + # + # Related: [Modifying](rdoc-ref:String@Modifying). # def tr_s!: (selector source, string replacement) -> self? @@ -3430,9 +5202,9 @@ class String # - unicode_normalize!(form = :nfc) -> self # --> # Like String#unicode_normalize, except that the normalization is performed on - # `self`. + # `self` (not on a copy of `self`). # - # Related String#unicode_normalized?. + # Related: see [Modifying](rdoc-ref:String@Modifying). # def unicode_normalize!: (?:nfc | :nfd | :nfkc | :nfkd form) -> self @@ -3440,9 +5212,10 @@ class String # rdoc-file=string.c # - unicode_normalized?(form = :nfc) -> true or false # --> - # Returns `true` if `self` is in the given `form` of Unicode normalization, - # `false` otherwise. The `form` must be one of `:nfc`, `:nfd`, `:nfkc`, or - # `:nfkd`. + # Returns whether `self` is in the given `form` of Unicode normalization; see + # String#unicode_normalize. + # + # The `form` must be one of `:nfc`, `:nfd`, `:nfkc`, or `:nfkd`. # # Examples: # @@ -3453,23 +5226,27 @@ class String # # Raises an exception if `self` is not in a Unicode encoding: # - # s = "\xE0".force_encoding('ISO-8859-1') - # s.unicode_normalized? # Raises Encoding::CompatibilityError. + # s = "\xE0".force_encoding(Encoding::ISO_8859_1) + # s.unicode_normalized? # Raises Encoding::CompatibilityError # - # Related: String#unicode_normalize, String#unicode_normalize!. + # Related: see [Querying](rdoc-ref:String@Querying). # def unicode_normalized?: (?:nfc | :nfd | :nfkc | :nfkd) -> bool # - # Extracts data from `self`. + # Extracts data from `self` to form new objects; see [Packed + # Data](rdoc-ref:packed_data.rdoc). # - # If `block` is not given, forming objects that become the elements of a new - # array, and returns that array. Otherwise, yields each object. + # With a block given, calls the block with each unpacked object. # - # See [Packed Data](rdoc-ref:packed_data.rdoc). + # With no block given, returns an array containing the unpacked objects. + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def unpack: (string template, ?offset: int) -> Array[Integer | Float | String | nil] | (string template, ?offset: int) { (Integer | Float | String | nil value) -> void } -> nil @@ -3478,21 +5255,24 @@ class String # rdoc-file=pack.rb # - unpack1(template, offset: 0) -> object # --> - # Like String#unpack, but unpacks and returns only the first extracted object. - # See [Packed Data](rdoc-ref:packed_data.rdoc). + # Like String#unpack with no block, but unpacks and returns only the first + # extracted object. See [Packed Data](rdoc-ref:packed_data.rdoc). + # + # Related: see [Converting to + # Non-String](rdoc-ref:String@Converting+to+Non--5CString). # def unpack1: (string template, ?offset: int) -> (Integer | Float | String)? # # Returns a string containing the upcased characters in `self`: # # s = 'Hello World!' # => "Hello World!" # s.upcase # => "HELLO WORLD!" # - # The casing may be affected by the given `options`; see [Case + # The casing may be affected by the given `mapping`; see [Case # Mapping](rdoc-ref:case_mapping.rdoc). # # Related: String#upcase!, String#downcase, String#downcase!. @@ -3504,7 +5284,7 @@ class String # # Upcases the characters in `self`; returns `self` if any changes were made, # `nil` otherwise: @@ -3514,7 +5294,7 @@ class String # s # => "HELLO WORLD!" # s.upcase! # => nil # - # The casing may be affected by the given `options`; see [Case + # The casing may be affected by the given `mapping`; see [Case # Mapping](rdoc-ref:case_mapping.rdoc). # # Related: String#upcase, String#downcase, String#downcase!. @@ -3567,9 +5347,9 @@ class String # --> # Returns `true` if `self` is encoded correctly, `false` otherwise: # - # "\xc2\xa1".force_encoding("UTF-8").valid_encoding? # => true - # "\xc2".force_encoding("UTF-8").valid_encoding? # => false - # "\x80".force_encoding("UTF-8").valid_encoding? # => false + # "\xc2\xa1".force_encoding(Encoding::UTF_8).valid_encoding? # => true + # "\xc2".force_encoding(Encoding::UTF_8).valid_encoding? # => false + # "\x80".force_encoding(Encoding::UTF_8).valid_encoding? # => false # def valid_encoding?: () -> bool end diff --git a/core/struct.rbs b/core/struct.rbs index 1026b1c6e..65f088711 100644 --- a/core/struct.rbs +++ b/core/struct.rbs @@ -130,7 +130,7 @@ class Struct[Elem] # Foo = Struct.new('Foo', :foo, :bar) # => Struct::Foo # f = Foo.new(0, 1) # => # # - # **\Class Name** + # **Class Name** # # With string argument `class_name`, returns a new subclass of `Struct` named # `Struct::*class_name`*: diff --git a/core/symbol.rbs b/core/symbol.rbs index 5589f9370..9e21ff95a 100644 --- a/core/symbol.rbs +++ b/core/symbol.rbs @@ -188,7 +188,7 @@ class Symbol # # Equivalent to `sym.to_s.capitalize.to_sym`. # @@ -268,7 +268,7 @@ class Symbol # # Equivalent to `sym.to_s.downcase.to_sym`. # @@ -413,7 +413,7 @@ class Symbol # # Equivalent to `sym.to_s.swapcase.to_sym`. # @@ -462,7 +462,7 @@ class Symbol # # Equivalent to `sym.to_s.upcase.to_sym`. # diff --git a/core/thread.rbs b/core/thread.rbs index 467c06f9d..b70bc0beb 100644 --- a/core/thread.rbs +++ b/core/thread.rbs @@ -265,7 +265,10 @@ class Thread < Object # --> # Terminates `thr` and schedules another thread to be run, returning the # terminated Thread. If this is the main thread, or the last thread, exits the - # process. + # process. Note that the caller does not wait for the thread to terminate if the + # receiver is different from the currently running thread. The termination is + # asynchronous, and the thread can still run a small amount of ruby code before + # exiting. # def kill: () -> Thread? @@ -334,7 +337,10 @@ class Thread < Object # # Terminates `thr` and schedules another thread to be run, returning the # terminated Thread. If this is the main thread, or the last thread, exits the - # process. + # process. Note that the caller does not wait for the thread to terminate if the + # receiver is different from the currently running thread. The termination is + # asynchronous, and the thread can still run a small amount of ruby code before + # exiting. # def exit: () -> Thread? @@ -364,19 +370,23 @@ class Thread < Object # + # Creates a new thread executing the given block. + # + # Any `args` given to ::new will be passed to the block: + # + # arr = [] + # a, b, c = 1, 2, 3 + # Thread.new(a,b,c) { |d,e,f| arr << d << e << f }.join + # arr #=> [1, 2, 3] + # + # A ThreadError exception is raised if ::new is called without a block. + # + # If you're going to subclass Thread, be sure to call super in your `initialize` + # method, otherwise a ThreadError will be raised. # def initialize: (*untyped) { (?) -> void } -> void @@ -656,7 +666,10 @@ class Thread < Object # # Terminates `thr` and schedules another thread to be run, returning the # terminated Thread. If this is the main thread, or the last thread, exits the - # process. + # process. Note that the caller does not wait for the thread to terminate if the + # receiver is different from the currently running thread. The termination is + # asynchronous, and the thread can still run a small amount of ruby code before + # exiting. # def terminate: () -> Thread? @@ -968,8 +981,8 @@ class Thread < Object # from prog.rb:2:in `new' # from prog.rb:2 # - def raise: (?String message) -> nil - | (_Exception, ?_ToS message, ?Array[Thread::Backtrace::Location] | Array[String] | nil backtrace) -> nil + def raise: (?String message, ?cause: Exception?) -> nil + | (_Exception, ?_ToS message, ?Array[Thread::Backtrace::Location] | Array[String] | nil backtrace, ?cause: Exception?) -> nil # # ConditionVariable objects augment class Mutex. Using condition variables, it # is possible to suspend while in the middle of a critical section until a -# resource becomes available. +# condition is met, such as a resource becomes available. +# +# Due to non-deterministic scheduling and spurious wake-ups, users of condition +# variables should always use a separate boolean predicate (such as reading from +# a boolean variable) to check if the condition is actually met before starting +# to wait, and should wait in a loop, re-checking the condition every time the +# ConditionVariable is waken up. The idiomatic way of using condition variables +# is calling the `wait` method in an `until` loop with the predicate as the loop +# condition. +# +# condvar.wait(mutex) until condition_is_met +# +# In the example below, we use the boolean variable `resource_available` (which +# is protected by `mutex`) to indicate the availability of the resource, and use +# `condvar` to wait for that variable to become true. Note that: +# +# 1. Thread `b` may be scheduled before thread `a1` and `a2`, and may run so +# fast that it have already made the resource available before either `a1` +# or `a2` starts. Therefore, `a1` and `a2` should check if +# `resource_available` is already true before starting to wait. +# 2. The `wait` method may spuriously wake up without signalling. Therefore, +# thread `a1` and `a2` should recheck `resource_available` after the `wait` +# method returns, and go back to wait if the condition is not actually met. +# 3. It is possible that thread `a2` starts right after thread `a1` is waken up +# by `b`. Thread `a2` may have acquired the `mutex` and consumed the +# resource before thread `a1` acquires the `mutex`. This necessitates +# rechecking after `wait`, too. # # Example: # # mutex = Thread::Mutex.new -# resource = Thread::ConditionVariable.new # -# a = Thread.new { -# mutex.synchronize { -# # Thread 'a' now needs the resource -# resource.wait(mutex) -# # 'a' can now have the resource -# } +# resource_available = false +# condvar = Thread::ConditionVariable.new +# +# a1 = Thread.new { +# # Thread 'a1' waits for the resource to become available and consumes +# # the resource. +# mutex.synchronize { +# condvar.wait(mutex) until resource_available +# # After the loop, 'resource_available' is guaranteed to be true. +# +# resource_available = false +# puts "a1 consumed the resource" +# } +# } +# +# a2 = Thread.new { +# # Thread 'a2' behaves like 'a1'. +# mutex.synchronize { +# condvar.wait(mutex) until resource_available +# resource_available = false +# puts "a2 consumed the resource" +# } # } # # b = Thread.new { -# mutex.synchronize { -# # Thread 'b' has finished using the resource -# resource.signal -# } +# # Thread 'b' periodically makes the resource available. +# loop { +# mutex.synchronize { +# resource_available = true +# +# # Notify one waiting thread if any. It is possible that neither +# # 'a1' nor 'a2 is waiting on 'condvar' at this moment. That's OK. +# condvar.signal +# } +# sleep 1 +# } # } # +# # Eventually both 'a1' and 'a2' will have their resources, albeit in an +# # unspecified order. +# [a1, a2].each {|th| th.join} +# class Thread::ConditionVariable < Object # -# Ruby supports two forms of objectified methods. Class Method is used to +# Ruby supports two forms of objectified methods. Class `Method` is used to # represent methods that are associated with a particular object: these method # objects are bound to that object. Bound method objects for an object can be # created using Object#method. @@ -287,10 +287,18 @@ class UnboundMethod # - # Returns the Ruby source filename and line number containing this method or nil - # if this method was not defined in Ruby (i.e. native). + # Returns the location where the method was defined. The returned Array + # contains: + # (1) the Ruby source filename + # (2) the line number where the definition starts + # (3) the column number where the definition starts + # (4) the line number where the definition ends + # (5) the column number where the definitions ends + # + # This method will return `nil` if the method was not defined in Ruby (i.e. + # native). # def source_location: () -> [String, Integer]? @@ -298,8 +306,8 @@ class UnboundMethod # rdoc-file=proc.c # - meth.super_method -> method # --> - # Returns a Method of superclass which would be called when super is used or nil - # if there is no method on superclass. + # Returns a `Method` of superclass which would be called when super is used or + # nil if there is no method on superclass. # def super_method: () -> UnboundMethod? diff --git a/stdlib/cgi/0/core.rbs b/stdlib/cgi/0/core.rbs index 52e8ccd07..ac62d42c0 100644 --- a/stdlib/cgi/0/core.rbs +++ b/stdlib/cgi/0/core.rbs @@ -1,274 +1,5 @@ -# -# ## Overview -# -# The Common Gateway Interface (CGI) is a simple protocol for passing an HTTP -# request from a web server to a standalone program, and returning the output to -# the web browser. Basically, a CGI program is called with the parameters of -# the request passed in either in the environment (GET) or via $stdin (POST), -# and everything it prints to $stdout is returned to the client. -# -# This file holds the CGI class. This class provides functionality for -# retrieving HTTP request parameters, managing cookies, and generating HTML -# output. -# -# The file CGI::Session provides session management functionality; see that -# class for more details. -# -# See http://www.w3.org/CGI/ for more information on the CGI protocol. -# -# ## Introduction -# -# CGI is a large class, providing several categories of methods, many of which -# are mixed in from other modules. Some of the documentation is in this class, -# some in the modules CGI::QueryExtension and CGI::HtmlExtension. See -# CGI::Cookie for specific information on handling cookies, and cgi/session.rb -# (CGI::Session) for information on sessions. -# -# For queries, CGI provides methods to get at environmental variables, -# parameters, cookies, and multipart request data. For responses, CGI provides -# methods for writing output and generating HTML. -# -# Read on for more details. Examples are provided at the bottom. -# -# ## Queries -# -# The CGI class dynamically mixes in parameter and cookie-parsing functionality, -# environmental variable access, and support for parsing multipart requests -# (including uploaded files) from the CGI::QueryExtension module. -# -# ### Environmental Variables -# -# The standard CGI environmental variables are available as read-only attributes -# of a CGI object. The following is a list of these variables: -# -# AUTH_TYPE HTTP_HOST REMOTE_IDENT -# CONTENT_LENGTH HTTP_NEGOTIATE REMOTE_USER -# CONTENT_TYPE HTTP_PRAGMA REQUEST_METHOD -# GATEWAY_INTERFACE HTTP_REFERER SCRIPT_NAME -# HTTP_ACCEPT HTTP_USER_AGENT SERVER_NAME -# HTTP_ACCEPT_CHARSET PATH_INFO SERVER_PORT -# HTTP_ACCEPT_ENCODING PATH_TRANSLATED SERVER_PROTOCOL -# HTTP_ACCEPT_LANGUAGE QUERY_STRING SERVER_SOFTWARE -# HTTP_CACHE_CONTROL REMOTE_ADDR -# HTTP_FROM REMOTE_HOST -# -# For each of these variables, there is a corresponding attribute with the same -# name, except all lower case and without a preceding HTTP_. `content_length` -# and `server_port` are integers; the rest are strings. -# -# ### Parameters -# -# The method #params() returns a hash of all parameters in the request as -# name/value-list pairs, where the value-list is an Array of one or more values. -# The CGI object itself also behaves as a hash of parameter names to values, -# but only returns a single value (as a String) for each parameter name. -# -# For instance, suppose the request contains the parameter "favourite_colours" -# with the multiple values "blue" and "green". The following behavior would -# occur: -# -# cgi.params["favourite_colours"] # => ["blue", "green"] -# cgi["favourite_colours"] # => "blue" -# -# If a parameter does not exist, the former method will return an empty array, -# the latter an empty string. The simplest way to test for existence of a -# parameter is by the #has_key? method. -# -# ### Cookies -# -# HTTP Cookies are automatically parsed from the request. They are available -# from the #cookies() accessor, which returns a hash from cookie name to -# CGI::Cookie object. -# -# ### Multipart requests -# -# If a request's method is POST and its content type is multipart/form-data, -# then it may contain uploaded files. These are stored by the QueryExtension -# module in the parameters of the request. The parameter name is the name -# attribute of the file input field, as usual. However, the value is not a -# string, but an IO object, either an IOString for small files, or a Tempfile -# for larger ones. This object also has the additional singleton methods: -# -# #local_path() -# : the path of the uploaded file on the local filesystem -# -# #original_filename() -# : the name of the file on the client computer -# -# #content_type() -# : the content type of the file -# -# -# ## Responses -# -# The CGI class provides methods for sending header and content output to the -# HTTP client, and mixes in methods for programmatic HTML generation from -# CGI::HtmlExtension and CGI::TagMaker modules. The precise version of HTML to -# use for HTML generation is specified at object creation time. -# -# ### Writing output -# -# The simplest way to send output to the HTTP client is using the #out() method. -# This takes the HTTP headers as a hash parameter, and the body content via a -# block. The headers can be generated as a string using the #http_header() -# method. The output stream can be written directly to using the #print() -# method. -# -# ### Generating HTML -# -# Each HTML element has a corresponding method for generating that element as a -# String. The name of this method is the same as that of the element, all -# lowercase. The attributes of the element are passed in as a hash, and the -# body as a no-argument block that evaluates to a String. The HTML generation -# module knows which elements are always empty, and silently drops any passed-in -# body. It also knows which elements require matching closing tags and which -# don't. However, it does not know what attributes are legal for which -# elements. -# -# There are also some additional HTML generation methods mixed in from the -# CGI::HtmlExtension module. These include individual methods for the different -# types of form inputs, and methods for elements that commonly take particular -# attributes where the attributes can be directly specified as arguments, rather -# than via a hash. -# -# ### Utility HTML escape and other methods like a function. -# -# There are some utility tool defined in cgi/util.rb . And when include, you can -# use utility methods like a function. -# -# ## Examples of use -# -# ### Get form values -# -# require "cgi" -# cgi = CGI.new -# value = cgi['field_name'] # <== value string for 'field_name' -# # if not 'field_name' included, then return "". -# fields = cgi.keys # <== array of field names -# -# # returns true if form has 'field_name' -# cgi.has_key?('field_name') -# cgi.has_key?('field_name') -# cgi.include?('field_name') -# -# CAUTION! `cgi['field_name']` returned an Array with the old cgi.rb(included in -# Ruby 1.6) -# -# ### Get form values as hash -# -# require "cgi" -# cgi = CGI.new -# params = cgi.params -# -# cgi.params is a hash. -# -# cgi.params['new_field_name'] = ["value"] # add new param -# cgi.params['field_name'] = ["new_value"] # change value -# cgi.params.delete('field_name') # delete param -# cgi.params.clear # delete all params -# -# ### Save form values to file -# -# require "pstore" -# db = PStore.new("query.db") -# db.transaction do -# db["params"] = cgi.params -# end -# -# ### Restore form values from file -# -# require "pstore" -# db = PStore.new("query.db") -# db.transaction do -# cgi.params = db["params"] -# end -# -# ### Get multipart form values -# -# require "cgi" -# cgi = CGI.new -# value = cgi['field_name'] # <== value string for 'field_name' -# value.read # <== body of value -# value.local_path # <== path to local file of value -# value.original_filename # <== original filename of value -# value.content_type # <== content_type of value -# -# and value has StringIO or Tempfile class methods. -# -# ### Get cookie values -# -# require "cgi" -# cgi = CGI.new -# values = cgi.cookies['name'] # <== array of 'name' -# # if not 'name' included, then return []. -# names = cgi.cookies.keys # <== array of cookie names -# -# and cgi.cookies is a hash. -# -# ### Get cookie objects -# -# require "cgi" -# cgi = CGI.new -# for name, cookie in cgi.cookies -# cookie.expires = Time.now + 30 -# end -# cgi.out("cookie" => cgi.cookies) {"string"} -# -# cgi.cookies # { "name1" => cookie1, "name2" => cookie2, ... } -# -# require "cgi" -# cgi = CGI.new -# cgi.cookies['name'].expires = Time.now + 30 -# cgi.out("cookie" => cgi.cookies['name']) {"string"} -# -# ### Print http header and html string to $DEFAULT_OUTPUT ($>) -# -# require "cgi" -# cgi = CGI.new("html4") # add HTML generation methods -# cgi.out do -# cgi.html do -# cgi.head do -# cgi.title { "TITLE" } -# end + -# cgi.body do -# cgi.form("ACTION" => "uri") do -# cgi.p do -# cgi.textarea("get_text") + -# cgi.br + -# cgi.submit -# end -# end + -# cgi.pre do -# CGI.escapeHTML( -# "params: #{cgi.params.inspect}\n" + -# "cookies: #{cgi.cookies.inspect}\n" + -# ENV.collect do |key, value| -# "#{key} --> #{value}\n" -# end.join("") -# ) -# end -# end -# end -# end -# -# # add HTML generation methods -# CGI.new("html3") # html3.2 -# CGI.new("html4") # html4.01 (Strict) -# CGI.new("html4Tr") # html4.01 Transitional -# CGI.new("html4Fr") # html4.01 Frameset -# CGI.new("html5") # html5 -# -# ### Some utility methods -# -# require 'cgi/util' -# CGI.escapeHTML('Usage: foo "bar" ') -# -# ### Some utility methods like a function -# -# require 'cgi/util' -# include CGI::Util -# escapeHTML('Usage: foo "bar" ') -# h('Usage: foo "bar" ') # alias +# +# :stopdoc # class CGI include CGI::Util @@ -906,62 +637,84 @@ class CGI | (Hash[String, untyped] options_hash) -> void end + # + # Escape/unescape for CGI, HTML, URI. + # module Escape # - # Returns URL-escaped string (`application/x-www-form-urlencoded`). + # URL-encode a string into application/x-www-form-urlencoded. Space characters + # (+" "+) are encoded with plus signs (+"+"+) + # url_encoded_string = CGI.escape("'Stop!' said Fred") + # # => "%27Stop%21%27+said+Fred" # def escape: (string str) -> String # - # Returns HTML-escaped string. + # Escape special characters in HTML, namely '&"<> + # CGI.escapeHTML('Usage: foo "bar" ') + # # => "Usage: foo "bar" <baz>" # def escapeHTML: (string str) -> String # - # Returns URL-escaped string following RFC 3986. + # URL-encode a string following RFC 3986 Space characters (+" "+) are encoded + # with (+"%20"+) + # url_encoded_string = CGI.escapeURIComponent("'Stop!' said Fred") + # # => "%27Stop%21%27%20said%20Fred" # def escapeURIComponent: (string) -> String - # - # Returns URL-escaped string following RFC 3986. + # # alias escape_uri_component escapeURIComponent # - # Returns URL-unescaped string (`application/x-www-form-urlencoded`). + # URL-decode an application/x-www-form-urlencoded string with + # encoding(optional). + # string = CGI.unescape("%27Stop%21%27+said+Fred") + # # => "'Stop!' said Fred" # def unescape: (string str, ?encoding encoding) -> String # - # Returns HTML-unescaped string. + # Unescape a string that has been HTML-escaped + # CGI.unescapeHTML("Usage: foo "bar" <baz>") + # # => "Usage: foo \"bar\" " # def unescapeHTML: (string str) -> String # - # Returns URL-unescaped string following RFC 3986. + # URL-decode a string following RFC 3986 with encoding(optional). + # string = CGI.unescapeURIComponent("%27Stop%21%27+said%20Fred") + # # => "'Stop!'+said Fred" # def unescapeURIComponent: (string) -> String - # - # Returns URL-unescaped string following RFC 3986. + # # alias unescape_uri_component unescapeURIComponent end diff --git a/stdlib/coverage/0/coverage.rbs b/stdlib/coverage/0/coverage.rbs index 8f980f234..a9ca35cb2 100644 --- a/stdlib/coverage/0/coverage.rbs +++ b/stdlib/coverage/0/coverage.rbs @@ -147,8 +147,10 @@ module Coverage # + # A simple helper function that creates the "stub" of line coverage from a given + # source code. # def self.line_stub: (String) -> Array[Integer?] diff --git a/stdlib/delegate/0/delegator.rbs b/stdlib/delegate/0/delegator.rbs index cc31b931c..10f37d8a4 100644 --- a/stdlib/delegate/0/delegator.rbs +++ b/stdlib/delegate/0/delegator.rbs @@ -44,7 +44,7 @@ class Delegator < BasicObject # rdoc-file=lib/delegate.rb # - !() # --> - # Delegates ! to the _*getobj*_ + # Delegates ! to the `__getobj__` # def !: () -> untyped @@ -94,7 +94,7 @@ class Delegator < BasicObject # rdoc-file=lib/delegate.rb # - freeze() # --> - # :method: freeze Freeze both the object returned by _*getobj*_ and self. + # :method: freeze Freeze both the object returned by `__getobj__` and self. # def freeze: () -> self @@ -102,7 +102,7 @@ class Delegator < BasicObject # rdoc-file=lib/delegate.rb # - marshal_dump() # --> - # Serialization support for the object returned by _*getobj*_. + # Serialization support for the object returned by `__getobj__`. # def marshal_dump: () -> untyped @@ -126,7 +126,7 @@ class Delegator < BasicObject # - methods(all=true) # --> # Returns the methods available to this delegate object as the union of this - # object's and _*getobj*_ methods. + # object's and `__getobj__` methods. # def methods: (?boolish all) -> Array[Symbol] @@ -135,7 +135,7 @@ class Delegator < BasicObject # - protected_methods(all=true) # --> # Returns the methods available to this delegate object as the union of this - # object's and _*getobj*_ protected methods. + # object's and `__getobj__` protected methods. # def protected_methods: (?boolish all) -> Array[Symbol] @@ -144,7 +144,7 @@ class Delegator < BasicObject # - public_methods(all=true) # --> # Returns the methods available to this delegate object as the union of this - # object's and _*getobj*_ public methods. + # object's and `__getobj__` public methods. # def public_methods: (?untyped all) -> Array[Symbol] @@ -168,7 +168,7 @@ class Delegator < BasicObject # - respond_to_missing?(m, include_private) # --> # Checks for a method provided by this the delegate object by forwarding the - # call through _*getobj*_. + # call through `__getobj__`. # def respond_to_missing?: (Symbol m, bool include_private) -> bool @@ -180,5 +180,8 @@ class Delegator < BasicObject # def target_respond_to?: (untyped target, Symbol m, bool include_private) -> bool + # + # The version string + # VERSION: String end diff --git a/stdlib/erb/0/erb.rbs b/stdlib/erb/0/erb.rbs index 3e2ebb035..64eac1aa1 100644 --- a/stdlib/erb/0/erb.rbs +++ b/stdlib/erb/0/erb.rbs @@ -1,451 +1,804 @@ # -# # ERB -- Ruby Templating -# -# ## Introduction -# -# ERB provides an easy to use but powerful templating system for Ruby. Using -# ERB, actual Ruby code can be added to any plain text document for the purposes -# of generating document information details and/or flow control. -# -# A very simple example is this: -# +# Class **ERB** (the name stands for **Embedded Ruby**) +# is an easy-to-use, but also very powerful, [template +# processor](https://en.wikipedia.org/wiki/Template_processor). +# ## Usage +# Before you can use ERB, you must first require it +# (examples on this page assume that this has been done): # require 'erb' # -# x = 42 -# template = ERB.new <<-EOF -# The value of x is: <%= x %> -# EOF -# puts template.result(binding) -# -# *Prints:* The value of x is: 42 -# -# More complex examples are given below. -# -# ## Recognized Tags -# -# ERB recognizes certain tags in the provided template and converts them based -# on the rules below: -# -# <% Ruby code -- inline with output %> -# <%= Ruby expression -- replace with result %> -# <%# comment -- ignored -- useful in testing %> (`<% #` doesn't work. Don't use Ruby comments.) -# % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new) -# %% replaced with % if first thing on a line and % processing is used -# <%% or %%> -- replace with <% or %> respectively -# -# All other text is passed through ERB filtering unchanged. -# -# ## Options -# -# There are several settings you can change when you use ERB: -# * the nature of the tags that are recognized; -# * the binding used to resolve local variables in the template. -# -# See the ERB.new and ERB#result methods for more detail. -# -# ## Character encodings -# -# ERB (or Ruby code generated by ERB) returns a string in the same character -# encoding as the input string. When the input string has a magic comment, -# however, it returns a string in the encoding specified by the magic comment. -# -# # -*- coding: utf-8 -*- -# require 'erb' -# -# template = ERB.new < -# \_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>. -# EOF -# puts template.result -# -# *Prints:* _*ENCODING*_ is Big5. -# -# ## Examples -# -# ### Plain Text -# -# ERB is useful for any generic templating situation. Note that in this -# example, we use the convenient "% at start of line" tag, and we quote the -# template literally with `%q{...}` to avoid trouble with the backslash. -# -# require "erb" -# -# # Create template. +# ## In Brief +# Here's how ERB works: +# * You can create a *template*: a plain-text string that includes specially +# formatted *tags*.. +# * You can create an ERB object to store the template. +# * You can call instance method ERB#result to get the *result*. +# ERB supports tags of three kinds: +# * [Expression tags](rdoc-ref:ERB@Expression+Tags): +# each begins with `'<%='`, ends with `'%>'`; contains a Ruby expression; +# in the result, the value of the expression replaces the entire tag: +# template = 'The magic word is <%= magic_word %>.' +# erb = ERB.new(template) +# magic_word = 'xyzzy' +# erb.result(binding) # => "The magic word is xyzzy." +# +# The above call to #result passes argument `binding`, +# which contains the binding of variable `magic_word` to its string value +# `'xyzzy'`. +# The below call to #result need not pass a binding, +# because its expression `Date::DAYNAMES` is globally defined. +# ERB.new('Today is <%= Date::DAYNAMES[Date.today.wday] %>.').result # => "Today is Monday." +# +# * [Execution tags](rdoc-ref:ERB@Execution+Tags): +# each begins with `'<%'`, ends with `'%>'`; contains Ruby code to be +# executed: +# template = '<% File.write("t.txt", "Some stuff.") %>' +# ERB.new(template).result +# File.read('t.txt') # => "Some stuff." +# +# * [Comment tags](rdoc-ref:ERB@Comment+Tags): +# each begins with `'<%#'`, ends with `'%>'`; contains comment text; +# in the result, the entire tag is omitted. +# template = 'Some stuff;<%# Note to self: figure out what the stuff is. %> more stuff.' +# ERB.new(template).result # => "Some stuff; more stuff." +# +# ## Some Simple Examples +# Here's a simple example of ERB in action: +# template = 'The time is <%= Time.now %>.' +# erb = ERB.new(template) +# erb.result +# # => "The time is 2025-09-09 10:49:26 -0500." +# +# Details: +# 1. A plain-text string is assigned to variable `template`. +# Its embedded [expression tag](rdoc-ref:ERB@Expression+Tags) `'<%= +# Time.now %>'` includes a Ruby expression, `Time.now`. +# 2. The string is put into a new ERB object, and stored in variable `erb`. +# 3. Method call `erb.result` generates a string that contains the run-time +# value of `Time.now`, +# as computed at the time of the call. +# The +# ERB object may be re-used: +# erb.result +# # => "The time is 2025-09-09 10:49:33 -0500." +# +# Another example: +# template = 'The magic word is <%= magic_word %>.' +# erb = ERB.new(template) +# magic_word = 'abracadabra' +# erb.result(binding) +# # => "The magic word is abracadabra." +# +# Details: +# 1. As before, a plain-text string is assigned to variable `template`. +# Its embedded [expression tag](rdoc-ref:ERB@Expression+Tags) `'<%= +# magic_word %>'` has a variable *name*, `magic_word`. +# 2. The string is put into a new ERB object, and stored in variable `erb`; +# note that `magic_word` need not be defined before the ERB object is +# created. +# 3. `magic_word = 'abracadabra'` assigns a value to variable `magic_word`. +# 4. Method call `erb.result(binding)` generates a string +# that contains the *value* of `magic_word`. +# As before, the ERB object may be re-used: +# magic_word = 'xyzzy' +# erb.result(binding) +# # => "The magic word is xyzzy." +# +# ## Bindings +# A call to method #result, which produces the formatted result string, +# requires a [Binding object](https://docs.ruby-lang.org/en/master/Binding.html) +# as its argument. +# The binding object provides the bindings for expressions in [expression +# tags](rdoc-ref:ERB@Expression+Tags). +# There are three ways to provide the required binding: +# * [Default binding](rdoc-ref:ERB@Default+Binding). +# * [Local binding](rdoc-ref:ERB@Local+Binding). +# * [Augmented binding](rdoc-ref:ERB@Augmented+Binding) +# ### Default Binding +# When you pass no `binding` argument to method #result, +# the method uses its default binding: the one returned by method #new_toplevel. +# This binding has the bindings defined by Ruby itself, +# which are those for Ruby's constants and variables. +# That binding is sufficient for an expression tag that refers only to Ruby's +# constants and variables; +# these expression tags refer only to Ruby's global constant `RUBY_COPYRIGHT` +# and global variable `$0`: +# template = <