Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -1598,7 +1598,7 @@ no-install-for-test-bundled-gems: no-update-default-gemspecs
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" \
"hoe" "json-schema:5.1.0" "test-unit-rr" "simplecov" "rspec" "zeitwerk" \
"sinatra" "rack" "tilt" "mustermann" "base64" "compact_index" "rack-test" "logger" "kpeg" "tracer" "minitest-mock"

test-bundled-gems-fetch: yes-test-bundled-gems-fetch
Expand Down
13 changes: 12 additions & 1 deletion eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,26 @@ rb_ec_fiber_scheduler_finalize(rb_execution_context_t *ec)
static void
rb_ec_teardown(rb_execution_context_t *ec)
{
enum ruby_tag_type state = TAG_NONE;
volatile VALUE trap_errinfo = Qnil;

// If the user code defined a scheduler for the top level thread, run it:
rb_ec_fiber_scheduler_finalize(ec);

EC_PUSH_TAG(ec);
if (EC_EXEC_TAG() == TAG_NONE) {
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
rb_vm_trap_exit(rb_ec_vm_ptr(ec));
}
else {
trap_errinfo = ec->errinfo;
ec->errinfo = Qnil;
}
EC_POP_TAG();
rb_ec_exec_end_proc(ec);
if (!NIL_P(trap_errinfo)) {
error_handle(ec, trap_errinfo, state);
ec->errinfo = trap_errinfo;
}
rb_ec_clear_all_trace_func(ec);
}

Expand Down
49 changes: 40 additions & 9 deletions eval_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,16 @@ shown_cause_p(VALUE cause, VALUE *shown_causes)
return FALSE;
}

static void
add_shown_cause(VALUE cause, VALUE *shown_causes)
{
if (!NIL_OR_UNDEF_P(cause) &&
!THROW_DATA_P(cause) &&
rb_obj_is_kind_of(cause, rb_eException)) {
shown_cause_p(cause, shown_causes);
}
}

static void
show_cause(VALUE errinfo, VALUE str, VALUE opt, VALUE highlight, VALUE reverse, long backtrace_limit, VALUE *shown_causes)
{
Expand Down Expand Up @@ -309,15 +319,18 @@ rb_exc_check_circular_cause(VALUE exc)
} while (!NIL_P(cause = rb_attr_get(cause, id_cause)));
}

void
rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE opt, VALUE highlight, VALUE reverse)
static void
rb_error_write0(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE opt, VALUE highlight, VALUE reverse, VALUE *shown_causes)
{
volatile VALUE eclass;
VALUE shown_causes = 0;
VALUE local_shown_causes = 0;
long backtrace_limit = rb_backtrace_length_limit;

if (NIL_P(errinfo))
return;
if (!shown_causes) {
shown_causes = &local_shown_causes;
}

if (UNDEF_P(errat)) {
errat = Qnil;
Expand All @@ -340,19 +353,25 @@ rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE opt, VA
len = p - (msg = buff);
}
write_warn2(str, msg, len);
show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, &shown_causes);
show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, shown_causes);
print_backtrace(eclass, errat, str, TRUE, backtrace_limit);
print_errinfo(eclass, errat, emesg, str, RTEST(highlight));
}
else {
print_errinfo(eclass, errat, emesg, str, RTEST(highlight));
print_backtrace(eclass, errat, str, FALSE, backtrace_limit);
show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, &shown_causes);
show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, shown_causes);
}
}

void
rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE opt, VALUE highlight, VALUE reverse)
{
rb_error_write0(errinfo, emesg, errat, str, opt, highlight, reverse, NULL);
}

static void
rb_ec_error_print_detailed(rb_execution_context_t *const ec, const VALUE errinfo, const VALUE str, VALUE emesg0)
rb_ec_error_print_detailed0(rb_execution_context_t *const ec, const VALUE errinfo, const VALUE str, VALUE emesg0, VALUE *shown_causes)
{
volatile uint8_t raised_flag = ec->raised_flag;
volatile VALUE errat = Qundef;
Expand All @@ -378,14 +397,20 @@ rb_ec_error_print_detailed(rb_execution_context_t *const ec, const VALUE errinfo

if (!written) {
written = true;
rb_error_write(errinfo, emesg, errat, str, opt, highlight, Qfalse);
rb_error_write0(errinfo, emesg, errat, str, opt, highlight, Qfalse, shown_causes);
}

EC_POP_TAG();
ec->errinfo = errinfo;
rb_ec_raised_set(ec, raised_flag);
}

static void
rb_ec_error_print_detailed(rb_execution_context_t *const ec, const VALUE errinfo, const VALUE str, VALUE emesg0)
{
rb_ec_error_print_detailed0(ec, errinfo, str, emesg0, NULL);
}

void
rb_ec_error_print(rb_execution_context_t *volatile ec, volatile VALUE errinfo)
{
Expand Down Expand Up @@ -504,7 +529,7 @@ exiting_split(VALUE errinfo, volatile int *exitcode, volatile int *sigstatus)
rb_bug("Unknown longjmp status %d", status)

static int
error_handle(rb_execution_context_t *ec, VALUE errinfo, enum ruby_tag_type ex)
error_handle_with_shown_causes(rb_execution_context_t *ec, VALUE errinfo, enum ruby_tag_type ex, VALUE *shown_causes)
{
int status = EXIT_FAILURE;

Expand Down Expand Up @@ -546,7 +571,7 @@ error_handle(rb_execution_context_t *ec, VALUE errinfo, enum ruby_tag_type ex)
}
/* fallthrough */
case TAG_FATAL:
rb_ec_error_print(ec, errinfo);
rb_ec_error_print_detailed0(ec, errinfo, Qnil, Qundef, shown_causes);
break;
default:
unknown_longjmp_status(ex);
Expand All @@ -555,3 +580,9 @@ error_handle(rb_execution_context_t *ec, VALUE errinfo, enum ruby_tag_type ex)
rb_ec_reset_raised(ec);
return status;
}

static int
error_handle(rb_execution_context_t *ec, VALUE errinfo, enum ruby_tag_type ex)
{
return error_handle_with_shown_causes(ec, errinfo, ex, NULL);
}
8 changes: 6 additions & 2 deletions eval_jump.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ rb_ec_exec_end_proc(rb_execution_context_t * ec)
{
enum ruby_tag_type state;
volatile VALUE errinfo = ec->errinfo;
/* Share only among END/at_exit handlers to avoid repeated causes. */
VALUE shown_causes = 0;
volatile bool finished = false;

while (!finished) {
Expand All @@ -125,8 +127,10 @@ rb_ec_exec_end_proc(rb_execution_context_t * ec)
}
EC_POP_TAG();
if (state != TAG_NONE) {
error_handle(ec, ec->errinfo, state);
if (!NIL_P(ec->errinfo)) errinfo = ec->errinfo;
VALUE err = ec->errinfo;
add_shown_cause(errinfo, &shown_causes);
error_handle_with_shown_causes(ec, err, state, &shown_causes);
if (!NIL_P(err)) errinfo = err;
}
}

Expand Down
2 changes: 1 addition & 1 deletion gems/bundled_gems
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ rake 13.4.2 https://github.com/ruby/rake
test-unit 3.7.8 https://github.com/test-unit/test-unit
rexml 3.4.4 https://github.com/ruby/rexml
rss 0.3.3 https://github.com/ruby/rss
net-imap 0.6.4.1 https://github.com/ruby/net-imap
net-imap 0.6.4.1 https://github.com/ruby/net-imap 20d4f2c39dcc12307a6b30b497565770e89b66e3
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
Expand Down
20 changes: 17 additions & 3 deletions lib/pathname.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,25 @@ def find(ignore_error: true) # :yield: pathname


class Pathname # * FileUtils *
# Recursively deletes a directory, including all directories beneath it.

# :markup: markdown
#
# call-seq:
# rmtree -> 0
#
# Deletes the entire filetree at the path in `self`; returns `0`:
#
# ```ruby
# dir_pn = Pathname('foo/bar/baz') # => #<Pathname:foo/bar/baz>
# dir_pn.mkpath # Create 'baz' and intermediate directories.
# file_pn = dir_pn.join('t.tmp') # => #<Pathname:foo/bar/baz/t.tmp>
# file_pn.write('foo') # Create file at nested directory 'baz'.
# Pathname('foo').rmtree # Delete the entire tree at directory 'foo'.
# Pathname('foo').exist? # => false
# ```
#
# Note that you need to require 'pathname' to use this method.
# Use method #rmdir to delete a single (empty) directory.
#
# See FileUtils.rm_rf
def rmtree(noop: nil, verbose: nil, secure: nil)
# The name "rmtree" is borrowed from File::Path of Perl.
# File::Path provides "mkpath" and "rmtree".
Expand Down
67 changes: 59 additions & 8 deletions pathname.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,54 @@ path_cmp(VALUE self, VALUE other)
}

/*
* Return a pathname which is substituted by String#sub.
* :markup: markdown
*
* call-seq:
* sub(pattern, replacement) -> new_pathname
* sub(pattern) {|match| ... } -> new_pathname
*
* Returns a new pathname whose path is the path in `self`,
* after the specified substitutions.
*
* Argument `pattern` may be a string or a Regexp;
* argument `replacement` may be a string or a hash.
*
* Varying types for the argument values makes this method very versatile.
*
* Below are some simple examples;
* for many more related examples (using strings, not pathnames),
* see [Substitution Methods](rdoc-ref:String@Substitution+Methods).
*
* With arguments `pattern` and string `replacement` given,
* replaces the first matching substring with the given replacement string:
*
* ```ruby
* pn = Pathname('abracadabra.txt') # => #<Pathname:abracadabra.txt>
* pn.sub('bra', 'xyzzy') # => #<Pathname:axyzzycadabra.txt>
* pn.sub(/bra/, 'xyzzy') # => #<Pathname:axyzzycadabra.txt>
* pn.sub('nope', 'xyzzy') # => #<Pathname:abracadabra.txt>
* ```
*
* With arguments `pattern` and hash `replacement` given,
* replaces the first matching substring with a value from the given replacement hash,
* or removes it:
*
* ```ruby
* h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
* pn.sub('b', h) # => #<Pathname:aBracadabra.txt>
* pn.sub(/b/, h) # => #<Pathname:aBracadabra.txt>
* pn.sub(/d/, h) # => #<Pathname:abracaabra.txt> # 'd' removed.
* ```
*
* With argument `pattern` and a block given,
* calls the block with the first matching substring;
* replaces that substring with the block’s return value:
*
* ```ruby
* pn.sub('b') {|match| match.upcase } # => #<Pathname:aBracadabra.txt>
* pn.sub(/X/) {|match| match.upcase } # => #<Pathname:abracadabra.txt>
* ```
*
* path1 = Pathname.new('/usr/bin/perl')
* path1.sub('perl', 'ruby')
* #=> #<Pathname:/usr/bin/ruby>
*/
static VALUE
path_sub(int argc, VALUE *argv, VALUE self)
Expand Down Expand Up @@ -234,12 +277,20 @@ has_separator_p(VALUE self, VALUE path)
}

/*
* Return a pathname with +repl+ added as a suffix to the basename.
* :markup: markdown
*
* call-seq:
* sub_ext(replacement) -> new_pathname
*
* If self has no extension part, +repl+ is appended.
* Returns a new pathname whose path is the path in `self`,
* after specified changes:
*
* ```ruby
* Pathname('t.tmp').sub_ext('.txt') # => #<Pathname:t.txt> # Extension replaced.
* Pathname('temp').sub_ext('.txt') # => #<Pathname:temp.txt> # Extension added.
* Pathname('t.tmp').sub_ext('') # => #<Pathname:t> # Extension removed.
* ```
*
* Pathname.new('/usr/bin/shutdown').sub_ext('.rb')
* #=> #<Pathname:/usr/bin/shutdown.rb>
*/
static VALUE
path_sub_ext(VALUE self, VALUE repl)
Expand Down
Loading