turingstudio-freshbooks-rb 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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