diff --git a/doc/string.rb b/doc/string.rb index b3d5886b8dd718..4304b96aee7f9a 100644 --- a/doc/string.rb +++ b/doc/string.rb @@ -402,6 +402,7 @@ # - #to_c: Returns the complex value of leading characters, interpreted as a complex number. # - #to_i: Returns the integer value of leading characters, interpreted as an integer. # - #to_f: Returns the floating-point value of leading characters, interpreted as a floating-point number. +# - #to_r: Returns the rational value of leading characters, interpreted as a rational. # # Strings and Symbols # diff --git a/lib/rubygems/package/tar_header.rb b/lib/rubygems/package/tar_header.rb index 0ebcbd789d4038..dd20d65080ff00 100644 --- a/lib/rubygems/package/tar_header.rb +++ b/lib/rubygems/package/tar_header.rb @@ -56,7 +56,7 @@ class Gem::Package::TarHeader ## # Pack format for a tar header - PACK_FORMAT = "a100" + # name + PACK_FORMAT = ("a100" + # name "a8" + # mode "a8" + # uid "a8" + # gid @@ -71,12 +71,12 @@ class Gem::Package::TarHeader "a32" + # gname "a8" + # devmajor "a8" + # devminor - "a155" # prefix + "a155").freeze # prefix ## # Unpack format for a tar header - UNPACK_FORMAT = "A100" + # name + UNPACK_FORMAT = ("A100" + # name "A8" + # mode "A8" + # uid "A8" + # gid @@ -91,7 +91,7 @@ class Gem::Package::TarHeader "A32" + # gname "A8" + # devmajor "A8" + # devminor - "A155" # prefix + "A155").freeze # prefix attr_reader(*FIELDS) diff --git a/rational.c b/rational.c index 89e74c328dca0d..28f116580fb945 100644 --- a/rational.c +++ b/rational.c @@ -2467,31 +2467,32 @@ string_to_r_strict(VALUE self, int raise) /* * call-seq: - * str.to_r -> rational - * - * Returns the result of interpreting leading characters in +str+ - * as a rational. Leading whitespace and extraneous characters - * past the end of a valid number are ignored. - * Digit sequences can be separated by an underscore. - * If there is not a valid number at the start of +str+, - * zero is returned. This method never raises an exception. - * - * ' 2 '.to_r #=> (2/1) - * '300/2'.to_r #=> (150/1) - * '-9.2'.to_r #=> (-46/5) - * '-9.2e2'.to_r #=> (-920/1) - * '1_234_567'.to_r #=> (1234567/1) - * '21 June 09'.to_r #=> (21/1) - * '21/06/09'.to_r #=> (7/2) - * 'BWV 1079'.to_r #=> (0/1) - * - * NOTE: "0.3".to_r isn't the same as 0.3.to_r. The former is - * equivalent to "3/10".to_r, but the latter isn't so. + * str.to_r -> rational * - * "0.3".to_r == 3/10r #=> true - * 0.3.to_r == 3/10r #=> false + * Returns the result of interpreting leading characters in +self+ as a rational value: + * + * '123'.to_r # => (123/1) # Integer literal. + * '300/2'.to_r # => (150/1) # Rational literal. + * '-9.2'.to_r # => (-46/5) # Float literal. + * '-9.2e2'.to_r # => (-920/1) # Float literal. + * + * Ignores leading and trailing whitespace, and trailing non-numeric characters: + * + * ' 2 '.to_r # => (2/1) + * '21-Jun-09'.to_r # => (21/1) + * + * Returns \Rational zero if there are no leading numeric characters. + * + * 'BWV 1079'.to_r # => (0/1) + * + * NOTE: '0.3'.to_r is equivalent to 3/10r, + * but is different from 0.3.to_r: + * + * '0.3'.to_r # => (3/10) + * 3/10r # => (3/10) + * 0.3.to_r # => (5404319552844595/18014398509481984) * - * See also Kernel#Rational. + * Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString]. */ static VALUE string_to_r(VALUE self) diff --git a/test/rubygems/test_gem_package_tar_header_ractor.rb b/test/rubygems/test_gem_package_tar_header_ractor.rb new file mode 100644 index 00000000000000..6f417f43f90cd2 --- /dev/null +++ b/test/rubygems/test_gem_package_tar_header_ractor.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true +require_relative "package/tar_test_case" + +class TestGemPackageTarHeaderRactor < Gem::Package::TarTestCase + ASSERT_HEADERS_EQUAL = <<~RUBY + def assert_headers_equal(expected, actual) + expected = expected.to_s unless String === expected + actual = actual.to_s unless String === actual + + fields = %w[ + name 100 + mode 8 + uid 8 + gid 8 + size 12 + mtime 12 + checksum 8 + typeflag 1 + linkname 100 + magic 6 + version 2 + uname 32 + gname 32 + devmajor 8 + devminor 8 + prefix 155 + ] + + offset = 0 + + until fields.empty? do + name = fields.shift + length = fields.shift.to_i + + if name == "checksum" + chksum_off = offset + offset += length + next + end + + assert_equal expected[offset, length], actual[offset, length] + + offset += length + end + + assert_equal expected[chksum_off, 8], actual[chksum_off, 8] + end + RUBY + + SETUP = <<~RUBY + header = { + name: "x", + mode: 0o644, + uid: 1000, + gid: 10_000, + size: 100, + mtime: 12_345, + typeflag: "0", + linkname: "link", + uname: "user", + gname: "group", + devmajor: 1, + devminor: 2, + prefix: "y", + } + + tar_header = Gem::Package::TarHeader.new header + RUBY + + def test_decode_in_ractor + assert_ractor(ASSERT_HEADERS_EQUAL + SETUP + <<~RUBY, require: ["rubygems/package", "stringio"]) + new_header = Ractor.new(tar_header.to_s) do |str| + Gem::Package::TarHeader.from StringIO.new str + end.value + + assert_headers_equal tar_header, new_header + RUBY + end + + def test_encode_in_ractor + assert_ractor(ASSERT_HEADERS_EQUAL + SETUP + <<~RUBY, require: ["rubygems/package", "stringio"]) + header_bytes = tar_header.to_s + + new_header_bytes = Ractor.new(header_bytes) do |str| + new_header = Gem::Package::TarHeader.from StringIO.new str + new_header.to_s + end.value + + assert_headers_equal header_bytes, new_header_bytes + RUBY + end +end diff --git a/tool/lib/core_assertions.rb b/tool/lib/core_assertions.rb index fbf2c1a8bb3174..5d4c733a73d3be 100644 --- a/tool/lib/core_assertions.rb +++ b/tool/lib/core_assertions.rb @@ -339,6 +339,8 @@ def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **o args = args.dup args.insert((Hash === args.first ? 1 : 0), "-w", "--disable=gems", *$:.map {|l| "-I#{l}"}) args << "--debug" if RUBY_ENGINE == 'jruby' # warning: tracing (e.g. set_trace_func) will not capture all events without --debug flag + # power_assert 3 requires ruby 3.1 or later + args << "-W:no-experimental" if RUBY_VERSION < "3.1." stdout, stderr, status = EnvUtil.invoke_ruby(args, src, capture_stdout, true, **opt) if sanitizers&.lsan_enabled? @@ -394,7 +396,11 @@ def assert_ractor(src, args: [], require: nil, require_relative: nil, file: nil, shim_value = "class Ractor; alias value take; end" unless Ractor.method_defined?(:value) shim_join = "class Ractor; alias join take; end" unless Ractor.method_defined?(:join) - require = "require #{require.inspect}" if require + if require + require = [require] unless require.is_a?(Array) + require = require.map {|r| "require #{r.inspect}"}.join("\n") + end + if require_relative dir = File.dirname(caller_locations[0,1][0].absolute_path) full_path = File.expand_path(require_relative, dir) diff --git a/tool/lib/envutil.rb b/tool/lib/envutil.rb index fef9a0c992b28c..ea1f83e6f0b3bc 100644 --- a/tool/lib/envutil.rb +++ b/tool/lib/envutil.rb @@ -104,9 +104,11 @@ def dump(pid, timeout: 60, reprieve: timeout&.div(4)) else return unless dpid [[timeout, :TERM], [reprieve, :KILL]].find do |t, sig| - return EnvUtil.timeout(t) {Process.wait(dpid)} - rescue Timeout::Error - Process.kill(sig, dpid) + begin + return EnvUtil.timeout(t) {Process.wait(dpid)} + rescue Timeout::Error + Process.kill(sig, dpid) + end end true end diff --git a/vm_method.c b/vm_method.c index bf04140cb7fd19..179deb749daeec 100644 --- a/vm_method.c +++ b/vm_method.c @@ -563,6 +563,7 @@ invalidate_ccs_in_iclass_cc_tbl(VALUE value, void *data) { struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)value; vm_cme_invalidate((rb_callable_method_entry_t *)ccs->cme); + xfree(ccs); return ID_TABLE_DELETE; }