From 6f5cf581b8077717617b0610f4edd653ae087796 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Thu, 19 Dec 2024 15:29:59 +0900 Subject: [PATCH 01/18] Add `Array#fetch_values` --- core/array.rbs | 37 +++++++++++++++++++++++++++++++++++++ test/stdlib/Array_test.rb | 17 +++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/core/array.rbs b/core/array.rbs index a05741c69..d2e5b963d 100644 --- a/core/array.rbs +++ b/core/array.rbs @@ -1763,6 +1763,43 @@ class Array[unchecked out Elem] < Object | [T] (int index, T default) -> (Elem | T) | [T] (int index) { (int index) -> T } -> (Elem | T) + # + # With no block given, returns a new array containing the elements of `self` at + # the offsets given by `indexes`; each of the `indexes` must be an + # [integer-convertible + # object](rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects): + # + # a = [:foo, :bar, :baz] + # a.fetch_values(3, 1) # => [:baz, :foo] + # a.fetch_values(3.1, 1) # => [:baz, :foo] + # a.fetch_values # => [] + # + # For a negative index, counts backwards from the end of the array: + # + # a.fetch_values([-2, -1]) # [:bar, :baz] + # + # When no block is given, raises an exception if any index is out of range. + # + # With a block given, for each index: + # + # * If the index in in range, uses an element of `self` (as above). + # * Otherwise calls, the block with the index, and uses the block's return + # value. + # + # Example: + # + # a = [:foo, :bar, :baz] + # a.fetch_values(1, 0, 42, 777) {|index| index.to_s} + # # => [:bar, :foo, "42", "777"] + # + # Related: see [Methods for Fetching](rdoc-ref:Array@Methods+for+Fetching). + # + def fetch_values: (*int indexes) -> self + # + # Sets or gets information about the current GC config. + # + # Configuration parameters are GC implementation-specific and may change without + # notice. + # + # This method can be called without parameters to retrieve the current config. + # + # 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. + # + # Valid config keys for Ruby's default GC implementation are: + # + # rgengc_allow_full_mark + # : Controls whether the GC is allowed to run a full mark (young & old + # objects). + # + # When `true`, GC interleaves major and minor collections. This is the + # default. GC will function as intended. + # + # 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. + # + # 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`. + # + def self.config: () -> Hash[Symbol, untyped] + | (Hash[Symbol, untyped]) -> Hash[Symbol, untyped] + # - # TODO: Remove on the 3.4 development start: - # - SPELL_CHECKERS: untyped - NameErrorCheckers: Object VERSION: String From 52eda0615ff4c77be43b44ea38bf13efba9daf07 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Thu, 19 Dec 2024 15:34:15 +0900 Subject: [PATCH 10/18] Add `MatchData#bytebegin` and `MatchData#byteend` --- core/match_data.rbs | 76 +++++++++++++++++++++++++++++++++++ test/stdlib/MatchData_test.rb | 22 ++++++++++ 2 files changed, 98 insertions(+) diff --git a/core/match_data.rbs b/core/match_data.rbs index f343d5b84..8e946074b 100644 --- a/core/match_data.rbs +++ b/core/match_data.rbs @@ -132,6 +132,82 @@ class MatchData # def begin: (capture backref) -> Integer? + # + # Returns the offset (in bytes) of the beginning of the specified match. + # + # When non-negative integer argument `n` is given, returns the offset of the + # beginning of the `n`th match: + # + # m = /(.)(.)(\d+)(\d)/.match("THX1138.") + # # => # + # m[0] # => "HX1138" + # m.bytebegin(0) # => 1 + # m[3] # => "113" + # m.bytebegin(3) # => 3 + # + # m = /(т)(е)(с)/.match('тест') + # # => # + # m[0] # => "тес" + # m.bytebegin(0) # => 0 + # m[3] # => "с" + # m.bytebegin(3) # => 4 + # + # When string or symbol argument `name` is given, returns the offset of the + # beginning for the named match: + # + # m = /(?.)(.)(?.)/.match("hoge") + # # => # + # m[:foo] # => "h" + # m.bytebegin('foo') # => 0 + # m[:bar] # => "g" + # m.bytebegin(:bar) # => 2 + # + # Related: MatchData#byteend, MatchData#byteoffset. + # + def bytebegin: (capture backref) -> Integer? + + # + # Returns the offset (in bytes) of the end of the specified match. + # + # When non-negative integer argument `n` is given, returns the offset of the end + # of the `n`th match: + # + # m = /(.)(.)(\d+)(\d)/.match("THX1138.") + # # => # + # m[0] # => "HX1138" + # m.byteend(0) # => 7 + # m[3] # => "113" + # m.byteend(3) # => 6 + # + # m = /(т)(е)(с)/.match('тест') + # # => # + # m[0] # => "тес" + # m.byteend(0) # => 6 + # m[3] # => "с" + # m.byteend(3) # => 6 + # + # When string or symbol argument `name` is given, returns the offset of the end + # for the named match: + # + # m = /(?.)(.)(?.)/.match("hoge") + # # => # + # m[:foo] # => "h" + # m.byteend('foo') # => 1 + # m[:bar] # => "g" + # m.byteend(:bar) # => 3 + # + # Related: MatchData#bytebegin, MatchData#byteoffset. + # + def byteend: (capture backref) -> Integer? + # + # internal method + # + def self._require: (String feature) -> bool + # # returns main ractor # - def self.main: () -> untyped + def self.main: () -> Ractor + + # + # return true if the current ractor is main ractor + # + def self.main?: () -> boolish # + # get a value from ractor-local storage of current Ractor + # + def self.[]: (Symbol) -> untyped + + # + # set a value in ractor-local storage of current Ractor + # + def self.[]=: (Symbol, untyped) -> untyped + # + # Returns location objects associated with the AST node. The returned array + # contains RubyVM::AbstractSyntaxTree::Location. + # + def locations: () -> Array[Location] + # + # RubyVM::AbstractSyntaxTree::Location instances are created by + # RubyVM::AbstractSyntaxTree#locations. + # + # This class is MRI specific. + # + class Location + # + # The column number in the source code where this AST's text began. + # + def first_column: () -> Integer + + # + # The line number in the source code where this AST's text began. + # + def first_lineno: () -> Integer + + # + # Returns debugging information about this location as a string. + # + def inspect: () -> String + + # + # The line number in the source code where this AST's text ended. + # + def last_lineno: () -> Integer + + # + # The column number in the source code where this AST's text ended. + # + def last_column: () -> Integer + end end # diff --git a/test/stdlib/RubyVM_test.rb b/test/stdlib/RubyVM_test.rb index e3f4fbf9c..71d5f42c2 100644 --- a/test/stdlib/RubyVM_test.rb +++ b/test/stdlib/RubyVM_test.rb @@ -59,6 +59,13 @@ def test_last_column RubyVM::AbstractSyntaxTree.parse("1 + 2"), :last_column end + if RUBY_VERSION >= '3.4' + def test_locations + assert_send_type "() -> ::Array[::RubyVM::AbstractSyntaxTree::Location]", + RubyVM::AbstractSyntaxTree.parse("1 + 2"), :locations + end + end + if RUBY_VERSION >= '3.2' def test_tokens assert_send_type "() -> ::Array[[ ::Integer, ::Symbol, ::String, [ ::Integer, ::Integer, ::Integer, ::Integer ] ]]?", From 44823872ff8b0296ddc42d5c992d0e5642c4c288 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Thu, 19 Dec 2024 15:17:22 +0900 Subject: [PATCH 15/18] Add `String#append_as_bytes` --- core/string.rbs | 24 ++++++++++++++++++++++++ test/stdlib/String_test.rb | 7 +++++++ 2 files changed, 31 insertions(+) diff --git a/core/string.rbs b/core/string.rbs index 0f2d594e3..1df3330e8 100644 --- a/core/string.rbs +++ b/core/string.rbs @@ -939,6 +939,30 @@ class String | [T < _ToStr] (Regexp regexp, MatchData::capture backref, T replacement) -> T | [T < _ToStr] (String substring, T replacement) -> T + # + # Concatenates each object in `objects` into `self` without any encoding + # validation or conversion and returns `self`: + # + # s = 'foo' + # s.append_as_bytes(" \xE2\x82") # => "foo \xE2\x82" + # s.valid_encoding? # => false + # s.append_as_bytes("\xAC 12") + # 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: + # + # s = "" + # s.append_as_bytes(0, 257) # => "\u0000\u0001" + # + # Related: String#<<, String#concat, which do an encoding aware concatenation. + # + def append_as_bytes: (String) -> String + # + # Parses `time` as a dateTime defined by the XML Schema and converts it to a + # Time object. The format is a restricted version of the format defined by ISO + # 8601. + # + # ArgumentError is raised if `time` is not compliant with the format or if the + # Time class cannot represent the specified time. + # + # See #xmlschema for more information on this format. + # + # require 'time' + # + # Time.xmlschema("2011-10-05T22:26:12-04:00") + # #=> 2011-10-05 22:26:12-04:00 + # + # You must require 'time' to use this method. + # + alias iso8601 xmlschema + # + # Returns a string which represents the time as a dateTime defined by XML + # Schema: + # + # CCYY-MM-DDThh:mm:ssTZD + # CCYY-MM-DDThh:mm:ss.sssTZD + # + # where TZD is Z or [+-]hh:mm. + # + # If self is a UTC time, Z is used as TZD. [+-]hh:mm is used otherwise. + # + # `fraction_digits` specifies a number of digits to use for fractional seconds. + # Its default value is 0. + # + # require 'time' + # + # t = Time.now + # t.iso8601 # => "2011-10-05T22:26:12-04:00" + # + # You must require 'time' to use this method. + # + def xmlschema: () -> String + # - # Returns a string which represents the time as a dateTime defined by XML - # Schema: - # - # CCYY-MM-DDThh:mm:ssTZD - # CCYY-MM-DDThh:mm:ss.sssTZD - # - # where TZD is Z or [+-]hh:mm. - # - # If self is a UTC time, Z is used as TZD. [+-]hh:mm is used otherwise. - # - # `fraction_digits` specifies a number of digits to use for fractional seconds. - # Its default value is 0. - # - # require 'time' - # - # t = Time.now - # t.iso8601 # => "2011-10-05T22:26:12-04:00" - # - # You must require 'time' to use this method. - # - def xmlschema: (?Integer fraction_digits) -> String - - # - # Parses `time` as a dateTime defined by the XML Schema and converts it to a - # Time object. The format is a restricted version of the format defined by ISO - # 8601. - # - # ArgumentError is raised if `time` is not compliant with the format or if the - # Time class cannot represent the specified time. - # - # See #xmlschema for more information on this format. - # - # require 'time' - # - # Time.xmlschema("2011-10-05T22:26:12-04:00") - # #=> 2011-10-05 22:26:12-04:00 - # - # You must require 'time' to use this method. - # - alias iso8601 xmlschema end diff --git a/test/stdlib/TimeExtension_test.rb b/test/stdlib/TimeExtension_test.rb index 4eabb593b..590f51724 100644 --- a/test/stdlib/TimeExtension_test.rb +++ b/test/stdlib/TimeExtension_test.rb @@ -102,18 +102,4 @@ def test_httpdate assert_send_type "() -> String", Time.now, :httpdate end - - def test_xmlschema - assert_send_type "() -> String", - Time.now, :xmlschema - assert_send_type "(Integer) -> String", - Time.now, :xmlschema, 3 - end - - def test_iso8601 - assert_send_type "() -> String", - Time.now, :iso8601 - assert_send_type "(Integer) -> String", - Time.now, :iso8601, 3 - end end diff --git a/test/stdlib/Time_test.rb b/test/stdlib/Time_test.rb index d235676c8..27f24c0ea 100644 --- a/test/stdlib/Time_test.rb +++ b/test/stdlib/Time_test.rb @@ -354,6 +354,13 @@ def test_to_a Time.now(in: 0), :to_a end + def test_xmlschema + if_ruby("3.4.0"...) do + assert_send_type "() -> String", + Time.now, :xmlschema + end + end + def test_zone assert_send_type "() -> String", Time.now, :zone From 53c8e4ed1b80e23d37fa066623f49adab730cb79 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Thu, 19 Dec 2024 15:23:32 +0900 Subject: [PATCH 17/18] Add `Warning.categories` --- core/warning.rbs | 8 ++++++++ test/stdlib/Warning_test.rb | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/core/warning.rbs b/core/warning.rbs index d5fcddfe3..5117dbf42 100644 --- a/core/warning.rbs +++ b/core/warning.rbs @@ -66,6 +66,14 @@ module Warning # def self.[]=: [T] (category, T flag) -> T + # + # Returns a list of the supported category symbols. + # + def self.categories: () -> Array[Symbol] + #