-
-
Notifications
You must be signed in to change notification settings - Fork 283
Let RSpec/SpecFilePathFormat
leverage ActiveSupport inflections when configured
#2090
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
0a308f6
3bd4d24
eb1a6b4
eca02bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,12 @@ module RSpec | |
# # good | ||
# whatever_spec.rb # describe MyClass, type: :routing do; end | ||
# | ||
# @example `EnforcedInflector: active_support` | ||
# # Enable to use ActiveSupport's inflector for custom acronyms | ||
# # like HTTP, etc. Set to "default" by default. | ||
# # Configure `InflectorPath` with the path to the inflector file. | ||
# # The default is ./config/initializers/inflections.rb. | ||
# | ||
class SpecFilePathFormat < Base | ||
include TopLevelGroup | ||
include Namespace | ||
|
@@ -59,6 +65,53 @@ def on_top_level_example_group(node) | |
|
||
private | ||
|
||
# Inflector module that uses ActiveSupport for advanced inflection rules | ||
module ActiveSupportInflector | ||
def self.call(string) | ||
ActiveSupport::Inflector.underscore(string) | ||
end | ||
|
||
def self.prepare_availability(config) | ||
return if @prepared | ||
|
||
@prepared = true | ||
|
||
inflector_path = config.fetch('InflectorPath') | ||
|
||
unless File.exist?(inflector_path) | ||
raise "The configured `InflectorPath` #{inflector_path} does " \ | ||
'not exist.' | ||
end | ||
|
||
require 'active_support/inflector' | ||
require inflector_path | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I commented on Corson’s code, and now I can add the same comment on my own code 😅 It is unlikely, but not impossible, that different folders in a project use different inflector paths. We cannot blindly use the same There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, the file in https://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-inflections says
So I am not sure how we would handle multiple inflector paths 🤷🏼 Ideas are welcome. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If it helps, I think the ActiveSupport inflector is in one of the most stable possible states software can be in --- it's not deprecated and doesn't look like it will ever be deprecated, and it's essentially Open-Closed -- Closed for Modification (to prevent breaking any legacy apps or forcing upgrades) and Open for Extension. With that context, I wonder if we have an example of a real world code base that needs to support multiple inflector paths? Because all I've ever seen is that the authoritative path is used, or possibly additional files are used byt they are included into it. I have not seen separate nesting across an application --- which I guess could happen in the case of engines being included in the same repo that don't all funnel their inflection into the base app (which I believe would be a choice folks would not necessarily need to stick to). Is that what we have in mind? I guess what I'm suggesting rather than a technical solution is that we ship the 99.99% use case, comment and document it as needed, and let someone reach out if they want to support even further customization. Now, that goes out the window I guess if we have a real world use case in hand to work against right now, but it would help to know the details of that example to solve for it. |
||
end | ||
end | ||
|
||
# Inflector module that uses basic regex-based conversion | ||
module DefaultInflector | ||
def self.call(string) | ||
string | ||
.gsub(/([^A-Z])([A-Z]+)/, '\1_\2') | ||
.gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2') | ||
.downcase | ||
end | ||
end | ||
|
||
def inflector | ||
case cop_config.fetch('EnforcedInflector') | ||
when 'active_support' | ||
ActiveSupportInflector.prepare_availability(cop_config) | ||
ActiveSupportInflector | ||
when 'default' | ||
DefaultInflector | ||
else | ||
# :nocov: | ||
:noop | ||
# :nocov: | ||
end | ||
end | ||
|
||
def ensure_correct_file_path(send_node, class_name, arguments) | ||
pattern = correct_path_pattern(class_name, arguments) | ||
return if filename_ends_with?(pattern) | ||
|
@@ -106,10 +159,7 @@ def expected_path(constant) | |
end | ||
|
||
def camel_to_snake_case(string) | ||
string | ||
.gsub(/([^A-Z])([A-Z]+)/, '\1_\2') | ||
.gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2') | ||
.downcase | ||
inflector.call(string) | ||
end | ||
|
||
def custom_transform | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
most should never need to set this, but just in case