rforce 0.11 → 0.12
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.
- checksums.yaml +7 -0
- data/History.txt +9 -0
- data/Manifest.txt +3 -1
- data/README.rdoc +3 -4
- data/Rakefile +6 -3
- data/examples/oauth_setup.rb +26 -0
- data/examples/oauth_use.rb +25 -0
- data/examples/simple.rb +20 -0
- data/lib/rforce/binding.rb +85 -59
- data/lib/rforce/soap_response.rb +1 -3
- data/lib/rforce/version.rb +1 -1
- data/spec/rforce_spec.rb +7 -25
- data/tasks/timing.rake +0 -1
- metadata +30 -60
- data/lib/rforce/soap_response_hpricot.rb +0 -90
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0f5d3cfdef0e31e56d1bc1d770e79f26323d0a6c
|
4
|
+
data.tar.gz: a73f9b20c24d37ba4a3a68b2c43e16a1d9204822
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 861c42017d1f723532b074fef3e400e843f1fcf20e4da5448add773a769c02dc2c6ce17f2fc24d7eb009a44015e944f5297d8c55b8306dcbb71dc076b9004359
|
7
|
+
data.tar.gz: baa7d21e2f81675213086da031bb0eca550658d3a9625f94f9a7e820fa4c51bc4a620804356fa8f00dd8688c6537b7d4fa4133a47ad8ee9f8d7c156e26a4e2d3
|
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 0.12.0 2014-07-27
|
2
|
+
* 2 enhancements
|
3
|
+
* Clearer errors when skipping login (Victor Stan)
|
4
|
+
* Allow passing in an optional logger (Jeff Jolma)
|
5
|
+
* 3 bug fixes
|
6
|
+
* Fixed URL error in OAuth flow (reported by karthickbabuos)
|
7
|
+
* Corrected UTF-8 handling error (Maxime Rety)
|
8
|
+
* Fixed repeat login issue (Jeff Jolma)
|
9
|
+
|
1
10
|
== 0.11.0 2013-06-08
|
2
11
|
* 1 minor enhancement
|
3
12
|
* Give the README an .rdoc extension for easy Github viewing
|
data/Manifest.txt
CHANGED
@@ -2,13 +2,15 @@ History.txt
|
|
2
2
|
Manifest.txt
|
3
3
|
README.rdoc
|
4
4
|
Rakefile
|
5
|
+
examples/oauth_setup.rb
|
6
|
+
examples/oauth_use.rb
|
7
|
+
examples/simple.rb
|
5
8
|
lib/rforce.rb
|
6
9
|
lib/rforce/binding.rb
|
7
10
|
lib/rforce/method_keys.rb
|
8
11
|
lib/rforce/soap_pullable.rb
|
9
12
|
lib/rforce/soap_response.rb
|
10
13
|
lib/rforce/soap_response_expat.rb
|
11
|
-
lib/rforce/soap_response_hpricot.rb
|
12
14
|
lib/rforce/soap_response_nokogiri.rb
|
13
15
|
lib/rforce/soap_response_rexml.rb
|
14
16
|
lib/rforce/version.rb
|
data/README.rdoc
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
= rforce
|
2
2
|
|
3
|
-
* http://rforce.rubyforge.org
|
4
|
-
* http://rubyforge.org/projects/rforce
|
5
|
-
* http://bitbucket.org/undees/rforce
|
6
3
|
* http://github.com/undees/rforce
|
4
|
+
* http://bitbucket.org/undees/rforce
|
5
|
+
* http://rdoc.info/github/undees/rforce
|
7
6
|
|
8
7
|
== DESCRIPTION:
|
9
8
|
|
@@ -75,7 +74,7 @@ Rather than enforcing adherence to the sforce.com schema, RForce assumes you are
|
|
75
74
|
|
76
75
|
== LICENSE:
|
77
76
|
|
78
|
-
Copyright (c) 2005-
|
77
|
+
Copyright (c) 2005-2014 Ian Dees and contributors
|
79
78
|
|
80
79
|
Permission is hereby granted, free of charge, to any person obtaining
|
81
80
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
@@ -8,16 +8,19 @@ require 'hoe/gemspec2'
|
|
8
8
|
Hoe.plugin :gemspec2
|
9
9
|
|
10
10
|
Hoe.spec 'rforce' do
|
11
|
+
is_jruby = (RUBY_PLATFORM == 'java')
|
12
|
+
is_ruby18 = (RUBY_VERSION =~ /^1.8/)
|
13
|
+
|
11
14
|
developer('Ian Dees', 'undees@gmail.com')
|
15
|
+
license('MIT')
|
12
16
|
|
13
17
|
self.extra_deps << ['builder', '~> 3.0']
|
14
18
|
self.extra_deps << ['oauth', '~> 0.4']
|
15
19
|
|
16
20
|
self.extra_dev_deps << ['rspec', '~> 2.8']
|
17
21
|
self.extra_dev_deps << ['hoe-gemspec2', '~> 1.1']
|
18
|
-
self.extra_dev_deps << ['
|
19
|
-
self.extra_dev_deps << ['
|
20
|
-
self.extra_dev_deps << ['xmlparser', '~> 0.7']
|
22
|
+
self.extra_dev_deps << ['nokogiri', '~> 1.5'] unless is_ruby18
|
23
|
+
self.extra_dev_deps << ['xmlparser', '~> 0.7'] unless is_jruby
|
21
24
|
|
22
25
|
self.rdoc_locations = ['undees@rforce.rubyforge.org:/var/www/gforge-projects/rforce']
|
23
26
|
self.remote_rdoc_dir = ''
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'oauth'
|
2
|
+
|
3
|
+
consumer_key = ENV['SALESFORCE_CONSUMER_KEY']
|
4
|
+
consumer_secret = ENV['SALESFORCE_CONSUMER_SECRET']
|
5
|
+
|
6
|
+
oauth_options = {
|
7
|
+
:site => 'https://login.salesforce.com',
|
8
|
+
:scheme => :body,
|
9
|
+
:request_token_path => '/_nc_external/system/security/oauth/RequestTokenHandler',
|
10
|
+
:authorize_path => '/setup/secur/RemoteAccessAuthorizationPage.apexp',
|
11
|
+
:access_token_path => '/_nc_external/system/security/oauth/AccessTokenHandler',
|
12
|
+
}
|
13
|
+
|
14
|
+
consumer = OAuth::Consumer.new consumer_key, consumer_secret, oauth_options
|
15
|
+
# consumer.http.set_debug_output STDERR # if you're curious
|
16
|
+
|
17
|
+
request = consumer.get_request_token
|
18
|
+
authorize_url = request.authorize_url :oauth_consumer_key => consumer_key
|
19
|
+
|
20
|
+
puts "Go to #{authorize_url} in your browser, then enter the verification code:"
|
21
|
+
verification_code = gets.strip
|
22
|
+
|
23
|
+
access = request.get_access_token :oauth_verifier => verification_code
|
24
|
+
|
25
|
+
puts "Access Token: " + access.token
|
26
|
+
puts "Access Secret: " + access.secret
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rforce'
|
2
|
+
|
3
|
+
oauth = {
|
4
|
+
:consumer_key => ENV['SALESFORCE_CONSUMER_KEY'],
|
5
|
+
:consumer_secret => ENV['SALESFORCE_CONSUMER_SECRET'],
|
6
|
+
:access_token => ENV['SALESFORCE_ACCESS_TOKEN'],
|
7
|
+
:access_secret => ENV['SALESFORCE_ACCESS_SECRET'],
|
8
|
+
:login_url => 'https://login.salesforce.com/services/OAuth/u/20.0'
|
9
|
+
}
|
10
|
+
|
11
|
+
binding = RForce::Binding.new \
|
12
|
+
'https://www.salesforce.com/services/Soap/u/20.0',
|
13
|
+
nil,
|
14
|
+
oauth
|
15
|
+
|
16
|
+
binding.login_with_oauth
|
17
|
+
|
18
|
+
answer = binding.search \
|
19
|
+
:searchString =>
|
20
|
+
'find {McFakerson Co} in name fields returning account(id)'
|
21
|
+
|
22
|
+
account = answer.searchResponse.result.searchRecords.record
|
23
|
+
account_id = account.Id
|
24
|
+
|
25
|
+
puts account_id
|
data/examples/simple.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rforce'
|
2
|
+
|
3
|
+
email = ENV['SALESFORCE_USER']
|
4
|
+
password = ENV['SALESFORCE_PASS']
|
5
|
+
token = ENV['SALESFORCE_TOKEN']
|
6
|
+
|
7
|
+
binding = RForce::Binding.new \
|
8
|
+
'https://www.salesforce.com/services/Soap/u/20.0'
|
9
|
+
|
10
|
+
binding.login \
|
11
|
+
email, password + token
|
12
|
+
|
13
|
+
answer = binding.search \
|
14
|
+
:searchString =>
|
15
|
+
'find {McFakerson Co} in name fields returning account(id)'
|
16
|
+
|
17
|
+
account = answer.searchResponse.result.searchRecords.record
|
18
|
+
account_id = account.Id
|
19
|
+
|
20
|
+
puts account_id
|
data/lib/rforce/binding.rb
CHANGED
@@ -44,99 +44,87 @@ module RForce
|
|
44
44
|
MruHeader = '<partner:MruHeader soap:mustUnderstand="1"><partner:updateMru>true</partner:updateMru></partner:MruHeader>'
|
45
45
|
ClientIdHeader = '<partner:CallOptions soap:mustUnderstand="1"><partner:client>%s</partner:client></partner:CallOptions>'
|
46
46
|
|
47
|
-
#
|
48
|
-
#
|
47
|
+
# Create a binding to the server (after which you can call login
|
48
|
+
# or login_with_oauth to connect to it). If you pass an oauth
|
49
|
+
# hash, it must contain the keys :consumer_key, :consumer_secret,
|
49
50
|
# :access_token, :access_secret, and :login_url.
|
50
51
|
#
|
51
52
|
# proxy may be a URL of the form http://user:pass@example.com:port
|
52
53
|
#
|
53
|
-
|
54
|
+
# if a logger is specified, it will be used for very verbose SOAP logging
|
55
|
+
#
|
56
|
+
def initialize(url, sid = nil, oauth = nil, proxy = nil, logger = nil)
|
54
57
|
@session_id = sid
|
55
58
|
@oauth = oauth
|
56
59
|
@proxy = proxy
|
57
60
|
@batch_size = DEFAULT_BATCH_SIZE
|
58
|
-
|
59
|
-
|
61
|
+
@logger = logger
|
62
|
+
@url = URI.parse(url)
|
60
63
|
end
|
61
64
|
|
62
|
-
|
63
65
|
def show_debug
|
64
66
|
ENV['SHOWSOAP'] == 'true'
|
65
67
|
end
|
66
68
|
|
69
|
+
def create_server(url)
|
70
|
+
server = Net::HTTP.Proxy(@proxy).new(url.host, url.port)
|
71
|
+
server.use_ssl = (url.scheme == 'https')
|
72
|
+
server.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
67
73
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
if (@oauth)
|
72
|
-
consumer = OAuth::Consumer.new \
|
73
|
-
@oauth[:consumer_key],
|
74
|
-
@oauth[:consumer_secret],
|
75
|
-
{
|
76
|
-
:site => url,
|
77
|
-
:proxy => @proxy
|
78
|
-
}
|
79
|
-
|
80
|
-
consumer.http.set_debug_output $stderr if show_debug
|
81
|
-
|
82
|
-
@server = OAuth::AccessToken.new \
|
83
|
-
consumer,
|
84
|
-
@oauth[:access_token],
|
85
|
-
@oauth[:access_secret]
|
86
|
-
|
87
|
-
class << @server
|
88
|
-
alias_method :post2, :post
|
89
|
-
end
|
90
|
-
else
|
91
|
-
@server = Net::HTTP.Proxy(@proxy).new(@url.host, @url.port)
|
92
|
-
@server.use_ssl = @url.scheme == 'https'
|
93
|
-
@server.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
94
|
-
|
95
|
-
# run ruby with -d or env variable SHOWSOAP=true to see SOAP wiredumps.
|
96
|
-
@server.set_debug_output $stderr if show_debug
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# Connect to remote server
|
101
|
-
#
|
102
|
-
def connect(user, password)
|
103
|
-
@user = user
|
104
|
-
@password = password
|
74
|
+
# run ruby with -d or env variable SHOWSOAP=true to see SOAP wiredumps.
|
75
|
+
server.set_debug_output $stderr if show_debug
|
105
76
|
|
106
|
-
|
77
|
+
return server
|
107
78
|
end
|
108
79
|
|
109
80
|
# Log in to the server with a user name and password, remembering
|
110
81
|
# the session ID returned to us by Salesforce.
|
111
82
|
def login(user, password)
|
112
|
-
|
83
|
+
@user = user
|
84
|
+
@password = password
|
85
|
+
@server = create_server(@url)
|
86
|
+
response = call_remote(:login, [:username, user, :password, password])
|
113
87
|
|
114
88
|
raise "Incorrect user name / password [#{response.Fault}]" unless response.loginResponse
|
115
89
|
|
116
|
-
result
|
90
|
+
result = response[:loginResponse][:result]
|
117
91
|
@session_id = result[:sessionId]
|
92
|
+
@url = URI.parse(result[:serverUrl])
|
93
|
+
@server = create_server(@url)
|
118
94
|
|
119
|
-
|
120
|
-
|
121
|
-
response
|
95
|
+
return response
|
122
96
|
end
|
123
97
|
|
124
98
|
# Log in to the server with OAuth, remembering
|
125
99
|
# the session ID returned to us by Salesforce.
|
126
100
|
def login_with_oauth
|
127
|
-
|
128
|
-
@oauth[:
|
101
|
+
consumer = OAuth::Consumer.new \
|
102
|
+
@oauth[:consumer_key],
|
103
|
+
@oauth[:consumer_secret]
|
104
|
+
|
105
|
+
access = OAuth::AccessToken.new \
|
106
|
+
consumer, @oauth[:access_token],
|
107
|
+
@oauth[:access_secret]
|
108
|
+
|
109
|
+
login_url = @oauth[:login_url]
|
110
|
+
|
111
|
+
result = access.post \
|
112
|
+
login_url,
|
129
113
|
'',
|
130
114
|
{'content-type' => 'application/x-www-form-urlencoded'}
|
131
115
|
|
132
116
|
case result
|
133
117
|
when Net::HTTPSuccess
|
134
|
-
doc
|
118
|
+
doc = REXML::Document.new result.body
|
135
119
|
@session_id = doc.elements['*/sessionId'].text
|
136
|
-
|
137
|
-
|
120
|
+
@url = URI.parse(doc.elements['*/serverUrl'].text)
|
121
|
+
@server = access
|
122
|
+
|
123
|
+
class << @server
|
124
|
+
alias_method :post2, :post
|
125
|
+
end
|
138
126
|
|
139
|
-
return {:sessionId => @
|
127
|
+
return {:sessionId => @session_id, :serverUrl => @url.to_s}
|
140
128
|
when Net::HTTPUnauthorized
|
141
129
|
raise 'Invalid OAuth tokens'
|
142
130
|
else
|
@@ -148,8 +136,11 @@ module RForce
|
|
148
136
|
# a hash or (if order is important) an array of alternating
|
149
137
|
# keys and values.
|
150
138
|
def call_remote(method, args)
|
139
|
+
# Different URI requirements for regular vs. OAuth. This is
|
140
|
+
# *screaming* for a refactor.
|
141
|
+
fallback_soap_url = @oauth ? @url.to_s : @url.path
|
151
142
|
|
152
|
-
urn, soap_url = block_given? ? yield : ["urn:partner.soap.sforce.com",
|
143
|
+
urn, soap_url = block_given? ? yield : ["urn:partner.soap.sforce.com", fallback_soap_url]
|
153
144
|
|
154
145
|
# Create XML text from the arguments.
|
155
146
|
expanded = ''
|
@@ -181,6 +172,7 @@ module RForce
|
|
181
172
|
# Fill in the blanks of the SOAP envelope with our
|
182
173
|
# session ID and the expanded XML of our request.
|
183
174
|
request = (Envelope % [@session_id, extra_headers, expanded])
|
175
|
+
@logger && @logger.info("RForce request: #{request}")
|
184
176
|
|
185
177
|
# reset the batch size for the next request
|
186
178
|
@batch_size = DEFAULT_BATCH_SIZE
|
@@ -201,14 +193,23 @@ module RForce
|
|
201
193
|
end
|
202
194
|
|
203
195
|
# Send the request to the server and read the response.
|
196
|
+
@logger && @logger.info("RForce request to host #{@server} url #{soap_url} headers: #{headers}")
|
204
197
|
response = @server.post2(soap_url, request.lstrip, headers)
|
205
198
|
|
206
199
|
# decode if we have encoding
|
207
200
|
content = decode(response)
|
208
201
|
|
202
|
+
# Fix charset encoding. Needed because the "content" variable may contain a UTF-8
|
203
|
+
# or ISO-8859-1 string, but is carrying the US-ASCII encoding.
|
204
|
+
content = fix_encoding(content)
|
205
|
+
|
209
206
|
# Check to see if INVALID_SESSION_ID was raised and try to relogin in
|
210
207
|
if method != :login and @session_id and content =~ /sf:INVALID_SESSION_ID/
|
211
|
-
|
208
|
+
if @user
|
209
|
+
login(@user, @password)
|
210
|
+
else
|
211
|
+
raise "INVALID_SESSION_ID"
|
212
|
+
end
|
212
213
|
|
213
214
|
# repackage and rencode request with the new session id
|
214
215
|
request = (Envelope % [@session_id, extra_headers, expanded])
|
@@ -218,12 +219,16 @@ module RForce
|
|
218
219
|
response = @server.post2(soap_url, request.lstrip, headers)
|
219
220
|
|
220
221
|
content = decode(response)
|
222
|
+
|
223
|
+
# Fix charset encoding. Needed because the "content" variable may contain a UTF-8
|
224
|
+
# or ISO-8859-1 string, but is carrying the US-ASCII encoding.
|
225
|
+
content = fix_encoding(content)
|
221
226
|
end
|
222
227
|
|
228
|
+
@logger && @logger.info("RForce response: #{content}")
|
223
229
|
SoapResponse.new(content).parse
|
224
230
|
end
|
225
231
|
|
226
|
-
|
227
232
|
# decode gzip
|
228
233
|
def decode(response)
|
229
234
|
encoding = response['Content-Encoding']
|
@@ -246,7 +251,6 @@ module RForce
|
|
246
251
|
end
|
247
252
|
end
|
248
253
|
|
249
|
-
|
250
254
|
# encode gzip
|
251
255
|
def encode(request)
|
252
256
|
return request if show_debug
|
@@ -261,6 +265,28 @@ module RForce
|
|
261
265
|
end
|
262
266
|
end
|
263
267
|
|
268
|
+
# fix invalid US-ASCII strings by applying the correct encoding on ruby 1.9+
|
269
|
+
def fix_encoding(string)
|
270
|
+
if [:valid_encoding?, :force_encoding].all? { |m| string.respond_to?(m) }
|
271
|
+
if !string.valid_encoding?
|
272
|
+
# The 2 possible encodings in responses are UTF-8 and ISO-8859-1
|
273
|
+
# http://www.salesforce.com/us/developer/docs/api/Content/implementation_considerations.htm#topic-title_international
|
274
|
+
#
|
275
|
+
["UTF-8", "ISO-8859-1"].each do |encoding_name|
|
276
|
+
|
277
|
+
s = string.dup.force_encoding(encoding_name)
|
278
|
+
|
279
|
+
if s.valid_encoding?
|
280
|
+
return s
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
raise "Invalid encoding in SOAP response: not in [US-ASCII, UTF-8, ISO-8859-1]"
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
return string
|
289
|
+
end
|
264
290
|
|
265
291
|
# Turns method calls on this object into remote SOAP calls.
|
266
292
|
def method_missing(method, *args)
|
data/lib/rforce/soap_response.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
begin; require 'rforce/soap_response_nokogiri'; rescue LoadError; end
|
2
|
-
begin; require 'rforce/soap_response_hpricot'; rescue LoadError; end
|
3
2
|
begin; require 'rforce/soap_response_expat'; rescue LoadError; end
|
4
3
|
require 'rforce/soap_response_rexml'
|
5
4
|
|
@@ -7,8 +6,7 @@ require 'rforce/soap_response_rexml'
|
|
7
6
|
module RForce
|
8
7
|
# Use the fastest XML parser available.
|
9
8
|
SoapResponse =
|
10
|
-
(RForce::const_get(:SoapResponseExpat) rescue nil) ||
|
11
9
|
(RForce::const_get(:SoapResponseNokogiri) rescue nil) ||
|
12
|
-
(RForce::const_get(:
|
10
|
+
(RForce::const_get(:SoapResponseExpat) rescue nil) ||
|
13
11
|
SoapResponseRexml
|
14
12
|
end
|
data/lib/rforce/version.rb
CHANGED
data/spec/rforce_spec.rb
CHANGED
@@ -60,7 +60,7 @@ describe 'a SoapResponse implementation' do
|
|
60
60
|
fname = File.join(File.dirname(__FILE__), 'soap-response.xml')
|
61
61
|
@contents = File.open(fname) {|f| f.read}
|
62
62
|
|
63
|
-
[:rexml, :expat, :
|
63
|
+
[:rexml, :expat, :nokogiri].each do |processor|
|
64
64
|
name = "SoapResponse#{processor.to_s.capitalize}".to_sym
|
65
65
|
variable = "@#{processor}_recs".to_sym
|
66
66
|
|
@@ -82,14 +82,10 @@ describe 'a SoapResponse implementation' do
|
|
82
82
|
|
83
83
|
# Special-case expat tests for CI
|
84
84
|
it 'returns the same results with expat' do
|
85
|
-
|
85
|
+
skip 'expat not installed' unless @expat_recs
|
86
86
|
@expat_recs.should == @rexml_recs
|
87
87
|
end
|
88
88
|
|
89
|
-
it 'returns the same results with hpricot' do
|
90
|
-
@hpricot_recs.should == @rexml_recs
|
91
|
-
end
|
92
|
-
|
93
89
|
it 'understands XML entities' do
|
94
90
|
expected = "Bee's knees"
|
95
91
|
@rexml_recs.first.Description.should == expected
|
@@ -98,16 +94,6 @@ describe 'a SoapResponse implementation' do
|
|
98
94
|
if @expat_recs
|
99
95
|
@expat_recs.first.Description.should == expected
|
100
96
|
end
|
101
|
-
|
102
|
-
@hpricot_recs.first.Description.should == expected
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
describe 'SoapResponseHpricot' do
|
107
|
-
it 'parses basic XML entities' do
|
108
|
-
text = '<tag attr="Bee's knees & toes">'
|
109
|
-
SoapResponseHpricot.unescapeXML(text).should ==
|
110
|
-
%q(<tag attr="Bee's knees & toes">)
|
111
97
|
end
|
112
98
|
end
|
113
99
|
|
@@ -213,9 +199,11 @@ shared_examples_for 'a SOAP response' do
|
|
213
199
|
end
|
214
200
|
end
|
215
201
|
|
216
|
-
|
217
|
-
|
218
|
-
|
202
|
+
if RForce.const_defined? :SoapResponseNokogiri
|
203
|
+
describe 'SoapResponseNokogiri' do
|
204
|
+
it_behaves_like 'a SOAP response' do
|
205
|
+
let(:klass) { SoapResponseNokogiri }
|
206
|
+
end
|
219
207
|
end
|
220
208
|
end
|
221
209
|
|
@@ -234,12 +222,6 @@ describe 'SoapResponseRexml' do
|
|
234
222
|
end
|
235
223
|
end
|
236
224
|
|
237
|
-
describe 'SoapResponseHpricot' do
|
238
|
-
it_behaves_like 'a SOAP response' do
|
239
|
-
let(:klass) { SoapResponseHpricot }
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
225
|
CreateXml = <<HERE.gsub(/\n\s*/, '')
|
244
226
|
<partner:create>
|
245
227
|
<partner:sObjects>
|
data/tasks/timing.rake
CHANGED
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rforce
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
5
|
-
prerelease:
|
4
|
+
version: '0.12'
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Ian Dees
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-07-28 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: builder
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: oauth
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,63 +34,55 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0.4'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
42
|
+
name: rdoc
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ~>
|
52
46
|
- !ruby/object:Gem::Version
|
53
|
-
version: '
|
47
|
+
version: '4.0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ~>
|
60
53
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
54
|
+
version: '4.0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
56
|
+
name: rspec
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ~>
|
68
60
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
61
|
+
version: '2.8'
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ~>
|
76
67
|
- !ruby/object:Gem::Version
|
77
|
-
version: '
|
68
|
+
version: '2.8'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
70
|
+
name: hoe-gemspec2
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - ~>
|
84
74
|
- !ruby/object:Gem::Version
|
85
|
-
version: '
|
75
|
+
version: '1.1'
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - ~>
|
92
81
|
- !ruby/object:Gem::Version
|
93
|
-
version: '
|
82
|
+
version: '1.1'
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: nokogiri
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
87
|
- - ~>
|
100
88
|
- !ruby/object:Gem::Version
|
@@ -102,7 +90,6 @@ dependencies:
|
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
94
|
- - ~>
|
108
95
|
- !ruby/object:Gem::Version
|
@@ -110,7 +97,6 @@ dependencies:
|
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: xmlparser
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
101
|
- - ~>
|
116
102
|
- !ruby/object:Gem::Version
|
@@ -118,47 +104,28 @@ dependencies:
|
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
108
|
- - ~>
|
124
109
|
- !ruby/object:Gem::Version
|
125
110
|
version: '0.7'
|
126
|
-
- !ruby/object:Gem::Dependency
|
127
|
-
name: rdoc
|
128
|
-
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
|
-
requirements:
|
131
|
-
- - ~>
|
132
|
-
- !ruby/object:Gem::Version
|
133
|
-
version: '3.10'
|
134
|
-
type: :development
|
135
|
-
prerelease: false
|
136
|
-
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
|
-
requirements:
|
139
|
-
- - ~>
|
140
|
-
- !ruby/object:Gem::Version
|
141
|
-
version: '3.10'
|
142
111
|
- !ruby/object:Gem::Dependency
|
143
112
|
name: hoe
|
144
113
|
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
114
|
requirements:
|
147
115
|
- - ~>
|
148
116
|
- !ruby/object:Gem::Version
|
149
|
-
version: '
|
117
|
+
version: '3.12'
|
150
118
|
type: :development
|
151
119
|
prerelease: false
|
152
120
|
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
121
|
requirements:
|
155
122
|
- - ~>
|
156
123
|
- !ruby/object:Gem::Version
|
157
|
-
version: '
|
158
|
-
description:
|
124
|
+
version: '3.12'
|
125
|
+
description: |-
|
126
|
+
RForce is a simple, usable binding to the Salesforce API.
|
159
127
|
|
160
|
-
|
161
|
-
{<img src="https://travis-ci.org/undees/rforce.png" />}[https://travis-ci.org/undees/rforce]'
|
128
|
+
{<img src="https://travis-ci.org/undees/rforce.png" />}[https://travis-ci.org/undees/rforce]
|
162
129
|
email:
|
163
130
|
- undees@gmail.com
|
164
131
|
executables: []
|
@@ -166,18 +133,21 @@ extensions: []
|
|
166
133
|
extra_rdoc_files:
|
167
134
|
- History.txt
|
168
135
|
- Manifest.txt
|
136
|
+
- README.rdoc
|
169
137
|
files:
|
170
138
|
- History.txt
|
171
139
|
- Manifest.txt
|
172
140
|
- README.rdoc
|
173
141
|
- Rakefile
|
142
|
+
- examples/oauth_setup.rb
|
143
|
+
- examples/oauth_use.rb
|
144
|
+
- examples/simple.rb
|
174
145
|
- lib/rforce.rb
|
175
146
|
- lib/rforce/binding.rb
|
176
147
|
- lib/rforce/method_keys.rb
|
177
148
|
- lib/rforce/soap_pullable.rb
|
178
149
|
- lib/rforce/soap_response.rb
|
179
150
|
- lib/rforce/soap_response_expat.rb
|
180
|
-
- lib/rforce/soap_response_hpricot.rb
|
181
151
|
- lib/rforce/soap_response_nokogiri.rb
|
182
152
|
- lib/rforce/soap_response_rexml.rb
|
183
153
|
- lib/rforce/version.rb
|
@@ -187,30 +157,30 @@ files:
|
|
187
157
|
- spec/spec_helper.rb
|
188
158
|
- tasks/timing.rake
|
189
159
|
- .gemtest
|
190
|
-
homepage: http://rforce
|
191
|
-
licenses:
|
160
|
+
homepage: http://github.com/undees/rforce
|
161
|
+
licenses:
|
162
|
+
- MIT
|
163
|
+
metadata: {}
|
192
164
|
post_install_message:
|
193
165
|
rdoc_options:
|
194
166
|
- --main
|
195
|
-
- README.
|
167
|
+
- README.rdoc
|
196
168
|
require_paths:
|
197
169
|
- lib
|
198
170
|
required_ruby_version: !ruby/object:Gem::Requirement
|
199
|
-
none: false
|
200
171
|
requirements:
|
201
|
-
- -
|
172
|
+
- - '>='
|
202
173
|
- !ruby/object:Gem::Version
|
203
174
|
version: '0'
|
204
175
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
205
|
-
none: false
|
206
176
|
requirements:
|
207
|
-
- -
|
177
|
+
- - '>='
|
208
178
|
- !ruby/object:Gem::Version
|
209
179
|
version: '0'
|
210
180
|
requirements: []
|
211
|
-
rubyforge_project:
|
212
|
-
rubygems_version:
|
181
|
+
rubyforge_project:
|
182
|
+
rubygems_version: 2.0.14
|
213
183
|
signing_key:
|
214
|
-
specification_version:
|
184
|
+
specification_version: 4
|
215
185
|
summary: RForce is a simple, usable binding to the Salesforce API
|
216
186
|
test_files: []
|
@@ -1,90 +0,0 @@
|
|
1
|
-
require 'hpricot'
|
2
|
-
require 'cgi'
|
3
|
-
|
4
|
-
|
5
|
-
module RForce
|
6
|
-
class SoapResponseHpricot
|
7
|
-
# Parses an XML string into structured data.
|
8
|
-
def initialize(content)
|
9
|
-
@content = content
|
10
|
-
end
|
11
|
-
|
12
|
-
# Digests an XML DOM node into nested Ruby types.
|
13
|
-
def parse
|
14
|
-
document = Hpricot.XML(@content)
|
15
|
-
node = document % 'soapenv:Body'
|
16
|
-
self.class.node_to_ruby node
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def self.unescapeXML(string)
|
22
|
-
CGI.unescapeHTML(string).gsub("'", "'")
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.node_to_ruby(node)
|
26
|
-
# Convert text nodes into simple strings.
|
27
|
-
children = (node.children || []).reject do |c|
|
28
|
-
c.is_a?(Hpricot::Text) && c.to_s.strip.empty?
|
29
|
-
end
|
30
|
-
|
31
|
-
if node.is_a?(Hpricot::Text)
|
32
|
-
return convert(SoapResponseHpricot.unescapeXML(node.inspect[1..-2]))
|
33
|
-
end
|
34
|
-
|
35
|
-
if children.first.is_a?(Hpricot::Text)
|
36
|
-
return convert(SoapResponseHpricot.unescapeXML(children.first.inspect[1..-2]))
|
37
|
-
end
|
38
|
-
|
39
|
-
# Convert nodes with children into MethodHashes.
|
40
|
-
elements = MethodHash.new
|
41
|
-
|
42
|
-
# Add all the element's children to the hash.
|
43
|
-
children.each do |e|
|
44
|
-
next if e.is_a?(Hpricot::Text) && e.to_s.strip.empty?
|
45
|
-
name = e.name
|
46
|
-
|
47
|
-
if name.include? ':'
|
48
|
-
name = name.split(':').last
|
49
|
-
end
|
50
|
-
|
51
|
-
name = name.to_sym
|
52
|
-
|
53
|
-
case elements[name]
|
54
|
-
# The most common case: unique child element tags.
|
55
|
-
when NilClass then
|
56
|
-
# <records> contents are always arrays
|
57
|
-
elements[name] = :records == name ? [node_to_ruby(e)] : node_to_ruby(e)
|
58
|
-
|
59
|
-
# Non-unique child elements become arrays:
|
60
|
-
|
61
|
-
# We've already created the array: just
|
62
|
-
# add the element.
|
63
|
-
when Array then
|
64
|
-
elements[name] << node_to_ruby(e)
|
65
|
-
|
66
|
-
# We haven't created the array yet: do so,
|
67
|
-
# then put the existing element in, followed
|
68
|
-
# by the new one.
|
69
|
-
else
|
70
|
-
next if :Id == name # avoid duplicate <Id> tags
|
71
|
-
elements[name] = [elements[name]]
|
72
|
-
elements[name] << node_to_ruby(e)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
return elements.empty? ? nil : elements
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.convert(string)
|
80
|
-
return nil if string.nil?
|
81
|
-
s = string.strip
|
82
|
-
|
83
|
-
case s
|
84
|
-
when '' then nil
|
85
|
-
when 'true', 'false' then ('true' == s)
|
86
|
-
else s
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|