require 'set' require 'pathname' require 'lotus/view/version' require 'lotus/view/inheritable' require 'lotus/view/rendering' require 'lotus/view/dsl' require 'lotus/layout' require 'lotus/presenter' module Lotus # View # # @since 0.1.0 module View # Missing template error # # This is raised at the runtime when Lotus::View cannot find a template for # the requested format. # # We can't raise this error during the loading phase, because at that time # we don't know if a view implements its own rendering policy. # A view is allowed to override `#render`, and this scenario can make the # presence of a template useless. One typical example is the usage of a # serializer that returns the output string, without rendering a template. # # @since 0.1.0 class MissingTemplateError < ::StandardError def initialize(template, format) super("Can't find template '#{ template }' for '#{ format }' format.") end end # Missing format error # # This is raised at the runtime when rendering context lacks of the :format # key. # # @since 0.1.0 # # @see Lotus::View::Rendering#render class MissingFormatError < ::StandardError end # Register a view # # @api private # @since 0.1.0 # # @example # require 'lotus/view' # # class IndexView # include Lotus::View # end def self.included(base) base.class_eval do extend Inheritable.dup extend Dsl.dup extend Rendering.dup end views.add(base) end # Set the directory root where templates are located # # @param root [String] the root path # # @see Lotus::View.root # # @since 0.1.0 # # @example # require 'lotus/view' # # Lotus::View.root = '/path/to/templates' def self.root=(root) @root = Pathname.new(root) rescue nil end # Returns the directory root where templates are located. # If not already set, it returns the current directory. # # @return [Pathname] the root path for templates # # @see Lotus::View.root= # # @since 0.1.0 # # @example with already set value # require 'lotus/view' # # Lotus::View.root = '/path/to/templates' # Lotus::View.root # => #<Pathname:/path/to/templates> # # @example with missing set value # require 'lotus/view' # # Lotus::View.root # => #<Pathname:.> def self.root @root ||= begin self.root = '.' @root end end # Sets the default layout for all the registered views. # # @param layout [Symbol] the layout name # # @since 0.1.0 # # @see Lotus::View::Dsl#layout # @see Lotus::View.load! # # @example # require 'lotus/view' # # Lotus::View.layout = :application # # class IndexView # include Lotus::View # end # # Lotus::View.load! # IndexView.layout # => ApplicationLayout def self.layout=(layout) @layout = Rendering::LayoutFinder.find(layout) end # Returns the default layout to assign to the registered views. # If not already set, it returns a <tt>Rendering::NullLayout</tt>. # # @return [Class,Rendering::NullLayout] depends if already set or not. # # @since 0.1.0 # # @see Lotus::View.layout= def self.layout @layout ||= Rendering::NullLayout end # A set of registered views. # # @return [Set] all the registered views. # # @api private # @since 0.1.0 def self.views @views ||= Set.new end # A set of registered layouts. # # @return [Set] all the registered layout. # # @api private # @since 0.1.0 def self.layouts @layouts ||= Set.new end #FIXME extract a Loader class def self.load! root.freeze layout.freeze views.freeze views.each do |view| view.send(:load!) end layouts.each do |layout| layout.send(:load!) end end def self.unload! instance_variable_set(:@root, nil) instance_variable_set(:@layout, nil) instance_variable_set(:@views, Set.new) instance_variable_set(:@layouts, Set.new) end end end