parse_resource 1.7.1 → 1.7.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 +0 -2
- data/README.md +76 -5
- data/VERSION +1 -1
- data/lib/.DS_Store +0 -0
- data/lib/parse_resource.rb +7 -6
- data/lib/parse_resource/base.rb +459 -0
- data/lib/{parse_error.rb → parse_resource/parse_error.rb} +1 -1
- data/lib/parse_resource/parse_exceptions.rb +2 -0
- data/lib/parse_resource/parse_user.rb +61 -0
- data/lib/{parse_user_validator.rb → parse_resource/parse_user_validator.rb} +0 -0
- data/lib/{query.rb → parse_resource/query.rb} +10 -2
- data/parse_resource.gemspec +11 -8
- data/test/test_associations.rb +22 -5
- data/test/test_parse_resource.rb +22 -1
- data/test/test_query_options.rb +33 -0
- metadata +31 -28
- data/lib/base.rb +0 -406
- data/lib/parse_user.rb +0 -26
data/lib/base.rb
DELETED
@@ -1,406 +0,0 @@
|
|
1
|
-
require "rubygems"
|
2
|
-
require "bundler/setup"
|
3
|
-
require "active_model"
|
4
|
-
require "erb"
|
5
|
-
require "rest-client"
|
6
|
-
require "json"
|
7
|
-
require "active_support/hash_with_indifferent_access"
|
8
|
-
require "query"
|
9
|
-
require "parse_error"
|
10
|
-
|
11
|
-
module ParseResource
|
12
|
-
|
13
|
-
|
14
|
-
class Base
|
15
|
-
# ParseResource::Base provides an easy way to use Ruby to interace with a Parse.com backend
|
16
|
-
# Usage:
|
17
|
-
# class Post < ParseResource::Base
|
18
|
-
# fields :title, :author, :body
|
19
|
-
# end
|
20
|
-
|
21
|
-
include ActiveModel::Validations
|
22
|
-
include ActiveModel::Conversion
|
23
|
-
include ActiveModel::AttributeMethods
|
24
|
-
extend ActiveModel::Naming
|
25
|
-
extend ActiveModel::Callbacks
|
26
|
-
HashWithIndifferentAccess = ActiveSupport::HashWithIndifferentAccess
|
27
|
-
|
28
|
-
define_model_callbacks :save, :create, :update, :destroy
|
29
|
-
|
30
|
-
# Instantiates a ParseResource::Base object
|
31
|
-
#
|
32
|
-
# @params [Hash], [Boolean] a `Hash` of attributes and a `Boolean` that should be false only if the object already exists
|
33
|
-
# @return [ParseResource::Base] an object that subclasses `Parseresource::Base`
|
34
|
-
def initialize(attributes = {}, new=true)
|
35
|
-
#attributes = HashWithIndifferentAccess.new(attributes)
|
36
|
-
|
37
|
-
if new
|
38
|
-
@unsaved_attributes = attributes
|
39
|
-
else
|
40
|
-
@unsaved_attributes = {}
|
41
|
-
end
|
42
|
-
self.attributes = {}
|
43
|
-
self.attributes.merge!(attributes)
|
44
|
-
self.attributes unless self.attributes.empty?
|
45
|
-
create_setters!
|
46
|
-
end
|
47
|
-
|
48
|
-
# Explicitly adds a field to the model.
|
49
|
-
#
|
50
|
-
# @param [Symbol] name the name of the field, eg `:author`.
|
51
|
-
# @param [Boolean] val the return value of the field. Only use this within the class.
|
52
|
-
def self.field(name, val=nil)
|
53
|
-
class_eval do
|
54
|
-
define_method(name) do
|
55
|
-
@attributes[name] ? @attributes[name] : @unsaved_attributes[name]
|
56
|
-
end
|
57
|
-
define_method("#{name}=") do |val|
|
58
|
-
@attributes[name] = val
|
59
|
-
@unsaved_attributes[name] = val
|
60
|
-
val
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# Add multiple fields in one line. Same as `#field`, but accepts multiple args.
|
66
|
-
#
|
67
|
-
# @param [Array] *args an array of `Symbol`s, `eg :author, :body, :title`.
|
68
|
-
def self.fields(*args)
|
69
|
-
args.each {|f| field(f)}
|
70
|
-
end
|
71
|
-
|
72
|
-
def self.belongs_to(parent)
|
73
|
-
field(parent)
|
74
|
-
end
|
75
|
-
|
76
|
-
|
77
|
-
def to_pointer
|
78
|
-
klass_name = self.class.model_name
|
79
|
-
klass_name = "_User" if klass_name == "User"
|
80
|
-
{"__type" => "Pointer", "className" => klass_name, "objectId" => self.id}
|
81
|
-
end
|
82
|
-
|
83
|
-
# Creates getter and setter methods for model fields
|
84
|
-
#
|
85
|
-
def create_setters!
|
86
|
-
@attributes.each_pair do |k,v|
|
87
|
-
|
88
|
-
self.class.send(:define_method, "#{k}=") do |val|
|
89
|
-
if k.is_a?(Symbol)
|
90
|
-
k = k.to_s
|
91
|
-
end
|
92
|
-
|
93
|
-
val = val.to_pointer if val.respond_to?(:to_pointer)
|
94
|
-
|
95
|
-
@attributes[k.to_s] = val
|
96
|
-
@unsaved_attributes[k.to_s] = val
|
97
|
-
|
98
|
-
val
|
99
|
-
end
|
100
|
-
|
101
|
-
self.class.send(:define_method, "#{k}") do
|
102
|
-
|
103
|
-
case @attributes[k]
|
104
|
-
when Hash
|
105
|
-
|
106
|
-
case @attributes[k]["__type"]
|
107
|
-
when "Pointer"
|
108
|
-
klass_name = @attributes[k]["className"]
|
109
|
-
klass_name = "User" if klass_name == "_User"
|
110
|
-
result = klass_name.constantize.find(@attributes[k]["objectId"])
|
111
|
-
end #todo: support Dates and other types https://www.parse.com/docs/rest#objects-types
|
112
|
-
|
113
|
-
else
|
114
|
-
result = @attributes[k]
|
115
|
-
end
|
116
|
-
|
117
|
-
result
|
118
|
-
end
|
119
|
-
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
class << self
|
124
|
-
|
125
|
-
def has_many(children)
|
126
|
-
parent_klass_name = model_name
|
127
|
-
lowercase_parent_klass_name = parent_klass_name.downcase
|
128
|
-
parent_klass = model_name.constantize
|
129
|
-
child_klass_name = children.to_s.singularize.camelize
|
130
|
-
child_klass = child_klass_name.constantize
|
131
|
-
|
132
|
-
if parent_klass_name == "User"
|
133
|
-
parent_klass_name = "_User"
|
134
|
-
end
|
135
|
-
|
136
|
-
@@parent_klass_name = parent_klass_name
|
137
|
-
#@@parent_instance = self
|
138
|
-
|
139
|
-
send(:define_method, children) do
|
140
|
-
@@parent_id = self.id
|
141
|
-
@@parent_instance = self
|
142
|
-
|
143
|
-
|
144
|
-
singleton = child_klass.where(@@parent_klass_name.downcase => @@parent_instance.to_pointer).all
|
145
|
-
|
146
|
-
class << singleton
|
147
|
-
def <<(child)
|
148
|
-
if @@parent_instance.respond_to?(:to_pointer)
|
149
|
-
child.send("#{@@parent_klass_name.downcase}=", @@parent_instance.to_pointer)
|
150
|
-
child.save
|
151
|
-
end
|
152
|
-
super(child)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
singleton
|
157
|
-
end
|
158
|
-
|
159
|
-
end
|
160
|
-
|
161
|
-
@@settings ||= nil
|
162
|
-
|
163
|
-
# Explicitly set Parse.com API keys.
|
164
|
-
#
|
165
|
-
# @param [String] app_id the Application ID of your Parse database
|
166
|
-
# @param [String] master_key the Master Key of your Parse database
|
167
|
-
def load!(app_id, master_key)
|
168
|
-
@@settings = {"app_id" => app_id, "master_key" => master_key}
|
169
|
-
end
|
170
|
-
|
171
|
-
def settings
|
172
|
-
if @@settings.nil?
|
173
|
-
path = "config/parse_resource.yml"
|
174
|
-
#environment = defined?(Rails) && Rails.respond_to?(:env) ? Rails.env : ENV["RACK_ENV"]
|
175
|
-
environment = ENV["RACK_ENV"]
|
176
|
-
@@settings = YAML.load(ERB.new(File.new(path).read).result)[environment]
|
177
|
-
end
|
178
|
-
@@settings
|
179
|
-
end
|
180
|
-
|
181
|
-
# Creates a RESTful resource
|
182
|
-
# sends requests to [base_uri]/[classname]
|
183
|
-
#
|
184
|
-
def resource
|
185
|
-
if @@settings.nil?
|
186
|
-
path = "config/parse_resource.yml"
|
187
|
-
environment = defined?(Rails) && Rails.respond_to?(:env) ? Rails.env : ENV["RACK_ENV"]
|
188
|
-
@@settings = YAML.load(ERB.new(File.new(path).read).result)[environment]
|
189
|
-
end
|
190
|
-
|
191
|
-
if model_name == "User" #https://parse.com/docs/rest#users-signup
|
192
|
-
base_uri = "https://api.parse.com/1/users"
|
193
|
-
else
|
194
|
-
base_uri = "https://api.parse.com/1/classes/#{model_name}"
|
195
|
-
end
|
196
|
-
|
197
|
-
#refactor to settings['app_id'] etc
|
198
|
-
app_id = @@settings['app_id']
|
199
|
-
master_key = @@settings['master_key']
|
200
|
-
RestClient::Resource.new(base_uri, app_id, master_key)
|
201
|
-
end
|
202
|
-
|
203
|
-
# Find a ParseResource::Base object by ID
|
204
|
-
#
|
205
|
-
# @param [String] id the ID of the Parse object you want to find.
|
206
|
-
# @return [ParseResource] an object that subclasses ParseResource.
|
207
|
-
def find(id)
|
208
|
-
where(:objectId => id).first
|
209
|
-
end
|
210
|
-
|
211
|
-
# Find a ParseResource::Base object by chaining #where method calls.
|
212
|
-
#
|
213
|
-
def where(*args)
|
214
|
-
Query.new(self).where(*args)
|
215
|
-
end
|
216
|
-
|
217
|
-
# Include the attributes of a parent ojbect in the results
|
218
|
-
# Similar to ActiveRecord eager loading
|
219
|
-
#
|
220
|
-
def include_object(parent)
|
221
|
-
Query.new(self).include_object(parent)
|
222
|
-
end
|
223
|
-
|
224
|
-
# Add this at the end of a method chain to get the count of objects, instead of an Array of objects
|
225
|
-
def count
|
226
|
-
#https://www.parse.com/docs/rest#queries-counting
|
227
|
-
Query.new(self).count(1)
|
228
|
-
end
|
229
|
-
|
230
|
-
# Find all ParseResource::Base objects for that model.
|
231
|
-
#
|
232
|
-
# @return [Array] an `Array` of objects that subclass `ParseResource`.
|
233
|
-
def all
|
234
|
-
Query.new(self).all
|
235
|
-
end
|
236
|
-
|
237
|
-
# Find the first object. Fairly random, not based on any specific condition.
|
238
|
-
#
|
239
|
-
def first
|
240
|
-
Query.new(self).limit(1).first
|
241
|
-
end
|
242
|
-
|
243
|
-
# Limits the number of objects returned
|
244
|
-
#
|
245
|
-
def limit(n)
|
246
|
-
Query.new(self).limit(n)
|
247
|
-
end
|
248
|
-
|
249
|
-
# Create a ParseResource::Base object.
|
250
|
-
#
|
251
|
-
# @param [Hash] attributes a `Hash` of attributes
|
252
|
-
# @return [ParseResource] an object that subclasses `ParseResource`. Or returns `false` if object fails to save.
|
253
|
-
def create(attributes = {})
|
254
|
-
attributes = HashWithIndifferentAccess.new(attributes)
|
255
|
-
new(attributes).save
|
256
|
-
end
|
257
|
-
|
258
|
-
def destroy_all
|
259
|
-
all.each do |object|
|
260
|
-
object.destroy
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
def class_attributes
|
265
|
-
@class_attributes ||= {}
|
266
|
-
end
|
267
|
-
|
268
|
-
end
|
269
|
-
|
270
|
-
def persisted?
|
271
|
-
if id
|
272
|
-
true
|
273
|
-
else
|
274
|
-
false
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
def new?
|
279
|
-
!persisted?
|
280
|
-
end
|
281
|
-
|
282
|
-
# delegate from Class method
|
283
|
-
def resource
|
284
|
-
self.class.resource
|
285
|
-
end
|
286
|
-
|
287
|
-
# create RESTful resource for the specific Parse object
|
288
|
-
# sends requests to [base_uri]/[classname]/[objectId]
|
289
|
-
def instance_resource
|
290
|
-
self.class.resource["#{self.id}"]
|
291
|
-
end
|
292
|
-
|
293
|
-
def create
|
294
|
-
opts = {:content_type => "application/json"}
|
295
|
-
attrs = @unsaved_attributes.to_json
|
296
|
-
result = self.resource.post(attrs, opts) do |resp, req, res, &block|
|
297
|
-
|
298
|
-
case resp.code
|
299
|
-
when 400
|
300
|
-
|
301
|
-
# https://www.parse.com/docs/ios/api/Classes/PFConstants.html
|
302
|
-
error_response = JSON.parse(resp)
|
303
|
-
pe = ParseError.new(error_response["code"]).to_array
|
304
|
-
self.errors.add(pe[0], pe[1])
|
305
|
-
|
306
|
-
else
|
307
|
-
@attributes.merge!(JSON.parse(resp))
|
308
|
-
@attributes.merge!(@unsaved_attributes)
|
309
|
-
attributes = HashWithIndifferentAccess.new(attributes)
|
310
|
-
@unsaved_attributes = {}
|
311
|
-
create_setters!
|
312
|
-
end
|
313
|
-
|
314
|
-
self
|
315
|
-
end
|
316
|
-
|
317
|
-
result
|
318
|
-
end
|
319
|
-
|
320
|
-
def save
|
321
|
-
if valid?
|
322
|
-
run_callbacks :save do
|
323
|
-
new? ? create : update
|
324
|
-
end
|
325
|
-
else
|
326
|
-
false
|
327
|
-
end
|
328
|
-
rescue false
|
329
|
-
end
|
330
|
-
|
331
|
-
def update(attributes = {})
|
332
|
-
|
333
|
-
attributes = HashWithIndifferentAccess.new(attributes)
|
334
|
-
|
335
|
-
@unsaved_attributes.merge!(attributes)
|
336
|
-
|
337
|
-
put_attrs = @unsaved_attributes
|
338
|
-
put_attrs.delete('objectId')
|
339
|
-
put_attrs.delete('createdAt')
|
340
|
-
put_attrs.delete('updatedAt')
|
341
|
-
put_attrs = put_attrs.to_json
|
342
|
-
|
343
|
-
opts = {:content_type => "application/json"}
|
344
|
-
result = self.instance_resource.put(put_attrs, opts) do |resp, req, res, &block|
|
345
|
-
|
346
|
-
case resp.code
|
347
|
-
when 400
|
348
|
-
|
349
|
-
# https://www.parse.com/docs/ios/api/Classes/PFConstants.html
|
350
|
-
error_response = JSON.parse(resp)
|
351
|
-
pe = ParseError.new(error_response["code"], error_response["error"]).to_array
|
352
|
-
self.errors.add(pe[0], pe[1])
|
353
|
-
|
354
|
-
else
|
355
|
-
|
356
|
-
@attributes.merge!(JSON.parse(resp))
|
357
|
-
@attributes.merge!(@unsaved_attributes)
|
358
|
-
@unsaved_attributes = {}
|
359
|
-
create_setters!
|
360
|
-
|
361
|
-
self
|
362
|
-
end
|
363
|
-
|
364
|
-
result
|
365
|
-
end
|
366
|
-
|
367
|
-
end
|
368
|
-
|
369
|
-
def update_attributes(attributes = {})
|
370
|
-
self.update(attributes)
|
371
|
-
end
|
372
|
-
|
373
|
-
def destroy
|
374
|
-
self.instance_resource.delete
|
375
|
-
@attributes = {}
|
376
|
-
@unsaved_attributes = {}
|
377
|
-
nil
|
378
|
-
end
|
379
|
-
|
380
|
-
# provides access to @attributes for getting and setting
|
381
|
-
def attributes
|
382
|
-
@attributes ||= self.class.class_attributes
|
383
|
-
@attributes
|
384
|
-
end
|
385
|
-
|
386
|
-
def attributes=(n)
|
387
|
-
@attributes = n
|
388
|
-
@attributes
|
389
|
-
end
|
390
|
-
|
391
|
-
# aliasing for idiomatic Ruby
|
392
|
-
def id; self.objectId rescue nil; end
|
393
|
-
|
394
|
-
def created_at; self.createdAt; end
|
395
|
-
|
396
|
-
def updated_at; self.updatedAt rescue nil; end
|
397
|
-
|
398
|
-
def self.included(base)
|
399
|
-
base.extend(ClassMethods)
|
400
|
-
end
|
401
|
-
|
402
|
-
module ClassMethods
|
403
|
-
end
|
404
|
-
|
405
|
-
end
|
406
|
-
end
|
data/lib/parse_user.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'parse_user_validator'
|
2
|
-
|
3
|
-
class ParseUser < ParseResource::Base
|
4
|
-
fields :username, :password
|
5
|
-
|
6
|
-
validates_presence_of :username
|
7
|
-
validates_presence_of :password
|
8
|
-
#validates_with ParseUserValidator, :on => :create, :on => :save
|
9
|
-
|
10
|
-
def self.authenticate(username, password)
|
11
|
-
base_uri = "https://api.parse.com/1/login"
|
12
|
-
app_id = settings['app_id']
|
13
|
-
master_key = settings['master_key']
|
14
|
-
resource = RestClient::Resource.new(base_uri, app_id, master_key)
|
15
|
-
|
16
|
-
begin
|
17
|
-
resp = resource.get(:params => {:username => username, :password => password})
|
18
|
-
user = model_name.constantize.new(JSON.parse(resp), false)
|
19
|
-
|
20
|
-
user
|
21
|
-
rescue
|
22
|
-
false
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
end
|