lib/wcc/contentful/model.rb in wcc-contentful-0.1.0 vs lib/wcc/contentful/model.rb in wcc-contentful-0.2.0
- old
+ new
@@ -3,22 +3,103 @@
class WCC::Contentful::Model
extend WCC::Contentful::Helpers
extend WCC::Contentful::ModelValidators
+ # The Model base class maintains a registry which is best expressed as a
+ # class var.
+ # rubocop:disable Style/ClassVars
+
class << self
+ ##
+ # The configured store which executes all model queries against either the
+ # Contentful CDN or a locally-downloaded copy.
+ #
+ # See the {sync_store}[rdoc-ref:WCC::Contentful::Configuration.sync_store] parameter
+ # on the WCC::Contentful::Configuration class.
attr_accessor :store
+
+ def const_missing(name)
+ raise WCC::Contentful::ContentTypeNotFoundError,
+ "Content type '#{content_type_from_constant(name)}' does not exist in the space"
+ end
end
+ @@registry = {}
+
def self.all_models
+ # TODO: this needs to use the registry but it's OK for now cause we only
+ # use it in specs
WCC::Contentful::Model.constants(false).map { |k| WCC::Contentful::Model.const_get(k) }
end
+ ##
+ # Finds an Entry or Asset by ID in the configured contentful space
+ # and returns an initialized instance of the appropriate model type.
+ #
+ # Makes use of the configured {store}[rdoc-ref:WCC::Contentful::Model.store]
+ # to access the Contentful CDN.
def self.find(id, context = nil)
return unless raw = store.find(id)
content_type = content_type_from_raw(raw)
- const = WCC::Contentful::Model.const_get(constant_from_content_type(content_type))
+ unless const = @@registry[content_type]
+ begin
+ # The app may have defined a model and we haven't loaded it yet
+ const = Object.const_missing(constant_from_content_type(content_type).to_s)
+ rescue NameError
+ nil
+ end
+ end
+ unless const
+ # Autoloading couldn't find their model - we'll register our own.
+ const = WCC::Contentful::Model.const_get(constant_from_content_type(content_type))
+ register_for_content_type(content_type, klass: const)
+ end
+
const.new(raw, context)
end
+
+ ##
+ # Registers a class constant to be instantiated when resolving an instance
+ # of the given content type. This automatically happens for the first subclass
+ # of a generated model type, example:
+ #
+ # class MyMenu < WCC::Contentful::Model::Menu
+ # end
+ #
+ # In the above case, instances of MyMenu will be instantiated whenever a 'menu'
+ # content type is resolved.
+ # The mapping can be made explicit with the optional parameters. Example:
+ #
+ # class MyFoo < WCC::Contentful::Model::Foo
+ # register_for_content_type 'bar' # MyFoo is assumed
+ # end
+ #
+ # # in initializers/wcc_contentful.rb
+ # WCC::Contentful::Model.register_for_content_type('bar', klass: MyFoo)
+ def self.register_for_content_type(content_type = nil, klass: nil)
+ klass ||= self
+ raise ArgumentError, "#{klass} must be a class constant!" unless klass.respond_to?(:new)
+ content_type ||= content_type_from_constant(klass)
+
+ @@registry[content_type] = klass
+ end
+
+ ##
+ # Returns the current registry of content type names to constants.
+ def self.registry
+ return {} unless @@registry
+ @@registry.dup.freeze
+ end
+
+ ##
+ # Checks if a content type has already been registered to a class and returns
+ # that class. If nil, the generated WCC::Contentful::Model::{content_type} class
+ # will be resolved for this content type.
+ def self.registered?(content_type)
+ @@registry[content_type]
+ end
end
+
+# rubocop:enable Style/ClassVars