restforce 0.1.9 → 0.1.10
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of restforce might be problematic. Click here for more details.
- data/README.md +41 -5
- data/lib/restforce/client.rb +23 -27
- data/lib/restforce/client/api.rb +28 -44
- data/lib/restforce/client/caching.rb +2 -2
- data/lib/restforce/client/verbs.rb +68 -0
- data/lib/restforce/middleware/caching.rb +8 -3
- data/lib/restforce/version.rb +1 -1
- data/restforce.gemspec +1 -1
- data/spec/lib/client_spec.rb +47 -41
- data/spec/lib/collection_spec.rb +3 -3
- data/spec/lib/config_spec.rb +1 -1
- data/spec/lib/mash_spec.rb +1 -3
- data/spec/lib/middleware/authorization_spec.rb +1 -1
- data/spec/lib/middleware/gzip_spec.rb +3 -3
- data/spec/lib/middleware/mashify_spec.rb +2 -2
- data/spec/lib/sobject_spec.rb +8 -12
- metadata +8 -12
data/README.md
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
# Restforce [![travis-ci](https://secure.travis-ci.org/ejholmes/restforce.png)](https://secure.travis-ci.org/ejholmes/restforce) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/ejholmes/restforce)
|
2
2
|
|
3
3
|
Restforce is a ruby gem for the [Salesforce REST api](http://www.salesforce.com/us/developer/docs/api_rest/index.htm).
|
4
|
-
It's meant to be a lighter weight alternative to the [databasedotcom gem](https://github.com/heroku/databasedotcom)
|
4
|
+
It's meant to be a lighter weight alternative to the [databasedotcom gem](https://github.com/heroku/databasedotcom) that offers
|
5
|
+
greater flexibility and more advanced functionality.
|
5
6
|
|
6
|
-
|
7
|
+
Features include:
|
7
8
|
|
9
|
+
* A clean and modular architecture using [Faraday middleware](https://github.com/technoweenie/faraday) and [Hashie::Mash](https://github.com/intridea/hashie/tree/v1.2.0)'d responses.
|
8
10
|
* Support for interacting with multiple users from different orgs.
|
9
11
|
* Support for parent-to-child relationships.
|
10
12
|
* Support for aggregate queries.
|
11
13
|
* Remove the need to materialize constants.
|
12
|
-
* Support for the Streaming API
|
14
|
+
* Support for the [Streaming API](#streaming)
|
13
15
|
* Support for blob data types.
|
14
16
|
* Support for GZIP compression.
|
15
|
-
*
|
17
|
+
* Support for [custom Apex REST endpoints](#custom-apex-rest-endpoints).
|
16
18
|
* Support for decoding [Force.com Canvas](http://www.salesforce.com/us/developer/docs/platform_connectpre/canvas_framework.pdf) signed requests. (NEW!)
|
17
19
|
|
18
20
|
[Documentation](http://rubydoc.info/gems/restforce/frames) | [Changelog](http://revision.io/restforce)
|
@@ -281,6 +283,36 @@ _See also: http://www.salesforce.com/us/developer/docs/api_rest/Content/dome_sob
|
|
281
283
|
|
282
284
|
* * *
|
283
285
|
|
286
|
+
### Custom Apex REST endpoints
|
287
|
+
|
288
|
+
You can use Restforce to interact with your custom REST endpoints, by using
|
289
|
+
`.get`, `.put`, `.patch`, `.post`, and `.delete`.
|
290
|
+
|
291
|
+
For example, if you had the following Apex REST endpoint on Salesforce:
|
292
|
+
|
293
|
+
```apex
|
294
|
+
@RestResource(urlMapping='/FieldCase/*')
|
295
|
+
global class RESTCaseController {
|
296
|
+
@HttpGet
|
297
|
+
global static List<Case> getOpenCases() {
|
298
|
+
String companyName = RestContext.request.params.get('company');
|
299
|
+
Account company = [ Select ID, Name, Email__c, BillingState from Account where Name = :companyName];
|
300
|
+
|
301
|
+
List<Case> cases = [SELECT Id, Subject, Status, OwnerId, Owner.Name from Case WHERE AccountId = :company.Id];
|
302
|
+
return cases;
|
303
|
+
}
|
304
|
+
}
|
305
|
+
```
|
306
|
+
|
307
|
+
Then you could query the cases using Restforce:
|
308
|
+
|
309
|
+
```ruby
|
310
|
+
client.get '/services/apexrest/FieldCase', :company => 'GenePoint'
|
311
|
+
# => #<Restforce::Collection ...>
|
312
|
+
```
|
313
|
+
|
314
|
+
* * *
|
315
|
+
|
284
316
|
### Streaming
|
285
317
|
|
286
318
|
Restforce supports the [Streaming API](http://wiki.developerforce.com/page/Getting_Started_with_the_Force.com_Streaming_API), and makes implementing
|
@@ -292,7 +324,11 @@ pub/sub with Salesforce a trivial task:
|
|
292
324
|
require 'faye'
|
293
325
|
|
294
326
|
# Initialize a client with your username/password/oauth token/etc.
|
295
|
-
client = Restforce.new
|
327
|
+
client = Restforce.new :username => 'foo',
|
328
|
+
:password => 'bar',
|
329
|
+
:security_token => 'security token'
|
330
|
+
:client_id => 'client_id',
|
331
|
+
:client_secret => 'client_secret'
|
296
332
|
|
297
333
|
# Create a PushTopic for subscribing to Account changes.
|
298
334
|
client.create! 'PushTopic', {
|
data/lib/restforce/client.rb
CHANGED
@@ -20,35 +20,33 @@ module Restforce
|
|
20
20
|
# Public: Creates a new client instance
|
21
21
|
#
|
22
22
|
# opts - A hash of options to be passed in (default: {}).
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# (required for password authentication).
|
23
|
+
# :username - The String username to use (required for password authentication).
|
24
|
+
# :password - The String password to use (required for password authentication).
|
25
|
+
# :security_token - The String security token to use (required for password authentication).
|
27
26
|
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
27
|
+
# :oauth_token - The String oauth access token to authenticate api
|
28
|
+
# calls (required unless password
|
29
|
+
# authentication is used).
|
30
|
+
# :refresh_token - The String refresh token to obtain fresh
|
31
|
+
# oauth access tokens (required if oauth
|
32
|
+
# authentication is used).
|
33
|
+
# :instance_url - The String base url for all api requests
|
34
|
+
# (required if oauth authentication is used).
|
36
35
|
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
36
|
+
# :client_id - The oauth client id to use. Needed for both
|
37
|
+
# password and oauth authentication
|
38
|
+
# :client_secret - The oauth client secret to use.
|
40
39
|
#
|
41
|
-
#
|
42
|
-
#
|
40
|
+
# :host - The String hostname to use during
|
41
|
+
# authentication requests (default: 'login.salesforce.com').
|
43
42
|
#
|
44
|
-
#
|
43
|
+
# :api_version - The String REST api version to use (default: '24.0')
|
45
44
|
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
45
|
+
# :authentication_retries - The number of times that client
|
46
|
+
# should attempt to reauthenticate
|
47
|
+
# before raising an exception (default: 3).
|
49
48
|
#
|
50
|
-
#
|
51
|
-
# response (default: false).
|
49
|
+
# :compress - Set to true to have Salesforce compress the response (default: false).
|
52
50
|
#
|
53
51
|
# Examples
|
54
52
|
#
|
@@ -58,7 +56,6 @@ module Restforce
|
|
58
56
|
# :security_token => 'security token',
|
59
57
|
# :client_id => 'client id',
|
60
58
|
# :client_secret => 'client secret'
|
61
|
-
# # => #<Restforce::Client:0x007f934aa2dc28 @options={ ... }>
|
62
59
|
#
|
63
60
|
# # Initialize a new client using oauth authentication:
|
64
61
|
# Restforce::Client.new :oauth_token => 'access token',
|
@@ -66,12 +63,11 @@ module Restforce
|
|
66
63
|
# :instance_url => 'https://na1.salesforce.com',
|
67
64
|
# :client_id => 'client id',
|
68
65
|
# :client_secret => 'client secret'
|
69
|
-
# # => #<Restforce::Client:0x007f934aaaa0e8 @options={ ... }>
|
70
66
|
#
|
71
|
-
# # Initialize a new client
|
67
|
+
# # Initialize a new client without using any authentication middleware:
|
72
68
|
# Restforce::Client.new :oauth_token => 'access token',
|
73
69
|
# :instance_url => 'https://na1.salesforce.com'
|
74
|
-
#
|
70
|
+
#
|
75
71
|
def initialize(opts = {})
|
76
72
|
raise 'Please specify a hash of options' unless opts.is_a?(Hash)
|
77
73
|
@options = Hash[OPTIONS.map { |option| [option, Restforce.configuration.send(option)] }]
|
data/lib/restforce/client/api.rb
CHANGED
@@ -1,6 +1,33 @@
|
|
1
|
+
require 'restforce/client/verbs'
|
2
|
+
|
1
3
|
module Restforce
|
2
4
|
class Client
|
3
5
|
module API
|
6
|
+
extend Restforce::Client::Verbs
|
7
|
+
|
8
|
+
# Public: Helper methods for performing arbitrary actions against the API using
|
9
|
+
# various HTTP verbs.
|
10
|
+
#
|
11
|
+
# Examples
|
12
|
+
#
|
13
|
+
# # Perform a get request
|
14
|
+
# client.get '/services/data/v24.0/sobjects'
|
15
|
+
# client.api_get 'sobjects'
|
16
|
+
#
|
17
|
+
# # Perform a post request
|
18
|
+
# client.post '/services/data/v24.0/sobjects/Account', { ... }
|
19
|
+
# client.api_post 'sobjects/Account', { ... }
|
20
|
+
#
|
21
|
+
# # Perform a put request
|
22
|
+
# client.put '/services/data/v24.0/sobjects/Account/001D000000INjVe', { ... }
|
23
|
+
# client.api_put 'sobjects/Account/001D000000INjVe', { ... }
|
24
|
+
#
|
25
|
+
# # Perform a delete request
|
26
|
+
# client.delete '/services/data/v24.0/sobjects/Account/001D000000INjVe'
|
27
|
+
# client.api_delete 'sobjects/Account/001D000000INjVe'
|
28
|
+
#
|
29
|
+
# Returns the Faraday::Response.
|
30
|
+
define_verbs :get, :post, :put, :delete, :patch
|
4
31
|
|
5
32
|
# Public: Get the names of all sobjects on the org.
|
6
33
|
#
|
@@ -132,7 +159,7 @@ module Restforce
|
|
132
159
|
# Returns true if the sobject was successfully updated, raises an error
|
133
160
|
# otherwise.
|
134
161
|
def update!(sobject, attrs)
|
135
|
-
id = attrs.
|
162
|
+
id = attrs.delete(attrs.keys.find { |k| k.to_s.downcase == 'id' })
|
136
163
|
raise 'Id field missing.' unless id
|
137
164
|
api_patch "sobjects/#{sobject}/#{id}", attrs
|
138
165
|
true
|
@@ -192,49 +219,6 @@ module Restforce
|
|
192
219
|
true
|
193
220
|
end
|
194
221
|
|
195
|
-
# Public: Helper methods for performing arbitrary actions against the API using
|
196
|
-
# various HTTP verbs.
|
197
|
-
#
|
198
|
-
# Examples
|
199
|
-
#
|
200
|
-
# # Perform a get request
|
201
|
-
# client.get '/services/data/v24.0/sobjects'
|
202
|
-
# client.api_get 'sobjects'
|
203
|
-
#
|
204
|
-
# # Perform a post request
|
205
|
-
# client.post '/services/data/v24.0/sobjects/Account', { ... }
|
206
|
-
# client.api_post 'sobjects/Account', { ... }
|
207
|
-
#
|
208
|
-
# # Perform a put request
|
209
|
-
# client.put '/services/data/v24.0/sobjects/Account/001D000000INjVe', { ... }
|
210
|
-
# client.api_put 'sobjects/Account/001D000000INjVe', { ... }
|
211
|
-
#
|
212
|
-
# # Perform a delete request
|
213
|
-
# client.delete '/services/data/v24.0/sobjects/Account/001D000000INjVe'
|
214
|
-
# client.api_delete 'sobjects/Account/001D000000INjVe'
|
215
|
-
#
|
216
|
-
# Returns the Faraday::Response.
|
217
|
-
[:get, :post, :put, :delete, :patch].each do |method|
|
218
|
-
define_method method do |*args|
|
219
|
-
retries = @options[:authentication_retries]
|
220
|
-
begin
|
221
|
-
connection.send(method, *args)
|
222
|
-
rescue Restforce::UnauthorizedError
|
223
|
-
if retries > 0
|
224
|
-
retries -= 1
|
225
|
-
connection.url_prefix = @options[:instance_url]
|
226
|
-
retry
|
227
|
-
end
|
228
|
-
raise
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
define_method :"api_#{method}" do |*args|
|
233
|
-
args[0] = api_path(args[0])
|
234
|
-
send(method, *args)
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
222
|
private
|
239
223
|
|
240
224
|
# Internal: Returns a path to an api endpoint
|
@@ -8,10 +8,10 @@ module Restforce
|
|
8
8
|
#
|
9
9
|
# Returns the result of the block
|
10
10
|
def without_caching(&block)
|
11
|
-
@options[:
|
11
|
+
@options[:use_cache] = false
|
12
12
|
block.call
|
13
13
|
ensure
|
14
|
-
@options.delete(:
|
14
|
+
@options.delete(:use_cache)
|
15
15
|
end
|
16
16
|
|
17
17
|
private
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Restforce
|
2
|
+
class Client
|
3
|
+
module Verbs
|
4
|
+
|
5
|
+
# Internal: Define methods to handle a verb.
|
6
|
+
#
|
7
|
+
# verbs - A list of verbs to define methods for.
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
# define_verbs :get, :post
|
12
|
+
#
|
13
|
+
# Returns nil.
|
14
|
+
def define_verbs(*verbs)
|
15
|
+
verbs.each do |verb|
|
16
|
+
define_verb(verb)
|
17
|
+
define_api_verb(verb)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Internal: Defines a method to handle HTTP requests with the passed in
|
22
|
+
# verb.
|
23
|
+
#
|
24
|
+
# verb - Symbol name of the verb (e.g. :get).
|
25
|
+
#
|
26
|
+
# Examples
|
27
|
+
#
|
28
|
+
# define_verb :get
|
29
|
+
# # => get '/services/data/v24.0/sobjects'
|
30
|
+
#
|
31
|
+
# Returns nil.
|
32
|
+
def define_verb(verb)
|
33
|
+
define_method verb do |*args, &block|
|
34
|
+
retries = @options[:authentication_retries]
|
35
|
+
begin
|
36
|
+
connection.send(verb, *args, &block)
|
37
|
+
rescue Restforce::UnauthorizedError
|
38
|
+
if retries > 0
|
39
|
+
retries -= 1
|
40
|
+
connection.url_prefix = @options[:instance_url]
|
41
|
+
retry
|
42
|
+
end
|
43
|
+
raise
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Internal: Defines a method to handle HTTP requests with the passed in
|
49
|
+
# verb to a salesforce api endpoint.
|
50
|
+
#
|
51
|
+
# verb - Symbol name of the verb (e.g. :get).
|
52
|
+
#
|
53
|
+
# Examples
|
54
|
+
#
|
55
|
+
# define_api_verb :get
|
56
|
+
# # => api_get 'sobjects'
|
57
|
+
#
|
58
|
+
# Returns nil.
|
59
|
+
def define_api_verb(verb)
|
60
|
+
define_method :"api_#{verb}" do |*args, &block|
|
61
|
+
args[0] = api_path(args[0])
|
62
|
+
send(verb, *args, &block)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -2,7 +2,12 @@ module Restforce
|
|
2
2
|
class Middleware::Caching < FaradayMiddleware::Caching
|
3
3
|
|
4
4
|
def call(env)
|
5
|
-
|
5
|
+
expire(cache_key(env)) unless use_cache?
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def expire(key)
|
10
|
+
cache.delete(key) if cache
|
6
11
|
end
|
7
12
|
|
8
13
|
# We don't want to cache requests for different clients, so append the
|
@@ -11,8 +16,8 @@ module Restforce
|
|
11
16
|
super(env) + env[:request_headers][Restforce::Middleware::Authorization::AUTH_HEADER].gsub(/\s/, '')
|
12
17
|
end
|
13
18
|
|
14
|
-
def
|
15
|
-
!@options.has_key?(:
|
19
|
+
def use_cache?
|
20
|
+
!@options.has_key?(:use_cache) || @options[:use_cache]
|
16
21
|
end
|
17
22
|
|
18
23
|
end
|
data/lib/restforce/version.rb
CHANGED
data/restforce.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.add_dependency 'json', '~> 1.7.5'
|
22
22
|
gem.add_dependency 'hashie', '~> 1.2.0'
|
23
23
|
|
24
|
-
gem.add_development_dependency 'rspec'
|
24
|
+
gem.add_development_dependency 'rspec', '~> 2.12.0'
|
25
25
|
gem.add_development_dependency 'webmock'
|
26
26
|
gem.add_development_dependency 'simplecov'
|
27
27
|
gem.add_development_dependency 'faye', '0.8.3' unless RUBY_PLATFORM == 'java'
|
data/spec/lib/client_spec.rb
CHANGED
@@ -1,9 +1,23 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
class MockCache
|
4
|
+
def initialize
|
5
|
+
@storage = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def fetch(key, &block)
|
9
|
+
@storage[key] ||= block.call
|
10
|
+
end
|
11
|
+
|
12
|
+
def delete(key)
|
13
|
+
@storage.delete(key)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
3
17
|
shared_examples_for 'methods' do
|
4
18
|
describe '#new' do
|
5
19
|
context 'without options passed in' do
|
6
|
-
it '
|
20
|
+
it 'does not raise an exception' do
|
7
21
|
expect {
|
8
22
|
described_class.new
|
9
23
|
}.to_not raise_error
|
@@ -11,7 +25,7 @@ shared_examples_for 'methods' do
|
|
11
25
|
end
|
12
26
|
|
13
27
|
context 'with a non-hash value' do
|
14
|
-
it '
|
28
|
+
it 'raises an exception' do
|
15
29
|
expect {
|
16
30
|
described_class.new 'foo'
|
17
31
|
}.to raise_error, 'Please specify a hash of options'
|
@@ -59,7 +73,7 @@ shared_examples_for 'methods' do
|
|
59
73
|
end
|
60
74
|
|
61
75
|
after do
|
62
|
-
@request.
|
76
|
+
expect(@request).to have_been_requested
|
63
77
|
end
|
64
78
|
|
65
79
|
subject { client.list_sobjects }
|
@@ -75,7 +89,7 @@ shared_examples_for 'methods' do
|
|
75
89
|
end
|
76
90
|
|
77
91
|
after do
|
78
|
-
@request.
|
92
|
+
expect(@request).to have_been_requested
|
79
93
|
end
|
80
94
|
|
81
95
|
subject { client.describe }
|
@@ -89,7 +103,7 @@ shared_examples_for 'methods' do
|
|
89
103
|
end
|
90
104
|
|
91
105
|
after do
|
92
|
-
@request.
|
106
|
+
expect(@request).to have_been_requested
|
93
107
|
end
|
94
108
|
|
95
109
|
subject { client.describe('Whizbang') }
|
@@ -104,7 +118,7 @@ shared_examples_for 'methods' do
|
|
104
118
|
end
|
105
119
|
|
106
120
|
after do
|
107
|
-
@request.
|
121
|
+
expect(@request).to have_been_requested
|
108
122
|
end
|
109
123
|
|
110
124
|
subject { client.query('SELECT some, fields FROM object') }
|
@@ -118,7 +132,7 @@ shared_examples_for 'methods' do
|
|
118
132
|
end
|
119
133
|
|
120
134
|
after do
|
121
|
-
@request.
|
135
|
+
expect(@request).to have_been_requested
|
122
136
|
end
|
123
137
|
|
124
138
|
subject { client.search('FIND {bar}') }
|
@@ -133,7 +147,7 @@ shared_examples_for 'methods' do
|
|
133
147
|
end
|
134
148
|
|
135
149
|
after do
|
136
|
-
@request.
|
150
|
+
expect(@request).to have_been_requested
|
137
151
|
end
|
138
152
|
|
139
153
|
subject { client.org_id }
|
@@ -150,7 +164,7 @@ shared_examples_for 'methods' do
|
|
150
164
|
end
|
151
165
|
|
152
166
|
after do
|
153
|
-
@request.
|
167
|
+
expect(@request).to have_been_requested
|
154
168
|
end
|
155
169
|
|
156
170
|
subject { client.create('Account', :Name => 'Foobar') }
|
@@ -166,7 +180,7 @@ shared_examples_for 'methods' do
|
|
166
180
|
end
|
167
181
|
|
168
182
|
after do
|
169
|
-
@request.
|
183
|
+
expect(@request).to have_been_requested
|
170
184
|
end
|
171
185
|
|
172
186
|
subject { client.create('Account', :Name => 'Foobar', :Blob => Restforce::UploadIO.new(File.expand_path('../../fixtures/blob.jpg', __FILE__), 'image/jpeg')) }
|
@@ -185,7 +199,7 @@ shared_examples_for 'methods' do
|
|
185
199
|
end
|
186
200
|
|
187
201
|
after do
|
188
|
-
@request.
|
202
|
+
expect(@request).to have_been_requested
|
189
203
|
end
|
190
204
|
|
191
205
|
subject { client.update!('Account', :Id => '001D000000INjVe', :Name => 'Foobar') }
|
@@ -209,7 +223,7 @@ shared_examples_for 'methods' do
|
|
209
223
|
end
|
210
224
|
|
211
225
|
after do
|
212
|
-
@request.
|
226
|
+
expect(@request).to have_been_requested
|
213
227
|
end
|
214
228
|
|
215
229
|
subject { client.update('Account', :Id => '001D000000INjVe', :Name => 'Foobar') }
|
@@ -224,7 +238,7 @@ shared_examples_for 'methods' do
|
|
224
238
|
end
|
225
239
|
|
226
240
|
after do
|
227
|
-
@request.
|
241
|
+
expect(@request).to have_been_requested
|
228
242
|
end
|
229
243
|
|
230
244
|
context 'with symbol Id key' do
|
@@ -236,6 +250,11 @@ shared_examples_for 'methods' do
|
|
236
250
|
subject { client.update('Account', 'Id' => '001D000000INjVe', 'Name' => 'Foobar') }
|
237
251
|
it { should be_true }
|
238
252
|
end
|
253
|
+
|
254
|
+
context 'with a lower case id' do
|
255
|
+
subject { client.update('Account', 'id' => '001D000000INjVe', 'Name' => 'Foobar') }
|
256
|
+
it { should be_true }
|
257
|
+
end
|
239
258
|
end
|
240
259
|
end
|
241
260
|
|
@@ -248,7 +267,7 @@ shared_examples_for 'methods' do
|
|
248
267
|
end
|
249
268
|
|
250
269
|
after do
|
251
|
-
@request.
|
270
|
+
expect(@request).to have_been_requested
|
252
271
|
end
|
253
272
|
|
254
273
|
context 'with symbol external Id key' do
|
@@ -271,7 +290,7 @@ shared_examples_for 'methods' do
|
|
271
290
|
end
|
272
291
|
|
273
292
|
after do
|
274
|
-
@request.
|
293
|
+
expect(@request).to have_been_requested
|
275
294
|
end
|
276
295
|
|
277
296
|
context 'with symbol external Id key' do
|
@@ -298,7 +317,7 @@ shared_examples_for 'methods' do
|
|
298
317
|
end
|
299
318
|
|
300
319
|
after do
|
301
|
-
@request.
|
320
|
+
expect(@request).to have_been_requested
|
302
321
|
end
|
303
322
|
|
304
323
|
specify { expect { subject }.to raise_error Faraday::Error::ResourceNotFound }
|
@@ -310,7 +329,7 @@ shared_examples_for 'methods' do
|
|
310
329
|
end
|
311
330
|
|
312
331
|
after do
|
313
|
-
@request.
|
332
|
+
expect(@request).to have_been_requested
|
314
333
|
end
|
315
334
|
|
316
335
|
it { should be_true }
|
@@ -329,7 +348,7 @@ shared_examples_for 'methods' do
|
|
329
348
|
end
|
330
349
|
|
331
350
|
after do
|
332
|
-
@request.
|
351
|
+
expect(@request).to have_been_requested
|
333
352
|
end
|
334
353
|
|
335
354
|
it { should be_false }
|
@@ -341,7 +360,7 @@ shared_examples_for 'methods' do
|
|
341
360
|
end
|
342
361
|
|
343
362
|
after do
|
344
|
-
@request.
|
363
|
+
expect(@request).to have_been_requested
|
345
364
|
end
|
346
365
|
|
347
366
|
it { should be_true }
|
@@ -356,7 +375,7 @@ shared_examples_for 'methods' do
|
|
356
375
|
end
|
357
376
|
|
358
377
|
after do
|
359
|
-
@request.
|
378
|
+
expect(@request).to have_been_requested
|
360
379
|
end
|
361
380
|
|
362
381
|
subject { client.authenticate! }
|
@@ -405,16 +424,17 @@ shared_examples_for 'methods' do
|
|
405
424
|
end
|
406
425
|
|
407
426
|
describe '.without_caching' do
|
408
|
-
let(:cache) {
|
427
|
+
let(:cache) { MockCache.new }
|
409
428
|
|
410
429
|
before do
|
411
430
|
@request = stub_api_request 'query\?q=SELECT%20some,%20fields%20FROM%20object',
|
412
431
|
:with => 'sobject/query_success_response'
|
413
|
-
cache.should_receive(:
|
432
|
+
cache.should_receive(:delete).and_call_original
|
433
|
+
cache.should_receive(:fetch).and_call_original
|
414
434
|
end
|
415
435
|
|
416
436
|
after do
|
417
|
-
@request.
|
437
|
+
expect(@request).to have_been_requested
|
418
438
|
end
|
419
439
|
|
420
440
|
subject { client.without_caching { client.query('SELECT some, fields FROM object') } }
|
@@ -453,20 +473,6 @@ shared_examples_for 'methods' do
|
|
453
473
|
end
|
454
474
|
|
455
475
|
describe '.query with caching' do
|
456
|
-
class MockCache
|
457
|
-
def initialize
|
458
|
-
@storage = {}
|
459
|
-
end
|
460
|
-
|
461
|
-
def fetch(key, &block)
|
462
|
-
@storage[key] || begin
|
463
|
-
block.call.tap do |result|
|
464
|
-
@storage[key] = result
|
465
|
-
end
|
466
|
-
end
|
467
|
-
end
|
468
|
-
end
|
469
|
-
|
470
476
|
let(:cache) { MockCache.new }
|
471
477
|
|
472
478
|
before do
|
@@ -481,8 +487,8 @@ shared_examples_for 'methods' do
|
|
481
487
|
end
|
482
488
|
|
483
489
|
after do
|
484
|
-
@query.
|
485
|
-
@login.
|
490
|
+
expect(@query).to have_been_made.times(2)
|
491
|
+
expect(@login).to have_been_made
|
486
492
|
end
|
487
493
|
|
488
494
|
subject { client.query('SELECT some, fields FROM object') }
|
@@ -511,12 +517,12 @@ describe 'with mashify middleware' do
|
|
511
517
|
end
|
512
518
|
|
513
519
|
after do
|
514
|
-
@requests.each { |request| request.
|
520
|
+
@requests.each { |request| expect(request).to have_been_requested }
|
515
521
|
end
|
516
522
|
|
517
523
|
subject { client.query('SELECT some, fields FROM object').next_page }
|
518
524
|
it { should be_a Restforce::Collection }
|
519
|
-
specify { subject.first.Text_Label.
|
525
|
+
specify { expect(subject.first.Text_Label).to eq 'Last Page' }
|
520
526
|
end
|
521
527
|
end
|
522
528
|
end
|
data/spec/lib/collection_spec.rb
CHANGED
@@ -15,12 +15,12 @@ describe Restforce::Collection do
|
|
15
15
|
its(:size) { should eq 1 }
|
16
16
|
its(:total_size) { should eq 1 }
|
17
17
|
its(:next_page_url) { should be_nil }
|
18
|
-
specify { subject.instance_variable_get(:@client).
|
18
|
+
specify { expect(subject.instance_variable_get(:@client)).to eq client }
|
19
19
|
|
20
20
|
describe 'each record' do
|
21
21
|
it 'should be a Restforce::SObject' do
|
22
22
|
records.each do |record|
|
23
|
-
record.
|
23
|
+
expect(record).to be_a Restforce::SObject
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -35,7 +35,7 @@ describe Restforce::Collection do
|
|
35
35
|
its(:size) { should eq 1 }
|
36
36
|
its(:total_size) { should eq 2 }
|
37
37
|
its(:next_page_url) { should eq '/services/data/v24.0/query/01gD' }
|
38
|
-
specify { subject.instance_variable_get(:@client).
|
38
|
+
specify { expect(subject.instance_variable_get(:@client)).to eq client }
|
39
39
|
|
40
40
|
describe '.next_page' do
|
41
41
|
before do
|
data/spec/lib/config_spec.rb
CHANGED
data/spec/lib/mash_spec.rb
CHANGED
@@ -6,9 +6,7 @@ describe Restforce::Mash do
|
|
6
6
|
|
7
7
|
context 'when array' do
|
8
8
|
let(:input) { [{ :foo => 'hello' }, { :bar => 'world' }] }
|
9
|
-
it
|
10
|
-
subject.each { |obj| obj.should be_a Restforce::Mash }
|
11
|
-
end
|
9
|
+
it { should be_all { |obj| expect(obj).to be_a Restforce::Mash } }
|
12
10
|
end
|
13
11
|
end
|
14
12
|
|
@@ -24,7 +24,7 @@ describe Restforce::Middleware::Gzip do
|
|
24
24
|
context 'when :compress is false' do
|
25
25
|
it 'does not add the Accept-Encoding header' do
|
26
26
|
middleware.call(env)
|
27
|
-
env[:request_headers]['Accept-Encoding'].
|
27
|
+
expect(env[:request_headers]['Accept-Encoding']).to be_nil
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -35,7 +35,7 @@ describe Restforce::Middleware::Gzip do
|
|
35
35
|
|
36
36
|
it 'adds the Accept-Encoding header' do
|
37
37
|
middleware.call(env)
|
38
|
-
env[:request_headers]['Accept-Encoding'].
|
38
|
+
expect(env[:request_headers]['Accept-Encoding']).to eq 'gzip'
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -52,7 +52,7 @@ describe Restforce::Middleware::Gzip do
|
|
52
52
|
|
53
53
|
it 'decompresses the response body' do
|
54
54
|
middleware.call(env)
|
55
|
-
env[:body].
|
55
|
+
expect(env[:body]).to eq fixture('sobject/query_success_response')
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -14,7 +14,7 @@ describe Restforce::Middleware::Mashify do
|
|
14
14
|
let(:env) { { :body => JSON.parse(fixture('sobject/query_success_response')) } }
|
15
15
|
|
16
16
|
it 'converts the response body into a restforce collection' do
|
17
|
-
env[:body].
|
17
|
+
expect(env[:body]).to be_a Restforce::Collection
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -22,7 +22,7 @@ describe Restforce::Middleware::Mashify do
|
|
22
22
|
let(:env) { { :body => { 'foo' => 'bar' } } }
|
23
23
|
|
24
24
|
it 'does not touch the body' do
|
25
|
-
env[:body].foo.
|
25
|
+
expect(env[:body].foo).to eq 'bar'
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
data/spec/lib/sobject_spec.rb
CHANGED
@@ -28,13 +28,9 @@ describe Restforce::SObject do
|
|
28
28
|
it { should be_a Restforce::Collection }
|
29
29
|
|
30
30
|
describe 'each child' do
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
it 'should set the client' do
|
36
|
-
sobject.Whizbangs__r.each { |sobject| sobject.should have_client client }
|
37
|
-
end
|
31
|
+
subject { sobject.Whizbangs__r }
|
32
|
+
it { should be_all { |sobject| expect(sobject).to be_a Restforce::SObject } }
|
33
|
+
it { should be_all { |sobject| expect(sobject).to have_client client } }
|
38
34
|
end
|
39
35
|
end
|
40
36
|
|
@@ -66,7 +62,7 @@ describe Restforce::SObject do
|
|
66
62
|
end
|
67
63
|
|
68
64
|
after do
|
69
|
-
@request.
|
65
|
+
expect(@request).to have_been_requested
|
70
66
|
end
|
71
67
|
|
72
68
|
specify { expect { subject }.to_not raise_error }
|
@@ -86,7 +82,7 @@ describe Restforce::SObject do
|
|
86
82
|
end
|
87
83
|
|
88
84
|
after do
|
89
|
-
@request.
|
85
|
+
expect(@request).to have_been_requested
|
90
86
|
end
|
91
87
|
|
92
88
|
specify { expect { subject }.to raise_error Faraday::Error::ResourceNotFound }
|
@@ -107,7 +103,7 @@ describe Restforce::SObject do
|
|
107
103
|
end
|
108
104
|
|
109
105
|
after do
|
110
|
-
@request.
|
106
|
+
expect(@request).to have_been_requested
|
111
107
|
end
|
112
108
|
|
113
109
|
specify { expect { subject }.to_not raise_error }
|
@@ -127,7 +123,7 @@ describe Restforce::SObject do
|
|
127
123
|
end
|
128
124
|
|
129
125
|
after do
|
130
|
-
@request.
|
126
|
+
expect(@request).to have_been_requested
|
131
127
|
end
|
132
128
|
|
133
129
|
specify { expect { subject }.to raise_error Faraday::Error::ResourceNotFound }
|
@@ -141,7 +137,7 @@ describe Restforce::SObject do
|
|
141
137
|
end
|
142
138
|
|
143
139
|
after do
|
144
|
-
@request.
|
140
|
+
expect(@request).to have_been_requested
|
145
141
|
end
|
146
142
|
|
147
143
|
subject { sobject.describe }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restforce
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.10
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -96,17 +96,17 @@ dependencies:
|
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
99
|
-
- -
|
99
|
+
- - ~>
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
101
|
+
version: 2.12.0
|
102
102
|
type: :development
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
|
-
- -
|
107
|
+
- - ~>
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
109
|
+
version: 2.12.0
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
111
|
name: webmock
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -177,6 +177,7 @@ files:
|
|
177
177
|
- lib/restforce/client/canvas.rb
|
178
178
|
- lib/restforce/client/connection.rb
|
179
179
|
- lib/restforce/client/streaming.rb
|
180
|
+
- lib/restforce/client/verbs.rb
|
180
181
|
- lib/restforce/collection.rb
|
181
182
|
- lib/restforce/config.rb
|
182
183
|
- lib/restforce/mash.rb
|
@@ -257,18 +258,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
257
258
|
- - ! '>='
|
258
259
|
- !ruby/object:Gem::Version
|
259
260
|
version: '0'
|
260
|
-
segments:
|
261
|
-
- 0
|
262
|
-
hash: -2351979982713256813
|
263
261
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
264
262
|
none: false
|
265
263
|
requirements:
|
266
264
|
- - ! '>='
|
267
265
|
- !ruby/object:Gem::Version
|
268
266
|
version: '0'
|
269
|
-
segments:
|
270
|
-
- 0
|
271
|
-
hash: -2351979982713256813
|
272
267
|
requirements: []
|
273
268
|
rubyforge_project:
|
274
269
|
rubygems_version: 1.8.23
|
@@ -325,3 +320,4 @@ test_files:
|
|
325
320
|
- spec/support/basic_client.rb
|
326
321
|
- spec/support/fixture_helpers.rb
|
327
322
|
- spec/support/middleware.rb
|
323
|
+
has_rdoc:
|