mongomodel 0.1

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 (108) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +34 -0
  3. data/Rakefile +47 -0
  4. data/bin/console +45 -0
  5. data/lib/mongomodel.rb +92 -0
  6. data/lib/mongomodel/attributes/mongo.rb +40 -0
  7. data/lib/mongomodel/attributes/store.rb +30 -0
  8. data/lib/mongomodel/attributes/typecasting.rb +51 -0
  9. data/lib/mongomodel/concerns/abstract_class.rb +17 -0
  10. data/lib/mongomodel/concerns/activemodel.rb +11 -0
  11. data/lib/mongomodel/concerns/associations.rb +103 -0
  12. data/lib/mongomodel/concerns/associations/base/association.rb +33 -0
  13. data/lib/mongomodel/concerns/associations/base/definition.rb +56 -0
  14. data/lib/mongomodel/concerns/associations/base/proxy.rb +58 -0
  15. data/lib/mongomodel/concerns/associations/belongs_to.rb +68 -0
  16. data/lib/mongomodel/concerns/associations/has_many_by_foreign_key.rb +159 -0
  17. data/lib/mongomodel/concerns/associations/has_many_by_ids.rb +175 -0
  18. data/lib/mongomodel/concerns/attribute_methods.rb +55 -0
  19. data/lib/mongomodel/concerns/attribute_methods/before_type_cast.rb +29 -0
  20. data/lib/mongomodel/concerns/attribute_methods/dirty.rb +35 -0
  21. data/lib/mongomodel/concerns/attribute_methods/protected.rb +127 -0
  22. data/lib/mongomodel/concerns/attribute_methods/query.rb +22 -0
  23. data/lib/mongomodel/concerns/attribute_methods/read.rb +29 -0
  24. data/lib/mongomodel/concerns/attribute_methods/write.rb +29 -0
  25. data/lib/mongomodel/concerns/attributes.rb +85 -0
  26. data/lib/mongomodel/concerns/callbacks.rb +294 -0
  27. data/lib/mongomodel/concerns/logging.rb +15 -0
  28. data/lib/mongomodel/concerns/pretty_inspect.rb +29 -0
  29. data/lib/mongomodel/concerns/properties.rb +69 -0
  30. data/lib/mongomodel/concerns/record_status.rb +42 -0
  31. data/lib/mongomodel/concerns/timestamps.rb +32 -0
  32. data/lib/mongomodel/concerns/validations.rb +38 -0
  33. data/lib/mongomodel/concerns/validations/associated.rb +46 -0
  34. data/lib/mongomodel/document.rb +20 -0
  35. data/lib/mongomodel/document/callbacks.rb +46 -0
  36. data/lib/mongomodel/document/dynamic_finders.rb +88 -0
  37. data/lib/mongomodel/document/finders.rb +82 -0
  38. data/lib/mongomodel/document/indexes.rb +91 -0
  39. data/lib/mongomodel/document/optimistic_locking.rb +48 -0
  40. data/lib/mongomodel/document/persistence.rb +143 -0
  41. data/lib/mongomodel/document/scopes.rb +161 -0
  42. data/lib/mongomodel/document/validations.rb +68 -0
  43. data/lib/mongomodel/document/validations/uniqueness.rb +78 -0
  44. data/lib/mongomodel/embedded_document.rb +42 -0
  45. data/lib/mongomodel/locale/en.yml +55 -0
  46. data/lib/mongomodel/support/collection.rb +109 -0
  47. data/lib/mongomodel/support/configuration.rb +35 -0
  48. data/lib/mongomodel/support/core_extensions.rb +10 -0
  49. data/lib/mongomodel/support/exceptions.rb +25 -0
  50. data/lib/mongomodel/support/mongo_options.rb +177 -0
  51. data/lib/mongomodel/support/types.rb +35 -0
  52. data/lib/mongomodel/support/types/array.rb +11 -0
  53. data/lib/mongomodel/support/types/boolean.rb +25 -0
  54. data/lib/mongomodel/support/types/custom.rb +38 -0
  55. data/lib/mongomodel/support/types/date.rb +20 -0
  56. data/lib/mongomodel/support/types/float.rb +13 -0
  57. data/lib/mongomodel/support/types/hash.rb +18 -0
  58. data/lib/mongomodel/support/types/integer.rb +13 -0
  59. data/lib/mongomodel/support/types/object.rb +21 -0
  60. data/lib/mongomodel/support/types/string.rb +9 -0
  61. data/lib/mongomodel/support/types/symbol.rb +9 -0
  62. data/lib/mongomodel/support/types/time.rb +12 -0
  63. data/lib/mongomodel/version.rb +3 -0
  64. data/spec/mongomodel/attributes/store_spec.rb +273 -0
  65. data/spec/mongomodel/concerns/activemodel_spec.rb +61 -0
  66. data/spec/mongomodel/concerns/associations/belongs_to_spec.rb +153 -0
  67. data/spec/mongomodel/concerns/associations/has_many_by_foreign_key_spec.rb +165 -0
  68. data/spec/mongomodel/concerns/associations/has_many_by_ids_spec.rb +192 -0
  69. data/spec/mongomodel/concerns/attribute_methods/before_type_cast_spec.rb +46 -0
  70. data/spec/mongomodel/concerns/attribute_methods/dirty_spec.rb +131 -0
  71. data/spec/mongomodel/concerns/attribute_methods/protected_spec.rb +86 -0
  72. data/spec/mongomodel/concerns/attribute_methods/query_spec.rb +27 -0
  73. data/spec/mongomodel/concerns/attribute_methods/read_spec.rb +52 -0
  74. data/spec/mongomodel/concerns/attribute_methods/write_spec.rb +43 -0
  75. data/spec/mongomodel/concerns/attributes_spec.rb +152 -0
  76. data/spec/mongomodel/concerns/callbacks_spec.rb +90 -0
  77. data/spec/mongomodel/concerns/logging_spec.rb +20 -0
  78. data/spec/mongomodel/concerns/pretty_inspect_spec.rb +68 -0
  79. data/spec/mongomodel/concerns/properties_spec.rb +29 -0
  80. data/spec/mongomodel/concerns/timestamps_spec.rb +170 -0
  81. data/spec/mongomodel/concerns/validations_spec.rb +159 -0
  82. data/spec/mongomodel/document/callbacks_spec.rb +80 -0
  83. data/spec/mongomodel/document/dynamic_finders_spec.rb +183 -0
  84. data/spec/mongomodel/document/finders_spec.rb +231 -0
  85. data/spec/mongomodel/document/indexes_spec.rb +121 -0
  86. data/spec/mongomodel/document/optimistic_locking_spec.rb +57 -0
  87. data/spec/mongomodel/document/persistence_spec.rb +319 -0
  88. data/spec/mongomodel/document/scopes_spec.rb +204 -0
  89. data/spec/mongomodel/document/validations/uniqueness_spec.rb +217 -0
  90. data/spec/mongomodel/document/validations_spec.rb +132 -0
  91. data/spec/mongomodel/document_spec.rb +74 -0
  92. data/spec/mongomodel/embedded_document_spec.rb +66 -0
  93. data/spec/mongomodel/mongomodel_spec.rb +33 -0
  94. data/spec/mongomodel/support/collection_spec.rb +248 -0
  95. data/spec/mongomodel/support/mongo_options_spec.rb +295 -0
  96. data/spec/mongomodel/support/property_spec.rb +83 -0
  97. data/spec/spec.opts +6 -0
  98. data/spec/spec_helper.rb +21 -0
  99. data/spec/specdoc.opts +6 -0
  100. data/spec/support/callbacks.rb +44 -0
  101. data/spec/support/helpers/define_class.rb +24 -0
  102. data/spec/support/helpers/specs_for.rb +11 -0
  103. data/spec/support/matchers/be_a_subclass_of.rb +5 -0
  104. data/spec/support/matchers/respond_to_boolean.rb +17 -0
  105. data/spec/support/matchers/run_callbacks.rb +20 -0
  106. data/spec/support/models.rb +23 -0
  107. data/spec/support/time.rb +6 -0
  108. metadata +232 -0
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2010 Sam Pohlenz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,34 @@
1
+ MongoModel
2
+ ==========
3
+
4
+ MongoModel is a Ruby ORM for interfacing with [MongoDB](http://www.mongodb.org/) databases.
5
+
6
+
7
+ Installation
8
+ ============
9
+
10
+ MongoModel is distributed as a gem. Install with:
11
+
12
+ gem install mongomodel
13
+
14
+
15
+ Sample Usage
16
+ ============
17
+
18
+ require 'mongomodel'
19
+
20
+ MongoModel.configuration = { 'host' => 'localhost', 'database' => 'mydb' }
21
+
22
+ class Article < MongoModel::Document
23
+ property :title, String, :default => 'Untitled'
24
+ property :body, String
25
+ property :published_at, Time, :protected => true
26
+ property :approved, Boolean, :default => false, :protected => true
27
+
28
+ timestamps!
29
+
30
+ validates_presence_of :title, :body
31
+
32
+ belongs_to :author, :class => User
33
+ end
34
+
@@ -0,0 +1,47 @@
1
+ require 'spec/rake/spectask'
2
+ require 'rake/rdoctask'
3
+
4
+ task :default => :spec
5
+
6
+ Spec::Rake::SpecTask.new(:spec) do |t|
7
+ t.libs << 'lib'
8
+ t.spec_opts = ['--options', "#{File.expand_path(File.dirname(__FILE__))}/spec/spec.opts"]
9
+ end
10
+
11
+ namespace :spec do
12
+ desc "Run specs in nested documenting format"
13
+ Spec::Rake::SpecTask.new(:doc) do |t|
14
+ t.libs << 'lib'
15
+ t.spec_opts = ['--options', "#{File.expand_path(File.dirname(__FILE__))}/spec/specdoc.opts"]
16
+ end
17
+ end
18
+
19
+ desc "Generate documentation"
20
+ Rake::RDocTask.new(:doc) do |rdoc|
21
+ rdoc.rdoc_dir = 'doc'
22
+ rdoc.options << '--line-numbers' << '--inline-source'
23
+ rdoc.rdoc_files.include('lib')
24
+ end
25
+
26
+ begin
27
+ require 'jeweler'
28
+ require File.dirname(__FILE__) + "/lib/mongomodel/version"
29
+
30
+ Jeweler::Tasks.new do |gem|
31
+ gem.name = "mongomodel"
32
+ gem.summary = "MongoDB ORM for Ruby/Rails"
33
+ gem.description = "MongoModel is a MongoDB ORM for Ruby/Rails similar to ActiveRecord, DataMapper."
34
+ gem.email = "sam@sampohlenz.com"
35
+ gem.homepage = "http://github.com/spohlenz/mongomodel"
36
+ gem.authors = ["Sam Pohlenz"]
37
+ gem.version = MongoModel::VERSION
38
+
39
+ gem.add_dependency('activesupport', '>= 3.0.pre')
40
+ gem.add_dependency('activemodel', '>= 3.0.pre')
41
+ gem.add_dependency('mongo', '>= 0.18.3')
42
+ end
43
+
44
+ Jeweler::GemcutterTasks.new
45
+ rescue LoadError
46
+ puts "Jeweler not available. Install it with: gem install jeweler"
47
+ end
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ puts "Loading MongoModel sandbox..."
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
6
+
7
+ require 'irb'
8
+ require 'irb/completion'
9
+
10
+ require 'mongomodel'
11
+
12
+ IRB.setup(nil)
13
+
14
+ IRB.conf[:USE_READLINE] = true
15
+ IRB.conf[:PROMPT_MODE] = :SIMPLE
16
+
17
+ irb = IRB::Irb.new
18
+
19
+ IRB.conf[:MAIN_CONTEXT] = irb.context
20
+
21
+ examples = <<-EXAMPLES
22
+
23
+ class Article < MongoModel::Document
24
+ property :title, String
25
+ property :published, Boolean, :default => false
26
+
27
+ timestamps!
28
+
29
+ default_scope :order => :title.asc
30
+
31
+ named_scope :published, :conditions => { :published => true }
32
+ named_scope :latest, lambda { |num| { :limit => num, :order => 'created_at DESC' } }
33
+ end
34
+
35
+ EXAMPLES
36
+
37
+ puts examples
38
+ irb.context.evaluate(examples, 0)
39
+
40
+ trap("SIGINT") do
41
+ irb.signal_handle
42
+ end
43
+ catch(:IRB_EXIT) do
44
+ irb.eval_input
45
+ end
@@ -0,0 +1,92 @@
1
+ require 'active_support'
2
+ require 'active_model'
3
+
4
+ require 'mongo'
5
+
6
+ require 'mongomodel/support/core_extensions'
7
+ require 'mongomodel/support/exceptions'
8
+ require 'mongomodel/version'
9
+
10
+ require 'active_support/core_ext/module/attribute_accessors'
11
+
12
+ module MongoModel
13
+ autoload :Document, 'mongomodel/document'
14
+ autoload :EmbeddedDocument, 'mongomodel/embedded_document'
15
+
16
+ autoload :Properties, 'mongomodel/concerns/properties'
17
+ autoload :Attributes, 'mongomodel/concerns/attributes'
18
+ autoload :AttributeMethods, 'mongomodel/concerns/attribute_methods'
19
+ autoload :Associations, 'mongomodel/concerns/associations'
20
+ autoload :Validations, 'mongomodel/concerns/validations'
21
+ autoload :Callbacks, 'mongomodel/concerns/callbacks'
22
+ autoload :Logging, 'mongomodel/concerns/logging'
23
+ autoload :Timestamps, 'mongomodel/concerns/timestamps'
24
+ autoload :PrettyInspect, 'mongomodel/concerns/pretty_inspect'
25
+ autoload :RecordStatus, 'mongomodel/concerns/record_status'
26
+ autoload :AbstractClass, 'mongomodel/concerns/abstract_class'
27
+ autoload :ActiveModelCompatibility, 'mongomodel/concerns/activemodel'
28
+
29
+ autoload :MongoOptions, 'mongomodel/support/mongo_options'
30
+ autoload :MongoOrder, 'mongomodel/support/mongo_options'
31
+ autoload :MongoOperator, 'mongomodel/support/mongo_options'
32
+ autoload :Types, 'mongomodel/support/types'
33
+ autoload :Configuration, 'mongomodel/support/configuration'
34
+
35
+ autoload :Collection, 'mongomodel/support/collection'
36
+
37
+ module AttributeMethods
38
+ autoload :Read, 'mongomodel/concerns/attribute_methods/read'
39
+ autoload :Write, 'mongomodel/concerns/attribute_methods/write'
40
+ autoload :Query, 'mongomodel/concerns/attribute_methods/query'
41
+ autoload :BeforeTypeCast, 'mongomodel/concerns/attribute_methods/before_type_cast'
42
+ autoload :Protected, 'mongomodel/concerns/attribute_methods/protected'
43
+ autoload :Dirty, 'mongomodel/concerns/attribute_methods/dirty'
44
+ end
45
+
46
+ module Attributes
47
+ autoload :Store, 'mongomodel/attributes/store'
48
+ autoload :Typecasting, 'mongomodel/attributes/typecasting'
49
+ autoload :Mongo, 'mongomodel/attributes/mongo'
50
+ end
51
+
52
+ module Associations
53
+ module Base
54
+ autoload :Definition, 'mongomodel/concerns/associations/base/definition'
55
+ autoload :Association, 'mongomodel/concerns/associations/base/association'
56
+ autoload :Proxy, 'mongomodel/concerns/associations/base/proxy'
57
+ end
58
+
59
+ autoload :BelongsTo, 'mongomodel/concerns/associations/belongs_to'
60
+ autoload :HasManyByIds, 'mongomodel/concerns/associations/has_many_by_ids'
61
+ autoload :HasManyByForeignKey, 'mongomodel/concerns/associations/has_many_by_foreign_key'
62
+ end
63
+
64
+ module DocumentExtensions
65
+ autoload :Persistence, 'mongomodel/document/persistence'
66
+ autoload :OptimisticLocking, 'mongomodel/document/optimistic_locking'
67
+ autoload :Finders, 'mongomodel/document/finders'
68
+ autoload :DynamicFinders, 'mongomodel/document/dynamic_finders'
69
+ autoload :Indexes, 'mongomodel/document/indexes'
70
+ autoload :Scopes, 'mongomodel/document/scopes'
71
+ autoload :Scope, 'mongomodel/document/scopes'
72
+ autoload :Validations, 'mongomodel/document/validations'
73
+ autoload :Callbacks, 'mongomodel/document/callbacks'
74
+ end
75
+
76
+ mattr_accessor :logger
77
+
78
+ def self.configuration
79
+ @_configuration ||= Configuration.defaults
80
+ end
81
+
82
+ def self.configuration=(config)
83
+ @_database = nil
84
+ @_configuration = Configuration.new(config)
85
+ end
86
+
87
+ def self.database
88
+ @_database ||= configuration.establish_connection
89
+ end
90
+ end
91
+
92
+ I18n.load_path << File.dirname(__FILE__) + '/mongomodel/locale/en.yml'
@@ -0,0 +1,40 @@
1
+ module MongoModel
2
+ module Attributes
3
+ module Mongo
4
+ def to_mongo
5
+ inject({}) do |result, (k, v)|
6
+ property = properties[k]
7
+
8
+ if property
9
+ result[property.as] = property.to_mongo(v)
10
+ else
11
+ converter = Types.converter_for(v.class)
12
+ result[k.to_s] = converter.to_mongo(v)
13
+ end
14
+
15
+ result
16
+ end
17
+ end
18
+
19
+ def from_mongo!(hash)
20
+ hash.each do |k, v|
21
+ property = properties_as[k.to_s]
22
+
23
+ if property
24
+ self[property.name] = property.from_mongo(v)
25
+ else
26
+ self[k.to_sym] = v
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+ def properties_as
33
+ @properties_as ||= properties.inject({}) do |result, (name, property)|
34
+ result[property.as] = property
35
+ result
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,30 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ module MongoModel
4
+ module Attributes
5
+ class Store < ActiveSupport::OrderedHash
6
+ include Typecasting
7
+ include Mongo
8
+
9
+ attr_reader :instance
10
+ delegate :properties, :to => :instance
11
+
12
+ def initialize(instance)
13
+ super()
14
+ @instance = instance
15
+ set_defaults!
16
+ end
17
+
18
+ def inspect
19
+ "{#{map { |k, v| "#{k.inspect}=>#{v.inspect}"}.join(', ')}}"
20
+ end
21
+
22
+ private
23
+ def set_defaults!
24
+ properties.each do |name, property|
25
+ self[name] = property.default(instance)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,51 @@
1
+ module MongoModel
2
+ module Attributes
3
+ module Typecasting
4
+ def []=(key, value)
5
+ values_before_typecast[key] = value
6
+ super(key, typecast(key, value))
7
+ end
8
+
9
+ # Check if key has a value that typecasts to true.
10
+ #
11
+ # attributes = Attributes::Store.new(:comments_count => Property.new(:comments_count, Integer))
12
+ #
13
+ # attributes[:comments_count] = 0
14
+ # attributes.has?(:comments_count)
15
+ # => false
16
+ #
17
+ # attributes[:comments_count] = 1
18
+ # attributes.has?(:comments_count)
19
+ # => true
20
+ #
21
+ def has?(key)
22
+ value = self[key]
23
+ boolean_typecast(key, value)
24
+ end
25
+
26
+ def before_type_cast(key)
27
+ values_before_typecast[key]
28
+ end
29
+
30
+ private
31
+ def typecast(key, value)
32
+ unless value.nil?
33
+ property = properties[key]
34
+ property ? property.cast(value) : value
35
+ end
36
+ end
37
+
38
+ def boolean_typecast(key, value)
39
+ if property = properties[key]
40
+ value ? property.boolean(value) : false
41
+ else
42
+ !!value
43
+ end
44
+ end
45
+
46
+ def values_before_typecast
47
+ @values_before_typecast ||= {}
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,17 @@
1
+ module MongoModel
2
+ module AbstractClass
3
+ extend ActiveSupport::Concern
4
+
5
+ def inherited(subclass)
6
+ subclass.abstract_class = false
7
+ end
8
+
9
+ module ClassMethods
10
+ attr_accessor :abstract_class
11
+
12
+ def abstract_class?
13
+ abstract_class == true
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module MongoModel
2
+ module ActiveModelCompatibility
3
+ extend ActiveSupport::Concern
4
+
5
+ include ActiveModel::Conversion
6
+
7
+ module ClassMethods
8
+ include ActiveModel::Naming
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,103 @@
1
+ module MongoModel
2
+ module Associations
3
+ extend ActiveSupport::Concern
4
+
5
+ def associations
6
+ @_associations ||= self.class.associations.inject({}) do |result, (name, association)|
7
+ result[name] = association.for(self)
8
+ result
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ def belongs_to(name, options={})
14
+ associations[name] = create_association(BelongsTo, name, options)
15
+ end
16
+
17
+ def has_many(name, options={})
18
+ associations[name] = create_association(has_many_type(options), name, options)
19
+ end
20
+
21
+ def associations
22
+ read_inheritable_attribute(:associations) || write_inheritable_attribute(:associations, {})
23
+ end
24
+
25
+ private
26
+ def has_many_type(options)
27
+ case options[:by]
28
+ when :ids
29
+ HasManyByIds
30
+ when :foreign_key
31
+ HasManyByForeignKey
32
+ else
33
+ ancestors.include?(Document) ? HasManyByForeignKey : HasManyByIds
34
+ end
35
+ end
36
+
37
+ def create_association(type, name, options={})
38
+ type.new(self, name, options).define!
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+
45
+
46
+ #
47
+ # belongs_to :user
48
+ # => property :user_id
49
+ # belongs_to :author, :class_name => 'User'
50
+ # => property :author_id
51
+ # belongs_to :commentable, :polymorphic => true
52
+ # => property :commentable_id
53
+ # => property :commentable_type
54
+ #
55
+
56
+ #
57
+ # has_many :contributors, :class_name => 'User', :foreign_key => :publication_id
58
+ # has_many :comments, :as => :commentable
59
+ # has_many :roles
60
+ #
61
+
62
+
63
+
64
+
65
+ #
66
+ # Documents and EmbeddedDocuments can:
67
+ # - belong to any Document
68
+ # - have many Documents by ids
69
+ #
70
+ # Documents can also:
71
+ # - have many Documents by foreign key
72
+ #
73
+
74
+ # class Author < Document; end
75
+ #
76
+ # class Comment < Document
77
+ # # Creates properties :commentable_id and :commentable_type
78
+ # belongs_to :commentable, :polymorphic => true
79
+ # end
80
+ #
81
+ # class Page < EmbeddedDocument
82
+ # # Creates property :editor_id
83
+ # belongs_to :editor, :class => 'Author'
84
+ #
85
+ # # Creates property :related_article_ids
86
+ # has_many :related_articles, :class => 'Article'
87
+ #
88
+ # # Polymorphic association, uses commentable_id/commentable_type on Comment class
89
+ # has_many :comments, :as => :commentable
90
+ # end
91
+ #
92
+ # class Article < Document
93
+ # # Creates property :author_id
94
+ # belongs_to :author
95
+ #
96
+ # # Creates property :recommended_by_ids
97
+ # has_many :recommended_by, :by => :ids, :class => 'Author'
98
+ #
99
+ # # Creates property :parent_article_id
100
+ # belongs_to :parent_article, :class => 'Article'
101
+ # # Uses parent_article_id property on referenced class
102
+ # has_many :child_articles, :by => :foreign_key, :foreign_key => :parent_article_id, :class => 'Article'
103
+ # end