EGI-FCTF/rOCCI-core

View on GitHub
lib/occi/core/renderers/text/category.rb

Summary

Maintainability
A
25 mins
Test Coverage
require 'occi/core/renderers/text/base'

module Occi
  module Core
    module Renderers
      module Text
        # Implements routines required to render `Occi::Core::Category` and
        # its subclasses to a text-based representation. Supports rendering
        # to plain and header-like formats. Internally, the rendering itself
        # is done via ERB templates.
        #
        # @author Boris Parak <parak@cesnet.cz>
        class Category < Base
          # Category key constants
          CATEGORY_KEY_PLAIN = 'Category'.freeze
          CATEGORY_KEY_HEADERS = 'X-OCCI-Category'.freeze

          # Renders `object` into plain text and returns the result
          # as `String`.
          #
          # @return [String] textual representation of Object
          def render_plain
            obj_data = object_data
            "#{CATEGORY_KEY_PLAIN}: #{erb_render(obj_data)}"
          end

          # Renders `object` into text for headers and returns the result
          # as `Hash`.
          #
          # @return [Hash] textual representation of Object for headers
          def render_headers
            obj_data = object_data
            { CATEGORY_KEY_HEADERS => [erb_render(obj_data)] }
          end

          # Returns keyword used to prefix all categories rendered to plain text.
          #
          # @return [String] category keyword
          def category_key_plain
            CATEGORY_KEY_PLAIN
          end

          # Returns word used to key all categories rendered to headers.
          #
          # @return [String] category key
          def category_key_headers
            CATEGORY_KEY_HEADERS
          end

          class << self
            # Returns keyword used to prefix all categories rendered to plain text.
            #
            # @return [String] category keyword
            def category_key_plain
              CATEGORY_KEY_PLAIN
            end

            # Returns word used to key all categories rendered to headers.
            #
            # @return [String] category key
            def category_key_headers
              CATEGORY_KEY_HEADERS
            end
          end

          private

          # :nodoc:
          def short?
            options[:type] == 'short'
          end

          # :nodoc:
          def long?
            !short?
          end

          # :nodoc:
          def object_data
            {
              term: object.term, schema: object.schema,
              subclass: prepare_subclass, title: object.title,
              rel: prepare_parent, location: prepare_location,
              attributes: prepare_attributes, actions: prepare_actions
            }
          end

          # :nodoc:
          def prepare_parent
            cand = if object.respond_to?(:directly_related)
                     prepare_kind_rel
                   elsif object.respond_to?(:depends) && object.respond_to?(:applies)
                     prepare_mixin_rel.to_a
                   end
            cand.compact! if cand

            cand.blank? ? nil : cand.collect(&:identifier).join(' ')
          end

          # :nodoc:
          def prepare_kind_rel
            [object.directly_related.first]
          end

          # :nodoc:
          def prepare_mixin_rel
            return Set.new if object.depends.blank?
            object.depends + object.applies
          end

          # :nodoc:
          def prepare_subclass
            kancest = object.class.ancestors

            if kancest.include? Occi::Core::Action
              'action'
            elsif kancest.include? Occi::Core::Mixin
              'mixin'
            elsif kancest.include? Occi::Core::Kind
              'kind'
            else
              raise Occi::Core::Errors::RenderingError,
                    "Could not find known parent for #{object.inspect}"
            end
          end

          # :nodoc:
          def prepare_location
            object.respond_to?(:location) ? object.location : nil
          end

          # :nodoc:
          def prepare_attributes
            return unless object.respond_to?(:attributes)
            attrs = object.attributes.collect do |key, attr_def|
              key + prepare_attribute_def(attr_def)
            end

            attrs.empty? ? nil : attrs.join(' ')
          end

          # :nodoc:
          def prepare_attribute_def(attr_def)
            return '' unless attr_def.required? || attr_def.immutable?
            defs = []
            defs << 'required' if attr_def.required?
            defs << 'immutable' if attr_def.immutable?
            "{#{defs.join(' ')}}"
          end

          # :nodoc:
          def prepare_actions
            return unless object.respond_to?(:actions)
            acts = object.actions.collect(&:identifier)
            acts.empty? ? nil : acts.join(' ')
          end

          # :nodoc:
          def erb_render(obj_data)
            ERB.new(self.class.template, render_safe).result(binding)
          end

          class << self
            # Returns a static ERB template used to render `Category`-like
            # instances to plain text.
            #
            # @return [String] ERB template
            def template
              '<%= obj_data[:term] %>; ' \
              'scheme="<%= obj_data[:schema] %>"; ' \
              'class="<%= obj_data[:subclass] %>"' \
              '<% if long? && obj_data[:title] %>; title="<%= obj_data[:title] %>"<% end %>' \
              '<% if long? && obj_data[:rel] %>; rel="<%= obj_data[:rel] %>"<% end %>' \
              '<% if long? && obj_data[:location] %>; location="<%= obj_data[:location] %>"<% end %>' \
              '<% if long? && obj_data[:attributes] %>; attributes="<%= obj_data[:attributes] %>"<% end %>' \
              '<% if long? && obj_data[:actions] %>; actions="<%= obj_data[:actions] %>"<% end %>'
            end
          end
        end
      end
    end
  end
end