Skip to content

Instantly share code, notes, and snippets.

@estum
Created April 20, 2022 16:26
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 estum/5a69fad6db9a914bf8ec69ad8d41371b to your computer and use it in GitHub Desktop.
Save estum/5a69fad6db9a914bf8ec69ad8d41371b to your computer and use it in GitHub Desktop.
Mixin with namespaced macro to inherit view prefixes from several modules.
# Mixin with namespaced macro to inherit view prefixes from several modules.
#
# @example Imagine legacy controllers…
# module V1
# class BaseController < ActionController::Metal; end
# # => _prefixes: ['api/v1/base']
#
# class PostsController < BaseController; end
# # => _prefixes: ['api/v1/base', 'api/v1/posts']
# end
#
# @example …and inherited actual version
# module V2
# class PostsController < V1::PostsController; end
# # => _prefixes: ['v1/base', 'v1/posts', 'v2/posts']
# end
#
# @example Extend namespace with SumsPrefix, if it's wanted to include 'v2/base' in the view prefixes of V2::PostsController!
# module V2
# extend SumsPrefix
#
# class BaseController < V1::BaseController; end
# # => _prefixes: ['v1/base', 'v2/base']
#
# class PostsController < Sum(V1::PostsController, BaseController); end
# # => _prefixes: ['v1/base', 'v1/posts', 'v2/base', 'v2/posts']
# end
module SumsPrefix
NAME_TEMPLATE = 'Sum_%sController'
private
# @!visibility public
# @overload Sum(parent, *rest)
# Hooks the given class with view prefixes from parents
# @param parent [Class] class to inherit
# @param rest [Array<Class>] classes to include prefixes from
# @return [Class]
# a middleware controller inherited from a +parent+ class and
# defined in the caller's namespace with name template {NAME_TEMPLATE}
def Sum(*parents)
@sumed_classes = Concurrent::Map.new unless defined?(@sumed_classes)
@sumed_classes.fetch_or_store(parents.hash) do
parent, *rest = parents
const_name = (NAME_TEMPLATE % parents.map(&:controller_name).join(?_).classify).to_sym
sumed = const_set(const_name, Class.new(parent))
prefixes = rest.inject(parent._prefixes) { |a, e| (e._prefixes - a) + a }
sumed.instance_variable_set(:@_prefixes, prefixes)
sumed
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment