rubocop-rspec 1.26.0 → 1.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25c78adb48d8a15bb6229d1d8140abcd3f2e455c846288276ad01cedba024b4a
4
- data.tar.gz: 0e2fbf154570fca1aaf0a32cf7866902424bab10da2854038f5674c8664a2d11
3
+ metadata.gz: 2cb62faf05dbb3d997032a8fbac1d3d1897542d7a98b1540c54afebc10a6a294
4
+ data.tar.gz: 6b1fae2d79e473c5e8295fe6ccb5e843e8801b2ec6ea3c54625e8ba16e7c522d
5
5
  SHA512:
6
- metadata.gz: 7cc9ec95f341241d6c02083673e09ebd861929d846baae085c927a185998da95f573a18f0e7f3b9e7cdaba7f62812d7b80338534742fb2bde205df2fe29e0f3b
7
- data.tar.gz: 891e9714f685e8a3b1bee0ef80395cc11fe87eccb3226cd1bef201a90379e4424cbc5bd937cc632ba11efb7463f0654d756450e4ba44556e93dde7ef0838ab1a
6
+ metadata.gz: 2136057006988a3e05ab8be06f16125e76c520d1e46d656dd8aee9d7ae0c841fbc55d07e247e332120ab32b1f0a41e5b24827012104c8c3b75ac7e15de7e9395
7
+ data.tar.gz: 6a55cfcf03e4c2b15157e3292a89e161b3a25dc10ee45325912e9bf0fd4a13705b7d9b1e7c5f309c9a5ea9fc608a333af144a36844e95d6f20658cde5d290fd5
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 1.27.0 (2018-06-14)
6
+
7
+ * `RSpec/LeadingSubject` now enforces subject to be before any examples, hooks or let declarations. ([@Darhazer][])
8
+ * Fix `RSpec/NotToNot` to highlight only the selector (`not_to` or `to_not`), so it works also on `expect { ... }` blocks. ([@bquorning][])
9
+ * Add `RSpec/EmptyLineAfterHook` cop. ([@bquorning][])
10
+ * Add `RSpec/EmptyLineAfterExampleGroup` cop to check that there is an empty line after example group blocks. ([@bquorning][])
11
+ * Fix `RSpec/DescribeClass` crashing on `RSpec.describe` without arguments. ([@Darhazer][])
12
+ * Bump RuboCop requirement to v0.56.0. ([@bquorning][])
13
+ * Fix `RSpec/OverwritingSetup` crashing if a variable is used as an argument for `let`. ([@Darhazer][])
14
+
5
15
  ## 1.26.0 (2018-06-06)
6
16
 
7
17
  * Fix false positive in `RSpec/EmptyExampleGroup` cop when methods named like a RSpec method are used. ([@Darhazer][])
data/Gemfile CHANGED
@@ -2,10 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- group :test do
6
- gem 'simplecov', require: false
7
- end
8
-
9
5
  local_gemfile = 'Gemfile.local'
10
6
 
11
7
  if File.exist?(local_gemfile)
data/Rakefile CHANGED
@@ -51,7 +51,8 @@ task confirm_documentation: :generate_cops_documentation do
51
51
  Open3.popen3('git diff --exit-code manual/')
52
52
 
53
53
  unless process.value.success?
54
- raise 'manual is out of sync, please add manual/ to the commit'
54
+ raise 'Please run `rake generate_cops_documentation` ' \
55
+ 'and add manual/ to the commit.'
55
56
  end
56
57
  end
57
58
 
@@ -70,7 +71,10 @@ task :new_cop, [:cop] do |_task, args|
70
71
  exit!
71
72
  end
72
73
 
73
- generator = RuboCop::Cop::Generator.new(cop_name)
74
+ github_user = `git config github.user`.chop
75
+ github_user = 'your_id' if github_user.empty?
76
+
77
+ generator = RuboCop::Cop::Generator.new(cop_name, github_user)
74
78
 
75
79
  generator.write_source
76
80
  generator.write_spec
@@ -93,11 +93,21 @@ RSpec/EmptyExampleGroup:
93
93
  CustomIncludeMethods: []
94
94
  StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyExampleGroup
95
95
 
96
+ RSpec/EmptyLineAfterExampleGroup:
97
+ Description: Checks if there is an empty line after example group blocks.
98
+ Enabled: true
99
+ StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterExampleGroup
100
+
96
101
  RSpec/EmptyLineAfterFinalLet:
97
102
  Description: Checks if there is an empty line after the last let block.
98
103
  Enabled: true
99
104
  StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterFinalLet
100
105
 
106
+ RSpec/EmptyLineAfterHook:
107
+ Description: Checks if there is an empty line after hook blocks.
108
+ Enabled: true
109
+ StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/EmptyLineAfterHook
110
+
101
111
  RSpec/EmptyLineAfterSubject:
102
112
  Description: Checks if there is an empty line after subject block.
103
113
  Enabled: true
@@ -215,7 +225,7 @@ RSpec/ItBehavesLike:
215
225
  StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ItBehavesLike
216
226
 
217
227
  RSpec/LeadingSubject:
218
- Description: Checks for `subject` definitions that come after `let` definitions.
228
+ Description: Enforce that subject is the first definition in the test.
219
229
  Enabled: true
220
230
  StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/LeadingSubject
221
231
 
@@ -20,6 +20,8 @@ require_relative 'rubocop/cop/rspec/cop'
20
20
  require_relative 'rubocop/rspec/align_let_brace'
21
21
  require_relative 'rubocop/rspec/capybara'
22
22
  require_relative 'rubocop/rspec/factory_bot'
23
+ require_relative 'rubocop/rspec/final_end_location'
24
+ require_relative 'rubocop/rspec/blank_line_separation'
23
25
 
24
26
  RuboCop::RSpec::Inject.defaults!
25
27
 
@@ -23,7 +23,10 @@ module RuboCop
23
23
  'the class or module being tested.'.freeze
24
24
 
25
25
  def_node_matcher :valid_describe?, <<-PATTERN
26
- {(send {(const nil? :RSpec) nil?} :describe const ...) (send nil? :describe)}
26
+ {
27
+ (send {(const nil? :RSpec) nil?} :describe const ...)
28
+ (send {(const nil? :RSpec) nil?} :describe)
29
+ }
27
30
  PATTERN
28
31
 
29
32
  def_node_matcher :describe_with_metadata, <<-PATTERN
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks if there is an empty line after example group blocks.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # RSpec.describe Foo do
11
+ # describe '#bar' do
12
+ # end
13
+ # describe '#baz' do
14
+ # end
15
+ # end
16
+ #
17
+ # # good
18
+ # RSpec.describe Foo do
19
+ # describe '#bar' do
20
+ # end
21
+ #
22
+ # describe '#baz' do
23
+ # end
24
+ # end
25
+ #
26
+ class EmptyLineAfterExampleGroup < Cop
27
+ include RuboCop::RSpec::BlankLineSeparation
28
+
29
+ MSG = 'Add an empty line after `%<example_group>s`.'.freeze
30
+
31
+ def_node_matcher :example_group, ExampleGroups::ALL.block_pattern
32
+
33
+ def on_block(node)
34
+ return unless example_group(node)
35
+ return if node.parent && node.equal?(node.parent.children.last)
36
+
37
+ missing_separating_line(node) do |location|
38
+ add_offense(
39
+ node,
40
+ location: location,
41
+ message: format(MSG, example_group: node.method_name)
42
+ )
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -17,7 +17,7 @@ module RuboCop
17
17
  #
18
18
  # it { does_something }
19
19
  class EmptyLineAfterFinalLet < Cop
20
- include RangeHelp
20
+ include RuboCop::RSpec::BlankLineSeparation
21
21
 
22
22
  MSG = 'Add an empty line after the last `let` block.'.freeze
23
23
 
@@ -31,54 +31,10 @@ module RuboCop
31
31
  return if latest_let.nil?
32
32
  return if latest_let.equal?(node.body.children.last)
33
33
 
34
- no_new_line_after(latest_let) do |location|
34
+ missing_separating_line(latest_let) do |location|
35
35
  add_offense(latest_let, location: location)
36
36
  end
37
37
  end
38
-
39
- def autocorrect(node)
40
- lambda do |corrector|
41
- no_new_line_after(node) do |location|
42
- corrector.insert_after(location.end, "\n")
43
- end
44
- end
45
- end
46
-
47
- private
48
-
49
- def no_new_line_after(node)
50
- loc = last_node_loc(node)
51
- line = loc.line
52
- line += 1 while comment_line?(processed_source[line])
53
-
54
- return if processed_source[line].blank?
55
- yield offending_loc(node, line)
56
- end
57
-
58
- def last_node_loc(node)
59
- last_line = node.loc.end.line
60
- heredoc_line(node) do |loc|
61
- return loc if loc.line > last_line
62
- end
63
- node.loc.end
64
- end
65
-
66
- def heredoc_line(node, &block)
67
- yield node.loc.heredoc_end if node.loc.respond_to?(:heredoc_end)
68
-
69
- node.each_child_node { |child| heredoc_line(child, &block) }
70
- end
71
-
72
- def offending_loc(node, last_line)
73
- offending_line = processed_source[last_line - 1]
74
- if comment_line?(offending_line)
75
- start = offending_line.index('#')
76
- length = offending_line.length - start
77
- source_range(processed_source.buffer, last_line, start, length)
78
- else
79
- node.loc.expression
80
- end
81
- end
82
38
  end
83
39
  end
84
40
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks if there is an empty line after hook blocks.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # before { do_something }
11
+ # it { does_something }
12
+ #
13
+ # # bad
14
+ # after { do_something }
15
+ # it { does_something }
16
+ #
17
+ # # bad
18
+ # around { |test| test.run }
19
+ # it { does_something }
20
+ #
21
+ # # good
22
+ # before { do_something }
23
+ #
24
+ # it { does_something }
25
+ #
26
+ # # good
27
+ # after { do_something }
28
+ #
29
+ # it { does_something }
30
+ #
31
+ # # good
32
+ # around { |test| test.run }
33
+ #
34
+ # it { does_something }
35
+ #
36
+ class EmptyLineAfterHook < Cop
37
+ include RuboCop::RSpec::BlankLineSeparation
38
+
39
+ MSG = 'Add an empty line after `%<hook>s`.'.freeze
40
+
41
+ def_node_matcher :hook?, Hooks::ALL.block_pattern
42
+
43
+ def on_block(node)
44
+ return unless hook?(node)
45
+ return if node.equal?(node.parent.children.last)
46
+
47
+ missing_separating_line(node) do |location|
48
+ add_offense(
49
+ node,
50
+ location: location,
51
+ message: format(MSG, hook: node.method_name)
52
+ )
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -15,6 +15,8 @@ module RuboCop
15
15
  #
16
16
  # let(:foo) { bar }
17
17
  class EmptyLineAfterSubject < Cop
18
+ include RuboCop::RSpec::BlankLineSeparation
19
+
18
20
  MSG = 'Add empty line after `subject`.'.freeze
19
21
 
20
22
  def_node_matcher :subject?, Subject::ALL.block_pattern
@@ -23,15 +25,9 @@ module RuboCop
23
25
  return unless subject?(node) && !in_spec_block?(node)
24
26
  return if node.equal?(node.parent.children.last)
25
27
 
26
- send_line = node.loc.end.line
27
- next_line = processed_source[send_line]
28
- return if next_line.blank?
29
-
30
- add_offense(node, location: :expression, message: MSG)
31
- end
32
-
33
- def autocorrect(node)
34
- ->(corrector) { corrector.insert_after(node.loc.end, "\n") }
28
+ missing_separating_line(node) do |location|
29
+ add_offense(node, location: location, message: MSG)
30
+ end
35
31
  end
36
32
 
37
33
  private
@@ -3,64 +3,83 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- # Checks for `subject` definitions that come after `let` definitions.
6
+ # Enforce that subject is the first definition in the test.
7
7
  #
8
8
  # @example
9
9
  # # bad
10
- # RSpec.describe User do
11
10
  # let(:params) { blah }
12
11
  # subject { described_class.new(params) }
13
12
  #
14
- # it 'is valid' do
15
- # expect(subject.valid?).to be(true)
16
- # end
17
- # end
13
+ # before { do_something }
14
+ # subject { described_class.new(params) }
18
15
  #
19
- # # good
20
- # RSpec.describe User do
16
+ # it { expect_something }
21
17
  # subject { described_class.new(params) }
18
+ # it { expect_something_else }
22
19
  #
20
+ #
21
+ # # good
22
+ # subject { described_class.new(params) }
23
23
  # let(:params) { blah }
24
24
  #
25
- # it 'is valid' do
26
- # expect(subject.valid?).to be(true)
27
- # end
28
- # end
25
+ # # good
26
+ # subject { described_class.new(params) }
27
+ # before { do_something }
28
+ #
29
+ # # good
30
+ # subject { described_class.new(params) }
31
+ # it { expect_something }
32
+ # it { expect_something_else }
33
+ #
29
34
  class LeadingSubject < Cop
30
35
  include RangeHelp
31
36
 
32
- MSG = 'Declare `subject` above any other `let` declarations.'.freeze
37
+ MSG = 'Declare `subject` above any other `%<offending>s` ' \
38
+ 'declarations.'.freeze
33
39
 
34
40
  def_node_matcher :subject?, Subject::ALL.block_pattern
41
+ def_node_matcher :let?, Helpers::ALL.block_pattern
42
+ def_node_matcher :hook?, Hooks::ALL.block_pattern
43
+ def_node_matcher :example?, Examples::ALL.block_pattern
35
44
 
36
45
  def on_block(node)
37
46
  return unless subject?(node) && !in_spec_block?(node)
38
47
 
48
+ check_previous_nodes(node)
49
+ end
50
+
51
+ def check_previous_nodes(node)
39
52
  node.parent.each_child_node do |sibling|
40
- break if sibling.equal?(node)
53
+ if offending?(sibling)
54
+ add_offense(
55
+ node,
56
+ location: :expression,
57
+ message: format(MSG, offending: sibling.method_name)
58
+ )
59
+ end
41
60
 
42
- break add_offense(node, location: :expression) if let?(sibling)
61
+ break if offending?(sibling) || sibling.equal?(node)
43
62
  end
44
63
  end
45
64
 
46
65
  def autocorrect(node)
47
66
  lambda do |corrector|
48
- first_let = find_first_let(node)
49
- first_let_position = first_let.loc.expression
50
- indent = "\n" + ' ' * first_let.loc.column
51
- corrector.insert_before(first_let_position, node.source + indent)
67
+ first_node = find_first_offending_node(node)
68
+ first_node_position = first_node.loc.expression
69
+ indent = "\n" + ' ' * first_node.loc.column
70
+ corrector.insert_before(first_node_position, node.source + indent)
52
71
  corrector.remove(node_range(node))
53
72
  end
54
73
  end
55
74
 
56
75
  private
57
76
 
58
- def let?(node)
59
- %i[let let!].include?(node.method_name)
77
+ def offending?(node)
78
+ let?(node) || hook?(node) || example?(node)
60
79
  end
61
80
 
62
- def find_first_let(node)
63
- node.parent.children.find { |sibling| let?(sibling) }
81
+ def find_first_offending_node(node)
82
+ node.parent.children.find { |sibling| offending?(sibling) }
64
83
  end
65
84
 
66
85
  def node_range(node)
@@ -32,6 +32,7 @@ module RuboCop
32
32
  # end
33
33
  class LetBeforeExamples < Cop
34
34
  include RangeHelp
35
+ include RuboCop::RSpec::FinalEndLocation
35
36
 
36
37
  MSG = 'Move `let` before the examples in the group.'.freeze
37
38
 
@@ -91,21 +92,10 @@ module RuboCop
91
92
  end
92
93
 
93
94
  def node_range(node)
94
- range_between(node.loc.expression.begin_pos, last_node_loc(node))
95
- end
96
-
97
- def last_node_loc(node)
98
- heredoc = heredoc_lines(node).last
99
-
100
- if heredoc
101
- heredoc.loc.heredoc_end.end_pos
102
- else
103
- node.loc.end.end_pos
104
- end
105
- end
106
-
107
- def heredoc_lines(node)
108
- node.body.child_nodes.select { |n| n.loc.respond_to?(:heredoc_end) }
95
+ range_between(
96
+ node.loc.expression.begin_pos,
97
+ final_end_location(node).end_pos
98
+ )
109
99
  end
110
100
  end
111
101
  end
@@ -22,7 +22,7 @@ module RuboCop
22
22
 
23
23
  def on_send(node)
24
24
  not_to_not_offense(node, alternative_style) do
25
- add_offense(node, location: :expression)
25
+ add_offense(node, location: :selector)
26
26
  end
27
27
  end
28
28
 
@@ -22,11 +22,10 @@ module RuboCop
22
22
  # let(:baz) { baz }
23
23
  # let!(:other) { other }
24
24
  class OverwritingSetup < Cop
25
- include RuboCop::RSpec::Util
26
-
27
25
  MSG = '`%<name>s` is already defined.'.freeze
28
26
 
29
27
  def_node_matcher :setup?, (Helpers::ALL + Subject::ALL).block_pattern
28
+ def_node_matcher :first_argument_name, '(send _ _ ({str sym} $_))'
30
29
 
31
30
  def on_block(node)
32
31
  return unless example_group_with_body?(node)
@@ -44,11 +43,11 @@ module RuboCop
44
43
 
45
44
  def find_duplicates(node)
46
45
  setup_expressions = Set.new
47
- node.each_child_node do |child|
48
- next unless setup?(child)
46
+ node.each_child_node(:block) do |child|
47
+ next unless common_setup?(child)
49
48
 
50
49
  name = if child.send_node.arguments?
51
- child.send_node.first_argument.value
50
+ first_argument_name(child.send_node).to_sym
52
51
  else
53
52
  :subject
54
53
  end
@@ -56,6 +55,13 @@ module RuboCop
56
55
  yield child, name unless setup_expressions.add?(name)
57
56
  end
58
57
  end
58
+
59
+ def common_setup?(node)
60
+ return false unless setup?(node)
61
+ # Search only for setup with basic_literal arguments (e.g. :sym, :str)
62
+ # or no arguments at all.
63
+ node.send_node.arguments.all?(&:basic_literal?)
64
+ end
59
65
  end
60
66
  end
61
67
  end
@@ -76,7 +76,7 @@ module RuboCop
76
76
 
77
77
  def range(node, offending_node)
78
78
  range_between(
79
- offending_node.loc.selector.begin_pos - 1, # match the dot as well
79
+ offending_node.loc.dot.begin_pos,
80
80
  node.loc.expression.end_pos
81
81
  )
82
82
  end
@@ -24,7 +24,9 @@ require_relative 'rspec/described_class'
24
24
  require_relative 'rspec/describe_method'
25
25
  require_relative 'rspec/describe_symbol'
26
26
  require_relative 'rspec/empty_example_group'
27
+ require_relative 'rspec/empty_line_after_example_group'
27
28
  require_relative 'rspec/empty_line_after_final_let'
29
+ require_relative 'rspec/empty_line_after_hook'
28
30
  require_relative 'rspec/empty_line_after_subject'
29
31
  require_relative 'rspec/example_length'
30
32
  require_relative 'rspec/example_without_description'
@@ -0,0 +1,37 @@
1
+ module RuboCop
2
+ module RSpec
3
+ # Helps determine the offending location if there is not a blank line
4
+ # following the node. Allows comments to follow directly after.
5
+ module BlankLineSeparation
6
+ include FinalEndLocation
7
+ include RuboCop::Cop::RangeHelp
8
+
9
+ def missing_separating_line(node)
10
+ line = final_end_location(node).line
11
+
12
+ line += 1 while comment_line?(processed_source[line])
13
+
14
+ return if processed_source[line].blank?
15
+
16
+ yield offending_loc(line)
17
+ end
18
+
19
+ def offending_loc(last_line)
20
+ offending_line = processed_source[last_line - 1]
21
+
22
+ content_length = offending_line.lstrip.length
23
+ start = offending_line.length - content_length
24
+
25
+ source_range(processed_source.buffer, last_line, start, content_length)
26
+ end
27
+
28
+ def autocorrect(node)
29
+ lambda do |corrector|
30
+ missing_separating_line(node) do |location|
31
+ corrector.insert_after(location.end, "\n")
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,15 @@
1
+ module RuboCop
2
+ module RSpec
3
+ # Helps find the true end location of nodes which might contain heredocs.
4
+ module FinalEndLocation
5
+ def final_end_location(start_node)
6
+ heredoc_endings =
7
+ start_node.each_node(:str, :dstr, :xstr)
8
+ .select(&:heredoc?)
9
+ .map { |node| node.loc.heredoc_end }
10
+
11
+ [start_node.loc.end, *heredoc_endings].max_by(&:line)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # Version information for the RSpec RuboCop plugin.
6
6
  module Version
7
- STRING = '1.26.0'.freeze
7
+ STRING = '1.27.0'.freeze
8
8
  end
9
9
  end
10
10
  end
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
37
37
  'documentation_uri' => 'https://rubocop-rspec.readthedocs.io/'
38
38
  }
39
39
 
40
- spec.add_runtime_dependency 'rubocop', '>= 0.53.0'
40
+ spec.add_runtime_dependency 'rubocop', '>= 0.56.0'
41
41
 
42
42
  spec.add_development_dependency 'rack'
43
43
  spec.add_development_dependency 'rake'
@@ -95,6 +95,9 @@ RSpec.describe RuboCop::Cop::RSpec::DescribeClass do
95
95
 
96
96
  it 'ignores an empty describe' do
97
97
  expect_no_offenses(<<-RUBY)
98
+ RSpec.describe do
99
+ end
100
+
98
101
  describe do
99
102
  end
100
103
  RUBY
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RuboCop::Cop::RSpec::EmptyLineAfterExampleGroup do
4
+ subject(:cop) { described_class.new }
5
+
6
+ it 'checks for empty line after describe' do
7
+ expect_offense(<<-RUBY)
8
+ RSpec.describe Foo do
9
+ describe '#bar' do
10
+ end
11
+ ^^^ Add an empty line after `describe`.
12
+ describe '#baz' do
13
+ end
14
+ end
15
+ RUBY
16
+ end
17
+
18
+ it 'highlights single line formulations correctly' do
19
+ expect_offense(<<-RUBY)
20
+ RSpec.describe Foo do
21
+ describe('#bar') { }
22
+ ^^^^^^^^^^^^^^^^^^^^ Add an empty line after `describe`.
23
+ describe '#baz' do
24
+ end
25
+ end
26
+ RUBY
27
+ end
28
+
29
+ it 'checks for empty line after context' do
30
+ expect_offense(<<-RUBY)
31
+ RSpec.context 'foo' do
32
+ context 'bar' do
33
+ end
34
+ ^^^ Add an empty line after `context`.
35
+ context 'baz' do
36
+ end
37
+ end
38
+ RUBY
39
+ end
40
+
41
+ it 'approves empty line after describe' do
42
+ expect_no_offenses(<<-RUBY)
43
+ RSpec.describe Foo do
44
+ describe '#bar' do
45
+ end
46
+
47
+ describe '#baz' do
48
+ end
49
+ end
50
+ RUBY
51
+ end
52
+
53
+ it 'approves empty line after context' do
54
+ expect_no_offenses(<<-RUBY)
55
+ RSpec.context 'foo' do
56
+ context 'bar' do
57
+ end
58
+
59
+ context 'baz' do
60
+ end
61
+ end
62
+ RUBY
63
+ end
64
+
65
+ bad_example = <<-RUBY
66
+ RSpec.describe Foo do
67
+ describe '#bar' do
68
+ end
69
+ describe '#baz' do
70
+ end
71
+ end
72
+ RUBY
73
+
74
+ good_example = <<-RUBY
75
+ RSpec.describe Foo do
76
+ describe '#bar' do
77
+ end
78
+
79
+ describe '#baz' do
80
+ end
81
+ end
82
+ RUBY
83
+
84
+ include_examples 'autocorrect',
85
+ bad_example,
86
+ good_example
87
+ end
@@ -19,9 +19,9 @@ RSpec.describe RuboCop::Cop::RSpec::EmptyLineAfterFinalLet do
19
19
  RSpec.describe User do
20
20
  let(:a) { a }
21
21
  let!(:b) do
22
- ^^^^^^^^^^^ Add an empty line after the last `let` block.
23
22
  b
24
23
  end
24
+ ^^^ Add an empty line after the last `let` block.
25
25
  it { expect(a).to eq(b) }
26
26
  end
27
27
  RUBY
@@ -143,6 +143,21 @@ RSpec.describe RuboCop::Cop::RSpec::EmptyLineAfterFinalLet do
143
143
  RUBY
144
144
  end
145
145
 
146
+ it 'handles silly HEREDOC offense' do
147
+ expect_offense(<<-RUBY)
148
+ RSpec.describe 'silly heredoc syntax' do
149
+ let(:foo) { <<-BAR }
150
+ hello
151
+ world
152
+ BAR
153
+ ^^^ Add an empty line after the last `let` block.
154
+ it 'has tricky syntax' do
155
+ expect(foo).to eql(" hello\n world\n")
156
+ end
157
+ end
158
+ RUBY
159
+ end
160
+
146
161
  bad_example = <<-RUBY
147
162
  RSpec.describe User do
148
163
  let(:params) { foo }
@@ -185,6 +200,31 @@ RSpec.describe RuboCop::Cop::RSpec::EmptyLineAfterFinalLet do
185
200
  end
186
201
  RUBY
187
202
 
203
+ include_examples 'autocorrect',
204
+ bad_example,
205
+ good_example
206
+
207
+ bad_example = <<-RUBY
208
+ RSpec.describe User do
209
+ let(:params) { <<-DOC }
210
+ I'm super annoying!
211
+ DOC
212
+ it 'has a new line' do
213
+ end
214
+ end
215
+ RUBY
216
+
217
+ good_example = <<-RUBY
218
+ RSpec.describe User do
219
+ let(:params) { <<-DOC }
220
+ I'm super annoying!
221
+ DOC
222
+
223
+ it 'has a new line' do
224
+ end
225
+ end
226
+ RUBY
227
+
188
228
  include_examples 'autocorrect',
189
229
  bad_example,
190
230
  good_example
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RuboCop::Cop::RSpec::EmptyLineAfterHook do
4
+ subject(:cop) { described_class.new }
5
+
6
+ it 'checks for empty line after `before` hook' do
7
+ expect_offense(<<-RUBY)
8
+ RSpec.describe User do
9
+ before { do_something }
10
+ ^^^^^^^^^^^^^^^^^^^^^^^ Add an empty line after `before`.
11
+ it { does_something }
12
+ end
13
+ RUBY
14
+ end
15
+
16
+ it 'checks for empty line after `after` hook' do
17
+ expect_offense(<<-RUBY)
18
+ RSpec.describe User do
19
+ after { do_something }
20
+ ^^^^^^^^^^^^^^^^^^^^^^ Add an empty line after `after`.
21
+ it { does_something }
22
+ end
23
+ RUBY
24
+ end
25
+
26
+ it 'checks for empty line after `around` hook' do
27
+ expect_offense(<<-RUBY)
28
+ RSpec.describe User do
29
+ around { |test| test.run }
30
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Add an empty line after `around`.
31
+ it { does_something }
32
+ end
33
+ RUBY
34
+ end
35
+
36
+ it 'approves empty line after `before` hook' do
37
+ expect_no_offenses(<<-RUBY)
38
+ RSpec.describe User do
39
+ before { do_something }
40
+
41
+ it { does_something }
42
+ end
43
+ RUBY
44
+ end
45
+
46
+ it 'approves empty line after `after` hook' do
47
+ expect_no_offenses(<<-RUBY)
48
+ RSpec.describe User do
49
+ after { do_something }
50
+
51
+ it { does_something }
52
+ end
53
+ RUBY
54
+ end
55
+
56
+ it 'approves empty line after `around` hook' do
57
+ expect_no_offenses(<<-RUBY)
58
+ RSpec.describe User do
59
+ around { |test| test.run }
60
+
61
+ it { does_something }
62
+ end
63
+ RUBY
64
+ end
65
+
66
+ it 'handles multiline `before` block' do
67
+ expect_no_offenses(<<-RUBY)
68
+ RSpec.describe User do
69
+ before do
70
+ do_something
71
+ end
72
+
73
+ it { does_something }
74
+ end
75
+ RUBY
76
+ end
77
+
78
+ it 'handles multiline `after` block' do
79
+ expect_no_offenses(<<-RUBY)
80
+ RSpec.describe User do
81
+ after do
82
+ do_something
83
+ end
84
+
85
+ it { does_something }
86
+ end
87
+ RUBY
88
+ end
89
+
90
+ it 'handles multiline `around` block' do
91
+ expect_no_offenses(<<-RUBY)
92
+ RSpec.describe User do
93
+ around do |test|
94
+ test.run
95
+ end
96
+
97
+ it { does_something }
98
+ end
99
+ RUBY
100
+ end
101
+
102
+ it 'handles `before` being the latest node' do
103
+ expect_no_offenses(<<-RUBY)
104
+ RSpec.describe User do
105
+ before { do_something }
106
+ end
107
+ RUBY
108
+ end
109
+
110
+ bad_example = <<-RUBY
111
+ RSpec.describe User do
112
+ before { do_something }
113
+ it { does_something }
114
+ end
115
+ RUBY
116
+
117
+ good_example = <<-RUBY
118
+ RSpec.describe User do
119
+ before { do_something }
120
+
121
+ it { does_something }
122
+ end
123
+ RUBY
124
+
125
+ include_examples 'autocorrect',
126
+ bad_example,
127
+ good_example
128
+ end
@@ -20,7 +20,7 @@ RSpec.describe RuboCop::Cop::RSpec::LeadingSubject do
20
20
  let!(:params) { foo }
21
21
 
22
22
  subject { described_class.new }
23
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Declare `subject` above any other `let` declarations.
23
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Declare `subject` above any other `let!` declarations.
24
24
  end
25
25
  RUBY
26
26
  end
@@ -63,8 +63,31 @@ RSpec.describe RuboCop::Cop::RSpec::LeadingSubject do
63
63
  RUBY
64
64
  end
65
65
 
66
+ it 'checks subject below hook' do
67
+ expect_offense(<<-RUBY)
68
+ RSpec.describe User do
69
+ before { allow(Foo).to receive(:bar) }
70
+
71
+ subject { described_class.new }
72
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Declare `subject` above any other `before` declarations.
73
+ end
74
+ RUBY
75
+ end
76
+
77
+ it 'checks subject below example' do
78
+ expect_offense(<<-RUBY)
79
+ RSpec.describe User do
80
+ it { is_expected.to be_present }
81
+
82
+ subject { described_class.new }
83
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Declare `subject` above any other `it` declarations.
84
+ end
85
+ RUBY
86
+ end
87
+
66
88
  bad_code = <<-RUBY
67
89
  RSpec.describe User do
90
+ before { allow(Foo).to receive(:bar) }
68
91
  let(:params) { foo }
69
92
  let(:bar) { baz }
70
93
 
@@ -76,6 +99,7 @@ RSpec.describe RuboCop::Cop::RSpec::LeadingSubject do
76
99
  good_code = <<-RUBY
77
100
  RSpec.describe User do
78
101
  subject { described_class.new }
102
+ before { allow(Foo).to receive(:bar) }
79
103
  let(:params) { foo }
80
104
  let(:bar) { baz }
81
105
 
@@ -7,7 +7,16 @@ RSpec.describe RuboCop::Cop::RSpec::NotToNot, :config do
7
7
  it 'detects the `to_not` offense' do
8
8
  expect_offense(<<-RUBY)
9
9
  it { expect(false).to_not be_true }
10
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `not_to` over `to_not`.
10
+ ^^^^^^ Prefer `not_to` over `to_not`.
11
+ RUBY
12
+ end
13
+
14
+ it 'detects the `to_not` offense on an expect block' do
15
+ expect_offense(<<-RUBY)
16
+ expect {
17
+ 2 + 2
18
+ }.to_not raise_error
19
+ ^^^^^^ Prefer `not_to` over `to_not`.
11
20
  RUBY
12
21
  end
13
22
 
@@ -20,6 +29,18 @@ RSpec.describe RuboCop::Cop::RSpec::NotToNot, :config do
20
29
  include_examples 'autocorrect',
21
30
  'it { expect(0).to_not equal 1 }',
22
31
  'it { expect(0).not_to equal 1 }'
32
+
33
+ original = <<-RUBY
34
+ expect {
35
+ 2 + 2
36
+ }.to_not raise_error
37
+ RUBY
38
+ corrected = <<-RUBY
39
+ expect {
40
+ 2 + 2
41
+ }.not_to raise_error
42
+ RUBY
43
+ include_examples 'autocorrect', original, corrected
23
44
  end
24
45
 
25
46
  context 'when AcceptedMethod is `to_not`' do
@@ -28,7 +49,16 @@ RSpec.describe RuboCop::Cop::RSpec::NotToNot, :config do
28
49
  it 'detects the `not_to` offense' do
29
50
  expect_offense(<<-RUBY)
30
51
  it { expect(false).not_to be_true }
31
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `to_not` over `not_to`.
52
+ ^^^^^^ Prefer `to_not` over `not_to`.
53
+ RUBY
54
+ end
55
+
56
+ it 'detects the `not_to` offense on an expect block' do
57
+ expect_offense(<<-RUBY)
58
+ expect {
59
+ 2 + 2
60
+ }.not_to raise_error
61
+ ^^^^^^ Prefer `to_not` over `not_to`.
32
62
  RUBY
33
63
  end
34
64
 
@@ -41,5 +71,17 @@ RSpec.describe RuboCop::Cop::RSpec::NotToNot, :config do
41
71
  include_examples 'autocorrect',
42
72
  'it { expect(0).not_to equal 1 }',
43
73
  'it { expect(0).to_not equal 1 }'
74
+
75
+ original = <<-RUBY
76
+ expect {
77
+ 2 + 2
78
+ }.not_to raise_error
79
+ RUBY
80
+ corrected = <<-RUBY
81
+ expect {
82
+ 2 + 2
83
+ }.to_not raise_error
84
+ RUBY
85
+ include_examples 'autocorrect', original, corrected
44
86
  end
45
87
  end
@@ -66,6 +66,27 @@ RSpec.describe RuboCop::Cop::RSpec::OverwritingSetup do
66
66
  RUBY
67
67
  end
68
68
 
69
+ it 'handles dynamic names for `let`' do
70
+ expect_no_offenses(<<-RUBY)
71
+ RSpec.describe User do
72
+ subject(:name) { a }
73
+
74
+ let(name) { b }
75
+ end
76
+ RUBY
77
+ end
78
+
79
+ it 'handles string arguments' do
80
+ expect_offense(<<-RUBY)
81
+ RSpec.describe User do
82
+ subject(:name) { a }
83
+
84
+ let("name") { b }
85
+ ^^^^^^^^^^^^^^^^^ `name` is already defined.
86
+ end
87
+ RUBY
88
+ end
89
+
69
90
  it 'does not encounter an error when handling an empty describe' do
70
91
  expect { inspect_source('RSpec.describe(User) do end', 'a_spec.rb') }
71
92
  .not_to raise_error
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.26.0
4
+ version: 1.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Backus
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-06-06 00:00:00.000000000 Z
13
+ date: 2018-06-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 0.53.0
21
+ version: 0.56.0
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: 0.53.0
28
+ version: 0.56.0
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: rack
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -132,7 +132,9 @@ files:
132
132
  - lib/rubocop/cop/rspec/describe_symbol.rb
133
133
  - lib/rubocop/cop/rspec/described_class.rb
134
134
  - lib/rubocop/cop/rspec/empty_example_group.rb
135
+ - lib/rubocop/cop/rspec/empty_line_after_example_group.rb
135
136
  - lib/rubocop/cop/rspec/empty_line_after_final_let.rb
137
+ - lib/rubocop/cop/rspec/empty_line_after_hook.rb
136
138
  - lib/rubocop/cop/rspec/empty_line_after_subject.rb
137
139
  - lib/rubocop/cop/rspec/example_length.rb
138
140
  - lib/rubocop/cop/rspec/example_without_description.rb
@@ -184,6 +186,7 @@ files:
184
186
  - lib/rubocop/cop/rspec_cops.rb
185
187
  - lib/rubocop/rspec.rb
186
188
  - lib/rubocop/rspec/align_let_brace.rb
189
+ - lib/rubocop/rspec/blank_line_separation.rb
187
190
  - lib/rubocop/rspec/capybara.rb
188
191
  - lib/rubocop/rspec/concept.rb
189
192
  - lib/rubocop/rspec/config_formatter.rb
@@ -191,6 +194,7 @@ files:
191
194
  - lib/rubocop/rspec/example.rb
192
195
  - lib/rubocop/rspec/example_group.rb
193
196
  - lib/rubocop/rspec/factory_bot.rb
197
+ - lib/rubocop/rspec/final_end_location.rb
194
198
  - lib/rubocop/rspec/hook.rb
195
199
  - lib/rubocop/rspec/inject.rb
196
200
  - lib/rubocop/rspec/language.rb
@@ -220,7 +224,9 @@ files:
220
224
  - spec/rubocop/cop/rspec/describe_symbol_spec.rb
221
225
  - spec/rubocop/cop/rspec/described_class_spec.rb
222
226
  - spec/rubocop/cop/rspec/empty_example_group_spec.rb
227
+ - spec/rubocop/cop/rspec/empty_line_after_example_group_spec.rb
223
228
  - spec/rubocop/cop/rspec/empty_line_after_final_let_spec.rb
229
+ - spec/rubocop/cop/rspec/empty_line_after_hook_spec.rb
224
230
  - spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb
225
231
  - spec/rubocop/cop/rspec/example_length_spec.rb
226
232
  - spec/rubocop/cop/rspec/example_without_description_spec.rb
@@ -327,7 +333,9 @@ test_files:
327
333
  - spec/rubocop/cop/rspec/describe_symbol_spec.rb
328
334
  - spec/rubocop/cop/rspec/described_class_spec.rb
329
335
  - spec/rubocop/cop/rspec/empty_example_group_spec.rb
336
+ - spec/rubocop/cop/rspec/empty_line_after_example_group_spec.rb
330
337
  - spec/rubocop/cop/rspec/empty_line_after_final_let_spec.rb
338
+ - spec/rubocop/cop/rspec/empty_line_after_hook_spec.rb
331
339
  - spec/rubocop/cop/rspec/empty_line_after_subject_spec.rb
332
340
  - spec/rubocop/cop/rspec/example_length_spec.rb
333
341
  - spec/rubocop/cop/rspec/example_without_description_spec.rb