razum2um/lurker

View on GitHub
lib/lurker/json/schema/attribute.rb

Summary

Maintainability
A
1 hr
Test Coverage
require 'action_dispatch'

module Lurker
  module Json
    class Attribute < Schema
      URI = 'uri'.freeze
      COLOR = 'color'.freeze
      FORMAT = 'format'.freeze
      DATE_TIME = 'date-time'.freeze

      TYPE_MAP = {
        'Time' => Json::STRING,
        'Hash' => Json::OBJECT,
        'Float' => Json::NUMBER,
        'Fixnum' => Json::INTEGER,
        'NilClass' => Json::NULL,
        'TrueClass' => Json::BOOLEAN,
        'FalseClass' => Json::BOOLEAN,
        'ActionDispatch::Http::UploadedFile' => Json::STRING
      }.freeze

      def merge!(schema)
        return replace!(schema) if @schema[Json::TYPE].blank?

        schema = attributify(schema)
        return if eql?(schema)

        replace_options = {root_schema: root_schema, parent_schema: parent_schema,
                           parent_property: parent_property}

        attributes_tuple = Lurker::Json::Tuple::AnyOf.new(
          [to_hash, schema], replace_options)

        parent_schema.replace!(parent_property, attributes_tuple)
      end

      def replace!(schema)
        @schema.clear.merge!(attributify schema)
      end

      def eql?(schema)
        @schema[Json::TYPE] == attributify(schema)[Json::TYPE]
      end

      private

      def initialize_default_properties
        @schema[Json::DESCRIPTION] ||= ''
        @schema[Json::TYPE] ||= ''
        @schema[Json::EXAMPLE] = '' if @schema[Json::EXAMPLE].nil?
      end

      def parse_schema(schema)
        @schema = {}

        if schema.is_a?(Hash)
          @schema.merge!(schema)
        else
          @schema = attributify(schema)
        end

        initialize_default_properties
      end

      def attributify(schema)
        return schema if schema.is_a?(Hash) || schema.is_a?(Lurker::Json::Schema)

        attribute = {
          Json::DESCRIPTION => '',
          Json::TYPE => guess_type(schema),
          Json::EXAMPLE => serialize_example(schema)
        }

        if format = guess_format(schema)
          attribute[FORMAT] = format
        end

        attribute
      end

      def serialize_example(data)
        if data.is_a?(ActionDispatch::Http::UploadedFile)
          data.headers
        else
          data
        end
      end

      def guess_type(data)
        data_type = data.class.to_s
        TYPE_MAP[data_type] || data_type.downcase
      end

      def guess_format(data)
        if data.is_a?(Time)
          DATE_TIME
        elsif data.is_a?(String)
          if data.start_with? 'http://'
            URI
          elsif data.match(/\#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?\b/)
            COLOR
          else
            begin
              DATE_TIME if Time.iso8601(data)
            rescue
              nil
            end
          end
        end
      end
    end
  end
end