parse-stack 1.4.3 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +52 -39
  3. data/Gemfile.lock +2 -2
  4. data/README.md +609 -124
  5. data/bin/console +0 -9
  6. data/lib/parse/api/all.rb +3 -0
  7. data/lib/parse/api/analytics.rb +2 -2
  8. data/lib/parse/api/apps.rb +15 -17
  9. data/lib/parse/api/batch.rb +4 -1
  10. data/lib/parse/api/cloud_functions.rb +2 -0
  11. data/lib/parse/api/config.rb +14 -2
  12. data/lib/parse/api/files.rb +6 -3
  13. data/lib/parse/api/hooks.rb +4 -4
  14. data/lib/parse/api/objects.rb +14 -11
  15. data/lib/parse/api/push.rb +4 -2
  16. data/lib/parse/api/schemas.rb +6 -5
  17. data/lib/parse/api/sessions.rb +11 -1
  18. data/lib/parse/api/users.rb +65 -15
  19. data/lib/parse/client/authentication.rb +4 -2
  20. data/lib/parse/client/body_builder.rb +11 -3
  21. data/lib/parse/client/caching.rb +17 -6
  22. data/lib/parse/client/protocol.rb +14 -8
  23. data/lib/parse/client/request.rb +4 -1
  24. data/lib/parse/client/response.rb +59 -6
  25. data/lib/parse/client.rb +72 -42
  26. data/lib/parse/model/acl.rb +22 -4
  27. data/lib/parse/model/associations/belongs_to.rb +22 -10
  28. data/lib/parse/model/associations/collection_proxy.rb +14 -1
  29. data/lib/parse/model/associations/has_many.rb +76 -15
  30. data/lib/parse/model/associations/has_one.rb +69 -0
  31. data/lib/parse/model/associations/pointer_collection_proxy.rb +13 -6
  32. data/lib/parse/model/associations/relation_collection_proxy.rb +5 -2
  33. data/lib/parse/model/bytes.rb +6 -2
  34. data/lib/parse/model/classes/installation.rb +27 -0
  35. data/lib/parse/model/classes/role.rb +20 -0
  36. data/lib/parse/model/classes/session.rb +26 -0
  37. data/lib/parse/model/classes/user.rb +185 -0
  38. data/lib/parse/model/core/actions.rb +40 -26
  39. data/lib/parse/model/core/properties.rb +126 -20
  40. data/lib/parse/model/core/querying.rb +63 -3
  41. data/lib/parse/model/core/schema.rb +9 -6
  42. data/lib/parse/model/date.rb +5 -1
  43. data/lib/parse/model/file.rb +12 -9
  44. data/lib/parse/model/geopoint.rb +6 -4
  45. data/lib/parse/model/model.rb +29 -21
  46. data/lib/parse/model/object.rb +29 -76
  47. data/lib/parse/model/pointer.rb +8 -6
  48. data/lib/parse/model/push.rb +4 -1
  49. data/lib/parse/query/constraint.rb +3 -0
  50. data/lib/parse/query/constraints.rb +6 -3
  51. data/lib/parse/query/operation.rb +3 -0
  52. data/lib/parse/query/ordering.rb +3 -0
  53. data/lib/parse/query.rb +85 -38
  54. data/lib/parse/stack/generators/rails.rb +3 -0
  55. data/lib/parse/stack/railtie.rb +2 -0
  56. data/lib/parse/stack/tasks.rb +4 -1
  57. data/lib/parse/stack/version.rb +4 -1
  58. data/lib/parse/stack.rb +3 -0
  59. data/lib/parse/webhooks/payload.rb +14 -8
  60. data/lib/parse/webhooks/registration.rb +11 -8
  61. data/lib/parse/webhooks.rb +11 -8
  62. data/lib/parse-stack.rb +3 -0
  63. data/parse-stack.gemspec +10 -8
  64. metadata +16 -4
@@ -1,3 +1,6 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
1
4
  require 'active_model'
2
5
  require 'active_support'
3
6
  require 'active_support/inflector'
@@ -7,6 +10,7 @@ require 'active_support/inflector'
7
10
  require 'active_model_serializers'
8
11
  require 'active_support/inflector'
9
12
  require 'active_model_serializers'
13
+ require 'active_support/hash_with_indifferent_access'
10
14
  require 'time'
11
15
 
12
16
  =begin
@@ -25,8 +29,8 @@ module Parse
25
29
 
26
30
  module Properties
27
31
  # This is an exception that is thrown if there is an issue when creating a specific property for a class.
28
- class DefinitionError < Exception; end;
29
- class ValueError < Exception; end;
32
+ class DefinitionError < StandardError; end;
33
+ class ValueError < StandardError; end;
30
34
 
31
35
  # These are the base types supported by Parse.
32
36
  TYPES = [:id, :string, :relation, :integer, :float, :boolean, :date, :array, :file, :geopoint, :bytes, :object, :acl].freeze
@@ -61,6 +65,10 @@ module Parse
61
65
  @field_map ||= BASE_FIELD_MAP.dup
62
66
  end
63
67
 
68
+ def enums
69
+ @enums ||= {}
70
+ end
71
+
64
72
  # Keeps track of all the attributes supported by this class.
65
73
  def attributes=(hash)
66
74
  @attributes = BASE.merge(hash)
@@ -93,9 +101,12 @@ module Parse
93
101
  # for enum type fields that are string columns in Parse. Ex. a booking_status for a field
94
102
  # could be either "submitted" or "completed" in Parse, however with symbolize, these would
95
103
  # be available as :submitted or :completed.
96
- def property(key, data_type = :string, opts = {})
104
+ def property(key, data_type = :string, **opts)
97
105
 
98
106
  key = key.to_sym
107
+ ivar = :"@#{key}"
108
+ will_change_method = :"#{key}_will_change!"
109
+ set_attribute_method = :"#{key}_set_attribute!"
99
110
 
100
111
  if data_type.is_a?(Hash)
101
112
  opts.merge!(data_type)
@@ -104,10 +115,16 @@ module Parse
104
115
 
105
116
  # allow :bool for :boolean
106
117
  data_type = :boolean if data_type == :bool
118
+ data_type = :integer if data_type == :int
119
+
107
120
  # set defaults
108
121
  opts = { required: false,
109
122
  alias: true,
110
123
  symbolize: false,
124
+ enum: nil,
125
+ scopes: true,
126
+ _prefix: nil,
127
+ _suffix: false,
111
128
  field: key.to_s.camelize(:lower)
112
129
  }.merge( opts )
113
130
  #By default, the remote field name is a lower-first-camelcase version of the key
@@ -142,11 +159,79 @@ module Parse
142
159
  validates_presence_of key
143
160
  end
144
161
 
162
+
163
+ is_enum_type = opts[:enum].nil? == false
164
+
165
+ if is_enum_type
166
+
167
+ unless data_type == :string
168
+ raise DefinitionError, "Property #{self}##{parse_field} :enum option is only supported on :string data types."
169
+ end
170
+
171
+ enum_values = opts[:enum]
172
+ unless enum_values.is_a?(Array) && enum_values.empty? == false
173
+ raise DefinitionError, "Property #{self}##{parse_field} :enum option must be an Array type of symbols."
174
+ end
175
+ opts[:symbolize] = true
176
+
177
+ enum_values = enum_values.dup.map(&:to_sym).freeze
178
+
179
+ self.enums.merge!( key => enum_values )
180
+ allow_nil = opts[:required] == false
181
+ validates key, inclusion: { in: enum_values }, allow_nil: allow_nil
182
+
183
+ unless opts[:scopes] == false
184
+ # You can use the :_prefix or :_suffix options when you need to define multiple enums with same values.
185
+ # If the passed value is true, the methods are prefixed/suffixed with the name of the enum. It is also possible to supply a custom value:
186
+ prefix = opts[:_prefix]
187
+ unless opts[:_prefix].nil? || prefix.is_a?(Symbol) || prefix.is_a?(String)
188
+ raise DefinitionError, "Enumeration option :_prefix must either be a symbol or string for #{self}##{key}."
189
+ end
190
+
191
+ unless opts[:_suffix].is_a?(TrueClass) || opts[:_suffix].is_a?(FalseClass)
192
+ raise DefinitionError, "Enumeration option :_suffix must either be true or false for #{self}##{key}."
193
+ end
194
+
195
+ add_suffix = opts[:_suffix] == true
196
+ prefix_or_key = (prefix.blank? ? key : prefix).to_sym
197
+
198
+ class_method_name = prefix_or_key.to_s.pluralize.to_sym
199
+ if singleton_class.method_defined?(class_method_name)
200
+ raise DefinitionError, "You tried to define an enum named `#{key}` for #{self} " + \
201
+ "but this will generate a method `#{self}.#{class_method_name}` " + \
202
+ " which is already defined. Try using :_suffix or :_prefix options."
203
+ end
204
+
205
+ define_singleton_method(class_method_name) { enum_values }
206
+
207
+ method_name = add_suffix ? :"valid_#{prefix_or_key}?" : :"#{prefix_or_key}_valid?"
208
+ define_method(method_name) do
209
+ value = instance_variable_get(ivar)
210
+ return true if allow_nil && value.nil?
211
+ enum_values.include?(value.to_s.to_sym)
212
+ end
213
+
214
+ enum_values.each do |enum|
215
+ method_name = enum # default
216
+ scope_name = enum
217
+ if add_suffix
218
+ method_name = :"#{enum}_#{prefix_or_key}"
219
+ elsif prefix.present?
220
+ method_name = :"#{prefix}_#{enum}"
221
+ end
222
+ self.scope method_name, ->(ex = {}){ ex.merge!(key => enum); query( ex ) }
223
+ define_method("#{method_name}!") { instance_variable_set(ivar, enum) }
224
+ define_method("#{method_name}?") { enum == instance_variable_get(ivar).to_s.to_sym }
225
+ end
226
+ end # unless scopes
227
+
228
+ end
229
+
145
230
  symbolize_value = opts[:symbolize]
146
231
 
147
232
  #only support symbolization of string data types
148
233
  if symbolize_value && (data_type == :string || data_type == :array) == false
149
- raise 'Symbolization is only supported on :string or :array data types.'
234
+ raise DefinitionError, "Tried to symbolize #{self}##{key}, but it is only supported on :string or :array data types."
150
235
  end
151
236
 
152
237
  # Here is the where the 'magic' begins. For each property defined, we will
@@ -166,11 +251,11 @@ module Parse
166
251
  end
167
252
 
168
253
  # We define a getter with the key
254
+
169
255
  define_method(key) do
170
256
 
171
257
  # we will get the value using the internal value of the instance variable
172
258
  # using the instance_variable_get
173
- ivar = :"@#{key}"
174
259
  value = instance_variable_get ivar
175
260
 
176
261
  # If the value is nil and this current Parse::Object instance is a pointer?
@@ -191,7 +276,7 @@ module Parse
191
276
  value = format_value(key, value, data_type)
192
277
  # lets set the variable with the updated value
193
278
  instance_variable_set ivar, value
194
- send "#{key}_will_change!"
279
+ send will_change_method
195
280
  end
196
281
 
197
282
  # if the value is a String (like an iso8601 date) and the data type of
@@ -199,7 +284,7 @@ module Parse
199
284
  if value.is_a?(String) && data_type == :date
200
285
  value = format_value(key, value, data_type)
201
286
  instance_variable_set ivar, value
202
- send "#{key}_will_change!"
287
+ send will_change_method
203
288
  end
204
289
  # finally return the value
205
290
  if symbolize_value
@@ -214,6 +299,19 @@ module Parse
214
299
  value
215
300
  end
216
301
 
302
+ # support question mark methods for boolean
303
+ if data_type == :boolean
304
+ if self.method_defined?("#{key}?")
305
+ puts "Creating boolean helper :#{key}?. Will overwrite existing method #{self}##{key}?."
306
+ end
307
+
308
+ # returns true if set to true, false otherwise
309
+ define_method("#{key}?") { (send(key) == true) }
310
+ unless opts[:scopes] == false
311
+ scope key, ->(opts = {}){ query( opts.merge(key => true) ) }
312
+ end
313
+ end
314
+
217
315
  # The second method to be defined is a setter method. This is done by
218
316
  # defining :key with a '=' sign. However, to support setting the attribute
219
317
  # with and without dirty tracking, we really will just proxy it to another method
@@ -221,12 +319,12 @@ module Parse
221
319
  define_method("#{key}=") do |val|
222
320
  #we proxy the method passing the value and true. Passing true to the
223
321
  # method tells it to make sure dirty tracking is enabled.
224
- self.send "#{key}_set_attribute!", val, true
322
+ self.send set_attribute_method, val, true
225
323
  end
226
324
 
227
325
  # This is the real setter method. Takes two arguments, the value to set
228
326
  # and whether to mark it as dirty tracked.
229
- define_method("#{key}_set_attribute!") do |val, track = true|
327
+ define_method(set_attribute_method) do |val, track = true|
230
328
  # Each value has a data type, based on that we can treat the incoming
231
329
  # value as input, and format it to the correct storage format. This method is
232
330
  # defined in this file (instance method)
@@ -235,7 +333,7 @@ module Parse
235
333
  # this will grab the current value and keep a copy of it - but we only do this if
236
334
  # the new value being set is different from the current value stored.
237
335
  if track == true
238
- send :"#{key}_will_change!" unless val == instance_variable_get( :"@#{key}" )
336
+ send will_change_method unless val == instance_variable_get( ivar )
239
337
  end
240
338
 
241
339
  if symbolize_value
@@ -247,8 +345,12 @@ module Parse
247
345
  val.set_collection! items
248
346
  end
249
347
  end
348
+
349
+ # if is_enum_type
350
+ #
351
+ # end
250
352
  # now set the instance value
251
- instance_variable_set :"@#{key}", val
353
+ instance_variable_set ivar, val
252
354
  end
253
355
 
254
356
  # The core methods above support all attributes with the base local :key parameter
@@ -267,7 +369,7 @@ module Parse
267
369
  if self.method_defined?(parse_field) == false && opts[:alias]
268
370
  alias_method parse_field, key
269
371
  alias_method "#{parse_field}=", "#{key}="
270
- alias_method "#{parse_field}_set_attribute!", "#{key}_set_attribute!"
372
+ alias_method "#{parse_field}_set_attribute!", set_attribute_method
271
373
  elsif parse_field.to_sym != :objectId
272
374
  warn "Alias property method #{self}##{parse_field} already defined."
273
375
  end
@@ -286,6 +388,7 @@ module Parse
286
388
  self.class.fields(type)
287
389
  end
288
390
 
391
+ # TODO: We can optimize
289
392
  def attributes
290
393
  {__type: :string, :className => :string}.merge!(self.class.attributes)
291
394
  end
@@ -295,9 +398,9 @@ module Parse
295
398
  def apply_attributes!(hash, dirty_track: false)
296
399
  return unless hash.is_a?(Hash)
297
400
 
298
- @id ||= hash["id"] || hash["objectId"] || hash[:objectId]
401
+ @id ||= hash[Parse::Model::ID] || hash[Parse::Model::OBJECT_ID] || hash[:objectId]
299
402
  hash.each do |key, value|
300
- method = "#{key}_set_attribute!"
403
+ method = "#{key}_set_attribute!".freeze
301
404
  send(method, value, dirty_track) if respond_to?( method )
302
405
  end
303
406
  end
@@ -326,6 +429,8 @@ module Parse
326
429
  h[remote_field] = send key
327
430
  h[remote_field] = {__op: :Delete} if h[remote_field].nil?
328
431
  # in the case that the field is a Parse object, generate a pointer
432
+ # if it is a Parse::PointerCollectionProxy, then make sure we get a list of pointers.
433
+ h[remote_field] = h[remote_field].parse_pointers if h[remote_field].is_a?(Parse::PointerCollectionProxy)
329
434
  h[remote_field] = h[remote_field].pointer if h[remote_field].respond_to?(:pointer)
330
435
  end
331
436
  h
@@ -341,21 +446,22 @@ module Parse
341
446
  def format_operation(key, val, data_type)
342
447
  return val unless val.is_a?(Hash) && val["__op"].present?
343
448
  op = val["__op"]
449
+ ivar = :"@#{key}"
344
450
  #handles delete case otherwise 'null' shows up in column
345
451
  if "Delete" == op
346
452
  val = nil
347
453
  elsif "Add" == op && data_type == :array
348
- val = (instance_variable_get(:"@#{key}") || []).to_a + (val["objects"] || [])
454
+ val = (instance_variable_get(ivar) || []).to_a + (val["objects"] || [])
349
455
  elsif "Remove" == op && data_type == :array
350
- val = (instance_variable_get(:"@#{key}") || []).to_a - (val["objects"] || [])
456
+ val = (instance_variable_get(ivar) || []).to_a - (val["objects"] || [])
351
457
  elsif "AddUnique" == op && data_type == :array
352
458
  objects = (val["objects"] || []).uniq
353
- original_items = (instance_variable_get(:"@#{key}") || []).to_a
459
+ original_items = (instance_variable_get(ivar) || []).to_a
354
460
  objects.reject! { |r| original_items.include?(r) }
355
461
  val = original_items + objects
356
462
  elsif "Increment" == op && data_type == :integer || data_type == :integer
357
463
  # for operations that increment by a certain amount, they come as a hash
358
- val = (instance_variable_get(:"@#{key}") || 0) + (val["amount"] || 0).to_i
464
+ val = (instance_variable_get(ivar) || 0) + (val["amount"] || 0).to_i
359
465
  end
360
466
  val
361
467
  end
@@ -370,7 +476,7 @@ module Parse
370
476
 
371
477
  case data_type
372
478
  when :object
373
- val = val #should be regular hash, maybe in the future we return hashie?
479
+ val = val.with_indifferent_access if val.is_a?(Hash)
374
480
  when :array
375
481
  # All "array" types use a collection proxy
376
482
  val = val.to_a if val.is_a?(Parse::CollectionProxy) #all objects must be in array form
@@ -408,7 +514,7 @@ module Parse
408
514
  val = val.parse_date
409
515
  # if the value is a hash, then it may be the Parse hash format for an iso date.
410
516
  elsif val.is_a?(Hash) # val.respond_to?(:iso8601)
411
- val = Parse::Date.parse(val["iso".freeze] || val[:iso])
517
+ val = Parse::Date.parse(val["iso"] || val[:iso])
412
518
  elsif val.is_a?(String)
413
519
  # if it's a string, try parsing the date
414
520
  val = Parse::Date.parse val
@@ -1,3 +1,6 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
1
4
  require_relative '../../query'
2
5
 
3
6
  # This module provides most of the querying methods for Parse Objects.
@@ -12,14 +15,57 @@ module Parse
12
15
 
13
16
  module ClassMethods
14
17
 
18
+ def scope(name, body)
19
+ unless body.respond_to?(:call)
20
+ raise ArgumentError, 'The scope body needs to be callable.'
21
+ end
22
+
23
+ name = name.to_sym
24
+ if respond_to?(name, true)
25
+ puts "Creating scope :#{name}. Will overwrite existing method #{self}.#{name}."
26
+ end
27
+
28
+ define_singleton_method(name) do |*args, &block|
29
+
30
+ if body.arity.zero?
31
+ res = body.call
32
+ res.conditions(*args) if args.present?
33
+ else
34
+ res = body.call(*args)
35
+ end
36
+
37
+ _q = res || query
38
+
39
+ if _q.is_a?(Parse::Query)
40
+ klass = self
41
+ _q.define_singleton_method(:method_missing) do |m, *args, &block|
42
+ if klass.respond_to?(m, true)
43
+ klass_scope = klass.send(m, *args, &block)
44
+ if klass_scope.is_a?(Parse::Query)
45
+ return self.add_constraints( klass_scope.constraints )
46
+ end
47
+ klass = nil # help clean up ruby gc
48
+ return klass_scope
49
+ end
50
+ klass = nil # help clean up ruby gc
51
+ return self.results.send(m, *args, &block)
52
+ end
53
+ end
54
+ return _q if block.nil?
55
+ _q.results(&block)
56
+ end
57
+
58
+ end
59
+
60
+
15
61
  # This query method helper returns a Query object tied to a parse class.
16
62
  # The parse class should be the name of the one that will be sent in the query
17
63
  # request pointing to the remote table.
18
64
  def query(constraints = {})
19
65
  Parse::Query.new self.parse_class, constraints
20
- end
66
+ end; alias_method :where, :query
21
67
 
22
- def where(clauses = {})
68
+ def literal_where(clauses = {})
23
69
  query.where(clauses)
24
70
  end
25
71
 
@@ -49,10 +95,24 @@ module Parse
49
95
  end
50
96
 
51
97
  # creates a count request (which is more performant when counting objects)
52
- def count(constraints = {})
98
+ def count(**constraints)
53
99
  query(constraints).count
54
100
  end
55
101
 
102
+ def newest(**constraints)
103
+ constraints.merge!(order: :created_at.desc)
104
+ _q = query(constraints)
105
+ _q.define_singleton_method(:method_missing) { |m, *args, &block| self.results.send(m, *args, &block) }
106
+ _q
107
+ end
108
+
109
+ def oldest(**constraints)
110
+ constraints.merge!(order: :created_at.asc)
111
+ _q = query(constraints)
112
+ _q.define_singleton_method(:method_missing) { |m, *args, &block| self.results.send(m, *args, &block) }
113
+ _q
114
+ end
115
+
56
116
  # Find objects based on objectIds. The result is a list (or single item) of the
57
117
  # objects that were successfully found.
58
118
  # Example:
@@ -1,10 +1,13 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
1
4
  require_relative "properties"
2
5
  # This class adds methods to Parse::Objects in order to create a JSON Parse schema
3
6
  # in order to support table creation and table alterations.
4
7
  module Parse
5
8
 
6
9
  def self.auto_upgrade!
7
- klassModels = Parse::Object.descendants - [Parse::User, Parse::Installation, Parse::Role, Parse::Session]
10
+ klassModels = Parse::Object.descendants
8
11
  klassModels.sort_by { |c| c.parse_class }.each do |klass|
9
12
  yield(klass) if block_given?
10
13
  klass.auto_upgrade!
@@ -31,13 +34,13 @@ module Parse
31
34
  # if it is a basic column property, find the right datatype
32
35
  case v
33
36
  when :integer, :float
34
- result[:type] = "Number".freeze
37
+ result[:type] = "Number"
35
38
  when :geopoint, :geo_point
36
- result[:type] = "GeoPoint".freeze
39
+ result[:type] = "GeoPoint"
37
40
  when :pointer
38
- result = { type: "Pointer".freeze, targetClass: references[k] }
41
+ result = { type: "Pointer", targetClass: references[k] }
39
42
  when :acl
40
- result[:type] = "ACL".freeze
43
+ result[:type] = "ACL"
41
44
  else
42
45
  result[:type] = v.to_s.camelize
43
46
  end
@@ -47,7 +50,7 @@ module Parse
47
50
  end
48
51
  #then add all the relational column attributes
49
52
  relations.each do |k,v|
50
- sch[:fields][k] = { type: "Relation".freeze, targetClass: relations[k] }
53
+ sch[:fields][k] = { type: "Relation", targetClass: relations[k] }
51
54
  end
52
55
  sch
53
56
  end
@@ -1,3 +1,6 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
1
4
  require 'time'
2
5
  require 'date'
3
6
  require 'active_model'
@@ -19,6 +22,7 @@ require_relative 'model'
19
22
  # providing our own encoding for sending to Parse.
20
23
  module Parse
21
24
  class Date < ::DateTime
25
+ ATTRIBUTES = { __type: :string, iso: :string }.freeze
22
26
  include ::ActiveModel::Model
23
27
  include ::ActiveModel::Serializers::JSON
24
28
  def self.parse_class; Parse::Model::TYPE_DATE; end;
@@ -27,7 +31,7 @@ module Parse
27
31
 
28
32
  # called when encoding to JSON.
29
33
  def attributes
30
- { __type: :string, iso: :string }.freeze
34
+ ATTRIBUTES
31
35
  end
32
36
 
33
37
  # this method is defined because it is used by JSON encoding
@@ -1,3 +1,6 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
1
4
  require 'active_support'
2
5
  require 'active_support/core_ext/object'
3
6
  require_relative "model"
@@ -12,14 +15,14 @@ require 'open-uri'
12
15
  module Parse
13
16
 
14
17
  class File < Model
15
-
18
+ ATTRIBUTES = { __type: :string, name: :string, url: :string }.freeze
16
19
  attr_accessor :name, :url
17
20
  attr_accessor :contents, :mime_type
18
21
  def self.parse_class; TYPE_FILE; end;
19
22
  def parse_class; self.class.parse_class; end;
20
23
  alias_method :__type, :parse_class
21
- FIELD_NAME = "name".freeze
22
- FIELD_URL = "url".freeze
24
+ FIELD_NAME = "name"
25
+ FIELD_URL = "url"
23
26
  class << self
24
27
  attr_accessor :default_mime_type
25
28
 
@@ -36,7 +39,7 @@ module Parse
36
39
  def initialize(name, contents = nil, mime_type = nil)
37
40
  mime_type ||= Parse::File.default_mime_type
38
41
 
39
- if name.is_a?(String) && name.start_with?("http".freeze) #could be url string
42
+ if name.is_a?(String) && name.start_with?('http') #could be url string
40
43
  file = open( name )
41
44
  @contents = file.read
42
45
  @name = File.basename file.base_uri.to_s
@@ -54,7 +57,7 @@ module Parse
54
57
  @contents = contents
55
58
  end
56
59
  if @name.blank?
57
- raise "Invalid Parse::File initialization with name '#{@name}'"
60
+ raise ArgumentError, "Invalid Parse::File initialization with name '#{@name}'"
58
61
  end
59
62
 
60
63
  @mime_type ||= mime_type
@@ -72,11 +75,11 @@ module Parse
72
75
  # A File object is considered saved if the basename of the URL and the name parameters are equal and
73
76
  # the name of the file begins with 'tfss'
74
77
  def saved?
75
- @url.present? && @name.present? && @name == File.basename(@url) && @name.start_with?("tfss".freeze)
78
+ @url.present? && @name.present? && @name == File.basename(@url) && @name.start_with?("tfss")
76
79
  end
77
80
 
78
81
  def attributes
79
- { __type: :string, name: :string, url: :string }.freeze
82
+ ATTRIBUTES
80
83
  end
81
84
 
82
85
  def ==(u)
@@ -135,8 +138,8 @@ class Hash
135
138
  def parse_file?
136
139
  url = self[Parse::File::FIELD_URL]
137
140
  name = self[Parse::File::FIELD_NAME]
138
- (count == 2 || self["__type".freeze] == Parse::File.parse_class) &&
141
+ (count == 2 || self["__type"] == Parse::File.parse_class) &&
139
142
  url.present? && name.present? &&
140
- name == ::File.basename(url) && name.start_with?("tfss".freeze)
143
+ name == ::File.basename(url) && name.start_with?("tfss")
141
144
  end
142
145
  end
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
1
3
 
2
4
  require_relative "model"
3
5
 
@@ -6,10 +8,10 @@ module Parse
6
8
  # A basic geo location object in Parse. It represents a location on a map through a
7
9
  # latitude and longitue.
8
10
  class GeoPoint < Model
9
-
11
+ ATTRIBUTES = { __type: :string, latitude: :float, longitude: :float }.freeze
10
12
  attr_accessor :latitude, :longitude
11
- FIELD_LAT = "latitude".freeze
12
- FIELD_LNG = "longitude".freeze
13
+ FIELD_LAT = "latitude"
14
+ FIELD_LNG = "longitude"
13
15
  # Latitude should not be -90.0 or 90.0.
14
16
  # Longitude should not be -180.0 or 180.0.
15
17
  LAT_MIN = -90.0
@@ -58,7 +60,7 @@ module Parse
58
60
  end
59
61
 
60
62
  def attributes
61
- { __type: :string, latitude: :float, longitude: :float }.freeze
63
+ ATTRIBUTES
62
64
  end
63
65
 
64
66
  def max_miles(m)
@@ -1,3 +1,6 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
1
4
  require 'active_model'
2
5
  require 'active_support'
3
6
  require 'active_support/inflector'
@@ -20,20 +23,24 @@ module Parse
20
23
  extend ::ActiveModel::Naming # provides the methods for getting class names from Model classes
21
24
 
22
25
  # General Parse constants
26
+ ID = "id".freeze
27
+ OBJECT_ID = 'objectId'.freeze
23
28
  KEY_CLASS_NAME = 'className'.freeze
24
29
  KEY_OBJECT_ID = 'objectId'.freeze
25
- KEY_CREATED_AT = 'createdAt'.freeze
26
- KEY_UPDATED_AT = 'updatedAt'.freeze
27
- CLASS_USER = '_User'.freeze
28
- CLASS_INSTALLATION = '_Installation'.freeze
29
- TYPE_FILE = "File".freeze
30
- TYPE_GEOPOINT = "GeoPoint".freeze
31
- TYPE_OBJECT = "Object".freeze
32
- TYPE_DATE = "Date".freeze
33
- TYPE_BYTES = "Bytes".freeze
34
- TYPE_POINTER = "Pointer".freeze
35
- TYPE_RELATION = "Relation".freeze
36
- TYPE_FIELD = "__type".freeze
30
+ KEY_CREATED_AT = 'createdAt'
31
+ KEY_UPDATED_AT = 'updatedAt'
32
+ CLASS_USER = '_User'
33
+ CLASS_INSTALLATION = '_Installation'
34
+ CLASS_SESSION = '_Session'
35
+ CLASS_ROLE = '_Role'
36
+ TYPE_FILE = 'File'
37
+ TYPE_GEOPOINT = 'GeoPoint'
38
+ TYPE_OBJECT = 'Object'
39
+ TYPE_DATE = 'Date'
40
+ TYPE_BYTES = 'Bytes'
41
+ TYPE_POINTER = 'Pointer'
42
+ TYPE_RELATION = 'Relation'
43
+ TYPE_FIELD = '__type'
37
44
 
38
45
  # To support being able to have different ruby class names from the 'table'
39
46
  # names used in Parse, we will need to have a dynamic lookup system where
@@ -63,12 +70,12 @@ module Parse
63
70
  # class method to find the responsible ruby Parse::Object subclass that handles
64
71
  # the provided parse class (str).
65
72
  def self.find_class(str)
66
- return Parse::File if str == TYPE_FILE.freeze
67
- return Parse::GeoPoint if str == TYPE_GEOPOINT.freeze
68
- return Parse::Date if str == TYPE_DATE.freeze
69
- return Parse::Bytes if str == TYPE_BYTES.freeze
70
- # return Parse::User if str == "User".freeze
71
- # return Parse::Installation if str == "Installation".freeze
73
+ return Parse::File if str == TYPE_FILE
74
+ return Parse::GeoPoint if str == TYPE_GEOPOINT
75
+ return Parse::Date if str == TYPE_DATE
76
+ return Parse::Bytes if str == TYPE_BYTES
77
+ # return Parse::User if str == "User"
78
+ # return Parse::Installation if str == "Installation"
72
79
 
73
80
  str = str.to_s
74
81
  # Basically go through all Parse::Object subclasses and see who is has a parse_class
@@ -87,9 +94,10 @@ end
87
94
  class String
88
95
  # short helper method to provide lower-first-camelcase
89
96
  def columnize
90
- return "objectId".freeze if self == "id".freeze
91
- camelize(:lower)
92
- end;
97
+ return Parse::Model::OBJECT_ID if self == Parse::Model::ID
98
+ u = '_'.freeze
99
+ (first == u ? sub(u,'') : self).camelize(:lower)
100
+ end
93
101
 
94
102
  #users for properties: ex. :users -> "_User" or :songs -> Song
95
103
  def to_parse_class(singularize: false)