salesforce_bulk_api 1.1.0 → 1.3.0

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/CHANGELOG.md ADDED
File without changes
data/LICENCE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015 Yatish Mehta
3
+ Copyright (c) 2025 Yatish Mehta
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,141 +1,496 @@
1
1
  # Salesforce-Bulk-Api
2
+
2
3
  [![Gem Version](https://badge.fury.io/rb/salesforce_bulk_api.png)](http://badge.fury.io/rb/salesforce_bulk_api)
3
4
 
5
+ ## Table of Contents
6
+
7
+ - [Overview](#overview)
8
+ - [Installation](#installation)
9
+ - [Authentication](#authentication)
10
+ - [Usage](#usage)
11
+ - [Basic Operations](#basic-operations)
12
+ - [Method Parameters](#method-parameters)
13
+ - [Getting Results](#getting-results)
14
+ - [Null Value Handling](#null-value-handling)
15
+ - [Job Management](#job-management)
16
+ - [Batch Operations](#batch-operations)
17
+ - [Event Listening](#event-listening)
18
+ - [API Call Throttling](#api-call-throttling)
19
+ - [Monitoring and Counters](#monitoring-and-counters)
20
+ - [Error Handling](#error-handling)
21
+ - [Advanced Features](#advanced-features)
22
+ - [Contributing](#contributing)
23
+ - [License](#license)
24
+
4
25
  ## Overview
5
26
 
6
- `SalesforceBulkApi` is a ruby wrapper for the Salesforce Bulk API.
7
- It is rewritten from [salesforce_bulk](https://github.com/jorgevaldivia/salesforce_bulk).
8
- It adds some missing features of `salesforce_bulk`.
27
+ `SalesforceBulkApi` is a Ruby wrapper for the Salesforce Bulk API. It is rewritten from [salesforce_bulk](https://github.com/jorgevaldivia/salesforce_bulk) and adds several missing features, making it easier to perform bulk operations with Salesforce from Ruby applications.
9
28
 
10
- ## How to use
29
+ Key features:
30
+ - Support for all Bulk API operations (create, update, upsert, delete, query)
31
+ - Comprehensive error handling
32
+ - Job and batch status monitoring
33
+ - Event listening for job lifecycle
34
+ - API call throttling and monitoring
35
+ - Performance optimized string concatenation for large batches
11
36
 
12
- Using this gem is simple and straight forward.
37
+ ## Installation
13
38
 
14
- ### Install
39
+ Add this line to your application's Gemfile:
15
40
 
16
- `gem install salesforce_bulk_api`
41
+ ```ruby
42
+ gem 'salesforce_bulk_api'
43
+ ```
17
44
 
18
- or add it to your Gemfile
45
+ And then execute:
19
46
 
20
- `gem salesforce_bulk_api`
47
+ ```
48
+ bundle install
49
+ ```
50
+
51
+ Or install it directly:
21
52
 
22
- ### Authenticate
53
+ ```
54
+ gem install salesforce_bulk_api
55
+ ```
23
56
 
24
- You can authenticate with Salesforce using two gems, `databasedotcom` & `restforce`.
57
+ ## Authentication
25
58
 
26
- Please check the documentation of the respective gems to learn how to authenticate with Salesforce
59
+ You can authenticate with Salesforce using either `databasedotcom` or `restforce` gems. Both support various authentication methods including username/password, OmniAuth, and OAuth2.
27
60
 
28
- [Databasedotcom](https://github.com/heroku/databasedotcom)
29
- [Restforce](https://github.com/ejholmes/restforce)
61
+ Please refer to the documentation of these gems for detailed authentication options:
30
62
 
31
- You can use username password combo, OmniAuth, Oauth2
32
- You can use as many records possible in the Array. Governor limits are taken care of inside the gem.
63
+ - [Databasedotcom](https://github.com/heroku/databasedotcom)
64
+ - [Restforce](https://github.com/ejholmes/restforce)
65
+
66
+ ### Authentication Examples
67
+
68
+ #### Using Databasedotcom:
33
69
 
34
70
  ```ruby
35
71
  require 'salesforce_bulk_api'
36
72
 
37
73
  client = Databasedotcom::Client.new(
38
- :client_id => SFDC_APP_CONFIG["client_id"],
39
- :client_secret => SFDC_APP_CONFIG["client_secret"]
74
+ client_id: SFDC_APP_CONFIG["client_id"],
75
+ client_secret: SFDC_APP_CONFIG["client_secret"]
40
76
  )
41
77
  client.authenticate(
42
- :token => " ",
43
- :instance_url => "http://na1.salesforce.com"
78
+ token: " ",
79
+ instance_url: "http://na1.salesforce.com"
44
80
  )
45
81
 
46
82
  salesforce = SalesforceBulkApi::Api.new(client)
47
83
  ```
48
84
 
49
- OR
85
+ #### Using Restforce:
50
86
 
51
87
  ```ruby
52
88
  require 'salesforce_bulk_api'
89
+
53
90
  client = Restforce.new(
54
- username: SFDC_APP_CONFIG['SFDC_USERNAME'],
55
- password: SFDC_APP_CONFIG['SFDC_PASSWORD'],
91
+ username: SFDC_APP_CONFIG['SFDC_USERNAME'],
92
+ password: SFDC_APP_CONFIG['SFDC_PASSWORD'],
56
93
  security_token: SFDC_APP_CONFIG['SFDC_SECURITY_TOKEN'],
57
- client_id: SFDC_APP_CONFIG['SFDC_CLIENT_ID'],
58
- client_secret: SFDC_APP_CONFIG['SFDC_CLIENT_SECRET'].to_i,
59
- host: SFDC_APP_CONFIG['SFDC_HOST']
94
+ client_id: SFDC_APP_CONFIG['SFDC_CLIENT_ID'],
95
+ client_secret: SFDC_APP_CONFIG['SFDC_CLIENT_SECRET'],
96
+ host: SFDC_APP_CONFIG['SFDC_HOST']
60
97
  )
61
98
  client.authenticate!
62
99
 
63
100
  salesforce = SalesforceBulkApi::Api.new(client)
64
101
  ```
65
102
 
66
- ### Sample operations:
103
+ ## Usage
104
+
105
+ ### Basic Operations
106
+
107
+ #### Create/Insert Records
67
108
 
68
109
  ```ruby
69
- # Insert/Create
70
- # Add as many fields per record as needed.
71
- new_account = Hash["name" => "Test Account", "type" => "Other"]
72
- records_to_insert = Array.new
73
- # You can add as many records as you want here, just keep in mind that Salesforce has governor limits.
74
- records_to_insert.push(new_account)
110
+ new_account = { "name" => "Test Account", "type" => "Other" }
111
+ records_to_insert = [new_account]
112
+
113
+ # Basic usage
75
114
  result = salesforce.create("Account", records_to_insert)
76
- puts "result is: #{result.inspect}"
77
115
 
78
- # Update
79
- updated_account = Hash["name" => "Test Account -- Updated", id => "a00A0001009zA2m"] # Nearly identical to an insert, but we need to pass the salesforce id.
80
- records_to_update = Array.new
81
- records_to_update.push(updated_account)
116
+ # With response and custom batch size
117
+ result = salesforce.create("Account", records_to_insert, true, false, [], 5000)
118
+ ```
119
+
120
+ #### Update Records
121
+
122
+ ```ruby
123
+ updated_account = { "name" => "Test Account -- Updated", "id" => "a00A0001009zA2m" }
124
+ records_to_update = [updated_account]
125
+
126
+ # Basic usage
82
127
  salesforce.update("Account", records_to_update)
83
128
 
84
- # Upsert
85
- upserted_account = Hash["name" => "Test Account -- Upserted", "External_Field_Name" => "123456"] # Fields to be updated. External field must be included
86
- records_to_upsert = Array.new
87
- records_to_upsert.push(upserted_account)
88
- salesforce.upsert("Account", records_to_upsert, "External_Field_Name") # Note that upsert accepts an extra parameter for the external field name
129
+ # With null handling
130
+ salesforce.update("Account", records_to_update, true, true, ["Phone"])
131
+ ```
132
+
133
+ #### Upsert Records
134
+
135
+ ```ruby
136
+ upserted_account = { "name" => "Test Account -- Upserted", "External_Field_Name" => "123456" }
137
+ records_to_upsert = [upserted_account]
138
+
139
+ # Basic usage
140
+ salesforce.upsert("Account", records_to_upsert, "External_Field_Name")
89
141
 
90
- # Delete
91
- deleted_account = Hash["id" => "a00A0001009zA2m"] # We only specify the id of the records to delete
92
- records_to_delete = Array.new
93
- records_to_delete.push(deleted_account)
142
+ # With all options
143
+ result = salesforce.upsert("Account", records_to_upsert, "External_Field_Name", true, false, [], 10000, 3600)
144
+ ```
145
+
146
+ #### Delete Records
147
+
148
+ ```ruby
149
+ deleted_account = { "id" => "a00A0001009zA2m" }
150
+ records_to_delete = [deleted_account]
151
+
152
+ # Basic usage
94
153
  salesforce.delete("Account", records_to_delete)
95
154
 
96
- # Query
97
- res = salesforce.query("Account", "select id, name, createddate from Account limit 3") # We just need to pass the sobject name and the query string
155
+ # With response
156
+ result = salesforce.delete("Account", records_to_delete, true)
157
+ ```
158
+
159
+ #### Query Records
160
+
161
+ ```ruby
162
+ result = salesforce.query("Account", "SELECT id, name, createddate FROM Account LIMIT 3")
163
+ puts "Records found: #{result["batches"][0]["response"].length}"
98
164
  ```
99
165
 
100
- ### Helpful methods:
166
+ ### Method Parameters
167
+
168
+ All bulk operation methods support additional parameters for fine-tuned control:
169
+
170
+ #### Complete Method Signatures:
101
171
 
102
172
  ```ruby
103
- # Check status of a job via #job_from_id
104
- job = salesforce.job_from_id('a00A0001009zA2m') # Returns a SalesforceBulkApi::Job instance
105
- puts "status is: #{job.check_job_status.inspect}"
173
+ # CREATE
174
+ salesforce.create(sobject, records, get_response=false, send_nulls=false, no_null_list=[], batch_size=10000, timeout=1500)
175
+
176
+ # UPDATE
177
+ salesforce.update(sobject, records, get_response=false, send_nulls=false, no_null_list=[], batch_size=10000, timeout=1500)
178
+
179
+ # UPSERT
180
+ salesforce.upsert(sobject, records, external_field, get_response=false, send_nulls=false, no_null_list=[], batch_size=10000, timeout=1500)
181
+
182
+ # DELETE
183
+ salesforce.delete(sobject, records, get_response=false, batch_size=10000, timeout=1500)
184
+
185
+ # QUERY
186
+ salesforce.query(sobject, query_string, batch_size=10000, timeout=1500)
106
187
  ```
107
188
 
108
- ### Listening to events:
189
+ #### Parameter Descriptions:
190
+
191
+ - **`get_response`** (Boolean): Whether to return batch processing results (default: false)
192
+ - **`send_nulls`** (Boolean): Whether to send null/empty values to Salesforce (default: false)
193
+ - **`no_null_list`** (Array): Fields to exclude from null value handling when `send_nulls` is true
194
+ - **`batch_size`** (Integer): Number of records per batch (default: 10000, max: 10000)
195
+ - **`timeout`** (Integer): Timeout in seconds for job completion (default: 1500)
196
+
197
+ ### Getting Results
198
+
199
+ When `get_response` is set to true, you'll receive detailed results:
200
+
201
+ ```ruby
202
+ result = salesforce.create("Account", records, true)
203
+
204
+ # Access job information
205
+ puts "Job ID: #{result['job_id']}"
206
+ puts "Job state: #{result['state']}"
207
+
208
+ # Access batch results
209
+ result["batches"].each_with_index do |batch, index|
210
+ puts "Batch #{index + 1}:"
211
+ puts " State: #{batch['state'][0]}"
212
+ puts " Records processed: #{batch['numberRecordsProcessed'][0]}"
213
+
214
+ if batch["response"]
215
+ batch["response"].each do |record|
216
+ if record["success"] == ["true"]
217
+ puts " ✓ Success: #{record['id'][0]}"
218
+ else
219
+ puts " ✗ Error: #{record['errors'][0]['message'][0]}"
220
+ end
221
+ end
222
+ end
223
+ end
224
+ ```
225
+
226
+ ### Null Value Handling
227
+
228
+ Control how null and empty values are handled:
229
+
230
+ ```ruby
231
+ records = [
232
+ { "Id" => "001...", "Name" => "Test", "Phone" => "", "Website" => nil }
233
+ ]
234
+
235
+ # Send nulls for empty/nil fields, except for Phone
236
+ result = salesforce.update("Account", records, true, true, ["Phone"])
237
+
238
+ # This will:
239
+ # - Set Website to NULL in Salesforce (because it's nil)
240
+ # - Leave Phone unchanged (because it's in no_null_list)
241
+ # - Update Name normally
242
+ ```
243
+
244
+ ### Job Management
245
+
246
+ #### Get Job by ID
247
+
248
+ ```ruby
249
+ job = salesforce.job_from_id('750A0000001234567')
250
+ status = job.check_job_status
251
+ puts "Job state: #{status['state'][0]}"
252
+ puts "Batches total: #{status['numberBatchesTotal'][0]}"
253
+ ```
254
+
255
+ #### Check Job Status
256
+
257
+ ```ruby
258
+ job = salesforce.job_from_id(job_id)
259
+ status = job.check_job_status
260
+
261
+ puts "Job Information:"
262
+ puts " State: #{status['state'][0]}"
263
+ puts " Object: #{status['object'][0]}"
264
+ puts " Operation: #{status['operation'][0]}"
265
+ puts " Total Batches: #{status['numberBatchesTotal'][0]}"
266
+ puts " Completed Batches: #{status['numberBatchesCompleted'][0]}"
267
+ puts " Failed Batches: #{status['numberBatchesFailed'][0]}"
268
+ ```
269
+
270
+ ### Batch Operations
271
+
272
+ #### Check Batch Status
273
+
274
+ ```ruby
275
+ job = salesforce.job_from_id(job_id)
276
+ batch_status = job.check_batch_status(batch_id)
277
+
278
+ puts "Batch Information:"
279
+ puts " State: #{batch_status['state'][0]}"
280
+ puts " Records Processed: #{batch_status['numberRecordsProcessed'][0]}"
281
+ puts " Records Failed: #{batch_status['numberRecordsFailed'][0]}"
282
+ ```
283
+
284
+ #### Retrieve Batch Records
285
+
286
+ ```ruby
287
+ job = salesforce.job_from_id(job_id)
288
+ records = job.get_batch_records(batch_id)
289
+
290
+ puts "Batch Records:"
291
+ records.each do |record|
292
+ puts " #{record.inspect}"
293
+ end
294
+ ```
295
+
296
+ #### Get Batch Results
297
+
298
+ ```ruby
299
+ job = salesforce.job_from_id(job_id)
300
+ results = job.get_batch_result(batch_id)
301
+
302
+ results.each do |result|
303
+ if result["success"] == ["true"]
304
+ puts "Success: Record ID #{result['id'][0]}"
305
+ else
306
+ puts "Failed: #{result['errors'][0]['message'][0]}"
307
+ end
308
+ end
309
+ ```
310
+
311
+ ### Event Listening
312
+
313
+ Listen for job creation events:
109
314
 
110
315
  ```ruby
111
- # A job is created
112
- # Useful when you need to store the job_id before any work begins, then if you fail during a complex load scenario, you can wait for your
113
- # previous job(s) to finish.
114
316
  salesforce.on_job_created do |job|
115
- puts "Job #{job.job_id} created!"
317
+ puts "Job #{job.job_id} created for #{job.operation} on #{job.sobject}!"
318
+
319
+ # You can perform additional operations here
320
+ # like logging, notifications, etc.
116
321
  end
322
+
323
+ # Now when you create/update/etc, the listener will be called
324
+ result = salesforce.create("Account", records)
117
325
  ```
118
326
 
119
- ### Fetching records from a batch
327
+ ### API Call Throttling
328
+
329
+ Control the frequency of status checks to avoid hitting API limits:
330
+
331
+ ```ruby
332
+ # Set status check interval to 30 seconds (default is 5 seconds)
333
+ salesforce.connection.set_status_throttle(30)
334
+
335
+ # Check current throttle setting
336
+ puts "Current throttle: #{salesforce.connection.get_status_throttle} seconds"
337
+ ```
338
+
339
+ ### Monitoring and Counters
340
+
341
+ Track API usage and operations:
120
342
 
121
343
  ```ruby
122
- job_id = 'l02A0231009Za8m'
123
- batch_id = 'H24a0708089zA2J'
124
- salesforce.get_batch_records(job_id, batch_id)
125
- # => [{"Id"=>["RECORD_ID_1"], "AField__c"=>["123123"]},
126
- {"Id"=>["RECORD_ID_2"], "AField__c"=>["123123"]},
127
- {"Id"=>["RECORD_ID_3"], "AField__c"=>["123123"]}]
344
+ # Get operation counters
345
+ counters = salesforce.counters
346
+ puts "API Usage: #{counters}"
347
+ # => {:http_get=>15, :http_post=>8, :upsert=>2, :update=>1, :create=>3, :delete=>0, :query=>2}
348
+
349
+ # Reset counters
350
+ salesforce.reset_counters
351
+ ```
352
+
353
+ ## Error Handling
128
354
 
355
+ The gem provides comprehensive error handling:
356
+
357
+ ```ruby
358
+ begin
359
+ result = salesforce.create("Account", records, true)
360
+
361
+ # Check for batch-level errors
362
+ result["batches"].each do |batch|
363
+ if batch["state"][0] == "Failed"
364
+ puts "Batch failed: #{batch["stateMessage"][0]}"
365
+ end
366
+ end
367
+
368
+ rescue SalesforceBulkApi::Job::SalesforceException => e
369
+ puts "Salesforce API error: #{e.message}"
370
+ # Handle API-level errors (invalid objects, fields, etc.)
371
+
372
+ rescue SalesforceBulkApi::JobTimeout => e
373
+ puts "Job timed out: #{e.message}"
374
+ # Handle timeout errors - job took longer than specified timeout
375
+
376
+ rescue => e
377
+ puts "Unexpected error: #{e.message}"
378
+ # Handle other errors (network issues, authentication, etc.)
379
+ end
129
380
  ```
130
381
 
131
- ### Throttling API calls:
382
+ ### Common Error Scenarios
132
383
 
133
384
  ```ruby
134
- # By default, this gem (and maybe your app driving it) will query job/batch statuses at an unbounded rate. We
135
- # can fix that, e.g.:
136
- salesforce.connection.set_status_throttle(30) # only check status of individual jobs/batches every 30 seconds
385
+ # Invalid field names
386
+ begin
387
+ records = [{ "InvalidField__c" => "value" }]
388
+ salesforce.create("Account", records, true)
389
+ rescue SalesforceBulkApi::Job::SalesforceException => e
390
+ puts "Field error: #{e.message}"
391
+ end
392
+
393
+ # Malformed record IDs
394
+ begin
395
+ records = [{ "Id" => "invalid_id" }]
396
+ salesforce.update("Account", records, true)
397
+ rescue => e
398
+ # This might not raise immediately - check batch results
399
+ result = salesforce.update("Account", records, true)
400
+ failed_records = result["batches"][0]["response"].select { |r| r["success"] == ["false"] }
401
+ failed_records.each { |r| puts "Failed: #{r['errors'][0]['message'][0]}" }
402
+ end
403
+ ```
404
+
405
+ ## Advanced Features
406
+
407
+ ### Relationship Fields
408
+
409
+ You can work with relationship fields using dot notation:
410
+
411
+ ```ruby
412
+ # Create records with relationship data
413
+ records = [
414
+ {
415
+ "Name" => "Test Account",
416
+ "Parent.Name" => "Parent Account Name",
417
+ "Owner.Email" => "owner@example.com"
418
+ }
419
+ ]
420
+
421
+ result = salesforce.create("Account", records, true)
422
+ ```
423
+
424
+ ### Special Data Types
425
+
426
+ The gem automatically handles various data types:
427
+
428
+ ```ruby
429
+ records = [
430
+ {
431
+ "Name" => "Test Account",
432
+ "AnnualRevenue" => 1000000, # Numbers
433
+ "IsActive__c" => true, # Booleans
434
+ "LastModifiedDate" => Time.now, # Timestamps (converted to ISO8601)
435
+ "Description" => "Text with <special> chars" # XML encoding handled automatically
436
+ }
437
+ ]
438
+ ```
439
+
440
+ ### Large Dataset Handling
441
+
442
+ For large datasets, the gem automatically handles batching:
443
+
444
+ ```ruby
445
+ # This will be automatically split into multiple batches of 10,000 records each
446
+ large_dataset = (1..50000).map { |i| { "Name" => "Account #{i}" } }
447
+
448
+ result = salesforce.create("Account", large_dataset, true, false, [], 10000, 7200) # 2 hour timeout
449
+ puts "Created #{result['batches'].length} batches"
450
+ ```
451
+
452
+ ### Custom Batch Sizes
453
+
454
+ Optimize for your use case:
455
+
456
+ ```ruby
457
+ # Smaller batches for complex records
458
+ complex_records = [...]
459
+ salesforce.create("CustomObject__c", complex_records, true, false, [], 2000)
460
+
461
+ # Larger batches for simple records (up to 10,000)
462
+ simple_records = [...]
463
+ salesforce.create("Account", simple_records, true, false, [], 10000)
464
+ ```
465
+
466
+ ## Contributing
467
+
468
+ We welcome contributions to improve this gem. Feel free to:
469
+
470
+ 1. Fork the repository
471
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
472
+ 3. Commit your changes (`git commit -am 'Add some amazing feature'`)
473
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
474
+ 5. Create a new Pull Request
475
+
476
+ ### Development Setup
477
+
478
+ ```bash
479
+ git clone https://github.com/yatish27/salesforce_bulk_api.git
480
+ cd salesforce_bulk_api
481
+ bundle install
482
+
483
+ # Copy environment template
484
+ cp .env.sample .env
485
+ # Edit .env with your Salesforce credentials
486
+
487
+ # Run tests
488
+ bundle exec rspec
489
+
490
+ # Run RuboCop
491
+ bundle exec rubocop
137
492
  ```
138
493
 
139
- ## Contribute
494
+ ## License
140
495
 
141
- Feel to fork and send Pull request
496
+ This project is licensed under the MIT License, Copyright (c) 2025 - see the [LICENCE](LICENCE) file for details.
data/Rakefile CHANGED
@@ -1,3 +1,3 @@
1
- require 'rspec/core/rake_task'
2
- task :default => :spec
3
- RSpec::Core::RakeTask.new
1
+ require "rspec/core/rake_task"
2
+ task default: :spec
3
+ RSpec::Core::RakeTask.new
@@ -1,6 +1,5 @@
1
1
  module SalesforceBulkApi::Concerns
2
2
  module Throttling
3
-
4
3
  def throttles
5
4
  @throttles.dup
6
5
  end
@@ -48,13 +47,12 @@ module SalesforceBulkApi::Concerns
48
47
  @limits
49
48
  end
50
49
 
51
- def throttle(details={})
50
+ def throttle(details = {})
52
51
  (@throttles || []).each do |callback|
53
52
  args = [details]
54
53
  args = args[0..callback.arity]
55
54
  callback.call(*args)
56
55
  end
57
56
  end
58
-
59
57
  end
60
58
  end
@@ -1,20 +1,20 @@
1
- require 'timeout'
1
+ require "timeout"
2
2
 
3
3
  module SalesforceBulkApi
4
4
  class Connection
5
5
  include Concerns::Throttling
6
6
 
7
- LOGIN_HOST = 'login.salesforce.com'
7
+ LOGIN_HOST = "login.salesforce.com"
8
8
 
9
9
  def initialize(api_version, client)
10
10
  @client = client
11
11
  @api_version = api_version
12
12
  @path_prefix = "/services/async/#{@api_version}/"
13
13
 
14
- login()
14
+ login
15
15
  end
16
16
 
17
- def login()
17
+ def login
18
18
  client_type = @client.class.to_s
19
19
  case client_type
20
20
  when "Restforce::Data::Client"
@@ -24,14 +24,14 @@ module SalesforceBulkApi
24
24
  @session_id = @client.oauth_token
25
25
  @server_url = @client.instance_url
26
26
  end
27
- @instance = parse_instance()
27
+ @instance = parse_instance
28
28
  @instance_host = "#{@instance}.salesforce.com"
29
29
  end
30
30
 
31
31
  def post_xml(host, path, xml, headers)
32
- host = host || @instance_host
32
+ host ||= @instance_host
33
33
  if host != LOGIN_HOST # Not login, need to add session id to header
34
- headers['X-SFDC-Session'] = @session_id
34
+ headers["X-SFDC-Session"] = @session_id
35
35
  path = "#{@path_prefix}#{path}"
36
36
  end
37
37
  i = 0
@@ -52,10 +52,10 @@ module SalesforceBulkApi
52
52
  end
53
53
 
54
54
  def get_request(host, path, headers)
55
- host = host || @instance_host
55
+ host ||= @instance_host
56
56
  path = "#{@path_prefix}#{path}"
57
57
  if host != LOGIN_HOST # Not login, need to add session id to header
58
- headers['X-SFDC-Session'] = @session_id;
58
+ headers["X-SFDC-Session"] = @session_id
59
59
  end
60
60
 
61
61
  count :get
@@ -80,19 +80,17 @@ module SalesforceBulkApi
80
80
  private
81
81
 
82
82
  def get_counters
83
- @counters ||= Hash.new(0)
83
+ @counters ||= Hash.new { |hash, key| hash[key] = 0 }
84
84
  end
85
85
 
86
86
  def count(http_method)
87
87
  get_counters[http_method] += 1
88
88
  end
89
89
 
90
- def parse_instance()
91
- @instance = @server_url.match(/https:\/\/[a-z]{2}[0-9]{1,2}\./).to_s.gsub("https://","").split(".")[0]
90
+ def parse_instance
91
+ @instance = @server_url.match(/https:\/\/[a-z]{2}[0-9]{1,2}\./).to_s.gsub("https://", "").split(".")[0]
92
92
  @instance = @server_url.split(".salesforce.com")[0].split("://")[1] if @instance.nil? || @instance.empty?
93
93
  @instance
94
94
  end
95
-
96
95
  end
97
-
98
96
  end