lib/mongoid/serialization.rb in mongoid-3.0.0.rc vs lib/mongoid/serialization.rb in mongoid-3.0.0

- old
+ new

@@ -25,45 +25,114 @@ # @return [ Hash ] The document, ready to be serialized. # # @since 2.0.0.rc.6 def serializable_hash(options = nil) options ||= {} + attrs = {} - only = Array.wrap(options[:only]).map(&:to_s) - except = Array.wrap(options[:except]).map(&:to_s) + names = field_names(options) - except |= ['_type'] unless Mongoid.include_type_for_serialization + _serializing do + method_names = Array.wrap(options[:methods]).map do |name| + name.to_s if respond_to?(name) + end.compact - field_names = self.class.attribute_names - attribute_names = (as_document.keys + field_names).sort - if only.any? - attribute_names &= only - elsif except.any? - attribute_names -= except - end - - method_names = Array.wrap(options[:methods]).map do |name| - name.to_s if respond_to?(name) - end.compact - - attrs = {} - (attribute_names + method_names).each do |name| - without_autobuild do - if relations.has_key?(name) - value = send(name) - attrs[name] = value ? value.serializable_hash(options) : nil - elsif attribute_names.include?(name) && !fields.has_key?(name) - attrs[name] = read_attribute(name) - else - attrs[name] = send(name) + (names + method_names).each do |name| + without_autobuild do + serialize_attribute(attrs, name, names, options) end end + serialize_relations(attrs, options) if options[:include] end - serialize_relations(attrs, options) if options[:include] attrs end private + + # Enter the serialization block. + # + # @api private + # + # @example Begin serialization. + # document._serializing do + # end + # + # @return [ Object ] The result of the yield. + # + # @since 3.0.0 + def _serializing + Threaded.begin("serialization") + yield + ensure + Threaded.exit("serialization") + end + + # Are we in a serialization block? We use this to protect multiple + # unnecessary calls to #as_document. + # + # @api private + # + # @example Are we in serialization? + # document._serializing? + # + # @return [ true, false ] If we are serializing. + # + # @since 3.0.0 + def _serializing? + Threaded.executing?("serialization") + end + + # Get the names of all fields that will be serialized. + # + # @api private + # + # @example Get all the field names. + # document.send(:field_names) + # + # @return [ Array<String> ] The names of the fields. + # + # @since 3.0.0 + def field_names(options) + names = (_serializing? ? attribute_names : as_document.keys + attribute_names).uniq.sort + + only = Array.wrap(options[:only]).map(&:to_s) + except = Array.wrap(options[:except]).map(&:to_s) + except |= ['_type'] unless Mongoid.include_type_for_serialization + + if !only.empty? + names &= only + elsif !except.empty? + names -= except + end + names + end + + # Serialize a single attribute. Handles relations, fields, and dynamic + # attributes. + # + # @api private + # + # @example Serialize the attribute. + # document.serialize_attribute({}, "id" , [ "id" ]) + # + # @param [ Hash ] attrs The attributes. + # @param [ String ] name The attribute name. + # @param [ Array<String> ] names The names of all attributes. + # @param [ Hash ] options The options. + # + # @return [ Object ] The attribute. + # + # @since 3.0.0 + def serialize_attribute(attrs, name, names, options) + if relations.has_key?(name) + value = send(name) + attrs[name] = value ? value.serializable_hash(options) : nil + elsif names.include?(name) && !fields.has_key?(name) + attrs[name] = read_attribute(name) + else + attrs[name] = send(name) + end + end # For each of the provided include options, get the relation needed and # provide it in the hash. # # @example Serialize the included relations.