rforce 0.4.1 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +11 -0
- data/Rakefile +2 -2
- data/lib/rforce/binding.rb +64 -21
- data/lib/rforce/soap_pullable.rb +2 -2
- data/lib/rforce/soap_response_expat.rb +2 -1
- data/lib/rforce/soap_response_hpricot.rb +1 -1
- data/lib/rforce/soap_response_rexml.rb +4 -3
- data/lib/rforce/version.rb +1 -1
- data/spec/rforce_spec.rb +22 -2
- metadata +47 -30
data/History.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
== 0.5.1 2010-12-11
|
2
|
+
|
3
|
+
* 2 minor enhancements:
|
4
|
+
* Increase batch size (Raymond Gao)
|
5
|
+
* Removed Facets dependency (Justin Ramos, Aaron Qian)
|
6
|
+
|
7
|
+
== 0.4.1 2010-03-21
|
8
|
+
|
9
|
+
* 1 minor enhancement:
|
10
|
+
* Experimental OAuth support
|
11
|
+
|
1
12
|
== 0.4 2010-01-21
|
2
13
|
|
3
14
|
* 1 minor enhancement:
|
data/Rakefile
CHANGED
@@ -8,8 +8,8 @@ require 'rforce/version'
|
|
8
8
|
|
9
9
|
Hoe.new('rforce', RForce::VERSION) do |p|
|
10
10
|
p.developer 'Ian Dees', 'undees@gmail.com'
|
11
|
-
p.extra_deps = [['builder', '
|
12
|
-
p.extra_dev_deps = [['rspec', '
|
11
|
+
p.extra_deps = [['builder', '~> 2.0']]
|
12
|
+
p.extra_dev_deps = [['rspec', '~> 1.3']]
|
13
13
|
p.remote_rdoc_dir = ''
|
14
14
|
p.rspec_options = ['-rubygems', '--options', 'spec/spec.opts']
|
15
15
|
end
|
data/lib/rforce/binding.rb
CHANGED
@@ -2,16 +2,19 @@ require 'net/https'
|
|
2
2
|
require 'uri'
|
3
3
|
require 'zlib'
|
4
4
|
require 'stringio'
|
5
|
+
require 'rexml/document'
|
5
6
|
require 'builder'
|
6
|
-
|
7
|
+
require 'oauth'
|
7
8
|
|
8
9
|
module RForce
|
9
10
|
# Implements the connection to the SalesForce server.
|
10
11
|
class Binding
|
11
12
|
include RForce
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
|
14
|
+
# Increase the maximum fetch size to 2000, as allowed by Salesforce
|
15
|
+
# Added by Raymond Gao
|
16
|
+
DEFAULT_BATCH_SIZE = 2000
|
17
|
+
attr_accessor :batch_size, :url, :assignment_rule_id, :use_default_rule, :update_mru, :client_id, :trigger_user_email,
|
15
18
|
:trigger_other_email, :trigger_auto_response_email
|
16
19
|
|
17
20
|
# Fill in the guts of this typical SOAP envelope
|
@@ -43,12 +46,15 @@ module RForce
|
|
43
46
|
MruHeader = '<partner:MruHeader soap:mustUnderstand="1"><partner:updateMru>true</partner:updateMru></partner:MruHeader>'
|
44
47
|
ClientIdHeader = '<partner:CallOptions soap:mustUnderstand="1"><partner:client>%s</partner:client></partner:CallOptions>'
|
45
48
|
|
46
|
-
# Connect to the server securely.
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
# Connect to the server securely. If you pass an oauth hash, it
|
50
|
+
# must contain the keys :consumer_key, :consumer_secret,
|
51
|
+
# :access_token, :access_secret, and :login_url.
|
52
|
+
def initialize(url, sid = nil, oauth = nil)
|
50
53
|
@session_id = sid
|
54
|
+
@oauth = oauth
|
51
55
|
@batch_size = DEFAULT_BATCH_SIZE
|
56
|
+
|
57
|
+
init_server(url)
|
52
58
|
end
|
53
59
|
|
54
60
|
|
@@ -59,23 +65,42 @@ module RForce
|
|
59
65
|
|
60
66
|
def init_server(url)
|
61
67
|
@url = URI.parse(url)
|
62
|
-
@server = Net::HTTP.new(@url.host, @url.port)
|
63
|
-
@server.use_ssl = @url.scheme == 'https'
|
64
|
-
@server.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
65
68
|
|
66
|
-
|
67
|
-
|
69
|
+
if (@oauth)
|
70
|
+
consumer = OAuth::Consumer.new \
|
71
|
+
@oauth[:consumer_key],
|
72
|
+
@oauth[:consumer_secret],
|
73
|
+
{ :site => url }
|
74
|
+
|
75
|
+
consumer.http.set_debug_output $stderr if show_debug
|
76
|
+
|
77
|
+
@server = OAuth::AccessToken.new \
|
78
|
+
consumer,
|
79
|
+
@oauth[:access_token],
|
80
|
+
@oauth[:access_secret]
|
81
|
+
|
82
|
+
class << @server
|
83
|
+
alias_method :post2, :post
|
84
|
+
end
|
85
|
+
else
|
86
|
+
@server = Net::HTTP.new(@url.host, @url.port)
|
87
|
+
@server.use_ssl = @url.scheme == 'https'
|
88
|
+
@server.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
89
|
+
|
90
|
+
# run ruby with -d or env variable SHOWSOAP=true to see SOAP wiredumps.
|
91
|
+
@server.set_debug_output $stderr if show_debug
|
92
|
+
end
|
68
93
|
end
|
69
94
|
|
70
95
|
|
71
|
-
# Log in to the server
|
72
|
-
# returned to us by SalesForce.
|
96
|
+
# Log in to the server with a user name and password, remembering
|
97
|
+
# the session ID returned to us by SalesForce.
|
73
98
|
def login(user, password)
|
74
99
|
@user = user
|
75
100
|
@password = password
|
76
101
|
|
77
102
|
response = call_remote(:login, [:username, user, :password, password])
|
78
|
-
|
103
|
+
|
79
104
|
raise "Incorrect user name / password [#{response.fault}]" unless response.loginResponse
|
80
105
|
|
81
106
|
result = response[:loginResponse][:result]
|
@@ -86,6 +111,25 @@ module RForce
|
|
86
111
|
response
|
87
112
|
end
|
88
113
|
|
114
|
+
# Log in to the server with OAuth, remembering
|
115
|
+
# the session ID returned to us by SalesForce.
|
116
|
+
def login_with_oauth
|
117
|
+
result = @server.post @oauth[:login_url], '', {}
|
118
|
+
|
119
|
+
case result
|
120
|
+
when Net::HTTPSuccess
|
121
|
+
doc = REXML::Document.new result.body
|
122
|
+
@session_id = doc.elements['*/sessionId'].text
|
123
|
+
server_url = doc.elements['*/serverUrl'].text
|
124
|
+
init_server server_url
|
125
|
+
|
126
|
+
return {:sessionId => @sessionId, :serverUrl => server_url}
|
127
|
+
when Net::HTTPUnauthorized
|
128
|
+
raise 'Invalid OAuth tokens'
|
129
|
+
else
|
130
|
+
raise "Unexpected error: #{response.inspect}"
|
131
|
+
end
|
132
|
+
end
|
89
133
|
|
90
134
|
# Call a method on the remote server. Arguments can be
|
91
135
|
# a hash or (if order is important) an array of alternating
|
@@ -104,21 +148,21 @@ module RForce
|
|
104
148
|
extra_headers << AssignmentRuleHeaderUsingDefaultRule if use_default_rule
|
105
149
|
extra_headers << MruHeader if update_mru
|
106
150
|
extra_headers << (ClientIdHeader % client_id) if client_id
|
107
|
-
|
151
|
+
|
108
152
|
if trigger_user_email or trigger_other_email or trigger_auto_response_email
|
109
153
|
extra_headers << '<partner:EmailHeader soap:mustUnderstand="1">'
|
110
|
-
|
154
|
+
|
111
155
|
extra_headers << '<partner:triggerUserEmail>true</partner:triggerUserEmail>' if trigger_user_email
|
112
156
|
extra_headers << '<partner:triggerOtherEmail>true</partner:triggerOtherEmail>' if trigger_other_email
|
113
157
|
extra_headers << '<partner:triggerAutoResponseEmail>true</partner:triggerAutoResponseEmail>' if trigger_auto_response_email
|
114
|
-
|
158
|
+
|
115
159
|
extra_headers << '</partner:EmailHeader>'
|
116
160
|
end
|
117
161
|
|
118
162
|
# Fill in the blanks of the SOAP envelope with our
|
119
163
|
# session ID and the expanded XML of our request.
|
120
164
|
request = (Envelope % [@session_id, @batch_size, extra_headers, expanded])
|
121
|
-
|
165
|
+
|
122
166
|
# reset the batch size for the next request
|
123
167
|
@batch_size = DEFAULT_BATCH_SIZE
|
124
168
|
|
@@ -209,4 +253,3 @@ module RForce
|
|
209
253
|
end
|
210
254
|
end
|
211
255
|
end
|
212
|
-
|
data/lib/rforce/soap_pullable.rb
CHANGED
@@ -4,6 +4,7 @@ require 'rforce/soap_pullable'
|
|
4
4
|
module RForce
|
5
5
|
class SoapResponseExpat
|
6
6
|
include SoapPullable
|
7
|
+
include MethodKeys
|
7
8
|
|
8
9
|
def initialize(content)
|
9
10
|
@content = content
|
@@ -12,7 +13,7 @@ module RForce
|
|
12
13
|
def parse
|
13
14
|
@current_value = nil
|
14
15
|
@stack = []
|
15
|
-
@parsed =
|
16
|
+
@parsed = {}
|
16
17
|
@done = false
|
17
18
|
@namespaces = []
|
18
19
|
|
@@ -8,6 +8,7 @@ module RForce
|
|
8
8
|
# object whose methods correspond to nested XML elements.
|
9
9
|
class SoapResponseRexml
|
10
10
|
include SoapPullable
|
11
|
+
include MethodKeys
|
11
12
|
|
12
13
|
%w(attlistdecl cdata comment doctype doctype_end elementdecl
|
13
14
|
entity entitydecl instruction notationdecl xmldecl).each do |unused|
|
@@ -17,17 +18,17 @@ module RForce
|
|
17
18
|
def initialize(content)
|
18
19
|
@content = content
|
19
20
|
end
|
20
|
-
|
21
|
+
|
21
22
|
# Parses an XML string into structured data.
|
22
23
|
def parse
|
23
24
|
@current_value = nil
|
24
25
|
@stack = []
|
25
|
-
@parsed =
|
26
|
+
@parsed = {}
|
26
27
|
@done = false
|
27
28
|
@namespaces = []
|
28
29
|
|
29
30
|
REXML::Document.parse_stream @content, self
|
30
|
-
|
31
|
+
|
31
32
|
@parsed
|
32
33
|
end
|
33
34
|
end
|
data/lib/rforce/version.rb
CHANGED
data/spec/rforce_spec.rb
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
describe MethodKeys do
|
4
|
+
it 'lets you access hash keys with methods' do
|
5
|
+
h = {:foo => :bar}
|
6
|
+
class << h; include MethodKeys; end
|
7
|
+
|
8
|
+
h.foo.should == :bar
|
9
|
+
h.nonexistent.should be_nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'provides a Hash-like class' do
|
13
|
+
mh = MethodHash.new
|
14
|
+
mh[:one] = 1
|
15
|
+
mh[:ten] = 10
|
16
|
+
|
17
|
+
mh.one.should == 1
|
18
|
+
mh.ten.should == 10
|
19
|
+
mh.nothing.should be_nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
3
23
|
describe 'expand' do
|
4
24
|
it 'turns Ruby into XML' do
|
5
25
|
xmlns = 'urn:partner.soap.sforce.com'
|
@@ -35,7 +55,7 @@ describe 'a SoapResponse implementation' do
|
|
35
55
|
|
36
56
|
results = begin
|
37
57
|
klass = RForce.const_get name
|
38
|
-
klass.new(@contents).parse.queryResponse
|
58
|
+
klass.new(@contents).parse.queryResponse[:result][:records]
|
39
59
|
rescue NameError
|
40
60
|
nil
|
41
61
|
end
|
@@ -76,7 +96,7 @@ describe 'a SoapResponse implementation' do
|
|
76
96
|
pending 'expat not installed' unless @expat_recs
|
77
97
|
@expat_recs.first.Description.should == expected
|
78
98
|
|
79
|
-
pending 'hpricot not installed' unless @
|
99
|
+
pending 'hpricot not installed' unless @hpricot_recs
|
80
100
|
@hpricot_recs.first.Description.should == expected
|
81
101
|
end
|
82
102
|
end
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rforce
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 1
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 5
|
9
|
+
version: "0.5"
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Ian Dees
|
@@ -9,49 +14,55 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-
|
17
|
+
date: 2010-12-11 00:00:00 -08:00
|
13
18
|
default_executable:
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: builder
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
20
25
|
requirements:
|
21
|
-
- -
|
26
|
+
- - ~>
|
22
27
|
- !ruby/object:Gem::Version
|
23
|
-
|
24
|
-
|
25
|
-
-
|
26
|
-
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 2
|
31
|
+
- 0
|
32
|
+
version: "2.0"
|
27
33
|
type: :runtime
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: "2.4"
|
34
|
-
version:
|
34
|
+
version_requirements: *id001
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: rspec
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
40
|
requirements:
|
41
|
-
- -
|
41
|
+
- - ~>
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
+
hash: 9
|
44
|
+
segments:
|
45
|
+
- 1
|
46
|
+
- 3
|
43
47
|
version: "1.3"
|
44
|
-
|
48
|
+
type: :development
|
49
|
+
version_requirements: *id002
|
45
50
|
- !ruby/object:Gem::Dependency
|
46
51
|
name: hoe
|
47
|
-
|
48
|
-
|
49
|
-
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
50
55
|
requirements:
|
51
56
|
- - ">="
|
52
57
|
- !ruby/object:Gem::Version
|
53
|
-
|
54
|
-
|
58
|
+
hash: 47
|
59
|
+
segments:
|
60
|
+
- 2
|
61
|
+
- 8
|
62
|
+
- 0
|
63
|
+
version: 2.8.0
|
64
|
+
type: :development
|
65
|
+
version_requirements: *id003
|
55
66
|
description: RForce is a simple, usable binding to the SalesForce API.
|
56
67
|
email:
|
57
68
|
- undees@gmail.com
|
@@ -92,21 +103,27 @@ rdoc_options:
|
|
92
103
|
require_paths:
|
93
104
|
- lib
|
94
105
|
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
95
107
|
requirements:
|
96
108
|
- - ">="
|
97
109
|
- !ruby/object:Gem::Version
|
110
|
+
hash: 3
|
111
|
+
segments:
|
112
|
+
- 0
|
98
113
|
version: "0"
|
99
|
-
version:
|
100
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
101
116
|
requirements:
|
102
117
|
- - ">="
|
103
118
|
- !ruby/object:Gem::Version
|
119
|
+
hash: 3
|
120
|
+
segments:
|
121
|
+
- 0
|
104
122
|
version: "0"
|
105
|
-
version:
|
106
123
|
requirements: []
|
107
124
|
|
108
125
|
rubyforge_project: rforce
|
109
|
-
rubygems_version: 1.3.
|
126
|
+
rubygems_version: 1.3.7
|
110
127
|
signing_key:
|
111
128
|
specification_version: 3
|
112
129
|
summary: RForce is a simple, usable binding to the SalesForce API.
|