forked from rubocop/rubocop-rspec
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexcessive_docstring_spacing.rb
101 lines (85 loc) · 2.49 KB
/
excessive_docstring_spacing.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
# frozen_string_literal: true
module RuboCop
module Cop
module RSpec
# Checks for excessive whitespace in example descriptions.
#
# @example
# # bad
# it ' has excessive spacing ' do
# end
#
# # good
# it 'has excessive spacing' do
# end
#
# @example
# # bad
# context ' when a condition is met ' do
# end
#
# # good
# context 'when a condition is met' do
# end
#
class ExcessiveDocstringSpacing < Base
extend AutoCorrector
MSG = 'Excessive whitespace.'
# @!method example_description(node)
def_node_matcher :example_description, <<-PATTERN
(send _ {#Examples.all #ExampleGroups.all} ${
$str
$(dstr ({str dstr `sym} ...) ...)
} ...)
PATTERN
def on_send(node)
example_description(node) do |description_node, message|
return if description_node.heredoc?
text = text(message)
return unless excessive_whitespace?(text)
add_whitespace_offense(description_node, text)
end
end
private
# @param text [String]
def excessive_whitespace?(text)
return true if text.start_with?(' ') || text.end_with?(' ')
text.match?(/[^\n ] +[^ ]/)
end
# @param text [String]
def strip_excessive_whitespace(text)
text.strip.gsub(/ +/, ' ')
end
# @param node [RuboCop::AST::Node]
# @param text [String]
def add_whitespace_offense(node, text)
docstring = docstring(node)
corrected = strip_excessive_whitespace(text)
add_offense(docstring) do |corrector|
corrector.replace(docstring, corrected)
end
end
def docstring(node)
expr = node.loc.expression
Parser::Source::Range.new(
expr.source_buffer,
expr.begin_pos + 1,
expr.end_pos - 1
)
end
# Recursive processing is required to process nested dstr nodes
# that is the case for \-separated multiline strings with interpolation.
def text(node)
case node.type
when :dstr
node.node_parts.map { |child_node| text(child_node) }.join
when :str, :sym
node.value
when :begin
node.source
end
end
end
end
end
end