diff --git a/CHANGELOG.md b/CHANGELOG.md index ae7fd53a84..5e9a284008 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Add configuration option `CustomTransformPatterns` to `RSpec/SpecFilePathFormat`. ([@ydah]) + ## 2.24.0 (2023-09-08) - Split `RSpec/FilePath` into `RSpec/SpecFilePathSuffix` and `RSpec/SpecFilePathFormat`. `RSpec/FilePath` cop is enabled by default, the two new cops are pending and need to be enabled explicitly. ([@ydah]) diff --git a/config/default.yml b/config/default.yml index c648545862..f6be99e384 100644 --- a/config/default.yml +++ b/config/default.yml @@ -866,10 +866,12 @@ RSpec/SpecFilePathFormat: CustomTransform: RuboCop: rubocop RSpec: rspec + CustomTransformPatterns: {} IgnoreMethods: false IgnoreMetadata: type: routing VersionAdded: '2.24' + VersionChanged: "<>" Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathFormat RSpec/SpecFilePathSuffix: diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index 58de73def9..7cea77044c 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -5121,7 +5121,7 @@ it 'works', :a, :b, baz: true, foo: 'bar' | Yes | No | 2.24 -| - +| <> |=== Checks that spec file paths are consistent and well-formed. @@ -5149,6 +5149,24 @@ rubocop_spec.rb # describe RuboCop rspec_spec.rb # describe RSpec ---- +==== `CustomTransformPatterns: {}` (default) + +[source,ruby] +---- +# bad +rspec_spec.rb # describe RSpec +rspec_class_spec.rb # describe RSpecClass +---- + +==== `CustomTransformPatterns: {RSpec=>rspec}` + +[source,ruby] +---- +# good +rspec_spec.rb # describe RSpec +rspec_class_spec.rb # describe RSpecClass +---- + ==== `IgnoreMethods: false` (default) [source,ruby] @@ -5190,6 +5208,10 @@ whatever_spec.rb # describe MyClass, type: :routing do; end | `{"RuboCop"=>"rubocop", "RSpec"=>"rspec"}` | +| CustomTransformPatterns +| `{}` +| + | IgnoreMethods | `false` | Boolean diff --git a/lib/rubocop/cop/rspec/spec_file_path_format.rb b/lib/rubocop/cop/rspec/spec_file_path_format.rb index 25f2d3e4dc..4a18116012 100644 --- a/lib/rubocop/cop/rspec/spec_file_path_format.rb +++ b/lib/rubocop/cop/rspec/spec_file_path_format.rb @@ -20,6 +20,16 @@ module RSpec # rubocop_spec.rb # describe RuboCop # rspec_spec.rb # describe RSpec # + # @example `CustomTransformPatterns: {}` (default) + # # bad + # rspec_spec.rb # describe RSpec + # rspec_class_spec.rb # describe RSpecClass + # + # @example `CustomTransformPatterns: {RSpec=>rspec}` + # # good + # rspec_spec.rb # describe RSpec + # rspec_class_spec.rb # describe RSpecClass + # # @example `IgnoreMethods: false` (default) # # bad # my_class_spec.rb # describe MyClass, '#method' @@ -100,11 +110,19 @@ def expected_path(constant) File.join( constants.map do |name| + pattern, transformed = transformed_pattern(name) + name.gsub!(pattern, transformed) if transformed custom_transform.fetch(name) { camel_to_snake_case(name) } end ) end + def transformed_pattern(name) + custom_transform_patterns.find do |pattern, _| + name.include?(pattern) + end + end + def camel_to_snake_case(string) string .gsub(/([^A-Z])([A-Z]+)/, '\1_\2') @@ -116,6 +134,10 @@ def custom_transform cop_config.fetch('CustomTransform', {}) end + def custom_transform_patterns + cop_config.fetch('CustomTransformPatterns', {}) + end + def ignore_methods? cop_config['IgnoreMethods'] end diff --git a/spec/rubocop/cop/rspec/spec_file_path_format_spec.rb b/spec/rubocop/cop/rspec/spec_file_path_format_spec.rb index 8b1dcc3e09..c0ae8ee698 100644 --- a/spec/rubocop/cop/rspec/spec_file_path_format_spec.rb +++ b/spec/rubocop/cop/rspec/spec_file_path_format_spec.rb @@ -299,12 +299,40 @@ class Foo end end - context 'when configured with `CustomTransform: { "FooFoo" => "foofoo" }`' do - let(:cop_config) { { 'CustomTransform' => { 'FooFoo' => 'foofoo' } } } + context 'when configured with `CustomTransform: { "RSpec" => "rspec" }`' do + let(:cop_config) { { 'CustomTransform' => { 'RSpec' => 'rspec' } } } + let(:suffix) { 'foo/some/r_spec_foo*bar*_spec.rb' } - it 'does not register an offense for custom module name transformation' do - expect_no_global_offenses(<<-RUBY, 'foofoo/some/class/bar_spec.rb') - describe FooFoo::Some::Class, '#bar' do; end + it 'registers an offense when not an exact match to custom ' \ + 'module name transformation' do + expect_global_offense(<<-RUBY, 'foo/some/rspec_foo/bar_spec.rb', message) + describe Foo::Some::RSpecFoo, '#bar' do; end + RUBY + end + + it 'does not register an offense when an exact match to custom ' \ + 'module name transformation' do + expect_no_global_offenses(<<-RUBY, 'rspec/some/foo/bar_spec.rb') + describe RSpec::Some::Foo, '#bar' do; end + RUBY + end + end + + context 'when configured with `CustomTransformPatterns: ' \ + '{ "RSpec" => "rspec" }`' do + let(:cop_config) { { 'CustomTransformPatterns' => { 'RSpec' => 'rspec' } } } + + it 'does not register an offense when not an exact match to custom ' \ + 'module name transformation' do + expect_no_global_offenses(<<-RUBY, 'foo/some/rspec_foo/bar_spec.rb') + describe Foo::Some::RSpecFoo, '#bar' do; end + RUBY + end + + it 'does not register an offense when an exact match to custom ' \ + 'module name transformation' do + expect_no_global_offenses(<<-RUBY, 'rspec/some/foo/bar_spec.rb') + describe RSpec::Some::Foo, '#bar' do; end RUBY end end