the-rocci-project/rOCCI-core

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

Summary

Maintainability
A
0 mins
Test Coverage
module Occi
  module Core
    # Implements the base class for all OCCI categories, including
    # `Kind`, `Action`, and `Mixin`.
    #
    # @attr term [String] category term
    # @attr schema [String] category schema, ending with '#'
    # @attr title [String] category title
    # @attr attributes [Hash] category attributes
    #
    # @attr_reader identifier [String] full identifier constructed from term and schema
    #
    # @abstract The base class itself is not renderable and should be
    #           used as an abstract starting point.
    # @author Boris Parak <parak@cesnet.cz>
    class Category
      include Yell::Loggable
      include Helpers::Renderable
      extend Helpers::IdentifierValidator
      include Helpers::AttributesAccessor
      include Helpers::ArgumentValidator
      extend Helpers::YamlSummoner

      attr_accessor :term, :schema, :title, :attributes

      # Constructs an instance with the given category information.
      # Both `term` and `schema` are mandatory arguments. `schema` must
      # be terminated with '#'.
      #
      # @example
      #   Category.new term: 'gnr', schema: 'http://example.org/test#'
      #
      # @param args [Hash] arguments with category information
      # @option args [String] :term category term
      # @option args [String] :schema category schema, ending with '#'
      # @option args [String] :title (nil) category title
      # @option args [Hash] :attributes (Hash) category attributes
      def initialize(args = {})
        pre_initialize(args)
        default_args! args

        @term = args.fetch(:term)
        @schema = args.fetch(:schema)
        @title = args.fetch(:title)
        @attributes = args.fetch(:attributes)

        post_initialize(args)
      end

      # Returns a full category identifier constructed from
      # `term` and `schema`.
      #
      # @example
      #   category.identifier  # => 'http://example.org/test#gnr'
      #
      # @return [String] category identifier
      def identifier
        "#{schema}#{term}"
      end

      # Performs internal validation of the category. Returns
      # `true` or `false` depending on the result. Currently, only
      # the category identifier is used in this process.
      #
      # @example
      #   category.valid?  # => true
      #
      # @return [TrueClass] when valid
      # @return [FalseClass] when invalid
      def valid?
        # TODO: validate attribute definitions?
        self.class.valid_identifier? identifier
      end

      # Performs internal validation of the category. Raises error
      # depending on the result. Currently, only the category
      # identifier is used in this process.
      #
      # @example
      #   category.valid!
      #
      # @raise [Occi::Core::Errors::CategoryValidationError] when invalid
      def valid!
        # TODO: validate attribute definitions?
        self.class.valid_identifier! identifier
      end

      # :nodoc:
      def to_s
        identifier
      end

      # :nodoc:
      def ==(other)
        return false unless other && other.respond_to?(:identifier)
        identifier == other.identifier
      end

      # :nodoc:
      def eql?(other)
        self == other
      end

      # :nodoc:
      def hash
        identifier.hash
      end

      protected

      # :nodoc:
      def sufficient_args!(args)
        %i[term schema].each do |attr|
          unless self.class.send("valid_#{attr}?", args[attr])
            raise Occi::Core::Errors::MandatoryArgumentError, "#{attr} is a mandatory " \
                  "argument for #{self.class}"
          end
        end
      end

      # :nodoc:
      def defaults
        {
          term: nil,
          schema: nil,
          title: nil,
          attributes: {}
        }
      end

      # :nodoc:
      def pre_initialize(args); end

      # :nodoc:
      def post_initialize(args); end
    end
  end
end