parse-ruby-client 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -1
- data/Gemfile.lock +6 -0
- data/VERSION +1 -1
- data/lib/parse/client.rb +20 -6
- data/lib/parse/datatypes.rb +161 -20
- data/lib/parse/object.rb +12 -3
- data/lib/parse/protocol.rb +16 -2
- data/lib/parse/push.rb +10 -5
- data/lib/parse/query.rb +28 -2
- data/lib/parse/util.rb +7 -5
- data/parse-ruby-client.gemspec +9 -3
- data/test/helper.rb +1 -0
- data/test/test_datatypes.rb +33 -12
- data/test/test_object.rb +13 -2
- data/test/test_push.rb +22 -4
- data/test/test_query.rb +43 -1
- metadata +78 -16
data/Gemfile
CHANGED
@@ -7,10 +7,12 @@ source "http://rubygems.org"
|
|
7
7
|
# Include everything needed to run rake, tests, features, etc.
|
8
8
|
group :development do
|
9
9
|
gem "shoulda", ">= 0"
|
10
|
+
gem "test-unit", '= 2.5.0'
|
11
|
+
gem "mocha", '= 0.12.0', :require => false
|
10
12
|
gem "bundler", "~> 1.0.0"
|
11
13
|
gem "jeweler", "~> 1.6.4"
|
12
14
|
gem "rcov", ">= 0"
|
13
15
|
end
|
14
16
|
|
15
17
|
gem "patron"
|
16
|
-
gem "vcr"
|
18
|
+
gem "vcr"
|
data/Gemfile.lock
CHANGED
@@ -6,10 +6,14 @@ GEM
|
|
6
6
|
bundler (~> 1.0)
|
7
7
|
git (>= 1.2.5)
|
8
8
|
rake
|
9
|
+
metaclass (0.0.1)
|
10
|
+
mocha (0.12.0)
|
11
|
+
metaclass (~> 0.0.1)
|
9
12
|
patron (0.4.17)
|
10
13
|
rake (0.9.2.2)
|
11
14
|
rcov (0.9.11)
|
12
15
|
shoulda (2.11.3)
|
16
|
+
test-unit (2.5.0)
|
13
17
|
vcr (2.0.1)
|
14
18
|
|
15
19
|
PLATFORMS
|
@@ -18,7 +22,9 @@ PLATFORMS
|
|
18
22
|
DEPENDENCIES
|
19
23
|
bundler (~> 1.0.0)
|
20
24
|
jeweler (~> 1.6.4)
|
25
|
+
mocha (= 0.12.0)
|
21
26
|
patron
|
22
27
|
rcov
|
23
28
|
shoulda
|
29
|
+
test-unit (= 2.5.0)
|
24
30
|
vcr
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/lib/parse/client.rb
CHANGED
@@ -11,12 +11,16 @@ module Parse
|
|
11
11
|
attr_accessor :host
|
12
12
|
attr_accessor :application_id
|
13
13
|
attr_accessor :api_key
|
14
|
+
attr_accessor :master_key
|
15
|
+
attr_accessor :session_token
|
14
16
|
attr_accessor :session
|
15
17
|
|
16
18
|
def initialize(data = {})
|
17
19
|
@host = data[:host] || Protocol::HOST
|
18
20
|
@application_id = data[:application_id]
|
19
21
|
@api_key = data[:api_key]
|
22
|
+
@master_key = data[:master_key]
|
23
|
+
@session_token = data[:session_token]
|
20
24
|
@session = Patron::Session.new
|
21
25
|
@session.timeout = 30
|
22
26
|
@session.connect_timeout = 30
|
@@ -25,8 +29,6 @@ module Parse
|
|
25
29
|
@session.headers["Content-Type"] = "application/json"
|
26
30
|
@session.headers["Accept"] = "application/json"
|
27
31
|
@session.headers["User-Agent"] = "Parse for Ruby, 0.0"
|
28
|
-
@session.headers[Protocol::HEADER_API_KEY] = @api_key
|
29
|
-
@session.headers[Protocol::HEADER_APP_ID] = @application_id
|
30
32
|
end
|
31
33
|
|
32
34
|
# Perform an HTTP request for the given uri and method
|
@@ -34,6 +36,11 @@ module Parse
|
|
34
36
|
# ParseProtocolError if the response has an error status code,
|
35
37
|
# and will return the parsed JSON body on success, if there is one.
|
36
38
|
def request(uri, method = :get, body = nil, query = nil, max_retries = 2)
|
39
|
+
@session.headers[Protocol::HEADER_MASTER_KEY] = @master_key
|
40
|
+
@session.headers[Protocol::HEADER_API_KEY] = @api_key
|
41
|
+
@session.headers[Protocol::HEADER_APP_ID] = @application_id
|
42
|
+
@session.headers[Protocol::HEADER_SESSION_TOKEN] = @session_token
|
43
|
+
|
37
44
|
options = {}
|
38
45
|
if body
|
39
46
|
options[:data] = body
|
@@ -48,7 +55,7 @@ module Parse
|
|
48
55
|
rescue Patron::TimeoutError
|
49
56
|
num_tries += 1
|
50
57
|
if num_tries <= max_retries
|
51
|
-
retry
|
58
|
+
retry
|
52
59
|
else
|
53
60
|
raise Patron::TimeoutError
|
54
61
|
end
|
@@ -92,10 +99,17 @@ module Parse
|
|
92
99
|
# Initialize the singleton instance of Client which is used
|
93
100
|
# by all API methods. Parse.init must be called before saving
|
94
101
|
# or retrieving any objects.
|
95
|
-
def Parse.init(data = {
|
96
|
-
|
102
|
+
def Parse.init(data = {})
|
103
|
+
defaulted = {:application_id => ENV["PARSE_APPLICATION_ID"],
|
104
|
+
:api_key => ENV["PARSE_REST_API_KEY"]}
|
105
|
+
defaulted.merge!(data)
|
106
|
+
|
107
|
+
# use less permissive key if both are specified
|
108
|
+
defaulted[:master_key] = ENV["PARSE_MASTER_API_KEY"] unless data[:master_key] || defaulted[:api_key]
|
109
|
+
|
110
|
+
@@client = Client.new(defaulted)
|
97
111
|
end
|
98
|
-
|
112
|
+
|
99
113
|
# Used mostly for testing. Lets you delete the api key global vars.
|
100
114
|
def Parse.destroy
|
101
115
|
@@client = nil
|
data/lib/parse/datatypes.rb
CHANGED
@@ -14,6 +14,18 @@ module Parse
|
|
14
14
|
@parse_object_id = data[Protocol::KEY_OBJECT_ID]
|
15
15
|
end
|
16
16
|
|
17
|
+
def eql?(other)
|
18
|
+
self.class.equal?(other.class) &&
|
19
|
+
class_name == other.class_name &&
|
20
|
+
parse_object_id == other.parse_object_id
|
21
|
+
end
|
22
|
+
|
23
|
+
alias == eql?
|
24
|
+
|
25
|
+
def hash
|
26
|
+
class_name.hash ^ parse_object_id.hash
|
27
|
+
end
|
28
|
+
|
17
29
|
def as_json(*a)
|
18
30
|
{
|
19
31
|
Protocol::KEY_TYPE => Protocol::TYPE_POINTER,
|
@@ -21,14 +33,14 @@ module Parse
|
|
21
33
|
Protocol::KEY_OBJECT_ID => @parse_object_id
|
22
34
|
}
|
23
35
|
end
|
24
|
-
|
36
|
+
|
25
37
|
def to_json(*a)
|
26
38
|
as_json.to_json(*a)
|
27
39
|
end
|
28
40
|
|
29
41
|
# Retrieve the Parse object referenced by this pointer.
|
30
42
|
def get
|
31
|
-
Parse.get @class_name, @parse_object_id
|
43
|
+
Parse.get @class_name, @parse_object_id if @parse_object_id
|
32
44
|
end
|
33
45
|
end
|
34
46
|
|
@@ -48,13 +60,44 @@ module Parse
|
|
48
60
|
end
|
49
61
|
end
|
50
62
|
|
63
|
+
def eql?(other)
|
64
|
+
self.class.equal?(other.class) &&
|
65
|
+
value == other.value
|
66
|
+
end
|
67
|
+
|
68
|
+
alias == eql?
|
69
|
+
|
70
|
+
def hash
|
71
|
+
value.hash
|
72
|
+
end
|
73
|
+
|
74
|
+
def <=>(other)
|
75
|
+
value <=> other.value
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_s
|
79
|
+
value.to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
def method_missing(method, *args, &block)
|
83
|
+
if value.respond_to?(method)
|
84
|
+
value.send(method, *args, &block)
|
85
|
+
else
|
86
|
+
super(method)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def respond_to?(method, include_private = false)
|
91
|
+
super || value.respond_to?(method, include_private)
|
92
|
+
end
|
93
|
+
|
51
94
|
def as_json(*a)
|
52
95
|
{
|
53
96
|
Protocol::KEY_TYPE => Protocol::TYPE_DATE,
|
54
97
|
"iso" => value.iso8601
|
55
98
|
}
|
56
99
|
end
|
57
|
-
|
100
|
+
|
58
101
|
def to_json(*a)
|
59
102
|
as_json.to_json(*a)
|
60
103
|
end
|
@@ -71,78 +114,139 @@ module Parse
|
|
71
114
|
@value = Base64.decode64(bytes)
|
72
115
|
end
|
73
116
|
|
117
|
+
def eql?(other)
|
118
|
+
self.class.equal?(other.class) &&
|
119
|
+
value == other.value
|
120
|
+
end
|
121
|
+
|
122
|
+
alias == eql?
|
123
|
+
|
124
|
+
def hash
|
125
|
+
value.hash
|
126
|
+
end
|
127
|
+
|
128
|
+
def <=>(other)
|
129
|
+
value <=> other.value
|
130
|
+
end
|
131
|
+
|
132
|
+
def method_missing(method, *args, &block)
|
133
|
+
if value.respond_to?(method)
|
134
|
+
value.send(method, *args, &block)
|
135
|
+
else
|
136
|
+
super(method)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def respond_to?(method, include_private = false)
|
141
|
+
super || value.respond_to?(method, include_private)
|
142
|
+
end
|
143
|
+
|
74
144
|
def as_json(*a)
|
75
145
|
{
|
76
146
|
Protocol::KEY_TYPE => Protocol::TYPE_BYTES,
|
77
147
|
"base64" => Base64.encode64(@value)
|
78
148
|
}
|
79
149
|
end
|
80
|
-
|
150
|
+
|
81
151
|
def to_json(*a)
|
82
152
|
as_json.to_json(*a)
|
83
153
|
end
|
84
154
|
end
|
85
|
-
|
155
|
+
|
86
156
|
# Increment and Decrement
|
87
157
|
# ------------------------------------------------------------
|
88
|
-
|
158
|
+
|
89
159
|
class Increment
|
90
160
|
# '{"score": {"__op": "Increment", "amount": 1 } }'
|
91
161
|
attr_accessor :amount
|
92
|
-
|
162
|
+
|
93
163
|
def initialize(amount)
|
94
164
|
@amount = amount
|
95
165
|
end
|
96
|
-
|
166
|
+
|
167
|
+
def eql?(other)
|
168
|
+
self.class.equal?(other.class) &&
|
169
|
+
amount == other.amount
|
170
|
+
end
|
171
|
+
|
172
|
+
alias == eql?
|
173
|
+
|
174
|
+
def hash
|
175
|
+
amount.hash
|
176
|
+
end
|
177
|
+
|
97
178
|
def as_json(*a)
|
98
179
|
{
|
99
180
|
Protocol::KEY_OP => Protocol::KEY_INCREMENT,
|
100
181
|
Protocol::KEY_AMOUNT => @amount
|
101
182
|
}
|
102
183
|
end
|
103
|
-
|
184
|
+
|
104
185
|
def to_json(*a)
|
105
186
|
as_json.to_json(*a)
|
106
187
|
end
|
107
188
|
end
|
108
|
-
|
189
|
+
|
109
190
|
class Decrement
|
110
191
|
# '{"score": {"__op": "Decrement", "amount": 1 } }'
|
111
192
|
attr_accessor :amount
|
112
|
-
|
193
|
+
|
113
194
|
def initialize(amount)
|
114
195
|
@amount = amount
|
115
196
|
end
|
116
|
-
|
197
|
+
|
198
|
+
def eql?(other)
|
199
|
+
self.class.equal?(other.class) &&
|
200
|
+
amount == other.amount
|
201
|
+
end
|
202
|
+
|
203
|
+
alias == eql?
|
204
|
+
|
205
|
+
def hash
|
206
|
+
amount.hash
|
207
|
+
end
|
208
|
+
|
117
209
|
def as_json(*a)
|
118
210
|
{
|
119
211
|
Protocol::KEY_OP => Protocol::KEY_DECREMENT,
|
120
212
|
Protocol::KEY_AMOUNT => @amount
|
121
213
|
}
|
122
214
|
end
|
123
|
-
|
215
|
+
|
124
216
|
def to_json(*a)
|
125
217
|
as_json.to_json(*a)
|
126
218
|
end
|
127
219
|
end
|
128
|
-
|
220
|
+
|
129
221
|
# GeoPoint
|
130
222
|
# ------------------------------------------------------------
|
131
|
-
|
223
|
+
|
132
224
|
class GeoPoint
|
133
225
|
# '{"location": {"__type":"GeoPoint", "latitude":40.0, "longitude":-30.0}}'
|
134
226
|
attr_accessor :longitude, :latitude
|
135
|
-
|
227
|
+
|
136
228
|
def initialize(data)
|
137
229
|
@longitude = data["longitude"]
|
138
230
|
@latitude = data["latitude"]
|
139
|
-
|
231
|
+
|
140
232
|
if !@longitude && !@latitude
|
141
233
|
@longitude = data[:longitude]
|
142
234
|
@latitude = data[:latitude]
|
143
235
|
end
|
144
236
|
end
|
145
|
-
|
237
|
+
|
238
|
+
def eql?(other)
|
239
|
+
self.class.equal?(other.class) &&
|
240
|
+
longitude == other.longitude &&
|
241
|
+
latitude == other.latitude
|
242
|
+
end
|
243
|
+
|
244
|
+
alias == eql?
|
245
|
+
|
246
|
+
def hash
|
247
|
+
longitude.hash ^ latitude.hash
|
248
|
+
end
|
249
|
+
|
146
250
|
def as_json(*a)
|
147
251
|
{
|
148
252
|
Protocol::KEY_TYPE => Protocol::TYPE_GEOPOINT,
|
@@ -150,11 +254,48 @@ module Parse
|
|
150
254
|
"longitude" => @longitude
|
151
255
|
}
|
152
256
|
end
|
153
|
-
|
257
|
+
|
154
258
|
def to_json(*a)
|
155
259
|
as_json.to_json(*a)
|
156
260
|
end
|
157
261
|
end
|
158
|
-
|
262
|
+
|
263
|
+
# File
|
264
|
+
# ------------------------------------------------------------
|
265
|
+
|
266
|
+
class File
|
267
|
+
# '{"avatar": {"__type":"File", "name":"profile.png", "url"=>"http://files.parse.com/blah/profile.png"}}'
|
268
|
+
attr_accessor :name
|
269
|
+
attr_accessor :url
|
270
|
+
|
271
|
+
def initialize(data)
|
272
|
+
@name = data["name"]
|
273
|
+
@url = data["url"]
|
274
|
+
end
|
275
|
+
|
276
|
+
def eql?(other)
|
277
|
+
self.class.equal?(other.class) &&
|
278
|
+
url == other.url
|
279
|
+
end
|
280
|
+
|
281
|
+
alias == eql?
|
282
|
+
|
283
|
+
def hash
|
284
|
+
url.hash
|
285
|
+
end
|
286
|
+
|
287
|
+
def as_json(*a)
|
288
|
+
{
|
289
|
+
Protocol::KEY_TYPE => Protocol::TYPE_FILE,
|
290
|
+
"name" => @name,
|
291
|
+
"url" => @url
|
292
|
+
}
|
293
|
+
end
|
294
|
+
|
295
|
+
def to_json(*a)
|
296
|
+
as_json.to_json(*a)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
159
300
|
|
160
301
|
end
|
data/lib/parse/object.rb
CHANGED
@@ -24,7 +24,7 @@ module Parse
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def pointer
|
27
|
-
Parse::Pointer.new
|
27
|
+
Parse::Pointer.new(self.merge(Parse::Protocol::KEY_CLASS_NAME => class_name)) unless new?
|
28
28
|
end
|
29
29
|
|
30
30
|
# Merge a hash parsed from the JSON representation into
|
@@ -72,8 +72,17 @@ module Parse
|
|
72
72
|
|
73
73
|
without_reserved = self.dup
|
74
74
|
Protocol::RESERVED_KEYS.each { |k| without_reserved.delete(k) }
|
75
|
-
body = without_reserved.to_json
|
76
75
|
|
76
|
+
without_relations = without_reserved
|
77
|
+
without_relations.each { |k,v|
|
78
|
+
if v.is_a? Hash
|
79
|
+
if v[Protocol::KEY_TYPE] == Protocol::TYPE_RELATION
|
80
|
+
without_relations.delete(k)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
}
|
84
|
+
|
85
|
+
body = without_relations.to_json
|
77
86
|
data = Parse.client.request(self.uri, method, body)
|
78
87
|
|
79
88
|
if data
|
@@ -93,7 +102,7 @@ module Parse
|
|
93
102
|
# values from the API.
|
94
103
|
def refresh
|
95
104
|
if @parse_object_id
|
96
|
-
data = Parse.
|
105
|
+
data = Parse.get @class_name, @parse_object_id
|
97
106
|
if data
|
98
107
|
parse data
|
99
108
|
end
|
data/lib/parse/protocol.rb
CHANGED
@@ -22,6 +22,13 @@ module Parse
|
|
22
22
|
# Parse API.
|
23
23
|
HEADER_API_KEY = "X-Parse-REST-API-Key"
|
24
24
|
|
25
|
+
# The HTTP header used for passing your API Master key to the
|
26
|
+
# Parse API.
|
27
|
+
HEADER_MASTER_KEY = "X-Parse-Master-Key"
|
28
|
+
|
29
|
+
# The HTTP header used for passing your authenticated session
|
30
|
+
HEADER_SESSION_TOKEN = "X-Parse-Session-Token"
|
31
|
+
|
25
32
|
# JSON Keys
|
26
33
|
# ----------------------------------------
|
27
34
|
|
@@ -90,11 +97,18 @@ module Parse
|
|
90
97
|
# a file.
|
91
98
|
TYPE_FILE = "File"
|
92
99
|
|
100
|
+
# The data type name for special JSON objects representing
|
101
|
+
# a Relation.
|
102
|
+
TYPE_RELATION = "Relation"
|
103
|
+
|
93
104
|
# The class name for User objects, when referenced by a Pointer.
|
94
105
|
CLASS_USER = "_User"
|
106
|
+
|
107
|
+
CLASS_INSTALLATION = "_Installation"
|
108
|
+
|
95
109
|
USER_LOGIN_URI = "/#{VERSION}/login"
|
96
110
|
PASSWORD_RESET_URI = "/#{VERSION}/requestPasswordReset"
|
97
|
-
|
111
|
+
|
98
112
|
KEY_USER_SESSION_TOKEN = "sessionToken"
|
99
113
|
|
100
114
|
# URI Helpers
|
@@ -109,7 +123,7 @@ module Parse
|
|
109
123
|
"/#{VERSION}/classes/#{class_name}"
|
110
124
|
end
|
111
125
|
end
|
112
|
-
|
126
|
+
|
113
127
|
|
114
128
|
# Construct a uri referencing a given Parse user
|
115
129
|
# instance or the users category.
|
data/lib/parse/push.rb
CHANGED
@@ -5,6 +5,7 @@ module Parse
|
|
5
5
|
class Push
|
6
6
|
attr_accessor :channels
|
7
7
|
attr_accessor :channel
|
8
|
+
attr_accessor :where
|
8
9
|
attr_accessor :type
|
9
10
|
attr_accessor :expiration_time_interval
|
10
11
|
attr_accessor :expiration_time
|
@@ -17,18 +18,22 @@ module Parse
|
|
17
18
|
|
18
19
|
def save
|
19
20
|
uri = Protocol.push_uri
|
20
|
-
|
21
|
+
|
21
22
|
body = { :data => @data, :channel => @channel }
|
22
|
-
|
23
|
+
|
23
24
|
if @channels
|
24
25
|
body.merge!({ :channels => @channels })
|
25
26
|
body.delete :channel
|
26
27
|
end
|
27
|
-
|
28
|
+
|
29
|
+
if @where
|
30
|
+
body.merge!({ :where => @where })
|
31
|
+
end
|
32
|
+
|
28
33
|
body.merge!({ :expiration_time_interval => @expiration_time_interval }) if @expiration_time_interval
|
29
|
-
body.merge!({ :expiration_time => @expiration_time }) if @expiration_time
|
34
|
+
body.merge!({ :expiration_time => @expiration_time }) if @expiration_time
|
30
35
|
body.merge!({ :type => @type }) if @type
|
31
|
-
|
36
|
+
|
32
37
|
response = Parse.client.request uri, :post, body.to_json, nil
|
33
38
|
end
|
34
39
|
|
data/lib/parse/query.rb
CHANGED
@@ -15,9 +15,11 @@ module Parse
|
|
15
15
|
@class_name = cls_name
|
16
16
|
@where = {}
|
17
17
|
@order = :ascending
|
18
|
+
@ors = []
|
18
19
|
end
|
19
20
|
|
20
21
|
def add_constraint(field, constraint)
|
22
|
+
raise ArgumentError, "cannot add constraint to an $or query" if @ors.size > 0
|
21
23
|
current = where[field]
|
22
24
|
if current && current.is_a?(Hash) && constraint.is_a?(Hash)
|
23
25
|
current.merge! constraint
|
@@ -27,6 +29,12 @@ module Parse
|
|
27
29
|
end
|
28
30
|
#private :add_constraint
|
29
31
|
|
32
|
+
def or(query)
|
33
|
+
raise ArgumentError, "you must pass an entire #{self.class} to \#or" unless query.is_a?(self.class)
|
34
|
+
@ors << query
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
30
38
|
def eq(field, value)
|
31
39
|
add_constraint field, value
|
32
40
|
self
|
@@ -67,16 +75,34 @@ module Parse
|
|
67
75
|
self
|
68
76
|
end
|
69
77
|
|
78
|
+
def in_query(field, query)
|
79
|
+
query_hash = {Parse::Protocol::KEY_CLASS_NAME => query.class_name, "where" => query.where}
|
80
|
+
add_constraint(field, "$inQuery" => query_hash)
|
81
|
+
end
|
82
|
+
|
70
83
|
def count
|
71
84
|
@count = true
|
72
85
|
self
|
73
86
|
end
|
74
87
|
|
88
|
+
def where_as_json
|
89
|
+
if @ors.size > 0
|
90
|
+
{"$or" => [self.where] + @ors.map{|query| query.where_as_json}}
|
91
|
+
else
|
92
|
+
@where
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
75
96
|
def get
|
76
97
|
uri = Protocol.class_uri @class_name
|
77
|
-
|
98
|
+
if @class_name == Parse::Protocol::CLASS_USER
|
99
|
+
uri = Protocol.user_uri
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
query = { "where" => CGI.escape(where_as_json.to_json) }
|
78
104
|
set_order(query)
|
79
|
-
[:count, :limit].each {|a| merge_attribute(a, query)}
|
105
|
+
[:count, :limit, :skip].each {|a| merge_attribute(a, query)}
|
80
106
|
|
81
107
|
response = Parse.client.request uri, :get, nil, query
|
82
108
|
Parse.parse_json class_name, response
|
data/lib/parse/util.rb
CHANGED
@@ -9,9 +9,6 @@ module Parse
|
|
9
9
|
|
10
10
|
if obj.nil?
|
11
11
|
nil
|
12
|
-
# String
|
13
|
-
elsif obj.is_a? String
|
14
|
-
parse_json class_name, JSON.parse(obj)
|
15
12
|
|
16
13
|
# Array
|
17
14
|
elsif obj.is_a? Array
|
@@ -25,10 +22,11 @@ module Parse
|
|
25
22
|
parse_datatype obj
|
26
23
|
elsif obj.size == 1 && obj.has_key?(Protocol::KEY_RESULTS) && obj[Protocol::KEY_RESULTS].is_a?(Array)
|
27
24
|
obj[Protocol::KEY_RESULTS].collect { |o| parse_json(class_name, o) }
|
28
|
-
else # otherwise it must be a regular object
|
29
|
-
Parse::Object.new class_name, obj
|
25
|
+
else # otherwise it must be a regular object, so deep parse it avoiding re-JSON.parsing raw Strings
|
26
|
+
Parse::Object.new class_name, Hash[obj.map{|k,v| [k, parse_json(nil, v)]}]
|
30
27
|
end
|
31
28
|
|
29
|
+
# primitive
|
32
30
|
else
|
33
31
|
obj
|
34
32
|
end
|
@@ -44,6 +42,10 @@ module Parse
|
|
44
42
|
Parse::Bytes.new obj
|
45
43
|
when Protocol::TYPE_DATE
|
46
44
|
Parse::Date.new obj
|
45
|
+
when Protocol::TYPE_GEOPOINT
|
46
|
+
Parse::GeoPoint.new obj
|
47
|
+
when Protocol::TYPE_FILE
|
48
|
+
Parse::File.new obj
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
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.2"
|
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 = "2012-
|
12
|
+
s.date = "2012-08-31"
|
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 = [
|
@@ -52,7 +52,7 @@ Gem::Specification.new do |s|
|
|
52
52
|
s.homepage = "http://github.com/adelevie/parse-ruby-client"
|
53
53
|
s.licenses = ["MIT"]
|
54
54
|
s.require_paths = ["lib"]
|
55
|
-
s.rubygems_version = "1.8.
|
55
|
+
s.rubygems_version = "1.8.24"
|
56
56
|
s.summary = "A simple Ruby client for the parse.com REST API"
|
57
57
|
|
58
58
|
if s.respond_to? :specification_version then
|
@@ -62,6 +62,8 @@ Gem::Specification.new do |s|
|
|
62
62
|
s.add_runtime_dependency(%q<patron>, [">= 0"])
|
63
63
|
s.add_runtime_dependency(%q<vcr>, [">= 0"])
|
64
64
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
65
|
+
s.add_development_dependency(%q<test-unit>, ["= 2.5.0"])
|
66
|
+
s.add_development_dependency(%q<mocha>, ["= 0.12.0"])
|
65
67
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
66
68
|
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
67
69
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
@@ -69,6 +71,8 @@ Gem::Specification.new do |s|
|
|
69
71
|
s.add_dependency(%q<patron>, [">= 0"])
|
70
72
|
s.add_dependency(%q<vcr>, [">= 0"])
|
71
73
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
74
|
+
s.add_dependency(%q<test-unit>, ["= 2.5.0"])
|
75
|
+
s.add_dependency(%q<mocha>, ["= 0.12.0"])
|
72
76
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
73
77
|
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
74
78
|
s.add_dependency(%q<rcov>, [">= 0"])
|
@@ -77,6 +81,8 @@ Gem::Specification.new do |s|
|
|
77
81
|
s.add_dependency(%q<patron>, [">= 0"])
|
78
82
|
s.add_dependency(%q<vcr>, [">= 0"])
|
79
83
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
84
|
+
s.add_dependency(%q<test-unit>, ["= 2.5.0"])
|
85
|
+
s.add_dependency(%q<mocha>, ["= 0.12.0"])
|
80
86
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
81
87
|
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
82
88
|
s.add_dependency(%q<rcov>, [">= 0"])
|
data/test/helper.rb
CHANGED
data/test/test_datatypes.rb
CHANGED
@@ -7,19 +7,21 @@ class TestDatatypes < Test::Unit::TestCase
|
|
7
7
|
Parse::Protocol::KEY_OBJECT_ID => "12345abcd"
|
8
8
|
}
|
9
9
|
p = Parse::Pointer.new data
|
10
|
-
|
11
|
-
assert_equal p.to_json, "{\"__type\":\"Pointer\",\"#{Parse::Protocol::KEY_CLASS_NAME}\":\"DatatypeTestClass\",\"#{Parse::Protocol::KEY_OBJECT_ID}\":\"12345abcd\"}"
|
10
|
+
|
11
|
+
assert_equal p.to_json, "{\"__type\":\"Pointer\",\"#{Parse::Protocol::KEY_CLASS_NAME}\":\"DatatypeTestClass\",\"#{Parse::Protocol::KEY_OBJECT_ID}\":\"12345abcd\"}"
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def test_date
|
15
15
|
date_time = DateTime.now
|
16
16
|
data = date_time
|
17
17
|
parse_date = Parse::Date.new data
|
18
|
-
|
18
|
+
|
19
19
|
assert_equal parse_date.value, date_time
|
20
20
|
assert_equal JSON.parse(parse_date.to_json)["iso"], date_time.iso8601
|
21
|
+
assert_equal 0, parse_date <=> parse_date
|
22
|
+
assert_equal 0, Parse::Date.new(data) <=> Parse::Date.new(data)
|
21
23
|
end
|
22
|
-
|
24
|
+
|
23
25
|
def test_bytes
|
24
26
|
data = {
|
25
27
|
"base64" => Base64.encode64("testing bytes!")
|
@@ -30,21 +32,21 @@ class TestDatatypes < Test::Unit::TestCase
|
|
30
32
|
assert_equal JSON.parse(byte.to_json)[Parse::Protocol::KEY_TYPE], Parse::Protocol::TYPE_BYTES
|
31
33
|
assert_equal JSON.parse(byte.to_json)["base64"], Base64.encode64("testing bytes!")
|
32
34
|
end
|
33
|
-
|
35
|
+
|
34
36
|
def test_increment
|
35
37
|
amount = 5
|
36
38
|
increment = Parse::Increment.new amount
|
37
|
-
|
39
|
+
|
38
40
|
assert_equal increment.to_json, "{\"__op\":\"Increment\",\"amount\":#{amount}}"
|
39
41
|
end
|
40
|
-
|
42
|
+
|
41
43
|
def test_decrement
|
42
44
|
amount = 5
|
43
45
|
increment = Parse::Decrement.new amount
|
44
|
-
|
46
|
+
|
45
47
|
assert_equal increment.to_json, "{\"__op\":\"Decrement\",\"amount\":#{amount}}"
|
46
48
|
end
|
47
|
-
|
49
|
+
|
48
50
|
def test_geopoint
|
49
51
|
# '{"location": {"__type":"GeoPoint", "latitude":40.0, "longitude":-30.0}}'
|
50
52
|
data = {
|
@@ -52,9 +54,28 @@ class TestDatatypes < Test::Unit::TestCase
|
|
52
54
|
"latitude" => -30.0
|
53
55
|
}
|
54
56
|
gp = Parse::GeoPoint.new data
|
55
|
-
|
56
|
-
assert_equal JSON.parse(gp.to_json)["longitude"], data["longitude"]
|
57
|
+
|
58
|
+
assert_equal JSON.parse(gp.to_json)["longitude"], data["longitude"]
|
57
59
|
assert_equal JSON.parse(gp.to_json)["latitude"], data["latitude"]
|
58
60
|
assert_equal JSON.parse(gp.to_json)[Parse::Protocol::KEY_TYPE], Parse::Protocol::TYPE_GEOPOINT
|
61
|
+
|
62
|
+
post = Parse::Object.new("Post")
|
63
|
+
post["location"] = gp
|
64
|
+
post.save
|
65
|
+
q = Parse.get("Post", post.id)
|
66
|
+
assert_equal gp, q["location"]
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_file
|
70
|
+
data = {"name" => "blah.png"}
|
71
|
+
file = Parse::File.new(data)
|
72
|
+
assert_equal JSON.parse(file.to_json)["name"], data["name"]
|
73
|
+
assert_equal JSON.parse(file.to_json)[Parse::Protocol::KEY_TYPE], Parse::Protocol::TYPE_FILE
|
74
|
+
|
75
|
+
post = Parse::Object.new("Post")
|
76
|
+
post["avatar"] = file
|
77
|
+
post.save
|
78
|
+
q = Parse.get("Post", post.id)
|
79
|
+
assert_equal file.name, q["avatar"].name
|
59
80
|
end
|
60
81
|
end
|
data/test/test_object.rb
CHANGED
@@ -22,8 +22,7 @@ class TestObject < Test::Unit::TestCase
|
|
22
22
|
|
23
23
|
def test_pointer
|
24
24
|
post = Parse::Object.new "Post"
|
25
|
-
|
26
|
-
assert_equal pointer.class_name, post.class_name
|
25
|
+
assert_nil post.pointer
|
27
26
|
|
28
27
|
post.save
|
29
28
|
pointer = post.pointer
|
@@ -64,4 +63,16 @@ class TestObject < Test::Unit::TestCase
|
|
64
63
|
end
|
65
64
|
end
|
66
65
|
|
66
|
+
def test_deep_parse
|
67
|
+
other = Parse::Object.new "Post"
|
68
|
+
other.save
|
69
|
+
post = Parse::Object.new "Post"
|
70
|
+
post["other"] = other.pointer
|
71
|
+
post.save
|
72
|
+
|
73
|
+
q = Parse.get("Post", post.id)
|
74
|
+
assert_equal Parse::Pointer, q["other"].class
|
75
|
+
assert_equal other.pointer, q["other"]
|
76
|
+
end
|
77
|
+
|
67
78
|
end
|
data/test/test_push.rb
CHANGED
@@ -1,14 +1,32 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
class TestPush < Test::Unit::TestCase
|
4
|
-
|
4
|
+
|
5
5
|
def setup
|
6
6
|
Parse.init
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
10
|
-
|
9
|
+
def test_save
|
10
|
+
data = {:foo => 'bar',
|
11
|
+
:alert => 'message'}
|
12
|
+
pf_push = Parse::Push.new(data, "some_chan")
|
13
|
+
pf_push.type = 'ios'
|
14
|
+
|
15
|
+
query = Parse::Query.new(Parse::Protocol::CLASS_INSTALLATION).eq('deviceToken', 'baz')
|
16
|
+
pf_push.where = query.where
|
17
|
+
|
18
|
+
Parse::Client.any_instance.expects(:request).with do |uri, method, body, query|
|
19
|
+
hash = JSON.parse(body)
|
20
|
+
assert_equal :post, method
|
21
|
+
assert has_entries('type' => 'ios', 'channel' => "some_chan").matches?([hash])
|
22
|
+
assert has_entries('foo' => 'bar', 'alert' => 'message').matches?([hash['data']])
|
23
|
+
assert has_entries('deviceToken' => 'baz').matches?([hash['where']])
|
24
|
+
assert_nil query
|
25
|
+
true
|
26
|
+
end.returns({}.to_json)
|
27
|
+
|
28
|
+
pf_push.save
|
11
29
|
end
|
12
|
-
|
30
|
+
|
13
31
|
|
14
32
|
end
|
data/test/test_query.rb
CHANGED
@@ -27,7 +27,7 @@ class TestQuery < Test::Unit::TestCase
|
|
27
27
|
q.add_constraint("player", { "$regex" => "regex voodoo"})
|
28
28
|
assert_equal q.where["player"], { "$regex" => "regex voodoo"}
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def test_eq
|
32
32
|
q = Parse::Query.new "TestQuery"
|
33
33
|
q.eq("points", 5)
|
@@ -35,4 +35,46 @@ class TestQuery < Test::Unit::TestCase
|
|
35
35
|
q.eq("player", "michael@jordan.com")
|
36
36
|
assert_equal q.where, {"points" => 5, "player" => "michael@jordan.com"}
|
37
37
|
end
|
38
|
+
|
39
|
+
def test_limit_skip
|
40
|
+
q = Parse::Query.new "TestQuery"
|
41
|
+
q.limit = 2
|
42
|
+
q.skip = 3
|
43
|
+
query_matcher = has_entries(:limit => 2, :skip => 3)
|
44
|
+
Parse::Client.any_instance.expects(:request).with(anything, :get, nil, query_matcher).returns({}.to_json)
|
45
|
+
q.get
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_count
|
49
|
+
q = Parse::Query.new "TestQuery"
|
50
|
+
q.count = true
|
51
|
+
query_matcher = has_entries(:count => true)
|
52
|
+
Parse::Client.any_instance.expects(:request).with(anything, :get, nil, query_matcher).returns({}.to_json)
|
53
|
+
q.get
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_or
|
57
|
+
foo = Parse::Object.new "Post"
|
58
|
+
foo["random"] = rand
|
59
|
+
foo.save
|
60
|
+
foo_query = Parse::Query.new("Post").eq("random", foo["random"])
|
61
|
+
assert_equal 1, foo_query.get.size
|
62
|
+
|
63
|
+
bar = Parse::Object.new "Post"
|
64
|
+
bar["random"] = rand
|
65
|
+
bar.save
|
66
|
+
bar_query = Parse::Query.new("Post").eq("random", bar["random"])
|
67
|
+
assert_equal 1, foo_query.get.size
|
68
|
+
|
69
|
+
query = foo_query.or(bar_query)
|
70
|
+
assert_equal 2, query.get.size
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_in_query
|
74
|
+
outer_query = Parse::Query.new "Outer"
|
75
|
+
inner_query = Parse::Query.new "Inner"
|
76
|
+
inner_query.eq("foo", "bar")
|
77
|
+
outer_query.in_query("inner", inner_query)
|
78
|
+
assert_equal({"inner"=>{"$inQuery"=>{"className"=>"Inner", "where"=>{"foo"=>"bar"}}}}, outer_query.where)
|
79
|
+
end
|
38
80
|
end
|
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.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-08-31 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: patron
|
17
|
-
requirement:
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,15 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements:
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
26
31
|
- !ruby/object:Gem::Dependency
|
27
32
|
name: vcr
|
28
|
-
requirement:
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
29
34
|
none: false
|
30
35
|
requirements:
|
31
36
|
- - ! '>='
|
@@ -33,21 +38,63 @@ dependencies:
|
|
33
38
|
version: '0'
|
34
39
|
type: :runtime
|
35
40
|
prerelease: false
|
36
|
-
version_requirements:
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
37
47
|
- !ruby/object:Gem::Dependency
|
38
48
|
name: shoulda
|
39
|
-
requirement:
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
58
|
none: false
|
41
59
|
requirements:
|
42
60
|
- - ! '>='
|
43
61
|
- !ruby/object:Gem::Version
|
44
62
|
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: test-unit
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - '='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 2.5.0
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - '='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 2.5.0
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: mocha
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - '='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 0.12.0
|
45
87
|
type: :development
|
46
88
|
prerelease: false
|
47
|
-
version_requirements:
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - '='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 0.12.0
|
48
95
|
- !ruby/object:Gem::Dependency
|
49
96
|
name: bundler
|
50
|
-
requirement:
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
51
98
|
none: false
|
52
99
|
requirements:
|
53
100
|
- - ~>
|
@@ -55,10 +102,15 @@ dependencies:
|
|
55
102
|
version: 1.0.0
|
56
103
|
type: :development
|
57
104
|
prerelease: false
|
58
|
-
version_requirements:
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.0.0
|
59
111
|
- !ruby/object:Gem::Dependency
|
60
112
|
name: jeweler
|
61
|
-
requirement:
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
62
114
|
none: false
|
63
115
|
requirements:
|
64
116
|
- - ~>
|
@@ -66,10 +118,15 @@ dependencies:
|
|
66
118
|
version: 1.6.4
|
67
119
|
type: :development
|
68
120
|
prerelease: false
|
69
|
-
version_requirements:
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ~>
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 1.6.4
|
70
127
|
- !ruby/object:Gem::Dependency
|
71
128
|
name: rcov
|
72
|
-
requirement:
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
73
130
|
none: false
|
74
131
|
requirements:
|
75
132
|
- - ! '>='
|
@@ -77,7 +134,12 @@ dependencies:
|
|
77
134
|
version: '0'
|
78
135
|
type: :development
|
79
136
|
prerelease: false
|
80
|
-
version_requirements:
|
137
|
+
version_requirements: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
81
143
|
description: A simple Ruby client for the parse.com REST API
|
82
144
|
email: adelevie@gmail.com
|
83
145
|
executables: []
|
@@ -132,7 +194,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
132
194
|
version: '0'
|
133
195
|
segments:
|
134
196
|
- 0
|
135
|
-
hash:
|
197
|
+
hash: 2354067513295992545
|
136
198
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
199
|
none: false
|
138
200
|
requirements:
|
@@ -141,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
203
|
version: '0'
|
142
204
|
requirements: []
|
143
205
|
rubyforge_project:
|
144
|
-
rubygems_version: 1.8.
|
206
|
+
rubygems_version: 1.8.24
|
145
207
|
signing_key:
|
146
208
|
specification_version: 3
|
147
209
|
summary: A simple Ruby client for the parse.com REST API
|