rubocop-rspec 0.18.1 → 1.0.rc1
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 +4 -4
- data/CHANGELOG.md +24 -0
- data/Gemfile.lock +10 -8
- data/README.md +19 -0
- data/config/default.yml +27 -5
- data/lib/rubocop-rspec.rb +9 -4
- data/lib/rubocop/cop/rspec_describe_class.rb +28 -0
- data/lib/rubocop/cop/rspec_describe_method.rb +35 -0
- data/lib/rubocop/cop/rspec_described_class.rb +56 -0
- data/lib/rubocop/cop/rspec_example_wording.rb +33 -0
- data/lib/rubocop/cop/rspec_file_name.rb +59 -0
- data/lib/rubocop/cop/rspec_instance_variable.rb +39 -0
- data/lib/rubocop/cop/rspec_multiple_describes.rb +35 -0
- data/lib/rubocop/rspec/top_level_describe.rb +59 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/pkg/rubocop-rspec-0.18.1.gem +0 -0
- data/pkg/rubocop-rspec-1.0.rc1.gem +0 -0
- data/rubocop-rspec.gemspec +3 -3
- data/spec/rubocop/cop/rspec_describe_class_spec.rb +36 -0
- data/spec/rubocop/cop/rspec_describe_method_spec.rb +22 -0
- data/spec/rubocop/cop/rspec_described_class_spec.rb +113 -0
- data/spec/rubocop/cop/rspec_example_wording_spec.rb +23 -0
- data/spec/rubocop/cop/rspec_file_name_spec.rb +122 -0
- data/spec/rubocop/cop/rspec_instance_variable_spec.rb +32 -0
- data/spec/rubocop/cop/rspec_multiple_describes_spec.rb +32 -0
- metadata +38 -9
- data/lib/rubocop/cop/rspec/unit_spec_naming.rb +0 -144
- data/spec/rubocop/cop/rspec/unit_spec_naming_spec.rb +0 -137
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49fdb4caa58a78596796faa90d973ac516dffa1f
|
4
|
+
data.tar.gz: 10a46ce312058c7611a916851dcb40c0b49205f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e27e4fb551f7c7354f3cda21bf1f3236e1f205bb1dbc69d2f30a21fb8b635bafbfac8555eb4723b5d33e437385b311d1fcb23019ec4dc439198f7752b5ae090
|
7
|
+
data.tar.gz: 778915e1974fae1b074d478e3a90bc9323fd199becbb17ff88d36c6f703df0e6fc48a9873381d26e28fae7f631ffa3f5bf7432afd335a7f4e55c6ba38a3b86fb
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Change log
|
2
|
+
|
3
|
+
## 1.0.rc1
|
4
|
+
|
5
|
+
* Update code to work with rubocop >= 0.19 ([@geniou][])
|
6
|
+
* Split `UnitSpecNaming` cop into `RSpecDescribeClass`,
|
7
|
+
`RSpecDescribeMethod` and `RSpecFileName` and enabled them all by
|
8
|
+
default. ([@geniou][])
|
9
|
+
* Add `RSpecExampleWording` cop to prevent to use of should at the
|
10
|
+
beginning of the spec description. ([@geniou][])
|
11
|
+
* Fix `RSpecFileName` cop for non-class specs. ([@geniou][])
|
12
|
+
* Adapt `RSpecFileName` cop to commen naming convention and skip spec
|
13
|
+
with multiple top level describes. ([@geniou][])
|
14
|
+
* Add `RSpecMultipleDescribes` cop to check for multiple top level
|
15
|
+
describes. ([@geniou][])
|
16
|
+
* Add `RSpecDescribedClass` to promote the use of `described_class`.
|
17
|
+
([@geniou][])
|
18
|
+
* Add `RSpecInstanceVariable` cop to check for the usage of instance
|
19
|
+
variables. ([@geniou][])
|
20
|
+
|
21
|
+
<!-- Contributors -->
|
22
|
+
|
23
|
+
[@geniou]: https://github.com/geniou
|
24
|
+
[@nevir]: https://github.com/nevir
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rubocop-rspec (0.
|
5
|
-
rubocop (~> 0.
|
4
|
+
rubocop-rspec (1.0.rc1)
|
5
|
+
rubocop (~> 0.19, >= 0.19)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
ast (
|
10
|
+
ast (2.0.0)
|
11
11
|
columnize (0.3.6)
|
12
12
|
coveralls (0.7.0)
|
13
13
|
multi_json (~> 1.3)
|
@@ -27,8 +27,8 @@ GEM
|
|
27
27
|
json (1.8.1)
|
28
28
|
mime-types (2.1)
|
29
29
|
multi_json (1.8.4)
|
30
|
-
parser (2.1.
|
31
|
-
ast (
|
30
|
+
parser (2.1.9)
|
31
|
+
ast (>= 1.1, < 3.0)
|
32
32
|
slop (~> 3.4, >= 3.4.5)
|
33
33
|
powerpack (0.0.9)
|
34
34
|
racc (1.4.11)
|
@@ -54,11 +54,13 @@ GEM
|
|
54
54
|
rubinius-debugger (~> 2.0)
|
55
55
|
rubinius-profiler (~> 2.0)
|
56
56
|
rubinius-profiler (2.0.1)
|
57
|
-
rubocop (0.
|
57
|
+
rubocop (0.21.0)
|
58
58
|
json (>= 1.7.7, < 2)
|
59
|
-
parser (~> 2.1.
|
59
|
+
parser (~> 2.1.9)
|
60
60
|
powerpack (~> 0.0.6)
|
61
61
|
rainbow (>= 1.99.1, < 3.0)
|
62
|
+
ruby-progressbar (~> 1.4)
|
63
|
+
ruby-progressbar (1.5.1)
|
62
64
|
rubysl (2.0.15)
|
63
65
|
rubysl-abbrev (~> 2.0)
|
64
66
|
rubysl-base64 (~> 2.0)
|
@@ -266,7 +268,7 @@ GEM
|
|
266
268
|
multi_json
|
267
269
|
simplecov-html (~> 0.8.0)
|
268
270
|
simplecov-html (0.8.0)
|
269
|
-
slop (3.
|
271
|
+
slop (3.5.0)
|
270
272
|
term-ansicolor (1.2.2)
|
271
273
|
tins (~> 0.8)
|
272
274
|
thor (0.18.1)
|
data/README.md
CHANGED
@@ -29,6 +29,25 @@ end
|
|
29
29
|
```
|
30
30
|
|
31
31
|
|
32
|
+
The Cops
|
33
|
+
--------
|
34
|
+
|
35
|
+
**WARNING: Cop names are under flux and will likely change in the near future.**
|
36
|
+
We're hoping to [introduce namespaces](bbatsov/rubocop#1097) into the mix.
|
37
|
+
|
38
|
+
All cops are located under [`lib/rubocop/cop`](lib/rubocop/cop), and contain
|
39
|
+
examples/documentation.
|
40
|
+
|
41
|
+
In your `.rubocop.yml`, you may treat the RSpec cops just like any other cop.
|
42
|
+
For example:
|
43
|
+
|
44
|
+
```yaml
|
45
|
+
RSpecFileName:
|
46
|
+
Exclude:
|
47
|
+
- spec/my_poorly_named_spec_file.rb
|
48
|
+
```
|
49
|
+
|
50
|
+
|
32
51
|
License
|
33
52
|
-------
|
34
53
|
|
data/config/default.yml
CHANGED
@@ -1,5 +1,27 @@
|
|
1
|
-
|
2
|
-
Description: 'Check that
|
3
|
-
Enabled:
|
4
|
-
|
5
|
-
|
1
|
+
RSpecDescribeClass:
|
2
|
+
Description: 'Check that the first argument to the top level describe is the tested class or module.'
|
3
|
+
Enabled: true
|
4
|
+
|
5
|
+
RSpecDescribedClass:
|
6
|
+
Description: 'Use `described_class` for tested class / module'
|
7
|
+
Enabled: true
|
8
|
+
|
9
|
+
RSpecDescribeMethod:
|
10
|
+
Description: 'Checks that the second argument to top level describe is the tested method name.'
|
11
|
+
Enabled: true
|
12
|
+
|
13
|
+
RSpecExampleWording:
|
14
|
+
Description: 'Do not use should when describing your tests.'
|
15
|
+
Enabled: true
|
16
|
+
|
17
|
+
RSpecMultipleDescribes:
|
18
|
+
Description: 'Checks for multiple top level describes.'
|
19
|
+
Enabled: true
|
20
|
+
|
21
|
+
RSpecInstanceVariable:
|
22
|
+
Description: 'Checks for the usage of instance variables.'
|
23
|
+
Enabled: true
|
24
|
+
|
25
|
+
RSpecFileName:
|
26
|
+
Description: 'Checks the file and folder naming of the spec file.'
|
27
|
+
Enabled: true
|
data/lib/rubocop-rspec.rb
CHANGED
@@ -4,10 +4,15 @@ require 'rubocop'
|
|
4
4
|
|
5
5
|
require 'rubocop/rspec/version'
|
6
6
|
require 'rubocop/rspec/inject'
|
7
|
+
require 'rubocop/rspec/top_level_describe'
|
7
8
|
|
8
9
|
Rubocop::RSpec::Inject.defaults!
|
9
10
|
|
10
|
-
#
|
11
|
-
|
12
|
-
|
13
|
-
require 'rubocop/cop/
|
11
|
+
# cops
|
12
|
+
require 'rubocop/cop/rspec_describe_class'
|
13
|
+
require 'rubocop/cop/rspec_describe_method'
|
14
|
+
require 'rubocop/cop/rspec_described_class'
|
15
|
+
require 'rubocop/cop/rspec_example_wording'
|
16
|
+
require 'rubocop/cop/rspec_file_name'
|
17
|
+
require 'rubocop/cop/rspec_instance_variable'
|
18
|
+
require 'rubocop/cop/rspec_multiple_describes'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
# Check that the first argument to the top level describe is the tested
|
6
|
+
# class or module.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# describe 'Do something' do
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# describe TestedClass do
|
15
|
+
# end
|
16
|
+
class RSpecDescribeClass < Cop
|
17
|
+
include RSpec::TopLevelDescribe
|
18
|
+
|
19
|
+
MESSAGE = 'The first argument to describe should be the class or ' \
|
20
|
+
'module being tested.'
|
21
|
+
|
22
|
+
def on_top_level_describe(_node, args)
|
23
|
+
return if args.first && args.first.type == :const
|
24
|
+
add_offense(args.first, :expression, MESSAGE)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
# Checks that the second argument to the top level describe is the tested
|
6
|
+
# method name.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# describe MyClass, 'do something' do
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# describe MyClass, '#my_instance_method' do
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# describe MyClass, '.my_class_method' do
|
18
|
+
# end
|
19
|
+
class RSpecDescribeMethod < Cop
|
20
|
+
include RSpec::TopLevelDescribe
|
21
|
+
|
22
|
+
MESSAGE = 'The second argument to describe should be the method being ' \
|
23
|
+
"tested. '#instance' or '.class'"
|
24
|
+
METHOD_STRING_MATCHER = /^[\#\.].+/
|
25
|
+
|
26
|
+
def on_top_level_describe(_node, args)
|
27
|
+
second_arg = args[1]
|
28
|
+
return unless second_arg
|
29
|
+
return if METHOD_STRING_MATCHER =~ second_arg.children.first
|
30
|
+
|
31
|
+
add_offense(second_arg, :expression, MESSAGE)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
# If the first argument of describe is a class, the class is exposed to
|
6
|
+
# each example via described_class - this should be used instead of
|
7
|
+
# repeating the class.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# describe MyClass do
|
12
|
+
# subject { MyClass.do_something }
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# describe MyClass do
|
17
|
+
# subject { described_class.do_something }
|
18
|
+
# end
|
19
|
+
class RSpecDescribedClass < Cop
|
20
|
+
include RSpec::TopLevelDescribe
|
21
|
+
|
22
|
+
MESSAGE = 'Use `described_class` instead of `%s`'
|
23
|
+
|
24
|
+
def on_block(node)
|
25
|
+
method, _args, body = *node
|
26
|
+
return unless top_level_describe?(method)
|
27
|
+
|
28
|
+
_receiver, method_name, object = *method
|
29
|
+
return unless method_name == :describe
|
30
|
+
return unless object && object.type == :const
|
31
|
+
|
32
|
+
inspect_children(body, object)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def inspect_children(node, object)
|
38
|
+
return unless node.is_a? Parser::AST::Node
|
39
|
+
return if scope_change?(node) || node.type == :const
|
40
|
+
|
41
|
+
node.children.each do |child|
|
42
|
+
if child == object
|
43
|
+
name = object.loc.expression.source
|
44
|
+
add_offense(child, :expression, format(MESSAGE, name))
|
45
|
+
break
|
46
|
+
end
|
47
|
+
inspect_children(child, object)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def scope_change?(node)
|
52
|
+
[:def, :class, :module].include?(node.type)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
# Do not use should when describing your tests.
|
6
|
+
# see: http://betterspecs.org/#should
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# it 'should find nothing' do
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# it 'finds nothing' do
|
15
|
+
# end
|
16
|
+
class RSpecExampleWording < Cop
|
17
|
+
MSG = 'Do not use should when describing your tests.'
|
18
|
+
|
19
|
+
def on_block(node)
|
20
|
+
method, _, _ = *node
|
21
|
+
_, method_name, *args = *method
|
22
|
+
|
23
|
+
return unless method_name == :it
|
24
|
+
|
25
|
+
arguments = *(args.first)
|
26
|
+
message = arguments.first.to_s
|
27
|
+
return unless message.start_with?('should')
|
28
|
+
|
29
|
+
add_offense(method, :selector, MSG)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
# Checks the path of the spec file and enforces that it reflects the
|
6
|
+
# described class/module.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class/method_spec.rb
|
10
|
+
# class_spec.rb
|
11
|
+
class RSpecFileName < Cop
|
12
|
+
include RSpec::TopLevelDescribe
|
13
|
+
|
14
|
+
MESSAGE = 'Spec path should end with `%s`'
|
15
|
+
METHOD_STRING_MATCHER = /^[\#\.].+/
|
16
|
+
|
17
|
+
def on_top_level_describe(node, args)
|
18
|
+
return unless single_top_level_describe?
|
19
|
+
object = const_name(args.first)
|
20
|
+
return unless object
|
21
|
+
|
22
|
+
glob_matcher = matcher(object, args[1])
|
23
|
+
return if source_filename =~ regexp_from_glob(glob_matcher)
|
24
|
+
|
25
|
+
add_offense(node, :expression, format(MESSAGE, glob_matcher))
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def matcher(object, method)
|
31
|
+
method_string = method ? method.children.first.gsub(/\W+/, '') : nil
|
32
|
+
path = [File.join(path_parts(object)), method_string].compact.join('_')
|
33
|
+
"#{path}*_spec.rb"
|
34
|
+
end
|
35
|
+
|
36
|
+
def path_parts(object)
|
37
|
+
object.split('::').map do |part|
|
38
|
+
camel_to_underscore(part)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def source_filename
|
43
|
+
processed_source.buffer.name
|
44
|
+
end
|
45
|
+
|
46
|
+
def camel_to_underscore(string)
|
47
|
+
string.dup.tap do |result|
|
48
|
+
result.gsub!(/([^A-Z])([A-Z]+)/, '\\1_\\2')
|
49
|
+
result.gsub!(/([A-Z]{2,})([A-Z][^A-Z]+)/, '\\1_\\2')
|
50
|
+
result.downcase!
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def regexp_from_glob(glob)
|
55
|
+
Regexp.new(glob.gsub('.', '\\.').gsub('*', '.*') + '$')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
# When you have to assign a variable instead of using an instance variable,
|
6
|
+
# use let.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# describe MyClass do
|
11
|
+
# before { @foo = [] }
|
12
|
+
# it { expect(@foo).to be_emtpy }
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# describe MyClass do
|
17
|
+
# let(:foo) { [] }
|
18
|
+
# it { expect(foo).to be_emtpy }
|
19
|
+
# end
|
20
|
+
class RSpecInstanceVariable < Cop
|
21
|
+
MESSAGE = 'Use `let` instead of an instance variable'
|
22
|
+
EXAMPLE_GROUP_METHODS = [
|
23
|
+
:example_group, :describe, :context, :xdescribe, :xcontext, :fdescribe,
|
24
|
+
:fcontext, :shared_examples, :shared_context, :share_examples_for,
|
25
|
+
:shared_examples_for, :feature
|
26
|
+
]
|
27
|
+
|
28
|
+
def on_block(node)
|
29
|
+
method, _args, _body = *node
|
30
|
+
_receiver, method_name, _object = *method
|
31
|
+
@in_spec = true if EXAMPLE_GROUP_METHODS.include?(method_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def on_ivar(node)
|
35
|
+
add_offense(node, :expression, MESSAGE) if @in_spec
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Rubocop
|
4
|
+
module Cop
|
5
|
+
# Checks for multiple top level describes. They should be nested if it is
|
6
|
+
# for the same class or module or seperated into different files.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# describe MyClass, '.do_someting' do
|
11
|
+
# end
|
12
|
+
# describe MyClass, '.do_someting_else' do
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# #good
|
16
|
+
# describe MyClass
|
17
|
+
# describe '.do_someting' do
|
18
|
+
# end
|
19
|
+
# describe '.do_someting_else' do
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
class RSpecMultipleDescribes < Cop
|
23
|
+
include RSpec::TopLevelDescribe
|
24
|
+
|
25
|
+
MESSAGE = 'Do not use multiple top level describes - try to nest them.'
|
26
|
+
|
27
|
+
def on_top_level_describe(node, _args)
|
28
|
+
return if single_top_level_describe?
|
29
|
+
return unless top_level_nodes.first == node
|
30
|
+
|
31
|
+
add_offense(node, :expression, MESSAGE)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|