parse-ruby-client 0.1.1 → 0.1.2
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/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
|