From 3bdaf27fc695b484881eed49bf7124d0138f1cb9 Mon Sep 17 00:00:00 2001 From: Alessandro Desantis Date: Fri, 31 Jan 2020 15:33:15 +0100 Subject: [PATCH] Load Solidus engine extension files automatically By cleanly separating extension files for the different Solidus engines, we can only load solidus_backend files when the engine itself is available rather than doing it all the time. In turn, this allows extensions to only actually require the parts of Solidus that they really need. --- .../engine_extensions/decorators.rb | 59 +++++++++++++++---- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/lib/solidus_support/engine_extensions/decorators.rb b/lib/solidus_support/engine_extensions/decorators.rb index 7cdfc54..50dabfe 100644 --- a/lib/solidus_support/engine_extensions/decorators.rb +++ b/lib/solidus_support/engine_extensions/decorators.rb @@ -4,33 +4,68 @@ module SolidusSupport module EngineExtensions module Decorators def self.included(engine) + engine.extend ClassMethods + engine.class_eval do - extend ClassMethods config.to_prepare(&method(:activate).to_proc) + + enable_solidus_engine_support('backend') if SolidusSupport.backend_available? + enable_solidus_engine_support('frontend') if SolidusSupport.frontend_available? + enable_solidus_engine_support('api') if SolidusSupport.api_available? end end module ClassMethods def activate - base_path = root.join('app/decorators') - if Rails.respond_to?(:autoloaders) && Rails.autoloaders.main - # Add decorators folder to the Rails autoloader. This - # allows Zeitwerk to resolve decorators paths correctly, - # when used. - Dir.glob(base_path.join('*')) do |decorators_folder| + # Add decorators folder to the Rails autoloader. This tells Zeitwerk to treat paths + # such as app/decorators/controllers as roots. + solidus_decorators_root.glob('*') do |decorators_folder| Rails.autoloaders.main.push_dir(decorators_folder) end end - # Load decorator files. This is needed since they are - # never explicitely referenced in the application code - # and won't be loaded by default. We need them to be - # executed anyway to extend exisiting classes. - Dir.glob(base_path.join('**/*.rb')) do |decorator_path| + load_solidus_decorators_from(solidus_decorators_root) + end + + # Loads decorator files. + # + # This is needed since they are never explicitly referenced in the application code and + # won't be loaded by default. We need them to be executed regardless in order to decorate + # existing classes. + def load_solidus_decorators_from(path) + path.glob('**/*.rb') do |decorator_path| require_dependency(decorator_path) end end + + private + + # Returns the root for this engine's decorators. + # + # @return [Path] + def solidus_decorators_root + root.join('app/decorators') + end + + # Enables support for a Solidus engine. + # + # This will simply tell Rails to load lib/controllers/[engine] and lib/views/[engine], as + # well as loading the decorators from lib/decorators/[engine]. + # + # @see #load_solidus_decorators_from + def enable_solidus_engine_support(engine) + paths['app/controllers'] << "lib/controllers/#{engine}" + paths['app/views'] << "lib/views/#{engine}" + + engine_context = self + config.to_prepare do + engine_context.instance_eval do + path = root.join("lib/decorators/#{engine}") + load_solidus_decorators_from(path) + end + end + end end end end