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 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 ||= load_models('page', Scrivito::BasicObj) end # # Lists available widget models. # # @api public # @see Scrivito.models # @return [Scrivito::ClassCollection] available widget classes # def widgets @widgets ||= load_models('widget', Scrivito::BasicWidget) end # # Lists available CMS object models. # # @api public # @see Scrivito.models # @return [Scrivito::ClassCollection] available CMS object classes # def objs @objs ||= load_obj_models end def load_obj_models base_class = Scrivito::BasicObj model_classes = load_models_from_paths('obj', base_class) + load_custom_models('obj', base_class) + load_custom_models('page', base_class) ClassCollection.new(model_classes) 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 load_models(type, base_class) model_classes = load_models_from_paths(type, base_class) + load_custom_models(type, base_class) ClassCollection.new(model_classes) end def load_models_from_paths(type, base_class) paths.map { |path| load_models_from_path(type, path, base_class) }.flatten end def load_models_from_path(type, path, base_class) candidates_from_path(type, path).map do |file_path| load_model(file_path.gsub(path, '').gsub('.rb', '').camelize, base_class) end end def candidates_from_path(type, path) Dir["#{path}/**/*.rb"].select do |file_path| case type when 'page' then file_path.ends_with?('page.rb') when 'widget' then file_path.ends_with?('_widget.rb') else true end end end def load_model(class_name, base_class) model_class = class_name.constantize model_class if model_class.ancestors.include?(base_class) rescue LoadError # Ignore files with invalid models, e.g. empty files. end def load_custom_models(type, base_class) send("custom_#{type}s").map do |class_name| load_model(class_name, base_class) 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