util.rb 4.46 KB
module Syspro
  class Util
    # Options that a user is allowed to specify.
    OPTS_USER_SPECIFIED = Set[
      # :syspro_version
    ].freeze


    def self.objects_to_ids(h)
      case h
      when ApiResource
        h.id
      when Hash
        res = {}
        h.each { |k, v| res[k] = objects_to_ids(v) unless v.nil? }
        res
      when Array
        h.map { |v| objects_to_ids(v) }
      else
        h
      end
    end

    # Converts a hash of fields or an array of hashes into a +SysproObject+ or
    # array of +SysproObject+s. These new objects will be created as a concrete
    # type as dictated by their `object` field (e.g. an `object` value of
    # `charge` would create an instance of +Charge+), but if `object` is not
    # present or of an unknown type, the newly created instance will fall back
    # to being a +SysproObject+.
    #
    # ==== Attributes
    #
    # * +data+ - Hash of fields and values to be converted into a SysproObject.
    # * +opts+ - Options for +SysproObject+ like an API key that will be reused
    #   on subsequent API calls.
    def self.convert_to_syspro_object(data, opts = {})
      case data
      when Array
        data.map { |i| convert_to_syspro_object(i, opts) }
      when Hash
        # Try converting to a known object class.  If none available, fall back to generic SysproObject
        object_classes.fetch(data[:object], SysproObject).construct_from(data, opts)
      else
        data
      end
    end


        # The secondary opts argument can either be a string or hash
    # Turn this value into an api_key and a set of headers
    def self.normalize_opts(opts)
      case opts
      when String
        opts
      when Hash
        opts.clone
      else
        raise TypeError, "normalize_opts expects a string or a hash"
      end
    end

    # Normalizes header keys so that they're all lower case and each
    # hyphen-delimited section starts with a single capitalized letter. For
    # example, `request-id` becomes `Request-Id`. This is useful for extracting
    # certain key values when the user could have set them with a variety of
    # diffent naming schemes.
    def self.normalize_headers(headers)
      headers.each_with_object({}) do |(k, v), new_headers|
        if k.is_a?(Symbol)
          k = titlecase_parts(k.to_s.tr("_", "-"))
        elsif k.is_a?(String)
          k = titlecase_parts(k)
        end

        new_headers[k] = v
      end
    end

    def self.encode_parameters(params)
      Util.flatten_params(params)
          .map { |k, v| "#{url_encode(k)}=#{url_encode(v)}" }.join("&")
    end

    def self.flatten_params(params, parent_key = nil)
      result = []

      # do not sort the final output because arrays (and arrays of hashes
      # especially) can be order sensitive, but do sort incoming parameters
      params.each do |key, value|
        calculated_key = parent_key ? "#{parent_key}[#{key}]" : key.to_s
        if value.is_a?(Hash)
          result += flatten_params(value, calculated_key)
        elsif value.is_a?(Array)
          check_array_of_maps_start_keys!(value)
          result += flatten_params_array(value, calculated_key)
        else
          result << [calculated_key, value]
        end
      end

      result
    end

    def self.log_error(message, data = {})
      if !Syspro.logger.nil? ||
         !Syspro.log_level.nil? && Syspro.log_level <= Syspro::LEVEL_ERROR
        log_internal(message, data, color: :cyan,
                                    level: Syspro::LEVEL_ERROR, logger: Syspro.logger, out: $stderr)
      end
    end

    def self.log_info(message, data = {})
      if !Syspro.logger.nil? ||
         !Syspro.log_level.nil? && Syspro.log_level <= Syspro::LEVEL_INFO
        log_internal(message, data, color: :cyan,
                                    level: Syspro::LEVEL_INFO, logger: Syspro.logger, out: $stdout)
      end
    end

    def self.log_debug(message, data = {})
      if !Syspro.logger.nil? ||
         !Syspro.log_level.nil? && Syspro.log_level <= Syspro::LEVEL_DEBUG
        log_internal(message, data, color: :blue,
                                    level: Syspro::LEVEL_DEBUG, logger: Syspro.logger, out: $stdout)
      end
    end

    def self.url_encode(key)
      CGI.escape(key.to_s).
        # Don't use strict form encoding by changing the square bracket control
        # characters back to their literals. This is fine by the server, and
        # makes these parameter strings easier to read.
        gsub("%5B", "[").gsub("%5D", "]")
    end
  end
end