Last active
October 21, 2022 12:25
-
-
Save andypike/82eb791e948171e6ad4e to your computer and use it in GitHub Desktop.
Self registering classes that works within a Rails app without turning on eager_loading loading in development
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ./config/environments/development.rb | |
config.eager_load = false | |
# ./lib/registry.rb | |
module Registry | |
def self.included(base) | |
base.send(:extend, ClassMethods) | |
end | |
module ClassMethods | |
def strategies(options = {}) | |
self.default = options.fetch(:default) | |
self.registry = {} | |
end | |
def register(strategy) | |
registry[strategy.identifier] = strategy | |
end | |
def strategy_for(identifier) | |
SelectiveEagerLoader.ensure_loaded | |
registry.fetch(identifier) { default } | |
end | |
private | |
attr_accessor :registry, :default | |
end | |
end | |
# ./lib/selective_eager_loader_base.rb | |
class SelectiveEagerLoaderBase | |
cattr_accessor :loaded | |
def self.ensure_loaded | |
return if already_loaded? | |
Rails.logger.info("Selectivly eager loading types") | |
files.each { |file| require_dependency(file) } | |
loaded! | |
end | |
def self.files | |
Dir.glob( | |
paths.map{ |path| Rails.root.join(path, "**/*.rb") } | |
) | |
end | |
def self.already_loaded? | |
loaded? || Rails.configuration.eager_load | |
end | |
def self.loaded? | |
loaded | |
end | |
def self.loaded! | |
self.loaded = true | |
end | |
end | |
# ./lib/self_registering.rb | |
module SelfRegistering | |
def self.included(base) | |
base.send(:extend, ClassMethods) | |
end | |
module ClassMethods | |
attr_accessor :identifier | |
def works_with(identifier, options = {}) | |
self.identifier = identifier | |
options.fetch(:registry).register(self) | |
end | |
end | |
end | |
# --------------------------------------------------------------------- | |
# ./app/models/selective_eager_loader.rb | |
class SelectiveEagerLoader < SelectiveEagerLoaderBase | |
def self.paths | |
["app/models/tools"] | |
end | |
end | |
# ./app/models/toolbox.rb | |
class Toolbox | |
include Registry | |
strategies :default => Tools::BareHands | |
end | |
# ./app/models/tools/anvil.rb | |
module Tools | |
class Anvil | |
include SelfRegistering | |
works_with :metal, :registry => Toolbox | |
def build_something | |
puts "I'm an anvil and I can work with metal" | |
end | |
end | |
end | |
# ./app/models/tools/saw.rb | |
module Tools | |
class Saw | |
include SelfRegistering | |
works_with :wood, :registry => Toolbox | |
def build_something | |
puts "I'm a saw and I can work with wood" | |
end | |
end | |
end | |
# ./app/models/tools/bare_hands.rb | |
module Tools | |
class BareHands | |
def build_something | |
puts "I use my bare hands and work with anything else" | |
end | |
end | |
end | |
# ./app/controllers/tools_controller.rb | |
class ToolsController < ApplicationController | |
def index | |
tool = Toolbox.strategy_for(:wood) | |
puts tool.new.build_something | |
tool = Toolbox.strategy_for(:metal) | |
puts tool.new.build_something | |
tool = Toolbox.strategy_for(:fabric) | |
puts tool.new.build_something | |
end | |
end | |
# => I'm a saw and I can work with wood | |
# => I'm an anvil and I can work with metal | |
# => I use my bare hands and work with anything else |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, I was trying to build something to register a set of classes in Rails when I came across this gist. I would like to use your code, but there doesn't seem to be a license attached. What is your policy on this?