diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 32c49518595817..f699cba2253a53 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -77,15 +77,15 @@ jobs:
run: sudo rm /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb
- name: Initialize CodeQL
- uses: github/codeql-action/init@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
+ uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
with:
languages: ${{ matrix.language }}
- name: Autobuild
- uses: github/codeql-action/autobuild@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
+ uses: github/codeql-action/autobuild@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
+ uses: github/codeql-action/analyze@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
with:
category: '/language:${{ matrix.language }}'
upload: False
@@ -115,7 +115,7 @@ jobs:
continue-on-error: true
- name: Upload SARIF
- uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
+ uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
with:
sarif_file: sarif-results/${{ matrix.language }}.sarif
continue-on-error: true
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index 4dc912f3db4ecd..097f086202af3c 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -67,6 +67,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: 'Upload to code-scanning'
- uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
+ uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13
with:
sarif_file: results.sarif
diff --git a/LEGAL b/LEGAL
index 162ba784836c1f..55c7ffc2917040 100644
--- a/LEGAL
+++ b/LEGAL
@@ -702,31 +702,6 @@ mentioned below.
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
-[ext/json/generator/generator.c]
-
- The file contains the following copyright notice.
-
- >>>
- Copyright 2001-2004:: Unicode, Inc.
-
- Disclaimer::
-
- This source code is provided as is by Unicode, Inc. No claims are
- made as to fitness for any particular purpose. No warranties of any
- kind are expressed or implied. The recipient agrees to determine
- applicability of information provided. If this file has been
- purchased on magnetic or optical media from Unicode, Inc., the
- sole remedy for any claim will be exchange of defective media
- within 90 days of receipt.
-
- Limitations on Rights to Redistribute This Code::
-
- Unicode, Inc. hereby grants the right to freely use the information
- supplied in this file in the creation of products supporting the
- Unicode Standard, and to make copies of this file in any form
- for internal or external distribution as long as this notice
- remains attached.
-
[ext/psych]
[test/psych]
diff --git a/NEWS.md b/NEWS.md
index 89aad671870881..25e42db1a944eb 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -107,7 +107,7 @@ The following bundled gems are updated.
* rexml 3.3.8
* rss 0.3.1
* net-ftp 0.3.8
-* net-imap 0.4.16
+* net-imap 0.4.17
* net-smtp 0.5.0
* rbs 3.6.1
* typeprof 0.21.11
diff --git a/array.c b/array.c
index b6768e52d3b4c7..015395f74caa72 100644
--- a/array.c
+++ b/array.c
@@ -1512,35 +1512,40 @@ rb_ary_shift(VALUE ary)
/*
* call-seq:
- * array.shift -> object or nil
- * array.shift(n) -> new_array
+ * shift -> object or nil
+ * shift(count) -> new_array or nil
*
- * Removes and returns leading elements.
+ * Removes and returns leading elements from +self+.
*
- * When no argument is given, removes and returns the first element:
+ * With no argument, removes and returns one element, if available,
+ * or +nil+ otherwise:
*
- * a = [:foo, 'bar', 2]
- * a.shift # => :foo
- * a # => ['bar', 2]
- *
- * Returns +nil+ if +self+ is empty.
+ * a = [0, 1, 2, 3]
+ * a.shift # => 0
+ * a # => [1, 2, 3]
+ * [].shift # => nil
*
- * When positive Integer argument +n+ is given, removes the first +n+ elements;
- * returns those elements in a new +Array+:
+ * With non-negative numeric argument +count+ given,
+ * removes and returns the first +count+ elements:
*
- * a = [:foo, 'bar', 2]
- * a.shift(2) # => [:foo, 'bar']
- * a # => [2]
+ * a = [0, 1, 2, 3]
+ * a.shift(2) # => [0, 1]
+ * a # => [2, 3]
+ * a.shift(1.1) # => [2]
+ * a # => [3]
+ * a.shift(0) # => []
+ * a # => [3]
*
- * If +n+ is as large as or larger than self.length,
- * removes all elements; returns those elements in a new +Array+:
+ * If +count+ is large,
+ * removes and returns all elements:
*
- * a = [:foo, 'bar', 2]
- * a.shift(3) # => [:foo, 'bar', 2]
+ * a = [0, 1, 2, 3]
+ * a.shift(50) # => [0, 1, 2, 3]
+ * a # => []
*
- * If +n+ is zero, returns a new empty +Array+; +self+ is unmodified.
+ * If +self+ is empty, returns a new empty array.
*
- * Related: #push, #pop, #unshift.
+ * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
*/
static VALUE
diff --git a/array.rb b/array.rb
index 3d64d31e95ee3e..23d38ebc655f7e 100644
--- a/array.rb
+++ b/array.rb
@@ -45,15 +45,25 @@ def each
end
# call-seq:
- # array.shuffle!(random: Random) -> array
+ # shuffle!(random: Random) -> self
#
- # Shuffles the elements of +self+ in place.
- # a = [1, 2, 3] #=> [1, 2, 3]
- # a.shuffle! #=> [2, 3, 1]
- # a #=> [2, 3, 1]
+ # Shuffles all elements in +self+ into a random order,
+ # as selected by the object given by keyword argument +random+;
+ # returns +self+:
#
- # The optional +random+ argument will be used as the random number generator:
- # a.shuffle!(random: Random.new(1)) #=> [1, 3, 2]
+ # a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+ # a.shuffle! # => [5, 3, 8, 7, 6, 1, 9, 4, 2, 0]
+ # a.shuffle! # => [9, 4, 0, 6, 2, 8, 1, 5, 3, 7]
+ #
+ # Duplicate elements are included:
+ #
+ # a = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
+ # a.shuffle! # => [1, 0, 0, 1, 1, 0, 1, 0, 0, 1]
+ # a.shuffle! # => [0, 1, 0, 1, 1, 0, 1, 0, 1, 0]
+ #
+ # The object given with keyword argument +random+ is used as the random number generator.
+ #
+ # Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
def shuffle!(random: Random)
Primitive.rb_ary_shuffle_bang(random)
end
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index f0192c04142ae0..545243a0e4c6b4 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -123,7 +123,7 @@ def test(name, args)
# regression test for GC marking stubs in invalidated code
assert_normal_exit %q{
- skip true unless defined?(GC.compact)
+ skip true unless GC.respond_to?(:compact)
garbage = Array.new(10_000) { [] } # create garbage to cause iseq movement
eval(<<~RUBY)
def foo(n, garbage)
@@ -158,7 +158,7 @@ def call_foo = foo(0, 1, 2, 3, &->{})
# regression test for invokeblock iseq guard
assert_equal 'ok', %q{
- skip :ok unless defined?(GC.compact)
+ skip :ok unless GC.respond_to?(:compact)
def foo = yield
10.times do |i|
ret = eval("foo { #{i} }")
@@ -1230,7 +1230,7 @@ def special.[](idx)
# Test that object references in generated code get marked and moved
assert_equal "good", %q{
- skip :good unless defined?(GC.compact)
+ skip :good unless GC.respond_to?(:compact)
def bar
"good"
end
@@ -2351,7 +2351,7 @@ def foo(obj)
# Test EP == BP invalidation with moving ISEQs
assert_equal 'ok', %q{
- skip :ok unless defined?(GC.compact)
+ skip :ok unless GC.respond_to?(:compact)
def entry
ok = proc { :ok } # set #entry as an EP-escaping ISEQ
[nil].reverse_each do # avoid exiting the JIT frame on the constant
diff --git a/ext/json/json.gemspec b/ext/json/json.gemspec
index 5a951a8b25db83..c714ba86d19c87 100644
--- a/ext/json/json.gemspec
+++ b/ext/json/json.gemspec
@@ -17,7 +17,9 @@ Gem::Specification.new do |s|
s.rdoc_options = ["--title", "JSON implementation for Ruby", "--main", "README.md"]
s.files = [
"CHANGES.md",
- "LICENSE",
+ "COPYING",
+ "BSDL",
+ "LEGAL",
"README.md",
"ext/json/ext/fbuffer/fbuffer.h",
"ext/json/ext/generator/depend",
diff --git a/ext/socket/init.c b/ext/socket/init.c
index b02ac5fef5748f..83af8c5b0e090e 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -473,10 +473,11 @@ rsock_socket(int domain, int type, int proto)
/* emulate blocking connect behavior on EINTR or non-blocking socket */
static int
-wait_connectable(int fd, struct timeval *timeout)
+wait_connectable(VALUE self, VALUE timeout)
{
- int sockerr, revents;
+ int sockerr;
socklen_t sockerrlen;
+ int fd = rb_io_descriptor(self);
sockerrlen = (socklen_t)sizeof(sockerr);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &sockerrlen) < 0)
@@ -510,7 +511,13 @@ wait_connectable(int fd, struct timeval *timeout)
*
* Note: rb_wait_for_single_fd already retries on EINTR/ERESTART
*/
- revents = rb_wait_for_single_fd(fd, RB_WAITFD_IN|RB_WAITFD_OUT, timeout);
+ VALUE result = rb_io_wait(self, RB_INT2NUM(RUBY_IO_READABLE|RUBY_IO_WRITABLE), timeout);
+
+ if (result == Qfalse) {
+ rb_raise(rb_eIOTimeoutError, "Connect timed out!");
+ }
+
+ int revents = RB_NUM2INT(result);
if (revents < 0)
return -1;
@@ -525,12 +532,6 @@ wait_connectable(int fd, struct timeval *timeout)
* be defensive in case some platforms set SO_ERROR on the original,
* interrupted connect()
*/
-
- /* when the connection timed out, no errno is set and revents is 0. */
- if (timeout && revents == 0) {
- errno = ETIMEDOUT;
- return -1;
- }
case EINTR:
#ifdef ERESTART
case ERESTART:
@@ -578,7 +579,7 @@ socks_connect_blocking(void *data)
#endif
int
-rsock_connect(VALUE self, const struct sockaddr *sockaddr, int len, int socks, struct timeval *timeout)
+rsock_connect(VALUE self, const struct sockaddr *sockaddr, int len, int socks, VALUE timeout)
{
int descriptor = rb_io_descriptor(self);
rb_blocking_function_t *func = connect_blocking;
@@ -602,7 +603,7 @@ rsock_connect(VALUE self, const struct sockaddr *sockaddr, int len, int socks, s
#ifdef EINPROGRESS
case EINPROGRESS:
#endif
- return wait_connectable(descriptor, timeout);
+ return wait_connectable(self, timeout);
}
}
return status;
diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c
index 7992212b87c324..3de84454355b66 100644
--- a/ext/socket/ipsocket.c
+++ b/ext/socket/ipsocket.c
@@ -55,13 +55,6 @@ init_inetsock_internal(VALUE v)
int family = AF_UNSPEC;
const char *syscall = 0;
VALUE connect_timeout = arg->connect_timeout;
- struct timeval tv_storage;
- struct timeval *tv = NULL;
-
- if (!NIL_P(connect_timeout)) {
- tv_storage = rb_time_interval(connect_timeout);
- tv = &tv_storage;
- }
arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv,
family, SOCK_STREAM,
@@ -130,7 +123,7 @@ init_inetsock_internal(VALUE v)
}
if (status >= 0) {
- status = rsock_connect(io, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS), tv);
+ status = rsock_connect(io, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS), connect_timeout);
syscall = "connect(2)";
}
}
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index e4ab412f6e834a..b4daa66071a472 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -379,7 +379,7 @@ VALUE rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
VALUE ex, enum sock_recv_type from);
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
-int rsock_connect(VALUE self, const struct sockaddr *sockaddr, int len, int socks, struct timeval *timeout);
+int rsock_connect(VALUE self, const struct sockaddr *sockaddr, int len, int socks, VALUE timeout);
VALUE rsock_s_accept(VALUE klass, VALUE io, struct sockaddr *sockaddr, socklen_t *len);
VALUE rsock_s_accept_nonblock(VALUE klass, VALUE ex, rb_io_t *fptr,
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index c974aafe55102c..487a293c4e2e61 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -387,16 +387,15 @@ rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
* * connect function in Microsoft's Winsock functions reference
*/
static VALUE
-sock_connect(VALUE sock, VALUE addr)
+sock_connect(VALUE self, VALUE addr)
{
VALUE rai;
- rb_io_t *fptr;
SockAddrStringValueWithAddrinfo(addr, rai);
addr = rb_str_new4(addr);
- GetOpenFile(sock, fptr);
- int result = rsock_connect(sock, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), 0, NULL);
+ int result = rsock_connect(self, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), 0, RUBY_IO_TIMEOUT_DEFAULT);
+
if (result < 0) {
rsock_sys_fail_raddrinfo_or_sockaddr("connect(2)", addr, rai);
}
diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c
index c31e9dbf6facac..a984933c9fd3fe 100644
--- a/ext/socket/udpsocket.c
+++ b/ext/socket/udpsocket.c
@@ -56,7 +56,7 @@ udp_connect_internal(VALUE v)
struct addrinfo *res;
for (res = arg->res->ai; res; res = res->ai_next) {
- if (rsock_connect(arg->io, res->ai_addr, res->ai_addrlen, 0, NULL) >= 0) {
+ if (rsock_connect(arg->io, res->ai_addr, res->ai_addrlen, 0, RUBY_IO_TIMEOUT_DEFAULT) >= 0) {
return Qtrue;
}
}
diff --git a/ext/socket/unixsocket.c b/ext/socket/unixsocket.c
index 11d7c0451fee96..31e2acee04e896 100644
--- a/ext/socket/unixsocket.c
+++ b/ext/socket/unixsocket.c
@@ -21,7 +21,7 @@ static VALUE
unixsock_connect_internal(VALUE a)
{
struct unixsock_arg *arg = (struct unixsock_arg *)a;
- return (VALUE)rsock_connect(arg->io, (struct sockaddr*)arg->sockaddr, arg->sockaddrlen, 0, NULL);
+ return (VALUE)rsock_connect(arg->io, (struct sockaddr*)arg->sockaddr, arg->sockaddrlen, 0, RUBY_IO_TIMEOUT_DEFAULT);
}
static VALUE
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 50d8dd40c6580c..0899861c028f75 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -1521,7 +1521,7 @@ rb_zstream_total_out(VALUE obj)
}
/*
- * Guesses the type of the data which have been inputed into the stream. The
+ * Guesses the type of the data which have been inputted into the stream. The
* returned value is either BINARY, ASCII, or
* UNKNOWN.
*/
@@ -4054,7 +4054,7 @@ rb_gzreader_read(int argc, VALUE *argv, VALUE obj)
* call-seq:
* gzipreader.readpartial(maxlen [, outbuf]) => string, outbuf
*
- * Reads at most maxlen bytes from the gziped stream but
+ * Reads at most maxlen bytes from the gzipped stream but
* it blocks only if gzipreader has no data immediately available.
* If the optional outbuf argument is present,
* it must reference a String, which will receive the data.
diff --git a/gems/bundled_gems b/gems/bundled_gems
index 0e88f06f21f422..8d0fc34ba0a3cb 100644
--- a/gems/bundled_gems
+++ b/gems/bundled_gems
@@ -13,7 +13,7 @@ test-unit 3.6.2 https://github.com/test-unit/test-unit
rexml 3.3.8 https://github.com/ruby/rexml
rss 0.3.1 https://github.com/ruby/rss
net-ftp 0.3.8 https://github.com/ruby/net-ftp
-net-imap 0.4.16 https://github.com/ruby/net-imap
+net-imap 0.4.17 https://github.com/ruby/net-imap
net-pop 0.1.2 https://github.com/ruby/net-pop
net-smtp 0.5.0 https://github.com/ruby/net-smtp
matrix 0.4.2 https://github.com/ruby/matrix
diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb
index 547102be41c22b..296bcfff38fccd 100644
--- a/lib/bundler/rubygems_ext.rb
+++ b/lib/bundler/rubygems_ext.rb
@@ -384,13 +384,13 @@ def extensions_dir
end
end
- remove_method :ignored? if new.respond_to?(:ignored?)
+ # Can be removed once RubyGems 3.5.22 support is dropped
+ unless new.respond_to?(:ignored?)
+ def ignored?
+ return @ignored unless @ignored.nil?
- # Same as RubyGems, but without warnings, because Bundler prints its own warnings
- def ignored?
- return @ignored unless @ignored.nil?
-
- @ignored = missing_extensions?
+ @ignored = missing_extensions?
+ end
end
end
diff --git a/lib/irb/history.rb b/lib/irb/history.rb
index a428003d2de946..25fa71b9c3721d 100644
--- a/lib/irb/history.rb
+++ b/lib/irb/history.rb
@@ -5,10 +5,7 @@ module History
class << self
# Integer representation of IRB.conf[:HISTORY_FILE]
.
def save_history
- num = IRB.conf[:SAVE_HISTORY].to_i
- # Bignums cause RangeErrors when slicing arrays.
- # Treat such values as 'infinite'.
- (num > save_history_max) ? -1 : num
+ IRB.conf[:SAVE_HISTORY].to_i
end
def save_history?
@@ -27,13 +24,6 @@ def history_file
IRB.rc_file("_history")
end
end
-
- private
-
- def save_history_max
- # Max fixnum (32-bit) that can be used without getting RangeError.
- 2**30 - 1
- end
end
end
@@ -90,7 +80,8 @@ def save_history
hist = history.map { |l| l.scrub.split("\n").join("\\\n") }
unless append_history || History.infinite?
- hist = hist.last(History.save_history)
+ # Check size before slicing because array.last(huge_number) raises RangeError.
+ hist = hist.last(History.save_history) if hist.size > History.save_history
end
f.puts(hist)
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index b8156597135430..f6627ca430a5a9 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -846,7 +846,11 @@ def editing_mode
when CompletionState::NORMAL
@completion_state = CompletionState::COMPLETION
when CompletionState::PERFECT_MATCH
- @dig_perfect_match_proc&.(@perfect_matched)
+ if @dig_perfect_match_proc
+ @dig_perfect_match_proc.(@perfect_matched)
+ else
+ @completion_state = CompletionState::COMPLETION
+ end
end
if just_show_list
is_menu = true
@@ -2368,9 +2372,9 @@ def finish
private def search_next_char(key, arg, need_prev_char: false, inclusive: false)
if key.instance_of?(String)
- inputed_char = key
+ inputted_char = key
else
- inputed_char = key.chr
+ inputted_char = key.chr
end
prev_total = nil
total = nil
@@ -2382,7 +2386,7 @@ def finish
width = Reline::Unicode.get_mbchar_width(mbchar)
total = [mbchar.bytesize, width]
else
- if inputed_char == mbchar
+ if inputted_char == mbchar
arg -= 1
if arg.zero?
found = true
@@ -2420,9 +2424,9 @@ def finish
private def search_prev_char(key, arg, need_next_char = false)
if key.instance_of?(String)
- inputed_char = key
+ inputted_char = key
else
- inputed_char = key.chr
+ inputted_char = key.chr
end
prev_total = nil
total = nil
@@ -2434,7 +2438,7 @@ def finish
width = Reline::Unicode.get_mbchar_width(mbchar)
total = [mbchar.bytesize, width]
else
- if inputed_char == mbchar
+ if inputted_char == mbchar
arg -= 1
if arg.zero?
found = true
diff --git a/lib/rubygems/basic_specification.rb b/lib/rubygems/basic_specification.rb
index 8c75fd41d41a57..a09e8ed0e13c81 100644
--- a/lib/rubygems/basic_specification.rb
+++ b/lib/rubygems/basic_specification.rb
@@ -71,7 +71,14 @@ def base_dir
# Return true if this spec can require +file+.
def contains_requirable_file?(file)
- return false if ignored?
+ if ignored?
+ if platform == Gem::Platform::RUBY || Gem::Platform.local === platform
+ warn "Ignoring #{full_name} because its extensions are not built. " \
+ "Try: gem pristine #{name} --version #{version}"
+ end
+
+ return false
+ end
is_soext = file.end_with?(".so", ".o")
@@ -89,14 +96,6 @@ def ignored?
return @ignored unless @ignored.nil?
@ignored = missing_extensions?
- return false unless @ignored
-
- if platform == Gem::Platform::RUBY || Gem::Platform.local === platform
- warn "Ignoring #{full_name} because its extensions are not built. " \
- "Try: gem pristine #{name} --version #{version}"
- end
-
- true
end
def default_gem?
diff --git a/lib/rubygems/commands/contents_command.rb b/lib/rubygems/commands/contents_command.rb
index 807158d9c97c3e..bd0cbce8ba69f8 100644
--- a/lib/rubygems/commands/contents_command.rb
+++ b/lib/rubygems/commands/contents_command.rb
@@ -103,16 +103,23 @@ def files_in_gem(spec)
def files_in_default_gem(spec)
spec.files.map do |file|
- case file
- when %r{\A#{spec.bindir}/}
- # $' is POSTMATCH
- [RbConfig::CONFIG["bindir"], $']
- when /\.so\z/
- [RbConfig::CONFIG["archdir"], file]
+ if file.start_with?("#{spec.bindir}/")
+ [RbConfig::CONFIG["bindir"], file.delete_prefix("#{spec.bindir}/")]
else
- [RbConfig::CONFIG["rubylibdir"], file]
+ gem spec.name, spec.version
+
+ require_path = spec.require_paths.find do |path|
+ file.start_with?("#{path}/")
+ end
+
+ requirable_part = file.delete_prefix("#{require_path}/")
+
+ resolve = $LOAD_PATH.resolve_feature_path(requirable_part)&.last
+ next unless resolve
+
+ [resolve.delete_suffix(requirable_part), requirable_part]
end
- end
+ end.compact
end
def gem_contents(name)
diff --git a/lib/rubygems/specification_record.rb b/lib/rubygems/specification_record.rb
index d838fcea26912a..195a35549670ed 100644
--- a/lib/rubygems/specification_record.rb
+++ b/lib/rubygems/specification_record.rb
@@ -30,7 +30,7 @@ def initialize(dirs)
# Returns the list of all specifications in the record
def all
- @all ||= Gem.loaded_specs.values + stubs.map(&:to_spec)
+ @all ||= stubs.map(&:to_spec)
end
##
diff --git a/prism/extension.c b/prism/extension.c
index 47603fd9b4f506..26415c2b6da977 100644
--- a/prism/extension.c
+++ b/prism/extension.c
@@ -1153,6 +1153,7 @@ string_query(pm_string_query_t result) {
case PM_STRING_QUERY_TRUE:
return Qtrue;
}
+ return Qfalse;
}
/**
diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb
index d686355270c75d..fa5b5c56d60f5a 100644
--- a/spec/ruby/core/time/new_spec.rb
+++ b/spec/ruby/core/time/new_spec.rb
@@ -625,15 +625,21 @@ def obj.to_int; 3; end
-> {
Time.new("2020-12-25 00:56:17 +23:59:60")
- }.should raise_error(ArgumentError, "utc_offset out of range")
+ }.should raise_error(ArgumentError, /utc_offset/)
-> {
Time.new("2020-12-25 00:56:17 +24:00")
- }.should raise_error(ArgumentError, "utc_offset out of range")
+ }.should raise_error(ArgumentError, /utc_offset/)
-> {
Time.new("2020-12-25 00:56:17 +23:61")
- }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +23:61')
+ }.should raise_error(ArgumentError, /utc_offset/)
+
+ ruby_bug '#20797', ''...'3.4' do
+ -> {
+ Time.new("2020-12-25 00:56:17 +00:23:61")
+ }.should raise_error(ArgumentError, /utc_offset/)
+ end
end
it "raises ArgumentError if string has not ascii-compatible encoding" do
diff --git a/spec/ruby/library/socket/socket/connect_spec.rb b/spec/ruby/library/socket/socket/connect_spec.rb
index 8653fba552bdcd..175c9942bcd667 100644
--- a/spec/ruby/library/socket/socket/connect_spec.rb
+++ b/spec/ruby/library/socket/socket/connect_spec.rb
@@ -53,4 +53,18 @@
end
end
end
+
+ ruby_version_is "3.4" do
+ it "fails with timeout" do
+ # TEST-NET-1 IP address are reserved for documentation and example purposes.
+ address = Socket.pack_sockaddr_in(1, "192.0.2.1")
+
+ client = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
+ client.timeout = 0
+
+ -> {
+ client.connect(address)
+ }.should raise_error(IO::TimeoutError)
+ end
+ end
end
diff --git a/test/irb/yamatanooroti/test_rendering.rb b/test/irb/yamatanooroti/test_rendering.rb
index 834c501d5c6035..ac6ce5346ea6c9 100644
--- a/test/irb/yamatanooroti/test_rendering.rb
+++ b/test/irb/yamatanooroti/test_rendering.rb
@@ -39,49 +39,44 @@ def teardown
end
def test_launch
- write_irbrc <<~'LINES'
- puts 'start IRB'
- LINES
- start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
write(<<~EOC)
'Hello, World!'
EOC
- close
assert_screen(<<~EOC)
- start IRB
irb(main):001> 'Hello, World!'
=> "Hello, World!"
irb(main):002>
EOC
+ close
end
def test_configuration_file_is_skipped_with_dash_f
write_irbrc <<~'LINES'
puts '.irbrc file should be ignored when -f is used'
LINES
- start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb -f}, startup_message: '')
+ start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb -f}, startup_message: /irb\(main\)/)
write(<<~EOC)
'Hello, World!'
EOC
- close
assert_screen(<<~EOC)
irb(main):001> 'Hello, World!'
=> "Hello, World!"
irb(main):002>
EOC
+ close
end
def test_configuration_file_is_skipped_with_dash_f_for_nested_sessions
write_irbrc <<~'LINES'
puts '.irbrc file should be ignored when -f is used'
LINES
- start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb -f}, startup_message: '')
+ start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb -f}, startup_message: /irb\(main\)/)
write(<<~EOC)
'Hello, World!'
binding.irb
exit!
EOC
- close
assert_screen(<<~EOC)
irb(main):001> 'Hello, World!'
=> "Hello, World!"
@@ -89,13 +84,11 @@ def test_configuration_file_is_skipped_with_dash_f_for_nested_sessions
irb(main):003> exit!
irb(main):001>
EOC
+ close
end
def test_nomultiline
- write_irbrc <<~'LINES'
- puts 'start IRB'
- LINES
- start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb --nomultiline}, startup_message: 'start IRB')
+ start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb --nomultiline}, startup_message: /irb\(main\)/)
write(<<~EOC)
if true
if false
@@ -105,9 +98,7 @@ def test_nomultiline
end
end
EOC
- close
assert_screen(<<~EOC)
- start IRB
irb(main):001> if true
irb(main):002* if false
irb(main):003* a = "hello
@@ -118,13 +109,11 @@ def test_nomultiline
=> nil
irb(main):008>
EOC
+ close
end
def test_multiline_paste
- write_irbrc <<~'LINES'
- puts 'start IRB'
- LINES
- start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(25, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
write(<<~EOC)
class A
def inspect; '#'; end
@@ -139,9 +128,7 @@ def b; true; end
.b
.itself
EOC
- close
assert_screen(<<~EOC)
- start IRB
irb(main):001* class A
irb(main):002* def inspect; '#'; end
irb(main):003* def a; self; end
@@ -159,13 +146,11 @@ def b; true; end
=> true
irb(main):013>
EOC
+ close
end
def test_evaluate_each_toplevel_statement_by_multiline_paste
- write_irbrc <<~'LINES'
- puts 'start IRB'
- LINES
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
write(<<~EOC)
class A
def inspect; '#'; end
@@ -193,9 +178,7 @@ class A def b; self; end; def c; true; end; end;
&.b()
.itself
EOC
- close
assert_screen(<<~EOC)
- start IRB
irb(main):001* class A
irb(main):002* def inspect; '#'; end
irb(main):003* def b; self; end
@@ -230,36 +213,28 @@ class A def b; self; end; def c; true; end; end;
=> #
irb(main):026>
EOC
+ close
end
def test_symbol_with_backtick
- write_irbrc <<~'LINES'
- puts 'start IRB'
- LINES
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
write(<<~EOC)
:`
EOC
- close
assert_screen(<<~EOC)
- start IRB
irb(main):001> :`
=> :`
irb(main):002>
EOC
+ close
end
def test_autocomplete_with_multiple_doc_namespaces
- write_irbrc <<~'LINES'
- puts 'start IRB'
- LINES
- start_terminal(3, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(3, 50, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
write("{}.__id_")
write("\C-i")
- sleep 0.2
+ assert_screen(/irb\(main\):001> {}\.__id__\n }\.__id__(?:Press )?/)
close
- screen = result.join("\n").sub(/\n*\z/, "\n")
- assert_match(/start\ IRB\nirb\(main\):001> {}\.__id__\n }\.__id__(?:Press )?/, screen)
end
def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_right
@@ -273,31 +248,27 @@ def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_right
:PROMPT_C => "%03n> "
}
IRB.conf[:PROMPT_MODE] = :MY_PROMPT
- puts 'start IRB'
LINES
- start_terminal(4, 19, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(4, 19, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /001>/)
write("IR")
write("\C-i")
- sleep 0.2
- close
# This is because on macOS we display different shortcut for displaying the full doc
# 'O' is for 'Option' and 'A' is for 'Alt'
if RUBY_PLATFORM =~ /darwin/
assert_screen(<<~EOC)
- start IRB
001> IRB
IRBPress Opti
IRB
EOC
else
assert_screen(<<~EOC)
- start IRB
001> IRB
IRBPress Alt+
IRB
EOC
end
+ close
end
def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_left
@@ -311,154 +282,129 @@ def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_left
:PROMPT_C => "%03n> "
}
IRB.conf[:PROMPT_MODE] = :MY_PROMPT
- puts 'start IRB'
LINES
- start_terminal(4, 12, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(4, 12, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /001>/)
write("IR")
write("\C-i")
- sleep 0.2
- close
assert_screen(<<~EOC)
- start IRB
001> IRB
PressIRB
IRB
EOC
+ close
end
def test_assignment_expression_truncate
- write_irbrc <<~'LINES'
- puts 'start IRB'
- LINES
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
# Assignment expression code that turns into non-assignment expression after evaluation
code = "a /'/i if false; a=1; x=1000.times.to_a#'.size"
write(code + "\n")
- close
assert_screen(<<~EOC)
- start IRB
irb(main):001> #{code}
=>
[0,
...
irb(main):002>
EOC
+ close
end
def test_ctrl_c_is_handled
- write_irbrc <<~'LINES'
- puts 'start IRB'
- LINES
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
# Assignment expression code that turns into non-assignment expression after evaluation
write("\C-c")
- close
assert_screen(<<~EOC)
- start IRB
irb(main):001>
^C
irb(main):001>
EOC
+ close
end
def test_show_cmds_with_pager_can_quit_with_ctrl_c
- write_irbrc <<~'LINES'
- puts 'start IRB'
- LINES
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
write("help\n")
write("G") # move to the end of the screen
write("\C-c") # quit pager
write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
- close
- screen = result.join("\n").sub(/\n*\z/, "\n")
- # IRB::Abort should be rescued
- assert_not_match(/IRB::Abort/, screen)
# IRB should resume
- assert_match(/foobar/, screen)
+ assert_screen(/foobar/)
+ # IRB::Abort should be rescued
+ assert_screen(/\A(?!IRB::Abort)/)
+ close
end
def test_pager_page_content_pages_output_when_it_does_not_fit_in_the_screen_because_of_total_length
write_irbrc <<~'LINES'
- puts 'start IRB'
require "irb/pager"
LINES
- start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
write("IRB::Pager.page_content('a' * (80 * 8))\n")
write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
- close
- screen = result.join("\n").sub(/\n*\z/, "\n")
- assert_match(/a{80}/, screen)
+ assert_screen(/a{80}/)
# because pager is invoked, foobar will not be evaluated
- assert_not_match(/foobar/, screen)
+ assert_screen(/\A(?!foobar)/)
+ close
end
def test_pager_page_content_pages_output_when_it_does_not_fit_in_the_screen_because_of_screen_height
write_irbrc <<~'LINES'
- puts 'start IRB'
require "irb/pager"
LINES
- start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
write("IRB::Pager.page_content('a\n' * 8)\n")
write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
- close
- screen = result.join("\n").sub(/\n*\z/, "\n")
- assert_match(/(a\n){8}/, screen)
+ assert_screen(/(a\n){8}/)
# because pager is invoked, foobar will not be evaluated
- assert_not_match(/foobar/, screen)
+ assert_screen(/\A(?!foobar)/)
+ close
end
def test_pager_page_content_doesnt_page_output_when_it_fits_in_the_screen
write_irbrc <<~'LINES'
- puts 'start IRB'
require "irb/pager"
LINES
- start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
write("IRB::Pager.page_content('a' * (80 * 7))\n")
write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
- close
- screen = result.join("\n").sub(/\n*\z/, "\n")
- assert_match(/a{80}/, screen)
+ assert_screen(/a{80}/)
# because pager is not invoked, foobar will be evaluated
- assert_match(/foobar/, screen)
+ assert_screen(/foobar/)
+ close
end
def test_long_evaluation_output_is_paged
write_irbrc <<~'LINES'
- puts 'start IRB'
require "irb/pager"
LINES
- start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
write("'a' * 80 * 11\n")
write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
- close
- screen = result.join("\n").sub(/\n*\z/, "\n")
- assert_match(/(a{80}\n){8}/, screen)
+ assert_screen(/(a{80}\n){8}/)
# because pager is invoked, foobar will not be evaluated
- assert_not_match(/foobar/, screen)
+ assert_screen(/\A(?!foobar)/)
+ close
end
def test_long_evaluation_output_is_preserved_after_paging
write_irbrc <<~'LINES'
- puts 'start IRB'
require "irb/pager"
LINES
- start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
+ start_terminal(10, 80, %W{ruby -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: /irb\(main\)/)
write("'a' * 80 * 11\n")
write("q") # quit pager
write("'foo' + 'bar'\n") # eval something to make sure IRB resumes
- close
- screen = result.join("\n").sub(/\n*\z/, "\n")
# confirm pager has exited
- assert_match(/foobar/, screen)
+ assert_screen(/foobar/)
# confirm output is preserved
- assert_match(/(a{80}\n){6}/, screen)
+ assert_screen(/(a{80}\n){6}/)
+ close
end
def test_debug_integration_hints_debugger_commands
@@ -467,21 +413,19 @@ def test_debug_integration_hints_debugger_commands
LINES
script = Tempfile.create(["debug", ".rb"])
script.write <<~RUBY
- puts 'start IRB'
binding.irb
RUBY
script.close
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: 'start IRB')
+ start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: /irb\(main\)/)
write("debug\n")
write("pp 1\n")
write("pp 1")
- close
- screen = result.join("\n").sub(/\n*\z/, "\n")
# submitted input shouldn't contain hint
- assert_include(screen, "irb:rdbg(main):002> pp 1\n")
+ assert_screen(/irb:rdbg\(main\):002> pp 1\n/)
# unsubmitted input should contain hint
- assert_include(screen, "irb:rdbg(main):003> pp 1 # debug command\n")
+ assert_screen(/irb:rdbg\(main\):003> pp 1 # debug command\n/)
+ close
ensure
File.unlink(script) if script
end
@@ -492,17 +436,14 @@ def test_debug_integration_doesnt_hint_non_debugger_commands
LINES
script = Tempfile.create(["debug", ".rb"])
script.write <<~RUBY
- puts 'start IRB'
binding.irb
RUBY
script.close
- start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: 'start IRB')
+ start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: /irb\(main\)/)
write("debug\n")
write("foo")
+ assert_screen(/irb:rdbg\(main\):002> foo\n/)
close
-
- screen = result.join("\n").sub(/\n*\z/, "\n")
- assert_include(screen, "irb:rdbg(main):002> foo\n")
ensure
File.unlink(script) if script
end
@@ -520,11 +461,9 @@ def test_debug_integration_doesnt_hint_debugger_commands_in_nomultiline_mode
start_terminal(40, 80, %W{ruby -I#{@pwd}/lib #{script.to_path}}, startup_message: 'start IRB')
write("debug\n")
write("pp 1")
- close
-
- screen = result.join("\n").sub(/\n*\z/, "\n")
# submitted input shouldn't contain hint
- assert_include(screen, "irb:rdbg(main):002> pp 1\n")
+ assert_screen(/irb:rdbg\(main\):002> pp 1\n/)
+ close
ensure
File.unlink(script) if script
end
diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb
index dc12c803f57787..2ebd91dc2ecf45 100644
--- a/test/reline/test_key_actor_emacs.rb
+++ b/test/reline/test_key_actor_emacs.rb
@@ -260,7 +260,7 @@ def test_ed_clear_screen
assert_empty(@line_editor.instance_variable_get(:@rendered_screen).lines)
end
- def test_ed_clear_screen_with_inputed
+ def test_ed_clear_screen_with_inputted
input_keys('abc')
input_keys("\C-b", false)
@line_editor.instance_variable_get(:@rendered_screen).lines = [[]]
@@ -920,6 +920,29 @@ def test_completion_with_perfect_match
assert_equal('foo_bar', matched)
end
+ def test_continuous_completion_with_perfect_match
+ @line_editor.completion_proc = proc { |word|
+ word == 'f' ? ['foo'] : %w[foobar foobaz]
+ }
+ input_keys('f')
+ input_keys("\C-i", false)
+ assert_line_around_cursor('foo', '')
+ input_keys("\C-i", false)
+ assert_line_around_cursor('fooba', '')
+ end
+
+ def test_continuous_completion_disabled_with_perfect_match
+ @line_editor.completion_proc = proc { |word|
+ word == 'f' ? ['foo'] : %w[foobar foobaz]
+ }
+ @line_editor.dig_perfect_match_proc = proc {}
+ input_keys('f')
+ input_keys("\C-i", false)
+ assert_line_around_cursor('foo', '')
+ input_keys("\C-i", false)
+ assert_line_around_cursor('foo', '')
+ end
+
def test_completion_with_completion_ignore_case
@line_editor.completion_proc = proc { |word|
%w{
diff --git a/test/ruby/test_objectspace.rb b/test/ruby/test_objectspace.rb
index beb66da7e216e9..5c79983b7e87d0 100644
--- a/test/ruby/test_objectspace.rb
+++ b/test/ruby/test_objectspace.rb
@@ -208,7 +208,6 @@ def test_finalizer_thread_raise
main_th.raise(my_error)
end
GC.start
- puts "After GC"
sleep(10)
assert(false)
rescue my_error
diff --git a/test/ruby/test_time.rb b/test/ruby/test_time.rb
index 99ee84f247e2d0..333edb80218a64 100644
--- a/test/ruby/test_time.rb
+++ b/test/ruby/test_time.rb
@@ -152,6 +152,18 @@ def test_new_from_string
assert_raise_with_message(ArgumentError, /can't parse/) {
Time.new("2020-12-02 00:00:00 ")
}
+ assert_raise_with_message(ArgumentError, /utc_offset/) {
+ Time.new("2020-12-25 00:00:00 +0960")
+ }
+ assert_raise_with_message(ArgumentError, /utc_offset/) {
+ Time.new("2020-12-25 00:00:00 +09:60")
+ }
+ assert_raise_with_message(ArgumentError, /utc_offset/) {
+ Time.new("2020-12-25 00:00:00 +090060")
+ }
+ assert_raise_with_message(ArgumentError, /utc_offset/) {
+ Time.new("2020-12-25 00:00:00 +09:00:60")
+ }
end
def test_time_add()
diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb
index 0d048b08b7f01f..cdc3479e3739d3 100644
--- a/test/rubygems/test_gem.rb
+++ b/test/rubygems/test_gem.rb
@@ -1026,6 +1026,20 @@ def test_self_refresh_keeps_loaded_specs_activated
Gem.refresh
end
+ def test_activated_specs_does_not_cause_duplicates_when_looping_through_specs
+ util_make_gems
+
+ s = Gem::Specification.first
+ s.activate
+
+ Gem.refresh
+
+ assert_equal 1, Gem::Specification.count {|spec| spec.full_name == s.full_name }
+
+ Gem.loaded_specs.delete(s)
+ Gem.refresh
+ end
+
def test_self_ruby_escaping_spaces_in_path
with_clean_path_to_ruby do
with_rb_config_ruby("C:/Ruby 1.8/bin/ruby.exe") do
diff --git a/test/rubygems/test_gem_commands_contents_command.rb b/test/rubygems/test_gem_commands_contents_command.rb
index d8e6ba3dec534b..049afe8a014ad1 100644
--- a/test/rubygems/test_gem_commands_contents_command.rb
+++ b/test/rubygems/test_gem_commands_contents_command.rb
@@ -227,7 +227,6 @@ def test_execute_default_gem
default_gem_spec = new_default_spec("default", "2.0.0.0",
nil, "default/gem.rb")
default_gem_spec.executables = ["default_command"]
- default_gem_spec.files += ["default_gem.so"]
install_default_gems(default_gem_spec)
@cmd.options[:args] = %w[default]
@@ -237,9 +236,8 @@ def test_execute_default_gem
end
expected = [
- [RbConfig::CONFIG["bindir"], "default_command"],
- [RbConfig::CONFIG["rubylibdir"], "default/gem.rb"],
- [RbConfig::CONFIG["archdir"], "default_gem.so"],
+ [File.join(@gemhome, "bin"), "default_command"],
+ [File.join(@tempdir, "default_gems", "lib"), "default/gem.rb"],
].sort.map {|a|File.join a }.join "\n"
assert_equal expected, @ui.output.chomp
diff --git a/time.c b/time.c
index 54db29c2af1d33..3c8ff365164caf 100644
--- a/time.c
+++ b/time.c
@@ -2153,6 +2153,9 @@ invalid_utc_offset(VALUE zone)
zone);
}
+#define have_2digits(ptr) (ISDIGIT((ptr)[0]) && ISDIGIT((ptr)[1]))
+#define num_from_2digits(ptr) ((ptr)[0] * 10 + (ptr)[1] - '0' * 11)
+
static VALUE
utc_offset_arg(VALUE arg)
{
@@ -2207,18 +2210,19 @@ utc_offset_arg(VALUE arg)
goto invalid_utc_offset;
}
if (sec) {
- if (!ISDIGIT(sec[0]) || !ISDIGIT(sec[1])) goto invalid_utc_offset;
- n += (sec[0] * 10 + sec[1] - '0' * 11);
+ if (!have_2digits(sec)) goto invalid_utc_offset;
+ if (sec[0] > '5') goto invalid_utc_offset;
+ n += num_from_2digits(sec);
ASSUME(min);
}
if (min) {
- if (!ISDIGIT(min[0]) || !ISDIGIT(min[1])) goto invalid_utc_offset;
+ if (!have_2digits(min)) goto invalid_utc_offset;
if (min[0] > '5') goto invalid_utc_offset;
- n += (min[0] * 10 + min[1] - '0' * 11) * 60;
+ n += num_from_2digits(min) * 60;
}
if (s[0] != '+' && s[0] != '-') goto invalid_utc_offset;
- if (!ISDIGIT(s[1]) || !ISDIGIT(s[2])) goto invalid_utc_offset;
- n += (s[1] * 10 + s[2] - '0' * 11) * 3600;
+ if (!have_2digits(s+1)) goto invalid_utc_offset;
+ n += num_from_2digits(s+1) * 3600;
if (s[0] == '-') {
if (n == 0) return UTC_ZONE;
n = -n;
@@ -2528,8 +2532,7 @@ static int
two_digits(const char *ptr, const char *end, const char **endp, const char *name)
{
ssize_t len = end - ptr;
- if (len < 2 || (!ISDIGIT(ptr[0]) || !ISDIGIT(ptr[1])) ||
- ((len > 2) && ISDIGIT(ptr[2]))) {
+ if (len < 2 || !have_2digits(ptr) || ((len > 2) && ISDIGIT(ptr[2]))) {
VALUE mesg = rb_sprintf("two digits %s is expected", name);
if (ptr[-1] == '-' || ptr[-1] == ':') {
rb_str_catf(mesg, " after '%c'", ptr[-1]);
@@ -2538,7 +2541,7 @@ two_digits(const char *ptr, const char *end, const char **endp, const char *name
rb_exc_raise(rb_exc_new_str(rb_eArgError, mesg));
}
*endp = ptr + 2;
- return (ptr[0] - '0') * 10 + (ptr[1] - '0');
+ return num_from_2digits(ptr);
}
static VALUE