From b1a3802c1ff1421371ae59aef551a1c1d2e8c3e8 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Mon, 11 Sep 2023 23:02:17 +0900 Subject: [PATCH] Add configuration option `CustomTransformPatterns` to `RSpec/SpecFilePathFormat` --- CHANGELOG.md | 2 + config/default.yml | 4 +- docs/modules/ROOT/pages/cops_rspec.adoc | 24 +++++++- .../cop/rspec/spec_file_path_format.rb | 22 +++++++ .../cop/rspec/spec_file_path_format_spec.rb | 59 +++++++++++++++++-- 5 files changed, 103 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7974d61b..941530b8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Master (Unreleased) +- Add configuration option `CustomTransformPatterns` to `RSpec/SpecFilePathFormat`. ([@ydah]) + ## 2.25.0 (2023-10-27) - Add support single quoted string and percent string and heredoc for `RSpec/Rails/HttpStatus`. ([@ydah]) diff --git a/config/default.yml b/config/default.yml index f672f26f4..8f873e89e 100644 --- a/config/default.yml +++ b/config/default.yml @@ -863,13 +863,15 @@ RSpec/SpecFilePathFormat: - "**/*_spec.rb" Exclude: - "**/spec/routing/**/*" - CustomTransform: + CustomTransform: {} + CustomTransformPatterns: RuboCop: rubocop RSpec: rspec 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 f985c7e5f..b66129f62 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -5127,7 +5127,7 @@ it 'works', :a, :b, baz: true, foo: 'bar' | Yes | No | 2.24 -| - +| <> |=== Checks that spec file paths are consistent and well-formed. @@ -5155,6 +5155,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] @@ -5193,6 +5211,10 @@ whatever_spec.rb # describe MyClass, type: :routing do; end | Array | CustomTransform +| `{}` +| + +| CustomTransformPatterns | `{"RuboCop"=>"rubocop", "RSpec"=>"rspec"}` | diff --git a/lib/rubocop/cop/rspec/spec_file_path_format.rb b/lib/rubocop/cop/rspec/spec_file_path_format.rb index 21466c064..7a05f5a30 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 837abb073..855f36adf 100644 --- a/spec/rubocop/cop/rspec/spec_file_path_format_spec.rb +++ b/spec/rubocop/cop/rspec/spec_file_path_format_spec.rb @@ -233,19 +233,66 @@ class Foo RUBY 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) do + { + 'CustomTransform' => { 'RSpec' => 'rspec' }, + 'CustomTransformPatterns' => {} + } + end + + it 'registers an offense when not an exact match to custom ' \ + 'module name transformation' do + expect_offense(<<-RUBY, 'rspec_foo_spec.rb') + RSpec.describe RSpecFoo do; end + ^^^^^^^^^^^^^^^^^^^^^^^ Spec path should end with `r_spec_foo*_spec.rb`. + RUBY + end + + it 'registers an offense when not an exact match to custom ' \ + 'module name transformation with nested directories' do + expect_offense(<<-RUBY, 'foo/some/rspec_foo/bar_spec.rb') + describe Foo::Some::RSpecFoo, '#bar' do; end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Spec path should end with `foo/some/r_spec_foo*bar*_spec.rb`. + RUBY + end + + it 'does not register an offense when an exact match to custom ' \ + 'module name transformation' do + expect_no_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_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_offenses(<<-RUBY, 'rspec_foo_spec.rb') + RSpec.describe RSpecFoo do; end + RUBY + end - it 'does not register an offense for custom module name transformation' do - expect_no_offenses(<<-RUBY, 'foofoo/some/class/bar_spec.rb') - describe FooFoo::Some::Class, '#bar' do; end + it 'does not register an offense when an exact match to custom ' \ + 'module name transformation with nested directories' do + expect_no_offenses(<<-RUBY, 'rspec/some/foo/bar_spec.rb') + describe RSpec::Some::Foo, '#bar' do; end RUBY end end context 'when configured with `IgnoreMethods: false`' do let(:cop_config) { { 'IgnoreMethods' => false } } - let(:suffix) { 'my_class*look_here_a_method*_spec.rb' } it 'registers an offense when file path not include method name' do expect_offense(<<-RUBY, 'my_class_spec.rb')