ManageIQ/manageiq-api-client

View on GitHub
lib/manageiq/api/client/resource.rb

Summary

Maintainability
A
35 mins
Test Coverage
F
54%
module ManageIQ
  module API
    class Client
      class Resource
        extend Forwardable
        include ActionMixin

        CUSTOM_INSPECT_EXCLUSIONS = [:@collection].freeze
        include CustomInspectMixin

        def self.subclass(name)
          name = name.classify

          if const_defined?(name, false)
            const_get(name, false)
          else
            const_set(name, Class.new(self))
          end
        end

        attr_reader :attributes
        attr_reader :collection
        attr_reader :actions

        def_delegators :collection, :client

        def initialize(collection, resource_hash)
          raise "Cannot instantiate a Resource directly" if instance_of?(Resource)
          @collection = collection
          @attributes = resource_hash.except("actions")
          add_href
          fetch_actions(resource_hash)
        end

        def [](attr)
          attr_str = attr.to_s
          attributes[attr_str] if attributes.key?(attr_str)
        end

        private

        def method_missing(sym, *args, &block)
          reload_actions unless actions_present?
          if attributes.key?(sym.to_s)
            attributes[sym.to_s]
          elsif action_defined?(sym)
            exec_action(sym, *args, &block)
          else
            super
          end
        end

        def respond_to_missing?(sym, *_)
          attributes.key?(sym.to_s) || action_defined?(sym) || super
        end

        def exec_action(name, args = nil, &block)
          args ||= {}
          raise "Action #{name} parameters must be a hash" if !args.kind_of?(Hash)
          action = find_action(name)
          res = client.send(action.method, URI(action.href)) do
            body = { "action" => action.name }
            resource = args.dup
            resource.merge!(block.call) if block
            resource.present? ? body.merge("resource" => resource) : body
          end
          action_result(res)
        end

        # Let's add href's here if not yet defined by the server
        def add_href
          return if attributes.key?("href")
          return unless attributes.key?("id")
          attributes["href"] = client.connection.api_path("#{collection.name}/#{attributes['id']}")
        end

        def reload_actions
          return unless attributes.key?("href")
          resource_hash = client.get(attributes["href"])
          @attributes = resource_hash.except("actions")
          fetch_actions(resource_hash)
        end
      end
    end
  end
end