Skip to content

Commit eb7bea8

Browse files
authored
Add support for parsing RSpec files (#94)
This PR adds support for parsing RSpec files correctly. Prior to this PR, RSpec files would not get annotated correctly. It adds support for files that use `RSpec.describe` and the `describe` when it gets globally monkey patched.
1 parent 4db10fd commit eb7bea8

File tree

2 files changed

+76
-6
lines changed

2 files changed

+76
-6
lines changed

lib/annotate_rb/model_annotator/file_parser/custom_parser.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,38 @@ def on_class(const, _superclass, _bodystmt)
7777
super
7878
end
7979

80+
# Gets the `RSpec` opening in:
81+
# ```ruby
82+
# RSpec.describe "Collapsed::TestModel" do
83+
# # Deliberately left empty
84+
# end
85+
# ```
86+
# receiver: "RSpec", operator: ".", method: "describe"
87+
def on_command_call(receiver, operator, method, args)
88+
add_event(__method__, receiver, lineno)
89+
@block_starts << [receiver, lineno]
90+
91+
# We keep track of blocks using a stack
92+
@_stack_code_block << receiver
93+
super
94+
end
95+
8096
def on_method_add_block(method, block)
97+
# When parsing a line with no explicit receiver, the method will be presented in an Array.
98+
# It's not immediately clear why.
99+
#
100+
# Example:
101+
# ```ruby
102+
# describe "Collapsed::TestModel" do
103+
# # Deliberately left empty
104+
# end
105+
# ```
106+
#
107+
# => method = ["describe"]
108+
if method.is_a?(Array) && method.size == 1
109+
method = method.first
110+
end
111+
81112
add_event(__method__, method, lineno)
82113

83114
if @_stack_code_block.last == method
@@ -125,6 +156,9 @@ def on_call(receiver, operator, message)
125156
def on_command(message, args)
126157
add_event(__method__, message, lineno)
127158
@block_starts << [message, lineno]
159+
160+
# We keep track of blocks using a stack
161+
@_stack_code_block << message
128162
super
129163
end
130164

spec/lib/annotate_rb/model_annotator/custom_parser_spec.rb

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ class Foo::User < ApplicationRecord
194194
FILE
195195
end
196196
let(:expected_comments) { [] }
197-
let(:expected_starts) { [["FactoryBot", 0], ["factory", 1], ["admin", 2], ["factory", 3], ["FactoryBot", 4]] }
198-
let(:expected_ends) { [["admin", 2], ["end", 3], ["end", 4]] }
197+
let(:expected_starts) { [["FactoryBot", 0], ["factory", 1], ["admin", 2], ["FactoryBot", 4]] }
198+
let(:expected_ends) { [["admin", 2], ["end", 3], ["factory", 3], ["end", 4]] }
199199

200200
it "parses correctly" do
201201
check_it_parses_correctly
@@ -214,9 +214,9 @@ class Foo::User < ApplicationRecord
214214
end
215215
let(:expected_comments) { [] }
216216
let(:expected_starts) {
217-
[["factory", 0], ["first_name", 1], ["last_name", 2], ["date_of_birth", 3], ["factory", 4]]
217+
[["factory", 0], ["first_name", 1], ["last_name", 2], ["date_of_birth", 3]]
218218
}
219-
let(:expected_ends) { [["first_name", 1], ["last_name", 2], ["date_of_birth", 3], ["end", 4]] }
219+
let(:expected_ends) { [["first_name", 1], ["last_name", 2], ["date_of_birth", 3], ["end", 4], ["factory", 4]] }
220220

221221
it "parses correctly" do
222222
check_it_parses_correctly
@@ -235,8 +235,44 @@ class Foo::User < ApplicationRecord
235235
FILE
236236
end
237237
let(:expected_comments) { [["# typed: strong", 0]] }
238-
let(:expected_starts) { [["factory", 1], ["first_name", 2], ["last_name", 3], ["date_of_birth", 4], ["factory", 5]] }
239-
let(:expected_ends) { [["first_name", 2], ["last_name", 3], ["date_of_birth", 4], ["end", 5]] }
238+
let(:expected_starts) { [["factory", 1], ["first_name", 2], ["last_name", 3], ["date_of_birth", 4]] }
239+
let(:expected_ends) { [["first_name", 2], ["last_name", 3], ["date_of_birth", 4], ["end", 5], ["factory", 5]] }
240+
241+
it "parses correctly" do
242+
check_it_parses_correctly
243+
end
244+
end
245+
246+
context "when using an RSpec file" do
247+
let(:input) do
248+
<<~FILE
249+
RSpec.describe "Collapsed::TestModel" do
250+
# Deliberately left empty
251+
end
252+
FILE
253+
end
254+
let(:expected_comments) { [["# Deliberately left empty", 1]] }
255+
let(:expected_starts) { [["RSpec", 0]] }
256+
let(:expected_ends) { [["end", 2], ["RSpec", 2]] }
257+
258+
it "parses correctly" do
259+
check_it_parses_correctly
260+
end
261+
end
262+
263+
context "when using an RSpec file with monkeypatching" do
264+
# Should be removed by RSpec 4+
265+
# https://github.com/rspec/rspec-core/issues/2301
266+
let(:input) do
267+
<<~FILE
268+
describe "Collapsed::TestModel" do
269+
# Deliberately left empty
270+
end
271+
FILE
272+
end
273+
let(:expected_comments) { [["# Deliberately left empty", 1]] }
274+
let(:expected_starts) { [["describe", 0]] }
275+
let(:expected_ends) { [["end", 2], ["describe", 2]] }
240276

241277
it "parses correctly" do
242278
check_it_parses_correctly

0 commit comments

Comments
 (0)