rubocop-rspec 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +22 -0
  3. data/Gemfile.lock +70 -0
  4. data/MIT-LICENSE.md +22 -0
  5. data/README.md +36 -0
  6. data/Rakefile +32 -0
  7. data/config/default.yml +5 -0
  8. data/coverage/assets/0.8.0/application.css +799 -0
  9. data/coverage/assets/0.8.0/application.js +1559 -0
  10. data/coverage/assets/0.8.0/colorbox/border.png +0 -0
  11. data/coverage/assets/0.8.0/colorbox/controls.png +0 -0
  12. data/coverage/assets/0.8.0/colorbox/loading.gif +0 -0
  13. data/coverage/assets/0.8.0/colorbox/loading_background.png +0 -0
  14. data/coverage/assets/0.8.0/favicon_green.png +0 -0
  15. data/coverage/assets/0.8.0/favicon_red.png +0 -0
  16. data/coverage/assets/0.8.0/favicon_yellow.png +0 -0
  17. data/coverage/assets/0.8.0/loading.gif +0 -0
  18. data/coverage/assets/0.8.0/magnify.png +0 -0
  19. data/coverage/assets/0.8.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  20. data/coverage/assets/0.8.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  21. data/coverage/assets/0.8.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  22. data/coverage/assets/0.8.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  23. data/coverage/assets/0.8.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  24. data/coverage/assets/0.8.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  25. data/coverage/assets/0.8.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  26. data/coverage/assets/0.8.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  27. data/coverage/assets/0.8.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  28. data/coverage/assets/0.8.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  29. data/coverage/assets/0.8.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  30. data/coverage/assets/0.8.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  31. data/coverage/assets/0.8.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  32. data/coverage/index.html +1224 -0
  33. data/lib/rubocop-rspec.rb +13 -0
  34. data/lib/rubocop/cop/rspec/unit_spec_naming.rb +144 -0
  35. data/lib/rubocop/rspec/inject.rb +23 -0
  36. data/lib/rubocop/rspec/version.rb +10 -0
  37. data/pkg/rubocop-rspec-0.1.0.gem +0 -0
  38. data/pkg/rubocop-rspec-0.17.0.gem +0 -0
  39. data/rubocop-rspec.gemspec +28 -0
  40. data/spec/rubocop/cop/rspec/unit_spec_naming_spec.rb +137 -0
  41. data/spec/spec_helper.rb +26 -0
  42. metadata +104 -0
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubocop'
4
+
5
+ require 'rubocop/rspec/version'
6
+ require 'rubocop/rspec/inject'
7
+
8
+ Rubocop::RSpec::Inject.defaults!
9
+
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'
@@ -0,0 +1,144 @@
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]+)([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
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ module Rubocop
6
+ module RSpec
7
+ # Because RuboCop doesn't yet support plugins, we have to monkey patch in a
8
+ # bit of our configuration.
9
+ module Inject
10
+ DEFAULT_FILE = File.expand_path(
11
+ '../../../../config/default.yml', __FILE__
12
+ )
13
+
14
+ def self.defaults!
15
+ hash = YAML.load_file(DEFAULT_FILE)
16
+ puts "configuration from #{path}" if ConfigLoader.debug?
17
+ config = ConfigLoader.merge_with_default(hash, DEFAULT_FILE)
18
+
19
+ ConfigLoader.instance_variable_set(:@default_configuration, config)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module RSpec
5
+ # Version information for the RSpec RuboCop plugin.
6
+ module Version
7
+ STRING = '0.17.0'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
4
+ require 'rubocop/rspec/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'rubocop-rspec'
8
+ spec.summary = 'Code style checking for RSpec files'
9
+ spec.description = <<-end_description
10
+ Code style checking for RSpec files.
11
+ A plugin for the RuboCop code style enforcing & linting tool.
12
+ end_description
13
+ spec.homepage = 'http://github.com/nevir/rubocop-rspec'
14
+ spec.authors = ['Ian MacLeod']
15
+ spec.email = ['ian@nevir.net']
16
+ spec.licenses = ['MIT']
17
+
18
+ spec.version = Rubocop::RSpec::Version::STRING
19
+ spec.platform = Gem::Platform::RUBY
20
+ spec.required_ruby_version = '>= 1.9.2'
21
+
22
+ spec.require_paths = ['lib']
23
+ spec.files = Dir['**/*']
24
+ spec.test_files = spec.files.grep(/^spec\//)
25
+ spec.extra_rdoc_files = ['MIT-LICENSE.md', 'README.md']
26
+
27
+ spec.add_runtime_dependency('rubocop', '~> 0.17')
28
+ end
@@ -0,0 +1,137 @@
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
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ # As much as possible, we try to reuse RuboCop's spec environment.
4
+ require File.join(
5
+ Gem::Specification.find_by_name('rubocop').gem_dir, 'spec', 'spec_helper.rb'
6
+ )
7
+
8
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
10
+ require 'rubocop-rspec'
11
+
12
+ # Overwriting RuboCop's parse_source to add support for mocked file paths.
13
+ #
14
+ # Remove once rubocop > 0.17.0 releases.
15
+ def parse_source(source, file = nil)
16
+ source = source.join($RS) if source.is_a?(Array)
17
+ if file.is_a? String
18
+ Rubocop::SourceParser.parse(source, file)
19
+ elsif file
20
+ file.write(source)
21
+ file.rewind
22
+ Rubocop::SourceParser.parse(source, file.path)
23
+ else
24
+ Rubocop::SourceParser.parse(source)
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubocop-rspec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.17.0
5
+ platform: ruby
6
+ authors:
7
+ - Ian MacLeod
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubocop
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '0.17'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '0.17'
27
+ description: |2
28
+ Code style checking for RSpec files.
29
+ A plugin for the RuboCop code style enforcing & linting tool.
30
+ email:
31
+ - ian@nevir.net
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files:
35
+ - MIT-LICENSE.md
36
+ - README.md
37
+ files:
38
+ - config/default.yml
39
+ - coverage/assets/0.8.0/application.css
40
+ - coverage/assets/0.8.0/application.js
41
+ - coverage/assets/0.8.0/colorbox/border.png
42
+ - coverage/assets/0.8.0/colorbox/controls.png
43
+ - coverage/assets/0.8.0/colorbox/loading.gif
44
+ - coverage/assets/0.8.0/colorbox/loading_background.png
45
+ - coverage/assets/0.8.0/favicon_green.png
46
+ - coverage/assets/0.8.0/favicon_red.png
47
+ - coverage/assets/0.8.0/favicon_yellow.png
48
+ - coverage/assets/0.8.0/loading.gif
49
+ - coverage/assets/0.8.0/magnify.png
50
+ - coverage/assets/0.8.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
51
+ - coverage/assets/0.8.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
52
+ - coverage/assets/0.8.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
53
+ - coverage/assets/0.8.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
54
+ - coverage/assets/0.8.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png
55
+ - coverage/assets/0.8.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
56
+ - coverage/assets/0.8.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
57
+ - coverage/assets/0.8.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
58
+ - coverage/assets/0.8.0/smoothness/images/ui-icons_222222_256x240.png
59
+ - coverage/assets/0.8.0/smoothness/images/ui-icons_2e83ff_256x240.png
60
+ - coverage/assets/0.8.0/smoothness/images/ui-icons_454545_256x240.png
61
+ - coverage/assets/0.8.0/smoothness/images/ui-icons_888888_256x240.png
62
+ - coverage/assets/0.8.0/smoothness/images/ui-icons_cd0a0a_256x240.png
63
+ - coverage/index.html
64
+ - Gemfile
65
+ - Gemfile.lock
66
+ - lib/rubocop/cop/rspec/unit_spec_naming.rb
67
+ - lib/rubocop/rspec/inject.rb
68
+ - lib/rubocop/rspec/version.rb
69
+ - lib/rubocop-rspec.rb
70
+ - MIT-LICENSE.md
71
+ - pkg/rubocop-rspec-0.1.0.gem
72
+ - pkg/rubocop-rspec-0.17.0.gem
73
+ - Rakefile
74
+ - README.md
75
+ - rubocop-rspec.gemspec
76
+ - spec/rubocop/cop/rspec/unit_spec_naming_spec.rb
77
+ - spec/spec_helper.rb
78
+ homepage: http://github.com/nevir/rubocop-rspec
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: 1.9.2
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.0.3
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Code style checking for RSpec files
102
+ test_files:
103
+ - spec/rubocop/cop/rspec/unit_spec_naming_spec.rb
104
+ - spec/spec_helper.rb