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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3c8a34ad0b9b0eeb621b444a9ea0ca5108fe7bbd
4
- data.tar.gz: eae429b50571f8ae18345d3ce6bf647158bc13bc
3
+ metadata.gz: 49fdb4caa58a78596796faa90d973ac516dffa1f
4
+ data.tar.gz: 10a46ce312058c7611a916851dcb40c0b49205f2
5
5
  SHA512:
6
- metadata.gz: a1df19a332dde5e17d88cc1ce1829248d937a19d548c56a38f48f700f65346a927b6f6182b6e2adb194706b69895594b0937bb2b76de17f7a3f8ba85c219accc
7
- data.tar.gz: 90aa18dabf7f24951b73ff0deaa1d06f99448eed62f563c342b389d7dc4e65bb50a46cc669bc05a1da582fef5842c35eb84e2c69468cd55dbb58bab189638b15
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.18.1)
5
- rubocop (~> 0.18)
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 (1.1.0)
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.4)
31
- ast (~> 1.1)
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.18.1)
57
+ rubocop (0.21.0)
58
58
  json (>= 1.7.7, < 2)
59
- parser (~> 2.1.3)
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.4.7)
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
- UnitSpecNaming:
2
- Description: 'Check that RSpec unit tests conform to a naming scheme.'
3
- Enabled: false
4
- EnforceDescribeStatement: true
5
- EnforceFilenames: true
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
- # We are housing ourselves directly into RuboCop's module structure. This is
11
- # less than ideal, but until RuboCop directly supports plugins, we can avoid
12
- # breaking too many assumptions.
13
- require 'rubocop/cop/rspec/unit_spec_naming'
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