-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
rspec_memoized_helper_block_delimiter.rb
112 lines (101 loc) · 2.84 KB
/
rspec_memoized_helper_block_delimiter.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# frozen_string_literal: true
module RuboCop
module Cop
module Sevencop
# Use do-end block delimiter on RSpec memoized helper.
#
# Since these helpers define methods, they should be written in the same style as `def`.
#
# @example
# # bad
# let(:foo) { 'bar' }
#
# # good
# let(:foo) do
# 'bar'
# end
#
# # bad
# subject(:foo) { 'bar' }
#
# # good
# subject(:foo) do
# 'bar'
# end
class RSpecMemoizedHelperBlockDelimiter < Base
extend AutoCorrector
include ConfigurableEnforcedStyle
include RangeHelp
MSG = 'Use do-end block delimiter on RSpec memoized helper.'
# @param node [RuboCop::AST::BlockNode]
# @return [void]
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
return unless bad?(node)
add_offense(
node.location.begin.with(
end_pos: node.location.end.end_pos
)
) do |corrector|
autocorrect(corrector, node)
end
end
private
# @!method memoized_helper?(node)
# @param node [RuboCop::AST::Node]
# @return [Boolean]
def_node_matcher :memoized_helper?, <<~PATTERN
(block
(send
nil?
{
:let
:let!
:subject
}
...
)
...
)
PATTERN
# @param corrector [RuboCop::Cop::Corrector]
# @param node [RuboCop::AST::BlockNode]
# @return [void]
def autocorrect(
corrector,
node
)
corrector.insert_before(node.location.begin, ' ') unless whitespace_before?(node.location.begin)
corrector.replace(node.location.begin, 'do')
corrector.replace(node.location.end, 'end')
wrap_in_newlines(corrector, node) if node.single_line?
end
# @param node [RuboCop::AST::BlockNode]
# @return [Boolean]
def bad?(node)
memoized_helper?(node) && node.braces?
end
# @param range [Parser::Source::Range]
# @return [Boolean]
def whitespace_before?(range)
range.source_buffer.source[range.begin_pos - 1].match?(/\s/)
end
# @param corrector [RuboCop::Cop::Corrector]
# @param node [RuboCop::AST::BlockNode]
# @return [void]
def wrap_in_newlines(
corrector,
node
)
corrector.wrap(
node.location.begin.with(
begin_pos: node.location.begin.end_pos,
end_pos: node.location.end.begin_pos
),
"\n",
"\n"
)
end
end
end
end
end