From 8852cd9200c114ce84607d35d57a158bd5996921 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 06:10:20 +0000 Subject: [PATCH 001/101] Bump json-schema from 4.0.0 to 4.1.1 Bumps [json-schema](https://github.com/voxpupuli/json-schema) from 4.0.0 to 4.1.1. - [Changelog](https://github.com/voxpupuli/json-schema/blob/master/CHANGELOG.md) - [Commits](https://github.com/voxpupuli/json-schema/compare/v4.0.0...v4.1.1) --- updated-dependencies: - dependency-name: json-schema dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 371095ad21..0c8f6c6bc2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,7 +11,7 @@ PATH GEM remote: https://rubygems.org/ specs: - addressable (2.8.4) + addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) ast (2.4.2) base64 (0.1.1) @@ -24,7 +24,7 @@ GEM rainbow (>= 3.0, < 4.0) strong_json (>= 1.1, < 2.2) json (2.6.3) - json-schema (4.0.0) + json-schema (4.1.1) addressable (>= 2.8) language_server-protocol (3.17.0.3) marcel (1.0.2) @@ -36,7 +36,7 @@ GEM power_assert (2.0.3) psych (4.0.6) stringio - public_suffix (5.0.1) + public_suffix (5.0.3) racc (1.7.1) rainbow (3.1.1) rake (13.0.6) From 7768d389548fccec13180b2b8ccdf05480001563 Mon Sep 17 00:00:00 2001 From: SamW Date: Wed, 6 Sep 2023 19:48:26 -0500 Subject: [PATCH 002/101] Update Marshal --- core/marshal.rbs | 38 +++++++----- test/stdlib/Marshal_test.rb | 120 ++++++++++++++++++++++++++---------- test/stdlib/test_helper.rb | 12 ++++ 3 files changed, 123 insertions(+), 47 deletions(-) diff --git a/core/marshal.rbs b/core/marshal.rbs index 6e162d1e97..552def4796 100644 --- a/core/marshal.rbs +++ b/core/marshal.rbs @@ -108,6 +108,16 @@ # which is Marshal.loaded in _load for complex objects. # module Marshal + # + # major version + # + MAJOR_VERSION: Integer + + # + # minor version + # + MINOR_VERSION: Integer + # -# major version -# -Marshal::MAJOR_VERSION: Integer - -# -# minor version -# -Marshal::MINOR_VERSION: Integer diff --git a/test/stdlib/Marshal_test.rb b/test/stdlib/Marshal_test.rb index d45dbe515b..bfd626f109 100644 --- a/test/stdlib/Marshal_test.rb +++ b/test/stdlib/Marshal_test.rb @@ -6,51 +6,105 @@ class MarshalSingletonTest < Test::Unit::TestCase include TypeAssertions testing "singleton(::Marshal)" + def test_MAJOR_VERSION + assert_const_type 'Integer', 'Marshal::MAJOR_VERSION' + end + + def test_MINOR_VERSION + assert_const_type 'Integer', 'Marshal::MINOR_VERSION' + end + def test_dump - assert_send_type "(::String) -> ::String", - Marshal, :dump, "" + obj = Object.new - assert_send_type "(::String, ::Integer) -> ::String", - Marshal, :dump, "", 3 + assert_send_type '(untyped) -> String', + Marshal, :dump, obj + assert_send_type '(untyped, Integer) -> String', + Marshal, :dump, obj, 123 - io = (Pathname(Dir.mktmpdir) + "foo").open("w") + writer = Writer.new + assert_send_type '(untyped, Writer) -> Writer', + Marshal, :dump, obj, writer - assert_send_type "(::String, ::File) -> ::File", - Marshal, :dump, "", io + with_int.chain([nil]).each do |limit| + assert_send_type '(untyped, Writer, int?) -> Writer', + Marshal, :dump, obj, writer, limit + end end - def test_load - dump = Marshal.dump([1,2,3]) + def with_source(src = Marshal.dump(Object.new)) + with_string src do |string| + def string.reset!; end + yield string + end + + src = src.chars + source = Struct.new(:source).new(src.dup) + source.define_singleton_method(:reset!) do + self.source = src.dup + end + + # String, String + def source.getbyte; source.shift end + def source.read(x) source.shift(x).join end + yield source + + # int, string + source.reset! + def source.getbyte; ToInt.new(source.shift.ord) end + def source.read(x) ToStr.new(source.shift(x).join) end + yield source + end - assert_send_type( - "(::String) -> ::Array[::Integer]", - Marshal, :load, dump - ) + def test_load(meth = :load) + result_proc = Object.new + def result_proc.call(loaded) 1r end - assert_send_type( - "(::String, freeze: bool) -> ::Array[::Integer]", - Marshal, :load, dump, freeze: true - ) - assert_send_type( - "(::String, freeze: Symbol) -> ::Array[::Integer]", - Marshal, :load, dump, freeze: :true - ) + with_source do |source| + assert_send_type '(string | Marshal::_Source) -> untyped', + Marshal, meth, source + source.reset! - assert_send_type( - "(::String, ^(untyped) -> void) -> ::Integer", - Marshal, :load, dump, -> (_x) { 123 } - ) + assert_send_type '(string | Marshal::_Source, Marshal::_Proc[Rational]) -> Rational', + Marshal, meth, source, result_proc + source.reset! - name = Pathname(Dir.mktmpdir) + "foo" + [nil, :yep, true, "hello"].each do |freeze| + assert_send_type '(string | Marshal::_Source, freeze: boolish) -> untyped', + Marshal, meth, source, freeze: freeze + source.reset! - File.open(name, "w") do |io| - Marshal.dump([1,2,3], io) + assert_send_type '(string | Marshal::_Source, Marshal::_Proc[Rational], freeze: boolish) -> Rational', + Marshal, meth, source, result_proc, freeze: freeze + source.reset! + end end - File.open(name) do |io| - assert_send_type( - "(IO) -> ::Array[::Integer]", - Marshal, :load, io - ) + end + + def test_restore + test_load :restore + end +end + +class MarshalIncludeTest < Test::Unit::TestCase + include TypeAssertions + testing "::Marshal" + + def test_dump + obj = Object.new + + assert_send_type '(untyped) -> String', + Marshal, :dump, obj + assert_send_type '(untyped, Integer) -> String', + Marshal, :dump, obj, 123 + + writer = Writer.new + assert_send_type '(untyped, Writer) -> Writer', + Marshal, :dump, obj, writer + + with_int.chain([nil]).each do |limit| + assert_send_type '(untyped, Writer, int?) -> Writer', + Marshal, :dump, obj, writer, limit end end end diff --git a/test/stdlib/test_helper.rb b/test/stdlib/test_helper.rb index 28db502245..3d544a16f2 100644 --- a/test/stdlib/test_helper.rb +++ b/test/stdlib/test_helper.rb @@ -625,6 +625,18 @@ def each(&block) end end +class Writer + attr_reader :buffer + + def initialize + @buffer = "" + end + + def write(*vals) + @buffer.concat vals.join + end +end + class ToJson end From cce9edc2e2261536d805de1a98944c9fbb5642e5 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 20 Sep 2023 03:10:29 +0900 Subject: [PATCH 003/101] stdlib: Add YAML.unsafe_load --- stdlib/yaml/0/yaml.rbs | 39 +++++++++++++++++++++++++++++++++++++++ test/stdlib/yaml_test.rb | 16 ++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/stdlib/yaml/0/yaml.rbs b/stdlib/yaml/0/yaml.rbs index 473af7ba42..dd9ab951fa 100644 --- a/stdlib/yaml/0/yaml.rbs +++ b/stdlib/yaml/0/yaml.rbs @@ -196,4 +196,43 @@ module YAML # %a{annotate:rdoc:copy:Psych.safe_load} def self.safe_load: (String yaml, ?permitted_classes: Array[Class], ?permitted_symbols: Array[Symbol], ?aliases: bool, ?filename: String | _ToStr | _ToS?, ?fallback: untyped, ?symbolize_names: bool, ?freeze: bool) -> untyped + + # + # Load `yaml` in to a Ruby data structure. If multiple documents are provided, + # the object contained in the first document will be returned. `filename` will + # be used in the exception message if any exception is raised while parsing. If + # `yaml` is empty, it returns the specified `fallback` return value, which + # defaults to `false`. + # + # Raises a Psych::SyntaxError when a YAML syntax error is detected. + # + # Example: + # + # Psych.unsafe_load("--- a") # => 'a' + # Psych.unsafe_load("---\n - a\n - b") # => ['a', 'b'] + # + # begin + # Psych.unsafe_load("--- `", filename: "file.txt") + # rescue Psych::SyntaxError => ex + # ex.file # => 'file.txt' + # ex.message # => "(file.txt): found character that cannot start any token" + # end + # + # When the optional `symbolize_names` keyword argument is set to a true value, + # returns symbols for keys in Hash objects (default: strings). + # + # Psych.unsafe_load("---\n foo: bar") # => {"foo"=>"bar"} + # Psych.unsafe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"} + # + # Raises a TypeError when `yaml` parameter is NilClass + # + # NOTE: This method *should not* be used to parse untrusted documents, such as + # YAML documents that are supplied via user input. Instead, please use the load + # method or the safe_load method. + # + %a{annotate:rdoc:copy:Psych.unsafe_load} + def self.unsafe_load: (String yaml, ?filename: String | _ToStr | _ToS?, ?fallback: untyped, ?symbolize_names: bool, ?freeze: bool, ?strict_integer: bool) -> untyped end diff --git a/test/stdlib/yaml_test.rb b/test/stdlib/yaml_test.rb index 491d6cd46e..0084bd18a7 100644 --- a/test/stdlib/yaml_test.rb +++ b/test/stdlib/yaml_test.rb @@ -59,6 +59,22 @@ def test_safe_load ) end + def test_unsafe_load + assert_send_type( + "(::String) -> untyped", + YAML, :unsafe_load, <<-YAML +foo: 123 + YAML + ) + + assert_send_type( + "(::String, filename: ::_ToS, fallback: ::Symbol, symbolize_names: bool, freeze: bool, strict_integer: bool) -> untyped", + YAML, :unsafe_load, <<-YAML, filename: ToS.new("foo.yaml"), fallback: :foo, symbolize_names: true, freeze: false, strict_integer: false +foo: 123 + YAML + ) + end + def test_dump assert_send_type( "(::Array[::Integer]) -> ::String", From 26dc3081550e6b7936951efa71bef56594908fc1 Mon Sep 17 00:00:00 2001 From: SamW Date: Tue, 19 Sep 2023 13:50:49 -0700 Subject: [PATCH 004/101] Update Exception --- core/exception.rbs | 22 ++--- test/stdlib/Exception_test.rb | 162 +++++++++++++++++++++++++--------- 2 files changed, 131 insertions(+), 53 deletions(-) diff --git a/core/exception.rbs b/core/exception.rbs index 854d7e30af..45c9df4d1b 100644 --- a/core/exception.rbs +++ b/core/exception.rbs @@ -105,7 +105,7 @@ # * SystemStackError # * fatal # -class Exception < Object +class Exception # # Construct a new Exception object, optionally passing in a message. # - def initialize: (?String arg0) -> void + def initialize: (?string | _ToS message) -> self # # ARGV contains the command line arguments used to run ruby. # # A library like OptionParser can be used to process command-line arguments. # -::ARGV: Array[String] +ARGV: Array[String] -::CROSS_COMPILING: NilClass +CROSS_COMPILING: true? # # DATA is a File that contains the data section of the executed file. To create @@ -27,70 +27,70 @@ # $ ruby t.rb # hello world! # -::DATA: File +DATA: File # # The copyright string for ruby # -::RUBY_COPYRIGHT: String +RUBY_COPYRIGHT: String # # The full ruby version string, like `ruby -v` prints # -::RUBY_DESCRIPTION: String +RUBY_DESCRIPTION: String # # The engine or interpreter this ruby uses. # -::RUBY_ENGINE: String +RUBY_ENGINE: String # # The version of the engine or interpreter this ruby uses. # -::RUBY_ENGINE_VERSION: String +RUBY_ENGINE_VERSION: String # # The patchlevel for this ruby. If this is a development build of ruby the # patchlevel will be -1 # -::RUBY_PATCHLEVEL: Integer +RUBY_PATCHLEVEL: Integer # # The platform for this ruby # -::RUBY_PLATFORM: String +RUBY_PLATFORM: String # # The date this ruby was released # -::RUBY_RELEASE_DATE: String +RUBY_RELEASE_DATE: String # # The GIT commit hash for this ruby. # -::RUBY_REVISION: Integer +RUBY_REVISION: String # # The running version of ruby # -::RUBY_VERSION: String +RUBY_VERSION: String # # Holds the original stderr # -::STDERR: IO +STDERR: IO # # Holds the original stdin # -::STDIN: IO +STDIN: IO # # Holds the original stdout # -::STDOUT: IO +STDOUT: IO # # The Binding of the top level scope # -::TOPLEVEL_BINDING: Binding +TOPLEVEL_BINDING: Binding diff --git a/test/stdlib/constants_test.rb b/test/stdlib/constants_test.rb new file mode 100644 index 0000000000..0792d9de8d --- /dev/null +++ b/test/stdlib/constants_test.rb @@ -0,0 +1,104 @@ +require_relative 'test_helper' + +# initialize temporary class +module RBS + module Unnamed + ARGFClass = ARGF.class + end +end + +class ConstantsTest < Test::Unit::TestCase + include TypeAssertions + + testing 'singleton(Object)' + + def test_ARGF + assert_const_type 'RBS::Unnamed::ARGFClass', + 'ARGF' + end + + def test_ARGV + assert_const_type 'Array[String]', + 'ARGV' + end + + def test_CROSS_COMPILING + # There's no way to test both variants of `CROSS_COMPILING`. + assert_const_type 'true?', + 'CROSS_COMPILING' + end + + def test_DATA + omit_unless defined?(DATA) # If you run this file from rake `DATA` won't be visible. + assert_const_type 'File', + 'DATA' + end + + def test_RUBY_COPYRIGHT + assert_const_type 'String', + 'RUBY_COPYRIGHT' + end + + def test_RUBY_DESCRIPTION + assert_const_type 'String', + 'RUBY_DESCRIPTION' + end + + def test_RUBY_ENGINE + assert_const_type 'String', + 'RUBY_ENGINE' + end + + def test_RUBY_ENGINE_VERSION + assert_const_type 'String', + 'RUBY_ENGINE_VERSION' + end + + def test_RUBY_PATCHLEVEL + assert_const_type 'Integer', + 'RUBY_PATCHLEVEL' + end + + def test_RUBY_PLATFORM + assert_const_type 'String', + 'RUBY_PLATFORM' + end + + def test_RUBY_RELEASE_DATE + assert_const_type 'String', + 'RUBY_RELEASE_DATE' + end + + def test_RUBY_REVISION + assert_const_type 'String', + 'RUBY_REVISION' + end + + def test_RUBY_VERSION + assert_const_type 'String', + 'RUBY_VERSION' + end + + def test_STDERR + assert_const_type 'IO', + 'STDERR' + end + + def test_STDIN + assert_const_type 'IO', + 'STDIN' + end + + def test_STDOUT + assert_const_type 'IO', + 'STDOUT' + end + + def test_TOPLEVEL_BINDING + assert_const_type 'Binding', + 'TOPLEVEL_BINDING' + end +end + +__END__ +This `__END__` is here so `DATA` is visible in the `test_DATA` method. From 754dc0e80ad8b6b39d509b8de18354d4c529f1e4 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Wed, 20 Sep 2023 12:52:56 +0900 Subject: [PATCH 006/101] Add `assert_type` helper --- test/stdlib/test_helper.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/stdlib/test_helper.rb b/test/stdlib/test_helper.rb index 28db502245..1c56c0b79b 100644 --- a/test/stdlib/test_helper.rb +++ b/test/stdlib/test_helper.rb @@ -502,6 +502,27 @@ def assert_const_type(type, constant_name) assert typecheck.value(constant, definition_type), "`#{constant_name}` (#{constant.inspect}) must be compatible with RBS type definition `#{definition_type}`" end + + def assert_type(type, value) + typecheck = RBS::Test::TypeCheck.new( + self_class: value.class, + instance_class: "No `instance` class allowed", + class_class: "No `class` class allowed", + builder: builder, + sample_size: 100, + unchecked_classes: [] + ) + + type = + case type + when String + RBS::Parser.parse_type(type, variables: []) + else + type + end + + assert typecheck.value(value, type), "`#{value.inspect}` must be compatible with given type `#{type}`" + end end class ToIO From 3861a9d7ca8296c172d28da4d7f34bb6b1cdcb98 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Wed, 20 Sep 2023 12:53:22 +0900 Subject: [PATCH 007/101] Fix `assert_const_type` It may be `RBS::Types::t`, not `RBS::MethodType`. --- test/stdlib/test_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/stdlib/test_helper.rb b/test/stdlib/test_helper.rb index 1c56c0b79b..75ed683bf5 100644 --- a/test/stdlib/test_helper.rb +++ b/test/stdlib/test_helper.rb @@ -480,7 +480,7 @@ def assert_const_type(type, constant_name) case type when String RBS::Parser.parse_type(type, variables: []) - when RBS::MethodType + else type end From 9971d510e05ee42827a155958aa409c1fbf39ab9 Mon Sep 17 00:00:00 2001 From: SamW Date: Tue, 19 Sep 2023 21:52:05 -0700 Subject: [PATCH 008/101] Updated Math --- core/math.rbs | 110 ++++++------ test/stdlib/Math_test.rb | 357 +++++++++++++++++++++++++++++++++------ 2 files changed, 358 insertions(+), 109 deletions(-) diff --git a/core/math.rbs b/core/math.rbs index 5ac532eccb..52ce78ea1f 100644 --- a/core/math.rbs +++ b/core/math.rbs @@ -127,6 +127,37 @@ # * ::hypot: Returns `sqrt(a**2 + b**2)` for the given `a` and `b`. # module Math + # + # Definition of the mathematical constant E for Euler's number (e) as a Float + # number. + # + E: Float + + # + # Definition of the mathematical constant PI as a Float number. + # + PI: Float + + # + # Raised when a mathematical function is evaluated outside of its domain of + # definition. + # + # For example, since `cos` returns values in the range -1..1, its inverse + # function `acos` is only defined on that interval: + # + # Math.acos(42) + # + # *produces:* + # + # Math::DomainError: Numerical argument is out of domain - "acos" + # + class DomainError < StandardError + end + + # A type that's passable to `Math` functions: A `Numeric` type that defines `.to_f`. + # + type double = Numeric & _ToF + # -# Definition of the mathematical constant E for Euler's number (e) as a Float -# number. -# -Math::E: Float - -# -# Definition of the mathematical constant PI as a Float number. -# -Math::PI: Float - -# -# Raised when a mathematical function is evaluated outside of its domain of -# definition. -# -# For example, since `cos` returns values in the range -1..1, its inverse -# function `acos` is only defined on that interval: -# -# Math.acos(42) -# -# *produces:* -# -# Math::DomainError: Numerical argument is out of domain - "acos" -# -class Math::DomainError < StandardError + def self.tanh: (double x) -> Float end diff --git a/test/stdlib/Math_test.rb b/test/stdlib/Math_test.rb index 24b2be8606..92a0c0ac60 100644 --- a/test/stdlib/Math_test.rb +++ b/test/stdlib/Math_test.rb @@ -1,62 +1,307 @@ -require_relative "test_helper" - -require "bigdecimal" - -class MathTest < StdlibTest - target Math - - %w( - acos - acosh - asin - asinh - atan - atanh - cbrt - cos - cosh - erf - erfc - exp - gamma - lgamma - log10 - log2 - sin - sinh - sqrt - tan - tanh - ).each do |method_name| - define_method("test_#{method_name}") do - Math.public_send(method_name, 1) - Math.public_send(method_name, 1.0) - Math.public_send(method_name, 1r) - Math.public_send(method_name, BigDecimal("1")) - end - end - - %w( - atan2 - hypot - ldexp - ).each do |method_name| - define_method("test_#{method_name}") do - Math.public_send(method_name, 1, 1.0) - Math.public_send(method_name, 1.0, 1r) - Math.public_send(method_name, 1r, BigDecimal("1")) - Math.public_send(method_name, BigDecimal("1"), 1) +require_relative 'test_helper' + +class MathSingletonTest < Test::Unit::TestCase + include TypeAssertions + + testing 'singleton(::Math)' + + def test_E + assert_const_type 'Float', 'Math::E' + end + + def test_PI + assert_const_type 'Float', 'Math::PI' + end + + def test_DomainError + assert_const_type 'Class', 'Math::DomainError' + end + + class Double < Numeric + def initialize(num) @num = num end + def to_f; @num end + end + + def with_double(num) + yield num + yield Double.new(num) + end + + def test_acos + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :acos, double end + + refute_send_type '(_ToF) -> Float', + Math, :acos, ToF.new(0.0) + end + + def test_acosh + with_double 2.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :acosh, double + end + + refute_send_type '(_ToF) -> Float', + Math, :acosh, ToF.new(2.0) + end + + def test_asin + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :asin, double + end + + refute_send_type '(_ToF) -> Float', + Math, :asin, ToF.new(0.0) + end + + def test_asinh + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :asinh, double + end + + refute_send_type '(_ToF) -> Float', + Math, :asinh, ToF.new(0.0) + end + + def test_atan + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :atan, double + end + + refute_send_type '(_ToF) -> Float', + Math, :atan, ToF.new(0.0) + end + + def test_atan2 + with_double 0.0 do |y| + with_double 0.0 do |x| + assert_send_type '(Math::double, Math::double) -> Float', + Math, :atan2, y, x + end + end + + refute_send_type '(_ToF, _ToF) -> Float', + Math, :atan2, ToF.new(0.0), ToF.new(0.0) + end + + def test_atanh + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :atanh, double + end + + refute_send_type '(_ToF) -> Float', + Math, :atanh, ToF.new(0.0) + end + + def test_cbrt + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :cbrt, double + end + + refute_send_type '(_ToF) -> Float', + Math, :cbrt, ToF.new(0.0) + end + + def test_cos + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :cos, double + end + + refute_send_type '(_ToF) -> Float', + Math, :cos, ToF.new(0.0) + end + + def test_cosh + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :cosh, double + end + + refute_send_type '(_ToF) -> Float', + Math, :cosh, ToF.new(0.0) + end + + def test_erf + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :erf, double + end + + refute_send_type '(_ToF) -> Float', + Math, :erf, ToF.new(0.0) + end + + def test_erfc + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :erfc, double + end + + refute_send_type '(_ToF) -> Float', + Math, :erfc, ToF.new(0.0) + end + + def test_exp + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :exp, double + end + + refute_send_type '(_ToF) -> Float', + Math, :exp, ToF.new(0.0) + end + + def test_frexp + with_double 0.0 do |double| + assert_send_type '(Math::double) -> [Float, Integer]', + Math, :frexp, double + end + + refute_send_type '(_ToF) -> [Float, Integer]', + Math, :frexp, ToF.new(0.0) + end + + def test_gamma + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :gamma, double + end + + refute_send_type '(_ToF) -> Float', + Math, :gamma, ToF.new(0.0) + end + + def test_hypot + with_double 3.0 do |a| + with_double 4.0 do |b| + assert_send_type '(Math::double, Math::double) -> Float', + Math, :hypot, a, b + end + end + + refute_send_type '(_ToF, _ToF) -> Float', + Math, :hypot, ToF.new(3.0), ToF.new(4.0) + end + + def test_ldexp + with_double 0.0 do |double| + with_int 2 do |int| + assert_send_type '(Math::double, int) -> Float', + Math, :ldexp, double, int + end + end + + refute_send_type '(_ToF, Integer) -> Float', + Math, :ldexp, ToF.new(0.0), 2 + end + + def test_lgamma + with_double 0.0 do |double| + assert_send_type '(Math::double) -> [Float, 1]', + Math, :lgamma, double + end + + with_double -0.3 do |double| + assert_send_type '(Math::double) -> [Float, -1]', + Math, :lgamma, double + end + + refute_send_type '(_ToF) -> [Float, Integer]', + Math, :lgamma, ToF.new(0.0) end def test_log - Math.log(1) - Math.log(1.0) - Math.log(1r) - Math.log(BigDecimal("1")) - Math.log(1, 1.0) - Math.log(1.0, 1r) - Math.log(1r, BigDecimal("1")) - Math.log(BigDecimal("1"), 1) + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :log, double + + with_double 0.0 do |base| + assert_send_type '(Math::double, Math::double) -> Float', + Math, :log, double, base + end + end + + refute_send_type '(_ToF) -> Float', + Math, :log, ToF.new(0.0) + refute_send_type '(_ToF, _ToF) -> Float', + Math, :log, ToF.new(0.0), ToF.new(0.0) + end + + def test_log10 + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :log10, double + end + + refute_send_type '(_ToF) -> Float', + Math, :log10, ToF.new(0.0) + end + + def test_log2 + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :log2, double + end + + refute_send_type '(_ToF) -> Float', + Math, :log2, ToF.new(0.0) + end + + def test_sin + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :sin, double + end + + refute_send_type '(_ToF) -> Float', + Math, :sin, ToF.new(0.0) + end + + def test_sinh + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :sinh, double + end + + refute_send_type '(_ToF) -> Float', + Math, :sinh, ToF.new(0.0) + end + + def test_sqrt + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :sqrt, double + end + + refute_send_type '(_ToF) -> Float', + Math, :sqrt, ToF.new(0.0) + end + + def test_tan + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :tan, double + end + + refute_send_type '(_ToF) -> Float', + Math, :tan, ToF.new(0.0) + end + + def test_tanh + with_double 0.0 do |double| + assert_send_type '(Math::double) -> Float', + Math, :tanh, double + end + + refute_send_type '(_ToF) -> Float', + Math, :tanh, ToF.new(0.0) end end From 674edf6053c6322f0ba8b0942486eba64ed99cba Mon Sep 17 00:00:00 2001 From: SamW Date: Wed, 20 Sep 2023 11:10:38 -0700 Subject: [PATCH 009/101] Update RbConfig --- core/rb_config.rbs | 107 +++++++++++++++++++++-------------- test/stdlib/RbConfig_test.rb | 67 ++++++++++++++++++---- 2 files changed, 121 insertions(+), 53 deletions(-) diff --git a/core/rb_config.rbs b/core/rb_config.rbs index 2717b1620e..ce95ab2878 100644 --- a/core/rb_config.rbs +++ b/core/rb_config.rbs @@ -7,6 +7,49 @@ # built. # module RbConfig + # + # The hash configurations stored. + # + CONFIG: Hash[String, String] + + # + # DESTDIR on make install. + # + DESTDIR: String + + # + # Almost same with CONFIG. MAKEFILE_CONFIG has other variable reference like + # below. + # + # MAKEFILE_CONFIG["bindir"] = "$(exec_prefix)/bin" + # + # The values of this constant is used for creating Makefile. + # + # require 'rbconfig' + # + # print <<-END_OF_MAKEFILE + # prefix = #{RbConfig::MAKEFILE_CONFIG['prefix']} + # exec_prefix = #{RbConfig::MAKEFILE_CONFIG['exec_prefix']} + # bindir = #{RbConfig::MAKEFILE_CONFIG['bindir']} + # END_OF_MAKEFILE + # + # => prefix = /usr/local + # exec_prefix = $(prefix) + # bindir = $(exec_prefix)/bin MAKEFILE_CONFIG = {} + # + # RbConfig.expand is used for resolving references like above in rbconfig. + # + # require 'rbconfig' + # p RbConfig.expand(RbConfig::MAKEFILE_CONFIG["bindir"]) + # # => "/usr/local/bin" + # + MAKEFILE_CONFIG: Hash[String, String] + + # + # Ruby installed directory. + # + TOPDIR: String + # + # updates `key+ in `mkconf` with `val`, and all values depending on + # the `key` in `mkconf`. + # + # RbConfig::MAKEFILE_CONFIG.values_at("CC", "LDSHARED") # => ["gcc", "$(CC) -shared"] + # RbConfig::CONFIG.values_at("CC", "LDSHARED") # => ["gcc", "gcc -shared"] + # RbConfig.fire_update!("CC", "gcc-8") # => ["CC", "LDSHARED"] + # RbConfig::MAKEFILE_CONFIG.values_at("CC", "LDSHARED") # => ["gcc-8", "$(CC) -shared"] + # RbConfig::CONFIG.values_at("CC", "LDSHARED") # => ["gcc-8", "gcc-8 -shared"] + # + # returns updated keys list, or `nil` if nothing changed. def self.fire_update!: (String key, String val, ?Hash[String, String] mkconf, ?Hash[String, String] conf) -> Array[String]? + # + # + # returns the absolute pathname of the ruby command. def self.ruby: () -> String end - -# -# The hash configurations stored. -# -RbConfig::CONFIG: Hash[String, String] - -# -# DESTDIR on make install. -# -RbConfig::DESTDIR: String - -# -# Almost same with CONFIG. MAKEFILE_CONFIG has other variable reference like -# below. -# -# MAKEFILE_CONFIG["bindir"] = "$(exec_prefix)/bin" -# -# The values of this constant is used for creating Makefile. -# -# require 'rbconfig' -# -# print <<-END_OF_MAKEFILE -# prefix = #{RbConfig::MAKEFILE_CONFIG['prefix']} -# exec_prefix = #{RbConfig::MAKEFILE_CONFIG['exec_prefix']} -# bindir = #{RbConfig::MAKEFILE_CONFIG['bindir']} -# END_OF_MAKEFILE -# -# => prefix = /usr/local -# exec_prefix = $(prefix) -# bindir = $(exec_prefix)/bin MAKEFILE_CONFIG = {} -# -# RbConfig.expand is used for resolving references like above in rbconfig. -# -# require 'rbconfig' -# p RbConfig.expand(RbConfig::MAKEFILE_CONFIG["bindir"]) -# # => "/usr/local/bin" -# -RbConfig::MAKEFILE_CONFIG: Hash[String, String] - -# -# Ruby installed directory. -# -RbConfig::TOPDIR: String diff --git a/test/stdlib/RbConfig_test.rb b/test/stdlib/RbConfig_test.rb index ae94402213..65bb5e0c39 100644 --- a/test/stdlib/RbConfig_test.rb +++ b/test/stdlib/RbConfig_test.rb @@ -1,21 +1,68 @@ -require_relative "test_helper" +require_relative 'test_helper' -class RbConfigTest < StdlibTest - target RbConfig +class RbConfigSingletonTest < Test::Unit::TestCase + include TypeAssertions + + testing 'singleton(::RbConfig)' + + def test_CONFIG + assert_const_type 'Hash[String, String]', + 'RbConfig::CONFIG' + end + + def test_DESTDIR + assert_const_type 'String', + 'RbConfig::DESTDIR' + end + + def test_MAKEFILE_CONFIG + assert_const_type 'Hash[String, String]', + 'RbConfig::MAKEFILE_CONFIG' + end + + def test_TOPDIR + assert_const_type 'String', + 'RbConfig::TOPDIR' + end def test_expand - RbConfig.expand("/home/userName/.rbenv/versions/2.7.0/bin") - RbConfig.expand("/home/userName/.rbenv/versions/2.7.0/bin", "UNICODE_VERSION"=>"12.1.0") + assert_send_type '(String) -> String', + RbConfig, :expand, 'hello/world' + + assert_send_type '(String, Hash[String, String]) -> String', + RbConfig, :expand, 'hello/world', 'a' => 'b' end def test_fire_update! - # Add test on nothing changed - RbConfig.fire_update!("CC", "gcc-8") - RbConfig.fire_update!("CC", "gcc-8", "UNICODE_VERSION"=>"12.1.0") - RbConfig.fire_update!("CC", "gcc-8", "UNICODE_VERSION"=>"12.1.0", "PATH_SEPARATOR"=>":") + orig_makefile_config = RbConfig::MAKEFILE_CONFIG.clone + orig_config = RbConfig::CONFIG.clone + + key, val = RbConfig::MAKEFILE_CONFIG.to_a.first + + # Note: we use `val += '1'` instead of `val.concat '1'`, as `val.concat` would leave the updated + # key in the config hash, and so you couldn't update it. + + assert_send_type '(String, String) -> nil', + RbConfig, :fire_update!, key, val + assert_send_type '(String, String) -> Array[String]', + RbConfig, :fire_update!, key, (val += '1') + + assert_send_type '(String, String, Hash[String, String]) -> nil', + RbConfig, :fire_update!, key, val, RbConfig::MAKEFILE_CONFIG + assert_send_type '(String, String, Hash[String, String]) -> Array[String]', + RbConfig, :fire_update!, key, (val += '1'), RbConfig::MAKEFILE_CONFIG + + assert_send_type '(String, String, Hash[String, String], Hash[String, String]) -> nil', + RbConfig, :fire_update!, key, val, RbConfig::MAKEFILE_CONFIG, RbConfig::CONFIG + assert_send_type '(String, String, Hash[String, String], Hash[String, String]) -> Array[String]', + RbConfig, :fire_update!, key, (val += '1'), RbConfig::MAKEFILE_CONFIG, RbConfig::CONFIG + ensure + RbConfig::MAKEFILE_CONFIG.replace orig_makefile_config + RbConfig::CONFIG.replace orig_config end def test_ruby - RbConfig.ruby + assert_send_type '() -> String', + RbConfig, :ruby end end From 17ea97362d06df144c6d50e03af963e8adcf9da9 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 20 Sep 2023 00:35:51 +0900 Subject: [PATCH 010/101] stdlib: Add psych module (rename yaml to psych) According to the implementation of CRuby, rename the definition of the YAML module to Psych module. --- stdlib/{yaml => psych}/0/dbm.rbs | 6 +- stdlib/{yaml => psych}/0/manifest.yaml | 0 stdlib/{yaml/0/yaml.rbs => psych/0/psych.rbs} | 2 +- stdlib/{yaml => psych}/0/store.rbs | 4 +- test/rbs/collection/sources/stdlib_test.rb | 2 +- test/rbs/environment_loader_test.rb | 4 +- test/stdlib/psych_test.rb | 78 +++++++++++++++++++ 7 files changed, 87 insertions(+), 9 deletions(-) rename stdlib/{yaml => psych}/0/dbm.rbs (98%) rename stdlib/{yaml => psych}/0/manifest.yaml (100%) rename stdlib/{yaml/0/yaml.rbs => psych/0/psych.rbs} (99%) rename stdlib/{yaml => psych}/0/store.rbs (95%) create mode 100644 test/stdlib/psych_test.rb diff --git a/stdlib/yaml/0/dbm.rbs b/stdlib/psych/0/dbm.rbs similarity index 98% rename from stdlib/yaml/0/dbm.rbs rename to stdlib/psych/0/dbm.rbs index f4bdae5a7b..db277ff97f 100644 --- a/stdlib/yaml/0/dbm.rbs +++ b/stdlib/psych/0/dbm.rbs @@ -1,5 +1,5 @@ %a{annotate:rdoc:skip} -module YAML +module Psych # # YAML + DBM = YDBM # @@ -169,7 +169,7 @@ module YAML # object. Takes any object which implements the each_pair method, including Hash # and DBM objects. # - def replace: (Hash[untyped, untyped] | DBM hsh) -> YAML::DBM + def replace: (Hash[untyped, untyped] | DBM hsh) -> Psych::DBM # -# YAML Ain't Markup Language +# +# # Overview # -# This module provides a Ruby interface for data serialization in YAML format. +# Psych is a YAML parser and emitter. Psych leverages libyaml [Home page: +# https://pyyaml.org/wiki/LibYAML] or [git repo: +# https://github.com/yaml/libyaml] for its YAML parsing and emitting +# capabilities. In addition to wrapping libyaml, Psych also knows how to +# serialize and de-serialize most Ruby objects to and from the YAML format. # -# The YAML module is an alias of Psych, the YAML engine for Ruby. +# # I NEED TO PARSE OR EMIT YAML RIGHT NOW! # -# ## Usage -# -# Working with YAML can be very simple, for example: -# -# require 'yaml' -# # Parse a YAML string -# YAML.load("--- foo") #=> "foo" +# # Parse some YAML +# Psych.load("--- foo") # => "foo" # # # Emit some YAML -# YAML.dump("foo") # => "--- foo\n...\n" +# Psych.dump("foo") # => "--- foo\n...\n" # { :a => 'b'}.to_yaml # => "---\n:a: b\n" # -# As the implementation is provided by the Psych library, detailed documentation -# can be found in that library's docs (also part of standard library). +# Got more time on your hands? Keep on reading! +# +# ## YAML Parsing +# +# Psych provides a range of interfaces for parsing a YAML document ranging from +# low level to high level, depending on your parsing needs. At the lowest +# level, is an event based parser. Mid level is access to the raw YAML AST, and +# at the highest level is the ability to unmarshal YAML to Ruby objects. +# +# ## YAML Emitting +# +# Psych provides a range of interfaces ranging from low to high level for +# producing YAML documents. Very similar to the YAML parsing interfaces, Psych +# provides at the lowest level, an event based system, mid-level is building a +# YAML AST, and the highest level is converting a Ruby object straight to a YAML +# document. +# +# ## High-level API +# +# ### Parsing +# +# The high level YAML parser provided by Psych simply takes YAML as input and +# returns a Ruby data structure. For information on using the high level parser +# see Psych.load +# +# #### Reading from a string +# +# Psych.safe_load("--- a") # => 'a' +# Psych.safe_load("---\n - a\n - b") # => ['a', 'b'] +# # From a trusted string: +# Psych.load("--- !ruby/range\nbegin: 0\nend: 42\nexcl: false\n") # => 0..42 +# +# #### Reading from a file +# +# Psych.safe_load_file("data.yml", permitted_classes: [Date]) +# Psych.load_file("trusted_database.yml") +# +# #### Exception handling +# +# begin +# # The second argument changes only the exception contents +# Psych.parse("--- `", "file.txt") +# rescue Psych::SyntaxError => ex +# ex.file # => 'file.txt' +# ex.message # => "(file.txt): found character that cannot start any token" +# end +# +# ### Emitting +# +# The high level emitter has the easiest interface. Psych simply takes a Ruby +# data structure and converts it to a YAML document. See Psych.dump for more +# information on dumping a Ruby data structure. +# +# #### Writing to a string +# +# # Dump an array, get back a YAML string +# Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" +# +# # Dump an array to an IO object +# Psych.dump(['a', 'b'], StringIO.new) # => # +# +# # Dump an array with indentation set +# Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n" +# +# # Dump an array to an IO with indentation set +# Psych.dump(['a', ['b']], StringIO.new, :indentation => 3) +# +# #### Writing to a file +# +# Currently there is no direct API for dumping Ruby structure to file: +# +# File.open('database.yml', 'w') do |file| +# file.write(Psych.dump(['a', 'b'])) +# end +# +# ## Mid-level API +# +# ### Parsing +# +# Psych provides access to an AST produced from parsing a YAML document. This +# tree is built using the Psych::Parser and Psych::TreeBuilder. The AST can be +# examined and manipulated freely. Please see Psych::parse_stream, +# Psych::Nodes, and Psych::Nodes::Node for more information on dealing with YAML +# syntax trees. +# +# #### Reading from a string +# +# # Returns Psych::Nodes::Stream +# Psych.parse_stream("---\n - a\n - b") +# +# # Returns Psych::Nodes::Document +# Psych.parse("---\n - a\n - b") +# +# #### Reading from a file +# +# # Returns Psych::Nodes::Stream +# Psych.parse_stream(File.read('database.yml')) +# +# # Returns Psych::Nodes::Document +# Psych.parse_file('database.yml') +# +# #### Exception handling +# +# begin +# # The second argument changes only the exception contents +# Psych.parse("--- `", "file.txt") +# rescue Psych::SyntaxError => ex +# ex.file # => 'file.txt' +# ex.message # => "(file.txt): found character that cannot start any token" +# end +# +# ### Emitting +# +# At the mid level is building an AST. This AST is exactly the same as the AST +# used when parsing a YAML document. Users can build an AST by hand and the AST +# knows how to emit itself as a YAML document. See Psych::Nodes, +# Psych::Nodes::Node, and Psych::TreeBuilder for more information on building a +# YAML AST. +# +# #### Writing to a string +# +# # We need Psych::Nodes::Stream (not Psych::Nodes::Document) +# stream = Psych.parse_stream("---\n - a\n - b") +# +# stream.to_yaml # => "---\n- a\n- b\n" +# +# #### Writing to a file +# +# # We need Psych::Nodes::Stream (not Psych::Nodes::Document) +# stream = Psych.parse_stream(File.read('database.yml')) +# +# File.open('database.yml', 'w') do |file| +# file.write(stream.to_yaml) +# end +# +# ## Low-level API +# +# ### Parsing +# +# The lowest level parser should be used when the YAML input is already known, +# and the developer does not want to pay the price of building an AST or +# automatic detection and conversion to Ruby objects. See Psych::Parser for +# more information on using the event based parser. +# +# #### Reading to Psych::Nodes::Stream structure +# +# parser = Psych::Parser.new(TreeBuilder.new) # => # +# parser = Psych.parser # it's an alias for the above +# +# parser.parse("---\n - a\n - b") # => # +# parser.handler # => # +# parser.handler.root # => # # -# ## Security +# #### Receiving an events stream # -# Do not use YAML to load untrusted data. Doing so is unsafe and could allow -# malicious input to execute arbitrary code inside your application. Please see -# doc/security.rdoc for more information. +# recorder = Psych::Handlers::Recorder.new +# parser = Psych::Parser.new(recorder) # -# ## History +# parser.parse("---\n - a\n - b") +# recorder.events # => [list of [event, args] lists] +# # event is one of: Psych::Handler::EVENTS +# # args are the arguments passed to the event # -# Syck was the original YAML implementation in Ruby's standard library developed -# by why the lucky stiff. +# ### Emitting # -# You can still use Syck, if you prefer, for parsing and emitting YAML, but you -# must install the 'syck' gem now in order to use it. +# The lowest level emitter is an event based system. Events are sent to a +# Psych::Emitter object. That object knows how to convert the events to a YAML +# document. This interface should be used when document format is known in +# advance or speed is a concern. See Psych::Emitter for more information. # -# In older Ruby versions, ie. <= 1.9, Syck is still provided, however it was -# completely removed with the release of Ruby 2.0.0. +# #### Writing to a Ruby structure # -# ## More info +# Psych.parser.parse("--- a") # => # # -# For more advanced details on the implementation see Psych, and also check out -# http://yaml.org for spec details and other helpful information. +# parser.handler.first # => # +# parser.handler.first.to_ruby # => ["a"] # -# Psych is maintained by Aaron Patterson on github: -# https://github.com/ruby/psych +# parser.handler.root.first # => # +# parser.handler.root.first.to_ruby # => "a" # -# Syck can also be found on github: https://github.com/ruby/syck +# # You can instantiate an Emitter manually +# Psych::Visitors::ToRuby.new.accept(parser.handler.root.first) +# # => "a" # module Psych # # True if the `version` string matches RubyGems' requirements. # - def self.correct?: (_ToS version) -> bool + def self.correct?: (_ToS & Object version) -> bool # # Sets or returns default options for the JSON.load method. Initially: diff --git a/stdlib/pathname/0/pathname.rbs b/stdlib/pathname/0/pathname.rbs index 146b48c9ab..92f80e5834 100644 --- a/stdlib/pathname/0/pathname.rbs +++ b/stdlib/pathname/0/pathname.rbs @@ -1084,7 +1084,7 @@ class Pathname # Note that this method does not handle situations where the case sensitivity of # the filesystem in use differs from the operating system default. # - def relative_path_from: (Pathname | string base_directory) -> Pathname + def relative_path_from: (Pathname | (string & _IsA) base_directory) -> Pathname # # True if the `version` string matches RubyGems' requirements. # - def self.correct?: (_ToS & Object version) -> bool + def self.correct?: (_ToS & Kernel version) -> bool # # Sets or returns default options for the JSON.load method. Initially: From 90ad29c45e51b770c7c53bf77f193f5617b78a93 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Wed, 27 Sep 2023 13:53:48 +0900 Subject: [PATCH 021/101] Delete `sources` section from lockfile --- lib/rbs/collection/config/lockfile.rb | 25 ------ .../collection/config/lockfile_generator.rb | 6 -- sig/collection/config/lockfile.rbs | 6 -- test/rbs/collection/config_test.rb | 84 ------------------- 4 files changed, 121 deletions(-) diff --git a/lib/rbs/collection/config/lockfile.rb b/lib/rbs/collection/config/lockfile.rb index 22cb48d15c..5f4c4c93f3 100644 --- a/lib/rbs/collection/config/lockfile.rb +++ b/lib/rbs/collection/config/lockfile.rb @@ -12,7 +12,6 @@ def initialize(lockfile_path:, path:, gemfile_lock_path:) @path = path @gemfile_lock_path = gemfile_lock_path - @sources = {} @gems = {} end @@ -26,27 +25,15 @@ def gemfile_lock_fullpath end end - def each_source(&block) - if block - sources.each_value(&block) - yield Sources::Rubygems.instance - yield Sources::Stdlib.instance - else - enum_for :each_source - end - end - def to_lockfile # @type var data: lockfile_data data = { - "sources" => sources.each_value.sort_by {|s| s.name }.map {|source| source.to_lockfile }, "path" => path.to_s, "gems" => gems.each_value.sort_by {|g| g[:name] }.map {|hash| library_data(hash) }, "gemfile_lock_path" => gemfile_lock_path.to_s } - data.delete("sources") if sources.empty? data.delete("gems") if gems.empty? data @@ -60,18 +47,6 @@ def self.from_lockfile(lockfile_path:, data:) lockfile = Lockfile.new(lockfile_path: lockfile_path, path: path, gemfile_lock_path: gemfile_lock_path) - if sources = data["sources"] - sources.each do |src| - git = Sources::Git.new( - name: src["name"], - revision: src["revision"], - remote: src["remote"], - repo_dir: src["repo_dir"] - ) - lockfile.sources[git.name] = git - end - end - if gems = data["gems"] gems.each do |gem| src = gem["source"] diff --git a/lib/rbs/collection/config/lockfile_generator.rb b/lib/rbs/collection/config/lockfile_generator.rb index 5420f0783e..01eff10d33 100644 --- a/lib/rbs/collection/config/lockfile_generator.rb +++ b/lib/rbs/collection/config/lockfile_generator.rb @@ -44,12 +44,6 @@ def initialize(config:, definition:, with_lockfile:) path: config.repo_path_data, gemfile_lock_path: definition.lockfile.relative_path_from(lockfile_dir) ) - config.sources.each do |source| - case source - when Sources::Git - lockfile.sources[source.name] = source - end - end if with_lockfile && lockfile_path.file? @existing_lockfile = Lockfile.from_lockfile(lockfile_path: lockfile_path, data: YAML.load_file(lockfile_path.to_s)) diff --git a/sig/collection/config/lockfile.rbs b/sig/collection/config/lockfile.rbs index ff748f3aa8..862005f154 100644 --- a/sig/collection/config/lockfile.rbs +++ b/sig/collection/config/lockfile.rbs @@ -7,7 +7,6 @@ module RBS # Data structure stored in `rbs_collection.lock.yaml` # type lockfile_data = { - "sources" => Array[Sources::Git::source_entry]?, # null if empty "path" => String, "gems" => Array[library_data]?, # null if empty "gemfile_lock_path" => String? # gemfile_lock_path is optional because older versions doesn't have it @@ -43,8 +42,6 @@ module RBS # attr_reader gemfile_lock_path: Pathname? - attr_reader sources: Hash[String, Sources::Git] - attr_reader gems: Hash[String, library] def initialize: (lockfile_path: Pathname, path: Pathname, gemfile_lock_path: Pathname?) -> void @@ -59,9 +56,6 @@ module RBS def to_lockfile: () -> lockfile_data - def each_source: () { (Sources::t) -> void } -> void - | () -> Enumerator[Sources::t, void] - def self.from_lockfile: (lockfile_path: Pathname, data: lockfile_data) -> Lockfile # Validates if directories are set up correctly diff --git a/test/rbs/collection/config_test.rb b/test/rbs/collection/config_test.rb index 835c02af59..e62713d47e 100644 --- a/test/rbs/collection/config_test.rb +++ b/test/rbs/collection/config_test.rb @@ -58,12 +58,6 @@ def test_generate_lock_from_collection_repository string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: "/path/to/somewhere" gemfile_lock_path: 'Gemfile.lock' gems: @@ -115,12 +109,6 @@ def test_generate_lock_from_relative_git_repository string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: #{remote} - revision: b4d3b346d9657543099a35a1fd20347e75b8c523 - repo_dir: gems path: "/path/to/somewhere" gemfile_lock_path: 'Gemfile.lock' gems: @@ -155,12 +143,6 @@ def test_generate_lock_from_collection_repository_with_lockfile gemfile_lock_path.write GEMFILE_LOCK lockfile_yaml = <<~YAML - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: "/path/to/somewhere" gemfile_lock_path: 'Gemfile.lock' gems: @@ -212,12 +194,6 @@ def test_generate_lock_from_collection_repository_ignoring string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: "/path/to/somewhere" gemfile_lock_path: 'Gemfile.lock' gems: @@ -277,12 +253,6 @@ def test_generate_lock_from_collection_with_manifest_yaml string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: "/path/to/somewhere" gemfile_lock_path: 'Gemfile.lock' gems: @@ -359,12 +329,6 @@ def test_generate_lock_from_stdlib string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: "/path/to/somewhere" gemfile_lock_path: 'Gemfile.lock' gems: @@ -414,12 +378,6 @@ def test_generate_lock_from_rubygems string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: "/path/to/somewhere" gemfile_lock_path: 'Gemfile.lock' gems: @@ -461,12 +419,6 @@ def test_generate_lock_with_empty_gemfile_lock string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: "/path/to/somewhere" gemfile_lock_path: 'Gemfile.lock' YAML @@ -564,12 +516,6 @@ def test_generate_lock_from_bundler_require_false string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: ".gem_rbs_collection" gemfile_lock_path: 'Gemfile.lock' gems: @@ -628,12 +574,6 @@ def test_generate_lock_install_indirect_dependency string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: ".gem_rbs_collection" gemfile_lock_path: 'Gemfile.lock' gems: @@ -690,12 +630,6 @@ def test_generate_lockfile_dependency_with_platform string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: ".gem_rbs_collection" gemfile_lock_path: 'Gemfile.lock' YAML @@ -740,12 +674,6 @@ def test_generate_lockfile__gems_not_included_in_gemfile string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: ".gem_rbs_collection" gemfile_lock_path: 'Gemfile.lock' gems: @@ -824,12 +752,6 @@ def test_generate_lockfile__dependency_source string = YAML.dump(lockfile.to_lockfile) assert_config <<~YAML, string - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: 9612e5e67697153dcc7464c01115db44d29b1e34 - repo_dir: gems path: ".gem_rbs_collection" gemfile_lock_path: 'Gemfile.lock' gems: @@ -896,12 +818,6 @@ def test_generate_lockfile_from_mismatched_lockfiles # Version mismatched rbs_collection.lock.yaml (Gemfile.lock expects rainbow-3.0.0, but this expects 2.0) lockfile_yaml = <<~YAML - sources: - - type: git - name: ruby/gem_rbs_collection - remote: https://github.com/ruby/gem_rbs_collection.git - revision: cde6057e7546843ace6420c5783dd945c6ccda54 - repo_dir: gems path: "/path/to/somewhere" gemfile_lock_path: 'Gemfile.lock' gems: From cd1974245785e0382c8977d7cb9a026e285c1425 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 27 Sep 2023 14:19:13 +0900 Subject: [PATCH 022/101] Suppress syntax warnings * assigned but unused variable --- test/rbs/cli_test.rb | 4 ++-- test/rbs/definition_builder_test.rb | 6 ------ test/validator_test.rb | 2 -- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/test/rbs/cli_test.rb b/test/rbs/cli_test.rb index 1b199e41a1..083960ea2b 100644 --- a/test/rbs/cli_test.rb +++ b/test/rbs/cli_test.rb @@ -912,8 +912,8 @@ def test_collection_install_gemspec stdout, _ = run_rbs("collection", "install", bundler: true) - assert_match /^Installing ast:(\d(\.\d)*)/, stdout - refute_match /^Using hola:(\d(\.\d)*)/, stdout + assert_match(/^Installing ast:(\d(\.\d)*)/, stdout) + refute_match(/^Using hola:(\d(\.\d)*)/, stdout) assert dir.join('rbs_collection.lock.yaml').exist? assert dir.join('gem_rbs_collection/ast').exist? diff --git a/test/rbs/definition_builder_test.rb b/test/rbs/definition_builder_test.rb index fff7e43e75..beaff03bc4 100644 --- a/test/rbs/definition_builder_test.rb +++ b/test/rbs/definition_builder_test.rb @@ -2609,8 +2609,6 @@ class Hoge < Baz::Bar EOF manager.build do |env| - root = nil - builder = DefinitionBuilder.new(env: env) builder.build_instance(type_name("::Hoge")) @@ -2634,8 +2632,6 @@ class Baz EOF manager.build do |env| - root = nil - builder = DefinitionBuilder.new(env: env) builder.build_instance(type_name("::Baz")) @@ -2654,8 +2650,6 @@ module Bar : Foo EOF manager.build do |env| - root = nil - builder = DefinitionBuilder.new(env: env) builder.build_instance(type_name("::Bar")) diff --git a/test/validator_test.rb b/test/validator_test.rb index fd8e2acaf5..9ffb9cb89a 100644 --- a/test/validator_test.rb +++ b/test/validator_test.rb @@ -358,8 +358,6 @@ class Baz = Numeric EOF manager.build do |env| - root = nil - resolver = RBS::Resolver::TypeNameResolver.new(env) validator = RBS::Validator.new(env: env, resolver: resolver) From b26a860d3e4b861e8a68810d6375fd65d8ee0b77 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 27 Sep 2023 14:19:23 +0900 Subject: [PATCH 023/101] Suppress runtime warnings * deprecated constant accesses --- lib/rbs/prototype/runtime.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/rbs/prototype/runtime.rb b/lib/rbs/prototype/runtime.rb index 1e56b716ba..71a437af4d 100644 --- a/lib/rbs/prototype/runtime.rb +++ b/lib/rbs/prototype/runtime.rb @@ -655,12 +655,15 @@ def const_name(const) return nil unless name begin + deprecated, Warning[:deprecated] = Warning[:deprecated], false Object.const_get(name) rescue NameError # Should generate const name if anonymous or internal module (e.g. NameError::message) nil else name + ensure + Warning[:deprecated] = deprecated end end From 1bc3bc8d33fe28bbccf4fcd303bb1b3211c840d8 Mon Sep 17 00:00:00 2001 From: ksss Date: Wed, 27 Sep 2023 13:50:43 +0900 Subject: [PATCH 024/101] Fix indentation of template --- Rakefile | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Rakefile b/Rakefile index 46864a634f..05571ada23 100644 --- a/Rakefile +++ b/Rakefile @@ -158,13 +158,14 @@ namespace :generate do # library "pathname", "securerandom" # Declare library signatures to load testing "singleton(::<%= target %>)" - <%- class_methods.each do |method_name, definition| %> + <%- class_methods.each do |method_name, definition| -%> def test_<%= test_name_for(method_name) %> <%- definition.method_types.each do |method_type| -%> - assert_send_type "<%= method_type %>", - <%= target %>, :<%= method_name %> + assert_send_type "<%= method_type %>", + <%= target %>, :<%= method_name %> <%- end -%> end + <%- end -%> end <%- end -%> @@ -176,13 +177,14 @@ namespace :generate do # library "pathname", "securerandom" # Declare library signatures to load testing "::<%= target %>" - <%- instance_methods.each do |method_name, definition| %> + <%- instance_methods.each do |method_name, definition| -%> def test_<%= test_name_for(method_name) %> <%- definition.method_types.each do |method_type| -%> - assert_send_type "<%= method_type %>", - <%= target %>.new, :<%= method_name %> + assert_send_type "<%= method_type %>", + <%= target %>.new, :<%= method_name %> <%- end -%> end + <%- end -%> end <%- end -%> From 616513ba2f7e3dbfdbee984ef9ece372ad48dc45 Mon Sep 17 00:00:00 2001 From: ksss Date: Wed, 27 Sep 2023 13:51:48 +0900 Subject: [PATCH 025/101] Add pp in stdlib --- Steepfile | 3 +- sig/shims/pp.rbs | 3 - stdlib/pp/0/manifest.yaml | 2 + stdlib/pp/0/pp.rbs | 301 ++++++++++++++++++++++++++++++++++++++ test/stdlib/PP_test.rb | 140 ++++++++++++++++++ 5 files changed, 445 insertions(+), 4 deletions(-) delete mode 100644 sig/shims/pp.rbs create mode 100644 stdlib/pp/0/manifest.yaml create mode 100644 stdlib/pp/0/pp.rbs create mode 100644 test/stdlib/PP_test.rb diff --git a/Steepfile b/Steepfile index faa26baa62..eb09449d86 100644 --- a/Steepfile +++ b/Steepfile @@ -8,12 +8,13 @@ target :lib do "lib/rbs/test.rb" ) - library "pathname", "json", "logger", "monitor", "tsort", "uri", 'dbm', 'pstore', 'singleton', 'shellwords', 'fileutils', 'find', 'digest', 'abbrev' + library "pathname", "json", "logger", "monitor", "tsort", "uri", 'dbm', 'pstore', 'singleton', 'shellwords', 'fileutils', 'find', 'digest', 'abbrev', 'prettyprint' signature 'stdlib/yaml/0' signature "stdlib/strscan/0/" signature "stdlib/optparse/0/" signature "stdlib/rdoc/0/" signature "stdlib/ripper/0" + signature "stdlib/pp/0" # configure_code_diagnostics do |config| # config[D::Ruby::MethodDefinitionMissing] = :hint diff --git a/sig/shims/pp.rbs b/sig/shims/pp.rbs deleted file mode 100644 index 1be946051a..0000000000 --- a/sig/shims/pp.rbs +++ /dev/null @@ -1,3 +0,0 @@ -class PP - def self.pp: (untyped obj, IO out, ?Integer width) -> void -end diff --git a/stdlib/pp/0/manifest.yaml b/stdlib/pp/0/manifest.yaml new file mode 100644 index 0000000000..df3206fe66 --- /dev/null +++ b/stdlib/pp/0/manifest.yaml @@ -0,0 +1,2 @@ +dependencies: + - name: prettyprint diff --git a/stdlib/pp/0/pp.rbs b/stdlib/pp/0/pp.rbs new file mode 100644 index 0000000000..a85fbd15b9 --- /dev/null +++ b/stdlib/pp/0/pp.rbs @@ -0,0 +1,301 @@ +# +# A pretty-printer for Ruby objects. +# +# ## What PP Does +# +# Standard output by #p returns this: +# #, @group_queue=#], []]>, @buffer=[], @newline="\n", @group_stack=[#], @buffer_width=0, @indent=0, @maxwidth=79, @output_width=2, @output=#> +# +# Pretty-printed output returns this: +# #, +# @group_queue= +# #], +# []]>, +# @group_stack= +# [#], +# @indent=0, +# @maxwidth=79, +# @newline="\n", +# @output=#, +# @output_width=2> +# +# ## Usage +# +# pp(obj) #=> obj +# pp obj #=> obj +# pp(obj1, obj2, ...) #=> [obj1, obj2, ...] +# pp() #=> nil +# +# Output `obj(s)` to `$>` in pretty printed format. +# +# It returns `obj(s)`. +# +# ## Output Customization +# +# To define a customized pretty printing function for your classes, redefine +# method `#pretty_print(pp)` in the class. +# +# `#pretty_print` takes the `pp` argument, which is an instance of the PP class. +# The method uses #text, #breakable, #nest, #group and #pp to print the object. +# +# ## Pretty-Print JSON +# +# To pretty-print JSON refer to JSON#pretty_generate. +# +# ## Author +# Tanaka Akira +# +class PP < PrettyPrint + interface _PrettyPrint + def pretty_print: (untyped q) -> untyped + + def pretty_print_cycle: (untyped q) -> untyped + + def is_a?: (Module) -> bool + end + + interface _LeftShift + def <<: (untyped obj) -> self + end + + interface _PPMethodsRequired + def text: (String obj, ?Integer width) -> void + + def breakable: (?String sep, ?Integer width) -> void + + def group: (?Integer indent, ?String open_obj, ?String close_obj, ?Integer open_width, ?Integer close_width) { () -> untyped } -> void + end + + module PPMethods : _PPMethodsRequired + # + # Yields to a block and preserves the previous set of objects being printed. + # + def guard_inspect_key: () { () -> untyped } -> void + + # + # Check whether the object_id `id` is in the current buffer of objects to be + # pretty printed. Used to break cycles in chains of objects to be pretty + # printed. + # + def check_inspect_key: (_PrettyPrint id) -> bool + + # + # Adds the object_id `id` to the set of objects being pretty printed, so as to + # not repeat objects. + # + def push_inspect_key: (_PrettyPrint id) -> void + + # + # Removes an object from the set of objects being pretty printed. + # + def pop_inspect_key: (_PrettyPrint id) -> void + + # + # Adds `obj` to the pretty printing buffer using Object#pretty_print or + # Object#pretty_print_cycle. + # + # Object#pretty_print_cycle is used when `obj` is already printed, a.k.a the + # object reference chain has a cycle. + # + def pp: (_PrettyPrint obj) -> untyped + + # + # A convenience method which is same as follows: + # + # group(1, '#<' + obj.class.name, '>') { ... } + # + def object_group: (untyped obj) { () -> untyped } -> Integer + + # + # A convenience method, like object_group, but also reformats the Object's + # object_id. + # + def object_address_group: (untyped obj) { () -> untyped } -> Integer + + # + # A convenience method which is same as follows: + # + # text ',' + # breakable + # + def comma_breakable: () -> void + + # + # Adds a separated list. The list is separated by comma with breakable space, by + # default. + # + # #seplist iterates the `list` using `iter_method`. It yields each object to the + # block given for #seplist. The procedure `separator_proc` is called between + # each yields. + # + # If the iteration is zero times, `separator_proc` is not called at all. + # + # If `separator_proc` is nil or not given, +lambda { comma_breakable }+ is used. + # If `iter_method` is not given, :each is used. + # + # For example, following 3 code fragments has similar effect. + # + # q.seplist([1,2,3]) {|v| xxx v } + # + # q.seplist([1,2,3], lambda { q.comma_breakable }, :each) {|v| xxx v } + # + # xxx 1 + # q.comma_breakable + # xxx 2 + # q.comma_breakable + # xxx 3 + # + def seplist: (untyped list, ?(^() -> void)? sep, ?interned iter_method) { (*untyped, **untyped) -> void } -> void + + # + # A present standard failsafe for pretty printing any given Object + # + def pp_object: (untyped obj) -> untyped + + # + # A pretty print for a Hash + # + def pp_hash: (untyped obj) -> untyped + end + include PPMethods + + class SingleLine < ::PrettyPrint::SingleLine + include PPMethods + end + + module ObjectMixin : BasicObject + def pretty_print: (PP q) -> untyped + + def pretty_print_cycle: (PP q) -> untyped + + def pretty_print_instance_variables: () -> Array[Symbol] + + def pretty_print_inspect: () -> untyped + end + + # + # Returns the usable width for `out`. As the width of `out`: + # 1. If `out` is assigned to a tty device, its width is used. + # 2. Otherwise, or it could not get the value, the `COLUMN` environment + # variable is assumed to be set to the width. + # 3. If `COLUMN` is not set to a non-zero number, 80 is assumed. + # + # + # And finally, returns the above width value - 1. + # * This -1 is for Windows command prompt, which moves the cursor to the next + # line if it reaches the last column. + # + def self.width_for: (untyped out) -> Integer + + # + # Outputs `obj` to `out` in pretty printed format of `width` columns in width. + # + # If `out` is omitted, `$>` is assumed. If `width` is omitted, the width of + # `out` is assumed (see width_for). + # + # PP.pp returns `out`. + # + def self.pp: (_PrettyPrint obj, ?_LeftShift out, ?Integer width) -> untyped + + # + # Outputs `obj` to `out` like PP.pp but with no indent and newline. + # + # PP.singleline_pp returns `out`. + # + def self.singleline_pp: (_PrettyPrint obj, ?_LeftShift out) -> untyped + def self.mcall: (untyped obj, Module mod, interned meth, *untyped args) ?{ (*untyped, **untyped) -> untyped } -> untyped + + # + # Returns the sharing detection flag as a boolean value. It is false (nil) by + # default. + # ---- + # + # Sets the sharing detection flag to b. + # + attr_accessor self.sharing_detection: bool? +end + +%a{annotate:rdoc:skip} +class RubyVM::AbstractSyntaxTree::Node + # + # + def pretty_print_children: (PP q, ?Array[untyped] names) -> void +end + +%a{annotate:rdoc:skip} +class Object + include PP::ObjectMixin +end + +%a{annotate:rdoc:skip} +module Kernel + # + # Returns a pretty printed object as a string. + # + # In order to use this method you must first require the PP module: + # + # require 'pp' + # + # See the PP module for more information. + # + def pretty_inspect: () -> String +end diff --git a/test/stdlib/PP_test.rb b/test/stdlib/PP_test.rb new file mode 100644 index 0000000000..7750ab7445 --- /dev/null +++ b/test/stdlib/PP_test.rb @@ -0,0 +1,140 @@ +require_relative "test_helper" +require "pp" + +class PPSingletonTest < Test::Unit::TestCase + include TypeAssertions + + library "pp" + testing "singleton(::PP)" + + def test_pp + assert_send_type "(::PP::_PrettyPrint obj, ?::PP::_LeftShift out, ?::Integer width) -> untyped", + PP, :pp, Object.new, ''.dup + + IO.pipe do |r, w| + assert_send_type "(::PP::_PrettyPrint obj, ?::PP::_LeftShift out, ?::Integer width) -> untyped", + PP, :pp, Object.new, w + end + end + + def test_width_for + assert_send_type "(untyped out) -> ::Integer", + PP, :width_for, Object.new + assert_send_type "(untyped out) -> ::Integer", + PP, :width_for, $stdout + end + + def test_singleline_pp + assert_send_type "(::PP::_PrettyPrint obj, ?::PP::_LeftShift out) -> untyped", + PP, :singleline_pp, Object.new + assert_send_type "(::PP::_PrettyPrint obj, ?::PP::_LeftShift out) -> untyped", + PP, :singleline_pp, Object.new, ''.dup + end + + def test_mcall + assert_send_type "(untyped obj, ::Module mod, ::interned meth, *untyped args) -> untyped", + PP, :mcall, self, Kernel, :class + assert_send_type "(untyped obj, ::Module mod, ::interned meth, *untyped args) -> untyped", + PP, :mcall, 1, Integer, :+, 2 + assert_send_type "(untyped obj, ::Module mod, ::interned meth, *untyped args) { (*untyped, **untyped) -> untyped } -> untyped", + PP, :mcall, 1, Kernel, :tap do end + end +end + +class PP::PPMethodsTest < Test::Unit::TestCase + include TypeAssertions + + library "pp" + testing "::PP::PPMethods" + + def test_guard_inspect_key + assert_send_type "() { () -> untyped } -> void", + PP.new, :guard_inspect_key do end + end + + def test_check_inspect_key + assert_send_type "(::PP::_PrettyPrint id) -> bool", + PP.new, :check_inspect_key, Object.new + end + + def test_push_inspect_key + assert_send_type "(::PP::_PrettyPrint id) -> void", + PP.new, :push_inspect_key, Object.new + end + + def test_pop_inspect_key + assert_send_type "(::PP::_PrettyPrint id) -> void", + PP.new, :pop_inspect_key, Object.new + end + + def test_pp + assert_send_type "(::PP::_PrettyPrint obj) -> untyped", + PP.new, :pp, Object.new + end + + def test_object_group + assert_send_type "(untyped obj) { () -> untyped } -> ::Integer", + PP.new, :object_group, Object.new do end + end + + def test_object_address_group + assert_send_type "(untyped obj) { () -> untyped } -> ::Integer", + PP.new, :object_address_group, Object.new do end + end + + def test_comma_breakable + assert_send_type "() -> void", + PP.new, :comma_breakable + end + + def test_seplist + assert_send_type "(untyped list) { (*untyped, **untyped) -> void } -> void", + PP.new, :seplist, [] do end + assert_send_type "(untyped list, ^() -> void? sep) { (*untyped, **untyped) -> void } -> void", + PP.new, :seplist, [], lambda {} do end + assert_send_type "(untyped list, ^() -> void? sep, ::interned iter_method) { (*untyped, **untyped) -> void } -> void", + PP.new, :seplist, [], lambda {}, :each do end + end + + def test_pp_object + assert_send_type "(untyped obj) -> untyped", + PP.new, :pp_object, Object.new + end + + def test_pp_hash + assert_send_type "(untyped obj) -> untyped", + PP.new, :pp_hash, {} + end +end + +class PP::ObjectMixinTest < Test::Unit::TestCase + include TypeAssertions + + library "pp" + testing "::PP::ObjectMixin" + + def test_pretty_print + assert_send_type "(PP q) -> untyped", + Object.new, :pretty_print, PP.new + end + + def test_pretty_print_cycle + assert_send_type "(PP q) -> untyped", + Object.new, :pretty_print_cycle, PP.new + end + + def test_pretty_print_instance_variables + assert_send_type "() -> Array[Symbol]", + Object.new, :pretty_print_instance_variables + end + + def test_pretty_print_inspect + has_pretty_print = Class.new do + def pretty_print(q) + 'ok' + end + end + assert_send_type "() -> untyped", + has_pretty_print.new, :pretty_print_inspect + end +end From d63b6a99639b91a291f4fcaf50a68abc5b12414d Mon Sep 17 00:00:00 2001 From: Masataka Pocke Kuwabara Date: Wed, 27 Sep 2023 15:52:44 +0900 Subject: [PATCH 026/101] [syntax.md] Cosmetic change to align comments --- docs/syntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/syntax.md b/docs/syntax.md index d319c75499..aca09c3766 100644 --- a/docs/syntax.md +++ b/docs/syntax.md @@ -723,7 +723,7 @@ If a type parameter has an upper bound, the type parameter must be instantiated ```rbs type str_printer = PrettyPrint[String] # OK -type int_printer = PrettyPrint[Integer] # Type error +type int_printer = PrettyPrint[Integer] # Type error ``` The upper bound must be one of a class instance type, interface type, or class singleton type. From 4ded4d6de40fd4dd33ede8a8edd314c766ae91f9 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Wed, 27 Sep 2023 17:49:50 +0900 Subject: [PATCH 027/101] Update README.md Add link to Discord and ruby-jp Slack. --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 45cf7111c7..22b10bdac8 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,13 @@ puts singleton.methods[:gsub] - [Syntax](docs/syntax.md) - [RBS by Example](docs/rbs_by_example.md) +## Community + +Here is a list of some places you can talk with active maintainers. + +- [Ruby Discord Server (invite link)](https://discord.gg/ad2acQFtkh) -- We have `rbs` channel in Ruby Discord server. +- [ruby-jp Slack Workspace (in Japanese)](https://ruby-jp.github.io/) -- We have `types` channel in ruby-jp slack workspace. + ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. From 329494e7cd42a3ecc6bd387d65964a38a2ab3b71 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 27 Sep 2023 20:08:30 +0900 Subject: [PATCH 028/101] Use valid syntax `yield` cannot appear outside a method. `RubyVM::AbstractSyntaxTree` currently does not check it, but that does not mean it will never do. --- test/rbs/node_usage_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/rbs/node_usage_test.rb b/test/rbs/node_usage_test.rb index 6e4ca40479..bdc933c49b 100644 --- a/test/rbs/node_usage_test.rb +++ b/test/rbs/node_usage_test.rb @@ -9,7 +9,7 @@ def parse(string) def test_conditional NodeUsage.new(parse(<<~RB)) - if block + def block yield end From 2d56df3a118d54685a70811fef645f672f69e3f8 Mon Sep 17 00:00:00 2001 From: ksss Date: Wed, 27 Sep 2023 15:03:53 +0900 Subject: [PATCH 029/101] Proc type should be enclosed in parentheses. --- lib/rbs/types.rb | 2 ++ test/rbs/types_test.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/rbs/types.rb b/lib/rbs/types.rb index b468e74383..0103ac12f5 100644 --- a/lib/rbs/types.rb +++ b/lib/rbs/types.rb @@ -552,6 +552,8 @@ def to_s(level = 0) when Symbol return "#{type.to_s(1)} ?" end + when RBS::Types::Proc + return "(#{type.to_s(1)})?" end "#{type.to_s(1)}?" diff --git a/test/rbs/types_test.rb b/test/rbs/types_test.rb index a2b7967b35..67748ea7ad 100644 --- a/test/rbs/types_test.rb +++ b/test/rbs/types_test.rb @@ -28,6 +28,7 @@ def test_to_s assert_equal "(Integer | String & bool)?", parse_type("(Integer | String & bool)?").to_s assert_equal "((Integer | String) & bool)?", parse_type("((Integer | String) & bool)?").to_s assert_equal "^() -> void", parse_type("^() -> void").to_s + assert_equal "(^() -> void)?", parse_type("(^() -> void)?").to_s assert_equal "^(bool flag, ?untyped, *Symbol, name: String, ?email: nil, **Symbol) -> void", parse_type("^(bool flag, ?untyped, *Symbol, name: String, ?email: nil, **Symbol) -> void").to_s assert_equal "^(untyped untyped, untyped footype) -> void", parse_type("^(untyped `untyped`, untyped footype) -> void").to_s end From e85a28591253fa8ef0a2e59de68f2dcbeb48e11e Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Wed, 27 Sep 2023 22:24:58 +0900 Subject: [PATCH 030/101] Maek global variables --- ext/rbs_extension/constants.c | 145 +++++++++++++++++----------------- 1 file changed, 73 insertions(+), 72 deletions(-) diff --git a/ext/rbs_extension/constants.c b/ext/rbs_extension/constants.c index 7bc6137dcd..57ec73ee34 100644 --- a/ext/rbs_extension/constants.c +++ b/ext/rbs_extension/constants.c @@ -75,77 +75,78 @@ VALUE RBS_MethodType; VALUE RBS_ParsingError; +#define IMPORT_CONSTANT(var, parent, name) { var = rb_const_get(parent, rb_intern(name)); rb_gc_register_mark_object(var); } + void rbs__init_constants(void) { - ID id_RBS = rb_intern_const("RBS"); - - RBS = rb_const_get(rb_cObject, id_RBS); - RBS_ParsingError = rb_const_get(RBS, rb_intern("ParsingError")); - RBS_AST = rb_const_get(RBS, rb_intern("AST")); - RBS_AST_Comment = rb_const_get(RBS_AST, rb_intern("Comment")); - RBS_AST_Annotation = rb_const_get(RBS_AST, rb_intern("Annotation")); - RBS_AST_TypeParam = rb_const_get(RBS_AST, rb_intern("TypeParam")); - - RBS_AST_Declarations = rb_const_get(RBS_AST, rb_intern("Declarations")); - - RBS_AST_Declarations_TypeAlias = rb_const_get(RBS_AST_Declarations, rb_intern("TypeAlias")); - RBS_AST_Declarations_Constant = rb_const_get(RBS_AST_Declarations, rb_intern("Constant")); - RBS_AST_Declarations_Global = rb_const_get(RBS_AST_Declarations, rb_intern("Global")); - RBS_AST_Declarations_Interface = rb_const_get(RBS_AST_Declarations, rb_intern("Interface")); - RBS_AST_Declarations_Module = rb_const_get(RBS_AST_Declarations, rb_intern("Module")); - RBS_AST_Declarations_Module_Self = rb_const_get(RBS_AST_Declarations_Module, rb_intern("Self")); - RBS_AST_Declarations_Class = rb_const_get(RBS_AST_Declarations, rb_intern("Class")); - RBS_AST_Declarations_Class_Super = rb_const_get(RBS_AST_Declarations_Class, rb_intern("Super")); - RBS_AST_Declarations_ClassAlias = rb_const_get(RBS_AST_Declarations, rb_intern("ClassAlias")); - RBS_AST_Declarations_ModuleAlias = rb_const_get(RBS_AST_Declarations, rb_intern("ModuleAlias")); - - RBS_AST_Directives = rb_const_get(RBS_AST, rb_intern("Directives")); - RBS_AST_Directives_Use = rb_const_get(RBS_AST_Directives, rb_intern("Use")); - RBS_AST_Directives_Use_SingleClause = rb_const_get(RBS_AST_Directives_Use, rb_intern("SingleClause")); - RBS_AST_Directives_Use_WildcardClause = rb_const_get(RBS_AST_Directives_Use, rb_intern("WildcardClause")); - - RBS_AST_Members = rb_const_get(RBS_AST, rb_intern("Members")); - RBS_AST_Members_Alias = rb_const_get(RBS_AST_Members, rb_intern("Alias")); - RBS_AST_Members_AttrAccessor = rb_const_get(RBS_AST_Members, rb_intern("AttrAccessor")); - RBS_AST_Members_AttrReader = rb_const_get(RBS_AST_Members, rb_intern("AttrReader")); - RBS_AST_Members_AttrWriter = rb_const_get(RBS_AST_Members, rb_intern("AttrWriter")); - RBS_AST_Members_ClassInstanceVariable = rb_const_get(RBS_AST_Members, rb_intern("ClassInstanceVariable")); - RBS_AST_Members_ClassVariable = rb_const_get(RBS_AST_Members, rb_intern("ClassVariable")); - RBS_AST_Members_Extend = rb_const_get(RBS_AST_Members, rb_intern("Extend")); - RBS_AST_Members_Include = rb_const_get(RBS_AST_Members, rb_intern("Include")); - RBS_AST_Members_InstanceVariable = rb_const_get(RBS_AST_Members, rb_intern("InstanceVariable")); - RBS_AST_Members_MethodDefinition = rb_const_get(RBS_AST_Members, rb_intern("MethodDefinition")); - RBS_AST_Members_MethodDefinition_Overload = rb_const_get(RBS_AST_Members_MethodDefinition, rb_intern("Overload")); - RBS_AST_Members_Prepend = rb_const_get(RBS_AST_Members, rb_intern("Prepend")); - RBS_AST_Members_Private = rb_const_get(RBS_AST_Members, rb_intern("Private")); - RBS_AST_Members_Public = rb_const_get(RBS_AST_Members, rb_intern("Public")); - - RBS_Namespace = rb_const_get(RBS, rb_intern("Namespace")); - RBS_TypeName = rb_const_get(RBS, rb_intern("TypeName")); - RBS_Types = rb_const_get(RBS, rb_intern("Types")); - RBS_Types_Alias = rb_const_get(RBS_Types, rb_intern("Alias")); - RBS_Types_Bases = rb_const_get(RBS_Types, rb_intern("Bases")); - RBS_Types_Bases_Any = rb_const_get(RBS_Types_Bases, rb_intern("Any")); - RBS_Types_Bases_Bool = rb_const_get(RBS_Types_Bases, rb_intern("Bool")); - RBS_Types_Bases_Bottom = rb_const_get(RBS_Types_Bases, rb_intern("Bottom")); - RBS_Types_Bases_Class = rb_const_get(RBS_Types_Bases, rb_intern("Class")); - RBS_Types_Bases_Instance = rb_const_get(RBS_Types_Bases, rb_intern("Instance")); - RBS_Types_Bases_Nil = rb_const_get(RBS_Types_Bases, rb_intern("Nil")); - RBS_Types_Bases_Self = rb_const_get(RBS_Types_Bases, rb_intern("Self")); - RBS_Types_Bases_Top = rb_const_get(RBS_Types_Bases, rb_intern("Top")); - RBS_Types_Bases_Void = rb_const_get(RBS_Types_Bases, rb_intern("Void")); - RBS_Types_Block = rb_const_get(RBS_Types, rb_intern("Block")); - RBS_Types_ClassInstance = rb_const_get(RBS_Types, rb_intern("ClassInstance")); - RBS_Types_ClassSingleton = rb_const_get(RBS_Types, rb_intern("ClassSingleton")); - RBS_Types_Function = rb_const_get(RBS_Types, rb_intern("Function")); - RBS_Types_Function_Param = rb_const_get(RBS_Types_Function, rb_intern("Param")); - RBS_Types_Interface = rb_const_get(RBS_Types, rb_intern("Interface")); - RBS_Types_Intersection = rb_const_get(RBS_Types, rb_intern("Intersection")); - RBS_Types_Literal = rb_const_get(RBS_Types, rb_intern("Literal")); - RBS_Types_Optional = rb_const_get(RBS_Types, rb_intern("Optional")); - RBS_Types_Proc = rb_const_get(RBS_Types, rb_intern("Proc")); - RBS_Types_Record = rb_const_get(RBS_Types, rb_intern("Record")); - RBS_Types_Tuple = rb_const_get(RBS_Types, rb_intern("Tuple")); - RBS_Types_Union = rb_const_get(RBS_Types, rb_intern("Union")); - RBS_Types_Variable = rb_const_get(RBS_Types, rb_intern("Variable")); - RBS_MethodType = rb_const_get(RBS, rb_intern("MethodType")); + IMPORT_CONSTANT(RBS, rb_cObject, "RBS"); + IMPORT_CONSTANT(RBS_ParsingError, RBS, "ParsingError"); + + IMPORT_CONSTANT(RBS_AST, RBS, "AST"); + IMPORT_CONSTANT(RBS_AST_Comment, RBS_AST, "Comment"); + IMPORT_CONSTANT(RBS_AST_Annotation, RBS_AST, "Annotation"); + IMPORT_CONSTANT(RBS_AST_TypeParam, RBS_AST, "TypeParam"); + + IMPORT_CONSTANT(RBS_AST_Declarations, RBS_AST, "Declarations"); + + IMPORT_CONSTANT(RBS_AST_Declarations_TypeAlias, RBS_AST_Declarations, "TypeAlias"); + IMPORT_CONSTANT(RBS_AST_Declarations_Constant, RBS_AST_Declarations, "Constant"); + IMPORT_CONSTANT(RBS_AST_Declarations_Global, RBS_AST_Declarations, "Global"); + IMPORT_CONSTANT(RBS_AST_Declarations_Interface, RBS_AST_Declarations, "Interface"); + IMPORT_CONSTANT(RBS_AST_Declarations_Module, RBS_AST_Declarations, "Module"); + IMPORT_CONSTANT(RBS_AST_Declarations_Module_Self, RBS_AST_Declarations_Module, "Self"); + IMPORT_CONSTANT(RBS_AST_Declarations_Class, RBS_AST_Declarations, "Class"); + IMPORT_CONSTANT(RBS_AST_Declarations_Class_Super, RBS_AST_Declarations_Class, "Super"); + IMPORT_CONSTANT(RBS_AST_Declarations_ClassAlias, RBS_AST_Declarations, "ClassAlias"); + IMPORT_CONSTANT(RBS_AST_Declarations_ModuleAlias, RBS_AST_Declarations, "ModuleAlias"); + + IMPORT_CONSTANT(RBS_AST_Directives, RBS_AST, "Directives"); + IMPORT_CONSTANT(RBS_AST_Directives_Use, RBS_AST_Directives, "Use"); + IMPORT_CONSTANT(RBS_AST_Directives_Use_SingleClause, RBS_AST_Directives_Use, "SingleClause"); + IMPORT_CONSTANT(RBS_AST_Directives_Use_WildcardClause, RBS_AST_Directives_Use, "WildcardClause"); + + IMPORT_CONSTANT(RBS_AST_Members, RBS_AST, "Members"); + IMPORT_CONSTANT(RBS_AST_Members_Alias, RBS_AST_Members, "Alias"); + IMPORT_CONSTANT(RBS_AST_Members_AttrAccessor, RBS_AST_Members, "AttrAccessor"); + IMPORT_CONSTANT(RBS_AST_Members_AttrReader, RBS_AST_Members, "AttrReader"); + IMPORT_CONSTANT(RBS_AST_Members_AttrWriter, RBS_AST_Members, "AttrWriter"); + IMPORT_CONSTANT(RBS_AST_Members_ClassInstanceVariable, RBS_AST_Members, "ClassInstanceVariable"); + IMPORT_CONSTANT(RBS_AST_Members_ClassVariable, RBS_AST_Members, "ClassVariable"); + IMPORT_CONSTANT(RBS_AST_Members_Extend, RBS_AST_Members, "Extend"); + IMPORT_CONSTANT(RBS_AST_Members_Include, RBS_AST_Members, "Include"); + IMPORT_CONSTANT(RBS_AST_Members_InstanceVariable, RBS_AST_Members, "InstanceVariable"); + IMPORT_CONSTANT(RBS_AST_Members_MethodDefinition, RBS_AST_Members, "MethodDefinition"); + IMPORT_CONSTANT(RBS_AST_Members_MethodDefinition_Overload, RBS_AST_Members_MethodDefinition, "Overload"); + IMPORT_CONSTANT(RBS_AST_Members_Prepend, RBS_AST_Members, "Prepend"); + IMPORT_CONSTANT(RBS_AST_Members_Private, RBS_AST_Members, "Private"); + IMPORT_CONSTANT(RBS_AST_Members_Public, RBS_AST_Members, "Public"); + + IMPORT_CONSTANT(RBS_Namespace, RBS, "Namespace"); + IMPORT_CONSTANT(RBS_TypeName, RBS, "TypeName"); + IMPORT_CONSTANT(RBS_Types, RBS, "Types"); + IMPORT_CONSTANT(RBS_Types_Alias, RBS_Types, "Alias"); + IMPORT_CONSTANT(RBS_Types_Bases, RBS_Types, "Bases"); + IMPORT_CONSTANT(RBS_Types_Bases_Any, RBS_Types_Bases, "Any"); + IMPORT_CONSTANT(RBS_Types_Bases_Bool, RBS_Types_Bases, "Bool"); + IMPORT_CONSTANT(RBS_Types_Bases_Bottom, RBS_Types_Bases, "Bottom"); + IMPORT_CONSTANT(RBS_Types_Bases_Class, RBS_Types_Bases, "Class"); + IMPORT_CONSTANT(RBS_Types_Bases_Instance, RBS_Types_Bases, "Instance"); + IMPORT_CONSTANT(RBS_Types_Bases_Nil, RBS_Types_Bases, "Nil"); + IMPORT_CONSTANT(RBS_Types_Bases_Self, RBS_Types_Bases, "Self"); + IMPORT_CONSTANT(RBS_Types_Bases_Top, RBS_Types_Bases, "Top"); + IMPORT_CONSTANT(RBS_Types_Bases_Void, RBS_Types_Bases, "Void"); + IMPORT_CONSTANT(RBS_Types_Block, RBS_Types, "Block"); + IMPORT_CONSTANT(RBS_Types_ClassInstance, RBS_Types, "ClassInstance"); + IMPORT_CONSTANT(RBS_Types_ClassSingleton, RBS_Types, "ClassSingleton"); + IMPORT_CONSTANT(RBS_Types_Function, RBS_Types, "Function"); + IMPORT_CONSTANT(RBS_Types_Function_Param, RBS_Types_Function, "Param"); + IMPORT_CONSTANT(RBS_Types_Interface, RBS_Types, "Interface"); + IMPORT_CONSTANT(RBS_Types_Intersection, RBS_Types, "Intersection"); + IMPORT_CONSTANT(RBS_Types_Literal, RBS_Types, "Literal"); + IMPORT_CONSTANT(RBS_Types_Optional, RBS_Types, "Optional"); + IMPORT_CONSTANT(RBS_Types_Proc, RBS_Types, "Proc"); + IMPORT_CONSTANT(RBS_Types_Record, RBS_Types, "Record"); + IMPORT_CONSTANT(RBS_Types_Tuple, RBS_Types, "Tuple"); + IMPORT_CONSTANT(RBS_Types_Union, RBS_Types, "Union"); + IMPORT_CONSTANT(RBS_Types_Variable, RBS_Types, "Variable"); + IMPORT_CONSTANT(RBS_MethodType, RBS, "MethodType"); } From b889936567d0c12c4413dfed09e0f4ae5ebfe1af Mon Sep 17 00:00:00 2001 From: ksss Date: Wed, 27 Sep 2023 22:29:24 +0900 Subject: [PATCH 031/101] Add testing code for pp with modern style --- test/stdlib/Kernel_test.rb | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/test/stdlib/Kernel_test.rb b/test/stdlib/Kernel_test.rb index c453b6aac9..6e455bfe61 100644 --- a/test/stdlib/Kernel_test.rb +++ b/test/stdlib/Kernel_test.rb @@ -941,10 +941,10 @@ def test_define_singleton_method Object.instance_method(:to_s) ) end - + def test_respond_to_missing? obj = Object.new - + # The default implementation always returns `false` regardless of the args, # let alone their types; though overrides only have to support Symbol + bool assert_send_type( @@ -952,4 +952,20 @@ def test_respond_to_missing? obj, :respond_to_missing?, :to_s, true ) end + + def test_pp + original_stdout = $stdout + $stdout = StringIO.new + + assert_send_type "() -> nil", + self, :pp + assert_send_type "(123) -> 123", + self, :pp, 123 + assert_send_type "(123, :foo) -> [123, :foo]", + self, :pp, 123, :foo + assert_send_type "(123, :foo, nil) -> [123, :foo, nil]", + self, :pp, 123, :foo, nil + ensure + $stdout = original_stdout + end end From af4b0cc0ff2a3cfd225d4af28ad75561c71c0231 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 06:11:10 +0000 Subject: [PATCH 032/101] Bump rbs from 3.2.1 to 3.2.2 in /steep Bumps [rbs](https://github.com/ruby/rbs) from 3.2.1 to 3.2.2. - [Release notes](https://github.com/ruby/rbs/releases) - [Changelog](https://github.com/ruby/rbs/blob/master/CHANGELOG.md) - [Commits](https://github.com/ruby/rbs/compare/v3.2.1...v3.2.2) --- updated-dependencies: - dependency-name: rbs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- steep/Gemfile | 2 +- steep/Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/steep/Gemfile b/steep/Gemfile index dce7aa87cf..41b52a8163 100644 --- a/steep/Gemfile +++ b/steep/Gemfile @@ -1,4 +1,4 @@ source "https://rubygems.org" -gem "rbs", "~> 3.2.1" +gem "rbs", "~> 3.2.2" gem "steep", "~> 1.5.3" diff --git a/steep/Gemfile.lock b/steep/Gemfile.lock index 7f8ef48463..8bc58b79f7 100644 --- a/steep/Gemfile.lock +++ b/steep/Gemfile.lock @@ -28,7 +28,7 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - rbs (3.2.1) + rbs (3.2.2) securerandom (0.2.2) steep (1.5.3) activesupport (>= 5.1) @@ -56,7 +56,7 @@ PLATFORMS ruby DEPENDENCIES - rbs (~> 3.2.1) + rbs (~> 3.2.2) steep (~> 1.5.3) BUNDLED WITH From 56e4a5232586cb0837f17af84d20591ad475cd64 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Tue, 12 Sep 2023 02:46:10 +0900 Subject: [PATCH 033/101] core: Add Enumerator.produce Add the signature for Enumerator.produce https://bugs.ruby-lang.org/issues/14781 --- core/enumerator.rbs | 36 ++++++++++++++++++++++++++++++++++ test/stdlib/Enumerator_test.rb | 7 +++++++ 2 files changed, 43 insertions(+) diff --git a/core/enumerator.rbs b/core/enumerator.rbs index 9187574b4f..6b202e520a 100644 --- a/core/enumerator.rbs +++ b/core/enumerator.rbs @@ -124,6 +124,42 @@ class Enumerator[unchecked out Elem, out Return] < Object include Enumerable[Elem] + # + # Creates an infinite enumerator from any block, just called over and over. The + # result of the previous iteration is passed to the next one. If `initial` is + # provided, it is passed to the first iteration, and becomes the first element + # of the enumerator; if it is not provided, the first iteration receives `nil`, + # and its result becomes the first element of the iterator. + # + # Raising StopIteration from the block stops an iteration. + # + # Enumerator.produce(1, &:succ) # => enumerator of 1, 2, 3, 4, .... + # + # Enumerator.produce { rand(10) } # => infinite random number sequence + # + # ancestors = Enumerator.produce(node) { |prev| node = prev.parent or raise StopIteration } + # enclosing_section = ancestors.find { |n| n.type == :section } + # + # Using ::produce together with Enumerable methods like Enumerable#detect, + # Enumerable#slice_after, Enumerable#take_while can provide Enumerator-based + # alternatives for `while` and `until` cycles: + # + # # Find next Tuesday + # require "date" + # Enumerator.produce(Date.today, &:succ).detect(&:tuesday?) + # + # # Simple lexer: + # require "strscan" + # scanner = StringScanner.new("7+38/6") + # PATTERN = %r{\d+|[-/+*]} + # Enumerator.produce { scanner.scan(PATTERN) }.slice_after { scanner.eos? }.first + # # => ["7", "+", "38", "/", "6"] + # + def self.produce: (?untyped initial) { (untyped prev) -> untyped } -> Enumerator[untyped, bot] + # # True if the `version` string matches RubyGems' requirements. # - def self.correct?: (_ToS & Kernel version) -> bool + def self.correct?: (_ToS version) -> bool # # Sets or returns default options for the JSON.load method. Initially: diff --git a/stdlib/pathname/0/pathname.rbs b/stdlib/pathname/0/pathname.rbs index 92f80e5834..146b48c9ab 100644 --- a/stdlib/pathname/0/pathname.rbs +++ b/stdlib/pathname/0/pathname.rbs @@ -1084,7 +1084,7 @@ class Pathname # Note that this method does not handle situations where the case sensitivity of # the filesystem in use differs from the operating system default. # - def relative_path_from: (Pathname | (string & _IsA) base_directory) -> Pathname + def relative_path_from: (Pathname | string base_directory) -> Pathname # - # OpenTimeout, a subclass of Timeout::Error, is raised if a connection cannot be - # created within the open_timeout. - # - class OpenTimeout < Timeout::Error - end - - # - # ReadTimeout, a subclass of Timeout::Error, is raised if a chunk of the - # response cannot be read within the read_timeout. - # - class ReadTimeout < Timeout::Error - end - - # - # WriteTimeout, a subclass of Timeout::Error, is raised if a chunk of the - # response cannot be written within the write_timeout. Not raised on Windows. - # - class WriteTimeout < Timeout::Error - end - # # Class Net::HTTP provides a rich library that implements the client in a # client-server model that uses the HTTP request-response protocol. For diff --git a/stdlib/net-protocol/0/manifest.yaml b/stdlib/net-protocol/0/manifest.yaml new file mode 100644 index 0000000000..76f5f2209d --- /dev/null +++ b/stdlib/net-protocol/0/manifest.yaml @@ -0,0 +1,2 @@ +dependencies: + - name: timeout diff --git a/stdlib/net-protocol/0/net-protocol.rbs b/stdlib/net-protocol/0/net-protocol.rbs new file mode 100644 index 0000000000..e6416afd54 --- /dev/null +++ b/stdlib/net-protocol/0/net-protocol.rbs @@ -0,0 +1,56 @@ +module Net + class Protocol + VERSION: String + end + + class ProtocolError < StandardError + end + + class ProtoSyntaxError < ProtocolError + end + + class ProtoFatalError < ProtocolError + end + + class ProtoUnknownError < ProtocolError + end + + class ProtoServerError < ProtocolError + end + + class ProtoAuthError < ProtocolError + end + + class ProtoCommandError < ProtocolError + end + + class ProtoRetriableError < ProtocolError + end + + class HTTPBadResponse < StandardError + end + + class HTTPHeaderSyntaxError < StandardError + end + + # + # OpenTimeout, a subclass of Timeout::Error, is raised if a connection cannot be + # created within the open_timeout. + # + class OpenTimeout < Timeout::Error + end + + # + # ReadTimeout, a subclass of Timeout::Error, is raised if a chunk of the + # response cannot be read within the read_timeout. + # + class ReadTimeout < Timeout::Error + end + + # + # WriteTimeout, a subclass of Timeout::Error, is raised if a chunk of the + # response cannot be written within the write_timeout. Not raised on Windows. + # + class WriteTimeout < Timeout::Error + end +end From 99cdd9122cbfaad5e27aa3792133aba45e6d2b37 Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 6 Oct 2023 08:43:42 +0900 Subject: [PATCH 044/101] Add --autoload option It allows objects from autoload destinations to be treated as analysis targets. --- lib/rbs/cli.rb | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/rbs/cli.rb b/lib/rbs/cli.rb index d348ecda8b..5820519c81 100644 --- a/lib/rbs/cli.rb +++ b/lib/rbs/cli.rb @@ -648,6 +648,7 @@ def run_prototype(args, options) todo = false owners_included = [] outline = false + autoload = false OptionParser.new do |opts| opts.banner = < void } -> void + autoloader = ->(&block) { + if autoload + hook = Module.new do + def autoload(name, path) + super + end + end + ::Module.prepend(hook) + + arguments = [] + TracePoint.new(:call) do |tp| + base = tp.self + name = (tp.binding or raise).local_variable_get(:name) + arguments << [base, name] + end.enable(target: hook.instance_method(:autoload), &block) + arguments.each do |(base, name)| + begin + base.const_get(name) + rescue LoadError, StandardError + end + end + else + block.call + end + } + autoloader.call do + require_libs.each do |lib| + require(lib) + end + relative_libs.each do |lib| + eval("require_relative(lib)", binding, "rbs") + end end runtime = Prototype::Runtime.new(patterns: args, env: env, merge: merge, todo: todo, owners_included: owners_included) From cbb266607feb0f62e9bff9bfa795c4f814e66809 Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 6 Oct 2023 09:42:41 +0900 Subject: [PATCH 045/101] Support Kernel#autoload --- lib/rbs/cli.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/rbs/cli.rb b/lib/rbs/cli.rb index 5820519c81..cb1e75c8a1 100644 --- a/lib/rbs/cli.rb +++ b/lib/rbs/cli.rb @@ -701,13 +701,15 @@ def autoload(name, path) end end ::Module.prepend(hook) + ::Kernel.prepend(hook) arguments = [] TracePoint.new(:call) do |tp| - base = tp.self + base = tp.self.kind_of?(Module) ? tp.self : Kernel name = (tp.binding or raise).local_variable_get(:name) arguments << [base, name] end.enable(target: hook.instance_method(:autoload), &block) + arguments.each do |(base, name)| begin base.const_get(name) From 5565896bc683e286b7ad174d8ab242be3059d28a Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Thu, 12 Oct 2023 03:36:29 +0900 Subject: [PATCH 046/101] prototype rb: Ignore ITER (method call with block) Not to extract incorrect definitions from DSL blocks, `rbs prototype rb` ignores all ITER nodes (method call with block). --- lib/rbs/prototype/rb.rb | 8 +------- test/rbs/rb_prototype_test.rb | 7 ++++++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/rbs/prototype/rb.rb b/lib/rbs/prototype/rb.rb index db820e3570..8c2cec984a 100644 --- a/lib/rbs/prototype/rb.rb +++ b/lib/rbs/prototype/rb.rb @@ -361,13 +361,7 @@ def process(node, decls:, comments:, context:) end when :ITER - method_name = node.children.first.children.first - case method_name - when :refine - # ignore - else - process_children(node, decls: decls, comments: comments, context: context) - end + # ignore when :CDECL const_name = case diff --git a/test/rbs/rb_prototype_test.rb b/test/rbs/rb_prototype_test.rb index b908b196e0..80ed23f128 100644 --- a/test/rbs/rb_prototype_test.rb +++ b/test/rbs/rb_prototype_test.rb @@ -864,7 +864,7 @@ def foo: (untyped x, untyped y, untyped z) -> untyped EOF end - def test_refinements + def test_ITER parser = RB.new rb = <<~'RUBY' @@ -876,6 +876,11 @@ def not_refinements def by_refinements end end + + included do + def in_included + end + end end RUBY From 2760f9d3a51acbbe3a92b506323c9ad6c5d598a8 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Fri, 13 Oct 2023 14:19:00 +0900 Subject: [PATCH 047/101] Add type predicates --- lib/rbs/method_type.rb | 23 ++++++ lib/rbs/types.rb | 170 +++++++++++++++++++++++++++++++++++++++++ sig/method_types.rbs | 6 ++ sig/types.rbs | 26 +++++++ test/rbs/types_test.rb | 62 +++++++++++++++ 5 files changed, 287 insertions(+) diff --git a/lib/rbs/method_type.rb b/lib/rbs/method_type.rb index e07d75e5e6..67d5ade3b8 100644 --- a/lib/rbs/method_type.rb +++ b/lib/rbs/method_type.rb @@ -86,6 +86,9 @@ def each_type(&block) type.each_type(&block) self.block&.yield_self do |b| b.type.each_type(&block) + if b.self_type + yield b.self_type + end end else enum_for :each_type @@ -114,5 +117,25 @@ def to_s def type_param_names type_params.map(&:name) end + + def has_self_type? + each_type.any? {|type| type.has_self_type? } + end + + def has_classish_type? + each_type.any? {|type| type.has_classish_type? } + end + + def with_nonreturn_void? + if type.with_nonreturn_void? + true + else + if block = block() + block.type.with_nonreturn_void? || block.self_type&.with_nonreturn_void? || false + else + false + end + end + end end end diff --git a/lib/rbs/types.rb b/lib/rbs/types.rb index b468e74383..61fdc72a42 100644 --- a/lib/rbs/types.rb +++ b/lib/rbs/types.rb @@ -90,6 +90,18 @@ def to_s(level = 0) raise "Unexpected base type: #{inspect}" end end + + def has_self_type? + self.is_a?(Types::Bases::Self) + end + + def has_classish_type? + self.is_a?(Bases::Instance) || self.is_a?(Bases::Class) + end + + def with_nonreturn_void? + self.is_a?(Bases::Void) + end end class Bool < Base; end @@ -162,6 +174,18 @@ def to_s(level = 0) end include EmptyEachType + + def has_self_type? + false + end + + def has_classish_type? + false + end + + def with_nonreturn_void? + false + end end class ClassSingleton @@ -202,6 +226,18 @@ def map_type_name location: location ) end + + def has_self_type? + false + end + + def has_classish_type? + false + end + + def with_nonreturn_void? + false + end end module Application @@ -241,6 +277,25 @@ def each_type(&block) enum_for :each_type end end + + def has_self_type? + each_type.any? {|type| type.has_self_type? } + end + + def has_classish_type? + each_type.any? {|type| type.has_classish_type? } + end + + def with_nonreturn_void? + each_type.any? do |type| + if type.is_a?(Bases::Void) + # `void` in immediate generics parameter is allowed + false + else + type.with_nonreturn_void? + end + end + end end class Interface @@ -436,6 +491,18 @@ def map_type(&block) enum_for :map_type end end + + def has_self_type? + each_type.any? {|type| type.has_self_type? } + end + + def has_classish_type? + each_type.any? {|type| type.has_classish_type? } + end + + def with_nonreturn_void? + each_type.any? {|type| type.with_nonreturn_void? } + end end class Record @@ -512,6 +579,18 @@ def map_type(&block) enum_for :map_type end end + + def has_self_type? + each_type.any? {|type| type.has_self_type? } + end + + def has_classish_type? + each_type.any? {|type| type.has_classish_type? } + end + + def with_nonreturn_void? + each_type.any? {|type| type.with_nonreturn_void? } + end end class Optional @@ -582,6 +661,18 @@ def map_type(&block) enum_for :map_type end end + + def has_self_type? + each_type.any? {|type| type.has_self_type? } + end + + def has_classish_type? + each_type.any? {|type| type.has_classish_type? } + end + + def with_nonreturn_void? + each_type.any? {|type| type.with_nonreturn_void? } + end end class Union @@ -650,6 +741,18 @@ def map_type_name(&block) location: location ) end + + def has_self_type? + each_type.any? {|type| type.has_self_type? } + end + + def has_classish_type? + each_type.any? {|type| type.has_classish_type? } + end + + def with_nonreturn_void? + each_type.any? {|type| type.with_nonreturn_void? } + end end class Intersection @@ -719,6 +822,18 @@ def map_type_name(&block) location: location ) end + + def has_self_type? + each_type.any? {|type| type.has_self_type? } + end + + def has_classish_type? + each_type.any? {|type| type.has_classish_type? } + end + + def with_nonreturn_void? + each_type.any? {|type| type.with_nonreturn_void? } + end end class Function @@ -1029,6 +1144,26 @@ def has_keyword? false end end + + def has_self_type? + each_type.any? {|type| type.has_self_type? } + end + + def has_classish_type? + each_type.any? {|type| type.has_classish_type? } + end + + def with_nonreturn_void? + if each_param.any? {|param| param.type.with_nonreturn_void? } + true + else + if return_type.is_a?(Bases::Void) + false + else + return_type.with_nonreturn_void? + end + end + end end class Block @@ -1155,6 +1290,9 @@ def each_type(&block) if block type.each_type(&block) self.block&.type&.each_type(&block) + if self_type = self.block&.self_type + yield self_type + end else enum_for :each_type end @@ -1181,6 +1319,26 @@ def map_type(&block) enum_for :map_type end end + + def has_self_type? + each_type.any? {|type| type.has_self_type? } + end + + def has_classish_type? + each_type.any? {|type| type.has_classish_type? } + end + + def with_nonreturn_void? + if type.with_nonreturn_void? + true + else + if block = block() + block.type.with_nonreturn_void? || block.self_type&.with_nonreturn_void? || false + else + false + end + end + end end class Literal @@ -1214,6 +1372,18 @@ def to_json(state = _ = nil) def to_s(level = 0) literal.inspect end + + def has_self_type? + false + end + + def has_classish_type? + false + end + + def with_nonreturn_void? + false + end end end end diff --git a/sig/method_types.rbs b/sig/method_types.rbs index dd03f2b8cb..1e81746ba4 100644 --- a/sig/method_types.rbs +++ b/sig/method_types.rbs @@ -48,5 +48,11 @@ module RBS def to_s: () -> String def type_param_names: () -> Array[Symbol] + + def has_self_type?: () -> bool + + def has_classish_type?: () -> bool + + def with_nonreturn_void?: () -> bool end end diff --git a/sig/types.rbs b/sig/types.rbs index 1c1e150de7..1e7091037d 100644 --- a/sig/types.rbs +++ b/sig/types.rbs @@ -41,6 +41,20 @@ module RBS # ``` # def to_s: (?Integer level) -> String + + # Returns `true` if it has `self` type + # + def has_self_type?: () -> bool + + # Returns `true` if it has `instance` or `class` types + def has_classish_type?: () -> bool + + # Returns `true` if it has `void` types other than *return* position + # + # * The function return type is a return position (`() -> void`) + # * Generic parameter is a return position (`Enumerator[Integer, void]`) + # + def with_nonreturn_void?: () -> bool end # t represents union of all possible types. @@ -191,6 +205,12 @@ module RBS def each_type: () { (t) -> void } -> void | () -> Enumerator[t, void] + + def has_self_type?: () -> bool + + def has_classish_type?: () -> bool + + def with_nonreturn_void?: () -> bool end class Interface @@ -412,6 +432,12 @@ module RBS def amap: [A, B] (Array[A]) { (A) -> B } -> Array[B] def hmapv: [X, Y, Z] (Hash[X, Y]) { (Y) -> Z } -> Hash[X, Z] + + def has_self_type?: () -> bool + + def has_classish_type?: () -> bool + + def with_nonreturn_void?: () -> bool end class Block diff --git a/test/rbs/types_test.rb b/test/rbs/types_test.rb index a2b7967b35..94b51b09ec 100644 --- a/test/rbs/types_test.rb +++ b/test/rbs/types_test.rb @@ -31,4 +31,66 @@ def test_to_s assert_equal "^(bool flag, ?untyped, *Symbol, name: String, ?email: nil, **Symbol) -> void", parse_type("^(bool flag, ?untyped, *Symbol, name: String, ?email: nil, **Symbol) -> void").to_s assert_equal "^(untyped untyped, untyped footype) -> void", parse_type("^(untyped `untyped`, untyped footype) -> void").to_s end + + def test_has_self_type? + [ + "self", + "[self]", + "Array[self]", + "^(self) -> void", + "^() { () [self: self] -> void } -> void" + ].each do |str| + type = parse_type(str) + assert_predicate type, :has_self_type? + end + + [ + "Integer", + "^() { () [self: untyped] -> void } -> void" + ].each do |str| + type = parse_type(str) + refute_predicate type, :has_self_type? + end + end + + def test_has_classish_type? + [ + "instance", + "class", + "class?", + "^() -> instance", + "^() { () [self: class] -> void } -> void" + ].each do |str| + type = parse_type(str) + assert_predicate type, :has_classish_type? + end + + [ + "Integer", + "^() { () [self: untyped] -> void } -> void" + ].each do |str| + type = parse_type(str) + refute_predicate type, :has_classish_type? + end + end + + def test_with_nonreturn_void? + [ + "void", + "[void]", + "void?" + ].each do |str| + type = parse_type(str) + assert_predicate type, :with_nonreturn_void? + end + + [ + "^() -> void", + "[Ineger, String]", + "Enumerator[Integer, void]" + ].each do |str| + type = parse_type(str) + refute_predicate type, :with_nonreturn_void? + end + end end From 879134d3e0d9de3b2eadfaf2b2686bd291fd5bb9 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 15 Oct 2023 20:49:15 +0900 Subject: [PATCH 048/101] core: Kernel.fail is able to accept keyword arguments For compatibility, Kernel.fail (as kwnon as raise) is able to accept keyword arguments. It's not undocumented in the Ruby language documentation, but it's surely mentioned in the Ruby's spec. refs: https://github.com/ruby/ruby/blob/v3_2_0/spec/ruby/shared/kernel/raise.rb#L38-L50 --- core/kernel.rbs | 1 + test/stdlib/Kernel_test.rb | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/core/kernel.rbs b/core/kernel.rbs index 1bce77b2a4..138118d93c 100644 --- a/core/kernel.rbs +++ b/core/kernel.rbs @@ -844,6 +844,7 @@ module Kernel : BasicObject def self?.fail: () -> bot | (string message, ?cause: Exception?) -> bot | (_Exception exception, ?_ToS? message, ?String | Array[String] | nil backtrace, ?cause: Exception?) -> bot + | (_Exception exception, ?cause: Exception?, **untyped) -> bot # + # Outputs *objs* to STDOUT as JSON strings in the shortest form, that is in one + # line. + # + def j: (*_ToJson) -> nil + + # + # Outputs *objs* to STDOUT as JSON strings in a pretty format, with indentation + # and over many lines. + # + def jj: (*_ToJson) -> nil + + # + # If *object* is string-like, parse the string and return the parsed result as a + # Ruby data structure. Otherwise, generate a JSON text from the Ruby data + # structure object and return it. + # + # The *opts* argument is passed through to generate/parse respectively. See + # generate and parse for their documentation. + # + def JSON: (string source, ?json_options opts) -> untyped + | (_ToJson obj, ?json_options opts) -> String +end + %a{annotate:rdoc:skip} class Object # Converts this object to a string (calling #to_s), converts diff --git a/test/stdlib/json/JSONKernel_test.rb b/test/stdlib/json/JSONKernel_test.rb new file mode 100644 index 0000000000..b1686fb766 --- /dev/null +++ b/test/stdlib/json/JSONKernel_test.rb @@ -0,0 +1,36 @@ +require_relative "../test_helper" +require "json" + +class JSONKernelInstanceTest < Test::Unit::TestCase + include TypeAssertions + + library "json" + testing "::Kernel" + + def silent + orig_stdout = $stdout + $stdout = StringIO.new + yield + ensure + $stdout = orig_stdout + end + + def test_j + silent do + assert_send_type("(Integer) -> nil", self, :j, 1) + assert_send_type("(Array[Integer]) -> nil", self, :j, [1, 2, 3]) + end + end + + def test_jj + silent do + assert_send_type("(Integer) -> nil", self, :jj, 1) + assert_send_type("(Array[Integer]) -> nil", self, :jj, [1, 2, 3]) + end + end + + def test_JSON + assert_send_type("(String) -> Hash[String, Integer]", self, :JSON, '{"a": 1}') + assert_send_type("(Array[Integer]) -> String", self, :JSON, [1, 2, 3]) + end +end From 07a52e9182e4b83183c9935599daf004df5e05bc Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Sat, 21 Oct 2023 20:16:24 +0900 Subject: [PATCH 063/101] Suppress already initialized constant warnings --- test/stdlib/ARGF_test.rb | 2 +- test/stdlib/constants_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/stdlib/ARGF_test.rb b/test/stdlib/ARGF_test.rb index 33eb459959..fe7c454cd9 100644 --- a/test/stdlib/ARGF_test.rb +++ b/test/stdlib/ARGF_test.rb @@ -4,7 +4,7 @@ # initialize temporary class module RBS module Unnamed - ARGFClass = ARGF.class + ARGFClass ||= ARGF.class end end diff --git a/test/stdlib/constants_test.rb b/test/stdlib/constants_test.rb index 0792d9de8d..0977315029 100644 --- a/test/stdlib/constants_test.rb +++ b/test/stdlib/constants_test.rb @@ -3,7 +3,7 @@ # initialize temporary class module RBS module Unnamed - ARGFClass = ARGF.class + ARGFClass ||= ARGF.class end end From 2f8ecc51917efed1020b945fbc193902c91869a6 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Sat, 21 Oct 2023 20:17:16 +0900 Subject: [PATCH 064/101] Suppress warning: ambiguity between regexp and two divisions --- test/rbs/cli_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/rbs/cli_test.rb b/test/rbs/cli_test.rb index 3fc2ce6087..4fe9e1348a 100644 --- a/test/rbs/cli_test.rb +++ b/test/rbs/cli_test.rb @@ -435,7 +435,7 @@ class Foo error = assert_raises RuntimeError do cli.run(["-I", dir, "validate"]) end - assert_match /void|self|instance|class/, error.message + assert_match(/void|self|instance|class/, error.message) end end end From e8367318a23d7b6e64fb7e9ab6d39fd58b1dd296 Mon Sep 17 00:00:00 2001 From: MSP-Greg Date: Sat, 21 Oct 2023 23:13:41 -0500 Subject: [PATCH 065/101] version.rb - update from 3.2.0 to 3.2.2 --- lib/rbs/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rbs/version.rb b/lib/rbs/version.rb index 6c1055b048..9e9f566c16 100644 --- a/lib/rbs/version.rb +++ b/lib/rbs/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module RBS - VERSION = "3.2.0" + VERSION = "3.2.2" end From d35c8c5affe696b88c64184354a490719a17a2bf Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 22 Oct 2023 14:26:09 +0900 Subject: [PATCH 066/101] stdlib: Update type for URI.join URI.join takes not only strings, but also URI objects. Therefore it would be better to update its signature. Internally, arguments will be converted to URI objects before concatenating. https://github.com/ruby/ruby/blob/v3_2_2/lib/uri/rfc3986_parser.rb#L107-L116 --- stdlib/uri/0/common.rbs | 2 +- test/stdlib/URI_test.rb | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/stdlib/uri/0/common.rbs b/stdlib/uri/0/common.rbs index a68b31feb4..b04a4895a3 100644 --- a/stdlib/uri/0/common.rbs +++ b/stdlib/uri/0/common.rbs @@ -278,7 +278,7 @@ module URI # URI.join('http://example.com', '/foo/', 'bar') # # => # # - def self.join: (String str, *String strs) -> URI::Generic + def self.join: (_ToStr | URI::Generic str, *_ToStr | URI::Generic strs) -> URI::Generic # + # Allows the opening of various resources including URIs. + # + # If the first argument responds to the 'open' method, 'open' is called on it + # with the rest of the arguments. + # + # If the first argument is a string that begins with `(protocol)://`, it is + # parsed by URI.parse. If the parsed object responds to the 'open' method, + # 'open' is called on it with the rest of the arguments. + # + # Otherwise, Kernel#open is called. + # + # OpenURI::OpenRead#open provides URI::HTTP#open, URI::HTTPS#open and + # URI::FTP#open, Kernel#open. + # + # We can accept URIs and strings that begin with http://, https:// and ftp://. + # In these cases, the opened file object is extended by OpenURI::Meta. + # + def self.open: (String name, ?String mode, ?Integer perm, ?untyped options) -> (StringIO & OpenURI::Meta | Tempfile & OpenURI::Meta) + | [T] (String name, ?String mode, ?Integer perm, ?untyped options) { (StringIO | Tempfile) -> T } -> T +end + +# +# OpenURI is an easy-to-use wrapper for Net::HTTP, Net::HTTPS and Net::FTP. +# +# ## Example +# +# It is possible to open an http, https or ftp URL as though it were a file: +# +# URI.open("http://www.ruby-lang.org/") {|f| +# f.each_line {|line| p line} +# } +# +# The opened file has several getter methods for its meta-information, as +# follows, since it is extended by OpenURI::Meta. +# +# URI.open("http://www.ruby-lang.org/en") {|f| +# f.each_line {|line| p line} +# p f.base_uri # +# p f.content_type # "text/html" +# p f.charset # "iso-8859-1" +# p f.content_encoding # [] +# p f.last_modified # Thu Dec 05 02:45:02 UTC 2002 +# } +# +# Additional header fields can be specified by an optional hash argument. +# +# URI.open("http://www.ruby-lang.org/en/", +# "User-Agent" => "Ruby/#{RUBY_VERSION}", +# "From" => "foo@bar.invalid", +# "Referer" => "http://www.ruby-lang.org/") {|f| +# # ... +# } +# +# The environment variables such as http_proxy, https_proxy and ftp_proxy are in +# effect by default. Here we disable proxy: +# +# URI.open("http://www.ruby-lang.org/en/", :proxy => nil) {|f| +# # ... +# } +# +# See OpenURI::OpenRead.open and URI.open for more on available options. +# +# URI objects can be opened in a similar way. +# +# uri = URI.parse("http://www.ruby-lang.org/en/") +# uri.open {|f| +# # ... +# } +# +# URI objects can be read directly. The returned string is also extended by +# OpenURI::Meta. +# +# str = uri.read +# p str.base_uri +# +# Author +# : Tanaka Akira +# +module OpenURI + # + # Mixin for holding meta-information. + # + module Meta + # + # returns an Array that consists of status code and message. + # + attr_accessor status: [ String, String ] + + # + # returns a URI that is the base of relative URIs in the data. It may differ + # from the URI supplied by a user due to redirection. + # + attr_accessor base_uri: URI::Generic + + # + # returns a Hash that represents header fields. The Hash keys are downcased for + # canonicalization. The Hash values are a field body. If there are multiple + # field with same field name, the field values are concatenated with a comma. + # + attr_reader meta: Hash[String, String] + + # + # returns a Time that represents the Last-Modified field. + # + def last_modified: () -> Time? + + # + # returns "type/subtype" which is MIME Content-Type. It is downcased for + # canonicalization. Content-Type parameters are stripped. + # + def content_type: () -> String + + def charet: () -> String? + + # + # Returns a list of encodings in Content-Encoding field as an array of strings. + # + # The encodings are downcased for canonicalization. + # + def content_encoding: () -> Array[String] + end + + # + # Mixin for HTTP and FTP URIs. + # + module OpenRead + # + # OpenURI::OpenRead#open provides `open' for URI::HTTP and URI::FTP. + # + # OpenURI::OpenRead#open takes optional 3 arguments as: + # + # OpenURI::OpenRead#open([mode [, perm]] [, options]) [{|io| ... }] + # + # OpenURI::OpenRead#open returns an IO-like object if block is not given. + # Otherwise it yields the IO object and return the value of the block. The IO + # object is extended with OpenURI::Meta. + # + # `mode` and `perm` are the same as Kernel#open. + # + # However, `mode` must be read mode because OpenURI::OpenRead#open doesn't + # support write mode (yet). Also `perm` is ignored because it is meaningful only + # for file creation. + # + # `options` must be a hash. + # + # Each option with a string key specifies an extra header field for HTTP. I.e., + # it is ignored for FTP without HTTP proxy. + # + # The hash may include other options, where keys are symbols: + # + # :proxy + # : Synopsis: + # :proxy => "http://proxy.foo.com:8000/" + # :proxy => URI.parse("http://proxy.foo.com:8000/") + # :proxy => true + # :proxy => false + # :proxy => nil + # + # If :proxy option is specified, the value should be String, URI, boolean or + # nil. + # + # When String or URI is given, it is treated as proxy URI. + # + # When true is given or the option itself is not specified, environment + # variable `scheme_proxy' is examined. `scheme' is replaced by `http', + # `https' or `ftp'. + # + # When false or nil is given, the environment variables are ignored and + # connection will be made to a server directly. + # + # :proxy_http_basic_authentication + # : Synopsis: + # :proxy_http_basic_authentication => + # ["http://proxy.foo.com:8000/", "proxy-user", "proxy-password"] + # :proxy_http_basic_authentication => + # [URI.parse("http://proxy.foo.com:8000/"), + # "proxy-user", "proxy-password"] + # + # If :proxy option is specified, the value should be an Array with 3 + # elements. It should contain a proxy URI, a proxy user name and a proxy + # password. The proxy URI should be a String, an URI or nil. The proxy + # user name and password should be a String. + # + # If nil is given for the proxy URI, this option is just ignored. + # + # If :proxy and :proxy_http_basic_authentication is specified, ArgumentError + # is raised. + # + # :http_basic_authentication + # : Synopsis: + # :http_basic_authentication=>[user, password] + # + # If :http_basic_authentication is specified, the value should be an array + # which contains 2 strings: username and password. It is used for HTTP Basic + # authentication defined by RFC 2617. + # + # :content_length_proc + # : Synopsis: + # :content_length_proc => lambda {|content_length| ... } + # + # If :content_length_proc option is specified, the option value procedure is + # called before actual transfer is started. It takes one argument, which is + # expected content length in bytes. + # + # If two or more transfers are performed by HTTP redirection, the procedure + # is called only once for the last transfer. + # + # When expected content length is unknown, the procedure is called with nil. + # This happens when the HTTP response has no Content-Length header. + # + # :progress_proc + # : Synopsis: + # :progress_proc => lambda {|size| ...} + # + # If :progress_proc option is specified, the proc is called with one + # argument each time when `open' gets content fragment from network. The + # argument `size` is the accumulated transferred size in bytes. + # + # If two or more transfer is done by HTTP redirection, the procedure is + # called only one for a last transfer. + # + # :progress_proc and :content_length_proc are intended to be used for + # progress bar. For example, it can be implemented as follows using + # Ruby/ProgressBar. + # + # pbar = nil + # open("http://...", + # :content_length_proc => lambda {|t| + # if t && 0 < t + # pbar = ProgressBar.new("...", t) + # pbar.file_transfer_mode + # end + # }, + # :progress_proc => lambda {|s| + # pbar.set s if pbar + # }) {|f| ... } + # + # :read_timeout + # : Synopsis: + # :read_timeout=>nil (no timeout) + # :read_timeout=>10 (10 second) + # + # :read_timeout option specifies a timeout of read for http connections. + # + # :open_timeout + # : Synopsis: + # :open_timeout=>nil (no timeout) + # :open_timeout=>10 (10 second) + # + # :open_timeout option specifies a timeout of open for http connections. + # + # :ssl_ca_cert + # : Synopsis: + # :ssl_ca_cert=>filename or an Array of filenames + # + # :ssl_ca_cert is used to specify CA certificate for SSL. If it is given, + # default certificates are not used. + # + # :ssl_verify_mode + # : Synopsis: + # :ssl_verify_mode=>mode + # + # :ssl_verify_mode is used to specify openssl verify mode. + # + # :ssl_min_version + # : Synopsis: + # :ssl_min_version=>:TLS1_2 + # + # :ssl_min_version option specifies the minimum allowed SSL/TLS protocol + # version. See also OpenSSL::SSL::SSLContext#min_version=. + # + # :ssl_max_version + # : Synopsis: + # :ssl_max_version=>:TLS1_2 + # + # :ssl_max_version option specifies the maximum allowed SSL/TLS protocol + # version. See also OpenSSL::SSL::SSLContext#max_version=. + # + # :ftp_active_mode + # : Synopsis: + # :ftp_active_mode=>bool + # + # `:ftp_active_mode => true` is used to make ftp active mode. Ruby 1.9 uses + # passive mode by default. Note that the active mode is default in Ruby 1.8 + # or prior. + # + # :redirect + # : Synopsis: + # :redirect=>bool + # + # `:redirect` is true by default. `:redirect => false` is used to disable + # all HTTP redirects. + # + # OpenURI::HTTPRedirect exception raised on redirection. Using `true` also + # means that redirections between http and ftp are permitted. + # + def open: (*untyped) -> IO + | [T] (*untyped) { (IO) -> T } -> T + + # + # OpenURI::OpenRead#read([ options ]) reads a content referenced by self and + # returns the content as string. The string is extended with OpenURI::Meta. The + # argument `options` is same as OpenURI::OpenRead#open. + # + def read: (untyped options) -> String + end +end + +%a{annotate:rdoc:skip} +module URI + %a{annotate:rdoc:skip} + class HTTP + include OpenURI::OpenRead + end + + # + # FTP URI syntax is defined by RFC1738 section 3.2. + # + # This class will be redesigned because of difference of implementations; the + # structure of its path. draft-hoffman-ftp-uri-04 is a draft but it is a good + # summary about the de facto spec. + # http://tools.ietf.org/html/draft-hoffman-ftp-uri-04 + # + %a{annotate:rdoc:skip} + class FTP + include OpenURI::OpenRead + end +end diff --git a/test/stdlib/open-uri_test.rb b/test/stdlib/open-uri_test.rb new file mode 100644 index 0000000000..acc9f03c95 --- /dev/null +++ b/test/stdlib/open-uri_test.rb @@ -0,0 +1,16 @@ +require_relative "test_helper" +require "open-uri" + +class OpenURISingletonTest < Test::Unit::TestCase + include TypeAssertions + + library "open-uri" + testing "singleton(::URI)" + + def test_URI_open + assert_send_type "(String) -> StringIO", + URI, :open, "https://www.ruby-lang.org" + assert_send_type "(String) { (StringIO) -> String } -> String", + URI, :open, "https://www.ruby-lang.org" do |io| io.read end + end +end From e13e32e8da69bfd2fffe74a9cd69cf7f020b9fe2 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Thu, 2 Nov 2023 17:14:10 +0900 Subject: [PATCH 089/101] Delete URI::FTP comment --- stdlib/open-uri/0/open-uri.rbs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/stdlib/open-uri/0/open-uri.rbs b/stdlib/open-uri/0/open-uri.rbs index d044b8dc9d..7b6649c088 100644 --- a/stdlib/open-uri/0/open-uri.rbs +++ b/stdlib/open-uri/0/open-uri.rbs @@ -334,14 +334,6 @@ module URI include OpenURI::OpenRead end - # - # FTP URI syntax is defined by RFC1738 section 3.2. - # - # This class will be redesigned because of difference of implementations; the - # structure of its path. draft-hoffman-ftp-uri-04 is a draft but it is a good - # summary about the de facto spec. - # http://tools.ietf.org/html/draft-hoffman-ftp-uri-04 - # %a{annotate:rdoc:skip} class FTP include OpenURI::OpenRead From 7216ab590d9b30e8ba691d22402aba8c592aa061 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Thu, 2 Nov 2023 17:37:29 +0900 Subject: [PATCH 090/101] Print type syntax errors instead of raising error --- lib/rbs/cli.rb | 16 +++++++++++++--- test/rbs/cli_test.rb | 8 ++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/rbs/cli.rb b/lib/rbs/cli.rb index d2e8d9bae9..c94ae11d1c 100644 --- a/lib/rbs/cli.rb +++ b/lib/rbs/cli.rb @@ -466,17 +466,19 @@ def run_validate(args, options) builder = DefinitionBuilder.new(env: env) validator = Validator.new(env: env, resolver: Resolver::TypeNameResolver.new(env)) + syntax_errors = [] #: Array[String] + no_self_type_validator = ->(type) { # @type var type: Types::t | MethodType if type.has_self_type? - raise "#{type.location}: `self` type is not allowed in this context" + syntax_errors << "#{type.location}: `self` type is not allowed in this context" end } no_classish_type_validator = ->(type) { # @type var type: Types::t | MethodType if type.has_classish_type? - raise "#{type.location}: `instance` or `class` type is not allowed in this context" + syntax_errors << "#{type.location}: `instance` or `class` type is not allowed in this context" end } @@ -486,7 +488,7 @@ def run_validate(args, options) next if type.is_a?(Types::Bases::Void) end if type.with_nonreturn_void? - raise "#{type.location}: `void` type is only allowed in return type or generics parameter" + syntax_errors << "#{type.location}: `void` type is only allowed in return type or generics parameter" end } @@ -621,6 +623,14 @@ def run_validate(args, options) no_classish_type_validator[decl.decl.type] void_type_context_validator[decl.decl.type] end + + unless syntax_errors.empty? + syntax_errors.sort! + syntax_errors.uniq! + syntax_errors.each do |message| + stdout.puts message + end + end end def run_constant(args, options) diff --git a/test/rbs/cli_test.rb b/test/rbs/cli_test.rb index 8fede7ffad..70c151b829 100644 --- a/test/rbs/cli_test.rb +++ b/test/rbs/cli_test.rb @@ -432,10 +432,10 @@ class Foo with_cli do |cli| Dir.mktmpdir do |dir| (Pathname(dir) + 'a.rbs').write(rbs) - error = assert_raises RuntimeError do - cli.run(["-I", dir, "validate"]) - end - assert_match(/void|self|instance|class/, error.message) + cli.run(["-I", dir, "validate"]) + + last_lines = stdout.string.lines.last(3) + assert_match(/void|self|instance|class/, last_lines.join("\n")) end end end From 8dc3c2a4191987d2425a03918f11414bf6ec68f7 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Thu, 2 Nov 2023 18:04:34 +0900 Subject: [PATCH 091/101] Fix `Set` types --- core/set.rbs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/set.rbs b/core/set.rbs index 5f4776cb49..60104c8e40 100644 --- a/core/set.rbs +++ b/core/set.rbs @@ -439,7 +439,7 @@ class Set[unchecked out A] # Set[1, 2, 3].disjoint? [3, 4] #=> false # Set[1, 2, 3].disjoint? 4..5 #=> true # - def disjoint?: (self) -> bool + def disjoint?: (_Each[A]) -> bool #