Skip to content

Commit 1e5b738

Browse files
committed
Fix source and lines handling for heredocs
1 parent 0a9c2b8 commit 1e5b738

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### New features
66

7+
* [#40](https://github.com/rubocop-hq/rubocop-ast/pull/40): Fix source and lines handling for heredocs. ([@fatkodima][])
78
* [#37](https://github.com/rubocop-hq/rubocop-ast/pull/37): Add `enumerable_method?` for `MethodIdentifierPredicates`. ([@fatkodima][])
89
* [#4](https://github.com/rubocop-hq/rubocop-ast/issues/4): Add `interpolation?` for `RegexpNode`. ([@tejasbubane][])
910
* [#20](https://github.com/rubocop-hq/rubocop-ast/pull/20): Add option predicates for `RegexpNode`. ([@owst][])

lib/rubocop/ast/node/str_node.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,40 @@ class StrNode < Node
1111
def heredoc?
1212
loc.is_a?(Parser::Source::Map::Heredoc)
1313
end
14+
15+
def source
16+
if heredoc?
17+
source_range.source
18+
else
19+
super
20+
end
21+
end
22+
23+
def source_range
24+
if heredoc?
25+
Parser::Source::Range.new(loc.expression.source_buffer,
26+
loc.expression.begin_pos,
27+
loc.heredoc_end.end_pos)
28+
else
29+
super
30+
end
31+
end
32+
33+
def first_line
34+
if heredoc?
35+
loc.expression.line
36+
else
37+
super
38+
end
39+
end
40+
41+
def last_line
42+
if heredoc?
43+
loc.heredoc_end.line
44+
else
45+
super
46+
end
47+
end
1448
end
1549
end
1650
end

spec/rubocop/ast/str_node_spec.rb

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,94 @@
5656
it { expect(str_node.heredoc?).to be(true) }
5757
end
5858
end
59+
60+
describe '#source' do
61+
context 'with a normal string' do
62+
let(:source) { "'foo'" }
63+
64+
it { expect(str_node.source).to eq(source) }
65+
end
66+
67+
context 'with a heredoc' do
68+
let(:source) do
69+
<<~RUBY
70+
<<-CODE
71+
foo
72+
bar
73+
CODE
74+
RUBY
75+
end
76+
77+
it { expect(str_node.source).to eq(source.rstrip) }
78+
end
79+
end
80+
81+
describe '#first_line' do
82+
context 'with a normal string' do
83+
let(:source) { "'foo'" }
84+
85+
it { expect(str_node.first_line).to eq(1) }
86+
end
87+
88+
context 'with a heredoc' do
89+
let(:source) do
90+
<<~RUBY
91+
<<-CODE
92+
foo
93+
bar
94+
CODE
95+
RUBY
96+
end
97+
98+
it { expect(str_node.first_line).to eq(1) }
99+
end
100+
end
101+
102+
describe '#last_line' do
103+
context 'with a normal string' do
104+
let(:source) do
105+
['"foo"\\',
106+
'"bar"'].join("\n")
107+
end
108+
109+
it { expect(str_node.last_line).to eq(2) }
110+
end
111+
112+
context 'with a heredoc' do
113+
let(:source) do
114+
<<~RUBY
115+
<<-CODE
116+
foo
117+
bar
118+
CODE
119+
RUBY
120+
end
121+
122+
it { expect(str_node.last_line).to eq(4) }
123+
end
124+
end
125+
126+
describe '#line_count' do
127+
context 'with a normal string' do
128+
let(:source) do
129+
['"foo"\\',
130+
'"bar"'].join("\n")
131+
end
132+
133+
it { expect(str_node.line_count).to eq(2) }
134+
end
135+
136+
context 'with a heredoc' do
137+
let(:source) do
138+
<<~RUBY
139+
<<-CODE
140+
foo
141+
bar
142+
CODE
143+
RUBY
144+
end
145+
146+
it { expect(str_node.line_count).to eq(4) }
147+
end
148+
end
59149
end

0 commit comments

Comments
 (0)