lib/twfy/client.rb

Summary

Maintainability
A
1 hr
Test Coverage
require 'cgi'
require 'logger'
require 'multi_json'
require 'open-uri'
require 'ostruct'

module Twfy

  class Client
    include API
    include Commands

    class Error < ::StandardError; end
    class APIError < ::StandardError; end

    def initialize(api_key, log_to=$stderr)
      @api_key = api_key
      @logger = Logger.new(log_to)
    end

    def log(message, level=:info)
      @logger.send(level, message) if $DEBUG
    end

    private

    def service(name, params = {}, target = OpenStruct, &block)
      log "Calling service #{name}"
      url = service_url(name, params)
      result = MultiJson.load(url.read)
      log result.inspect
      unless result.kind_of?(Enumerable)
        raise Error, "Could not handle result: #{result.inspect}"
      end
      if result.kind_of?(Hash) && result['error']
        raise APIError, result['error'].to_s
      else
        structure result, block || target
      end
    end

    def service_url(name, params = {})
      url = BASE + name.to_s
      url.query = build_query(validate(params, API::VALIDATIONS[name]))
      url
    end

    def validate(params, against)
      Validation.run(params, against)
      params
    end

    def structure(value, target)
      case value
      when Array
        value.map{|r| structure(r, target) }
      when Hash
        if target.kind_of?(Proc)
          target.call(value)
        elsif target == Hash
          value
        else
          target.ancestors.include?(DataElement) ? target.new(self,value) : target.new(value)
        end
      else
        result
      end
    end

    def build_query(params)
      params.merge(api_params).map { |set|
        set.map { |i|
          CGI.escape(i.to_s)
        }.join('=')
      }.join('&')
    end

    def api_params
      @api_params ||= {key: @api_key, version: API::VERSION}
    end

  end

end