SpontaneousCMS/spontaneous

View on GitHub
lib/spontaneous/output/format.rb

Summary

Maintainability
B
6 hrs
Test Coverage

module Spontaneous::Output
  class Format
    module ClassMethods
      # class_attribute :template_engine

      def inherited(subclass)
        subclass.helper_formats.concat helper_formats
      end

      def provides_format(*formats)
        helper_formats.concat formats
        Spontaneous::Output.register_format(self, *formats)
      end

      def helper_formats
        @helper_formats ||= []
      end

      def configure(output_name, options)
        format    = options[:format]
        extension = options[:extension]
        language  = options[:language]
        mimetype  = options[:mimetype] || options[:mime_type] || calculate_mimetype(format)
        options.update({
          format: format.to_sym,
          mimetype: mimetype,
          extension: extension,
          language: language
        })
        @name    = output_name.to_sym
        @options = default_options.merge(options)
      end

      def calculate_mimetype(format)
        ::Rack::Mime.mime_type(".#{format}", nil) || inherited_mimetype
      end

      def calculated_mimetype
        calculate_mimetype(format)
      end

      def default_options
        { private: false,
          dynamic: false }
      end

      def inherited_mimetype
        ::Rack::Mime.mime_type(".#{helper_formats.first}")
      end

      def mimetype
        return inherited_mimetype if @options.nil?
        @options[:mimetype]
      end

      alias_method :mime_type, :mimetype

      def custom_mimetype?
        calculated_mimetype != mimetype
      end

      def format
        @options[:format]
      end

      def name
        @name
      end

      def to_sym
        @name
      end

      def to_s
        to_sym.to_s
      end

      def extension(is_dynamic = false, dynamic_extension = Spontaneous::Output::Template.extension)
        if (override = @options[:extension])
          return normalise_extension(override.to_s)
        end
        ext =  normalise_extension(name.to_s)
        ext << ".#{self.dynamic_extension(dynamic_extension)}" if (is_dynamic or self.dynamic?)
        ext
      end

      def normalise_extension(ext)
        ext =  "." << ext unless ext.start_with?(".")
        ext
      end

      def dynamic_extension(default_extension)
        @options[:language] || default_extension
      end

      def private?
        @options[:private]
      end

      def public?
        !self.private?
      end

      def dynamic?
        @options[:dynamic]
      end


      def postprocess
        @options[:postprocess]
      end

      def options
        @options
      end

      def context(site = Spontaneous.instance)
        site.context (helper_formats + [name]).uniq.compact
      end

      def default_renderer(site)
        Spontaneous::Output::Template::Renderer.new(site)
      end

      def preview_renderer(site)
        Spontaneous::Output::Template::PreviewRenderer.new(site)
      end

      def published_renderer(site, revision)
        Spontaneous::Output::Template::PublishedRenderer.new(site, revision)
      end
    end

    extend ClassMethods
    extend Forwardable

    attr_reader :page
    attr_accessor :content

    def_delegators "self.class", :format, :dynamic?, :extension, :to_sym,
      :mimetype, :mime_type, :custom_mimetype?,
      :public?, :private?, :context, :name, :extension, :options

    def initialize(page, content = nil)
      @page, @content = page, content
      @content ||= page
    end

    def model
      content.model
    end

    # Hook into Pages' ability to re-define the object that they render as
    def renderable_content
      content.renderable
    end

    def render(params = {}, parent_context = nil)
      render_using(default_renderer, params, parent_context)
    end

    def render_using(renderer, params = {}, parent_context = nil)
      before_render
      output = render_content(renderer, params, parent_context)
      output = postprocess(output)
      after_render(output)
      output
    end

    def default_renderer
      self.class.default_renderer(@page.site)
    end

    def publish_renderer(transaction)
      Spontaneous::Output::Template::PublishRenderer.new(transaction, true)
    end

    def before_render
    end

    def after_render(output)
    end

    def postprocess(output)
      if (process = self.class.postprocess) && (process.is_a?(Proc))
        output = process.call(@page, output)
      end
      output
    end

    def render_content(renderer, params = {}, parent_context = nil)
      renderer.render(self, params, parent_context)
    end

    def publish_page(renderer, revision, transaction)
      rendered = render_using(renderer, {:revision => revision})
      transaction.store_output(self, renderer.is_dynamic_template?(rendered), rendered)
    end

    def output_path(revision, render)
      template_dynamic = Spontaneous::Output::Template.is_dynamic?(render)
      path = Spontaneous::Output.output_path(revision, self, template_dynamic)

      dir = File.dirname(path)
      FileUtils.mkdir_p(dir) unless File.exist?(dir)
      path
    end

    def ==(other)
      eql?(other)
    end

    def eql?(other)
      other.class == self.class && other.page == self.page
    end

    def hash
      [self.class, page, options].hash
    end

    def url_path
      path = page.path
      path = "/index" if path == "/"
      [path, name].join(".")
    end

    def output_protected?
      private? || custom_mimetype?
    end

    def protected?
      output_protected? || page.dynamic? || page.in_private_tree?
    end
  end
end

Dir[File.join(File.dirname(__FILE__), 'format', '*.rb')].each do |format|
  require format
end