lib/parse/util.rb
# encoding: utf-8
# This module contains all the code
module Parse
# Parse a JSON representation into a fully instantiated
# class. obj can be either a primitive or a Hash of primitives as parsed
# by JSON.parse
# @param class_name [Object]
# @param obj [Object]
def self.parse_json(class_name, obj)
if obj.nil?
nil
# Array
elsif obj.is_a? Array
obj.map { |o| parse_json(class_name, o) }
# Hash
elsif obj.is_a? Hash
# If it's a datatype hash
if obj.key?(Protocol::KEY_TYPE)
parse_datatype obj
elsif class_name # otherwise it must be a regular object, so deep parse it avoiding re-JSON.parsing raw Strings
# NOTE: passing '' for client to avoid passing nil to trigger the singleton. It's ugly!
Parse::Object.new(
class_name,
Hash[obj.map { |k, v| [k, parse_json(nil, v)] }], '')
else # plain old hash
obj
end
# primitive
else
obj
end
end
def self.parse_datatype(obj)
type = obj[Protocol::KEY_TYPE]
case type
when Protocol::TYPE_POINTER
Parse::Pointer.new obj
when Protocol::TYPE_BYTES
Parse::Bytes.new obj
when Protocol::TYPE_DATE
Parse::Date.new obj
when Protocol::TYPE_GEOPOINT
Parse::GeoPoint.new obj
when Protocol::TYPE_FILE
# NOTE: passing '' for client to avoid passing nil
# to trigger the singleton. It's ugly!
Parse::File.new(obj, '')
when Protocol::TYPE_OBJECT # used for relation queries, e.g. "?include=post"
# NOTE: passing '' for client to avoid passing nil
# to trigger the singleton. It's ugly!
Parse::Object.new(
obj[Protocol::KEY_CLASS_NAME],
Hash[obj.map { |k, v| [k, parse_json(nil, v)] }], '')
end
end
def self.pointerize_value(obj)
if obj.is_a?(Parse::Object)
p = obj.pointer
raise ArgumentError, "new object used in context requiring pointer #{obj}" unless p
p
elsif obj.is_a?(Array)
obj.map do |v|
Parse.pointerize_value(v)
end
elsif obj.is_a?(Hash)
Hash[obj.map do |k, v|
[k, Parse.pointerize_value(v)]
end]
else
obj
end
end
def self.object_pointer_equality?(a, b)
classes = [Parse::Object, Parse::Pointer]
return false unless classes.any? { |c| a.is_a?(c) } && classes.any? { |c| b.is_a?(c) }
return true if a.equal?(b)
return false if a.new? || b.new?
a.class_name == b.class_name && a.id == b.id
end
def self.object_pointer_hash(v)
if v.new?
v.object_id
else
v.class_name.hash ^ v.id.hash
end
end
# NOTE: this mess is used to pass along the @client to internal objects
def self.copy_client(client, parsed_data)
do_copy = lambda do |object|
if object.is_a?(Parse::Object)
object.client = client
object.each do |_key, value|
value.client = client if value.is_a?(Parse::Object)
end
end
object
end
if parsed_data.is_a?(Array)
parsed_data.map(&:do_copy)
else
parsed_data = do_copy.call(parsed_data)
end
parsed_data
end
end