Skip to content
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

Load Solidus engine extension files automatically #42

Merged
merged 2 commits into from
Feb 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ module SolidusExtensionName
class Engine < Rails::Engine
engine_name 'solidus_extension_name'

include SolidusSupport::EngineExtensions::Decorators
include SolidusSupport::EngineExtensions

# ...
end
Expand All @@ -57,6 +57,26 @@ end
config.to_prepare(&method(:activate).to_proc)
```

#### Loading files conditionally

If you include `EngineExtensions` in your extension and structure your files according to the
expected paths, they will be loaded automagically only when the relevant Solidus engines are
available.

Here's what an example structure may look like:

- `lib/views/backend`: will only be added to the view paths when `solidus_backend` is available.
- `lib/controllers/backend`: will only be added to the controller paths when `solidus_backend` is
available.
- `lib/decorators/backend`: will only be added to the decorator paths when `solidus_backend` is
available.

The same goes for `frontend` and `api`.

We strongly recommend following this structure and making your extensions so that they're not
dependent on anything other than `solidus_core`, only augmenting the functionality of the other
engines when they are available.

## Development

To install this gem onto your local machine, run `bundle exec rake install`. To release a new
Expand Down
75 changes: 74 additions & 1 deletion lib/solidus_support/engine_extensions.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,76 @@
# frozen_string_literal: true

require_relative 'engine_extensions/decorators'
module SolidusSupport
module EngineExtensions
include ActiveSupport::Deprecation::DeprecatedConstantAccessor
deprecate_constant 'Decorators', 'SolidusSupport::EngineExtensions'

def self.included(engine)
engine.extend ClassMethods

engine.class_eval do
config.to_prepare(&method(:activate))

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
if Rails.respond_to?(:autoloaders) && Rails.autoloaders.main
# 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_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 tell Rails to:
#
# * add +lib/controllers/[engine]+ to the controller paths;
# * add +lib/views/[engine]+ to the view paths;
# * load the decorators in +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
37 changes: 0 additions & 37 deletions lib/solidus_support/engine_extensions/decorators.rb

This file was deleted.

2 changes: 2 additions & 0 deletions solidus_support.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Gem::Specification.new do |s|
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
s.require_paths = ["lib"]

s.add_dependency 'activesupport', ['>= 5.2', '< 7.0.x']

s.add_development_dependency 'bundler'
s.add_development_dependency 'rake'
s.add_development_dependency 'rspec-rails'
Expand Down