-
-
Notifications
You must be signed in to change notification settings - Fork 269
/
hooks_before_examples.rb
81 lines (68 loc) · 2.02 KB
/
hooks_before_examples.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
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Checks for before/around/after hooks that come after an example.
#
# @example
# # bad
# it 'checks what foo does' do
# expect(foo).to be
# end
#
# before { prepare }
# after { clean_up }
#
# # good
# before { prepare }
# after { clean_up }
#
# it 'checks what foo does' do
# expect(foo).to be
# end
#
class HooksBeforeExamples < Base
extend AutoCorrector
MSG = 'Move `%<hook>s` above the examples in the group.'
# @!method example_or_group?(node)
def_node_matcher :example_or_group?, <<~PATTERN
{
({block numblock} {
(send #rspec? #ExampleGroups.all ...)
(send nil? #Examples.all ...)
} ...)
(send nil? #Includes.examples ...)
}
PATTERN
def on_block(node)
return unless example_group_with_body?(node)
check_hooks(node.body) if multiline_block?(node.body)
end
alias on_numblock on_block
private
def multiline_block?(block)
block.begin_type?
end
def check_hooks(node)
first_example = find_first_example(node)
return unless first_example
first_example.right_siblings.each do |sibling|
next unless hook?(sibling)
msg = format(MSG, hook: sibling.method_name)
add_offense(sibling, message: msg) do |corrector|
autocorrect(corrector, sibling, first_example)
end
end
end
def find_first_example(node)
node.children.find { |sibling| example_or_group?(sibling) }
end
def autocorrect(corrector, node, first_example)
RuboCop::RSpec::Corrector::MoveNode.new(
node, corrector, processed_source
).move_before(first_example)
end
end
end
end
end