cloudfoundry/cfoundry

View on GitHub
lib/cfoundry/v2/model.rb

Summary

Maintainability
B
5 hrs
Test Coverage
require "multi_json"
require "cfoundry/v2/model_magic"

module CFoundry::V2
  class Model
    include ActiveModel::Validations

    @@objects = {}

    extend ModelMagic

    class << self
      def objects
        @@objects
      end

      def inherited(klass)
        @@objects[klass.object_name] = klass
        super
      end
    end

    attr_accessor :guid, :cache, :changes
    attr_reader :created_at, :updated_at
    attr_reader :diff

    def initialize(guid, client, manifest = nil, partial = false)
      @guid = guid
      @client = client
      @manifest = manifest
      @partial = partial
      @cache = {}
      @diff = {}
      @changes = {}
    end

    def created_at
      timestamp = @manifest.try(:[], :metadata).try(:[], :created_at)
      DateTime.parse(timestamp) if timestamp.present?
    end

    def updated_at
      timestamp = @manifest.try(:[], :metadata).try(:[], :updated_at)
      DateTime.parse(timestamp) if timestamp.present?
    end

    def manifest
      @manifest ||= @client.base.send(object_name, @guid)
    end

    def partial?
      @partial
    end

    def changed?
      !@changes.empty?
    end

    def inspect
      "\#<#{self.class.name} '#@guid'>"
    end

    def object_name
      @object_name ||= self.class.object_name
    end

    def plural_object_name
      @plural_object_name ||= self.class.plural_object_name
    end

    def invalidate!
      @manifest = nil
      @partial = false
      @cache = {}
      @diff = {}
      @changes = {}
    end

    def create
      create!
      true
    rescue CFoundry::APIError => e
      if e.instance_of? CFoundry::APIError
        errors.add(:base, :cc_client)
      else
        errors.add(attribute_for_error(e), e.message)
      end
      false
    end

    def attribute_for_error(error)
      :base
    end

    # this does a bit of extra processing to allow for
    # `delete!' followed by `create!'
    def create!
      payload = {}

      @manifest ||= {}
      @manifest[:entity] ||= {}

      @manifest[:entity].each do |k, v|
        if v.is_a?(Hash) && v.key?(:metadata)
          # skip; there's a _guid attribute already
        elsif v.is_a?(Array) && !v.empty? && v.all? { |x|
          x.is_a?(Hash) && x.key?(:metadata)
        }
          singular = k.to_s.sub(/s$/, "")

          payload[:"#{singular}_guids"] = v.collect do |x|
            if x.is_a?(Hash) && x.key?(:metadata)
              x[:metadata][:guid]
            else
              x
            end
          end
        else
          payload[k] = v
        end
      end

      @manifest = @client.base.post("v2", create_endpoint_name,
        :content => :json,
        :accept => :json,
        :payload => payload
      )

      @guid = @manifest[:metadata][:guid]

      @diff.clear

      true
    end

    def create_endpoint_name
      plural_object_name
    end

    def update!
      @manifest = @client.base.put("v2", plural_object_name, guid,
        :content => :json,
        :accept => :json,
        :payload => @diff
      )

      @diff.clear

      true
    end

    def delete(options = {})
      delete!(options)
    rescue CFoundry::APIError => e
      if e.instance_of? CFoundry::APIError
        errors.add(:base, :cc_client)
      else
        errors.add(attribute_for_error(e), e.message)
      end
      false
    end

    def delete!(options = {})
      @client.base.delete("v2", plural_object_name, guid, :params => options)

      @deleted = true

      @diff.clear

      if @manifest
        @manifest.delete :metadata
      end

      true
    end

    def to_param
      persisted? ? @guid.to_s : nil
    end

    def to_key
      persisted? ? [@guid] : nil
    end

    def persisted?
      @guid && !@deleted
    end

    def exists?
      invalidate!
      manifest
      true
    rescue CFoundry::NotFound
      false
    end

    def query_target(klass)
      self
    end

    def eql?(other)
      other.is_a?(self.class) && @guid == other.guid
    end

    alias :== :eql?

    def hash
      @guid.hash
    end
  end
end