Preview Ruby 4.1 is a preview. It can change before the final release. Switch to Ruby 4.0 →
Thread::Backtrace::Location#source_range
static VALUE
location_source_range_m(VALUE self)
{
#ifdef USE_ISEQ_NODE_ID
rb_backtrace_location_t *backtrace_location = location_ptr(self);
const rb_iseq_t *iseq = location_iseq(backtrace_location);
if (!iseq) {
rb_raise(rb_eRuntimeError, "cannot get source range for location without Ruby bytecode");
}
rb_iseq_check(iseq);
int node_id = location_node_id(backtrace_location);
if (node_id == -1) {
rb_raise(rb_eRuntimeError, "cannot get source range for location without a node ID");
}
if (!ISEQ_BODY(iseq)->source_hash) {
rb_raise(rb_eRuntimeError, "cannot get source range because the source hash is unavailable");
}
uint64_t source_hash = ISEQ_BODY(iseq)->source_hash;
VALUE path = rb_iseq_path(iseq);
VALUE absolute_path = rb_iseq_realpath(iseq);
VALUE script_lines = ISEQ_SCRIPT_LINES(iseq);
VALUE source;
VALUE parser_path = path;
int first_lineno = 1;
if (!NIL_P(script_lines)) {
source = rb_ary_join(script_lines, Qnil);
first_lineno = location_source_first_lineno(iseq, script_lines);
}
else if (iseq_from_e_script_p(iseq, path, source_hash)) {
source = rb_e_script;
}
else if (!NIL_P(absolute_path)) {
source = location_source_read_file(absolute_path);
parser_path = absolute_path;
}
else {
rb_raise(rb_eArgError, "cannot get source range for location in eval");
}
if (NIL_P(parser_path)) {
parser_path = rb_str_new_cstr("(eval)");
}
if (!location_source_hash_matches(source, source_hash)) {
rb_raise(rb_eRuntimeError, "source has been modified");
}
rb_code_location_t code_location;
bool found;
if (ISEQ_BODY(iseq)->prism) {
found = pm_node_source_location(
source,
parser_path,
first_lineno,
node_id,
&code_location
);
}
else {
found = rb_ast_node_source_location(
source,
parser_path,
first_lineno,
node_id,
ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK,
ISEQ_BODY(iseq)->location.node_id,
&code_location
);
}
if (!found) {
rb_raise(rb_eRuntimeError, "cannot find node ID %d in parsed source", node_id);
}
return rb_source_range_new(path, absolute_path, &code_location);
#else
rb_raise(rb_eRuntimeError, "cannot get source range because node IDs are disabled");
#endif
}
Returns the Ruby::SourceRange for the Ruby expression associated with this backtrace location.
On CRuby, this method re-reads and re-parses the source file to determine the range. File errors encountered while reading the source are propagated. RuntimeError is raised if required source location information is unavailable, or if the source has changed.
RubyVM.keep_script_lines = true can be used to retain source files in memory and avoid re-reading them from the filesystem.
Locations from eval’d code are only available with RubyVM.keep_script_lines = true.
Ruby version changes
-
4.1
-
Thread::Backtrace::Location#source_rangeis added. It returns aRuby::SourceRangefor the Ruby expression associated with the frame.
-