rubocop-rspec 0.18.1 → 1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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