parse-stack 1.5.1 → 1.5.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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Changes.md +15 -1
  3. data/Gemfile.lock +10 -10
  4. data/README.md +23 -9
  5. data/bin/console +3 -0
  6. data/lib/parse/api/analytics.rb +1 -1
  7. data/lib/parse/api/objects.rb +1 -1
  8. data/lib/parse/api/users.rb +1 -1
  9. data/lib/parse/client.rb +77 -40
  10. data/lib/parse/client/caching.rb +9 -5
  11. data/lib/parse/client/protocol.rb +47 -0
  12. data/lib/parse/client/request.rb +66 -37
  13. data/lib/parse/client/response.rb +39 -21
  14. data/lib/parse/model/acl.rb +4 -9
  15. data/lib/parse/model/associations/belongs_to.rb +97 -9
  16. data/lib/parse/model/associations/collection_proxy.rb +89 -29
  17. data/lib/parse/model/associations/has_many.rb +301 -28
  18. data/lib/parse/model/associations/has_one.rb +98 -4
  19. data/lib/parse/model/associations/pointer_collection_proxy.rb +48 -16
  20. data/lib/parse/model/associations/relation_collection_proxy.rb +61 -36
  21. data/lib/parse/model/bytes.rb +11 -5
  22. data/lib/parse/model/classes/installation.rb +50 -3
  23. data/lib/parse/model/classes/role.rb +7 -2
  24. data/lib/parse/model/classes/session.rb +21 -4
  25. data/lib/parse/model/classes/user.rb +122 -22
  26. data/lib/parse/model/core/actions.rb +7 -3
  27. data/lib/parse/model/core/properties.rb +14 -13
  28. data/lib/parse/model/core/querying.rb +16 -10
  29. data/lib/parse/model/core/schema.rb +2 -3
  30. data/lib/parse/model/date.rb +18 -12
  31. data/lib/parse/model/file.rb +77 -19
  32. data/lib/parse/model/geopoint.rb +70 -12
  33. data/lib/parse/model/model.rb +84 -8
  34. data/lib/parse/model/object.rb +225 -94
  35. data/lib/parse/model/pointer.rb +94 -13
  36. data/lib/parse/model/push.rb +76 -4
  37. data/lib/parse/query.rb +356 -41
  38. data/lib/parse/query/constraints.rb +399 -29
  39. data/lib/parse/query/ordering.rb +21 -8
  40. data/lib/parse/stack.rb +1 -0
  41. data/lib/parse/stack/version.rb +2 -1
  42. data/lib/parse/webhooks.rb +0 -24
  43. data/lib/parse/webhooks/payload.rb +54 -1
  44. data/lib/parse/webhooks/registration.rb +13 -2
  45. metadata +2 -2
@@ -2,10 +2,9 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require_relative "properties"
5
- # This class adds methods to Parse::Objects in order to create a JSON Parse schema
6
- # in order to support table creation and table alterations.
7
- module Parse
8
5
 
6
+ module Parse
7
+ # Upgrade all
9
8
  def self.auto_upgrade!
10
9
  klassModels = Parse::Object.descendants
11
10
  klassModels.sort_by { |c| c.parse_class }.each do |klass|
@@ -13,38 +13,42 @@ require 'active_support/core_ext/time/calculations'
13
13
  require 'active_model_serializers'
14
14
  require_relative 'model'
15
15
 
16
- # Parse has a specific date format. One of the supported types is a date string in
17
- # ISO 8601 format (including milliseconds). The other is a hash object that contains
18
- # the similar information. When sending data to Parse, we need to use the hash object,
19
- # but when receiving data from Parse, we may either get the string version or the hash version.
20
- # To make things easier to use in ruby, th Parse::Date class inherits from the DateTime class.
21
- # This will allow us to use all the great ActiveSupport methods for date (ex. 3.days.ago) while
22
- # providing our own encoding for sending to Parse.
23
16
  module Parse
17
+ # This class manages dates in the special JSON format it requires for
18
+ # properties of type _:date_. One important note with dates, is that 'created_at' and 'updated_at'
19
+ # columns do not follow this convention all the time. Depending on the
20
+ # Cloud Code SDK, they can be the Parse ISO hash date format or the `iso8601`
21
+ # string format. By default, these are serialized as `iso8601` when sent as
22
+ # responses to Parse for backwards compatibility with some clients. To use
23
+ # the Parse ISO hash format for these fields instead, set
24
+ # `Parse::Object.disable_serialized_string_date = true`.
24
25
  class Date < ::DateTime
25
26
  ATTRIBUTES = { __type: :string, iso: :string }.freeze
26
27
  include ::ActiveModel::Model
27
28
  include ::ActiveModel::Serializers::JSON
29
+
30
+ # @return [Parse::Model::TYPE_DATE]
28
31
  def self.parse_class; Parse::Model::TYPE_DATE; end;
32
+ # @return [Parse::Model::TYPE_DATE]
29
33
  def parse_class; self.class.parse_class; end;
30
34
  alias_method :__type, :parse_class
31
35
 
32
- # called when encoding to JSON.
36
+ # @return [Hash]
33
37
  def attributes
34
38
  ATTRIBUTES
35
39
  end
36
40
 
37
- # this method is defined because it is used by JSON encoding
41
+ # @return [String] the ISO8601 time string including milliseconds
38
42
  def iso
39
- to_time.utc.iso8601(3) #include milliseconds
43
+ to_time.utc.iso8601(3)
40
44
  end
41
45
 
42
46
  end
43
47
  end
44
48
 
45
- # To enable conversion of other date class objects, we will add a mixin to turn
46
- # Time and DateTime objects to Parse::Date objects
49
+
47
50
  class Time
51
+ # @return [Parse::Date] Converts object to Parse::Date
48
52
  def parse_date
49
53
  Parse::Date.parse iso8601(3)
50
54
  end
@@ -52,6 +56,7 @@ class Time
52
56
  end
53
57
 
54
58
  class DateTime
59
+ # @return [Parse::Date] Converts object to Parse::Date
55
60
  def parse_date
56
61
  Parse::Date.parse iso8601(3)
57
62
  end
@@ -59,6 +64,7 @@ end
59
64
 
60
65
  module ActiveSupport
61
66
  class TimeWithZone
67
+ # @return [Parse::Date] Converts object to Parse::Date
62
68
  def parse_date
63
69
  Parse::Date.parse iso8601(3)
64
70
  end
@@ -5,30 +5,61 @@ require 'active_support'
5
5
  require 'active_support/core_ext/object'
6
6
  require_relative "model"
7
7
  require 'open-uri'
8
- # Parse File objects are the only non Parse::Object subclass that has a save method.
9
- # In general, a Parse File needs content and a specific mime-type to be created. When it is saved, it
10
- # is sent to AWS/S3 to be saved (by Parse), and the result is a new URL pointing to that file.
11
- # This however is return as a type of File pointer object (hash format)
12
- # It only has two fields, the absolute URL of the file and the basename of the file.
13
- # The contents and mime_type are only present when creating a new file locally and are not
14
- # stored as part of the parse pointer.
15
- module Parse
16
8
 
9
+ module Parse
10
+ # This class represents a Parse file pointer. `Parse::File` has helper
11
+ # methods to upload Parse files directly to Parse and manage file
12
+ # associations with your classes.
13
+ # @example
14
+ # file = File.open("file_path.jpg")
15
+ # contents = file.read
16
+ # file = Parse::File.new("myimage.jpg", contents , "image/jpeg")
17
+ # file.saved? # => false
18
+ # file.save
19
+ #
20
+ # file.url # https://files.parsetfss.com/....
21
+ #
22
+ # # or create and upload a remote file (auto-detected mime type)
23
+ # file = Parse::File.create(some_url)
24
+ #
25
+ #
26
+ # @note The default MIME type for all files is _image/jpeg_. This can be default
27
+ # can be changed by setting a value to `Parse::File.default_mime_type`.
17
28
  class File < Model
18
29
  ATTRIBUTES = { __type: :string, name: :string, url: :string }.freeze
19
- attr_accessor :name, :url
20
- attr_accessor :contents, :mime_type
30
+ # @return [String] the name of the file including extension (if any)
31
+ attr_accessor :name
32
+ # @return [String] the url resource of the file.
33
+ attr_accessor :url
34
+
35
+ # You may set the contents of the file.
36
+ attr_accessor :contents
37
+
38
+ # @return [String] the mime-type of the file whe
39
+ attr_accessor :mime_type
40
+ # @return [Model::TYPE_FILE]
21
41
  def self.parse_class; TYPE_FILE; end;
42
+ # @return [Model::TYPE_FILE]
22
43
  def parse_class; self.class.parse_class; end;
23
44
  alias_method :__type, :parse_class
24
45
  FIELD_NAME = "name"
25
46
  FIELD_URL = "url"
26
47
  class << self
48
+
27
49
  attr_accessor :default_mime_type
28
50
 
51
+ attr_accessor :force_ssl
52
+
53
+ # @return [String] The default mime type for created instances. Default: _'image/jpeg'_
29
54
  def default_mime_type
30
55
  @default_mime_type ||= "image/jpeg"
31
56
  end
57
+
58
+ # @return [Boolean] When set to true, it will make all calls to File#url
59
+ def force_ssl
60
+ @force_ssl ||= false
61
+ end
62
+
32
63
  end
33
64
  # The initializer to create a new file supports different inputs.
34
65
  # If the first paramter is a string which starts with 'http', we then download
@@ -36,6 +67,9 @@ module Parse
36
67
  # If the first parameter is a hash, we assume it might be the Parse File hash format which contains url and name fields only.
37
68
  # If the first paramter is a Parse::File, then we copy fields over
38
69
  # Otherwise, creating a new file requires a name, the actual contents (usually from a File.open("local.jpg").read ) and the mime-type
70
+ # @param name [String]
71
+ # @param contents [Object]
72
+ # @param mime_type [String] Default see default_mime_type
39
73
  def initialize(name, contents = nil, mime_type = nil)
40
74
  mime_type ||= Parse::File.default_mime_type
41
75
 
@@ -65,6 +99,8 @@ module Parse
65
99
  end
66
100
 
67
101
  # This creates a new Parse File Object with from a URL, saves it and returns it
102
+ # @param url [String] A url which will be used to create the file and automatically save it.
103
+ # @return [Parse::File] A newly saved file based on contents of _url_
68
104
  def self.create(url)
69
105
  url = url.url if url.is_a?(Parse::File)
70
106
  file = self.new(url)
@@ -72,16 +108,28 @@ module Parse
72
108
  file
73
109
  end
74
110
 
75
- # A File object is considered saved if the basename of the URL and the name parameters are equal and
76
- # the name of the file begins with 'tfss'
111
+ # A File object is considered saved if the basename of the URL and the name parameters are equal
112
+ # @return [Boolean] true if this file has already been saved.
77
113
  def saved?
78
- @url.present? && @name.present? && @name == File.basename(@url) && @name.start_with?("tfss")
114
+ @url.present? && @name.present? && @name == File.basename(@url)
115
+ end
116
+
117
+ # Returns the url string for this Parse::File pointer. If the *force_ssl* option is
118
+ # set to true, it will make sure it returns a secure url.
119
+ # @return [String] the url string for the file.
120
+ def url
121
+ if @url.present? && Parse::File.force_ssl && @url.starts_with?('http://')
122
+ return @url.sub('http://', 'https://')
123
+ end
124
+ @url
79
125
  end
80
126
 
127
+ # @return [Hash]
81
128
  def attributes
82
129
  ATTRIBUTES
83
130
  end
84
131
 
132
+ # @return [Boolean] Two files are equal if they have the same url
85
133
  def ==(u)
86
134
  return false unless u.is_a?(self.class)
87
135
  @url == u.url
@@ -97,7 +145,11 @@ module Parse
97
145
  end
98
146
  end
99
147
 
100
- # This is a proxy to the ruby ::File.basename method
148
+ # A proxy method for ::File.basename
149
+ # @param file_name [String]
150
+ # @param suffix [String]
151
+ # @return [String] File.basename(file_name)
152
+ # @see ::File.basename
101
153
  def self.basename(file_name, suffix = nil)
102
154
  if suffix.nil?
103
155
  ::File.basename(file_name)
@@ -106,7 +158,8 @@ module Parse
106
158
  end
107
159
  end
108
160
 
109
- # save (create) the file if it has all the proper fields. You cannot update Parse Files.
161
+ # Save the file by uploading it to Parse and creating a file pointer.
162
+ # @return [Boolean] true if successfully uploaded and saved.
110
163
  def save
111
164
  unless saved? || @contents.nil? || @name.nil?
112
165
  response = client.create_file(@name, @contents, @mime_type)
@@ -119,10 +172,13 @@ module Parse
119
172
  saved?
120
173
  end
121
174
 
175
+ # @!visibility private
122
176
  def inspect
123
177
  "<Parse::File @name='#{@name}' @mime_type='#{@mime_type}' @contents=#{@contents.nil?} @url='#{@url}'>"
124
178
  end
125
179
 
180
+ # @return [String] the url
181
+ # @see #url
126
182
  def to_s
127
183
  @url
128
184
  end
@@ -133,13 +189,15 @@ end
133
189
 
134
190
 
135
191
  class Hash
136
- # {"name"=>"tfss-cat.jpg", "url"=>"http://files.parsetfss.com/bcf638bb-3db0-4042-b846-7840b345b0d6/tfss-cat.jpg"}
137
- # This is a helper method that determines whether a hash looks like a Parse::File hash
192
+ # Determines if the hash contains Parse File json metadata fields. This is determined whether
193
+ # the key `__type` exists and is of type `__File` and whether the `name` field matches the File.basename
194
+ # of the `url` field.
195
+ #
196
+ # @return [Boolean] True if this hash contains Parse file metadata.
138
197
  def parse_file?
139
198
  url = self[Parse::File::FIELD_URL]
140
199
  name = self[Parse::File::FIELD_NAME]
141
200
  (count == 2 || self["__type"] == Parse::File.parse_class) &&
142
- url.present? && name.present? &&
143
- name == ::File.basename(url) && name.start_with?("tfss")
201
+ url.present? && name.present? && name == ::File.basename(url)
144
202
  end
145
203
  end
@@ -5,31 +5,54 @@ require_relative "model"
5
5
 
6
6
  module Parse
7
7
 
8
- # A basic geo location object in Parse. It represents a location on a map through a
9
- # latitude and longitue.
8
+ # This class manages the GeoPoint data type that Parse provides to support
9
+ # geo-queries. To define a GeoPoint property, use the `:geopoint` data type.
10
+ # Please note that latitudes should not be between -90.0 and 90.0, and
11
+ # longitudes should be between -180.0 and 180.0.
12
+ # @example
13
+ # class PlaceObject < Parse::Object
14
+ # property :location, :geopoint
15
+ # end
16
+ #
17
+ # san_diego = Parse::GeoPoint.new(32.8233, -117.6542)
18
+ # los_angeles = Parse::GeoPoint.new [34.0192341, -118.970792]
19
+ # san_diego == los_angeles # false
20
+ #
21
+ # place = PlaceObject.new
22
+ # place.location = san_diego
23
+ # place.save
24
+ #
10
25
  class GeoPoint < Model
11
26
  ATTRIBUTES = { __type: :string, latitude: :float, longitude: :float }.freeze
12
- attr_accessor :latitude, :longitude
27
+
28
+ # @return [Float] latitude value between -90.0 and 90.0
29
+ attr_accessor :latitude
30
+ # @return [Float] longitude value between -180.0 and 180.0
31
+ attr_accessor :longitude
13
32
  FIELD_LAT = "latitude"
14
33
  FIELD_LNG = "longitude"
15
- # Latitude should not be -90.0 or 90.0.
16
- # Longitude should not be -180.0 or 180.0.
34
+
17
35
  LAT_MIN = -90.0
18
36
  LAT_MAX = 90.0
19
37
  LNG_MIN = -180.0
20
38
  LNG_MAX = 180.0
39
+
21
40
  alias_method :lat, :latitude
22
41
  alias_method :lng, :longitude
42
+ # @return [Model::TYPE_GEOPOINT]
23
43
  def self.parse_class; TYPE_GEOPOINT; end;
44
+ # @return [Model::TYPE_GEOPOINT]
24
45
  def parse_class; self.class.parse_class; end;
25
46
  alias_method :__type, :parse_class
26
- # To create a GeoPoint, you can either pass a hash (ex. {latitude: 32, longitue: -117})
27
- # or an array (ex. [32,-117]) as the first parameter.
28
- # You may also pass a GeoPoint object or both a lat/lng pair (Ex. GeoPoint.new(32, -117) )
29
- # Points should not equal or exceed the extreme ends of the ranges.
30
-
31
- # Attempting to use GeoPoint’s with latitude and/or longitude outside these ranges will cause an error.
32
47
 
48
+ # The initializer can create a GeoPoint with a hash, array or values.
49
+ # @example
50
+ # san_diego = Parse::GeoPoint.new(32.8233, -117.6542)
51
+ # san_diego = Parse::GeoPoint.new [32.8233, -117.6542]
52
+ # san_diego = Parse::GeoPoint.new { latitude: 32.8233, longitude: -117.6542}
53
+ #
54
+ # @param latitude [Numeric] The latitude value between LAT_MIN and LAT_MAX.
55
+ # @param longitude [Numeric] The longitude value between LNG_MIN and LNG_MAX.
33
56
  def initialize(latitude = nil, longitude = nil)
34
57
  @latitude = @longitude = 0.0
35
58
  if latitude.is_a?(Hash) || latitude.is_a?(Array)
@@ -45,6 +68,7 @@ module Parse
45
68
  _validate_point
46
69
  end
47
70
 
71
+ # @!visibility private
48
72
  def _validate_point
49
73
 
50
74
  unless @latitude.nil? || @latitude.between?(LAT_MIN, LAT_MAX)
@@ -59,10 +83,13 @@ module Parse
59
83
 
60
84
  end
61
85
 
86
+ # @return [Hash]
62
87
  def attributes
63
88
  ATTRIBUTES
64
89
  end
65
90
 
91
+ # Helper method for performing geo-queries with radial miles constraints
92
+ # @return [Array] containing [lat,lng,miles]
66
93
  def max_miles(m)
67
94
  m = 0 if m.nil?
68
95
  [@latitude,@longitude,m]
@@ -92,24 +119,55 @@ module Parse
92
119
  _validate_point
93
120
  end
94
121
 
122
+ # @return [Boolean] true if two geopoints are equal based on lat and lng.
95
123
  def ==(g)
96
124
  return false unless g.is_a?(GeoPoint)
97
125
  @latitude == g.latitude && @longitude == g.longitude
98
126
  end
99
127
 
128
+ # Helper method for reducing the precision of a geopoint.
129
+ # @param precision [Integer] The number of floating digits to keep.
130
+ # @return [GeoPoint] Reduces the precision of a geopoint.
131
+ def estimated(precision = 2)
132
+ Parse::GeoPoint.new(@latitude.to_f.round(precision), @longitude.round(precision))
133
+ end
134
+
135
+ # Returns a tuple containing latitude and longitude
136
+ # @return [Array]
100
137
  def to_a
101
138
  [@latitude,@longitude]
102
139
  end
103
140
 
141
+ # @!visibility private
104
142
  def inspect
105
143
  "#<GeoPoint [#{@latitude},#{@longitude}]>"
106
144
  end
107
145
 
108
- # either GeoPoint, array or lat,lng
146
+ # Calculate the distance in miles to another GeoPoint using Haversine.
147
+ # You may also call this method with a latitude and longitude.
148
+ # @example
149
+ # point.distance_in_miles(geotpoint)
150
+ # point.distance_in_miles(lat, lng)
151
+ #
152
+ # @param geopoint [GeoPoint]
153
+ # @param lng [Float] Longitude assuming that the first parameter
154
+ # is longitude instead of a GeoPoint.
155
+ # @return [Float] number of miles between geopoints.
156
+ # @see #distance_in_km
109
157
  def distance_in_miles(geopoint,lng = nil)
110
158
  distance_in_km(geopoint, lng) * 0.621371
111
159
  end
112
160
 
161
+ # Calculate the distance in kilometers to another GeoPoint using Haversine
162
+ # method. You may also call this method with a latitude and longitude.
163
+ # @example
164
+ # point.distance_in_km(geotpoint)
165
+ # point.distance_in_km(lat, lng)
166
+ #
167
+ # @param geopoint [GeoPoint]
168
+ # @param lng [Float] Longitude assuming that the first parameter is a latitude instead of a GeoPoint.
169
+ # @return [Float] number of miles between geopoints.
170
+ # @see #distance_in_miles
113
171
  def distance_in_km(geopoint,lng = nil)
114
172
  unless geopoint.is_a?(Parse::GeoPoint)
115
173
  geopoint = Parse::GeoPoint.new(geopoint, lng)
@@ -8,10 +8,18 @@ require 'active_support/core_ext/object'
8
8
  require 'active_model_serializers'
9
9
  require_relative '../client'
10
10
 
11
- # This is the base model for all Parse object-type classes.
12
-
13
11
  module Parse
12
+ # Find a corresponding Parse::Object subclass for this string or symbol
13
+ # @param className [String] The name of the Parse class as string (ex. "_User")
14
+ # @return [Class] The proper subclass matching the className.
15
+ def self.classify(className)
16
+ Parse::Model.find_class className.to_parse_class
17
+ end
14
18
 
19
+ # The core model of all Parse-Stack classes. This class works by providing a
20
+ # baseline for all subclass objects to support ActiveModel features such as
21
+ # serialization, dirty tracking, callbacks, etc.
22
+ # @see ActiveModel
15
23
  class Model
16
24
 
17
25
  include Client::Connectable # allows easy default Parse::Client access
@@ -22,7 +30,6 @@ module Parse
22
30
  extend ::ActiveModel::Callbacks # callback support on save, update, delete, etc.
23
31
  extend ::ActiveModel::Naming # provides the methods for getting class names from Model classes
24
32
 
25
- # General Parse constants
26
33
  ID = "id".freeze
27
34
  OBJECT_ID = 'objectId'.freeze
28
35
  KEY_CLASS_NAME = 'className'.freeze
@@ -48,15 +55,40 @@ module Parse
48
55
  # which Parse::Object subclass is responsible for handling this Parse table class.
49
56
  # we use @@model_cache to cache the results of the algorithm since we do this frequently
50
57
  # when encoding and decoding objects.
58
+ # @!visibility private
51
59
  @@model_cache = {}
60
+
61
+ # If set to true, a call to first_or_create will automatically save the object.
62
+ # @return [Boolean]
52
63
  def self.autosave_on_create
53
64
  @@autosave_on_create ||= false
54
65
  end
66
+
55
67
  def self.autosave_on_create=(bool)
56
68
  @@autosave_on_create = bool
57
69
  end
58
70
 
59
71
  class << self
72
+ # By default, we return `true` or `false` for save and destroy operations.
73
+ # If you prefer to have `Parse::Object` raise an exception instead, you
74
+ # can tell to do so either globally or on a per-model basis. When a save
75
+ # fails, it will raise a `Parse::SaveFailureError`.
76
+ #
77
+ # @example
78
+ # Parse::Model.raise_on_save_failure = true # globally across all models
79
+ # Song.raise_on_save_failure = true # per-model
80
+ #
81
+ # # or per-instance raise on failure
82
+ # song.save!
83
+ #
84
+ # When enabled, if an error is returned by Parse due to saving or
85
+ # destroying a record, due to your `before_save` or `before_delete`
86
+ # validation cloud code triggers, `Parse::Object` will return the a
87
+ # `Parse::SaveFailureError` exception type. This exception has an
88
+ # instance method of `#object` which contains the object that failed to save.
89
+ #
90
+ # @return [Boolean]
91
+ attr_accessor :raise_on_save_failure
60
92
 
61
93
  def raise_on_save_failure
62
94
  @global_raise_on_save_failure ||= false
@@ -67,8 +99,23 @@ module Parse
67
99
 
68
100
  end
69
101
 
70
- # class method to find the responsible ruby Parse::Object subclass that handles
71
- # the provided parse class (str).
102
+ # Find a Parse::Model subclass matching this type or Pares collection name.
103
+ # This helper method is useful to find the corresponding class ruby Parse::Object subclass that handles
104
+ # the provided parse class.
105
+ #
106
+ # @example
107
+ # Parse::Model.find_class('_User') # => Parse::User
108
+ # Parse::Model.find_class('_Date') # => Parse::Date
109
+ # Parse::Model.find_class('Installation') # => Parse::Installation
110
+ #
111
+ # class Artist < Parse::Object
112
+ # parse_class "Musician"
113
+ # end
114
+ #
115
+ # Parse::Model.find_class("Musician") # => Artist
116
+ #
117
+ # @param str [String] the class name
118
+ # @return [Parse::Object] a Parse::Object subclass or a specific Parse type.
72
119
  def self.find_class(str)
73
120
  return Parse::File if str == TYPE_FILE
74
121
  return Parse::GeoPoint if str == TYPE_GEOPOINT
@@ -92,14 +139,39 @@ end
92
139
 
93
140
 
94
141
  class String
95
- # short helper method to provide lower-first-camelcase
142
+ # This method returns a camel-cased version of the string with the first letter
143
+ # of the string in lower case. This is the standard naming convention for Parse columns
144
+ # and property fields. This has special exception to the string "id", which returns
145
+ # "objectId". This is the default name filtering method for all defined properties and
146
+ # query keys in Parse::Query.
147
+ #
148
+ # @example
149
+ # "my_field".columnize # => "myField"
150
+ # "MyDataColumn".columnize # => "myDataColumn"
151
+ # "id".columnize # => "objectId" (special)
152
+ #
153
+ # @return [String]
154
+ # @see Parse::Query.field_formatter
96
155
  def columnize
97
156
  return Parse::Model::OBJECT_ID if self == Parse::Model::ID
98
157
  u = '_'.freeze
99
158
  (first == u ? sub(u,'') : self).camelize(:lower)
100
159
  end
101
160
 
102
- #users for properties: ex. :users -> "_User" or :songs -> Song
161
+ # Convert a string to a Parse class name. This method tries to find a
162
+ # responsible Parse::Object subclass that potentially matches the given string.
163
+ # If no match is found, it returns the camelized version of the string. This method
164
+ # is used internally for matching association attributes to registered
165
+ # Parse::Object subclasses. The method can also singularize the name before
166
+ # performing conversion.
167
+ #
168
+ # @example
169
+ # "users".to_parse_class(singularize: true) # => "_User"
170
+ # "users".to_parse_class # => "Users"
171
+ # "song_data".to_parse_class # => "SongData"
172
+ #
173
+ # @param singularize [Boolean] whether the string should be singularized first before performing conversion.
174
+ # @return [String] the matching Parse class for this string.
103
175
  def to_parse_class(singularize: false)
104
176
  final_class = singularize ? self.singularize.camelize : self.camelize
105
177
  klass = Parse::Model.find_class(final_class) || Parse::Model.find_class(self)
@@ -110,19 +182,23 @@ class String
110
182
  end
111
183
 
112
184
  class Symbol
113
- # for compatibility
185
+ # @return [String] a lower-first-camelcased version of the symbol
186
+ # @see String#columnize
114
187
  def columnize
115
188
  to_s.columnize.to_sym
116
189
  end
117
190
 
191
+ # @see String#singularize
118
192
  def singularize
119
193
  to_s.singularize
120
194
  end
121
195
 
196
+ # @see String#camelize
122
197
  def camelize
123
198
  to_s.camelize
124
199
  end
125
200
 
201
+ # @see String#to_parse_class
126
202
  def to_parse_class(singularize: false)
127
203
  to_s.to_parse_class(singularize: singularize)
128
204
  end