module Scrivito # # @api public # class ModelLibrary attr_reader :custom_pages, :custom_widgets, :custom_objs, :custom_paths def initialize @custom_pages = [] @custom_widgets = [] @custom_objs = [] @custom_paths = [] end # # Clears model cache. # # @api public # @see Scrivito.models # def clear_cache @pages = nil @widgets = nil @objs = nil @paths = nil @require_dependencies = nil end # # Configures which models Scrivito assumes as pages, widgets and objs. # # @api public # @see Scrivito.models # def define(&block) DSL.new(self).instance_eval(&block) end # # Lists available page models. # # @api public # @see Scrivito.models # @return [Scrivito::ClassCollection] available page classes # def pages @pages ||= build_class_collection { valid_page_classes } end # # Lists available widget models. # # @api public # @see Scrivito.models # @return [Scrivito::ClassCollection] available widget classes # def widgets @widgets ||= build_class_collection { valid_widget_classes } end # # Lists available CMS object models. # # @api public # @see Scrivito.models # @return [Scrivito::ClassCollection] available CMS object classes # def objs @objs ||= build_class_collection { BasicObj.descendants.select(&:name) } end # # Lists available paths to scan for models. # # @api public # @see Scrivito.models # @return [Array] available paths to scan for models. # def paths @paths ||= (autoload_model_paths + custom_paths).map(&:to_s) end private def build_class_collection require_dependencies ClassCollection.new(yield) end def valid_widget_classes BasicWidget.descendants.select { |descendant| valid_widget_class?(descendant) } end def valid_widget_class?(model_class) model_class = model_class.to_s return true if custom_widgets.include?(model_class) model_class != 'Widget' && model_class.ends_with?('Widget') end def valid_page_classes BasicObj.descendants.select { |descendant| valid_page_class?(descendant) } end def valid_page_class?(model_class) model_class = model_class.to_s model_class.downcase.ends_with?('page') || custom_pages.include?(model_class) end def require_dependencies @require_dependencies ||= begin paths.each do |path| Dir["#{path}/**/*.rb"].sort.each do |file_path| begin require_dependency(file_path) rescue TypeError, Zeitwerk::NameError => e raise e if file_path.starts_with?(Rails.root.to_s) end end end end end def autoload_model_paths ActiveSupport::Dependencies.autoload_paths.select do |path| path.to_s.ends_with?('/app/models') end end class DSL < Struct.new(:model_library) def obj(*names) model_library.custom_objs.push(*names) end def page(*names) model_library.custom_pages.push(*names) end def widget(*names) model_library.custom_widgets.push(*names) end def paths model_library.custom_paths end end end end