Skip to content

Instantly share code, notes, and snippets.

@caius
Created October 16, 2023 20:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save caius/12efec822b0c4cb96bfa39d78f7096a8 to your computer and use it in GitHub Desktop.
Save caius/12efec822b0c4cb96bfa39d78f7096a8 to your computer and use it in GitHub Desktop.
Zeitwerk Inflector for full path -> Constant
# frozen_string_literal: true
# Custom inflector for Zeitwerk
#
# The default inflector at ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector only
# lets us override by `basename`, but we have both `Thing` and `THING` defined as constants
# in the app so that doesn't work for us. Rather than rename everything just now, work around it
# by letting us define overrides by _filepath_ (`abspath`) as well as `basename`.
#
# NB: Normally we'd subclass the default implementation, but it's a Module so can't do that.
#
# @see Zeitwerk::Inflector
# @see ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector
#
class OurInflector
def initialize
@basename_overrides = {}
@relpath_overrides = {}
end
# Override constant inflections based on the basename
#
# basename is just snake_case. Basically lets you override the same snake_case to SnakeCASE
# across the app, no matter the namespace it's in.
#
# @param inflections [Hash{String => String}] mappings from base_name to BaseName
# @return [void]
def inflect_basename(inflections)
@basename_overrides.merge!(inflections)
end
# Override constant inflections based on filename in app
#
# Where we have the same downcased string resolving to two different constant names within
# the app we can't use `inflect_basename`. At that point we can define inflections on a file
# by file basis to let us override in one case.
#
# @param inflections [Hash{String => String}] mappings from relative paths to Constants
# @return [void]
def inflect_relpath(inflections)
@relpath_overrides.merge!(inflections)
end
# For a given basename & absolute path, return the expected constant
#
# We check for overrides in the following order:
# - path override
# - basename override
# - ActiveSupport camelize, which uses the app defined inflections
#
# @return [String] expected constant name as string
def camelize(basename, abspath)
relpath = abspath.sub("#{Rails.root}/", "") # rubocop:disable Rails/FilePath
@relpath_overrides[relpath] || @basename_overrides[basename] || basename.camelize
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment