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 +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
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Rubocop::Cop::RSpecMultipleDescribes do
|
6
|
+
subject(:cop) { described_class.new }
|
7
|
+
|
8
|
+
it 'finds multiple top level describes with class and method' do
|
9
|
+
inspect_source(cop, ["describe MyClass, '.do_something' do; end",
|
10
|
+
"describe MyClass, '.do_something_else' do; end"])
|
11
|
+
expect(cop.offenses.size).to eq(1)
|
12
|
+
expect(cop.offenses.map(&:line).sort).to eq([1])
|
13
|
+
expect(cop.messages).to eq(['Do not use multiple top level describes - ' \
|
14
|
+
'try to nest them.'])
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'finds multiple top level describes only with class' do
|
18
|
+
inspect_source(cop, ['describe MyClass do; end',
|
19
|
+
'describe MyOtherClass do; end'])
|
20
|
+
expect(cop.offenses.size).to eq(1)
|
21
|
+
expect(cop.offenses.map(&:line).sort).to eq([1])
|
22
|
+
expect(cop.messages).to eq(['Do not use multiple top level describes - ' \
|
23
|
+
'try to nest them.'])
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'skips single top level describe' do
|
27
|
+
inspect_source(cop, ["require 'spec_helper'",
|
28
|
+
'',
|
29
|
+
'describe MyClass do; end'])
|
30
|
+
expect(cop.offenses).to be_empty
|
31
|
+
end
|
32
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-rspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ian MacLeod
|
8
|
+
- Nils Gemeinhardt
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2014-
|
12
|
+
date: 2014-05-18 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: rubocop
|
@@ -16,25 +17,33 @@ dependencies:
|
|
16
17
|
requirements:
|
17
18
|
- - ~>
|
18
19
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
20
|
+
version: '0.19'
|
21
|
+
- - '>='
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '0.19'
|
20
24
|
type: :runtime
|
21
25
|
prerelease: false
|
22
26
|
version_requirements: !ruby/object:Gem::Requirement
|
23
27
|
requirements:
|
24
28
|
- - ~>
|
25
29
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
30
|
+
version: '0.19'
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.19'
|
27
34
|
description: |2
|
28
35
|
Code style checking for RSpec files.
|
29
36
|
A plugin for the RuboCop code style enforcing & linting tool.
|
30
37
|
email:
|
31
38
|
- ian@nevir.net
|
39
|
+
- git@nilsgemeinhardt.de
|
32
40
|
executables: []
|
33
41
|
extensions: []
|
34
42
|
extra_rdoc_files:
|
35
43
|
- MIT-LICENSE.md
|
36
44
|
- README.md
|
37
45
|
files:
|
46
|
+
- CHANGELOG.md
|
38
47
|
- config/default.yml
|
39
48
|
- coverage/assets/0.8.0/application.css
|
40
49
|
- coverage/assets/0.8.0/application.js
|
@@ -63,8 +72,15 @@ files:
|
|
63
72
|
- coverage/index.html
|
64
73
|
- Gemfile
|
65
74
|
- Gemfile.lock
|
66
|
-
- lib/rubocop/cop/
|
75
|
+
- lib/rubocop/cop/rspec_describe_class.rb
|
76
|
+
- lib/rubocop/cop/rspec_describe_method.rb
|
77
|
+
- lib/rubocop/cop/rspec_described_class.rb
|
78
|
+
- lib/rubocop/cop/rspec_example_wording.rb
|
79
|
+
- lib/rubocop/cop/rspec_file_name.rb
|
80
|
+
- lib/rubocop/cop/rspec_instance_variable.rb
|
81
|
+
- lib/rubocop/cop/rspec_multiple_describes.rb
|
67
82
|
- lib/rubocop/rspec/inject.rb
|
83
|
+
- lib/rubocop/rspec/top_level_describe.rb
|
68
84
|
- lib/rubocop/rspec/version.rb
|
69
85
|
- lib/rubocop-rspec.rb
|
70
86
|
- MIT-LICENSE.md
|
@@ -72,10 +88,17 @@ files:
|
|
72
88
|
- pkg/rubocop-rspec-0.17.0.gem
|
73
89
|
- pkg/rubocop-rspec-0.18.0.gem
|
74
90
|
- pkg/rubocop-rspec-0.18.1.gem
|
91
|
+
- pkg/rubocop-rspec-1.0.rc1.gem
|
75
92
|
- Rakefile
|
76
93
|
- README.md
|
77
94
|
- rubocop-rspec.gemspec
|
78
|
-
- spec/rubocop/cop/
|
95
|
+
- spec/rubocop/cop/rspec_describe_class_spec.rb
|
96
|
+
- spec/rubocop/cop/rspec_describe_method_spec.rb
|
97
|
+
- spec/rubocop/cop/rspec_described_class_spec.rb
|
98
|
+
- spec/rubocop/cop/rspec_example_wording_spec.rb
|
99
|
+
- spec/rubocop/cop/rspec_file_name_spec.rb
|
100
|
+
- spec/rubocop/cop/rspec_instance_variable_spec.rb
|
101
|
+
- spec/rubocop/cop/rspec_multiple_describes_spec.rb
|
79
102
|
- spec/spec_helper.rb
|
80
103
|
homepage: http://github.com/nevir/rubocop-rspec
|
81
104
|
licenses:
|
@@ -92,9 +115,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
115
|
version: 1.9.2
|
93
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
117
|
requirements:
|
95
|
-
- - '
|
118
|
+
- - '>'
|
96
119
|
- !ruby/object:Gem::Version
|
97
|
-
version:
|
120
|
+
version: 1.3.1
|
98
121
|
requirements: []
|
99
122
|
rubyforge_project:
|
100
123
|
rubygems_version: 2.0.3
|
@@ -102,5 +125,11 @@ signing_key:
|
|
102
125
|
specification_version: 4
|
103
126
|
summary: Code style checking for RSpec files
|
104
127
|
test_files:
|
105
|
-
- spec/rubocop/cop/
|
128
|
+
- spec/rubocop/cop/rspec_describe_class_spec.rb
|
129
|
+
- spec/rubocop/cop/rspec_describe_method_spec.rb
|
130
|
+
- spec/rubocop/cop/rspec_described_class_spec.rb
|
131
|
+
- spec/rubocop/cop/rspec_example_wording_spec.rb
|
132
|
+
- spec/rubocop/cop/rspec_file_name_spec.rb
|
133
|
+
- spec/rubocop/cop/rspec_instance_variable_spec.rb
|
134
|
+
- spec/rubocop/cop/rspec_multiple_describes_spec.rb
|
106
135
|
- spec/spec_helper.rb
|
@@ -1,144 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Rubocop
|
4
|
-
module Cop
|
5
|
-
module RSpec
|
6
|
-
# This cop checks that RSpec unit tests conform to a consistent naming
|
7
|
-
# scheme - both for the describe call, and the file path.
|
8
|
-
#
|
9
|
-
# Disabled by default. Generally, you want to scope it to your project's
|
10
|
-
# unit spec paths:
|
11
|
-
#
|
12
|
-
# UnitSpecNaming:
|
13
|
-
# Enabled: true
|
14
|
-
# Include:
|
15
|
-
# - 'spec/rubocop/*'
|
16
|
-
#
|
17
|
-
class UnitSpecNaming < Cop
|
18
|
-
DESCRIBE_CLASS_MSG = 'The first argument to describe should be the ' \
|
19
|
-
'class or module being tested.'
|
20
|
-
|
21
|
-
METHOD_STRING_MSG = 'The second argument to describe should be the ' \
|
22
|
-
"method being tested. '#instance' or '.class'"
|
23
|
-
|
24
|
-
CLASS_SPEC_MSG = 'Class unit spec should have a path ending with %s'
|
25
|
-
|
26
|
-
METHOD_SPEC_MSG = 'Unit spec should have a path matching %s'
|
27
|
-
|
28
|
-
METHOD_STRING_MATCHER = /^[\#\.].+/
|
29
|
-
|
30
|
-
def on_send(node)
|
31
|
-
return unless top_level_describe? node
|
32
|
-
_receiver, _method_name, *args = *node
|
33
|
-
# Ignore non-string args (RSpec metadata)
|
34
|
-
args = [args.first] + args[1..-1].select { |a| a.type == :str }
|
35
|
-
|
36
|
-
if cop_config['EnforceDescribeStatement']
|
37
|
-
enforce_describe_statement(node, args)
|
38
|
-
end
|
39
|
-
|
40
|
-
if offences.size == 0 && cop_config['EnforceFilenames']
|
41
|
-
enforce_filename(node, args)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def enforce_describe_statement(node, args)
|
48
|
-
check_described_class(node, args.first)
|
49
|
-
check_described_method(node, args[1])
|
50
|
-
end
|
51
|
-
|
52
|
-
def enforce_filename(node, args)
|
53
|
-
path_parts = const_name(args.first).split('::').map do |part|
|
54
|
-
camel_to_underscore(part)
|
55
|
-
end
|
56
|
-
|
57
|
-
if !args[1]
|
58
|
-
check_class_spec(node, path_parts)
|
59
|
-
else
|
60
|
-
method_str = args[1].children.first if args[1]
|
61
|
-
path_parts << 'class_methods' if method_str.start_with? '.'
|
62
|
-
check_method_spec(node, path_parts, method_str)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def check_described_class(node, first_arg)
|
67
|
-
if !first_arg || first_arg.type != :const
|
68
|
-
add_offence(first_arg || node, :expression, DESCRIBE_CLASS_MSG)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def check_described_method(node, second_arg)
|
73
|
-
return unless second_arg
|
74
|
-
|
75
|
-
unless METHOD_STRING_MATCHER =~ second_arg.children.first
|
76
|
-
add_offence(second_arg, :expression, METHOD_STRING_MSG)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def check_class_spec(node, path_parts)
|
81
|
-
spec_path = File.join(path_parts) + '_spec.rb'
|
82
|
-
unless source_filename.end_with? spec_path
|
83
|
-
add_offence(node, :expression, format(CLASS_SPEC_MSG, spec_path))
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def check_method_spec(node, path_parts, method_str)
|
88
|
-
matcher_parts = path_parts.dup
|
89
|
-
# Strip out symbols; it's not worth enforcing a vocabulary for them.
|
90
|
-
matcher_parts << method_str[1..-1].gsub(/\W+/, '*') + '_spec.rb'
|
91
|
-
|
92
|
-
glob_matcher = File.join(matcher_parts)
|
93
|
-
unless source_filename =~ regexp_from_glob(glob_matcher)
|
94
|
-
message = format(METHOD_SPEC_MSG, glob_matcher)
|
95
|
-
add_offence(node, :expression, message)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def top_level_describe?(node)
|
100
|
-
_receiver, method_name, *_args = *node
|
101
|
-
return false unless method_name == :describe
|
102
|
-
|
103
|
-
root_node = processed_source.ast
|
104
|
-
top_level_nodes = describe_statement_children(root_node)
|
105
|
-
# If we have no top level describe statements, we need to check any
|
106
|
-
# blocks on the top level (e.g. after a require).
|
107
|
-
if top_level_nodes.size == 0
|
108
|
-
top_level_nodes = node_children(root_node).map do |child|
|
109
|
-
describe_statement_children(child) if child.type == :block
|
110
|
-
end.flatten.compact
|
111
|
-
end
|
112
|
-
|
113
|
-
top_level_nodes.include? node
|
114
|
-
end
|
115
|
-
|
116
|
-
def describe_statement_children(node)
|
117
|
-
node_children(node).select do |element|
|
118
|
-
element.type == :send && element.children[1] == :describe
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def source_filename
|
123
|
-
processed_source.buffer.name
|
124
|
-
end
|
125
|
-
|
126
|
-
def camel_to_underscore(string)
|
127
|
-
string.dup.tap do |result|
|
128
|
-
result.gsub!(/([^A-Z])([A-Z]+)/, '\\1_\\2')
|
129
|
-
result.gsub!(/([A-Z]{2,})([A-Z][^A-Z]+)/, '\\1_\\2')
|
130
|
-
result.downcase!
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def regexp_from_glob(glob)
|
135
|
-
Regexp.new(glob.gsub('.', '\\.').gsub('*', '.*') + '$')
|
136
|
-
end
|
137
|
-
|
138
|
-
def node_children(node)
|
139
|
-
node.children.select { |e| e.is_a? Parser::AST::Node }
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
@@ -1,137 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
describe Rubocop::Cop::RSpec::UnitSpecNaming, :config do
|
6
|
-
subject(:cop) { described_class.new(config) }
|
7
|
-
|
8
|
-
context 'describe statement enforcement' do
|
9
|
-
let(:cop_config) { { 'EnforceFilenames' => false } }
|
10
|
-
|
11
|
-
it 'checks first-line describe statements' do
|
12
|
-
inspect_source(cop,
|
13
|
-
['describe "bad describe" do; end'])
|
14
|
-
expect(cop.offences.size).to eq(1)
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'checks describe statements after a require' do
|
18
|
-
inspect_source(cop,
|
19
|
-
["require 'spec_helper'",
|
20
|
-
'describe "bad describe" do; end'])
|
21
|
-
expect(cop.offences.size).to eq(1)
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'ignores nested describe statements' do
|
25
|
-
inspect_source(cop,
|
26
|
-
['describe Some::Class do',
|
27
|
-
' describe "bad describe" do; end',
|
28
|
-
'end'])
|
29
|
-
expect(cop.offences).to eq([])
|
30
|
-
end
|
31
|
-
|
32
|
-
it "doesn't blow up on single-line describes" do
|
33
|
-
inspect_source(cop,
|
34
|
-
['describe Some::Class'])
|
35
|
-
expect(cop.offences).to eq([])
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'checks class method naming' do
|
39
|
-
inspect_source(cop,
|
40
|
-
["describe Some::Class, '.asdf' do; end"])
|
41
|
-
expect(cop.offences).to eq([])
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'checks instance method naming' do
|
45
|
-
inspect_source(cop,
|
46
|
-
["describe Some::Class, '#fdsa' do; end"])
|
47
|
-
expect(cop.offences).to eq([])
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'enforces non-method names' do
|
51
|
-
inspect_source(cop,
|
52
|
-
["describe Some::Class, 'nope' do; end"])
|
53
|
-
expect(cop.offences.size).to eq(1)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
context 'filename enforcement' do
|
58
|
-
let(:cop_config) { { 'EnforceDescribeStatement' => false } }
|
59
|
-
|
60
|
-
it 'checks class specs' do
|
61
|
-
inspect_source(cop,
|
62
|
-
['describe Some::Class do; end'],
|
63
|
-
'some/class_spec.rb')
|
64
|
-
expect(cop.offences).to eq([])
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'handles CamelCaps class names' do
|
68
|
-
inspect_source(cop,
|
69
|
-
['describe MyClass do; end'],
|
70
|
-
'my_class_spec.rb')
|
71
|
-
expect(cop.offences).to eq([])
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'handles ACRONYMClassNames' do
|
75
|
-
inspect_source(cop,
|
76
|
-
['describe ABCOne::Two do; end'],
|
77
|
-
'abc_one/two_spec.rb')
|
78
|
-
expect(cop.offences).to eq([])
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'handles ALLCAPS class names' do
|
82
|
-
inspect_source(cop,
|
83
|
-
['describe ALLCAPS do; end'],
|
84
|
-
'allcaps_spec.rb')
|
85
|
-
expect(cop.offences).to eq([])
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'checks instance methods' do
|
89
|
-
inspect_source(cop,
|
90
|
-
["describe Some::Class, '#inst' do; end"],
|
91
|
-
'some/class/inst_spec.rb')
|
92
|
-
expect(cop.offences).to eq([])
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'checks class methods' do
|
96
|
-
inspect_source(cop,
|
97
|
-
["describe Some::Class, '.inst' do; end"],
|
98
|
-
'some/class/class_methods/inst_spec.rb')
|
99
|
-
expect(cop.offences).to eq([])
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'ignores non-alphanumeric characters' do
|
103
|
-
inspect_source(cop,
|
104
|
-
["describe Some::Class, '#pred?' do; end"],
|
105
|
-
'some/class/pred_spec.rb')
|
106
|
-
expect(cop.offences).to eq([])
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'allows flexibility with predicates' do
|
110
|
-
inspect_source(cop,
|
111
|
-
["describe Some::Class, '#thing?' do; end"],
|
112
|
-
'some/class/thing_predicate_spec.rb')
|
113
|
-
expect(cop.offences).to eq([])
|
114
|
-
end
|
115
|
-
|
116
|
-
it 'allows flexibility with operators' do
|
117
|
-
inspect_source(cop,
|
118
|
-
["describe MyClass, '#<=>' do; end"],
|
119
|
-
'my_class/spaceship_operator_spec.rb')
|
120
|
-
expect(cop.offences).to eq([])
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'checks the path' do
|
124
|
-
inspect_source(cop,
|
125
|
-
["describe MyClass, '#foo' do; end"],
|
126
|
-
'my_clas/foo_spec.rb')
|
127
|
-
expect(cop.offences.size).to eq(1)
|
128
|
-
end
|
129
|
-
|
130
|
-
it 'checks class spec paths' do
|
131
|
-
inspect_source(cop,
|
132
|
-
['describe MyClass do; end'],
|
133
|
-
'my_clas_spec.rb')
|
134
|
-
expect(cop.offences.size).to eq(1)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|