Skip to content

Commit 0a308f6

Browse files
committed
Let RSpec/SpecFilePathFormat leverage ActiveSupport inflections when defined and configured
Fix #740
1 parent bb168ba commit 0a308f6

File tree

5 files changed

+342
-4
lines changed

5 files changed

+342
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Mark `RSpec/IncludeExamples` as `SafeAutoCorrect: false`. ([@yujideveloper])
66
- Fix a false positive for `RSpec/LeakyConstantDeclaration` when defining constants in explicit namespaces. ([@naveg])
7+
- Let `RSpec/SpecFilePathFormat` leverage ActiveSupport inflections when configured. ([@corsonknowles])
78

89
## 3.6.0 (2025-04-18)
910

config/default.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,8 @@ RSpec/SpecFilePathFormat:
926926
IgnoreMethods: false
927927
IgnoreMetadata:
928928
type: routing
929+
InflectorPath: "./config/initializers/inflections.rb"
930+
UseActiveSupportInflections: false
929931
VersionAdded: '2.24'
930932
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/SpecFilePathFormat
931933

docs/modules/ROOT/pages/cops_rspec.adoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5951,6 +5951,17 @@ my_class_spec.rb # describe MyClass, '#method'
59515951
whatever_spec.rb # describe MyClass, type: :routing do; end
59525952
----
59535953
5954+
[#_useactivesupportinflections_-true_-rspecspecfilepathformat]
5955+
==== `UseActiveSupportInflections: true`
5956+
5957+
[source,ruby]
5958+
----
5959+
# Enable to use ActiveSupport's inflector for custom acronyms
5960+
# like HTTP, etc. Set to false by default.
5961+
# The InflectorPath provides the path to the inflector file.
5962+
# The default is ./config/initializers/inflections.rb.
5963+
----
5964+
59545965
[#configurable-attributes-rspecspecfilepathformat]
59555966
=== Configurable attributes
59565967
@@ -5976,6 +5987,14 @@ whatever_spec.rb # describe MyClass, type: :routing do; end
59765987
| IgnoreMetadata
59775988
| `{"type" => "routing"}`
59785989
|
5990+
5991+
| InflectorPath
5992+
| `./config/initializers/inflections.rb`
5993+
| String
5994+
5995+
| UseActiveSupportInflections
5996+
| `false`
5997+
| Boolean
59795998
|===
59805999
59816000
[#references-rspecspecfilepathformat]

lib/rubocop/cop/rspec/spec_file_path_format.rb

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ module RSpec
3232
# # good
3333
# whatever_spec.rb # describe MyClass, type: :routing do; end
3434
#
35+
# @example `UseActiveSupportInflections: true`
36+
# # Enable to use ActiveSupport's inflector for custom acronyms
37+
# # like HTTP, etc. Set to false by default.
38+
# # The InflectorPath provides the path to the inflector file.
39+
# # The default is ./config/initializers/inflections.rb.
40+
#
3541
class SpecFilePathFormat < Base
3642
include TopLevelGroup
3743
include Namespace
@@ -57,8 +63,67 @@ def on_top_level_example_group(node)
5763
end
5864
end
5965

66+
# For testing and debugging
67+
def self.reset_activesupport_cache!
68+
ActiveSupportInflector.reset_cache!
69+
end
70+
6071
private
6172

73+
# Inflector module that uses ActiveSupport for advanced inflection rules
74+
module ActiveSupportInflector
75+
def self.call(string)
76+
ActiveSupport::Inflector.underscore(string)
77+
end
78+
79+
def self.available?(cop_config)
80+
return @available unless @available.nil?
81+
82+
unless cop_config.fetch('UseActiveSupportInflections', false)
83+
return @available = false
84+
end
85+
86+
unless File.exist?(inflector_path(cop_config))
87+
return @available = false
88+
end
89+
90+
@available = begin
91+
require 'active_support/inflector'
92+
require inflector_path(cop_config)
93+
true
94+
rescue LoadError, StandardError
95+
false
96+
end
97+
end
98+
99+
def self.inflector_path(cop_config)
100+
cop_config.fetch('InflectorPath',
101+
'./config/initializers/inflections.rb')
102+
end
103+
104+
def self.reset_cache!
105+
@available = nil
106+
end
107+
end
108+
109+
# Inflector module that uses basic regex-based conversion
110+
module DefaultInflector
111+
def self.call(string)
112+
string
113+
.gsub(/([^A-Z])([A-Z]+)/, '\1_\2')
114+
.gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2')
115+
.downcase
116+
end
117+
end
118+
119+
def inflector
120+
@inflector ||= if ActiveSupportInflector.available?(cop_config)
121+
ActiveSupportInflector
122+
else
123+
DefaultInflector
124+
end
125+
end
126+
62127
def ensure_correct_file_path(send_node, class_name, arguments)
63128
pattern = correct_path_pattern(class_name, arguments)
64129
return if filename_ends_with?(pattern)
@@ -106,10 +171,7 @@ def expected_path(constant)
106171
end
107172

108173
def camel_to_snake_case(string)
109-
string
110-
.gsub(/([^A-Z])([A-Z]+)/, '\1_\2')
111-
.gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2')
112-
.downcase
174+
inflector.call(string)
113175
end
114176

115177
def custom_transform

0 commit comments

Comments
 (0)