djsun-mongo_mapper 0.5.6.6 → 0.5.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.gitignore +3 -1
  2. data/Rakefile +13 -8
  3. data/VERSION +1 -1
  4. data/djsun-mongo_mapper.gemspec +17 -21
  5. data/lib/mongo_mapper/associations/base.rb +32 -36
  6. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -2
  7. data/lib/mongo_mapper/associations/many_documents_proxy.rb +19 -10
  8. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +2 -2
  9. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +21 -36
  10. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +1 -1
  11. data/lib/mongo_mapper/associations/proxy.rb +3 -2
  12. data/lib/mongo_mapper/associations.rb +114 -8
  13. data/lib/mongo_mapper/callbacks.rb +18 -0
  14. data/lib/mongo_mapper/document.rb +173 -37
  15. data/lib/mongo_mapper/dynamic_finder.rb +1 -1
  16. data/lib/mongo_mapper/embedded_document.rb +9 -13
  17. data/lib/mongo_mapper/finder_options.rb +67 -44
  18. data/lib/mongo_mapper/pagination.rb +2 -0
  19. data/lib/mongo_mapper/serialization.rb +1 -1
  20. data/lib/mongo_mapper/serializers/json_serializer.rb +1 -1
  21. data/lib/mongo_mapper/support.rb +9 -0
  22. data/lib/mongo_mapper/validations.rb +12 -42
  23. data/lib/mongo_mapper.rb +11 -5
  24. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +5 -5
  25. data/test/functional/associations/test_belongs_to_proxy.rb +29 -31
  26. data/test/functional/associations/test_many_documents_as_proxy.rb +5 -5
  27. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +27 -3
  28. data/test/functional/associations/test_many_embedded_proxy.rb +58 -38
  29. data/test/functional/associations/test_many_polymorphic_proxy.rb +45 -3
  30. data/test/functional/associations/test_many_proxy.rb +61 -11
  31. data/test/functional/test_associations.rb +3 -3
  32. data/test/functional/test_binary.rb +1 -1
  33. data/test/functional/test_callbacks.rb +1 -1
  34. data/test/functional/test_dirty.rb +3 -3
  35. data/test/functional/test_document.rb +62 -58
  36. data/test/functional/test_embedded_document.rb +1 -1
  37. data/test/functional/test_pagination.rb +1 -1
  38. data/test/functional/test_rails_compatibility.rb +1 -1
  39. data/test/functional/test_validations.rb +46 -14
  40. data/test/models.rb +87 -35
  41. data/test/support/{test_timing.rb → timing.rb} +1 -1
  42. data/test/test_helper.rb +8 -13
  43. data/test/unit/serializers/test_json_serializer.rb +0 -4
  44. data/test/unit/test_association_base.rb +24 -8
  45. data/test/unit/test_document.rb +40 -71
  46. data/test/unit/test_embedded_document.rb +27 -67
  47. data/test/unit/test_finder_options.rb +16 -0
  48. data/test/unit/test_key.rb +5 -17
  49. data/test/unit/test_mongomapper.rb +2 -2
  50. data/test/unit/test_pagination.rb +4 -0
  51. metadata +10 -12
  52. data/mongo_mapper.gemspec +0 -170
  53. data/test/functional/associations/test_namespace.rb +0 -27
data/.gitignore CHANGED
@@ -5,4 +5,6 @@ rdoc
5
5
  pkg
6
6
  *~
7
7
  *.gem
8
- tmp
8
+ tmp
9
+ .yardoc
10
+ doc/*
data/Rakefile CHANGED
@@ -1,23 +1,24 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
-
4
3
  require 'jeweler'
4
+ require 'yard'
5
+ require 'yard/rake/yardoc_task'
6
+
5
7
  Jeweler::Tasks.new do |gem|
6
8
  gem.name = "djsun-mongo_mapper"
7
- gem.summary = %Q{Awesome gem for modeling your domain and storing it in mongo}
8
- gem.description = %Q{Awesome gem for modeling your domain and storing it in mongo}
9
+ gem.summary = %(Model your domain, store it in MongoDB)
9
10
  gem.email = "nunemaker@gmail.com"
10
11
  gem.homepage = "http://github.com/jnunemaker/mongomapper"
11
- gem.authors = ["John Nunemaker"]
12
+ gem.authors = ["John Nunemaker", "David James"]
12
13
 
13
14
  gem.add_dependency('activesupport', '>= 2.3')
14
- gem.add_dependency('mongo', '>= 0.15.1')
15
- gem.add_dependency('jnunemaker-validatable', '>= 1.8.0')
15
+ gem.add_dependency('mongo', '>= 0.16')
16
+ gem.add_dependency('jnunemaker-validatable', '>= 1.8.1')
16
17
 
17
18
  gem.add_development_dependency('jnunemaker-matchy', '>= 0.4.0')
18
19
  gem.add_development_dependency('shoulda', '>= 2.10.2')
19
- gem.add_development_dependency('timecop', '>= 0.3.1')
20
- gem.add_development_dependency('mocha', '>= 0.9.4')
20
+ gem.add_development_dependency('timecop', '>= 0.3.2')
21
+ gem.add_development_dependency('mocha', '>= 0.9.8')
21
22
  end
22
23
 
23
24
  Jeweler::GemcutterTasks.new
@@ -48,3 +49,7 @@ end
48
49
 
49
50
  task :default => :test
50
51
  task :test => :check_dependencies
52
+
53
+ YARD::Rake::YardocTask.new(:doc) do |t|
54
+ t.options = ["--legacy"]
55
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.6.6
1
+ 0.5.8.1
@@ -5,13 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{djsun-mongo_mapper}
8
- s.version = "0.5.6.6"
8
+ s.version = "0.5.8.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["John Nunemaker"]
11
+ s.authors = ["John Nunemaker", "David James"]
12
12
  s.date = %q{2009-11-04}
13
13
  s.default_executable = %q{mmconsole}
14
- s.description = %q{Awesome gem for modeling your domain and storing it in mongo}
15
14
  s.email = %q{nunemaker@gmail.com}
16
15
  s.executables = ["mmconsole"]
17
16
  s.extra_rdoc_files = [
@@ -53,7 +52,6 @@ Gem::Specification.new do |s|
53
52
  "lib/mongo_mapper/serializers/json_serializer.rb",
54
53
  "lib/mongo_mapper/support.rb",
55
54
  "lib/mongo_mapper/validations.rb",
56
- "mongo_mapper.gemspec",
57
55
  "specs.watchr",
58
56
  "test/NOTE_ON_TESTING",
59
57
  "test/functional/associations/test_belongs_to_polymorphic_proxy.rb",
@@ -63,7 +61,6 @@ Gem::Specification.new do |s|
63
61
  "test/functional/associations/test_many_embedded_proxy.rb",
64
62
  "test/functional/associations/test_many_polymorphic_proxy.rb",
65
63
  "test/functional/associations/test_many_proxy.rb",
66
- "test/functional/associations/test_namespace.rb",
67
64
  "test/functional/test_associations.rb",
68
65
  "test/functional/test_binary.rb",
69
66
  "test/functional/test_callbacks.rb",
@@ -76,7 +73,7 @@ Gem::Specification.new do |s|
76
73
  "test/functional/test_validations.rb",
77
74
  "test/models.rb",
78
75
  "test/support/custom_matchers.rb",
79
- "test/support/test_timing.rb",
76
+ "test/support/timing.rb",
80
77
  "test/test_helper.rb",
81
78
  "test/unit/serializers/test_json_serializer.rb",
82
79
  "test/unit/test_association_base.rb",
@@ -98,7 +95,7 @@ Gem::Specification.new do |s|
98
95
  s.rdoc_options = ["--charset=UTF-8"]
99
96
  s.require_paths = ["lib"]
100
97
  s.rubygems_version = %q{1.3.5}
101
- s.summary = %q{Awesome gem for modeling your domain and storing it in mongo}
98
+ s.summary = %q{Model your domain, store it in MongoDB}
102
99
  s.test_files = [
103
100
  "test/functional/associations/test_belongs_to_polymorphic_proxy.rb",
104
101
  "test/functional/associations/test_belongs_to_proxy.rb",
@@ -107,7 +104,6 @@ Gem::Specification.new do |s|
107
104
  "test/functional/associations/test_many_embedded_proxy.rb",
108
105
  "test/functional/associations/test_many_polymorphic_proxy.rb",
109
106
  "test/functional/associations/test_many_proxy.rb",
110
- "test/functional/associations/test_namespace.rb",
111
107
  "test/functional/test_associations.rb",
112
108
  "test/functional/test_binary.rb",
113
109
  "test/functional/test_callbacks.rb",
@@ -120,7 +116,7 @@ Gem::Specification.new do |s|
120
116
  "test/functional/test_validations.rb",
121
117
  "test/models.rb",
122
118
  "test/support/custom_matchers.rb",
123
- "test/support/test_timing.rb",
119
+ "test/support/timing.rb",
124
120
  "test/test_helper.rb",
125
121
  "test/unit/serializers/test_json_serializer.rb",
126
122
  "test/unit/test_association_base.rb",
@@ -145,29 +141,29 @@ Gem::Specification.new do |s|
145
141
 
146
142
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
147
143
  s.add_runtime_dependency(%q<activesupport>, [">= 2.3"])
148
- s.add_runtime_dependency(%q<mongo>, [">= 0.15.1"])
149
- s.add_runtime_dependency(%q<jnunemaker-validatable>, [">= 1.8.0"])
144
+ s.add_runtime_dependency(%q<mongo>, [">= 0.16"])
145
+ s.add_runtime_dependency(%q<jnunemaker-validatable>, [">= 1.8.1"])
150
146
  s.add_development_dependency(%q<jnunemaker-matchy>, [">= 0.4.0"])
151
147
  s.add_development_dependency(%q<shoulda>, [">= 2.10.2"])
152
- s.add_development_dependency(%q<timecop>, [">= 0.3.1"])
153
- s.add_development_dependency(%q<mocha>, [">= 0.9.4"])
148
+ s.add_development_dependency(%q<timecop>, [">= 0.3.2"])
149
+ s.add_development_dependency(%q<mocha>, [">= 0.9.8"])
154
150
  else
155
151
  s.add_dependency(%q<activesupport>, [">= 2.3"])
156
- s.add_dependency(%q<mongo>, [">= 0.15.1"])
157
- s.add_dependency(%q<jnunemaker-validatable>, [">= 1.8.0"])
152
+ s.add_dependency(%q<mongo>, [">= 0.16"])
153
+ s.add_dependency(%q<jnunemaker-validatable>, [">= 1.8.1"])
158
154
  s.add_dependency(%q<jnunemaker-matchy>, [">= 0.4.0"])
159
155
  s.add_dependency(%q<shoulda>, [">= 2.10.2"])
160
- s.add_dependency(%q<timecop>, [">= 0.3.1"])
161
- s.add_dependency(%q<mocha>, [">= 0.9.4"])
156
+ s.add_dependency(%q<timecop>, [">= 0.3.2"])
157
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
162
158
  end
163
159
  else
164
160
  s.add_dependency(%q<activesupport>, [">= 2.3"])
165
- s.add_dependency(%q<mongo>, [">= 0.15.1"])
166
- s.add_dependency(%q<jnunemaker-validatable>, [">= 1.8.0"])
161
+ s.add_dependency(%q<mongo>, [">= 0.16"])
162
+ s.add_dependency(%q<jnunemaker-validatable>, [">= 1.8.1"])
167
163
  s.add_dependency(%q<jnunemaker-matchy>, [">= 0.4.0"])
168
164
  s.add_dependency(%q<shoulda>, [">= 2.10.2"])
169
- s.add_dependency(%q<timecop>, [">= 0.3.1"])
170
- s.add_dependency(%q<mocha>, [">= 0.9.4"])
165
+ s.add_dependency(%q<timecop>, [">= 0.3.2"])
166
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
171
167
  end
172
168
  end
173
169
 
@@ -1,41 +1,27 @@
1
- module ConstantHelper
2
- def self.lookup(class_name, scope)
3
- if class_name.is_a?(Class)
4
- class_name
5
- elsif namespaced?(class_name)
6
- class_name.constantize
7
- else
8
- lookup_in_parent(class_name, scope)
9
- end
10
- end
11
-
12
- def self.namespaced?(class_name)
13
- class_name.include?("::")
14
- end
15
-
16
- def self.lookup_in_parent(class_name, scope)
17
- parent = parent_scope(scope)
18
- return nil unless parent.const_defined?(class_name)
19
- parent.const_get(class_name)
20
- end
21
-
22
- def self.parent_scope(scope)
23
- chain = scope.to_s.split("::")[0 ... -1]
24
- chain.reduce(Object) { |m, o| m.const_get(o) }
25
- end
26
-
27
- def self.leaf(constant_name)
28
- constant_name.split("::").last
29
- end
30
- end
31
-
32
1
  module MongoMapper
33
2
  module Associations
3
+ # Base class for keeping track of associations.
4
+ #
5
+ # @private
34
6
  class Base
35
- attr_reader :type, :name, :options
7
+ attr_reader :type, :name, :options, :finder_options
8
+
9
+ # Options that should not be considered MongoDB query options/criteria
10
+ AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :polymorphic]
11
+
12
+ def initialize(type, name, options={}, &extension)
13
+ @type, @name, @options, @finder_options = type, name, {}, {}
14
+ options.symbolize_keys!
36
15
 
37
- def initialize(type, name, options = {})
38
- @type, @name, @options = type, name, options
16
+ options[:extend] = modulized_extensions(extension, options[:extend])
17
+
18
+ options.each_pair do |key, value|
19
+ if AssociationOptions.include?(key)
20
+ @options[key] = value
21
+ else
22
+ @finder_options[key] = value
23
+ end
24
+ end
39
25
  end
40
26
 
41
27
  def class_name
@@ -49,9 +35,9 @@ module MongoMapper
49
35
  end
50
36
  end
51
37
  end
52
-
38
+
53
39
  def klass
54
- @klass ||= ConstantHelper.lookup(class_name, options[:scope])
40
+ @klass ||= options[:class] || class_name.constantize
55
41
  end
56
42
 
57
43
  def many?
@@ -109,6 +95,16 @@ module MongoMapper
109
95
  end
110
96
  end # end begin
111
97
  end # end proxy_class
98
+
99
+ private
100
+
101
+ # @param [Array<Module, Proc>] extensions a collection of Modules or
102
+ # Procs that extend the behaviour of this association.
103
+ def modulized_extensions(*extensions)
104
+ extensions.flatten.compact.map do |extension|
105
+ Proc === extension ? Module.new(&extension) : extension
106
+ end
107
+ end
112
108
  end
113
109
  end
114
110
  end
@@ -8,10 +8,8 @@ module MongoMapper
8
8
 
9
9
  def apply_scope(doc)
10
10
  ensure_owner_saved
11
-
12
11
  doc.send("#{as_type_name}=", @owner.class.name)
13
12
  doc.send("#{as_id_name}=", @owner.id)
14
-
15
13
  doc
16
14
  end
17
15
 
@@ -10,25 +10,30 @@ module MongoMapper
10
10
  options = args.extract_options!
11
11
  klass.find(*args << scoped_options(options))
12
12
  end
13
+
14
+ def find!(*args)
15
+ options = args.extract_options!
16
+ klass.find!(*args << scoped_options(options))
17
+ end
13
18
 
14
19
  def paginate(options)
15
20
  klass.paginate(scoped_options(options))
16
21
  end
17
22
 
18
23
  def all(options={})
19
- find(:all, scoped_options(options))
24
+ klass.all(scoped_options(options))
20
25
  end
21
26
 
22
27
  def first(options={})
23
- find(:first, scoped_options(options))
28
+ klass.first(scoped_options(options))
24
29
  end
25
30
 
26
31
  def last(options={})
27
- find(:last, scoped_options(options))
32
+ klass.last(scoped_options(options))
28
33
  end
29
34
 
30
35
  def count(options={})
31
- klass.count(options.merge(scoped_conditions))
36
+ klass.count(scoped_options(options))
32
37
  end
33
38
 
34
39
  def replace(docs)
@@ -56,6 +61,12 @@ module MongoMapper
56
61
  apply_scope(doc).save
57
62
  doc
58
63
  end
64
+
65
+ def create!(attrs={})
66
+ doc = klass.new(attrs)
67
+ apply_scope(doc).save!
68
+ doc
69
+ end
59
70
 
60
71
  def destroy_all(options={})
61
72
  all(options).map(&:destroy)
@@ -89,13 +100,13 @@ module MongoMapper
89
100
  def scoped_conditions
90
101
  {self.foreign_key => @owner.id}
91
102
  end
92
-
103
+
93
104
  def scoped_options(options)
94
- options.merge(scoped_conditions)
105
+ @association.finder_options.merge(options).merge(scoped_conditions)
95
106
  end
96
107
 
97
108
  def find_target
98
- find(:all)
109
+ all
99
110
  end
100
111
 
101
112
  def ensure_owner_saved
@@ -109,9 +120,7 @@ module MongoMapper
109
120
  end
110
121
 
111
122
  def foreign_key
112
- @association.options[:foreign_key] ||
113
- (ConstantHelper.leaf(@owner.class.name).
114
- underscore.gsub("/", "_") + "_id")
123
+ @association.options[:foreign_key] || @owner.class.name.underscore.gsub("/", "_") + "_id"
115
124
  end
116
125
  end
117
126
  end
@@ -1,6 +1,6 @@
1
1
  module MongoMapper
2
2
  module Associations
3
- class ManyEmbeddedPolymorphicProxy < Proxy
3
+ class ManyEmbeddedPolymorphicProxy < Proxy
4
4
  def replace(v)
5
5
  @_values = v.map do |doc_or_hash|
6
6
  if doc_or_hash.kind_of?(EmbeddedDocument)
@@ -30,4 +30,4 @@ module MongoMapper
30
30
  end
31
31
  end
32
32
  end
33
- end
33
+ end
@@ -5,34 +5,23 @@ module MongoMapper
5
5
  @_values = v.map { |e| e.kind_of?(EmbeddedDocument) ? e.attributes : e }
6
6
  reset
7
7
  end
8
-
9
- def build(opts={})
10
- owner = @owner
11
- child = @association.klass.new(opts)
12
- assign_parent_reference(child)
13
- child._root_document = owner
14
- self << child
15
- child
8
+
9
+ def build(attributes={})
10
+ doc = @association.klass.new(attributes)
11
+ assign_root_document(doc)
12
+ self << doc
13
+ doc
16
14
  end
17
-
18
- def find(opts)
19
- case opts
20
- when :all
21
- self
22
- when String
23
- if load_target
24
- child = @target.detect {|item| item.id == opts}
25
- assign_parent_reference(child)
26
- child
27
- end
28
- end
15
+
16
+ def find(id)
17
+ load_target
18
+ @target.detect { |item| item.id == id }
29
19
  end
30
20
 
31
21
  def <<(*docs)
32
22
  if load_target
33
- root = @owner._root_document || @owner
34
23
  docs.each do |doc|
35
- doc._root_document = root
24
+ assign_root_document(doc)
36
25
  @target << doc
37
26
  end
38
27
  end
@@ -40,28 +29,24 @@ module MongoMapper
40
29
  alias_method :push, :<<
41
30
  alias_method :concat, :<<
42
31
 
43
- protected
32
+ private
44
33
  def find_target
45
34
  (@_values || []).map do |e|
46
35
  child = @association.klass.new(e)
47
- assign_parent_reference(child)
36
+ assign_root_document(child)
48
37
  child
49
38
  end
50
39
  end
51
-
52
- private
53
-
54
- def assign_parent_reference(child)
55
- return unless child && @owner
56
- return if @owner.class.name.blank?
57
- owner = @owner
58
- child.class_eval do
59
- define_method(owner.class.name.underscore) do
60
- owner
61
- end
40
+
41
+ def root_document
42
+ @owner._root_document || @owner
43
+ end
44
+
45
+ def assign_root_document(*docs)
46
+ docs.each do |doc|
47
+ doc._root_document = root_document
62
48
  end
63
49
  end
64
-
65
50
  end
66
51
  end
67
52
  end
@@ -1,6 +1,6 @@
1
1
  module MongoMapper
2
2
  module Associations
3
- class ManyPolymorphicProxy < ManyDocumentsProxy
3
+ class ManyPolymorphicProxy < ManyDocumentsProxy
4
4
  private
5
5
  def apply_scope(doc)
6
6
  doc.send("#{@association.type_key_name}=", doc.class.name)
@@ -6,6 +6,7 @@ module MongoMapper
6
6
  def initialize(owner, association)
7
7
  @owner = owner
8
8
  @association = association
9
+ @association.options[:extend].each { |ext| proxy_extend(ext) }
9
10
  reset
10
11
  end
11
12
 
@@ -32,7 +33,7 @@ module MongoMapper
32
33
  def replace(v)
33
34
  raise NotImplementedError
34
35
  end
35
-
36
+
36
37
  def inspect
37
38
  load_target
38
39
  @target.inspect
@@ -42,7 +43,7 @@ module MongoMapper
42
43
  load_target
43
44
  @target.nil?
44
45
  end
45
-
46
+
46
47
  protected
47
48
  def method_missing(method, *args)
48
49
  if load_target
@@ -1,13 +1,121 @@
1
1
  module MongoMapper
2
2
  module Associations
3
3
  module ClassMethods
4
- def belongs_to(association_id, options = {})
5
- create_association(:belongs_to, association_id, options, self)
4
+ ##
5
+ # This macro allows you define a "belongs-to" relationship between one
6
+ # document and some other document.
7
+ #
8
+ # == Requirements
9
+ #
10
+ # Usage of this macro requires that your document define a key that can
11
+ # be used to store the ID of the target document that is the parent of
12
+ # this document.
13
+ #
14
+ # == Conventions
15
+ #
16
+ # The following is a list of the conventions used by MongoMapper in
17
+ # defining a belongs-to relationship. Each can likely be overridden via
18
+ # the +options+ parameter.
19
+ #
20
+ # * The name of your belongs-to association is the lowercase, singular
21
+ # name of the target class
22
+ # * A key with the name of your association exists with an "_id" suffix
23
+ # to store the ID of the target of this relationship
24
+ #
25
+ # @param [Symbol] association_id The name of this association
26
+ # @param [Hash] options Optional parameters that define the
27
+ # characteristics of this relationship. These are often used to
28
+ # override MongoMapper conventions.
29
+ # @option options [Boolean] :polymorphic (false) Set this option to
30
+ # <code>true</code> to define a relationship that can be between this
31
+ # document and any other type of document. Note that you *must* also
32
+ # have a key on your document to store the type of document in this
33
+ # relationship.
34
+ # @option options [String] :class_name If your relationship doesn't use
35
+ # the name of some class, you *must* use this option to indicate the
36
+ # target class for this relationship.
37
+ # @option options [Symbol] :foreign_key Use this option to specify a
38
+ # non-conventional key that stores the ID of the parent in this
39
+ # relationship
40
+ #
41
+ # @example Conventional, and simple, usage of <code>belongs_to</code>
42
+ # class Novel
43
+ # include MongoMapper::Document
44
+ #
45
+ # key :author_id, String # our "foreign key"
46
+ #
47
+ # belongs_to :author
48
+ # end
49
+ #
50
+ # @example Using :foreign_key and :class_name
51
+ # class Pet
52
+ # include MongoMapper::Document
53
+ #
54
+ # key :person_id, String
55
+ #
56
+ # belongs_to :owner,
57
+ # :foreign_key => :person_id,
58
+ # :class_name => "Person"
59
+ # end
60
+ #
61
+ # @example Defining a polymorphic belongs-to relationship
62
+ # class Vehicle
63
+ # include MongoMapper::Document
64
+ #
65
+ # key :owner_id, String
66
+ # key :owner_type, String
67
+ #
68
+ # belongs_to :owner,
69
+ # :polymorphic => true
70
+ # end
71
+ #
72
+ # @example Non-standard polymorphic belongs-to relationship
73
+ # class Vehicle
74
+ # include MongoMapper::Document
75
+ #
76
+ # key :person_id, String
77
+ # key :person_type, String
78
+ #
79
+ # belongs_to :owner,
80
+ # :polymorphic => true,
81
+ # :foreign_key => "person_id",
82
+ # :type_key_name => "person_type"
83
+ # end
84
+ def belongs_to(association_id, options={}, &extension)
85
+ create_association(:belongs_to, association_id, options, &extension)
6
86
  self
7
87
  end
8
88
 
9
- def many(association_id, options = {})
10
- create_association(:many, association_id, options, self)
89
+ ##
90
+ # This macro allows you to define a "has-many" relationship between a
91
+ # document, and numerous child documents.
92
+ #
93
+ # == Conventions
94
+ #
95
+ # The following is a list of the conventions used by MongoMapper in
96
+ # defining this relationship. Each can likely be overridden via the
97
+ # +options+ parameter.
98
+ #
99
+ # * The name of your association is the lowercase, *plural* name of the
100
+ # target class
101
+ # * Your target class must have a "foreign key" bearing the name of this
102
+ # class suffixed by "_id"
103
+ #
104
+ # @param [Symbol] association_id The name of this association
105
+ # @param [Hash] options Optional parameters that define the
106
+ # characteristics of this relationship. These are often used to
107
+ # override MongoMapper conventions.
108
+ # @option options [String] :class_name If your relationship doesn't use
109
+ # the name of some class, you *must* use this option to indicate the
110
+ # target class for this relationship.
111
+ # @option options [Symbol] :foreign_key Use this option to specify a
112
+ # non-conventional key that stores the ID of the parent in this
113
+ # relationship
114
+ # @option options [#to_s] :as Used when the target relationship is
115
+ # polymorphic (i.e. the +belongs_to+ has set <tt>:polymorphic</tt> to
116
+ # +true+). See examples for usage.
117
+ def many(association_id, options={}, &extension)
118
+ create_association(:many, association_id, options, &extension)
11
119
  self
12
120
  end
13
121
 
@@ -18,9 +126,8 @@ module MongoMapper
18
126
  end
19
127
 
20
128
  private
21
- def create_association(type, name, options, scope)
22
- options[:scope] = scope
23
- association = Associations::Base.new(type, name, options)
129
+ def create_association(type, name, options, &extension)
130
+ association = Associations::Base.new(type, name, options, &extension)
24
131
  associations[association.name] = association
25
132
  define_association_methods(association)
26
133
  define_dependent_callback(association)
@@ -60,7 +167,6 @@ module MongoMapper
60
167
  end
61
168
  end
62
169
  end
63
-
64
170
  end
65
171
 
66
172
  module InstanceMethods
@@ -1,4 +1,17 @@
1
1
  module MongoMapper
2
+ # This module is mixed into the Document module to provide call-backs before
3
+ # and after the following events:
4
+ #
5
+ # * save
6
+ # * create
7
+ # * update
8
+ # * validation
9
+ # ** every validation
10
+ # ** validation when created
11
+ # ** validation when updated
12
+ # * destruction
13
+ #
14
+ # @see ActiveSupport::Callbacks
2
15
  module Callbacks
3
16
  def self.included(model) #:nodoc:
4
17
  model.class_eval do
@@ -42,6 +55,11 @@ module MongoMapper
42
55
  return result
43
56
  end
44
57
 
58
+ # Here we override the +destroy+ method to allow for the +before_destroy+
59
+ # and +after_destroy+ call-backs. Note that the +destroy+ call is aborted
60
+ # if the +before_destroy+ call-back returns +false+.
61
+ #
62
+ # @return the result of calling +destroy+ on the document
45
63
  def destroy #:nodoc:
46
64
  return false if callback(:before_destroy) == false
47
65
  result = super