rubocop-rspec 0.17.0

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.
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