activesalesforce 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. data/lib/asf_adapter.rb +41 -46
  2. data/lib/result_array.rb +34 -0
  3. data/lib/rforce.rb +90 -79
  4. data/test/unit/basic_test.rb +40 -4
  5. data/test/unit/profiler_results.txt +1072 -0
  6. data/test/unit/profiler_results_live.txt +1347 -0
  7. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_add_notes_to_contact.recording +1050 -1017
  8. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_assignment_rule_id.recording +1078 -0
  9. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_batch_insert.recording +674 -644
  10. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_count_contacts.recording +770 -708
  11. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_create_a_contact.recording +731 -706
  12. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_find_a_contact.recording +741 -716
  13. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_find_a_contact_by_first_name.recording +1026 -764
  14. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_find_a_contact_by_id.recording +791 -764
  15. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_find_addresses.recording +1297 -0
  16. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_get_created_by_from_contact.recording +2325 -2280
  17. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_master_detail.recording +1315 -1302
  18. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_read_all_content_columns.recording +691 -666
  19. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_save_a_contact.recording +741 -716
  20. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_use_default_rule.recording +1078 -0
  21. data/test/unit/recorded_results/AsfUnitTestsBasicTest.test_use_update_mru.recording +1078 -0
  22. data/test/unit/recorded_test_case.rb +1 -4
  23. data/test/unit/test.html +157 -0
  24. data/test/unit/test.html~ +183 -0
  25. metadata +26 -18
  26. data/test/unit/recorded_results/AsfUnitTestsAsfScaffoldGeneratorTest.test_describe_layout.recording +0 -1789
data/lib/asf_adapter.rb CHANGED
@@ -30,15 +30,7 @@ require File.dirname(__FILE__) + '/asf_active_record'
30
30
  require File.dirname(__FILE__) + '/id_resolver'
31
31
  require File.dirname(__FILE__) + '/sid_authentication_filter'
32
32
  require File.dirname(__FILE__) + '/recording_binding'
33
-
34
-
35
- class ResultArray < Array
36
- attr_reader :actual_size
37
-
38
- def initialize(actual_size)
39
- @actual_size = actual_size
40
- end
41
- end
33
+ require File.dirname(__FILE__) + '/result_array'
42
34
 
43
35
 
44
36
  module ActiveRecord
@@ -262,11 +254,9 @@ module ActiveRecord
262
254
  end
263
255
 
264
256
  raw_table_name = sql.match(/FROM (\w+)/i)[1]
265
- table_name = raw_table_name.singularize
266
- entity_name = entity_name_from_table(table_name)
267
- entity_def = get_entity_def(entity_name)
257
+ table_name, columns, entity_def = lookup(raw_table_name)
268
258
 
269
- column_names = api_column_names(table_name)
259
+ column_names = columns.map { |column| column.api_name }
270
260
 
271
261
  # Always (unless COUNT*)'ing) select all columns (required for the AR attributes mechanism to work correctly
272
262
  soql = sql.sub(/SELECT .+ FROM/i, "SELECT #{column_names.join(', ')} FROM") unless selectCountMatch
@@ -274,13 +264,13 @@ module ActiveRecord
274
264
  soql.sub!(/\s+FROM\s+\w+/i, " FROM #{entity_def.api_name}")
275
265
 
276
266
  # Look for a LIMIT clause
277
- soql.sub!(/LIMIT\s+1/i, "")
267
+ limit = extract_sql_modifier(soql, "LIMIT")
278
268
 
279
269
  # Look for an OFFSET clause
280
- soql.sub!(/\d+\s+OFFSET\s+\d+/i, "")
270
+ offset = extract_sql_modifier(soql, "OFFSET")
281
271
 
282
272
  # Fixup column references to use api names
283
- columns = columns_map(table_name)
273
+ columns = entity_def.column_name_to_column
284
274
  soql.gsub!(/((?:\w+\.)?\w+)(?=\s*(?:=|!=|<|>|<=|>=)\s*(?:'[^']*'|NULL|TRUE|FALSE))/mi) do |column_name|
285
275
  # strip away any table alias
286
276
  column_name.sub!(/\w+\./, '')
@@ -295,12 +285,14 @@ module ActiveRecord
295
285
  soql.sub!(/#{raw_table_name}\./i, "#{entity_def.api_name}.")
296
286
 
297
287
  @connection.batch_size = @batch_size if @batch_size
288
+ @connection.batch_size = limit if limit
289
+
298
290
  @batch_size = nil
299
291
 
300
292
  queryResult = get_result(@connection.query(:queryString => soql), :query)
301
293
  records = queryResult[:records]
302
294
 
303
- result = ResultArray.new(queryResult[:size].to_i)
295
+ result = ActiveSalesforce::ResultArray.new(queryResult[:size].to_i)
304
296
  return result unless records
305
297
 
306
298
  records = [ records ] unless records.is_a?(Array)
@@ -324,7 +316,10 @@ module ActiveRecord
324
316
  end
325
317
  end
326
318
 
327
- result << row
319
+ result << row
320
+
321
+ # Insure that only LIMIT rows are returned
322
+ break if limit and result.length >= limit
328
323
  end
329
324
 
330
325
  if selectCountMatch
@@ -348,9 +343,8 @@ module ActiveRecord
348
343
  def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
349
344
  log(sql, name) {
350
345
  # Convert sql to sobject
351
- table_name = sql.match(/INSERT\s+INTO\s+(\w+)\s+/i)[1].singularize
352
- entity_name = entity_name_from_table(table_name)
353
- columns = columns_map(table_name)
346
+ table_name, columns, entity_def = lookup(sql.match(/INSERT\s+INTO\s+(\w+)\s+/i)[1])
347
+ columns = entity_def.column_name_to_column
354
348
 
355
349
  # Extract array of column names
356
350
  names = sql.match(/\((.+)\)\s+VALUES/i)[1].scan(/\w+/i)
@@ -363,7 +357,7 @@ module ActiveRecord
363
357
 
364
358
  fields = get_fields(columns, names, values, :createable)
365
359
 
366
- sobject = create_sobject(entity_name, nil, fields)
360
+ sobject = create_sobject(entity_def.api_name, nil, fields)
367
361
 
368
362
  # Track the id to be able to update it when the create() is actually executed
369
363
  id = String.new
@@ -377,9 +371,8 @@ module ActiveRecord
377
371
  def update(sql, name = nil) #:nodoc:
378
372
  log(sql, name) {
379
373
  # Convert sql to sobject
380
- table_name = sql.match(/UPDATE\s+(\w+)\s+/i)[1].singularize
381
- entity_name = entity_name_from_table(table_name)
382
- columns = columns_map(table_name)
374
+ table_name, columns, entity_def = lookup(sql.match(/UPDATE\s+(\w+)\s+/i)[1])
375
+ columns = entity_def.column_name_to_column
383
376
 
384
377
  match = sql.match(/SET\s+(.+)\s+WHERE/mi)[1]
385
378
  names = match.scan(/(\w+)\s*=\s*('|NULL|TRUE|FALSE)/i)
@@ -392,7 +385,7 @@ module ActiveRecord
392
385
 
393
386
  id = sql.match(/WHERE\s+id\s*=\s*'(\w+)'/i)[1]
394
387
 
395
- sobject = create_sobject(entity_name, id, fields)
388
+ sobject = create_sobject(entity_def.api_name, id, fields)
396
389
 
397
390
  @command_boxcar << ActiveSalesforce::BoxcarCommand::Update.new(self, sobject)
398
391
  }
@@ -468,6 +461,17 @@ module ActiveRecord
468
461
  end
469
462
 
470
463
 
464
+ def extract_sql_modifier(soql, modifier)
465
+ value = soql.match(/\s+#{modifier}\s+(\d+)/i)
466
+ if value
467
+ value = value[1].to_i
468
+ soql.sub!(/\s+#{modifier}\s+\d+/i, "")
469
+ end
470
+
471
+ value
472
+ end
473
+
474
+
471
475
  def get_result(response, method)
472
476
  responseName = (method.to_s + "Response").to_sym
473
477
  finalResponse = response[responseName]
@@ -538,7 +542,7 @@ module ActiveRecord
538
542
  key_prefix = metadata[:keyPrefix]
539
543
 
540
544
  entity_def = ActiveSalesforce::EntityDefinition.new(self, entity_name,
541
- cached_columns, cached_relationships, custom, key_prefix)
545
+ cached_columns, cached_relationships, custom, key_prefix)
542
546
 
543
547
  @entity_def_map[entity_name] = entity_def
544
548
  @keyprefix_to_entity_def_map[key_prefix] = entity_def
@@ -613,19 +617,8 @@ module ActiveRecord
613
617
 
614
618
 
615
619
  def columns(table_name, name = nil)
616
- entity_name = entity_name_from_table(table_name)
617
- get_entity_def(entity_name).columns
618
- end
619
-
620
-
621
- def columns_map(table_name, name = nil)
622
- entity_name = entity_name_from_table(table_name)
623
- get_entity_def(entity_name).column_name_to_column
624
- end
625
-
626
-
627
- def entity_name_from_table(table_name)
628
- return table_name.singularize.camelize
620
+ table_name, columns, entity_def = lookup(table_name)
621
+ entity_def.columns
629
622
  end
630
623
 
631
624
 
@@ -640,11 +633,9 @@ module ActiveRecord
640
633
 
641
634
 
642
635
  def create_sobject(entity_name, id, fields)
643
- entity_def = get_entity_def(entity_name)
644
-
645
636
  sobj = []
646
637
 
647
- sobj << 'type { :xmlns => "urn:sobject.partner.soap.sforce.com" }' << entity_def.api_name
638
+ sobj << 'type { :xmlns => "urn:sobject.partner.soap.sforce.com" }' << entity_name
648
639
  sobj << 'Id { :xmlns => "urn:sobject.partner.soap.sforce.com" }' << id if id
649
640
 
650
641
  # now add any changed fields
@@ -660,10 +651,14 @@ module ActiveRecord
660
651
  def column_names(table_name)
661
652
  columns(table_name).map { |column| column.name }
662
653
  end
654
+
663
655
 
664
-
665
- def api_column_names(table_name)
666
- columns(table_name).map { |column| column.api_name }
656
+ def lookup(raw_table_name)
657
+ table_name = raw_table_name.singularize
658
+ entity_def = get_entity_def(table_name.camelize)
659
+ columns = entity_def.columns
660
+
661
+ [table_name, columns, entity_def]
667
662
  end
668
663
 
669
664
  end
@@ -0,0 +1,34 @@
1
+ =begin
2
+ ActiveSalesforce
3
+ Copyright 2006 Doug Chasman
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ =end
17
+
18
+ require 'rubygems'
19
+ require_gem 'rails', ">= 1.0.0"
20
+
21
+ require 'pp'
22
+
23
+
24
+ module ActiveSalesforce
25
+
26
+ class ResultArray < Array
27
+ attr_reader :actual_size
28
+
29
+ def initialize(actual_size)
30
+ @actual_size = actual_size
31
+ end
32
+ end
33
+
34
+ end
data/lib/rforce.rb CHANGED
@@ -1,24 +1,24 @@
1
1
  =begin
2
- RForce v0.1
3
- Copyright (c) 2005 Ian Dees
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
2
+ RForce v0.1
3
+ Copyright (c) 2005 Ian Dees
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
22
  =end
23
23
 
24
24
  # RForce is a simple Ruby binding to the SalesForce CRM system.
@@ -59,7 +59,7 @@ require_gem 'builder'
59
59
 
60
60
 
61
61
  module RForce
62
-
62
+
63
63
  #Allows indexing hashes like method calls: hash.key
64
64
  #to supplement the traditional way of indexing: hash[key]
65
65
  module FlashHash
@@ -67,50 +67,50 @@ module RForce
67
67
  self[method]
68
68
  end
69
69
  end
70
-
70
+
71
71
  #Turns an XML response from the server into a Ruby
72
72
  #object whose methods correspond to nested XML elements.
73
73
  class SoapResponse
74
74
  include FlashHash
75
-
75
+
76
76
  #Parses an XML string into structured data.
77
77
  def initialize(content)
78
78
  document = REXML::Document.new content
79
79
  node = REXML::XPath.first document, '//soapenv:Body'
80
80
  @parsed = SoapResponse.parse node
81
81
  end
82
-
82
+
83
83
  #Allows this object to act like a hash (and therefore
84
84
  #as a FlashHash via the include above).
85
85
  def [](symbol)
86
86
  @parsed[symbol]
87
87
  end
88
-
88
+
89
89
  #Digests an XML DOM node into nested Ruby types.
90
90
  def SoapResponse.parse(node)
91
91
  #Convert text nodes into simple strings.
92
92
  return node.text unless node.has_elements?
93
-
93
+
94
94
  #Convert nodes with children into FlashHashes.
95
95
  elements = {}
96
96
  class << elements
97
97
  include FlashHash
98
98
  end
99
-
99
+
100
100
  #Add all the element's children to the hash.
101
101
  node.each_element do |e|
102
102
  name = e.name.to_sym
103
-
103
+
104
104
  case elements[name]
105
105
  #The most common case: unique child element tags.
106
106
  when NilClass: elements[name] = parse(e)
107
-
107
+
108
108
  #Non-unique child elements become arrays:
109
-
109
+
110
110
  #We've already created the array: just
111
111
  #add the element.
112
112
  when Array: elements[name] << parse(e)
113
-
113
+
114
114
  #We haven't created the array yet: do so,
115
115
  #then put the existing element in, followed
116
116
  #by the new one.
@@ -119,17 +119,17 @@ module RForce
119
119
  elements[name] << parse(e)
120
120
  end
121
121
  end
122
-
122
+
123
123
  return elements
124
124
  end
125
125
  end
126
126
 
127
-
127
+
128
128
  #Implements the connection to the SalesForce server.
129
129
  class Binding
130
130
  DEFAULT_BATCH_SIZE = 10
131
- attr_accessor :batch_size, :url
132
-
131
+ attr_accessor :batch_size, :url, :assignment_rule_id, :use_default_rule, :update_mru
132
+
133
133
  #Fill in the guts of this typical SOAP envelope
134
134
  #with the session ID and the body of the SOAP request.
135
135
  Envelope = <<-HERE
@@ -144,60 +144,66 @@ module RForce
144
144
  <QueryOptions>
145
145
  <batchSize>%d</batchSize>
146
146
  </QueryOptions>
147
+ %s
147
148
  </env:Header>
148
149
  <env:Body>
149
150
  %s
150
151
  </env:Body>
151
152
  </env:Envelope>
152
153
  HERE
154
+
155
+ AssignmentRuleHeaderUsingRuleId = "<AssignmentRuleHeader><assignment_rule_id>%s</assignment_rule_id></AssignmentRuleHeader>"
156
+ AssignmentRuleHeaderUsingDefaultRule = "<AssignmentRuleHeader><use_default_rule>true</use_default_rule></AssignmentRuleHeader>"
157
+ MruHeader = "<MruHeader><update_mru>true</update_mru></MruHeader>"
153
158
 
154
-
159
+
155
160
  #Connect to the server securely.
156
161
  def initialize(url, sid)
157
162
  init_server(url)
158
-
163
+
159
164
  @session_id = sid
160
165
  @batch_size = DEFAULT_BATCH_SIZE
161
166
  end
162
-
163
-
167
+
168
+
164
169
  def show_debug
165
170
  $DEBUG or ENV['SHOWSOAP']
166
171
  end
167
-
172
+
168
173
 
169
174
  def init_server(url)
170
175
  @url = URI.parse(url)
171
176
  @server = Net::HTTP.new(@url.host, @url.port)
172
177
  @server.use_ssl = @url.scheme == 'https'
173
178
  @server.verify_mode = OpenSSL::SSL::VERIFY_NONE
174
-
175
- # run ruby with -d to see SOAP wiredumps.
179
+
180
+ # run ruby with -d or env variable SHOWSOAP=true to see SOAP wiredumps.
176
181
  @server.set_debug_output $stderr if show_debug
177
182
  end
178
-
179
-
183
+
184
+
180
185
  #Log in to the server and remember the session ID
181
186
  #returned to us by SalesForce.
182
187
  def login(user, password)
183
- puts "\n\nIn login(#{user})\n\n"
184
-
185
188
  @user = user
186
189
  @password = password
187
-
190
+
188
191
  response = call_remote(:login, [:username, user, :password, password])
189
-
190
- raise "Incorrect user name / password [#{response.fault}]" unless response.loginResponse
191
-
192
+
193
+ unless response.loginResponse
194
+ pp response
195
+ raise "Incorrect user name / password [#{response.fault}]"
196
+ end
197
+
192
198
  result = response[:loginResponse][:result]
193
199
  @session_id = result[:sessionId]
194
-
200
+
195
201
  init_server(result[:serverUrl])
196
-
202
+
197
203
  response
198
204
  end
199
205
 
200
-
206
+
201
207
  #Call a method on the remote server. Arguments can be
202
208
  #a hash or (if order is important) an array of alternating
203
209
  #keys and values.
@@ -206,58 +212,63 @@ module RForce
206
212
  expanded = ''
207
213
  @builder = Builder::XmlMarkup.new(:target => expanded)
208
214
  expand({method => args}, 'urn:partner.soap.sforce.com')
215
+
216
+ extra_headers = ""
217
+ extra_headers << (AssignmentRuleHeaderUsingRuleId % assignment_rule_id) if assignment_rule_id
218
+ extra_headers << AssignmentRuleHeaderUsingDefaultRule if use_default_rule
219
+ extra_headers << MruHeader if update_mru
209
220
 
210
221
  #Fill in the blanks of the SOAP envelope with our
211
222
  #session ID and the expanded XML of our request.
212
- request = (Envelope % [@session_id, @batch_size, expanded])
213
-
223
+ request = (Envelope % [@session_id, @batch_size, extra_headers, expanded])
224
+
214
225
  # reset the batch size for the next request
215
226
  @batch_size = DEFAULT_BATCH_SIZE
216
-
227
+
217
228
  # gzip request
218
229
  request = encode(request)
219
-
230
+
220
231
  headers = {
221
232
  'Connection' => 'Keep-Alive',
222
233
  'Content-Type' => 'text/xml',
223
234
  'SOAPAction' => '""',
224
- 'User-Agent' => 'ActiveSalesforce RForce'
235
+ 'User-Agent' => 'ActiveSalesforce'
225
236
  }
226
237
 
227
238
  unless show_debug
228
239
  headers['Accept-Encoding'] = 'gzip'
229
240
  headers['Content-Encoding'] = 'gzip'
230
241
  end
231
-
242
+
232
243
  #Send the request to the server and read the response.
233
- response = @server.post2(@url.path, request, headers)
234
-
244
+ response = @server.post2(@url.path, request.lstrip, headers)
245
+
235
246
  # decode if we have encoding
236
247
  content = decode(response)
237
-
248
+
238
249
  # Check to see if INVALID_SESSION_ID was raised and try to relogin in
239
250
  if method != :login and @session_id and response =~ /<faultcode>sf\:INVALID_SESSION_ID<\/faultcode>/
240
251
  puts "\n\nSession timeout error - auto relogin activated"
241
-
252
+
242
253
  login(@user, @password)
243
-
254
+
244
255
  #Send the request to the server and read the response.
245
256
  response = @server.post2(@url.path, request, headers)
246
-
257
+
247
258
  content = decode(response)
248
259
  end
249
-
260
+
250
261
  SoapResponse.new(content)
251
262
  end
252
263
 
253
-
264
+
254
265
  # decode gzip
255
266
  def decode(response)
256
267
  encoding = response['Content-Encoding']
257
-
268
+
258
269
  # return body if no encoding
259
270
  if !encoding then return response.body end
260
-
271
+
261
272
  # decode gzip
262
273
  case encoding.strip
263
274
  when 'gzip':
@@ -273,7 +284,7 @@ module RForce
273
284
  end
274
285
  end
275
286
 
276
-
287
+
277
288
  # encode gzip
278
289
  def encode(request)
279
290
  return request if show_debug
@@ -287,28 +298,28 @@ module RForce
287
298
  gzw.close
288
299
  end
289
300
  end
290
-
291
-
301
+
302
+
292
303
  #Turns method calls on this object into remote SOAP calls.
293
304
  def method_missing(method, *args)
294
305
  unless args.size == 1 && [Hash, Array].include?(args[0].class)
295
306
  raise 'Expected 1 Hash or Array argument'
296
307
  end
297
-
308
+
298
309
  call_remote method, args[0]
299
310
  end
300
311
 
301
-
312
+
302
313
  #Expand Ruby data structures into XML.
303
314
  def expand(args, xmlns = nil)
304
315
  #Nest arrays: [:a, 1, :b, 2] => [[:a, 1], [:b, 2]]
305
316
  if (args.class == Array)
306
317
  args.each_index{|i| args[i, 2] = [args[i, 2]]}
307
318
  end
308
-
319
+
309
320
  args.each do |key, value|
310
321
  attributes = xmlns ? {:xmlns => xmlns} : {}
311
-
322
+
312
323
  #If the XML tag requires attributes,
313
324
  #the tag name will contain a space
314
325
  #followed by a string representation
@@ -318,16 +329,16 @@ module RForce
318
329
  #becomes <sObject xsi:type="Opportunity>...</sObject>
319
330
  if key.is_a? String
320
331
  key, modifier = key.split(' ', 2)
321
-
332
+
322
333
  attributes.merge!(eval(modifier)) if modifier
323
334
  end
324
-
335
+
325
336
  #Create an XML element and fill it with this
326
337
  #value's sub-items.
327
338
  case value
328
339
  when Hash, Array
329
340
  @builder.tag!(key, attributes) do expand value; end
330
-
341
+
331
342
  when String
332
343
  @builder.tag!(key, attributes) { @builder.text! value }
333
344
  end
@@ -17,10 +17,10 @@
17
17
 
18
18
  require 'rubygems'
19
19
 
20
- #require_gem 'activesalesforce', '>= 0.2.6'
21
- require 'activesalesforce'
20
+ #require_gem 'activesalesforce', '>= 0.4.3'
21
+ require File.dirname(__FILE__) + '/../../lib/activesalesforce'
22
22
 
23
- require 'recorded_test_case'
23
+ require File.dirname(__FILE__) + '/recorded_test_case'
24
24
  require 'pp'
25
25
 
26
26
 
@@ -30,6 +30,9 @@ end
30
30
  class Department < ActiveRecord::Base
31
31
  end
32
32
 
33
+ class Address < ActiveRecord::Base
34
+ end
35
+
33
36
 
34
37
  module Asf
35
38
  module UnitTests
@@ -42,7 +45,7 @@ module Asf
42
45
  def initialize(test_method_name)
43
46
  super(test_method_name)
44
47
 
45
- #force_recording :test_batch_insert
48
+ #force_recording :test_master_detail
46
49
  end
47
50
 
48
51
  def setup
@@ -51,6 +54,9 @@ module Asf
51
54
  super
52
55
 
53
56
  @contact = Contact.new
57
+
58
+ reset_header_options
59
+
54
60
  contact.first_name = 'DutchTestFirstName'
55
61
  contact.last_name = 'DutchTestLastName'
56
62
  contact.home_phone = '555-555-1212'
@@ -60,10 +66,19 @@ module Asf
60
66
  end
61
67
 
62
68
  def teardown
69
+ reset_header_options
70
+
63
71
  contact.destroy if contact
64
72
 
65
73
  super
66
74
  end
75
+
76
+ def reset_header_options
77
+ binding = Contact.connection.binding
78
+ binding.assignment_rule_id = nil
79
+ binding.use_default_rule = false
80
+ binding.update_mru = false
81
+ end
67
82
 
68
83
 
69
84
  def test_create_a_contact
@@ -101,6 +116,23 @@ module Asf
101
116
  user = contact.created_by
102
117
  assert_equal contact.created_by_id, user.id
103
118
  end
119
+
120
+ def test_use_update_mru
121
+ Contact.connection.binding.update_mru = true
122
+ contact.save
123
+ end
124
+
125
+ def test_use_default_rule
126
+ Contact.connection.binding.use_default_rule = true
127
+ contact.save
128
+ end
129
+
130
+ def test_assignment_rule_id
131
+ Contact.connection.binding.assignment_rule_id = "1234567890"
132
+ contact.save
133
+ end
134
+
135
+
104
136
 
105
137
  def test_add_notes_to_contact
106
138
  n1 = Note.new(:title => "My Title", :body => "My Body")
@@ -155,6 +187,10 @@ module Asf
155
187
  c1.destroy
156
188
  end
157
189
  end
190
+
191
+ def test_find_addresses
192
+ adresses = Address.find(:all)
193
+ end
158
194
 
159
195
  end
160
196