Permalink
Browse files

Documents no longer inherit from Mongoid::Document, will now include it

  • Loading branch information...
1 parent 34a5098 commit b53dc40e183ecc770a935025167fd3af012520a3 @durran durran committed Dec 28, 2009
Showing with 215 additions and 186 deletions.
  1. +182 −171 lib/mongoid/document.rb
  2. +1 −1 spec/integration/mongoid/document_spec.rb
  3. +32 −14 spec/spec_helper.rb
View
@@ -1,20 +1,26 @@
# encoding: utf-8
module Mongoid #:nodoc:
- class Document
- include ActiveSupport::Callbacks
- include Associations, Attributes, Commands, Observable, Validatable
- extend Finders
+ module Document
+ def self.included(base)
+ base.class_eval do
+ include ActiveSupport::Callbacks
+ include Associations, Attributes, Commands, Observable, Validatable
+ include InstanceMethods
- attr_accessor :association_name, :parent
- attr_reader :attributes, :new_record
+ extend ClassMethods
+ extend Finders
- delegate :collection, :defaults, :embedded?, :fields, :primary_key, :to => :klass
+ attr_accessor :association_name, :parent
+ attr_reader :attributes, :new_record
- define_callbacks :before_create, :before_destroy, :before_save, :before_update, :before_validation
- define_callbacks :after_create, :after_destroy, :after_save, :after_update, :after_validation
+ delegate :collection, :defaults, :embedded?, :fields, :primary_key, :to => :klass
- class << self
+ define_callbacks :before_create, :before_destroy, :before_save, :before_update, :before_validation
+ define_callbacks :after_create, :after_destroy, :after_save, :after_update, :after_validation
+ end
+ end
+ module ClassMethods
# Returns the collection associated with this +Document+. If the
# document is embedded, there will be no collection associated
# with it.
@@ -127,186 +133,191 @@ def set_default(name, options = {})
end
- # Performs equality checking on the attributes. For now we chack against
- # all attributes excluding timestamps on the object.
- def ==(other)
- return false unless other.is_a?(Document)
- @attributes.except(:modified_at).except(:created_at) ==
- other.attributes.except(:modified_at).except(:created_at)
- end
+ module InstanceMethods
+ # Performs equality checking on the attributes. For now we chack against
+ # all attributes excluding timestamps on the object.
+ def ==(other)
+ return false unless other.is_a?(Document)
+ @attributes.except(:modified_at).except(:created_at) ==
+ other.attributes.except(:modified_at).except(:created_at)
+ end
- # Introduces a child object into the +Document+ object graph. This will
- # set up the relationships between the parent and child and update the
- # attributes of the parent +Document+.
- #
- # Options:
- #
- # parent: The +Document+ to assimilate with.
- # options: The association +Options+ for the child.
- #
- # Example:
- #
- # <tt>name.assimilate(person, options)</tt>
- #
- # Returns: The child +Document+.
- def assimilate(parent, options)
- parentize(parent, options.name); notify; self
- end
+ # Introduces a child object into the +Document+ object graph. This will
+ # set up the relationships between the parent and child and update the
+ # attributes of the parent +Document+.
+ #
+ # Options:
+ #
+ # parent: The +Document+ to assimilate with.
+ # options: The association +Options+ for the child.
+ #
+ # Example:
+ #
+ # <tt>name.assimilate(person, options)</tt>
+ #
+ # Returns: The child +Document+.
+ def assimilate(parent, options)
+ parentize(parent, options.name); notify; self
+ end
- # Clone the current +Document+. This will return all attributes with the
- # exception of the document's id and versions.
- def clone
- self.class.instantiate(@attributes.except(:_id).except(:versions).dup, true)
- end
+ # Clone the current +Document+. This will return all attributes with the
+ # exception of the document's id and versions.
+ def clone
+ self.class.instantiate(@attributes.except(:_id).except(:versions).dup, true)
+ end
- # Get the id associated with this object. This will pull the _id value out
- # of the attributes +Hash+.
- def id
- @attributes[:_id]
- end
+ # Get the id associated with this object. This will pull the _id value out
+ # of the attributes +Hash+.
+ def id
+ @attributes[:_id]
+ end
- # Set the id
- def id=(new_id)
- @attributes[:_id] = new_id
- end
+ # Set the id
+ def id=(new_id)
+ @attributes[:_id] = new_id
+ end
- alias :_id :id
- alias :_id= :id=
-
- # Instantiate a new +Document+, setting the Document's attributes if
- # given. If no attributes are provided, they will be initialized with
- # an empty +Hash+.
- #
- # If a primary key is defined, the document's id will be set to that key,
- # otherwise it will be set to a fresh +Mongo::ObjectID+ string.
- #
- # Options:
- #
- # attrs: The attributes +Hash+ to set up the document with.
- #
- # Example:
- #
- # <tt>Person.new(:title => "Mr", :age => 30)</tt>
- def initialize(attrs = {})
- @attributes = {}.with_indifferent_access
- process(defaults.merge(attrs))
- @new_record = true if id.nil?
- document = yield self if block_given?
- generate_key; document
- end
+ alias :_id :id
+ alias :_id= :id=
- # Returns the class name plus its attributes.
- def inspect
- attrs = fields.map { |name, field| "#{name}: #{@attributes[name] || 'nil'}" } * ", "
- "#<#{self.class.name} _id: #{id}, #{attrs}>"
- end
+ # Instantiate a new +Document+, setting the Document's attributes if
+ # given. If no attributes are provided, they will be initialized with
+ # an empty +Hash+.
+ #
+ # If a primary key is defined, the document's id will be set to that key,
+ # otherwise it will be set to a fresh +Mongo::ObjectID+ string.
+ #
+ # Options:
+ #
+ # attrs: The attributes +Hash+ to set up the document with.
+ #
+ # Example:
+ #
+ # <tt>Person.new(:title => "Mr", :age => 30)</tt>
+ def initialize(attrs = {})
+ @attributes = {}.with_indifferent_access
+ process(defaults.merge(attrs))
+ @new_record = true if id.nil?
+ document = yield self if block_given?
+ generate_key; document
+ end
- # Returns true is the +Document+ has not been persisted to the database,
- # false if it has. This is determined by the instance variable @new_record
- # and NOT if the object has an id.
- def new_record?
- @new_record == true
- end
+ # Returns the class name plus its attributes.
+ def inspect
+ attrs = fields.map { |name, field| "#{name}: #{@attributes[name] || 'nil'}" } * ", "
+ "#<#{self.class.name} _id: #{id}, #{attrs}>"
+ end
- # Sets the new_record boolean - used after document is saved.
- def new_record=(saved)
- @new_record = saved
- end
+ # Returns true is the +Document+ has not been persisted to the database,
+ # false if it has. This is determined by the instance variable @new_record
+ # and NOT if the object has an id.
+ def new_record?
+ @new_record == true
+ end
- # Set the changed state of the +Document+ then notify observers that it has changed.
- #
- # Example:
- #
- # <tt>person.notify</tt>
- def notify
- changed(true)
- notify_observers(self)
- end
+ # Sets the new_record boolean - used after document is saved.
+ def new_record=(saved)
+ @new_record = saved
+ end
- # Sets up a child/parent association. This is used for newly created
- # objects so they can be properly added to the graph and have the parent
- # observers set up properly.
- #
- # Options:
- #
- # abject: The parent object that needs to be set for the child.
- # association_name: The name of the association for the child.
- #
- # Example:
- #
- # <tt>address.parentize(person, :addresses)</tt>
- def parentize(object, association_name)
- self.parent = object
- self.association_name = association_name
- add_observer(object)
- end
+ # Set the changed state of the +Document+ then notify observers that it has changed.
+ #
+ # Example:
+ #
+ # <tt>person.notify</tt>
+ def notify
+ changed(true)
+ notify_observers(self)
+ end
- # Reloads the +Document+ attributes from the database.
- def reload
- @attributes = collection.find_one(:_id => id).with_indifferent_access
- end
+ # Sets up a child/parent association. This is used for newly created
+ # objects so they can be properly added to the graph and have the parent
+ # observers set up properly.
+ #
+ # Options:
+ #
+ # abject: The parent object that needs to be set for the child.
+ # association_name: The name of the association for the child.
+ #
+ # Example:
+ #
+ # <tt>address.parentize(person, :addresses)</tt>
+ def parentize(object, association_name)
+ self.parent = object
+ self.association_name = association_name
+ add_observer(object)
+ end
- # Return the root +Document+ in the object graph. If the current +Document+
- # is the root object in the graph it will return self.
- def root
- object = self
- while (object.parent) do object = object.parent; end
- object || self
- end
+ # Reloads the +Document+ attributes from the database.
+ def reload
+ @attributes = collection.find_one(:_id => id).with_indifferent_access
+ end
- # Return an array with this +Document+ only in it.
- def to_a
- [ self ]
- end
+ # Return the root +Document+ in the object graph. If the current +Document+
+ # is the root object in the graph it will return self.
+ def root
+ object = self
+ while (object.parent) do object = object.parent; end
+ object || self
+ end
- # Returns the id of the Document, used in Rails compatibility.
- def to_param
- id
- end
+ # Return an array with this +Document+ only in it.
+ def to_a
+ [ self ]
+ end
- # Observe a notify call from a child +Document+. This will either update
- # existing attributes on the +Document+ or clear them out for the child if
- # the clear boolean is provided.
- #
- # Options:
- #
- # child: The child +Document+ that sent the notification.
- # clear: Will clear out the child's attributes if set to true.
- #
- # Example:
- #
- # <tt>person.notify_observers(self)</tt> will cause this method to execute.
- #
- # This will also cause the observing +Document+ to notify it's parent if
- # there is any.
- def update(child, clear = false)
- name = child.association_name
- clear ? @attributes.delete(name) : @attributes.insert(name, child.attributes)
- notify
- end
+ # Returns the id of the Document, used in Rails compatibility.
+ def to_param
+ id
+ end
- # Needs to run the appropriate callbacks the delegate up to the validatable
- # gem.
- def valid?
- run_callbacks(:before_validation)
- result = super
- run_callbacks(:after_validation)
- result
- end
+ # Observe a notify call from a child +Document+. This will either update
+ # existing attributes on the +Document+ or clear them out for the child if
+ # the clear boolean is provided.
+ #
+ # Options:
+ #
+ # child: The child +Document+ that sent the notification.
+ # clear: Will clear out the child's attributes if set to true.
+ #
+ # Example:
+ #
+ # <tt>person.notify_observers(self)</tt> will cause this method to execute.
+ #
+ # This will also cause the observing +Document+ to notify it's parent if
+ # there is any.
+ def update(child, clear = false)
+ name = child.association_name
+ clear ? @attributes.delete(name) : @attributes.insert(name, child.attributes)
+ notify
+ end
- protected
- def generate_key
- if primary_key
- values = primary_key.collect { |key| @attributes[key] }
- @attributes[:_id] = values.join(" ").parameterize.to_s
- else
- @attributes[:_id] = Mongo::ObjectID.new.to_s unless id
+ # Needs to run the appropriate callbacks the delegate up to the validatable
+ # gem.
+ def valid?
+ run_callbacks(:before_validation)
+ result = super
+ run_callbacks(:after_validation)
+ result
+ end
+
+ protected
+ def generate_key
+ if primary_key
+ values = primary_key.collect { |key| @attributes[key] }
+ @attributes[:_id] = values.join(" ").parameterize.to_s
+ else
+ @attributes[:_id] = Mongo::ObjectID.new.to_s unless id
+ end
+ end
+
+ # Convenience method to get the document's class
+ def klass
+ self.class
end
- end
- # Convenience method to get the document's class
- def klass
- self.class
end
+
end
+
end
@@ -159,7 +159,7 @@
describe "#group" do
before do
- 30.times do |num|
+ 5.times do |num|
Person.create(:title => "Sir", :age => num)
end
end
Oops, something went wrong.

0 comments on commit b53dc40

Please sign in to comment.