parse-ruby-client 0.1.8 → 0.1.9
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.
- data/README.md +19 -1
- data/VERSION +1 -1
- data/fixtures/vcr_cassettes/test_batch_create_object.yml +89 -0
- data/fixtures/vcr_cassettes/test_batch_delete_object.yml +482 -0
- data/fixtures/vcr_cassettes/test_batch_update_object.yml +486 -0
- data/fixtures/vcr_cassettes/test_request_batch.yml +62 -0
- data/lib/parse/batch.rb +32 -0
- data/lib/parse/client.rb +15 -14
- data/lib/parse/datatypes.rb +6 -0
- data/lib/parse/error.rb +6 -9
- data/lib/parse/object.rb +11 -2
- data/lib/parse/protocol.rb +2 -0
- data/lib/parse/query.rb +8 -3
- data/parse-ruby-client.gemspec +6 -2
- data/test/test_batch.rb +56 -0
- data/test/test_client.rb +13 -1
- data/test/test_object.rb +1 -1
- metadata +7 -3
@@ -0,0 +1,62 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://api.parse.com/1/batch
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: "{\"requests\":[{\"method\":\"POST\",\"path\":\"/1/classes/GameScore\",\"body\":{\"gameScore\":42}}]}"
|
9
|
+
headers:
|
10
|
+
Content-Type:
|
11
|
+
- application/json
|
12
|
+
Accept:
|
13
|
+
- application/json
|
14
|
+
User-Agent:
|
15
|
+
- Parse for Ruby, 0.0
|
16
|
+
X-Parse-Master-Key:
|
17
|
+
- ""
|
18
|
+
X-Parse-Rest-Api-Key:
|
19
|
+
- jYdptjS76YHikuIFfJEgHD8UMIjH6cp2rWz4fo2C
|
20
|
+
X-Parse-Application-Id:
|
21
|
+
- hnJRtntbYPvWfjqcqLZsdFaOKT0F3SfNU7Kc7woN
|
22
|
+
X-Parse-Session-Token:
|
23
|
+
- ""
|
24
|
+
Expect:
|
25
|
+
- ""
|
26
|
+
response:
|
27
|
+
status:
|
28
|
+
code: 200
|
29
|
+
message: OK
|
30
|
+
headers:
|
31
|
+
Access-Control-Allow-Origin:
|
32
|
+
- "*"
|
33
|
+
Access-Control-Request-Method:
|
34
|
+
- "*"
|
35
|
+
Cache-Control:
|
36
|
+
- max-age=0, private, must-revalidate
|
37
|
+
Content-Type:
|
38
|
+
- application/json; charset=utf-8
|
39
|
+
Date:
|
40
|
+
- Tue, 08 Jan 2013 15:12:42 GMT
|
41
|
+
Etag:
|
42
|
+
- "\"98e77897bd1902cdc3885b7f63ba4765\""
|
43
|
+
Server:
|
44
|
+
- nginx/1.2.2
|
45
|
+
Set-Cookie:
|
46
|
+
- _parse_session=BAh7BkkiD3Nlc3Npb25faWQGOgZFRiIlYmZjMTc1NWY3MzhkMzY4ZTFlNzA2OTJhNWVmODAxY2I%3D--c18a9b64bbafbd180ba894073d8e6452ee909d69; domain=.parse.com; path=/; expires=Sun, 08-Jan-2023 15:12:42 GMT; secure; HttpOnly
|
47
|
+
Status:
|
48
|
+
- 200 OK
|
49
|
+
X-Runtime:
|
50
|
+
- "18.138760"
|
51
|
+
X-Ua-Compatible:
|
52
|
+
- IE=Edge,chrome=1
|
53
|
+
Content-Length:
|
54
|
+
- "78"
|
55
|
+
Connection:
|
56
|
+
- keep-alive
|
57
|
+
body:
|
58
|
+
encoding: ASCII-8BIT
|
59
|
+
string: "[{\"success\":{\"createdAt\":\"2013-01-08T15:12:26.671Z\",\"objectId\":\"YwUiZtIHgm\"}}]"
|
60
|
+
http_version:
|
61
|
+
recorded_at: Tue, 08 Jan 2013 15:12:44 GMT
|
62
|
+
recorded_with: VCR 2.0.1
|
data/lib/parse/batch.rb
CHANGED
@@ -12,10 +12,42 @@ module Parse
|
|
12
12
|
@requests << request
|
13
13
|
end
|
14
14
|
|
15
|
+
def create_object(object)
|
16
|
+
method = "POST"
|
17
|
+
path = Parse::Protocol.class_uri(object.class_name)
|
18
|
+
body = object.safe_hash
|
19
|
+
add_request({
|
20
|
+
"method" => method,
|
21
|
+
"path" => path,
|
22
|
+
"body" => body
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
def update_object(object)
|
27
|
+
method = "PUT"
|
28
|
+
path = Parse::Protocol.class_uri(object.class_name, object.id)
|
29
|
+
body = object.safe_hash
|
30
|
+
add_request({
|
31
|
+
"method" => method,
|
32
|
+
"path" => path,
|
33
|
+
"body" => body
|
34
|
+
})
|
35
|
+
end
|
36
|
+
|
37
|
+
def delete_object(object)
|
38
|
+
add_request({
|
39
|
+
"method" => "DELETE",
|
40
|
+
"path" => Parse::Protocol.class_uri(object.class_name, object.id)
|
41
|
+
})
|
42
|
+
end
|
43
|
+
|
15
44
|
def run!
|
16
45
|
uri = Parse::Protocol.batch_request_uri
|
17
46
|
body = {:requests => @requests}.to_json
|
18
47
|
Parse.client.request(uri, :post, body)
|
19
48
|
end
|
49
|
+
|
50
|
+
|
20
51
|
end
|
52
|
+
|
21
53
|
end
|
data/lib/parse/client.rb
CHANGED
@@ -8,6 +8,8 @@ module Parse
|
|
8
8
|
# API server. Currently uses the Patron library for low-level HTTP
|
9
9
|
# communication.
|
10
10
|
class Client
|
11
|
+
DEFAULT_RETRIES = 2
|
12
|
+
|
11
13
|
attr_accessor :host
|
12
14
|
attr_accessor :application_id
|
13
15
|
attr_accessor :api_key
|
@@ -35,7 +37,7 @@ module Parse
|
|
35
37
|
# with common basic response handling. Will raise a
|
36
38
|
# ParseProtocolError if the response has an error status code,
|
37
39
|
# and will return the parsed JSON body on success, if there is one.
|
38
|
-
def request(uri, method = :get, body = nil, query = nil, max_retries =
|
40
|
+
def request(uri, method = :get, body = nil, query = nil, max_retries = DEFAULT_RETRIES)
|
39
41
|
@session.headers[Protocol::HEADER_MASTER_KEY] = @master_key
|
40
42
|
@session.headers[Protocol::HEADER_API_KEY] = @api_key
|
41
43
|
@session.headers[Protocol::HEADER_APP_ID] = @application_id
|
@@ -51,22 +53,21 @@ module Parse
|
|
51
53
|
|
52
54
|
num_tries = 0
|
53
55
|
begin
|
54
|
-
response = @session.request(method, uri, {}, options)
|
55
|
-
rescue Patron::TimeoutError
|
56
56
|
num_tries += 1
|
57
|
-
|
58
|
-
|
59
|
-
else
|
60
|
-
raise Patron::TimeoutError
|
61
|
-
end
|
62
|
-
end
|
57
|
+
response = @session.request(method, uri, {}, options)
|
58
|
+
parsed = JSON.parse(response.body)
|
63
59
|
|
64
|
-
|
65
|
-
|
66
|
-
else
|
67
|
-
if response
|
68
|
-
return JSON.parse response.body
|
60
|
+
if response.status >= 400
|
61
|
+
raise ParseProtocolError.new(parsed)
|
69
62
|
end
|
63
|
+
|
64
|
+
return parsed
|
65
|
+
rescue Patron::TimeoutError
|
66
|
+
retry if num_tries <= max_retries
|
67
|
+
raise
|
68
|
+
rescue ParseProtocolError => e
|
69
|
+
retry if e.code == Protocol::ERROR_TIMEOUT && num_tries <= max_retries
|
70
|
+
raise
|
70
71
|
end
|
71
72
|
end
|
72
73
|
|
data/lib/parse/datatypes.rb
CHANGED
@@ -8,12 +8,18 @@ module Parse
|
|
8
8
|
class Pointer
|
9
9
|
attr_accessor :parse_object_id
|
10
10
|
attr_accessor :class_name
|
11
|
+
alias :id :parse_object_id
|
11
12
|
|
12
13
|
def initialize(data)
|
13
14
|
@class_name = data[Protocol::KEY_CLASS_NAME]
|
14
15
|
@parse_object_id = data[Protocol::KEY_OBJECT_ID]
|
15
16
|
end
|
16
17
|
|
18
|
+
# make it easier to deal with the ambiguity of whether you're passed a pointer or object
|
19
|
+
def pointer
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
17
23
|
def eql?(other)
|
18
24
|
self.class.equal?(other.class) &&
|
19
25
|
class_name == other.class_name &&
|
data/lib/parse/error.rb
CHANGED
@@ -15,15 +15,12 @@ module Parse
|
|
15
15
|
attr_accessor :response
|
16
16
|
|
17
17
|
def initialize(response)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
#
|
23
|
-
#end
|
24
|
-
|
25
|
-
#{}"#{@code}: #{@message}"
|
18
|
+
@response = response
|
19
|
+
@code = response["code"]
|
20
|
+
@error = response["error"]
|
21
|
+
|
22
|
+
super("#{@code}: #{@error}")
|
26
23
|
end
|
27
24
|
end
|
28
|
-
|
25
|
+
|
29
26
|
end
|
data/lib/parse/object.rb
CHANGED
@@ -28,6 +28,11 @@ module Parse
|
|
28
28
|
Parse::Pointer.new(self.merge(Parse::Protocol::KEY_CLASS_NAME => class_name)) unless new?
|
29
29
|
end
|
30
30
|
|
31
|
+
# make it easier to deal with the ambiguity of whether you're passed a pointer or object
|
32
|
+
def get
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
31
36
|
# Merge a hash parsed from the JSON representation into
|
32
37
|
# this instance. This will extract the reserved fields,
|
33
38
|
# merge the hash keys, and then ensure that the reserved
|
@@ -63,7 +68,7 @@ module Parse
|
|
63
68
|
self["objectId"].nil?
|
64
69
|
end
|
65
70
|
|
66
|
-
def
|
71
|
+
def safe_hash
|
67
72
|
without_reserved = self.dup
|
68
73
|
Protocol::RESERVED_KEYS.each { |k| without_reserved.delete(k) }
|
69
74
|
|
@@ -76,7 +81,11 @@ module Parse
|
|
76
81
|
end
|
77
82
|
}
|
78
83
|
|
79
|
-
without_relations
|
84
|
+
without_relations
|
85
|
+
end
|
86
|
+
|
87
|
+
def safe_json
|
88
|
+
safe_hash.to_json
|
80
89
|
end
|
81
90
|
|
82
91
|
private :parse
|
data/lib/parse/protocol.rb
CHANGED
data/lib/parse/query.rb
CHANGED
@@ -39,7 +39,7 @@ module Parse
|
|
39
39
|
add_constraint field, value
|
40
40
|
self
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
def not_eq(field, value)
|
44
44
|
add_constraint field, { "$ne" => value }
|
45
45
|
self
|
@@ -75,6 +75,11 @@ module Parse
|
|
75
75
|
self
|
76
76
|
end
|
77
77
|
|
78
|
+
def value_not_in(field, values)
|
79
|
+
add_constraint field, { "$nin" => values }
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
78
83
|
def exists(field, value = true)
|
79
84
|
add_constraint field, { "$exists" => value }
|
80
85
|
self
|
@@ -86,12 +91,12 @@ module Parse
|
|
86
91
|
self
|
87
92
|
end
|
88
93
|
|
89
|
-
def
|
94
|
+
def set_limit(num)
|
90
95
|
@limit = num
|
91
96
|
self
|
92
97
|
end
|
93
98
|
|
94
|
-
def
|
99
|
+
def set_order(field, order = :ascending)
|
95
100
|
@order_by = field
|
96
101
|
@order = order
|
97
102
|
self
|
data/parse-ruby-client.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "parse-ruby-client"
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.9"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Alan deLevie", "Adam Alpern"]
|
12
|
-
s.date = "2013-01-
|
12
|
+
s.date = "2013-01-10"
|
13
13
|
s.description = "A simple Ruby client for the parse.com REST API"
|
14
14
|
s.email = "adelevie@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -26,7 +26,10 @@ Gem::Specification.new do |s|
|
|
26
26
|
"VERSION",
|
27
27
|
"example.rb",
|
28
28
|
"fixtures/vcr_cassettes/test_array_add.yml",
|
29
|
+
"fixtures/vcr_cassettes/test_batch_create_object.yml",
|
30
|
+
"fixtures/vcr_cassettes/test_batch_delete_object.yml",
|
29
31
|
"fixtures/vcr_cassettes/test_batch_run.yml",
|
32
|
+
"fixtures/vcr_cassettes/test_batch_update_object.yml",
|
30
33
|
"fixtures/vcr_cassettes/test_cloud_function.yml",
|
31
34
|
"fixtures/vcr_cassettes/test_created_at.yml",
|
32
35
|
"fixtures/vcr_cassettes/test_deep_parse.yml",
|
@@ -38,6 +41,7 @@ Gem::Specification.new do |s|
|
|
38
41
|
"fixtures/vcr_cassettes/test_object_id.yml",
|
39
42
|
"fixtures/vcr_cassettes/test_parse_delete.yml",
|
40
43
|
"fixtures/vcr_cassettes/test_pointer.yml",
|
44
|
+
"fixtures/vcr_cassettes/test_request_batch.yml",
|
41
45
|
"fixtures/vcr_cassettes/test_server_update.yml",
|
42
46
|
"fixtures/vcr_cassettes/test_simple_save.yml",
|
43
47
|
"fixtures/vcr_cassettes/test_update.yml",
|
data/test/test_batch.rb
CHANGED
@@ -56,4 +56,60 @@ class TestBatch < Test::Unit::TestCase
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
def test_create_object
|
60
|
+
VCR.use_cassette('test_batch_create_object', :record => :new_episodes) do
|
61
|
+
objects = [1, 2, 3, 4, 5].map do |i|
|
62
|
+
p = Parse::Object.new("BatchTestObject")
|
63
|
+
p["foo"] = "#{i}"
|
64
|
+
p
|
65
|
+
end
|
66
|
+
batch = Parse::Batch.new
|
67
|
+
objects.each do |obj|
|
68
|
+
batch.create_object(obj)
|
69
|
+
end
|
70
|
+
resp = batch.run!
|
71
|
+
assert_equal Array, resp.class
|
72
|
+
assert_equal resp.first["success"]["objectId"].class, String
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_update_object
|
77
|
+
VCR.use_cassette('test_batch_update_object', :record => :new_episodes) do
|
78
|
+
objects = [1, 2, 3, 4, 5].map do |i|
|
79
|
+
p = Parse::Object.new("BatchTestObject")
|
80
|
+
p["foo"] = "#{i}"
|
81
|
+
p.save
|
82
|
+
p
|
83
|
+
end
|
84
|
+
objects.map do |obj|
|
85
|
+
obj["foo"] = "updated"
|
86
|
+
end
|
87
|
+
batch = Parse::Batch.new
|
88
|
+
objects.each do |obj|
|
89
|
+
batch.update_object(obj)
|
90
|
+
end
|
91
|
+
resp = batch.run!
|
92
|
+
assert_equal Array, resp.class
|
93
|
+
assert_equal resp.first["success"]["updatedAt"].class, String
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_delete_object
|
98
|
+
VCR.use_cassette('test_batch_delete_object', :record => :new_episodes) do
|
99
|
+
objects = [1, 2, 3, 4, 5].map do |i|
|
100
|
+
p = Parse::Object.new("BatchTestObject")
|
101
|
+
p["foo"] = "#{i}"
|
102
|
+
p.save
|
103
|
+
p
|
104
|
+
end
|
105
|
+
batch = Parse::Batch.new
|
106
|
+
objects.each do |obj|
|
107
|
+
batch.delete_object(obj)
|
108
|
+
end
|
109
|
+
resp = batch.run!
|
110
|
+
assert_equal Array, resp.class
|
111
|
+
assert_equal resp.first["success"], true
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
59
115
|
end
|
data/test/test_client.rb
CHANGED
@@ -2,7 +2,19 @@ require 'helper'
|
|
2
2
|
|
3
3
|
class TestClient < Test::Unit::TestCase
|
4
4
|
def setup
|
5
|
-
Parse.init
|
5
|
+
@client = Parse.init
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_request
|
9
|
+
VCR.use_cassette('test_request', :record => :new_episodes) do
|
10
|
+
response = mock()
|
11
|
+
response.stubs(:body).returns({'code' => Parse::Protocol::ERROR_TIMEOUT}.to_json)
|
12
|
+
response.stubs(:status).returns(400)
|
13
|
+
@client.session.expects(:request).times(Parse::Client::DEFAULT_RETRIES + 1).returns(response)
|
14
|
+
assert_raise do
|
15
|
+
@client.request(nil)
|
16
|
+
end
|
17
|
+
end
|
6
18
|
end
|
7
19
|
|
8
20
|
def test_simple_save
|
data/test/test_object.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parse-ruby-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-01-
|
13
|
+
date: 2013-01-10 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: patron
|
@@ -173,7 +173,10 @@ files:
|
|
173
173
|
- VERSION
|
174
174
|
- example.rb
|
175
175
|
- fixtures/vcr_cassettes/test_array_add.yml
|
176
|
+
- fixtures/vcr_cassettes/test_batch_create_object.yml
|
177
|
+
- fixtures/vcr_cassettes/test_batch_delete_object.yml
|
176
178
|
- fixtures/vcr_cassettes/test_batch_run.yml
|
179
|
+
- fixtures/vcr_cassettes/test_batch_update_object.yml
|
177
180
|
- fixtures/vcr_cassettes/test_cloud_function.yml
|
178
181
|
- fixtures/vcr_cassettes/test_created_at.yml
|
179
182
|
- fixtures/vcr_cassettes/test_deep_parse.yml
|
@@ -185,6 +188,7 @@ files:
|
|
185
188
|
- fixtures/vcr_cassettes/test_object_id.yml
|
186
189
|
- fixtures/vcr_cassettes/test_parse_delete.yml
|
187
190
|
- fixtures/vcr_cassettes/test_pointer.yml
|
191
|
+
- fixtures/vcr_cassettes/test_request_batch.yml
|
188
192
|
- fixtures/vcr_cassettes/test_server_update.yml
|
189
193
|
- fixtures/vcr_cassettes/test_simple_save.yml
|
190
194
|
- fixtures/vcr_cassettes/test_update.yml
|
@@ -233,7 +237,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
233
237
|
version: '0'
|
234
238
|
segments:
|
235
239
|
- 0
|
236
|
-
hash:
|
240
|
+
hash: -4088256364268233622
|
237
241
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
238
242
|
none: false
|
239
243
|
requirements:
|