turingstudio-freshbooks-rb 3.0.1 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -10,7 +10,7 @@ A Ruby interface to the FreshBooks API. It exposes easy-to-use classes and metho
10
10
 
11
11
  Initialization:
12
12
 
13
- FreshBooks::Base.setup('sample.freshbooks.com', 'mytoken')
13
+ FreshBooks::Base.establish_connection!('sample.freshbooks.com', 'mytoken')
14
14
 
15
15
  Updating a client name:
16
16
 
data/lib/freshbooks.rb CHANGED
@@ -24,6 +24,7 @@ require 'rexml/document'
24
24
  require 'activesupport'
25
25
 
26
26
  require 'freshbooks/version'
27
+ require 'freshbooks/connection'
27
28
  require 'freshbooks/response'
28
29
  require 'freshbooks/base'
29
30
  require 'freshbooks/category'
@@ -33,9 +34,12 @@ require 'freshbooks/expense'
33
34
  require 'freshbooks/invoice'
34
35
  require 'freshbooks/item'
35
36
  require 'freshbooks/line'
37
+ require 'freshbooks/links'
38
+ require 'freshbooks/list_proxy'
36
39
  require 'freshbooks/payment'
37
40
  require 'freshbooks/project'
38
41
  require 'freshbooks/recurring'
39
42
  require 'freshbooks/staff'
40
43
  require 'freshbooks/task'
41
44
  require 'freshbooks/time_entry'
45
+ require 'freshbooks/xml_serializer'
@@ -4,140 +4,82 @@ module FreshBooks
4
4
  class AuthenticationError < Exception; end;
5
5
  class UnknownSystemError < Exception; end;
6
6
  class InvalidParameterError < Exception; end;
7
+ class InvalidAccountUrlError < Exception; end;
7
8
 
8
- attr_accessor :resp
9
-
10
9
  def initialize(data = {})
11
- @old_values = {}
12
10
  @changed_fields = []
11
+ self.class.attributes.each do |name, options|
12
+ send("#{name}=", []) if options[:type] == :array
13
+ end
13
14
  data.each do |name, value|
14
15
  send("#{name}=", value) if self.class.attributes[name]
15
16
  end
17
+ #@changed_fields = [] # reset changed fields
16
18
  end
17
-
18
- # Convert an instance of this class to an XML element
19
+
19
20
  def to_xml(elem_name = nil)
20
21
  root = REXML::Element.new(node_name)
21
-
22
22
  self.class.attributes.each do |name, options|
23
- next if options[:read_only] || !send("#{name}_changed?")
24
-
25
23
  value = send(name)
26
-
27
- if self.class.method_defined?("#{name}_to_xml")
28
- send("#{name}_to_xml", root)
29
- elsif value.is_a?(Array)
30
- unless value.empty?
31
- node = root.add_element(name.to_s)
32
- value.each do |item|
33
- node.add_element(item.to_xml)
34
- end
35
- end
36
- elsif !value.nil?
37
- root.add_element(name.to_s).text = value
24
+ next if options[:read_only] || !send("#{name}_changed?") || value.nil?
25
+
26
+ if options[:to_xml]
27
+ send(options[:to_xml], root)
28
+ else
29
+ element = XmlSerializer.to_node(name.to_s, value, options[:type])
30
+ root.add_element(element) if element != nil
38
31
  end
39
32
  end
40
-
41
33
  root
42
34
  end
43
35
 
44
- def create
45
- self.class.ensure_allowed! :create
46
- resp = Base.call_api("#{node_name}.create", node_name => self)
47
- if resp.success?
48
- self.send("#{node_name}_id=", resp.elements[1].text.to_i)
49
- end
50
- resp.success? ? self.send("#{node_name}_id") : nil
51
- end
52
-
53
- def update
54
- self.class.ensure_allowed! :update
55
- resp = Base.call_api("#{node_name}.update", node_name => self)
56
- resp.success?
57
- end
58
-
59
- def delete
60
- self.class.delete(self.send("#{node_name}_id"))
61
- end
62
-
63
- def send_by_email
64
- self.class.send_by_email(self.send("#{node_name}_id"))
65
- end
66
-
67
- def send_by_snail_mail
68
- self.class.send_by_snail_mail(self.send("#{node_name}_id"))
69
- end
70
-
71
- def node_name
72
- self.class.node_name
73
- end
74
-
75
36
  class << self
76
- def setup(account_url, auth_token, request_headers = {})
77
- @@account_url = account_url
78
- @@auth_token = auth_token
79
- @@request_headers = request_headers
80
- @@response = nil
81
- end
37
+ attr_reader :connection
82
38
 
83
- def list(options = {})
84
- ensure_allowed! :list
85
- resp = Base.call_api("#{node_name}.list", options)
86
- return nil unless resp.success?
87
-
88
- elems = resp.elements[1].elements
89
- elems.map { |elem| self.new_from_xml(elem) }
39
+ def establish_connection!(account_url, auth_token, request_headers = {})
40
+ @connection = Connection.new(account_url, auth_token, request_headers)
90
41
  end
91
42
 
92
- def get(id)
93
- ensure_allowed! :get
94
- resp = Base.call_api("#{node_name}.get", "#{node_name}_id" => id)
95
- resp.success? ? self.new_from_xml(resp.elements[1]) : nil
43
+ def new_from_xml(xml_root)
44
+ object = self.new
45
+ attributes.each do |name, options|
46
+ node = xml_root.elements[name.to_s]
47
+ next if node.nil?
48
+
49
+ value = FreshBooks::XmlSerializer.to_value(node, options[:type])
50
+ object.send("#{name}=", value)
51
+ end
52
+ object
96
53
  end
97
54
 
98
- def delete(id)
99
- ensure_allowed! :delete
100
- resp = Base.call_api("#{node_name}.delete", "#{node_name}_id" => id)
101
- resp.success?
102
- end
103
-
104
- def send_by_email(id)
105
- ensure_allowed! :send_by_email
106
- resp = Base.call_api("#{node_name}.sendByEmail", "#{node_name}_id" => id)
107
- resp.success?
108
- end
109
-
110
- def send_by_snail_mail(id)
111
- ensure_allowed! :send_by_snail_mail
112
- resp = Base.call_api("#{node_name}.sendBySnailMail", "#{node_name}_id" => id)
113
- resp.success?
114
- end
115
-
116
55
  def node_name
117
56
  self.to_s.split('::').last.underscore
118
57
  end
119
58
 
120
59
  #
121
- # Defines structure attribute. Generates attr_accessor and #{name}_changed? method
60
+ # Defines structure attribute. Generates attr_accessor and #{name}_changed? method.
61
+ # Options are:
62
+ # :read_only - specifies that attribute is read-only and attr_writer is protected
63
+ # :to_xml - overrides xml generation for this attribute
122
64
  #
123
- # class Test < Base
124
- # attribute :test_id, :integer
125
- # end
65
+ # class Test < Base
66
+ # attribute :test_id, :integer
67
+ # end
126
68
  #
127
- # test = Test.new
128
- # test.test_id_changed? # false
129
- # test.test_id = 1
130
- # test.test_id_changed? # true
131
- # test.test_id # 1
69
+ # test = Test.new
70
+ # test.test_id_changed? # false
71
+ # test.test_id = 1
72
+ # test.test_id_changed? # true
73
+ # test.test_id # 1
132
74
  #
133
75
  def attribute(name, type, options = {})
134
76
  self.attributes[name] = options.update(:type => type)
135
77
 
136
78
  define_method("#{name}=") do |value|
137
79
  @changed_fields << name
138
- @old_values[name] = send(name) if @old_values[name].nil?
139
80
  instance_variable_set("@#{name}", value)
140
81
  end
82
+ self.send(:protected, "#{name}=") if options[:read_only]
141
83
 
142
84
  define_method("#{name}_changed?") do
143
85
  @changed_fields.include?(name)
@@ -179,108 +121,92 @@ module FreshBooks
179
121
  # Defines allowed API methods.
180
122
  #
181
123
  # class Test < Base
182
- # method :list
124
+ # actions :list
183
125
  # end
184
126
  #
185
127
  # Test.list # [...]
186
128
  # Test.get(1) # "Error: Method get is not allowed for Test"
187
129
  #
188
- def method(*args)
189
- @methods = (methods + args).uniq
190
- end
191
-
192
- def methods
193
- @methods ||= []
194
- end
195
-
196
- def ensure_allowed!(name)
197
- unless methods.include?(name)
198
- raise "Error: Method #{name} is not allowed for #{self}"
199
- end
200
- end
201
-
202
- # Create a new instance of this class from an XML element
203
- def new_from_xml(xml_root)
204
- object = self.new
205
- attributes.each do |name, options|
206
- node = xml_root.elements[name.to_s]
207
- next if node.nil?
130
+ def define_class_method(name, &block)
131
+ self.class.send(:define_method, name, &block)
132
+ end
208
133
 
209
- case options[:type]
210
- when :integer
211
- value = node.text.to_i
212
- when :float
213
- value = node.text.to_f
214
- when :array
215
- value = node.elements.map do |item|
216
- FreshBooks::const_get(item.name.classify)::new_from_xml(item)
217
- end
218
- else
219
- value = node.text.to_s
220
- end
221
-
222
- object.send("#{name}=", value)
223
- end
224
- object
225
- end
226
-
227
- def call_api(method, elems = [])
228
- doc = REXML::Document.new '<?xml version="1.0" encoding="UTF-8"?>'
229
- request = doc.add_element 'request'
230
- request.attributes['method'] = method
134
+ def actions(*args)
135
+ args.each do |action|
136
+ method = action.to_s
137
+ api_method = method.camelize(:lower)
231
138
 
232
- elems.each do |key, value|
233
- if value.is_a?(Base)
234
- elem = value.to_xml
235
- request.add_element(elem)
139
+ case method
140
+ when 'list'
141
+ define_class_method(method) do |*args|
142
+ api_list_action(api_method, *args)
143
+ end
144
+ when 'get'
145
+ define_class_method(method) do |id|
146
+ api_get_action(api_method, id)
147
+ end
148
+ when 'create'
149
+ define_method(method) do
150
+ api_create_action(api_method)
151
+ end
152
+ when 'update'
153
+ define_method(method) do
154
+ api_update_action(api_method)
155
+ end
156
+ when 'delete'
157
+ define_class_method(method) do |id|
158
+ api_delete_action(api_method, id)
159
+ end
160
+ define_method(method) do
161
+ self.class.api_delete_action(api_method, self.send("#{node_name}_id"))
162
+ end
236
163
  else
237
- request.add_element(REXML::Element.new(key)).text = value.to_s
164
+ define_class_method(method) do |id|
165
+ api_action(api_method, id)
166
+ end
167
+ define_method(method) do
168
+ self.class.api_action(api_method, self.send("#{node_name}_id"))
169
+ end
238
170
  end
239
171
  end
240
-
241
- result = self.post(request.to_s)
242
172
 
243
- @@response = Response.new(result)
244
-
245
- #
246
- # Failure
247
- #
248
- if @@response.fail?
249
- error_msg = @@response.error_msg
250
-
251
- raise InternalError.new, error_msg if error_msg =~ /not formatted correctly/
252
- raise AuthenticationError.new, error_msg if error_msg =~ /[Aa]uthentication failed/
253
- raise UnknownSystemError.new, error_msg if error_msg =~ /does not exist/
254
- raise InvalidParameterError.new, error_msg if error_msg =~ /Invalid parameter: (.*)/
255
-
256
- # Raise an exception for unexpected errors
257
- raise error_msg
173
+ def api_list_action(method, options = {})
174
+ resp = Base.connection.call_api("#{node_name}.#{method}", options)
175
+ resp.success? ? ListProxy.new_from_xml(self, resp) : nil
258
176
  end
259
177
 
260
- @@response
261
- end
262
-
263
- def response
264
- @@response
265
- end
266
-
267
- def post(body)
268
- connection = Net::HTTP.new(@@account_url, 443)
269
- connection.use_ssl = true
270
- connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
271
-
272
- request = Net::HTTP::Post.new(FreshBooks::SERVICE_URL)
273
- request.basic_auth @@auth_token, 'X'
274
- request.body = body
275
- request.content_type = 'application/xml'
276
- @@request_headers.each_pair do |name, value|
277
- request[name.to_s] = value
178
+ def api_get_action(method, id)
179
+ resp = Base.connection.call_api("#{node_name}.#{method}", "#{node_name}_id" => id)
180
+ resp.success? ? self.new_from_xml(resp.elements[1]) : nil
278
181
  end
279
182
 
280
- result = connection.start { |http| http.request(request) }
183
+ def api_delete_action(method, id)
184
+ resp = Base.connection.call_api("#{node_name}.#{method}", "#{node_name}_id" => id)
185
+ resp.success?
186
+ end
281
187
 
282
- result.body
188
+ def api_action(method, id)
189
+ resp = Base.connection.call_api("#{node_name}.#{method}", "#{node_name}_id" => id)
190
+ resp.success?
191
+ end
283
192
  end
284
193
  end
194
+
195
+ protected
196
+
197
+ def node_name
198
+ self.class.node_name
199
+ end
200
+
201
+ def api_create_action(method)
202
+ resp = Base.connection.call_api("#{node_name}.#{method}", node_name => self)
203
+ self.send("#{node_name}_id=", resp.elements[1].text.to_i) if resp.success?
204
+ resp.success?
205
+ end
206
+
207
+ def api_update_action(method)
208
+ resp = Base.connection.call_api("#{node_name}.#{method}", node_name => self)
209
+ resp.success?
210
+ end
285
211
  end
286
- end
212
+ end
@@ -2,10 +2,10 @@ module FreshBooks
2
2
  class Category < Base
3
3
  attribute :category_id, :integer
4
4
  attribute :name, :string
5
- attribute :tax1, :integer
6
- attribute :tax2, :integer
5
+ attribute :tax1, :float
6
+ attribute :tax2, :float
7
7
 
8
8
  has_many :expenses
9
- method :list, :get, :create, :update, :delete
9
+ actions :list, :get, :create, :update, :delete
10
10
  end
11
11
  end
@@ -24,9 +24,9 @@ module FreshBooks
24
24
  attribute :s_state, :string
25
25
  attribute :s_country, :string
26
26
  attribute :s_code, :string
27
- attribute :url, :string, :read_only => true
27
+ attribute :links, :object, :read_only => true
28
28
 
29
29
  has_many :expenses, :estimates, :invoices, :payments, :projects, :recurrings
30
- method :list, :get, :create, :update, :delete
30
+ actions :list, :get, :create, :update, :delete
31
31
  end
32
32
  end
@@ -1,30 +1,25 @@
1
1
  module FreshBooks
2
2
  class Estimate < Base
3
- attribute :estimate_id, :integer
4
- attribute :client_id, :integer
5
- attribute :status, :string
6
- attribute :date, :string
7
- attribute :po_number, :integer
8
- attribute :discount, :float
9
- attribute :notes, :string
10
- attribute :terms, :string
11
- attribute :first_name, :string
12
- attribute :last_name, :string
13
- attribute :organization, :string
14
- attribute :p_street1, :string
15
- attribute :p_street2, :string
16
- attribute :p_city, :string
17
- attribute :p_state, :string
18
- attribute :p_country, :string
19
- attribute :p_code, :string
20
- attribute :lines, :array
3
+ attribute :estimate_id, :integer
4
+ attribute :client_id, :integer
5
+ attribute :status, :string
6
+ attribute :date, :date
7
+ attribute :po_number, :integer
8
+ attribute :discount, :float
9
+ attribute :notes, :string
10
+ attribute :terms, :string
11
+ attribute :first_name, :string
12
+ attribute :last_name, :string
13
+ attribute :organization, :string
14
+ attribute :p_street1, :string
15
+ attribute :p_street2, :string
16
+ attribute :p_city, :string
17
+ attribute :p_state, :string
18
+ attribute :p_country, :string
19
+ attribute :p_code, :string
20
+ attribute :lines, :array
21
21
 
22
22
  belongs_to :client
23
- method :list, :get, :create, :update, :delete, :send_by_email
24
-
25
- def initialize(data = {})
26
- super
27
- self.lines ||= []
28
- end
23
+ actions :list, :get, :create, :update, :delete, :send_by_email
29
24
  end
30
25
  end
@@ -6,11 +6,11 @@ module FreshBooks
6
6
  attribute :project_id, :integer
7
7
  attribute :client_id, :integer
8
8
  attribute :amount, :float
9
- attribute :date, :string
9
+ attribute :date, :date
10
10
  attribute :notes, :string
11
11
  attribute :status, :string
12
12
 
13
13
  belongs_to :staff, :category, :project, :client
14
- method :list, :get, :create, :update, :delete, :send_by_email
14
+ actions :list, :get, :create, :update, :delete, :send_by_email
15
15
  end
16
16
  end
@@ -3,7 +3,7 @@ module FreshBooks
3
3
  attribute :invoice_id, :integer
4
4
  attribute :client_id, :integer
5
5
  attribute :number, :string
6
- attribute :date, :string
6
+ attribute :date, :date
7
7
  attribute :po_number, :integer
8
8
  attribute :terms, :string
9
9
  attribute :first_name, :string
@@ -24,11 +24,6 @@ module FreshBooks
24
24
 
25
25
  belongs_to :client
26
26
  has_many :payments
27
- method :list, :get, :create, :update, :delete, :send_by_email, :send_by_snail_mail
28
-
29
- def initialize(data = {})
30
- super
31
- self.lines ||= []
32
- end
27
+ actions :list, :get, :create, :update, :delete, :send_by_email, :send_by_snail_mail
33
28
  end
34
29
  end
@@ -7,6 +7,6 @@ module FreshBooks
7
7
  attribute :quantity, :integer
8
8
  attribute :inventory, :integer
9
9
 
10
- method :list, :get, :create, :update, :delete
10
+ actions :list, :get, :create, :update, :delete
11
11
  end
12
12
  end
@@ -8,6 +8,6 @@ module FreshBooks
8
8
  attribute :tax2_name, :string
9
9
  attribute :tax1_percent, :float
10
10
  attribute :tax2_percent, :float
11
- attribute :amount, :float
11
+ attribute :amount, :float, :read_only => true
12
12
  end
13
13
  end
@@ -11,12 +11,12 @@ module FreshBooks
11
11
  attribute :payment_id, :integer
12
12
  attribute :client_id, :integer
13
13
  attribute :invoice_id, :integer
14
- attribute :date, :string
14
+ attribute :date, :date
15
15
  attribute :amount, :float
16
16
  attribute :type, :string
17
17
  attribute :notes, :string
18
18
 
19
19
  belongs_to :client, :invoice
20
- method :list, :get, :create, :update
20
+ actions :list, :get, :create, :update
21
21
  end
22
22
  end
@@ -15,16 +15,11 @@ module FreshBooks
15
15
  attribute :bill_method, :string
16
16
  attribute :rate, :float
17
17
  attribute :description, :string
18
- attribute :tasks, :array
18
+ attribute :tasks, :array, :to_xml => :tasks_to_xml
19
19
 
20
20
  belongs_to :client
21
21
  has_many :expenses
22
- method :list, :get, :create, :update, :delete
23
-
24
- def initialize(data = {})
25
- super
26
- self.tasks ||= []
27
- end
22
+ actions :list, :get, :create, :update, :delete
28
23
 
29
24
  protected
30
25
 
@@ -18,7 +18,7 @@ module FreshBooks
18
18
  class Recurring < Base
19
19
  attribute :recurring_id, :integer
20
20
  attribute :client_id, :integer
21
- attribute :date, :string
21
+ attribute :date, :date
22
22
  attribute :po_number, :integer
23
23
  attribute :terms, :string
24
24
  attribute :first_name, :string
@@ -37,15 +37,11 @@ module FreshBooks
37
37
  attribute :notes, :string
38
38
  attribute :occurrences, :integer
39
39
  attribute :frequency, :string
40
- attribute :send_email, :integer
41
- attribute :send_snail_mail, :integer
40
+ attribute :stopped, :boolean
41
+ attribute :send_email, :boolean
42
+ attribute :send_snail_mail, :boolean
42
43
 
43
44
  belongs_to :client
44
- method :list, :get, :create, :update, :delete
45
-
46
- def initialize(data = {})
47
- super
48
- self.lines ||= []
49
- end
45
+ actions :list, :get, :create, :update, :delete
50
46
  end
51
47
  end
@@ -7,10 +7,10 @@ module FreshBooks
7
7
  attribute :email, :string
8
8
  attribute :business_phone, :string
9
9
  attribute :mobile_phone, :string
10
- attribute :rate, :string
11
- attribute :last_login, :string
12
- attribute :number_of_logins,:string
13
- attribute :signup_date, :string
10
+ attribute :rate, :float
11
+ attribute :last_login, :date_time
12
+ attribute :number_of_logins,:integer
13
+ attribute :signup_date, :date_time
14
14
  attribute :street1, :string
15
15
  attribute :street2, :string
16
16
  attribute :city, :string
@@ -19,6 +19,6 @@ module FreshBooks
19
19
  attribute :code, :string
20
20
 
21
21
  has_many :expenses
22
- method :list, :get
22
+ actions :list, :get
23
23
  end
24
24
  end
@@ -2,10 +2,10 @@ module FreshBooks
2
2
  class Task < Base
3
3
  attribute :task_id, :integer
4
4
  attribute :name, :string
5
- attribute :billable, :string
5
+ attribute :billable, :boolean
6
6
  attribute :rate, :float
7
7
  attribute :description, :string
8
8
 
9
- method :list, :get, :create, :update, :delete
9
+ actions :list, :get, :create, :update, :delete
10
10
  end
11
11
  end
@@ -5,9 +5,9 @@ module FreshBooks
5
5
  attribute :task_id, :integer
6
6
  attribute :hours, :float
7
7
  attribute :notes, :string
8
- attribute :date, :string
8
+ attribute :date, :date
9
9
 
10
10
  belongs_to :project, :task
11
- method :list, :get, :create, :update, :delete
11
+ actions :list, :get, :create, :update, :delete
12
12
  end
13
13
  end
@@ -1,5 +1,5 @@
1
1
  module FreshBooks
2
- VERSION = '3.0.1' # Gem version
2
+ VERSION = '3.0.2' # Gem version
3
3
  API_VERSION = '2.1' # FreshBooks API version
4
4
 
5
5
  SERVICE_URL = "/api/#{API_VERSION}/xml-in"
@@ -18,7 +18,7 @@ describe FreshBooks::Base do
18
18
 
19
19
  class Test < FreshBooks::Base
20
20
  attribute :test_id, :integer
21
- method :list, :get, :create, :update, :delete, :send_by_email, :send_by_snail_mail
21
+ actions :list, :get, :create, :update, :delete, :send_by_email, :send_by_snail_mail
22
22
  end
23
23
 
24
24
  class TestWithoutMethods < FreshBooks::Base
@@ -116,7 +116,7 @@ describe FreshBooks::Base do
116
116
  it "should not include unchanged attributes in xml" do
117
117
  @xml.to_s.should_not =~ Regexp.new(Regexp.escape('<amount>'))
118
118
  end
119
-
119
+
120
120
  it "should return correct xml and initialize correctly from xml" do
121
121
  first = First.new_from_xml(@xml)
122
122
  first.first_id.should == 1
@@ -136,11 +136,13 @@ describe FreshBooks::Base do
136
136
  @elem = mock('XmlObj', :text => '123')
137
137
  @resp = mock('XmlResp', :elements => [nil, @elem])
138
138
  @resp.stub!(:success?).and_return(true)
139
- FreshBooks::Base.stub!(:call_api).and_return(@resp)
139
+ @connection = mock('Connection')
140
+ FreshBooks::Base.stub!(:connection).and_return(@connection)
141
+ @connection.stub!(:call_api).and_return(@resp)
140
142
  end
141
143
 
142
144
  it "should call api method" do
143
- FreshBooks::Base.should_receive(:call_api).with('test.create', 'test' => @object).and_return(@resp)
145
+ @connection.should_receive(:call_api).with('test.create', 'test' => @object).and_return(@resp)
144
146
  @object.create
145
147
  end
146
148
 
@@ -156,12 +158,12 @@ describe FreshBooks::Base do
156
158
  end
157
159
 
158
160
  it "should return id if call succeeded" do
159
- @object.create.should == 123
161
+ @object.create.should be_true
160
162
  end
161
163
 
162
164
  it "should return nil if call failed" do
163
165
  @resp.stub!(:success?).and_return(false)
164
- @object.create.should be_nil
166
+ @object.create.should be_false
165
167
  end
166
168
  end
167
169
 
@@ -169,11 +171,13 @@ describe FreshBooks::Base do
169
171
  before(:each) do
170
172
  @resp = mock('XmlResp')
171
173
  @resp.stub!(:success?).and_return(true)
172
- FreshBooks::Base.stub!(:call_api).and_return(@resp)
174
+ @connection = mock('Connection')
175
+ FreshBooks::Base.stub!(:connection).and_return(@connection)
176
+ @connection.stub!(:call_api).and_return(@resp)
173
177
  end
174
178
 
175
179
  it "should call api method" do
176
- FreshBooks::Base.should_receive(:call_api).with('test.update', 'test' => @object).and_return(@resp)
180
+ @connection.should_receive(:call_api).with('test.update', 'test' => @object).and_return(@resp)
177
181
  @object.update
178
182
  end
179
183
 
@@ -193,11 +197,13 @@ describe FreshBooks::Base do
193
197
  @object.test_id = 1
194
198
  @resp = mock('XmlResp')
195
199
  @resp.stub!(:success?).and_return(true)
196
- FreshBooks::Base.stub!(:call_api).and_return(@resp)
200
+ @connection = mock('Connection')
201
+ FreshBooks::Base.stub!(:connection).and_return(@connection)
202
+ @connection.stub!(:call_api).and_return(@resp)
197
203
  end
198
204
 
199
205
  it "should call api method" do
200
- FreshBooks::Base.should_receive(:call_api).with('test.delete', 'test_id' => 1).and_return(@resp)
206
+ @connection.should_receive(:call_api).with('test.delete', 'test_id' => 1).and_return(@resp)
201
207
  @object.delete
202
208
  end
203
209
 
@@ -216,11 +222,13 @@ describe FreshBooks::Base do
216
222
  before(:each) do
217
223
  @resp = mock('XmlResp')
218
224
  @resp.stub!(:success?).and_return(true)
219
- FreshBooks::Base.stub!(:call_api).and_return(@resp)
225
+ @connection = mock('Connection')
226
+ FreshBooks::Base.stub!(:connection).and_return(@connection)
227
+ @connection.stub!(:call_api).and_return(@resp)
220
228
  end
221
229
 
222
230
  it "should call api method" do
223
- FreshBooks::Base.should_receive(:call_api).with('test.delete', 'test_id' => 1).and_return(@resp)
231
+ @connection.should_receive(:call_api).with('test.delete', 'test_id' => 1).and_return(@resp)
224
232
  Test.delete(1)
225
233
  end
226
234
 
@@ -239,12 +247,14 @@ describe FreshBooks::Base do
239
247
  before(:each) do
240
248
  @resp = mock('XmlResp', :elements => [])
241
249
  @resp.stub!(:success?).and_return(true)
242
- FreshBooks::Base.stub!(:call_api).and_return(@resp)
250
+ @connection = mock('Connection')
251
+ FreshBooks::Base.stub!(:connection).and_return(@connection)
252
+ @connection.stub!(:call_api).and_return(@resp)
243
253
  Test.stub!(:new_from_xml).and_return(true)
244
254
  end
245
255
 
246
256
  it "should call api method" do
247
- FreshBooks::Base.should_receive(:call_api).with('test.get', 'test_id' => 1).and_return(@resp)
257
+ @connection.should_receive(:call_api).with('test.get', 'test_id' => 1).and_return(@resp)
248
258
  Test.get(1)
249
259
  end
250
260
 
@@ -264,15 +274,25 @@ describe FreshBooks::Base do
264
274
  before(:each) do
265
275
  @elem1 = mock('XmlElement')
266
276
  @elem2 = mock('XmlElement')
267
- @elems = mock('XmlElements', :elements => [@elem1, @elem2])
277
+ @elems = mock('XmlElements',
278
+ :elements => [@elem1, @elem2],
279
+ :attributes => {
280
+ 'page' => 1,
281
+ 'pages' => 10,
282
+ 'per_page' => 30,
283
+ 'total' => 300
284
+ }
285
+ )
268
286
  @resp = mock('XmlResp', :elements => [nil, @elems])
269
287
  @resp.stub!(:success?).and_return(true)
270
- FreshBooks::Base.stub!(:call_api).and_return(@resp)
288
+ @connection = mock('Connection')
289
+ FreshBooks::Base.stub!(:connection).and_return(@connection)
290
+ @connection.stub!(:call_api).and_return(@resp)
271
291
  Test.stub!(:new_from_xml).and_return(true)
272
292
  end
273
293
 
274
294
  it "should call api method" do
275
- FreshBooks::Base.should_receive(:call_api).with('test.list', :name => 'value').and_return(@resp)
295
+ @connection.should_receive(:call_api).with('test.list', :name => 'value').and_return(@resp)
276
296
  Test.list(:name => 'value')
277
297
  end
278
298
 
@@ -280,12 +300,17 @@ describe FreshBooks::Base do
280
300
  @resp.stub!(:success?).and_return(false)
281
301
  Test.list.should be_nil
282
302
  end
303
+
304
+ it "should create a list proxy if request succeeded" do
305
+ @resp.stub!(:success?).and_return(true)
306
+ Test.list.should be_a(FreshBooks::ListProxy)
307
+ end
283
308
 
284
309
  it "should build instances from response records if request succeeded" do
285
310
  @resp.stub!(:success?).and_return(true)
286
311
  Test.should_receive(:new_from_xml).with(@elem1).and_return(1)
287
312
  Test.should_receive(:new_from_xml).with(@elem2).and_return(2)
288
- Test.list.should == [1, 2]
313
+ Test.list.to_a.should == [1, 2]
289
314
  end
290
315
  end
291
316
 
@@ -294,11 +319,13 @@ describe FreshBooks::Base do
294
319
  @object.test_id = 1
295
320
  @resp = mock('XmlResp')
296
321
  @resp.stub!(:success?).and_return(true)
297
- FreshBooks::Base.stub!(:call_api).and_return(@resp)
322
+ @connection = mock('Connection')
323
+ FreshBooks::Base.stub!(:connection).and_return(@connection)
324
+ @connection.stub!(:call_api).and_return(@resp)
298
325
  end
299
326
 
300
327
  it "should call api method" do
301
- FreshBooks::Base.should_receive(:call_api).with('test.sendByEmail', 'test_id' => 1).and_return(@resp)
328
+ @connection.should_receive(:call_api).with('test.sendByEmail', 'test_id' => 1).and_return(@resp)
302
329
  @object.send_by_email
303
330
  end
304
331
 
@@ -317,11 +344,13 @@ describe FreshBooks::Base do
317
344
  before(:each) do
318
345
  @resp = mock('XmlResp')
319
346
  @resp.stub!(:success?).and_return(true)
320
- FreshBooks::Base.stub!(:call_api).and_return(@resp)
347
+ @connection = mock('Connection')
348
+ FreshBooks::Base.stub!(:connection).and_return(@connection)
349
+ @connection.stub!(:call_api).and_return(@resp)
321
350
  end
322
351
 
323
352
  it "should call api method" do
324
- FreshBooks::Base.should_receive(:call_api).with('test.sendByEmail', 'test_id' => 1).and_return(@resp)
353
+ @connection.should_receive(:call_api).with('test.sendByEmail', 'test_id' => 1).and_return(@resp)
325
354
  Test.send_by_email(1)
326
355
  end
327
356
 
@@ -341,11 +370,13 @@ describe FreshBooks::Base do
341
370
  @object.test_id = 1
342
371
  @resp = mock('XmlResp')
343
372
  @resp.stub!(:success?).and_return(true)
344
- FreshBooks::Base.stub!(:call_api).and_return(@resp)
373
+ @connection = mock('Connection')
374
+ FreshBooks::Base.stub!(:connection).and_return(@connection)
375
+ @connection.stub!(:call_api).and_return(@resp)
345
376
  end
346
377
 
347
378
  it "should call api method" do
348
- FreshBooks::Base.should_receive(:call_api).with('test.sendBySnailMail', 'test_id' => 1).and_return(@resp)
379
+ @connection.should_receive(:call_api).with('test.sendBySnailMail', 'test_id' => 1).and_return(@resp)
349
380
  @object.send_by_snail_mail
350
381
  end
351
382
 
@@ -364,11 +395,13 @@ describe FreshBooks::Base do
364
395
  before(:each) do
365
396
  @resp = mock('XmlResp')
366
397
  @resp.stub!(:success?).and_return(true)
367
- FreshBooks::Base.stub!(:call_api).and_return(@resp)
398
+ @connection = mock('Connection')
399
+ FreshBooks::Base.stub!(:connection).and_return(@connection)
400
+ @connection.stub!(:call_api).and_return(@resp)
368
401
  end
369
402
 
370
403
  it "should call api method" do
371
- FreshBooks::Base.should_receive(:call_api).with('test.sendBySnailMail', 'test_id' => 1).and_return(@resp)
404
+ @connection.should_receive(:call_api).with('test.sendBySnailMail', 'test_id' => 1).and_return(@resp)
372
405
  Test.send_by_snail_mail(1)
373
406
  end
374
407
 
@@ -74,8 +74,8 @@ describe FreshBooks::TimeEntry do
74
74
 
75
75
  # it "should update an existing time_entry" do
76
76
  # time_entries = FreshBooks::TimeEntry.list
77
- # @time_entry.hours = 2
78
- # @time_entry.update rescue nil
77
+ # time_entry = FreshBooks::TimeEntry.new(:time_entry_id => @time_entry.time_entry_id, :hours => 2)
78
+ # time_entry.update.should be_true
79
79
  # FreshBooks::TimeEntry.get(@time_entry.time_entry_id).hours.should == 2
80
80
  # FreshBooks::TimeEntry.list.size.should == time_entries.size
81
81
  # end
data/spec/spec_helper.rb CHANGED
@@ -8,4 +8,4 @@ end
8
8
 
9
9
  require File.dirname(__FILE__) + '/../lib/freshbooks.rb'
10
10
 
11
- FreshBooks::Base.setup('flatsourcingtest.freshbooks.com', 'dd4d8a3c9a8541161e6409df207fad84')
11
+ FreshBooks::Base.establish_connection!('flatsourcingtest.freshbooks.com', 'a2e32a3dcb2444c2f0fc47a5ae7227d2')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turingstudio-freshbooks-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Turing Studio, Inc.
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-03 00:00:00 -08:00
12
+ date: 2009-03-04 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -81,9 +81,8 @@ files:
81
81
  has_rdoc: true
82
82
  homepage: http://github.com/turingstudio/freshbooks-rb/
83
83
  post_install_message:
84
- rdoc_options:
85
- - --main
86
- - README.rdoc
84
+ rdoc_options: []
85
+
87
86
  require_paths:
88
87
  - lib
89
88
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -100,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
99
  version:
101
100
  requirements: []
102
101
 
103
- rubyforge_project: freshbooks-rb
102
+ rubyforge_project:
104
103
  rubygems_version: 1.2.0
105
104
  signing_key:
106
105
  specification_version: 2