rforce 0.11 → 0.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|