rubocop-rspec 1.4.1 → 1.5.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
  SHA1:
3
- metadata.gz: 4af4076d3a91d5fdb416fa1fec36c74e07998744
4
- data.tar.gz: e9bd1905617f520629969606be3a7d7228415b3b
3
+ metadata.gz: 7f7a58ee16af46402f371a3a3be9ae83752a7555
4
+ data.tar.gz: 15ecddf6c683fe294fb914faeadd45eabbbabba6
5
5
  SHA512:
6
- metadata.gz: 98850f3ef7a136727655aaf9eaaab8e889e8944f71762760def61d32c89e2690f6c6e3d519d1c82e9d7cd364796119105b82dfb7d2c17e58a9d4449fc9e6889d
7
- data.tar.gz: dff8cba69accc6a345a681a47a8529a3830821d5a1d09b12f81250c3bc1c513c6409c9267dc658c59a11af04421bf9f42ce029239097cb14ee1915a9b170ab4e
6
+ metadata.gz: ca7b87e0e9210d37795f29ebba6b5398c5e5583b9b68e3a1519c4f9208d18228d99378fba6114a6381c8bf579bf21cf755a3b9ef438765065965b381d9a1e3ca
7
+ data.tar.gz: f515ccc02aace366c6ec987aaf258450d8d7f0d2e740382d303a4480633b031de8150ca198369b2059c5856cb94d121afe7161bb10dfe1e70f7bdc1a60ed6f5d
data/CHANGELOG.md CHANGED
@@ -2,13 +2,26 @@
2
2
 
3
3
  ## master (unreleased)
4
4
 
5
- ## 1.4.1 (03/04/2016)
5
+ ## 1.5.0 (2016-05-17)
6
+
7
+ * Expand `VerifiedDoubles` cop to check for `spy` as well as `double`. ([@andyw8][])
8
+ * Enable `VerifiedDoubles` cop by default. ([@andyw8][])
9
+ * Add `IgnoreSymbolicNames` option for `VerifiedDoubles` cop. ([@andyw8][])
10
+ * Add `RSpec::ExampleLength` cop. ([@andyw8][])
11
+ * Handle alphanumeric class names in `FilePath` cop. ([@andyw8][])
12
+ * Skip `DescribeClass` cop for view specs. ([@andyw8][])
13
+ * Skip `FilePath` cop for Rails routing specs. ([@andyw8][])
14
+ * Add cop to check for focused specs. ([@renanborgescampos][], [@jaredmoody][])
15
+ * Clean-up `RSpec::NotToNot` to use same configuration semantics as other Rubocop cops, add autocorrect support for `RSpec::NotToNot`. ([@baberthal][])
16
+ * Update to rubocop 0.40.0. ([@nijikon][])
17
+
18
+ ## 1.4.1 (2016-04-03)
6
19
 
7
20
  * Ignore routing specs for DescribeClass cop. ([@nijikon][])
8
21
  * Move rubocop dependency to runtime. ([@nijikon][])
9
22
  * Update to rubocop 0.39.0. ([@nijikon][])
10
23
 
11
- ## 1.4.0 (15/02/2016)
24
+ ## 1.4.0 (2016-02-15)
12
25
 
13
26
  * Update to rubocop 0.37.2. ([@nijikon][])
14
27
  * Update ruby versions we test against. ([@nijikon][])
@@ -73,7 +86,7 @@
73
86
 
74
87
  <!-- Contributors -->
75
88
 
76
- [@andyw8]: https://github.com/andyw8i
89
+ [@andyw8]: https://github.com/andyw8
77
90
  [@bquorning]: https://github.com/bquorning
78
91
  [@deivid-rodriguez]: https://github.com/deivid-rodriguez
79
92
  [@geniou]: https://github.com/geniou
@@ -83,3 +96,6 @@
83
96
  [@pstengel]: https://github.com/pstengel
84
97
  [@miguelfteixeira]: https://github.com/miguelfteixeira
85
98
  [@mlarraz]: https://github.com/mlarraz
99
+ [@renanborgescampos]: https://github.com/renanborgescampos
100
+ [@jaredmoody]: https://github.com/jaredmoody
101
+ [@baberthal]: https://github.com/baberthal
data/README.md CHANGED
@@ -85,7 +85,7 @@ This means that in order to run the specs locally, you need a (shallow) clone
85
85
  of the RuboCop repository:
86
86
 
87
87
  ```bash
88
- git submodule update --init --depth 1 vendor/rubocop
88
+ git submodule update --init vendor/rubocop
89
89
  ```
90
90
 
91
91
  ## License
data/config/default.yml CHANGED
@@ -41,9 +41,21 @@ RSpec/FilePath:
41
41
 
42
42
  RSpec/VerifiedDoubles:
43
43
  Description: 'Prefer using verifying doubles over normal doubles.'
44
- Enabled: false
44
+ Enabled: true
45
45
 
46
46
  RSpec/NotToNot:
47
47
  Description: 'Enforces the usage of the same method on all negative message expectations.'
48
+ EnforcedStyle: not_to
49
+ SupportedStyles:
50
+ - not_to
51
+ - to_not
52
+ Enabled: true
53
+
54
+ RSpec/Focus:
55
+ Description: 'Checks if there are focused specs.'
56
+ Enabled: true
57
+
58
+ RSpec/ExampleLength:
59
+ Description: 'Checks for long example'
48
60
  Enabled: true
49
- AcceptedMethod: 'not_to'
61
+ Max: 5
data/lib/rubocop-rspec.rb CHANGED
@@ -15,7 +15,9 @@ require 'rubocop/cop/rspec/describe_method'
15
15
  require 'rubocop/cop/rspec/described_class'
16
16
  require 'rubocop/cop/rspec/example_wording'
17
17
  require 'rubocop/cop/rspec/file_path'
18
+ require 'rubocop/cop/rspec/focus'
18
19
  require 'rubocop/cop/rspec/instance_variable'
20
+ require 'rubocop/cop/rspec/example_length'
19
21
  require 'rubocop/cop/rspec/multiple_describes'
20
22
  require 'rubocop/cop/rspec/not_to_not'
21
23
  require 'rubocop/cop/rspec/verified_doubles'
@@ -33,11 +33,14 @@ module RuboCop
33
33
  _receiver, method_name, *_args = *node
34
34
  return unless ANY_INSTANCE_METHODS.include?(method_name)
35
35
 
36
- add_offense(node, :expression,
37
- format(MESSAGE % { method: method_name },
38
- node.loc.expression.source
39
- )
40
- )
36
+ add_offense(
37
+ node,
38
+ :expression,
39
+ format(
40
+ MESSAGE % { method: method_name },
41
+ node.loc.expression.source
42
+ )
43
+ )
41
44
  end
42
45
  end
43
46
  end
@@ -24,6 +24,7 @@ module RuboCop
24
24
  REQUEST_PAIR = s(:pair, s(:sym, :type), s(:sym, :request))
25
25
  FEATURE_PAIR = s(:pair, s(:sym, :type), s(:sym, :feature))
26
26
  ROUTING_PAIR = s(:pair, s(:sym, :type), s(:sym, :routing))
27
+ VIEW_PAIR = s(:pair, s(:sym, :type), s(:sym, :view))
27
28
 
28
29
  MESSAGE = 'The first argument to describe should be the class or ' \
29
30
  'module being tested.'.freeze
@@ -34,7 +35,7 @@ module RuboCop
34
35
  return if args[1..-1].any? do |arg|
35
36
  next unless arg.hash_type?
36
37
  arg.children.any? do |n|
37
- [REQUEST_PAIR, FEATURE_PAIR, ROUTING_PAIR].include?(n)
38
+ [REQUEST_PAIR, FEATURE_PAIR, ROUTING_PAIR, VIEW_PAIR].include?(n)
38
39
  end
39
40
  end
40
41
 
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module RSpec
7
+ # A long example is usually more difficult to understand. Consider
8
+ # extracting out some behaviour, e.g. with a `let` block, or a helper
9
+ # method.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # it do
14
+ # service = described_class.new
15
+ # more_setup
16
+ # more_setup
17
+ # result = service.call
18
+ # expect(result).to be(true)
19
+ # end
20
+ #
21
+ # # good
22
+ # it do
23
+ # service = described_class.new
24
+ # result = service.call
25
+ # expect(result).to be(true)
26
+ # end
27
+ class ExampleLength < Cop
28
+ include CodeLength
29
+ EXAMPLE_BLOCKS = [:it, :specify].freeze
30
+
31
+ def on_block(node)
32
+ method, _args, _body = *node
33
+ _receiver, method_name, _object = *method
34
+ return unless EXAMPLE_BLOCKS.include?(method_name)
35
+
36
+ length = code_length(node)
37
+
38
+ return unless length > max
39
+ add_offense(node, :expression, message(length, max))
40
+ end
41
+
42
+ private
43
+
44
+ def max
45
+ cop_config['Max']
46
+ end
47
+
48
+ def code_length(node)
49
+ lines = node.source.lines.to_a[1..-2] || []
50
+
51
+ lines.count { |line| !irrelevant_line(line) }
52
+ end
53
+
54
+ def message(length, max_length)
55
+ format('Example has too many lines. [%d/%d]', length, max_length)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -7,8 +7,8 @@ module RuboCop
7
7
  # Checks the path of the spec file and enforces that it reflects the
8
8
  # described class/module and its optionally called out method.
9
9
  #
10
- # With the configuration option `CustomTransform` modules or clases can be
11
- # specified that should not as usual be transformed from CamelCase to
10
+ # With the configuration option `CustomTransform` modules or classes can
11
+ # be specified that should not as usual be transformed from CamelCase to
12
12
  # snake_case (e.g. 'RuboCop' => 'rubocop' ).
13
13
  #
14
14
  # @example
@@ -20,8 +20,11 @@ module RuboCop
20
20
 
21
21
  MESSAGE = 'Spec path should end with `%s`'.freeze
22
22
  METHOD_STRING_MATCHER = /^[\#\.].+/
23
+ ROUTING_PAIR = s(:pair, s(:sym, :type), s(:sym, :routing))
23
24
 
24
25
  def on_top_level_describe(node, args)
26
+ return if routing_spec?(args)
27
+
25
28
  return unless single_top_level_describe?
26
29
  object = args.first.const_name
27
30
  return unless object
@@ -34,6 +37,13 @@ module RuboCop
34
37
 
35
38
  private
36
39
 
40
+ def routing_spec?(args)
41
+ args[1..-1].any? do |arg|
42
+ next unless arg.hash_type?
43
+ arg.children.include?(ROUTING_PAIR)
44
+ end
45
+ end
46
+
37
47
  def matcher(object, method)
38
48
  path = File.join(parts(object))
39
49
  if method && method.type == :str
@@ -56,7 +66,7 @@ module RuboCop
56
66
  def camel_to_underscore(string)
57
67
  string.dup.tap do |result|
58
68
  result.gsub!(/([^A-Z])([A-Z]+)/, '\\1_\\2')
59
- result.gsub!(/([A-Z])([A-Z][^A-Z]+)/, '\\1_\\2')
69
+ result.gsub!(/([A-Z])([A-Z\d][^A-Z\d]+)/, '\\1_\\2')
60
70
  result.downcase!
61
71
  end
62
72
  end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module RSpec
7
+ # Checks if test is focused.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # describe MyClass, focus: true do
12
+ # end
13
+ #
14
+ # describe MyClass, :focus do
15
+ # end
16
+ #
17
+ # fdescribe MyClass do
18
+ # end
19
+ #
20
+ # # good
21
+ # describe MyClass do
22
+ # end
23
+ class Focus < Cop
24
+ MESSAGE = 'Focused spec found.'.freeze
25
+
26
+ FOCUSABLE_BLOCKS = [
27
+ :example_group, :describe, :context, :xdescribe, :xcontext,
28
+ :it, :example, :specify, :xit, :xexample, :xspecify,
29
+ :feature, :scenario, :xfeature, :xscenario
30
+ ].freeze
31
+
32
+ FOCUSED_BLOCKS = [
33
+ :fdescribe, :fcontext,
34
+ :focus, :fexample, :fit, :fspecify,
35
+ :ffeature, :fscenario
36
+ ].freeze
37
+
38
+ FOCUS_KEY = s(:sym, :focus)
39
+
40
+ FOCUS_TRUE_PAIR = s(:pair, FOCUS_KEY, s(:true))
41
+
42
+ def on_send(node)
43
+ _receiver, method_name, *_args = *node
44
+ @focusable_block = FOCUSABLE_BLOCKS.include?(method_name)
45
+ if FOCUSED_BLOCKS.include?(method_name)
46
+ add_offense(node, :expression, MESSAGE)
47
+ end
48
+
49
+ # check for :focus
50
+ return unless @focusable_block
51
+ node.children.any? do |n|
52
+ add_offense(n, :expression, MESSAGE) if n == FOCUS_KEY
53
+ end
54
+ end
55
+
56
+ def on_hash(node)
57
+ return unless @focusable_block
58
+ return if node.children.any? do |n|
59
+ if [FOCUS_TRUE_PAIR].include?(n)
60
+ add_offense(n, :expression, MESSAGE)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -17,36 +17,37 @@ module RuboCop
17
17
  # expect(false).not_to be_true
18
18
  # end
19
19
  class NotToNot < Cop
20
- ACCEPTED_METHODS = [:not_to, :to_not].freeze
20
+ include RuboCop::Cop::ConfigurableEnforcedStyle
21
+
22
+ MSG = 'Prefer `%s` over `%s`'.freeze
23
+
24
+ METHOD_NAMES = [:not_to, :to_not].freeze
21
25
 
22
26
  def on_send(node)
23
27
  _receiver, method_name, *_args = *node
24
28
 
25
- if method_name == rejected_method
26
- add_offense(node, :expression, offense_message)
27
- end
28
- end
29
-
30
- private
29
+ return unless METHOD_NAMES.include?(method_name)
31
30
 
32
- def accepted_method
33
- @accepted_method ||= begin
34
- method = cop_config['AcceptedMethod'].to_sym
31
+ return if style == method_name
32
+ add_offense(node, :expression)
33
+ end
35
34
 
36
- unless ACCEPTED_METHODS.include?(method)
37
- raise "Invalid AcceptedMethod value: #{method}"
38
- end
35
+ def message(node)
36
+ _receiver, method_name, *_args = *node
39
37
 
40
- method
38
+ if method_name == :not_to
39
+ format(MSG, 'to_not', 'not_to')
40
+ else
41
+ format(MSG, 'not_to', 'to_not')
41
42
  end
42
43
  end
43
44
 
44
- def rejected_method
45
- @rejected_method ||= (ACCEPTED_METHODS - [accepted_method]).first
46
- end
47
-
48
- def offense_message
49
- "Use `#{accepted_method}` instead of `#{rejected_method}`"
45
+ def autocorrect(node)
46
+ _receiver, method_name, *_args = *node
47
+ lambda do |corrector|
48
+ corrector.replace(node.loc.selector,
49
+ method_name == :not_to ? 'to_not' : 'not_to')
50
+ end
50
51
  end
51
52
  end
52
53
  end
@@ -19,14 +19,24 @@ module RuboCop
19
19
  # end
20
20
  class VerifiedDoubles < Cop
21
21
  MSG = 'Prefer using verifying doubles over normal doubles.'.freeze
22
+ DOUBLE_TYPES = [:double, :spy].freeze
22
23
 
23
24
  def on_send(node)
24
- _receiver, method_name, *_args = *node
25
- return unless method_name == :double
25
+ _receiver, method_name, *args = *node
26
+ name, *_stubs = *args
27
+ return unless DOUBLE_TYPES.include?(method_name)
28
+ return if name.nil?
29
+ return if name_is_symbol?(name) && cop_config['IgnoreSymbolicNames']
26
30
  add_offense(node,
27
31
  :expression,
28
32
  format(MSG, node.loc.expression.source))
29
33
  end
34
+
35
+ private
36
+
37
+ def name_is_symbol?(name)
38
+ name.children.first.is_a? Symbol
39
+ end
30
40
  end
31
41
  end
32
42
  end
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module RSpec
6
6
  # Version information for the RSpec RuboCop plugin.
7
7
  module Version
8
- STRING = '1.4.1'.freeze
8
+ STRING = '1.5.0'.freeze
9
9
  end
10
10
  end
11
11
  end
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.test_files = spec.files.grep(%r{^spec/})
31
31
  spec.extra_rdoc_files = ['MIT-LICENSE.md', 'README.md']
32
32
 
33
- spec.add_runtime_dependency 'rubocop', '0.39.0'
33
+ spec.add_runtime_dependency 'rubocop', '>= 0.40.0'
34
34
 
35
35
  spec.add_development_dependency 'rake'
36
36
  spec.add_development_dependency 'rspec', '>= 3.4'
@@ -4,9 +4,14 @@ describe RuboCop::Cop::RSpec::AnyInstance do
4
4
  subject(:cop) { described_class.new }
5
5
 
6
6
  it 'finds `allow_any_instance_of` instead of an instance double' do
7
- inspect_source(cop, ['before do',
8
- ' allow_any_instance_of(Object).to receive(:foo)',
9
- 'end'])
7
+ inspect_source(
8
+ cop,
9
+ [
10
+ 'before do',
11
+ ' allow_any_instance_of(Object).to receive(:foo)',
12
+ 'end'
13
+ ]
14
+ )
10
15
  expect(cop.messages)
11
16
  .to eq(['Avoid stubbing using `allow_any_instance_of`'])
12
17
  expect(cop.highlights).to eq(['allow_any_instance_of(Object)'])
@@ -14,9 +19,14 @@ describe RuboCop::Cop::RSpec::AnyInstance do
14
19
  end
15
20
 
16
21
  it 'finds `expect_any_instance_of` instead of an instance double' do
17
- inspect_source(cop, ['before do',
18
- ' expect_any_instance_of(Object).to receive(:foo)',
19
- 'end'])
22
+ inspect_source(
23
+ cop,
24
+ [
25
+ 'before do',
26
+ ' expect_any_instance_of(Object).to receive(:foo)',
27
+ 'end'
28
+ ]
29
+ )
20
30
  expect(cop.messages)
21
31
  .to eq(['Avoid stubbing using `expect_any_instance_of`'])
22
32
  expect(cop.highlights).to eq(['expect_any_instance_of(Object)'])
@@ -24,9 +34,14 @@ describe RuboCop::Cop::RSpec::AnyInstance do
24
34
  end
25
35
 
26
36
  it 'finds old `any_instance` syntax instead of an instance double' do
27
- inspect_source(cop, ['before do',
28
- ' Object.any_instance.should_receive(:foo)',
29
- 'end'])
37
+ inspect_source(
38
+ cop,
39
+ [
40
+ 'before do',
41
+ ' Object.any_instance.should_receive(:foo)',
42
+ 'end'
43
+ ]
44
+ )
30
45
  expect(cop.messages)
31
46
  .to eq(['Avoid stubbing using `any_instance`'])
32
47
  expect(cop.highlights).to eq(['Object.any_instance'])