Skip to content

Commit 0595bd0

Browse files
author
Yorick Peterse
committed
Fixed Thread::Backtrace::Location#path.
Location#path isn't an alias, nor does it always return an absolute path. Instead, if it's called in the main script and the path to said script is relative _then_ Location#path gives a relative path. In all other cases it gives back an absolute path. Lets hope we now implemented it properly. Something something if MRI had clear tests this would've been far easier. Fixes #3310.
1 parent e076e33 commit 0595bd0

File tree

4 files changed

+90
-11
lines changed

4 files changed

+90
-11
lines changed

kernel/common/kernel.rb

+6-5
Original file line numberDiff line numberDiff line change
@@ -282,11 +282,12 @@ def caller_locations(start = 1, length = nil)
282282
break
283283
end
284284

285-
locations << Thread::Backtrace::Location.new(
286-
tup[3].to_s,
287-
tup[0].active_path,
288-
tup[1]
289-
)
285+
scope = tup[0].scope
286+
abs_path = tup[0].active_path
287+
path = scope ? scope.active_path : abs_path
288+
label = tup[3].to_s
289+
290+
locations << Thread::Backtrace::Location.new(label, abs_path, path, tup[1])
290291
end
291292

292293
locations

kernel/common/thread.rb

+3-2
Original file line numberDiff line numberDiff line change
@@ -140,17 +140,18 @@ class Backtrace
140140
# Stores location of a single call frame, available since Ruby 2.0.
141141
class Location
142142
attr_reader :label
143+
attr_reader :path
143144
attr_reader :absolute_path
144145
attr_reader :lineno
145146

146-
def initialize(label, absolute_path, lineno)
147+
def initialize(label, absolute_path, path, lineno)
147148
@label = label
148149
@absolute_path = absolute_path
150+
@path = path
149151
@lineno = lineno
150152
end
151153

152154
alias_method :base_label, :label
153-
alias_method :path, :absolute_path
154155

155156
def to_s
156157
"#{absolute_path}:#{lineno}:in `#{label}'"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
def example
2+
caller_locations[0].path
3+
end
4+
5+
print example

spec/ruby/core/thread/backtrace/location/path_spec.rb

+76-4
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,83 @@
22
require File.expand_path('../fixtures/classes', __FILE__)
33

44
describe 'Thread::Backtrace::Location#path' do
5-
before :each do
6-
@frame = ThreadBacktraceLocationSpecs.locations[0]
5+
context 'outside a main script' do
6+
it 'returns an absolute path' do
7+
frame = ThreadBacktraceLocationSpecs.locations[0]
8+
9+
frame.path.should == __FILE__
10+
end
711
end
812

9-
it 'returns the absolute path of the call frame' do
10-
@frame.path.should == __FILE__
13+
context 'in a main script' do
14+
before do
15+
@script = fixture(__FILE__, 'main.rb')
16+
end
17+
18+
context 'when the script is in the working directory' do
19+
before do
20+
@directory = File.dirname(@script)
21+
end
22+
23+
context 'when using a relative script path' do
24+
it 'returns a path relative to the working directory' do
25+
ruby_exe('main.rb', :dir => @directory).should == 'main.rb'
26+
end
27+
end
28+
29+
context 'when using an absolute script path' do
30+
it 'returns an absolute path' do
31+
ruby_exe(@script, :dir => @directory).should == @script
32+
end
33+
end
34+
end
35+
36+
context 'when the script is in a sub directory of the working directory' do
37+
context 'when using a relative script path' do
38+
it 'returns a path relative to the working directory' do
39+
path = 'fixtures/main.rb'
40+
directory = File.dirname(__FILE__)
41+
42+
ruby_exe(path, :dir => directory).should == path
43+
end
44+
end
45+
46+
context 'when using an absolute script path' do
47+
it 'returns an absolute path' do
48+
ruby_exe(@script).should == @script
49+
end
50+
end
51+
end
52+
53+
context 'when the script is outside of the working directory' do
54+
before do
55+
@parent_dir = tmp('path_outside_pwd')
56+
@sub_dir = File.join(@parent_dir, 'sub')
57+
@script = File.join(@parent_dir, 'main.rb')
58+
source = fixture(__FILE__, 'main.rb')
59+
60+
mkdir_p(@sub_dir)
61+
62+
cp(source, @script)
63+
end
64+
65+
after do
66+
rm_r(@script)
67+
rm_r(@sub_dir)
68+
rm_r(@parent_dir)
69+
end
70+
71+
context 'when using a relative script path' do
72+
it 'returns a path relative to the working directory' do
73+
ruby_exe('../main.rb', :dir => @sub_dir).should == '../main.rb'
74+
end
75+
end
76+
77+
context 'when using an absolute path' do
78+
it 'returns an absolute path' do
79+
ruby_exe(@script).should == @script
80+
end
81+
end
82+
end
1183
end
1284
end

0 commit comments

Comments
 (0)