From d9b03c9369001a835b186ee7fd637e7f94d3d64f Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 16 Dec 2025 15:39:00 +0100 Subject: [PATCH 01/14] [ruby/prism] Fix assertions in location_test.rb * assert_raise's 2nd argument is the failure message, shown when the expected exception is not raised. It's not the expected message. See https://github.com/test-unit/test-unit/issues/347 https://github.com/ruby/prism/commit/e3df994d47 --- test/prism/ruby/location_test.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/prism/ruby/location_test.rb b/test/prism/ruby/location_test.rb index 33f844243c0547..5e2ab63802b1f5 100644 --- a/test/prism/ruby/location_test.rb +++ b/test/prism/ruby/location_test.rb @@ -13,19 +13,22 @@ def test_join assert_equal 0, joined.start_offset assert_equal 10, joined.length - assert_raise(RuntimeError, "Incompatible locations") do + e = assert_raise(RuntimeError) do argument.location.join(receiver.location) end + assert_equal "Incompatible locations", e.message other_argument = Prism.parse_statement("1234 + 567").arguments.arguments.first - assert_raise(RuntimeError, "Incompatible sources") do + e = assert_raise(RuntimeError) do other_argument.location.join(receiver.location) end + assert_equal "Incompatible sources", e.message - assert_raise(RuntimeError, "Incompatible sources") do + e = assert_raise(RuntimeError) do receiver.location.join(other_argument.location) end + assert_equal "Incompatible sources", e.message end def test_character_offsets From 76248400b75d42288a5941aa03e2d2e6d4fac057 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Wed, 17 Dec 2025 10:47:43 +0100 Subject: [PATCH 02/14] [ruby/prism] Add Ruby 4.1 as a version specifier https://github.com/ruby/prism/commit/138db9ccc4 --- lib/prism/ffi.rb | 2 ++ lib/prism/prism.gemspec | 2 ++ lib/prism/translation.rb | 1 + lib/prism/translation/parser.rb | 4 +++- lib/prism/translation/parser41.rb | 13 +++++++++++++ lib/prism/translation/parser_current.rb | 2 ++ prism/options.c | 10 ++++++++++ prism/options.h | 5 ++++- test/prism/api/parse_test.rb | 3 +++ test/prism/test_helper.rb | 2 +- 10 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 lib/prism/translation/parser41.rb diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb index 7e6103fde775bf..d4c9d60c9aa2a4 100644 --- a/lib/prism/ffi.rb +++ b/lib/prism/ffi.rb @@ -434,6 +434,8 @@ def dump_options_version(version) 2 when /\A3\.5(\.\d+)?\z/, /\A4\.0(\.\d+)?\z/ 3 + when /\A4\.1(\.\d+)?\z/ + 4 else if current raise CurrentVersionError, RUBY_VERSION diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec index 10c2eaad209ed4..d9872f88acffd9 100644 --- a/lib/prism/prism.gemspec +++ b/lib/prism/prism.gemspec @@ -102,6 +102,7 @@ Gem::Specification.new do |spec| "lib/prism/translation/parser34.rb", "lib/prism/translation/parser35.rb", "lib/prism/translation/parser40.rb", + "lib/prism/translation/parser41.rb", "lib/prism/translation/parser/builder.rb", "lib/prism/translation/parser/compiler.rb", "lib/prism/translation/parser/lexer.rb", @@ -125,6 +126,7 @@ Gem::Specification.new do |spec| "rbi/prism/translation/parser34.rbi", "rbi/prism/translation/parser35.rbi", "rbi/prism/translation/parser40.rbi", + "rbi/prism/translation/parser41.rbi", "rbi/prism/translation/ripper.rbi", "rbi/prism/visitor.rbi", "sig/prism.rbs", diff --git a/lib/prism/translation.rb b/lib/prism/translation.rb index 7933b4a7222e93..89c70ee420130f 100644 --- a/lib/prism/translation.rb +++ b/lib/prism/translation.rb @@ -11,6 +11,7 @@ module Translation # steep:ignore autoload :Parser34, "prism/translation/parser34" autoload :Parser35, "prism/translation/parser35" autoload :Parser40, "prism/translation/parser40" + autoload :Parser41, "prism/translation/parser41" autoload :Ripper, "prism/translation/ripper" autoload :RubyParser, "prism/translation/ruby_parser" end diff --git a/lib/prism/translation/parser.rb b/lib/prism/translation/parser.rb index 23245dc383e9e9..fed4ac4cd1f0fd 100644 --- a/lib/prism/translation/parser.rb +++ b/lib/prism/translation/parser.rb @@ -84,7 +84,7 @@ def initialize(builder = Prism::Translation::Parser::Builder.new, parser: Prism) end def version # :nodoc: - 40 + 41 end # The default encoding for Ruby files is UTF-8. @@ -358,6 +358,8 @@ def convert_for_prism(version) "3.4.0" when 35, 40 "4.0.0" + when 41 + "4.1.0" else "latest" end diff --git a/lib/prism/translation/parser41.rb b/lib/prism/translation/parser41.rb new file mode 100644 index 00000000000000..ed819064004606 --- /dev/null +++ b/lib/prism/translation/parser41.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +# :markup: markdown + +module Prism + module Translation + # This class is the entry-point for Ruby 4.1 of `Prism::Translation::Parser`. + class Parser41 < Parser + def version # :nodoc: + 41 + end + end + end +end diff --git a/lib/prism/translation/parser_current.rb b/lib/prism/translation/parser_current.rb index 76d71e940926cc..ac6daf7082e416 100644 --- a/lib/prism/translation/parser_current.rb +++ b/lib/prism/translation/parser_current.rb @@ -12,6 +12,8 @@ module Translation ParserCurrent = Parser34 when /^3\.5\./, /^4\.0\./ ParserCurrent = Parser40 + when /^4\.1\./ + ParserCurrent = Parser41 else # Keep this in sync with released Ruby. parser = Parser34 diff --git a/prism/options.c b/prism/options.c index 4a8953da7d2aac..09d2a65a6cbcf6 100644 --- a/prism/options.c +++ b/prism/options.c @@ -93,6 +93,11 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length return true; } + if (strncmp(version, "4.1", 3) == 0) { + options->version = PM_OPTIONS_VERSION_CRUBY_4_1; + return true; + } + return false; } @@ -111,6 +116,11 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length options->version = PM_OPTIONS_VERSION_CRUBY_4_0; return true; } + + if (strncmp(version, "4.1.", 4) == 0) { + options->version = PM_OPTIONS_VERSION_CRUBY_4_1; + return true; + } } if (length >= 6) { diff --git a/prism/options.h b/prism/options.h index a663c9767e994e..c00c7bf7553a4f 100644 --- a/prism/options.h +++ b/prism/options.h @@ -97,8 +97,11 @@ typedef enum { /** The vendored version of prism in CRuby 4.0.x. */ PM_OPTIONS_VERSION_CRUBY_4_0 = 3, + /** The vendored version of prism in CRuby 4.1.x. */ + PM_OPTIONS_VERSION_CRUBY_4_1 = 4, + /** The current version of prism. */ - PM_OPTIONS_VERSION_LATEST = PM_OPTIONS_VERSION_CRUBY_4_0 + PM_OPTIONS_VERSION_LATEST = PM_OPTIONS_VERSION_CRUBY_4_1 } pm_options_version_t; /** diff --git a/test/prism/api/parse_test.rb b/test/prism/api/parse_test.rb index bb1761109fadbb..bbf28201ffe2b4 100644 --- a/test/prism/api/parse_test.rb +++ b/test/prism/api/parse_test.rb @@ -122,6 +122,9 @@ def test_version assert Prism.parse_success?("1 + 1", version: "4.0") assert Prism.parse_success?("1 + 1", version: "4.0.0") + assert Prism.parse_success?("1 + 1", version: "4.1") + assert Prism.parse_success?("1 + 1", version: "4.1.0") + assert Prism.parse_success?("1 + 1", version: "latest") # Test edge case diff --git a/test/prism/test_helper.rb b/test/prism/test_helper.rb index f78e68e87c107a..43771110b4284f 100644 --- a/test/prism/test_helper.rb +++ b/test/prism/test_helper.rb @@ -241,7 +241,7 @@ def self.windows? end # All versions that prism can parse - SYNTAX_VERSIONS = %w[3.3 3.4 4.0] + SYNTAX_VERSIONS = %w[3.3 3.4 4.0 4.1] # `RUBY_VERSION` with the patch version excluded CURRENT_MAJOR_MINOR = RUBY_VERSION.split(".")[0, 2].join(".") From e2c886dd669dd640dae75e3ac6d7206b74870d1b Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Mon, 1 Dec 2025 21:13:25 +0100 Subject: [PATCH 03/14] [ruby/prism] Reject `p(p a, &block => value)` and similar Redo of https://github.com/ruby/prism/pull/3669 with more tests https://github.com/ruby/prism/commit/48b403ea79 --- prism/prism.c | 26 ++++++++++- test/prism/errors/command_calls_35.txt | 46 +++++++++++++++++++ test/prism/fixtures/command_method_call_3.txt | 19 ++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 test/prism/errors/command_calls_35.txt create mode 100644 test/prism/fixtures/command_method_call_3.txt diff --git a/prism/prism.c b/prism/prism.c index f98032cd73b0b1..4c8ab91f0ef4e6 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -13412,6 +13412,30 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod return contains_keyword_splat; } +static inline bool +argument_allowed_for_bare_hash(pm_parser_t *parser, pm_node_t *argument) { + if (pm_symbol_node_label_p(argument)) { + return true; + } + + switch (PM_NODE_TYPE(argument)) { + case PM_CALL_NODE: { + pm_call_node_t *cast = (pm_call_node_t *) argument; + if (cast->opening_loc.start == NULL && cast->arguments != NULL) { + if (PM_NODE_FLAG_P(cast->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) { + return false; + } + if (cast->block != NULL) { + return false; + } + } + break; + } + default: break; + } + return accept1(parser, PM_TOKEN_EQUAL_GREATER); +} + /** * Append an argument to a list of arguments. */ @@ -13569,7 +13593,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for bool contains_keywords = false; bool contains_keyword_splat = false; - if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) { + if (argument_allowed_for_bare_hash(parser, argument)){ if (parsed_bare_hash) { pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH); } diff --git a/test/prism/errors/command_calls_35.txt b/test/prism/errors/command_calls_35.txt new file mode 100644 index 00000000000000..45f569b117c6c5 --- /dev/null +++ b/test/prism/errors/command_calls_35.txt @@ -0,0 +1,46 @@ +p(p a, x: b => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p(p a, x: => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p(p a, &block => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p(p a do end => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p(p a, *args => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p(p a, **kwargs => value) + ^~ unexpected '=>'; expected a `)` to close the arguments + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it + +p p 1, &block => 2, &block + ^~ unexpected '=>', expecting end-of-input + ^~ unexpected '=>', ignoring it + ^ unexpected ',', expecting end-of-input + ^ unexpected ',', ignoring it + ^ unexpected '&', ignoring it + +p p p 1 => 2 => 3 => 4 + ^~ unexpected '=>', expecting end-of-input + ^~ unexpected '=>', ignoring it + +p[p a, x: b => value] + ^ expected a matching `]` + ^ unexpected ']', expecting end-of-input + ^ unexpected ']', ignoring it + diff --git a/test/prism/fixtures/command_method_call_3.txt b/test/prism/fixtures/command_method_call_3.txt new file mode 100644 index 00000000000000..6de0446aa9be74 --- /dev/null +++ b/test/prism/fixtures/command_method_call_3.txt @@ -0,0 +1,19 @@ +foo(bar 1, key => '2') + +foo(bar 1, KEY => '2') + +foo(bar 1, :key => '2') + +foo(bar 1, { baz: :bat } => '2') + +foo bar - %i[baz] => '2' + +foo(bar {} => '2') + +foo(bar baz {} => '2') + +foo(bar do end => '2') + +foo(1, bar {} => '2') + +foo(1, bar do end => '2') From 5c0c0dd8737c8225f0ebcf0eaf3fb8b71917ee4d Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Thu, 18 Dec 2025 10:10:13 -0500 Subject: [PATCH 04/14] [ruby/prism] Bump to v1.7.0 https://github.com/ruby/prism/commit/21c499d6e4 --- lib/prism/prism.gemspec | 2 +- prism/extension.h | 2 +- prism/templates/lib/prism/serialize.rb.erb | 2 +- prism/version.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec index d9872f88acffd9..2fb5d1d0b308e4 100644 --- a/lib/prism/prism.gemspec +++ b/lib/prism/prism.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "prism" - spec.version = "1.6.0" + spec.version = "1.7.0" spec.authors = ["Shopify"] spec.email = ["ruby@shopify.com"] diff --git a/prism/extension.h b/prism/extension.h index 70017a4ae39ca2..6c3de31adb94d6 100644 --- a/prism/extension.h +++ b/prism/extension.h @@ -1,7 +1,7 @@ #ifndef PRISM_EXT_NODE_H #define PRISM_EXT_NODE_H -#define EXPECTED_PRISM_VERSION "1.6.0" +#define EXPECTED_PRISM_VERSION "1.7.0" #include #include diff --git a/prism/templates/lib/prism/serialize.rb.erb b/prism/templates/lib/prism/serialize.rb.erb index 526be67431f0f0..63f97dddd790b1 100644 --- a/prism/templates/lib/prism/serialize.rb.erb +++ b/prism/templates/lib/prism/serialize.rb.erb @@ -10,7 +10,7 @@ module Prism # The minor version of prism that we are expecting to find in the serialized # strings. - MINOR_VERSION = 6 + MINOR_VERSION = 7 # The patch version of prism that we are expecting to find in the serialized # strings. diff --git a/prism/version.h b/prism/version.h index f202b0f4d72c3a..0b64a70dfff5c0 100644 --- a/prism/version.h +++ b/prism/version.h @@ -14,7 +14,7 @@ /** * The minor version of the Prism library as an int. */ -#define PRISM_VERSION_MINOR 6 +#define PRISM_VERSION_MINOR 7 /** * The patch version of the Prism library as an int. @@ -24,6 +24,6 @@ /** * The version of the Prism library as a constant string. */ -#define PRISM_VERSION "1.6.0" +#define PRISM_VERSION "1.7.0" #endif From fec5363ba6fb541bfe4d9c6101f4faf8ffe90f3b Mon Sep 17 00:00:00 2001 From: git Date: Fri, 19 Dec 2025 00:59:55 +0000 Subject: [PATCH 05/14] Update default gems list at 5c0c0dd8737c8225f0ebcf0eaf3fb8 [ci skip] --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 3d1807beb6100a..3379433f2a72ca 100644 --- a/NEWS.md +++ b/NEWS.md @@ -308,7 +308,7 @@ The following default gems are updated. * openssl 4.0.0 * optparse 0.8.1 * pp 0.6.3 -* prism 1.6.0 +* prism 1.7.0 * psych 5.3.1 * resolv 0.7.0 * stringio 3.2.0 From 68a900e30b4ca1537d7975c3a619fd94fca7b084 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 18 Dec 2025 17:03:15 -0800 Subject: [PATCH 06/14] add news for pack / unpack directives --- NEWS.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS.md b/NEWS.md index 3379433f2a72ca..a5f657fb18f7a3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -87,6 +87,9 @@ Note: We're only listing outstanding class updates. * `Array#rfind` has been added as a more efficient alternative to `array.reverse_each.find` [[Feature #21678]] * `Array#find` has been added as a more efficient override of `Enumerable#find` [[Feature #21678]] + * `Array#pack` accepts a new format `R` and `r` for unpacking unsigned + and signed LEB128 encoded integers. [[Feature #21785]] + * Binding * `Binding#local_variables` does no longer include numbered parameters. @@ -239,6 +242,9 @@ Note: We're only listing outstanding class updates. * `String#strip`, `strip!`, `lstrip`, `lstrip!`, `rstrip`, and `rstrip!` are extended to accept `*selectors` arguments. [[Feature #21552]] + * `String#unpack` accepts a new format `R` and `r` for unpacking unsigned + and signed LEB128 encoded integers. [[Feature #21785]] + * Thread * Introduce support for `Thread#raise(cause:)` argument similar to @@ -545,3 +551,4 @@ A lot of work has gone into making Ractors more stable, performant, and usable. [Feature #21678]: https://bugs.ruby-lang.org/issues/21678 [Bug #21698]: https://bugs.ruby-lang.org/issues/21698 [Feature #21701]: https://bugs.ruby-lang.org/issues/21701 +[Feature #21785]: https://bugs.ruby-lang.org/issues/21785 From 81ad407475149ea47a78875444e0aef5ee4f6635 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Fri, 19 Dec 2025 11:43:58 +0900 Subject: [PATCH 07/14] Fix rbs test failure caused by minitest-6 (#15643) * Fix rbs test failure caused by minitest6 * Bundle minitest-6.0.0 --- common.mk | 2 +- gems/bundled_gems | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common.mk b/common.mk index 50abfeab8a4df6..c0d663f68e5658 100644 --- a/common.mk +++ b/common.mk @@ -1566,7 +1566,7 @@ yes-install-for-test-bundled-gems: yes-update-default-gemspecs $(XRUBY) -C "$(srcdir)" -r./tool/lib/gem_env.rb bin/gem \ install --no-document --conservative \ "hoe" "json-schema:5.1.0" "test-unit-rr" "simplecov" "simplecov-html" "simplecov-json" "rspec" "zeitwerk" \ - "sinatra" "rack" "tilt" "mustermann" "base64" "compact_index" "rack-test" "logger" "kpeg" "tracer" + "sinatra" "rack" "tilt" "mustermann" "base64" "compact_index" "rack-test" "logger" "kpeg" "tracer" "minitest-mock" test-bundled-gems-fetch: yes-test-bundled-gems-fetch yes-test-bundled-gems-fetch: clone-bundled-gems-src diff --git a/gems/bundled_gems b/gems/bundled_gems index 6717d7e1924180..3a2d410f269d7b 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -6,7 +6,7 @@ # - revision: revision in repository-url to test # if `revision` is not given, "v"+`version` or `version` will be used. -minitest 5.27.0 https://github.com/minitest/minitest +minitest 6.0.0 https://github.com/minitest/minitest power_assert 3.0.1 https://github.com/ruby/power_assert rake 13.3.1 https://github.com/ruby/rake test-unit 3.7.3 https://github.com/test-unit/test-unit @@ -18,7 +18,7 @@ net-pop 0.1.2 https://github.com/ruby/net-pop net-smtp 0.5.1 https://github.com/ruby/net-smtp matrix 0.4.3 https://github.com/ruby/matrix prime 0.1.4 https://github.com/ruby/prime -rbs 3.10.0.pre.2 https://github.com/ruby/rbs +rbs 3.10.0.pre.2 https://github.com/ruby/rbs badcb9165b52c1b7ccaa6251e4d5bbd78329c5a7 typeprof 0.31.0 https://github.com/ruby/typeprof debug 1.11.0 https://github.com/ruby/debug racc 1.8.1 https://github.com/ruby/racc From b90d3a6beef7e960dca737efcbff18f8fffa31c0 Mon Sep 17 00:00:00 2001 From: git Date: Fri, 19 Dec 2025 02:44:57 +0000 Subject: [PATCH 08/14] Update bundled gems list as of 2025-12-19 --- NEWS.md | 6 +++--- gems/bundled_gems | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/NEWS.md b/NEWS.md index a5f657fb18f7a3..b10270c17eae25 100644 --- a/NEWS.md +++ b/NEWS.md @@ -330,19 +330,19 @@ The following bundled gems are added. The following bundled gems are updated. -* minitest 5.27.0 +* minitest 6.0.0 * power_assert 3.0.1 * rake 13.3.1 * test-unit 3.7.3 * rexml 3.4.4 * net-ftp 0.3.9 -* net-imap 0.6.1 +* net-imap 0.6.2 * net-smtp 0.5.1 * matrix 0.4.3 * prime 0.1.4 * rbs 3.10.0.pre.2 * typeprof 0.31.0 -* debug 1.11.0 +* debug 1.11.1 * base64 0.3.0 * bigdecimal 4.0.1 * drb 2.2.3 diff --git a/gems/bundled_gems b/gems/bundled_gems index 3a2d410f269d7b..a305ca7091d775 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -13,14 +13,14 @@ test-unit 3.7.3 https://github.com/test-unit/test-unit rexml 3.4.4 https://github.com/ruby/rexml rss 0.3.1 https://github.com/ruby/rss net-ftp 0.3.9 https://github.com/ruby/net-ftp -net-imap 0.6.1 https://github.com/ruby/net-imap +net-imap 0.6.2 https://github.com/ruby/net-imap net-pop 0.1.2 https://github.com/ruby/net-pop net-smtp 0.5.1 https://github.com/ruby/net-smtp matrix 0.4.3 https://github.com/ruby/matrix prime 0.1.4 https://github.com/ruby/prime rbs 3.10.0.pre.2 https://github.com/ruby/rbs badcb9165b52c1b7ccaa6251e4d5bbd78329c5a7 typeprof 0.31.0 https://github.com/ruby/typeprof -debug 1.11.0 https://github.com/ruby/debug +debug 1.11.1 https://github.com/ruby/debug racc 1.8.1 https://github.com/ruby/racc mutex_m 0.3.0 https://github.com/ruby/mutex_m getoptlong 0.2.1 https://github.com/ruby/getoptlong From 305f04210545d6801b2a4821a91858f0aed84f01 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 Dec 2025 10:26:59 +0900 Subject: [PATCH 09/14] NEWS.md: Sort items in alphabetical order --- NEWS.md | 121 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 61 deletions(-) diff --git a/NEWS.md b/NEWS.md index b10270c17eae25..af3e78ddaaba3f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -33,6 +33,24 @@ Note that each entry is kept to a minimum, see links for details. Note: We're only listing outstanding class updates. +* Array + + * `Array#rfind` has been added as a more efficient alternative to `array.reverse_each.find` [[Feature #21678]] + * `Array#find` has been added as a more efficient override of `Enumerable#find` [[Feature #21678]] + * `Array#pack` accepts a new format `R` and `r` for unpacking unsigned + and signed LEB128 encoded integers. [[Feature #21785]] + +* Binding + + * `Binding#local_variables` does no longer include numbered parameters. + Also, `Binding#local_variable_get`, `Binding#local_variable_set`, and + `Binding#local_variable_defined?` reject to handle numbered parameters. + [[Bug #21049]] + + * `Binding#implicit_parameters`, `Binding#implicit_parameter_get`, and + `Binding#implicit_parameter_defined?` have been added to access + numbered parameters and "it" parameter. [[Bug #21049]] + * Enumerator * `Enumerator.produce` now accepts an optional `size` keyword argument @@ -57,50 +75,6 @@ Note: We're only listing outstanding class updates. [[Feature #21701]] -* Kernel - - * `Kernel#inspect` now checks for the existence of a `#instance_variables_to_inspect` method, - allowing control over which instance variables are displayed in the `#inspect` string: - - ```ruby - class DatabaseConfig - def initialize(host, user, password) - @host = host - @user = user - @password = password - end - - private def instance_variables_to_inspect = [:@host, :@user] - end - - conf = DatabaseConfig.new("localhost", "root", "hunter2") - conf.inspect #=> # - ``` - - [[Feature #21219]] - - * A deprecated behavior, process creation by `Kernel#open` with a - leading `|`, was removed. [[Feature #19630]] - -* Array - - * `Array#rfind` has been added as a more efficient alternative to `array.reverse_each.find` [[Feature #21678]] - * `Array#find` has been added as a more efficient override of `Enumerable#find` [[Feature #21678]] - - * `Array#pack` accepts a new format `R` and `r` for unpacking unsigned - and signed LEB128 encoded integers. [[Feature #21785]] - -* Binding - - * `Binding#local_variables` does no longer include numbered parameters. - Also, `Binding#local_variable_get`, `Binding#local_variable_set`, and - `Binding#local_variable_defined?` reject to handle numbered parameters. - [[Bug #21049]] - - * `Binding#implicit_parameters`, `Binding#implicit_parameter_get`, and - `Binding#implicit_parameter_defined?` have been added to access - numbered parameters and "it" parameter. [[Bug #21049]] - * ErrorHighlight * When an ArgumentError is raised, it now displays code snippets for @@ -119,6 +93,18 @@ Note: We're only listing outstanding class updates. from test.rb:3:in '
' ``` +* Fiber + + * Introduce support for `Fiber#raise(cause:)` argument similar to + `Kernel#raise`. [[Feature #21360]] + +* Fiber::Scheduler + + * Introduce `Fiber::Scheduler#fiber_interrupt` to interrupt a fiber with a + given exception. The initial use case is to interrupt a fiber that is + waiting on a blocking IO operation when the IO operation is closed. + [[Feature #21166]] + * File * `File::Stat#birthtime` is now available on Linux via the statx @@ -133,10 +119,40 @@ Note: We're only listing outstanding class updates. * A deprecated behavior, process creation by `IO` class methods with a leading `|`, was removed. [[Feature #19630]] +* Kernel + + * `Kernel#inspect` now checks for the existence of a `#instance_variables_to_inspect` method, + allowing control over which instance variables are displayed in the `#inspect` string: + + ```ruby + class DatabaseConfig + def initialize(host, user, password) + @host = host + @user = user + @password = password + end + + private def instance_variables_to_inspect = [:@host, :@user] + end + + conf = DatabaseConfig.new("localhost", "root", "hunter2") + conf.inspect #=> # + ``` + + [[Feature #21219]] + + * A deprecated behavior, process creation by `Kernel#open` with a + leading `|`, was removed. [[Feature #19630]] + * Math * `Math.log1p` and `Math.expm1` are added. [[Feature #21527]] +* Pathname + + * Pathname has been promoted from a default gem to a core class of Ruby. + [[Feature #17473]] + * Proc * `Proc#parameters` now shows anonymous optional parameters as `[:opt]` @@ -250,23 +266,6 @@ Note: We're only listing outstanding class updates. * Introduce support for `Thread#raise(cause:)` argument similar to `Kernel#raise`. [[Feature #21360]] -* Fiber - - * Introduce support for `Fiber#raise(cause:)` argument similar to - `Kernel#raise`. [[Feature #21360]] - -* Fiber::Scheduler - - * Introduce `Fiber::Scheduler#fiber_interrupt` to interrupt a fiber with a - given exception. The initial use case is to interrupt a fiber that is - waiting on a blocking IO operation when the IO operation is closed. - [[Feature #21166]] - -* Pathname - - * Pathname has been promoted from a default gem to a core class of Ruby. - [[Feature #17473]] - ## Stdlib updates The following bundled gems are promoted from default gems. From 42d66b894cdfa356ed67af3000f79f7b2e9185fe Mon Sep 17 00:00:00 2001 From: Misaki Shioi <31817032+shioimm@users.noreply.github.com> Date: Fri, 19 Dec 2025 12:12:12 +0900 Subject: [PATCH 10/14] Fix: Do not check open_timeout twice (#15626) --- ext/socket/ipsocket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c index 88225f76e5c882..c9fcfb64fb4eb0 100644 --- a/ext/socket/ipsocket.c +++ b/ext/socket/ipsocket.c @@ -633,7 +633,7 @@ init_fast_fallback_inetsock_internal(VALUE v) unsigned int t; if (!NIL_P(open_timeout)) { t = rsock_value_timeout_to_msec(open_timeout); - } else if (!NIL_P(open_timeout)) { + } else if (!NIL_P(resolv_timeout)) { t = rsock_value_timeout_to_msec(resolv_timeout); } else { t = 0; @@ -1340,7 +1340,7 @@ rsock_init_inetsock( unsigned int t; if (!NIL_P(open_timeout)) { t = rsock_value_timeout_to_msec(open_timeout); - } else if (!NIL_P(open_timeout)) { + } else if (!NIL_P(resolv_timeout)) { t = rsock_value_timeout_to_msec(resolv_timeout); } else { t = 0; From bfba65d8c1fcdc75ea3fc0f78d8bc7514e7afabd Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 19 Dec 2025 09:26:23 +0900 Subject: [PATCH 11/14] Extract `Test::JobServer` module A placeholder to handle GNU make jobserver option. spec/default.mspec didn't handle the jobserver using a FIFO. --- bootstraptest/runner.rb | 31 ++----------------------- spec/default.mspec | 33 ++++---------------------- tool/lib/test/jobserver.rb | 47 ++++++++++++++++++++++++++++++++++++++ tool/lib/test/unit.rb | 24 +++---------------- 4 files changed, 57 insertions(+), 78 deletions(-) create mode 100644 tool/lib/test/jobserver.rb diff --git a/bootstraptest/runner.rb b/bootstraptest/runner.rb index 8988ac20ce41f6..04de0c93b90cb0 100755 --- a/bootstraptest/runner.rb +++ b/bootstraptest/runner.rb @@ -16,6 +16,7 @@ $:.unshift File.join(File.dirname(__FILE__), '../lib') retry end +require_relative '../tool/lib/test/jobserver' if !Dir.respond_to?(:mktmpdir) # copied from lib/tmpdir.rb @@ -110,35 +111,7 @@ def putc(c) def wn=(wn) unless wn == 1 - if /(?:\A|\s)--jobserver-(?:auth|fds)=(?:(\d+),(\d+)|fifo:((?:\\.|\S)+))/ =~ ENV.delete("MAKEFLAGS") - begin - if fifo = $3 - fifo.gsub!(/\\(?=.)/, '') - r = File.open(fifo, IO::RDONLY|IO::NONBLOCK|IO::BINARY) - w = File.open(fifo, IO::WRONLY|IO::NONBLOCK|IO::BINARY) - else - r = IO.for_fd($1.to_i(10), "rb", autoclose: false) - w = IO.for_fd($2.to_i(10), "wb", autoclose: false) - end - rescue - r.close if r - else - r.close_on_exec = true - w.close_on_exec = true - tokens = r.read_nonblock(wn > 0 ? wn : 1024, exception: false) - r.close - if String === tokens - tokens.freeze - auth = w - w = nil - at_exit {auth << tokens; auth.close} - wn = tokens.size + 1 - else - w.close - wn = 1 - end - end - end + wn = Test::JobServer.max_jobs(wn > 0 ? wn : 1024, ENV.delete("MAKEFLAGS")) || wn if wn <= 0 require 'etc' wn = [Etc.nprocessors / 2, 1].max diff --git a/spec/default.mspec b/spec/default.mspec index 058835cd10d91c..d756dc31ffd566 100644 --- a/spec/default.mspec +++ b/spec/default.mspec @@ -9,6 +9,7 @@ ENV["CHECK_CONSTANT_LEAKS"] ||= "true" require "./rbconfig" unless defined?(RbConfig) require_relative "../tool/test-coverage" if ENV.key?("COVERAGE") +require_relative "../tool/lib/test/jobserver" load File.dirname(__FILE__) + '/ruby/default.mspec' OBJDIR = File.expand_path("spec/ruby/optional/capi/ext") unless defined?(OBJDIR) class MSpecScript @@ -50,34 +51,10 @@ end module MSpecScript::JobServer def cores(max = 1) - if max > 1 and /(?:\A|\s)--jobserver-(?:auth|fds)=(\d+),(\d+)/ =~ ENV["MAKEFLAGS"] - cores = 1 - begin - r = IO.for_fd($1.to_i(10), "rb", autoclose: false) - w = IO.for_fd($2.to_i(10), "wb", autoclose: false) - jobtokens = r.read_nonblock(max - 1) - cores = jobtokens.size - if cores > 0 - cores += 1 - jobserver = w - w = nil - at_exit { - jobserver.print(jobtokens) - jobserver.close - } - MSpecScript::JobServer.module_eval do - remove_method :cores - define_method(:cores) do - cores - end - end - return cores - end - rescue Errno::EBADF - ensure - r&.close - w&.close - end + MSpecScript::JobServer.remove_method :cores + if cores = Test::JobServer.max_jobs(max) + MSpecScript::JobServer.define_method(:cores) { cores } + return cores end super end diff --git a/tool/lib/test/jobserver.rb b/tool/lib/test/jobserver.rb new file mode 100644 index 00000000000000..7b889163b02aa2 --- /dev/null +++ b/tool/lib/test/jobserver.rb @@ -0,0 +1,47 @@ +module Test + module JobServer + end +end + +class << Test::JobServer + def connect(makeflags = ENV["MAKEFLAGS"]) + return unless /(?:\A|\s)--jobserver-(?:auth|fds)=(?:(\d+),(\d+)|fifo:((?:\\.|\S)+))/ =~ makeflags + begin + if fifo = $3 + fifo.gsub!(/\\(?=.)/, '') + r = File.open(fifo, IO::RDONLY|IO::NONBLOCK|IO::BINARY) + w = File.open(fifo, IO::WRONLY|IO::NONBLOCK|IO::BINARY) + else + r = IO.for_fd($1.to_i(10), "rb", autoclose: false) + w = IO.for_fd($2.to_i(10), "wb", autoclose: false) + end + rescue + r&.close + nil + else + return r, w + end + end + + def acquire_possible(r, w, max) + return unless tokens = r.read_nonblock(max - 1, exception: false) + if (jobs = tokens.size) > 0 + jobserver, w = w, nil + at_exit do + jobserver.print(tokens) + jobserver.close + end + end + return jobs + 1 + rescue Errno::EBADF + ensure + r&.close + w&.close + end + + def max_jobs(max = 2, makeflags = ENV["MAKEFLAGS"]) + if max > 1 and (r, w = connect(makeflags)) + acquire_possible(r, w, max) + end + end +end diff --git a/tool/lib/test/unit.rb b/tool/lib/test/unit.rb index 7d43e825e179eb..2663b7b76a10bf 100644 --- a/tool/lib/test/unit.rb +++ b/tool/lib/test/unit.rb @@ -19,6 +19,7 @@ def warn(message, category: nil, **kwargs) require_relative '../colorize' require_relative '../leakchecker' require_relative '../test/unit/testcase' +require_relative '../test/jobserver' require 'optparse' # See Test::Unit @@ -262,27 +263,8 @@ def process_args(args = []) def non_options(files, options) @jobserver = nil - makeflags = ENV.delete("MAKEFLAGS") - if !options[:parallel] and - /(?:\A|\s)--jobserver-(?:auth|fds)=(?:(\d+),(\d+)|fifo:((?:\\.|\S)+))/ =~ makeflags - begin - if fifo = $3 - fifo.gsub!(/\\(?=.)/, '') - r = File.open(fifo, IO::RDONLY|IO::NONBLOCK|IO::BINARY) - w = File.open(fifo, IO::WRONLY|IO::NONBLOCK|IO::BINARY) - else - r = IO.for_fd($1.to_i(10), "rb", autoclose: false) - w = IO.for_fd($2.to_i(10), "wb", autoclose: false) - end - rescue - r.close if r - nil - else - r.close_on_exec = true - w.close_on_exec = true - @jobserver = [r, w] - options[:parallel] ||= 256 # number of tokens to acquire first - end + if !options[:parallel] and @jobserver = Test::JobServer.connect(ENV.delete("MAKEFLAGS")) + options[:parallel] ||= 256 # number of tokens to acquire first end @worker_timeout = EnvUtil.apply_timeout_scale(options[:worker_timeout] || 1200) super From 6f6ea70dcea1bbcb00774c1da58735a78c8924c2 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 19 Dec 2025 09:47:22 +0900 Subject: [PATCH 12/14] Just passing FDs does not need to create IO objects --- spec/ruby/optional/capi/spec_helper.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/spec/ruby/optional/capi/spec_helper.rb b/spec/ruby/optional/capi/spec_helper.rb index 1076b206ecbdb6..e7abf46e6ccf65 100644 --- a/spec/ruby/optional/capi/spec_helper.rb +++ b/spec/ruby/optional/capi/spec_helper.rb @@ -122,13 +122,9 @@ def setup_make opts = {} if /(?:\A|\s)--jobserver-(?:auth|fds)=(\d+),(\d+)/ =~ make_flags - begin - r = IO.for_fd($1.to_i(10), "rb", autoclose: false) - w = IO.for_fd($2.to_i(10), "wb", autoclose: false) - rescue Errno::EBADF - else - opts[r] = r - opts[w] = w + [$1, $2].each do |fd| + fd = fd.to_i(10) + opts[fd] = fd end end From f81c62be3df7b29c4c3b6adaa16599b38d0c0c46 Mon Sep 17 00:00:00 2001 From: yui-knk Date: Fri, 19 Dec 2025 11:46:58 +0900 Subject: [PATCH 13/14] Terminate `args_tail_basic` rule with a semicolon Semicolon is optional however it clarifies the end of the rule. --- parse.y | 1 + 1 file changed, 1 insertion(+) diff --git a/parse.y b/parse.y index 4754435fab0d21..067f45e6d6044a 100644 --- a/parse.y +++ b/parse.y @@ -2943,6 +2943,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary) $$ = new_args_tail(p, 0, 0, $1, &@1); /*% ripper: [Qnil, Qnil, $:1] %*/ } + ; %rule def_endless_method(bodystmt) : defn_head[head] f_opt_paren_args[args] '=' bodystmt From 47244b0f306161f175b21f74d801882e950e18be Mon Sep 17 00:00:00 2001 From: Misaki Shioi <31817032+shioimm@users.noreply.github.com> Date: Fri, 19 Dec 2025 15:44:35 +0900 Subject: [PATCH 14/14] Fix: Specifying 0 should cause an immediate timeout (#15641) This change fixes a bug in which specifying 0 for timeout-related options (such as the `timeout` option of `Addrinfo.getaddrinfo`) incorrectly results in an infinite wait. (This change overwrites https://github.com/ruby/ruby/pull/15626 .) --- ext/socket/ipsocket.c | 27 +++++---------------------- ext/socket/raddrinfo.c | 29 ++++++++++++++++------------- ext/socket/rubysocket.h | 5 ++--- ext/socket/socket.c | 8 ++++---- ext/socket/tcpsocket.c | 2 +- ext/socket/udpsocket.c | 6 +++--- test/socket/test_socket.rb | 2 +- 7 files changed, 32 insertions(+), 47 deletions(-) diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c index c9fcfb64fb4eb0..e952b7871b3f6f 100644 --- a/ext/socket/ipsocket.c +++ b/ext/socket/ipsocket.c @@ -83,15 +83,13 @@ init_inetsock_internal(VALUE v) VALUE open_timeout = arg->open_timeout; VALUE timeout; VALUE starts_at; - unsigned int timeout_msec; timeout = NIL_P(open_timeout) ? resolv_timeout : open_timeout; - timeout_msec = NIL_P(timeout) ? 0 : rsock_value_timeout_to_msec(timeout); starts_at = current_clocktime(); arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv, family, SOCK_STREAM, - (type == INET_SERVER) ? AI_PASSIVE : 0, timeout_msec); + (type == INET_SERVER) ? AI_PASSIVE : 0, timeout); /* * Maybe also accept a local address @@ -99,7 +97,7 @@ init_inetsock_internal(VALUE v) if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) { arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv, - family, SOCK_STREAM, 0, 0); + family, SOCK_STREAM, 0, timeout); } VALUE io = Qnil; @@ -630,14 +628,7 @@ init_fast_fallback_inetsock_internal(VALUE v) arg->getaddrinfo_shared = NULL; int family = arg->families[0]; - unsigned int t; - if (!NIL_P(open_timeout)) { - t = rsock_value_timeout_to_msec(open_timeout); - } else if (!NIL_P(resolv_timeout)) { - t = rsock_value_timeout_to_msec(resolv_timeout); - } else { - t = 0; - } + VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout; arg->remote.res = rsock_addrinfo( arg->remote.host, @@ -1337,15 +1328,7 @@ rsock_init_inetsock( * Maybe also accept a local address */ if (!NIL_P(local_host) || !NIL_P(local_serv)) { - unsigned int t; - if (!NIL_P(open_timeout)) { - t = rsock_value_timeout_to_msec(open_timeout); - } else if (!NIL_P(resolv_timeout)) { - t = rsock_value_timeout_to_msec(resolv_timeout); - } else { - t = 0; - } - + VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout; local_res = rsock_addrinfo( local_host, local_serv, @@ -1609,7 +1592,7 @@ static VALUE ip_s_getaddress(VALUE obj, VALUE host) { union_sockaddr addr; - struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0, 0); + struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0, Qnil); socklen_t len = res->ai->ai_addrlen; /* just take the first one */ diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c index 3dcbe7717a0ca2..6cdf5c6abc40e7 100644 --- a/ext/socket/raddrinfo.c +++ b/ext/socket/raddrinfo.c @@ -293,7 +293,7 @@ rb_freeaddrinfo(struct rb_addrinfo *ai) xfree(ai); } -unsigned int +static int rsock_value_timeout_to_msec(VALUE timeout) { double seconds = NUM2DBL(timeout); @@ -308,7 +308,7 @@ rsock_value_timeout_to_msec(VALUE timeout) #if GETADDRINFO_IMPL == 0 static int -rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, unsigned int _timeout) +rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout) { return getaddrinfo(hostp, portp, hints, ai); } @@ -346,7 +346,7 @@ fork_safe_getaddrinfo(void *arg) } static int -rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, unsigned int _timeout) +rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout) { struct getaddrinfo_arg arg; MEMZERO(&arg, struct getaddrinfo_arg, 1); @@ -367,11 +367,11 @@ struct getaddrinfo_arg int err, gai_errno, refcount, done, cancelled, timedout; rb_nativethread_lock_t lock; rb_nativethread_cond_t cond; - unsigned int timeout; + int timeout; }; static struct getaddrinfo_arg * -allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints, unsigned int timeout) +allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints, int timeout) { size_t hostp_offset = sizeof(struct getaddrinfo_arg); size_t portp_offset = hostp_offset + (hostp ? strlen(hostp) + 1 : 0); @@ -465,8 +465,11 @@ wait_getaddrinfo(void *ptr) struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr; rb_nativethread_lock_lock(&arg->lock); while (!arg->done && !arg->cancelled) { - unsigned long msec = arg->timeout; - if (msec > 0) { + long msec = arg->timeout; + if (msec == 0) { + arg->cancelled = 1; + arg->timedout = 1; + } else if (msec > 0) { rb_native_cond_timedwait(&arg->cond, &arg->lock, msec); if (!arg->done) { arg->cancelled = 1; @@ -549,7 +552,7 @@ fork_safe_do_getaddrinfo(void *ptr) } static int -rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, unsigned int timeout) +rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int timeout) { int retry; struct getaddrinfo_arg *arg; @@ -1021,7 +1024,7 @@ rb_scheduler_getaddrinfo(VALUE scheduler, VALUE host, const char *service, } struct rb_addrinfo* -rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, unsigned int timeout) +rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout) { struct rb_addrinfo* res = NULL; struct addrinfo *ai; @@ -1056,7 +1059,8 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h } if (!resolved) { - error = rb_getaddrinfo(hostp, portp, hints, &ai, timeout); + int t = NIL_P(timeout) ? -1 : rsock_value_timeout_to_msec(timeout); + error = rb_getaddrinfo(hostp, portp, hints, &ai, t); if (error == 0) { res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo)); res->allocated_by_malloc = 0; @@ -1089,7 +1093,7 @@ rsock_fd_family(int fd) } struct rb_addrinfo* -rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, unsigned int timeout) +rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout) { struct addrinfo hints; @@ -1380,8 +1384,7 @@ call_getaddrinfo(VALUE node, VALUE service, hints.ai_flags = NUM2INT(flags); } - unsigned int t = NIL_P(timeout) ? 0 : rsock_value_timeout_to_msec(timeout); - res = rsock_getaddrinfo(node, service, &hints, socktype_hack, t); + res = rsock_getaddrinfo(node, service, &hints, socktype_hack, timeout); if (res == NULL) rb_raise(rb_eSocket, "host not found"); diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h index 638b7ede6ec72e..2ec3ab335aef86 100644 --- a/ext/socket/rubysocket.h +++ b/ext/socket/rubysocket.h @@ -327,8 +327,8 @@ void rb_freeaddrinfo(struct rb_addrinfo *ai); VALUE rsock_freeaddrinfo(VALUE arg); int rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags); int rsock_fd_family(int fd); -struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, unsigned int timeout); -struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, unsigned int timeout); +struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout); +struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout); VALUE rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len); VALUE rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len); @@ -453,7 +453,6 @@ void free_fast_fallback_getaddrinfo_shared(struct fast_fallback_getaddrinfo_shar # endif #endif -unsigned int rsock_value_timeout_to_msec(VALUE); NORETURN(void rsock_raise_user_specified_timeout(struct addrinfo *ai, VALUE host, VALUE port)); void rsock_init_basicsocket(void); diff --git a/ext/socket/socket.c b/ext/socket/socket.c index 26bf0bae8c046d..a8e5ae81190c21 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -965,7 +965,7 @@ sock_s_gethostbyname(VALUE obj, VALUE host) { rb_warn("Socket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead."); struct rb_addrinfo *res = - rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, 0); + rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil); return rsock_make_hostent(host, res, sock_sockaddr); } @@ -1183,7 +1183,7 @@ sock_s_getaddrinfo(int argc, VALUE *argv, VALUE _) norevlookup = rsock_do_not_reverse_lookup; } - res = rsock_getaddrinfo(host, port, &hints, 0, 0); + res = rsock_getaddrinfo(host, port, &hints, 0, Qnil); ret = make_addrinfo(res, norevlookup); rb_freeaddrinfo(res); @@ -1279,7 +1279,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _) hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM; /* af */ hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af); - res = rsock_getaddrinfo(host, port, &hints, 0, 0); + res = rsock_getaddrinfo(host, port, &hints, 0, Qnil); sap = res->ai->ai_addr; salen = res->ai->ai_addrlen; } @@ -1335,7 +1335,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _) static VALUE sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host) { - struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0, 0); + struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0, Qnil); VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen); rb_freeaddrinfo(res); diff --git a/ext/socket/tcpsocket.c b/ext/socket/tcpsocket.c index 300a426eda8471..7ce536e0af9ca3 100644 --- a/ext/socket/tcpsocket.c +++ b/ext/socket/tcpsocket.c @@ -113,7 +113,7 @@ tcp_s_gethostbyname(VALUE obj, VALUE host) { rb_warn("TCPSocket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead."); struct rb_addrinfo *res = - rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, 0); + rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil); return rsock_make_hostent(host, res, tcp_sockaddr); } diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c index 5538f24523fc09..b2bc92553886aa 100644 --- a/ext/socket/udpsocket.c +++ b/ext/socket/udpsocket.c @@ -84,7 +84,7 @@ udp_connect(VALUE self, VALUE host, VALUE port) { struct udp_arg arg = {.io = self}; - arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, 0); + arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil); int result = (int)rb_ensure(udp_connect_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res); if (!result) { @@ -129,7 +129,7 @@ udp_bind(VALUE self, VALUE host, VALUE port) { struct udp_arg arg = {.io = self}; - arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, 0); + arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil); VALUE result = rb_ensure(udp_bind_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res); if (!result) { @@ -212,7 +212,7 @@ udp_send(int argc, VALUE *argv, VALUE sock) GetOpenFile(sock, arg.fptr); arg.sarg.fd = arg.fptr->fd; arg.sarg.flags = NUM2INT(flags); - arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0, 0); + arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0, Qnil); ret = rb_ensure(udp_send_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res); if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port); diff --git a/test/socket/test_socket.rb b/test/socket/test_socket.rb index 686114f05c1418..c42527f3703173 100644 --- a/test/socket/test_socket.rb +++ b/test/socket/test_socket.rb @@ -1011,7 +1011,7 @@ def test_tcp_socket_all_hostname_resolution_failed Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_| case family when Socket::AF_INET6 then raise SocketError - when Socket::AF_INET then sleep(0.001); raise SocketError, "Last hostname resolution error" + when Socket::AF_INET then sleep(0.01); raise SocketError, "Last hostname resolution error" end end