From 98ab418fed61079f8ef7e229ea1b41957ec5722b Mon Sep 17 00:00:00 2001 From: Luke Gruber Date: Mon, 15 Dec 2025 17:07:15 -0500 Subject: [PATCH 01/10] Revert "Fix Socket.tcp cleanup after Thread#kill (#15131)" (#15565) This reverts commit 3038286a4bf7832f1c42c8cc9774ee6ff19876fc. The following CI failure scared me: https://github.com/ruby/ruby/actions/runs/20241051861/job/58108997049 ``` 1) Timeout: TestResolvDNS#test_multiple_servers_with_timeout_and_truncated_tcp_fallback ``` Since it could be related, I'm reverting this for now. --- ext/socket/lib/socket.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb index dae1c16760a550..9862c92c0b6591 100644 --- a/ext/socket/lib/socket.rb +++ b/ext/socket/lib/socket.rb @@ -917,8 +917,7 @@ def self.tcp_with_fast_fallback(host, port, local_host = nil, local_port = nil, end ensure hostname_resolution_threads.each do |thread| - thread.kill - thread.join + thread.exit end hostname_resolution_result&.close From 7fbf321d23f3cc20988c80fae25ce131a5d1b231 Mon Sep 17 00:00:00 2001 From: BurdetteLamar Date: Mon, 15 Dec 2025 20:20:25 +0000 Subject: [PATCH 02/10] [DOC] Harmonize #** methods --- complex.c | 4 ++-- numeric.c | 11 +++++------ rational.c | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/complex.c b/complex.c index 12dec4d23b04c8..c34c798a158457 100644 --- a/complex.c +++ b/complex.c @@ -1122,9 +1122,9 @@ complex_pow_for_special_angle(VALUE self, VALUE other) /* * call-seq: - * complex ** numeric -> new_complex + * self ** exponent -> complex * - * Returns +self+ raised to power +numeric+: + * Returns +self+ raised to the power +exponent+: * * Complex.rect(0, 1) ** 2 # => (-1+0i) * Complex.rect(-8) ** Rational(1, 3) # => (1.0000000000000002+1.7320508075688772i) diff --git a/numeric.c b/numeric.c index f96535cd2461d2..cb3ca129047669 100644 --- a/numeric.c +++ b/numeric.c @@ -1390,9 +1390,9 @@ flo_divmod(VALUE x, VALUE y) /* * call-seq: - * self ** other -> numeric + * self ** exponent -> numeric * - * Raises +self+ to the power of +other+: + * Returns +self+ raised to the power +exponent+: * * f = 3.14 * f ** 2 # => 9.8596 @@ -4623,9 +4623,9 @@ rb_int_divmod(VALUE x, VALUE y) /* * call-seq: - * self ** numeric -> numeric_result + * self ** exponent -> numeric * - * Raises +self+ to the power of +numeric+: + * Returns +self+ raised to the power +exponent+: * * 2 ** 3 # => 8 * 2 ** -3 # => (1/8) @@ -4748,8 +4748,7 @@ fix_pow(VALUE x, VALUE y) * call-seq: * self ** exponent -> numeric * - * Returns the value of base +self+ raised to the power +exponent+; - * see {Exponentiation}[https://en.wikipedia.org/wiki/Exponentiation]: + * Returns +self+ raised to the power +exponent+: * * # Result for non-negative Integer exponent is Integer. * 2 ** 0 # => 1 diff --git a/rational.c b/rational.c index 7c2bd0b1eb7f00..8c9b80cb62fe21 100644 --- a/rational.c +++ b/rational.c @@ -984,9 +984,9 @@ nurat_fdiv(VALUE self, VALUE other) /* * call-seq: - * rat ** numeric -> numeric + * self ** exponent -> numeric * - * Performs exponentiation. + * Returns +self+ raised to the power +exponent+: * * Rational(2) ** Rational(3) #=> (8/1) * Rational(10) ** -2 #=> (1/100) From acbf55f4e6658f94e49f28b4df21ab0c29683c4b Mon Sep 17 00:00:00 2001 From: BurdetteLamar Date: Mon, 15 Dec 2025 20:35:27 +0000 Subject: [PATCH 03/10] [DOC] Harmonize #- methods --- complex.c | 4 ++-- numeric.c | 6 +++--- rational.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/complex.c b/complex.c index c34c798a158457..2a92f4c7028b37 100644 --- a/complex.c +++ b/complex.c @@ -861,9 +861,9 @@ rb_complex_plus(VALUE self, VALUE other) /* * call-seq: - * complex - numeric -> new_complex + * self - other -> complex * - * Returns the difference of +self+ and +numeric+: + * Returns the difference of +self+ and +other+: * * Complex.rect(2, 3) - Complex.rect(2, 3) # => (0+0i) * Complex.rect(900) - Complex.rect(1) # => (899+0i) diff --git a/numeric.c b/numeric.c index cb3ca129047669..5f2f4ea79743a4 100644 --- a/numeric.c +++ b/numeric.c @@ -1089,7 +1089,7 @@ rb_float_plus(VALUE x, VALUE y) * call-seq: * self - other -> numeric * - * Returns a new \Float which is the difference of +self+ and +other+: + * Returns the difference of +self+ and +other+: * * f = 3.14 * f - 1 # => 2.14 @@ -4197,9 +4197,9 @@ fix_minus(VALUE x, VALUE y) /* * call-seq: - * self - numeric -> numeric_result + * self - other -> numeric * - * Performs subtraction: + * Returns the difference of +self+ and +other+: * * 4 - 2 # => 2 * -4 - 2 # => -6 diff --git a/rational.c b/rational.c index 8c9b80cb62fe21..f03a98a9ee2cd9 100644 --- a/rational.c +++ b/rational.c @@ -768,9 +768,9 @@ rb_rational_plus(VALUE self, VALUE other) /* * call-seq: - * rat - numeric -> numeric + * self - other -> numeric * - * Performs subtraction. + * Returns the difference of +self+ and +other+: * * Rational(2, 3) - Rational(2, 3) #=> (0/1) * Rational(900) - Rational(1) #=> (899/1) From cfd41cbf0338a28638ed54edb0de13539b159dfb Mon Sep 17 00:00:00 2001 From: BurdetteLamar Date: Mon, 15 Dec 2025 21:28:41 +0000 Subject: [PATCH 04/10] [DOC] Harmonize #-@ methods --- complex.c | 4 ++-- numeric.c | 2 +- numeric.rb | 17 +++++++++++++---- rational.c | 8 ++++++-- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/complex.c b/complex.c index 2a92f4c7028b37..eab6bde85ab82b 100644 --- a/complex.c +++ b/complex.c @@ -799,9 +799,9 @@ rb_complex_imag(VALUE self) /* * call-seq: - * -complex -> new_complex + * -self -> complex * - * Returns the negation of +self+, which is the negation of each of its parts: + * Returns +self+, negated, which is the negation of each of its parts: * * -Complex.rect(1, 2) # => (-1-2i) * -Complex.rect(-1, -2) # => (1+2i) diff --git a/numeric.c b/numeric.c index 5f2f4ea79743a4..4e105baa81532b 100644 --- a/numeric.c +++ b/numeric.c @@ -576,7 +576,7 @@ num_imaginary(VALUE num) * call-seq: * -self -> numeric * - * Unary Minus---Returns the receiver, negated. + * Returns +self+, negated. */ static VALUE diff --git a/numeric.rb b/numeric.rb index 552a3dd687aedc..306561943d5029 100644 --- a/numeric.rb +++ b/numeric.rb @@ -93,9 +93,14 @@ def +@ class Integer # call-seq: - # -int -> integer + # -self -> integer + # + # Returns +self+, negated: + # + # -1 # => -1 + # -(-1) # => 1 + # -0 # => 0 # - # Returns +self+, negated. def -@ Primitive.attr! :leaf Primitive.cexpr! 'rb_int_uminus(self)' @@ -373,9 +378,13 @@ def abs alias magnitude abs # call-seq: - # -float -> float + # -self -> float + # + # Returns +self+, negated: # - # Returns +self+, negated. + # -3.14 # => -3.14 + # -(-3.14) # => 3.14 + # -0.0 # => -0.0 # def -@ Primitive.attr! :leaf diff --git a/rational.c b/rational.c index f03a98a9ee2cd9..05dc3540c09442 100644 --- a/rational.c +++ b/rational.c @@ -609,9 +609,13 @@ nurat_denominator(VALUE self) /* * call-seq: - * -rat -> rational + * -self -> rational + * + * Returns +self+, negated: + * + * -(1/3r) # => (-1/3) + * -(-1/3r) # => (1/3) * - * Negates +rat+. */ VALUE rb_rational_uminus(VALUE self) From b3f0fb56187dd9711fac0baae81a3f1ed0b5714a Mon Sep 17 00:00:00 2001 From: nick evans Date: Thu, 11 Dec 2025 15:25:59 -0500 Subject: [PATCH 05/10] [ruby/psych] Replace C extension with Data#initialize bind_call https://github.com/ruby/psych/commit/6a826693ba --- ext/psych/lib/psych/visitors/to_ruby.rb | 7 +++++-- ext/psych/psych_to_ruby.c | 7 ------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb index e62311ae12d177..475444e589d1ca 100644 --- a/ext/psych/lib/psych/visitors/to_ruby.rb +++ b/ext/psych/lib/psych/visitors/to_ruby.rb @@ -12,6 +12,10 @@ module Visitors ### # This class walks a YAML AST, converting each node to Ruby class ToRuby < Psych::Visitors::Visitor + unless RUBY_VERSION < "3.2" + DATA_INITIALIZE = Data.instance_method(:initialize) + end + def self.create(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true) class_loader = ClassLoader.new scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols @@ -219,8 +223,7 @@ def visit_Psych_Nodes_Mapping o revive_data_members(members, o) end data ||= allocate_anon_data(o, members) - values = data.members.map { |m| members[m] } - init_data(data, values) + DATA_INITIALIZE.bind_call(data, **members) data.freeze data diff --git a/ext/psych/psych_to_ruby.c b/ext/psych/psych_to_ruby.c index 0132b2c94e28c7..3ab0138b52417c 100644 --- a/ext/psych/psych_to_ruby.c +++ b/ext/psych/psych_to_ruby.c @@ -28,12 +28,6 @@ static VALUE path2class(VALUE self, VALUE path) return rb_path_to_class(path); } -static VALUE init_data(VALUE self, VALUE data, VALUE values) -{ - rb_struct_initialize(data, values); - return data; -} - void Init_psych_to_ruby(void) { VALUE psych = rb_define_module("Psych"); @@ -43,7 +37,6 @@ void Init_psych_to_ruby(void) VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject); cPsychVisitorsToRuby = rb_define_class_under(visitors, "ToRuby", visitor); - rb_define_private_method(cPsychVisitorsToRuby, "init_data", init_data, 2); rb_define_private_method(cPsychVisitorsToRuby, "build_exception", build_exception, 2); rb_define_private_method(class_loader, "path2class", path2class, 1); } From abefd3e8ff1853800d4df5b28388191b51d9ec37 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Wed, 10 Dec 2025 21:11:05 +0100 Subject: [PATCH 06/10] [ruby/psych] Check that Data members match exactly * Fixes https://github.com/ruby/psych/issues/760 https://github.com/ruby/psych/commit/952008c898 --- test/psych/test_data.rb | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/psych/test_data.rb b/test/psych/test_data.rb index a67a037b9e4af5..57c3478193a526 100644 --- a/test/psych/test_data.rb +++ b/test/psych/test_data.rb @@ -64,6 +64,31 @@ def test_load assert_equal "hello", obj.bar assert_equal "bar", obj.foo end + + def test_members_must_be_identical + TestData.const_set :D, Data.define(:a, :b) + d = Psych.dump(TestData::D.new(1, 2)) + + # more members + TestData.send :remove_const, :D + TestData.const_set :D, Data.define(:a, :b, :c) + e = assert_raise(ArgumentError) { Psych.unsafe_load d } + assert_equal 'missing keyword: :c', e.message + + # less members + TestData.send :remove_const, :D + TestData.const_set :D, Data.define(:a) + e = assert_raise(ArgumentError) { Psych.unsafe_load d } + assert_equal 'unknown keyword: :b', e.message + + # completely different members + TestData.send :remove_const, :D + TestData.const_set :D, Data.define(:foo, :bar) + e = assert_raise(ArgumentError) { Psych.unsafe_load d } + assert_equal 'unknown keywords: :a, :b', e.message + ensure + TestData.send :remove_const, :D + end end end From 98cac1a75d9d9b7ff4cfd5b5d0fd99c1b5f17631 Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Mon, 15 Dec 2025 19:10:04 -0500 Subject: [PATCH 07/10] Point people to redmine on ZJIT docs (#15499) Fix https://github.com/Shopify/ruby/issues/900 --- doc/jit/zjit.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/doc/jit/zjit.md b/doc/jit/zjit.md index c66235269bd265..b5a2f05604983f 100644 --- a/doc/jit/zjit.md +++ b/doc/jit/zjit.md @@ -11,6 +11,38 @@ This project is open source and falls under the same license as CRuby. ZJIT may not be suitable for certain applications. It currently only supports macOS, Linux and BSD on x86-64 and arm64/aarch64 CPUs. ZJIT will use more memory than the Ruby interpreter because the JIT compiler needs to generate machine code in memory and maintain additional state information. You can change how much executable memory is allocated using [ZJIT's command-line options](rdoc-ref:@Command-Line+Options). +## Contributing + +We welcome open source contributions. Feel free to open new issues to report +bugs or just to ask questions. Suggestions on how to make this document more +helpful for new contributors are most welcome. + +Bug fixes and bug reports are very valuable to us. If you find a bug in ZJIT, +it's very possible that nobody has reported it before, or that we don't have +a good reproduction for it, so please open a ticket on [the official Ruby bug +tracker][rubybugs] (or, if you don't want to make an account, [on +Shopify/ruby][shopifyruby]) and provide as much information as you can about +your configuration and a description of how you encountered the problem. List +the commands you used to run ZJIT so that we can easily reproduce the issue on +our end and investigate it. If you are able to produce a small program +reproducing the error to help us track it down, that is very much appreciated +as well. + +[rubybugs]: https://bugs.ruby-lang.org/projects/ruby-master +[shopifyruby]: https://github.com/Shopify/ruby/issues + +If you would like to contribute a large patch to ZJIT, we suggest [chatting on +Zulip][zulip] for a casual chat and then opening an issue on the [Shopify/ruby +repository][shopifyruby] so that we can have a technical discussion. A common +problem is that sometimes people submit large pull requests to open source +projects without prior communication, and we have to reject them because the +work they implemented does not fit within the design of the project. We want to +save you time and frustration, so please reach out so we can have a productive +discussion as to how you can contribute patches we will want to merge into +ZJIT. + +[zulip]: https://zjit.zulipchat.com/ + ## Build Instructions Refer to [Building Ruby](rdoc-ref:contributing/building_ruby.md) for general build prerequists. From f88e7970901d3d8cfb6efeb536d983bf2e05b04a Mon Sep 17 00:00:00 2001 From: Edouard CHIN Date: Mon, 15 Dec 2025 15:56:41 +0100 Subject: [PATCH 08/10] [ruby/rubygems] Allow bundle pristine to work for git gems in the same repo: - Fix https://github.com/ruby/rubygems/pull/9186 - ### Problem Running `bundle pristine` in a Gemfile where there is many git gem pointing to the same repository will result in a error "Another git process seems to be running in this repository". ### Context This error is a regression since https://github.com/ruby/rubygems/commit/a555fd6ccd17 where `bundle pristine` now runs in parallel which could lead to running simultaneous git operations in the same repository. ### Solution When Bundler pristine a git gem it does a `git reset --hard` without specifying a path. This means the whole repository will be reset. In this case, we can leverage that by just pristining one gem per unique git sources. This is also more efficient. https://github.com/ruby/rubygems/commit/710ba514a8 --- lib/bundler/cli/pristine.rb | 4 ++ spec/bundler/commands/pristine_spec.rb | 60 ++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/lib/bundler/cli/pristine.rb b/lib/bundler/cli/pristine.rb index cfd4a995a31faa..b8545fe4c9c3eb 100644 --- a/lib/bundler/cli/pristine.rb +++ b/lib/bundler/cli/pristine.rb @@ -11,6 +11,7 @@ def run definition = Bundler.definition definition.validate_runtime! installer = Bundler::Installer.new(Bundler.root, definition) + git_sources = [] ProcessLock.lock do installed_specs = definition.specs.reject do |spec| @@ -41,6 +42,9 @@ def run end FileUtils.rm_rf spec.extension_dir FileUtils.rm_rf spec.full_gem_path + + next if git_sources.include?(source) + git_sources << source else Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.") next diff --git a/spec/bundler/commands/pristine_spec.rb b/spec/bundler/commands/pristine_spec.rb index da61dc819920fb..daeafea43bf87e 100644 --- a/spec/bundler/commands/pristine_spec.rb +++ b/spec/bundler/commands/pristine_spec.rb @@ -89,6 +89,66 @@ expect(changes_txt).to be_file expect(err).to include("Cannot pristine #{spec.name} (#{spec.version}#{spec.git_version}). Gem is locally overridden.") end + + it "doesn't run multiple git processes for the same repository" do + nested_gems = [ + "actioncable", + "actionmailer", + "actionpack", + "actionview", + "activejob", + "activemodel", + "activerecord", + "activestorage", + "activesupport", + "railties", + ] + + build_repo2 do + nested_gems.each do |gem| + build_lib gem, path: lib_path("rails/#{gem}") + end + + build_git "rails", path: lib_path("rails") do |s| + nested_gems.each do |gem| + s.add_dependency gem + end + end + end + + install_gemfile <<-G + source 'https://rubygems.org' + + git "#{lib_path("rails")}" do + gem "rails" + gem "actioncable" + gem "actionmailer" + gem "actionpack" + gem "actionview" + gem "activejob" + gem "activemodel" + gem "activerecord" + gem "activestorage" + gem "activesupport" + gem "railties" + end + G + + changed_files = [] + diff = "#Pristine spec changes" + + nested_gems.each do |gem| + spec = find_spec(gem) + changed_files << Pathname.new(spec.full_gem_path).join("lib/#{gem}.rb") + File.open(changed_files.last, "a") {|f| f.puts diff } + end + + bundle "pristine" + + changed_files.each do |changed_file| + expect(File.read(changed_file)).to_not include(diff) + end + end end context "when sourced from gemspec" do From ff1b8ffa61922a46eae217c06aa16b24f26ae723 Mon Sep 17 00:00:00 2001 From: Edouard CHIN Date: Mon, 15 Dec 2025 11:45:23 +0100 Subject: [PATCH 09/10] [ruby/rubygems] Tweak the Bundler's "X gems now installed message": - Fix https://github.com/ruby/rubygems/pull/9188 - This message is a bit misleading because it always outputs one extra specs, which is Bundler itself. This is now fixed when the message is about to be output. https://github.com/ruby/rubygems/commit/70b4e19506 --- lib/bundler/cli/install.rb | 2 +- spec/bundler/commands/post_bundle_message_spec.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb index ba1cef8434e63c..67feba84bdb06e 100644 --- a/lib/bundler/cli/install.rb +++ b/lib/bundler/cli/install.rb @@ -90,7 +90,7 @@ def dependencies_count_for(definition) end def gems_installed_for(definition) - count = definition.specs.count + count = definition.specs.count {|spec| spec.name != "bundler" } "#{count} #{count == 1 ? "gem" : "gems"} now installed" end diff --git a/spec/bundler/commands/post_bundle_message_spec.rb b/spec/bundler/commands/post_bundle_message_spec.rb index 257443526089ad..9eecff593f7e33 100644 --- a/spec/bundler/commands/post_bundle_message_spec.rb +++ b/spec/bundler/commands/post_bundle_message_spec.rb @@ -18,7 +18,7 @@ let(:bundle_show_path_message) { "Bundled gems are installed into `#{bundle_path}`" } let(:bundle_complete_message) { "Bundle complete!" } let(:bundle_updated_message) { "Bundle updated!" } - let(:installed_gems_stats) { "4 Gemfile dependencies, 5 gems now installed." } + let(:installed_gems_stats) { "4 Gemfile dependencies, 4 gems now installed." } describe "when installing to system gems" do before do @@ -44,14 +44,14 @@ expect(out).to include(bundle_show_system_message) expect(out).to include("Gems in the groups 'emo' and 'test' were not installed") expect(out).to include(bundle_complete_message) - expect(out).to include("4 Gemfile dependencies, 3 gems now installed.") + expect(out).to include("4 Gemfile dependencies, 2 gems now installed.") bundle "config set --local without emo obama test" bundle :install expect(out).to include(bundle_show_system_message) expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not installed") expect(out).to include(bundle_complete_message) - expect(out).to include("4 Gemfile dependencies, 2 gems now installed.") + expect(out).to include("4 Gemfile dependencies, 1 gem now installed.") end describe "for second bundle install run" do From b6d4562e6ae9cbf9864c3f35c361db8087e595e7 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Sun, 14 Dec 2025 17:34:34 -0500 Subject: [PATCH 10/10] [DOC] Remove copyright from Set class docs --- set.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/set.c b/set.c index 0c657cf66d8118..6d200b5dfa1495 100644 --- a/set.c +++ b/set.c @@ -1988,13 +1988,6 @@ rb_set_size(VALUE set) /* * Document-class: Set * - * Copyright (c) 2002-2024 Akinori MUSHA - * - * Documentation by Akinori MUSHA and Gavin Sinclair. - * - * All rights reserved. You can redistribute and/or modify it under the same - * terms as Ruby. - * * The Set class implements a collection of unordered values with no * duplicates. It is a hybrid of Array's intuitive inter-operation * facilities and Hash's fast lookup.