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.
@@ -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
@@ -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
@@ -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
@@ -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-2013 Ian Dees and contributors
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 << ['hpricot', '~> 0.8']
19
- self.extra_dev_deps << ['nokogiri', '~> 1.5']
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
@@ -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
@@ -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
- # Connect to the server securely. If you pass an oauth hash, it
48
- # must contain the keys :consumer_key, :consumer_secret,
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
- def initialize(url, sid = nil, oauth = nil, proxy = nil)
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
- init_server(url)
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
- def init_server(url)
69
- @url = URI.parse(url)
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
- call_remote(:login, [:username, user, :password, password])
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
- response = connect(user, password)
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 = response[:loginResponse][: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
- init_server(result[:serverUrl])
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
- result = @server.post \
128
- @oauth[:login_url],
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 = REXML::Document.new result.body
118
+ doc = REXML::Document.new result.body
135
119
  @session_id = doc.elements['*/sessionId'].text
136
- server_url = doc.elements['*/serverUrl'].text
137
- init_server server_url
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 => @sessionId, :serverUrl => server_url}
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", @url.path]
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
- login(@user, @password)
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)
@@ -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(:SoapResponseHpricot) rescue nil) ||
10
+ (RForce::const_get(:SoapResponseExpat) rescue nil) ||
13
11
  SoapResponseRexml
14
12
  end
@@ -1,3 +1,3 @@
1
1
  module RForce
2
- VERSION = '0.11'
2
+ VERSION = '0.12'
3
3
  end
@@ -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, :hpricot, :nokogiri].each do |processor|
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
- pending 'expat not installed' unless @expat_recs
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 = '&lt;tag attr=&quot;Bee&apos;s knees &amp; toes&quot;&gt;'
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
- describe 'SoapResponseNokogiri' do
217
- it_behaves_like 'a SOAP response' do
218
- let(:klass) { SoapResponseNokogiri }
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>
@@ -7,7 +7,6 @@ task :timing do
7
7
 
8
8
  [:SoapResponseRexml,
9
9
  :SoapResponseExpat,
10
- :SoapResponseHpricot,
11
10
  :SoapResponseNokogiri].each do |name|
12
11
  begin
13
12
  klass = RForce.const_get name
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.11'
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: 2013-06-08 00:00:00.000000000 Z
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: rspec
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: '2.8'
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: '2.8'
54
+ version: '4.0'
62
55
  - !ruby/object:Gem::Dependency
63
- name: hoe-gemspec2
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: '1.1'
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: '1.1'
68
+ version: '2.8'
78
69
  - !ruby/object:Gem::Dependency
79
- name: hpricot
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: '0.8'
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: '0.8'
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: '2.13'
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: '2.13'
158
- description: ! 'RForce is a simple, usable binding to the Salesforce API.
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.rubyforge.org
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.txt
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: rforce
212
- rubygems_version: 1.8.21
181
+ rubyforge_project:
182
+ rubygems_version: 2.0.14
213
183
  signing_key:
214
- specification_version: 3
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("&apos;", "'")
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