Module: FreshBooks::Client

Includes:
HTTParty
Included in:
OAuthClient, TokenClient
Defined in:
lib/freshbooks.rb

Overview

FreshBooks API client. instances are FreshBooks account specific so you can, e.g. setup two clients and copy/ sync data between them

Defined Under Namespace

Classes: FreshBooksAPIRequest, NamespaceProxy

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args) ⇒ Object

infer API methods based on 2-(and sometimes 3) deep method chains sent to clients. this allows us to provide a simple interface without actually knowing anything about the supported API methods (and hence trusting users to read the official FreshBooks API documentation)



109
110
111
# File 'lib/freshbooks.rb', line 109

def method_missing(sym, *args) # :nodoc:
  NamespaceProxy.new self, sym
end

Class Method Details

.build_xml(obj, xml = Builder::XmlMarkup.new) ⇒ Object

helper method to xml_body



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/freshbooks.rb', line 83

def self.build_xml(obj, xml=Builder::XmlMarkup.new)
  # ZOMG! haven't you ever heard of polymorphism?!?
  # of course. I'm simply electing not to pollute the
  # method space of two of the most common Ruby classes.
  # besides, what are the chances this library will ever
  # be used in a context where some other library hasn't
  # already defined #to_xml on Hash...
  case obj
  when Hash
    obj.each do |k,v|
      if [Hash, Array].include?(v.class)
        xml.tag!(k) { build_xml(v, xml) }
      else
        xml.__send__(k, v)
      end
    end
  when Array then obj.each { |e| build_xml(e, xml) }
  end
  xml.target!
end

.new(*args) ⇒ Object

:call-seq:

new(domain, api_token) => FreshBooks::TokenClient
new(domain, consumer_key, consumer_secret, token, token_secret) => FreshBooks::OAuthClient

creates a new FreshBooks API client. returns the appropriate client type based on the authorization arguments provided



47
48
49
50
51
52
53
# File 'lib/freshbooks.rb', line 47

def self.new(*args)
  case args.size
  when 2 then TokenClient.new(*args)
  when 5 then OAuthClient.new(*args)
  else raise ArgumentError
  end
end

.post(path, options = {}) ⇒ Object

:nodoc:



148
149
150
# File 'lib/freshbooks.rb', line 148

def self.post(path, options={}) # :nodoc:
  perform_freshbooks_api_request Net::HTTP::Post, path, options
end

.xml_body(method, params) ⇒ Object

takes nested Hash/Array combos and generates isomorphic XML bodies to be POSTed to FreshBooks API



73
74
75
76
77
78
79
80
# File 'lib/freshbooks.rb', line 73

def self.xml_body(method, params)
  xml = Builder::XmlMarkup.new(:indent => 2)
  xml.instruct! :xml, :version=>"1.0", :encoding=>"utf-8"
  xml.tag!("request", :method => method) do
    build_xml(params, xml)
  end
  xml.target!
end

Instance Method Details

#api_urlObject

:nodoc:



55
56
57
# File 'lib/freshbooks.rb', line 55

def api_url                 # :nodoc:
  "https://#{@domain}/api/#{API_VERSION}/xml-in"
end

#post(method, params = {}) ⇒ Object

HTTParty (sort of) assumes global connections to services but we can easily avoid that by making an instance method that knows account-specific details that calls its coresponding class method. note: we only need to provide a #post method because the FreshBooks API is POST only



65
66
67
68
69
# File 'lib/freshbooks.rb', line 65

def post(method, params={}) # :nodoc:
  Response.new Client.post(api_url,
                           :headers => auth,
                           :body => Client.xml_body(method, params))
end