# encoding: utf-8 module Mongoid # :nodoc: module Relations #:nodoc: # This class is the superclass for all relation proxy objects, and contains # common behaviour for all of them. class Proxy DEFAULT_OPTIONS = { :building => false, :continue => true } # We undefine most methods to get them sent through to the target. instance_methods.each do |method| undef_method(method) unless method =~ /(^__|^send$|^object_id$|^extend$|^tap$)/ end attr_accessor :base, :metadata, :target # Backwards compatibiloty with Mongoid beta releases. delegate :klass, :to => :metadata # Convenience for setting the target and the metadata properties since # all proxies will need to do this. # # @example Initialize the proxy. # proxy.init(person, name, metadata) # # @param [ Document ] base The base document on the proxy. # @param [ Document, Array ] target The target of the proxy. # @param [ Metadata ] metadata The relation's metadata. # # @since 2.0.0.rc.1 def init(base, target, metadata, &block) @base, @building, @target, @metadata = base, false, target, metadata yield block if block_given? extend Module.new(&metadata.extension) if metadata.extension? end protected # Yields to the block to allow the building flag to get set and unset for # the supplied code. # # @example Set the building status. # person.building { @target << Post.new } # # @since 2.0.0.rc.1 def building(&block) @building = true yield block if block_given? @building = false end # Convenience method for determining if we are building an association. # We never want to save in this case. # # @example Are we currently building? # person.posts.building? # # @return [ true, false ] True if currently building, false if not. # # @since 2.0.0.rc.1 def building? !!@building end # Return a new document for the type of class we want to instantiate. # If the type is provided use that, otherwise the klass from the # metadata. # # @example Get an instantiated document. # proxy.instantiated(Person) # # @param [ Class ] type The type of class to instantiate. # # @return [ Document ] The freshly created document. # # @since 2.0.0.rc.1 def instantiated(type = nil) type ? type.instantiate : metadata.klass.instantiate end # Determines if the target been loaded into memory or not. # # @example Is the proxy loaded? # proxy.loaded? # # @return [ true, false ] True if loaded, false if not. # # @since 2.0.0.rc.1 def loaded? !target.is_a?(Mongoid::Criteria) end # Takes the supplied documents and sets the metadata on them. Used when # creating new documents and adding them to the relation. # # @example Set the metadata. # proxy.characterize(addresses) # # @param [ Array ] documents The documents to set metadata on. # # @since 2.0.0.rc.4 def characterize(documents) documents.each { |doc| characterize_one(doc) } end # Takes the supplied document and sets the metadata on it. # # @example Set the metadata. # proxt.characterize_one(name) # # @param [ Document ] document The document to set on. # # @since 2.0.0.rc.4 def characterize_one(document) document.metadata = metadata unless document.metadata end # Default behavior of method missing should be to delegate all calls # to the target of the proxy. This can be overridden in special cases. # # @param [ String, Symbol ] name The name of the method. # @param [ Array ] *args The arguments passed to the method. def method_missing(name, *args, &block) target.send(name, *args, &block) end end end end