salesforce_bulk_quickfix 1.0.1
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/.gitignore +6 -0
- data/Gemfile +4 -0
- data/README.rdoc +75 -0
- data/Rakefile +1 -0
- data/lib/salesforce_bulk/connection.rb +114 -0
- data/lib/salesforce_bulk/job.rb +174 -0
- data/lib/salesforce_bulk/version.rb +3 -0
- data/lib/salesforce_bulk.rb +83 -0
- data/salesforce_bulk.gemspec +27 -0
- metadata +72 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.rdoc
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
= salesforce-bulk
|
|
2
|
+
|
|
3
|
+
==Overview
|
|
4
|
+
|
|
5
|
+
Salesforce bulk is a simple ruby gem for connecting to and using the Salesforce Bulk API (http://www.salesforce.com/us/developer/docs/api_asynch/index.htm). There are already some gems out there that provide connectivity to the Salesforce SOAP and Rest APIs, if your needs are simple, I recommend using those, specifically raygao's asf-rest-adapter (https://github.com/raygao/asf-rest-adapter) or databasedotcom (https://rubygems.org/gems/databasedotcom).
|
|
6
|
+
|
|
7
|
+
==Installation
|
|
8
|
+
|
|
9
|
+
sudo gem install salesforce_bulk
|
|
10
|
+
|
|
11
|
+
==How to use
|
|
12
|
+
|
|
13
|
+
Using this gem is simple and straight forward.
|
|
14
|
+
|
|
15
|
+
To initialize:
|
|
16
|
+
|
|
17
|
+
require 'salesforce_bulk'
|
|
18
|
+
salesforce = SalesforceBulk::Api.new("YOUR_SALESFORCE_USERNAME", "YOUR_SALESFORCE_PASSWORD+YOUR_SALESFORCE_TOKEN")
|
|
19
|
+
|
|
20
|
+
To use sandbox:
|
|
21
|
+
salesforce = SalesforceBulk::Api.new("YOUR_SALESFORCE_SANDBOX_USERNAME", "YOUR_SALESFORCE_PASSWORD+YOUR_SALESFORCE_SANDBOX_TOKEN", true)
|
|
22
|
+
|
|
23
|
+
Note: the second parameter is a combination of your Salesforce token and password. So if your password is xxxx and your token is yyyy, the second parameter will be xxxxyyyy
|
|
24
|
+
|
|
25
|
+
Sample operations:
|
|
26
|
+
|
|
27
|
+
# Insert/Create
|
|
28
|
+
new_account = Hash["name" => "Test Account", "type" => "Other"] # Add as many fields per record as needed.
|
|
29
|
+
records_to_insert = Array.new
|
|
30
|
+
records_to_insert.push(new_account) # You can add as many records as you want here, just keep in mind that Salesforce has governor limits.
|
|
31
|
+
result = salesforce.create("Account", records_to_insert)
|
|
32
|
+
puts "result is: #{result.inspect}"
|
|
33
|
+
|
|
34
|
+
# Update
|
|
35
|
+
updated_account = Hash["name" => "Test Account -- Updated", "id" => "a00A0001009zA2m"] # Nearly identical to an insert, but we need to pass the salesforce id.
|
|
36
|
+
records_to_update = Array.new
|
|
37
|
+
records_to_update.push(updated_account)
|
|
38
|
+
salesforce.update("Account", records_to_update)
|
|
39
|
+
|
|
40
|
+
# Upsert
|
|
41
|
+
upserted_account = Hash["name" => "Test Account -- Upserted", "External_Field_Name" => "123456"] # Fields to be updated. External field must be included
|
|
42
|
+
records_to_upsert = Array.new
|
|
43
|
+
records_to_upsert.push(upserted_account)
|
|
44
|
+
salesforce.upsert("Account", records_to_upsert, "External_Field_Name") # Note that upsert accepts an extra parameter for the external field name
|
|
45
|
+
|
|
46
|
+
OR
|
|
47
|
+
|
|
48
|
+
salesforce.upsert("Account", records_to_upsert, "External_Field_Name", true) # last parameter indicates whether to wait until the batch finishes
|
|
49
|
+
|
|
50
|
+
# Delete
|
|
51
|
+
deleted_account = Hash["id" => "a00A0001009zA2m"] # We only specify the id of the records to delete
|
|
52
|
+
records_to_delete = Array.new
|
|
53
|
+
records_to_delete.push(deleted_account)
|
|
54
|
+
salesforce.delete("Account", records_to_delete)
|
|
55
|
+
|
|
56
|
+
# Query
|
|
57
|
+
res = salesforce.query("Account", "select id, name, createddate from Account limit 3") # We just need to pass the sobject name and the query string
|
|
58
|
+
puts res.result.records.inspect
|
|
59
|
+
|
|
60
|
+
Result reporting:
|
|
61
|
+
|
|
62
|
+
new_account = Hash["type" => "Other"] # Missing required field "name."
|
|
63
|
+
records_to_insert = Array.new
|
|
64
|
+
records_to_insert.push(new_account) # You can add as many records as you want here, just keep in mind that Salesforce has governor limits.
|
|
65
|
+
result = salesforce.create("Account", records_to_insert, true) # Result reporting can only be used if wait is set to true
|
|
66
|
+
puts result.success? # false
|
|
67
|
+
puts result.has_errors? # true
|
|
68
|
+
puts result.result.errors # An indexed hash detailing the errors
|
|
69
|
+
|
|
70
|
+
== Copyright
|
|
71
|
+
|
|
72
|
+
Copyright (c) 2012 Jorge Valdivia.
|
|
73
|
+
|
|
74
|
+
===end
|
|
75
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
module SalesforceBulk
|
|
2
|
+
|
|
3
|
+
class Connection
|
|
4
|
+
|
|
5
|
+
@@XML_HEADER = '<?xml version="1.0" encoding="utf-8" ?>'
|
|
6
|
+
@@API_VERSION = nil
|
|
7
|
+
@@LOGIN_HOST = 'login.salesforce.com'
|
|
8
|
+
@@INSTANCE_HOST = nil # Gets set in login()
|
|
9
|
+
|
|
10
|
+
def initialize(username, password, api_version, in_sandbox)
|
|
11
|
+
@username = username
|
|
12
|
+
@password = password
|
|
13
|
+
@session_id = nil
|
|
14
|
+
@server_url = nil
|
|
15
|
+
@instance = nil
|
|
16
|
+
@@API_VERSION = api_version
|
|
17
|
+
@@LOGIN_PATH = "/services/Soap/u/#{@@API_VERSION}"
|
|
18
|
+
@@PATH_PREFIX = "/services/async/#{@@API_VERSION}/"
|
|
19
|
+
@@LOGIN_HOST = 'test.salesforce.com' if in_sandbox
|
|
20
|
+
|
|
21
|
+
login()
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
#private
|
|
25
|
+
|
|
26
|
+
def login()
|
|
27
|
+
|
|
28
|
+
xml = '<?xml version="1.0" encoding="utf-8" ?>'
|
|
29
|
+
xml += "<env:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""
|
|
30
|
+
xml += " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
|
|
31
|
+
xml += " xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\">"
|
|
32
|
+
xml += " <env:Body>"
|
|
33
|
+
xml += " <n1:login xmlns:n1=\"urn:partner.soap.sforce.com\">"
|
|
34
|
+
xml += " <n1:username>#{@username}</n1:username>"
|
|
35
|
+
xml += " <n1:password>#{@password}</n1:password>"
|
|
36
|
+
xml += " </n1:login>"
|
|
37
|
+
xml += " </env:Body>"
|
|
38
|
+
xml += "</env:Envelope>"
|
|
39
|
+
|
|
40
|
+
headers = Hash['Content-Type' => 'text/xml; charset=utf-8', 'SOAPAction' => 'login']
|
|
41
|
+
|
|
42
|
+
response = post_xml(@@LOGIN_HOST, @@LOGIN_PATH, xml, headers)
|
|
43
|
+
# response_parsed = XmlSimple.xml_in(response)
|
|
44
|
+
response_parsed = parse_response response
|
|
45
|
+
|
|
46
|
+
@session_id = response_parsed['Body'][0]['loginResponse'][0]['result'][0]['sessionId'][0]
|
|
47
|
+
@server_url = response_parsed['Body'][0]['loginResponse'][0]['result'][0]['serverUrl'][0]
|
|
48
|
+
@instance = parse_instance()
|
|
49
|
+
|
|
50
|
+
@@INSTANCE_HOST = "#{@instance}.salesforce.com"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def post_xml(host, path, xml, headers)
|
|
54
|
+
|
|
55
|
+
host = host || @@INSTANCE_HOST
|
|
56
|
+
|
|
57
|
+
if host != @@LOGIN_HOST # Not login, need to add session id to header
|
|
58
|
+
headers['X-SFDC-Session'] = @session_id;
|
|
59
|
+
path = "#{@@PATH_PREFIX}#{path}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
https(host).post(path, xml, headers).body
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def get_request(host, path, headers)
|
|
66
|
+
host = host || @@INSTANCE_HOST
|
|
67
|
+
path = "#{@@PATH_PREFIX}#{path}"
|
|
68
|
+
|
|
69
|
+
if host != @@LOGIN_HOST # Not login, need to add session id to header
|
|
70
|
+
headers['X-SFDC-Session'] = @session_id;
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
https(host).get(path, headers).body
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def https(host)
|
|
77
|
+
req = Net::HTTP.new(host, 443)
|
|
78
|
+
req.use_ssl = true
|
|
79
|
+
req.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
80
|
+
req
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def parse_instance()
|
|
84
|
+
#@server_url =~ /https:\/\/([a-z]{2,2}[0-9]{1,2})-api/
|
|
85
|
+
#@instance = $~.captures[0]
|
|
86
|
+
# JOHN RYAN: had to do this fix quick after a Salesforce API change
|
|
87
|
+
@server_url = @instance
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def parse_response response
|
|
91
|
+
response_parsed = XmlSimple.xml_in(response)
|
|
92
|
+
|
|
93
|
+
if response.downcase.include?("faultstring") || response.downcase.include?("exceptionmessage")
|
|
94
|
+
begin
|
|
95
|
+
|
|
96
|
+
if response.downcase.include?("faultstring")
|
|
97
|
+
error_message = response_parsed["Body"][0]["Fault"][0]["faultstring"][0]
|
|
98
|
+
elsif response.downcase.include?("exceptionmessage")
|
|
99
|
+
error_message = response_parsed["exceptionMessage"][0]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
rescue
|
|
103
|
+
raise "An unknown error has occured within the salesforce_bulk gem. This is most likely caused by bad request, but I am unable to parse the correct error message. Here is a dump of the response for your convenience. #{response}"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
raise error_message
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
response_parsed
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
module SalesforceBulk
|
|
2
|
+
|
|
3
|
+
class Job
|
|
4
|
+
|
|
5
|
+
attr :result
|
|
6
|
+
|
|
7
|
+
def initialize(operation, sobject, records, external_field, connection)
|
|
8
|
+
|
|
9
|
+
@@operation = operation
|
|
10
|
+
@@sobject = sobject
|
|
11
|
+
@@external_field = external_field
|
|
12
|
+
@@records = records
|
|
13
|
+
@@connection = connection
|
|
14
|
+
@@XML_HEADER = '<?xml version="1.0" encoding="utf-8" ?>'
|
|
15
|
+
|
|
16
|
+
# @result = {"errors" => [], "success" => nil, "records" => [], "raw" => nil, "message" => 'The job has been queued.'}
|
|
17
|
+
@result = JobResult.new
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def create_job()
|
|
22
|
+
xml = "#{@@XML_HEADER}<jobInfo xmlns=\"http://www.force.com/2009/06/asyncapi/dataload\">"
|
|
23
|
+
xml += "<operation>#{@@operation}</operation>"
|
|
24
|
+
xml += "<object>#{@@sobject}</object>"
|
|
25
|
+
if !@@external_field.nil? # This only happens on upsert
|
|
26
|
+
xml += "<externalIdFieldName>#{@@external_field}</externalIdFieldName>"
|
|
27
|
+
end
|
|
28
|
+
xml += "<contentType>CSV</contentType>"
|
|
29
|
+
xml += "</jobInfo>"
|
|
30
|
+
|
|
31
|
+
path = "job"
|
|
32
|
+
headers = Hash['Content-Type' => 'application/xml; charset=utf-8']
|
|
33
|
+
|
|
34
|
+
response = @@connection.post_xml(nil, path, xml, headers)
|
|
35
|
+
response_parsed = @@connection.parse_response response
|
|
36
|
+
|
|
37
|
+
@@job_id = response_parsed['id'][0]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def close_job()
|
|
41
|
+
xml = "#{@@XML_HEADER}<jobInfo xmlns=\"http://www.force.com/2009/06/asyncapi/dataload\">"
|
|
42
|
+
xml += "<state>Closed</state>"
|
|
43
|
+
xml += "</jobInfo>"
|
|
44
|
+
|
|
45
|
+
path = "job/#{@@job_id}"
|
|
46
|
+
headers = Hash['Content-Type' => 'application/xml; charset=utf-8']
|
|
47
|
+
|
|
48
|
+
response = @@connection.post_xml(nil, path, xml, headers)
|
|
49
|
+
response_parsed = XmlSimple.xml_in(response)
|
|
50
|
+
|
|
51
|
+
#job_id = response_parsed['id'][0]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def add_query
|
|
55
|
+
path = "job/#{@@job_id}/batch/"
|
|
56
|
+
headers = Hash["Content-Type" => "text/csv; charset=UTF-8"]
|
|
57
|
+
|
|
58
|
+
response = @@connection.post_xml(nil, path, @@records, headers)
|
|
59
|
+
response_parsed = XmlSimple.xml_in(response)
|
|
60
|
+
|
|
61
|
+
@@batch_id = response_parsed['id'][0]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def add_batch()
|
|
65
|
+
keys = @@records.first.keys
|
|
66
|
+
|
|
67
|
+
output_csv = keys.to_csv
|
|
68
|
+
|
|
69
|
+
@@records.each do |r|
|
|
70
|
+
fields = Array.new
|
|
71
|
+
keys.each do |k|
|
|
72
|
+
fields.push(r[k])
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
row_csv = fields.to_csv
|
|
76
|
+
output_csv += row_csv
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
path = "job/#{@@job_id}/batch/"
|
|
80
|
+
headers = Hash["Content-Type" => "text/csv; charset=UTF-8"]
|
|
81
|
+
|
|
82
|
+
response = @@connection.post_xml(nil, path, output_csv, headers)
|
|
83
|
+
response_parsed = XmlSimple.xml_in(response)
|
|
84
|
+
|
|
85
|
+
@@batch_id = response_parsed['id'][0]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def check_batch_status()
|
|
89
|
+
path = "job/#{@@job_id}/batch/#{@@batch_id}"
|
|
90
|
+
headers = Hash.new
|
|
91
|
+
|
|
92
|
+
response = @@connection.get_request(nil, path, headers)
|
|
93
|
+
response_parsed = XmlSimple.xml_in(response)
|
|
94
|
+
|
|
95
|
+
begin
|
|
96
|
+
#puts "check: #{response_parsed.inspect}\n"
|
|
97
|
+
response_parsed['state'][0]
|
|
98
|
+
rescue Exception => e
|
|
99
|
+
#puts "check: #{response_parsed.inspect}\n"
|
|
100
|
+
|
|
101
|
+
nil
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def get_batch_result()
|
|
106
|
+
path = "job/#{@@job_id}/batch/#{@@batch_id}/result"
|
|
107
|
+
headers = Hash["Content-Type" => "text/xml; charset=UTF-8"]
|
|
108
|
+
|
|
109
|
+
response = @@connection.get_request(nil, path, headers)
|
|
110
|
+
|
|
111
|
+
if(@@operation == "query") # The query op requires us to do another request to get the results
|
|
112
|
+
response_parsed = XmlSimple.xml_in(response)
|
|
113
|
+
result_id = response_parsed["result"][0]
|
|
114
|
+
|
|
115
|
+
path = "job/#{@@job_id}/batch/#{@@batch_id}/result/#{result_id}"
|
|
116
|
+
headers = Hash.new
|
|
117
|
+
headers = Hash["Content-Type" => "text/xml; charset=UTF-8"]
|
|
118
|
+
|
|
119
|
+
response = @@connection.get_request(nil, path, headers)
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
parse_results response
|
|
124
|
+
|
|
125
|
+
response = response.lines.to_a[1..-1].join
|
|
126
|
+
# csvRows = CSV.parse(response, :headers => true)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def parse_results response
|
|
130
|
+
@result.success = true
|
|
131
|
+
@result.raw = response.lines.to_a[1..-1].join
|
|
132
|
+
csvRows = CSV.parse(response, :headers => true)
|
|
133
|
+
|
|
134
|
+
csvRows.each_with_index do |row, index|
|
|
135
|
+
if @@operation != "query"
|
|
136
|
+
row["Created"] = row["Created"] == "true" ? true : false
|
|
137
|
+
row["Success"] = row["Success"] == "true" ? true : false
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
@result.records.push row
|
|
141
|
+
if row["Success"] == false
|
|
142
|
+
@result.success = false
|
|
143
|
+
@result.errors.push({"#{index}" => row["Error"]}) if row["Error"]
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
@result.message = "The job has been closed."
|
|
148
|
+
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
class JobResult
|
|
154
|
+
attr_writer :errors, :success, :records, :raw, :message
|
|
155
|
+
attr_reader :errors, :success, :records, :raw, :message
|
|
156
|
+
|
|
157
|
+
def initialize
|
|
158
|
+
@errors = []
|
|
159
|
+
@success = nil
|
|
160
|
+
@records = []
|
|
161
|
+
@raw = nil
|
|
162
|
+
@message = 'The job has been queued.'
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def success?
|
|
166
|
+
@success
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def has_errors?
|
|
170
|
+
@errors.count > 0
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'net/https'
|
|
2
|
+
require 'xmlsimple'
|
|
3
|
+
require 'csv'
|
|
4
|
+
require "salesforce_bulk/version"
|
|
5
|
+
require 'salesforce_bulk/job'
|
|
6
|
+
require 'salesforce_bulk/connection'
|
|
7
|
+
|
|
8
|
+
module SalesforceBulk
|
|
9
|
+
# Your code goes here...
|
|
10
|
+
class Api
|
|
11
|
+
|
|
12
|
+
@@SALESFORCE_API_VERSION = '24.0'
|
|
13
|
+
|
|
14
|
+
def initialize(username, password, in_sandbox=false)
|
|
15
|
+
@connection = SalesforceBulk::Connection.new(username, password, @@SALESFORCE_API_VERSION, in_sandbox)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def upsert(sobject, records, external_field, wait=false)
|
|
19
|
+
self.do_operation('upsert', sobject, records, external_field, wait)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def update(sobject, records, wait=false)
|
|
23
|
+
self.do_operation('update', sobject, records, nil, wait)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def create(sobject, records, wait=false)
|
|
27
|
+
self.do_operation('insert', sobject, records, nil, wait)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def delete(sobject, records, wait=false)
|
|
31
|
+
self.do_operation('delete', sobject, records, nil, wait)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def query(sobject, query)
|
|
35
|
+
self.do_operation('query', sobject, query, nil)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def do_operation(operation, sobject, records, external_field, wait=false)
|
|
39
|
+
job = SalesforceBulk::Job.new(operation, sobject, records, external_field, @connection)
|
|
40
|
+
|
|
41
|
+
# TODO: put this in one function
|
|
42
|
+
job_id = job.create_job()
|
|
43
|
+
if(operation == "query")
|
|
44
|
+
batch_id = job.add_query()
|
|
45
|
+
else
|
|
46
|
+
batch_id = job.add_batch()
|
|
47
|
+
end
|
|
48
|
+
job.close_job()
|
|
49
|
+
|
|
50
|
+
if wait or operation == 'query'
|
|
51
|
+
while true
|
|
52
|
+
state = job.check_batch_status()
|
|
53
|
+
if state != "Queued" && state != "InProgress"
|
|
54
|
+
break
|
|
55
|
+
end
|
|
56
|
+
sleep(2) # wait x seconds and check again
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
if state == 'Completed'
|
|
60
|
+
job.get_batch_result()
|
|
61
|
+
job
|
|
62
|
+
else
|
|
63
|
+
job.result.message = "There is an error in your job. The response returned a state of #{state}. Please check your query/parameters and try again."
|
|
64
|
+
job.result.success = false
|
|
65
|
+
return job
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
else
|
|
69
|
+
return job
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def parse_batch_result result
|
|
75
|
+
begin
|
|
76
|
+
CSV.parse(result, :headers => true)
|
|
77
|
+
rescue
|
|
78
|
+
result
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end # End class
|
|
83
|
+
end # End module
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "salesforce_bulk/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "salesforce_bulk_quickfix"
|
|
7
|
+
s.version = SalesforceBulk::VERSION
|
|
8
|
+
s.authors = ["Jorge Valdivia, John Ryan"]
|
|
9
|
+
s.email = ["jorge@valdivia.me;johnny@patchapps.com"]
|
|
10
|
+
s.homepage = "https://github.com/jorgevaldivia/salesforce_bulk"
|
|
11
|
+
s.summary = %q{Ruby support for the Salesforce Bulk API}
|
|
12
|
+
s.description = %q{This gem provides a super simple interface for the Salesforce Bulk API. It provides support for insert, update, upsert, delete, and query.}
|
|
13
|
+
|
|
14
|
+
s.rubyforge_project = "salesforce_bulk_quickfix"
|
|
15
|
+
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
|
+
s.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
# specify any dependencies here; for example:
|
|
22
|
+
# s.add_development_dependency "rspec"
|
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
|
24
|
+
|
|
25
|
+
s.add_dependency "xml-simple"
|
|
26
|
+
|
|
27
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: salesforce_bulk_quickfix
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Jorge Valdivia, John Ryan
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-06-17 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: xml-simple
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
30
|
+
description: This gem provides a super simple interface for the Salesforce Bulk API.
|
|
31
|
+
It provides support for insert, update, upsert, delete, and query.
|
|
32
|
+
email:
|
|
33
|
+
- jorge@valdivia.me;johnny@patchapps.com
|
|
34
|
+
executables: []
|
|
35
|
+
extensions: []
|
|
36
|
+
extra_rdoc_files: []
|
|
37
|
+
files:
|
|
38
|
+
- .gitignore
|
|
39
|
+
- Gemfile
|
|
40
|
+
- README.rdoc
|
|
41
|
+
- Rakefile
|
|
42
|
+
- lib/salesforce_bulk.rb
|
|
43
|
+
- lib/salesforce_bulk/connection.rb
|
|
44
|
+
- lib/salesforce_bulk/job.rb
|
|
45
|
+
- lib/salesforce_bulk/version.rb
|
|
46
|
+
- salesforce_bulk.gemspec
|
|
47
|
+
homepage: https://github.com/jorgevaldivia/salesforce_bulk
|
|
48
|
+
licenses: []
|
|
49
|
+
post_install_message:
|
|
50
|
+
rdoc_options: []
|
|
51
|
+
require_paths:
|
|
52
|
+
- lib
|
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
|
+
none: false
|
|
55
|
+
requirements:
|
|
56
|
+
- - ! '>='
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '0'
|
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
|
+
none: false
|
|
61
|
+
requirements:
|
|
62
|
+
- - ! '>='
|
|
63
|
+
- !ruby/object:Gem::Version
|
|
64
|
+
version: '0'
|
|
65
|
+
requirements: []
|
|
66
|
+
rubyforge_project: salesforce_bulk_quickfix
|
|
67
|
+
rubygems_version: 1.8.24
|
|
68
|
+
signing_key:
|
|
69
|
+
specification_version: 3
|
|
70
|
+
summary: Ruby support for the Salesforce Bulk API
|
|
71
|
+
test_files: []
|
|
72
|
+
has_rdoc:
|