mongo_mapper-unstable 2010.3.8 → 2010.06.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. data/README.rdoc +4 -8
  2. data/bin/mmconsole +1 -1
  3. data/examples/keys.rb +37 -0
  4. data/examples/plugins.rb +41 -0
  5. data/examples/querying.rb +35 -0
  6. data/examples/scopes.rb +52 -0
  7. data/lib/mongo_mapper/connection.rb +83 -0
  8. data/lib/mongo_mapper/document.rb +11 -329
  9. data/lib/mongo_mapper/embedded_document.rb +9 -38
  10. data/lib/mongo_mapper/exceptions.rb +30 -0
  11. data/lib/mongo_mapper/extensions/array.rb +19 -0
  12. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  13. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  14. data/lib/mongo_mapper/extensions/date.rb +25 -0
  15. data/lib/mongo_mapper/extensions/float.rb +14 -0
  16. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  17. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  18. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  19. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  20. data/lib/mongo_mapper/extensions/object.rb +27 -0
  21. data/lib/mongo_mapper/extensions/object_id.rb +30 -0
  22. data/lib/mongo_mapper/extensions/set.rb +20 -0
  23. data/lib/mongo_mapper/extensions/string.rb +18 -0
  24. data/lib/mongo_mapper/extensions/time.rb +29 -0
  25. data/lib/mongo_mapper/plugins/accessible.rb +44 -0
  26. data/lib/mongo_mapper/plugins/associations/base.rb +7 -6
  27. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +5 -6
  28. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +5 -6
  29. data/lib/mongo_mapper/plugins/associations/collection.rb +1 -0
  30. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +2 -1
  31. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +25 -39
  32. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +4 -4
  33. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +36 -46
  34. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +1 -0
  35. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +5 -4
  36. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +1 -0
  37. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +40 -0
  38. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +7 -7
  39. data/lib/mongo_mapper/plugins/associations/proxy.rb +16 -8
  40. data/lib/mongo_mapper/plugins/associations.rb +14 -22
  41. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  42. data/lib/mongo_mapper/plugins/callbacks.rb +17 -5
  43. data/lib/mongo_mapper/plugins/clone.rb +10 -4
  44. data/lib/mongo_mapper/plugins/descendants.rb +3 -2
  45. data/lib/mongo_mapper/plugins/dirty.rb +1 -0
  46. data/lib/mongo_mapper/plugins/document.rb +41 -0
  47. data/lib/mongo_mapper/{support/find.rb → plugins/dynamic_querying/dynamic_finder.rb} +3 -36
  48. data/lib/mongo_mapper/plugins/dynamic_querying.rb +43 -0
  49. data/lib/mongo_mapper/plugins/embedded_document.rb +49 -0
  50. data/lib/mongo_mapper/plugins/equality.rb +4 -10
  51. data/lib/mongo_mapper/plugins/identity_map.rb +29 -23
  52. data/lib/mongo_mapper/plugins/indexes.rb +12 -0
  53. data/lib/mongo_mapper/plugins/inspect.rb +1 -0
  54. data/lib/mongo_mapper/plugins/keys/key.rb +55 -0
  55. data/lib/mongo_mapper/plugins/keys.rb +85 -110
  56. data/lib/mongo_mapper/plugins/logger.rb +1 -0
  57. data/lib/mongo_mapper/plugins/modifiers.rb +41 -16
  58. data/lib/mongo_mapper/plugins/pagination.rb +5 -15
  59. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  60. data/lib/mongo_mapper/plugins/protected.rb +9 -1
  61. data/lib/mongo_mapper/plugins/querying/decorator.rb +46 -0
  62. data/lib/mongo_mapper/plugins/querying/plucky_methods.rb +15 -0
  63. data/lib/mongo_mapper/plugins/querying.rb +176 -0
  64. data/lib/mongo_mapper/plugins/rails.rb +6 -1
  65. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  66. data/lib/mongo_mapper/plugins/sci.rb +32 -0
  67. data/lib/mongo_mapper/plugins/scopes.rb +21 -0
  68. data/lib/mongo_mapper/plugins/serialization.rb +5 -4
  69. data/lib/mongo_mapper/plugins/timestamps.rb +2 -1
  70. data/lib/mongo_mapper/plugins/userstamps.rb +1 -0
  71. data/lib/mongo_mapper/plugins/validations.rb +9 -5
  72. data/lib/mongo_mapper/plugins.rb +1 -20
  73. data/lib/mongo_mapper/support/descendant_appends.rb +5 -6
  74. data/lib/mongo_mapper/version.rb +4 -0
  75. data/lib/mongo_mapper.rb +71 -128
  76. data/test/{NOTE_ON_TESTING → _NOTE_ON_TESTING} +0 -0
  77. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +5 -5
  78. data/test/functional/associations/test_belongs_to_proxy.rb +13 -21
  79. data/test/functional/associations/test_in_array_proxy.rb +7 -9
  80. data/test/functional/associations/test_many_documents_as_proxy.rb +5 -5
  81. data/test/functional/associations/test_many_documents_proxy.rb +186 -64
  82. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +22 -22
  83. data/test/functional/associations/test_many_embedded_proxy.rb +32 -32
  84. data/test/functional/associations/test_many_polymorphic_proxy.rb +47 -47
  85. data/test/functional/associations/test_one_embedded_proxy.rb +67 -0
  86. data/test/functional/associations/test_one_proxy.rb +70 -49
  87. data/test/functional/test_accessible.rb +168 -0
  88. data/test/functional/test_associations.rb +11 -11
  89. data/test/functional/test_binary.rb +5 -5
  90. data/test/functional/test_caching.rb +76 -0
  91. data/test/functional/test_callbacks.rb +104 -34
  92. data/test/functional/test_dirty.rb +16 -16
  93. data/test/functional/test_document.rb +12 -924
  94. data/test/functional/test_dynamic_querying.rb +75 -0
  95. data/test/functional/test_embedded_document.rb +88 -8
  96. data/test/functional/test_identity_map.rb +41 -43
  97. data/test/functional/{test_indexing.rb → test_indexes.rb} +3 -5
  98. data/test/functional/test_logger.rb +1 -1
  99. data/test/functional/test_modifiers.rb +275 -181
  100. data/test/functional/test_pagination.rb +13 -15
  101. data/test/functional/test_protected.rb +25 -11
  102. data/test/functional/test_querying.rb +873 -0
  103. data/test/functional/test_safe.rb +76 -0
  104. data/test/functional/test_sci.rb +230 -0
  105. data/test/functional/test_scopes.rb +171 -0
  106. data/test/functional/test_string_id_compatibility.rb +11 -11
  107. data/test/functional/test_timestamps.rb +0 -2
  108. data/test/functional/test_userstamps.rb +0 -1
  109. data/test/functional/test_validations.rb +44 -31
  110. data/test/models.rb +18 -17
  111. data/test/{active_model_lint_test.rb → test_active_model_lint.rb} +3 -1
  112. data/test/test_helper.rb +59 -16
  113. data/test/unit/associations/test_base.rb +47 -42
  114. data/test/unit/associations/test_proxy.rb +15 -15
  115. data/test/unit/serializers/test_json_serializer.rb +29 -29
  116. data/test/unit/test_clone.rb +69 -0
  117. data/test/unit/test_descendant_appends.rb +3 -3
  118. data/test/unit/test_document.rb +49 -67
  119. data/test/unit/test_dynamic_finder.rb +53 -51
  120. data/test/unit/test_embedded_document.rb +19 -38
  121. data/test/unit/{test_support.rb → test_extensions.rb} +136 -122
  122. data/test/unit/test_key.rb +185 -0
  123. data/test/unit/test_keys.rb +29 -147
  124. data/test/unit/test_mongo_mapper.rb +3 -48
  125. data/test/unit/test_pagination.rb +1 -150
  126. data/test/unit/test_rails.rb +77 -19
  127. data/test/unit/test_rails_compatibility.rb +12 -12
  128. data/test/unit/test_serialization.rb +5 -5
  129. data/test/unit/test_time_zones.rb +9 -9
  130. data/test/unit/test_validations.rb +46 -46
  131. metadata +157 -155
  132. data/.gitignore +0 -10
  133. data/Rakefile +0 -55
  134. data/VERSION +0 -1
  135. data/lib/mongo_mapper/plugins/pagination/proxy.rb +0 -72
  136. data/lib/mongo_mapper/query.rb +0 -130
  137. data/lib/mongo_mapper/support.rb +0 -215
  138. data/mongo_mapper.gemspec +0 -196
  139. data/performance/read_write.rb +0 -52
  140. data/specs.watchr +0 -51
  141. data/test/support/custom_matchers.rb +0 -55
  142. data/test/support/timing.rb +0 -16
  143. data/test/unit/test_query.rb +0 -340
@@ -1,57 +1,36 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
4
5
  class InArrayProxy < Collection
5
- include Support::Find
6
+ include DynamicQuerying::ClassMethods
6
7
 
7
8
  def find(*args)
8
- options = args.extract_options!
9
-
10
- case args.first
11
- when :first
12
- first(options)
13
- when :last
14
- last(options)
15
- when :all
16
- all(options)
17
- else
18
- klass.find(*scoped_ids(args) << scoped_options(options))
19
- end
9
+ query.find(*scoped_ids(args))
20
10
  end
21
11
 
22
12
  def find!(*args)
23
- options = args.extract_options!
24
-
25
- case args.first
26
- when :first
27
- first(options)
28
- when :last
29
- last(options)
30
- when :all
31
- all(options)
32
- else
33
- klass.find!(*scoped_ids(args) << scoped_options(options))
34
- end
13
+ query.find!(*scoped_ids(args))
35
14
  end
36
15
 
37
16
  def paginate(options)
38
- klass.paginate(scoped_options(options))
17
+ query.paginate(options)
39
18
  end
40
19
 
41
20
  def all(options={})
42
- klass.all(scoped_options(options))
21
+ query(options).all
43
22
  end
44
23
 
45
24
  def first(options={})
46
- klass.first(scoped_options(options))
25
+ query(options).first
47
26
  end
48
27
 
49
28
  def last(options={})
50
- klass.last(scoped_options(options))
29
+ query(options).last
51
30
  end
52
31
 
53
32
  def count(options={})
54
- options.blank? ? ids.size : klass.count(scoped_options(options))
33
+ options.blank? ? ids.size : query(options).count
55
34
  end
56
35
 
57
36
  def destroy_all(options={})
@@ -63,7 +42,7 @@ module MongoMapper
63
42
  end
64
43
 
65
44
  def delete_all(options={})
66
- docs = all(options.merge(:select => ['_id']))
45
+ docs = query(options).fields(:_id).all
67
46
  docs.each { |doc| ids.delete(doc.id) }
68
47
  klass.delete(docs.map(&:id))
69
48
  reset
@@ -78,7 +57,7 @@ module MongoMapper
78
57
  doc = klass.create(attrs)
79
58
  unless doc.new?
80
59
  ids << doc.id
81
- owner.save
60
+ proxy_owner.save
82
61
  reset
83
62
  end
84
63
  doc
@@ -88,7 +67,7 @@ module MongoMapper
88
67
  doc = klass.create!(attrs)
89
68
  unless doc.new?
90
69
  ids << doc.id
91
- owner.save
70
+ proxy_owner.save
92
71
  reset
93
72
  end
94
73
  doc
@@ -116,16 +95,23 @@ module MongoMapper
116
95
  end
117
96
 
118
97
  private
119
- def scoped_conditions
120
- {:_id => ids}
98
+ def query(options={})
99
+ klass.
100
+ query(association.query_options).
101
+ update(options).
102
+ update(criteria)
121
103
  end
122
104
 
123
- def scoped_options(options)
124
- association.query_options.merge(options).merge(scoped_conditions)
105
+ def criteria
106
+ {:_id => ids}
125
107
  end
126
108
 
127
109
  def scoped_ids(args)
128
- args.flatten.reject { |id| !ids.include?(id) }
110
+ valid = args.flatten.select do |id|
111
+ id = ObjectId.to_mongo(id) if klass.using_object_id?
112
+ ids.include?(id)
113
+ end
114
+ valid.empty? ? nil : valid
129
115
  end
130
116
 
131
117
  def find_target
@@ -133,7 +119,7 @@ module MongoMapper
133
119
  end
134
120
 
135
121
  def ids
136
- owner[options[:in]]
122
+ proxy_owner[options[:in]]
137
123
  end
138
124
  end
139
125
  end
@@ -1,16 +1,16 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
4
5
  class ManyDocumentsAsProxy < ManyDocumentsProxy
5
6
  protected
6
- def scoped_conditions
7
- {type_key_name => owner.class.name, id_key_name => owner.id}
7
+ def criteria
8
+ {type_key_name => proxy_owner.class.name, id_key_name => proxy_owner.id}
8
9
  end
9
10
 
10
11
  def apply_scope(doc)
11
12
  ensure_owner_saved
12
- doc[type_key_name] = owner.class.name
13
- doc[id_key_name] = owner.id
13
+ criteria.each { |key, value| doc[key] = value }
14
14
  doc
15
15
  end
16
16
 
@@ -1,49 +1,21 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
4
5
  class ManyDocumentsProxy < Collection
5
- include Support::Find
6
-
7
- def find(*args)
8
- options = args.extract_options!
9
- klass.find(*args << scoped_options(options))
10
- end
11
-
12
- def find!(*args)
13
- options = args.extract_options!
14
- klass.find!(*args << scoped_options(options))
15
- end
16
-
17
- def paginate(options)
18
- klass.paginate(scoped_options(options))
19
- end
20
-
21
- def all(options={})
22
- klass.all(scoped_options(options))
23
- end
24
-
25
- def first(options={})
26
- klass.first(scoped_options(options))
27
- end
28
-
29
- def last(options={})
30
- klass.last(scoped_options(options))
31
- end
32
-
33
- def count(options={})
34
- klass.count(scoped_options(options))
35
- end
6
+ include DynamicQuerying::ClassMethods
7
+ include Querying::PluckyMethods
36
8
 
37
9
  def replace(docs)
38
10
  load_target
39
11
  target.map(&:destroy)
40
- docs.each { |doc| apply_scope(doc).save }
12
+ docs.each { |doc| prepare(doc).save }
41
13
  reset
42
14
  end
43
15
 
44
16
  def <<(*docs)
45
17
  ensure_owner_saved
46
- flatten_deeper(docs).each { |doc| apply_scope(doc).save }
18
+ flatten_deeper(docs).each { |doc| prepare(doc).save }
47
19
  reset
48
20
  end
49
21
  alias_method :push, :<<
@@ -52,7 +24,8 @@ module MongoMapper
52
24
  def build(attrs={})
53
25
  doc = klass.new(attrs)
54
26
  apply_scope(doc)
55
- reset
27
+ @target ||= [] unless loaded?
28
+ @target << doc
56
29
  doc
57
30
  end
58
31
 
@@ -76,25 +49,38 @@ module MongoMapper
76
49
  end
77
50
 
78
51
  def delete_all(options={})
79
- klass.delete_all(options.merge(scoped_conditions))
52
+ query(options).remove
80
53
  reset
81
54
  end
82
55
 
83
56
  def nullify
84
- criteria = Query.new(klass, scoped_conditions).criteria
85
- all(criteria).each do |doc|
86
- doc.update_attributes(self.foreign_key => nil)
87
- end
57
+ all.each { |doc| doc.update_attributes(self.foreign_key => nil) }
88
58
  reset
89
59
  end
90
60
 
61
+ def save_to_collection(options={})
62
+ @target.each { |doc| doc.save(options) } if @target
63
+ end
64
+
91
65
  protected
92
- def scoped_conditions
93
- {self.foreign_key => owner.id}
66
+ def query(options={})
67
+ klass.
68
+ query(association.query_options).
69
+ update(options).update(criteria)
70
+ end
71
+
72
+ def method_missing(method, *args, &block)
73
+ if klass.respond_to?(method)
74
+ result = klass.send(method, *args, &block)
75
+ result.is_a?(Plucky::Query) ?
76
+ query.merge(result) : super
77
+ else
78
+ super
79
+ end
94
80
  end
95
81
 
96
- def scoped_options(options)
97
- association.query_options.merge(options).merge(scoped_conditions)
82
+ def criteria
83
+ {self.foreign_key => proxy_owner.id}
98
84
  end
99
85
 
100
86
  def find_target
@@ -102,17 +88,21 @@ module MongoMapper
102
88
  end
103
89
 
104
90
  def ensure_owner_saved
105
- owner.save if owner.new?
91
+ proxy_owner.save if proxy_owner.new?
92
+ end
93
+
94
+ def prepare(doc)
95
+ klass === doc ? apply_scope(doc) : build(doc)
106
96
  end
107
97
 
108
98
  def apply_scope(doc)
109
99
  ensure_owner_saved
110
- doc[foreign_key] = owner.id
100
+ criteria.each { |key, value| doc[key] = value }
111
101
  doc
112
102
  end
113
103
 
114
104
  def foreign_key
115
- options[:foreign_key] || owner.class.name.to_s.underscore.gsub("/", "_") + "_id"
105
+ options[:foreign_key] || proxy_owner.class.name.to_s.underscore.gsub("/", "_") + "_id"
116
106
  end
117
107
  end
118
108
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
@@ -11,10 +12,10 @@ module MongoMapper
11
12
 
12
13
  private
13
14
  def find_target
14
- (@_values || []).map do |v|
15
- child = klass.load(v)
16
- assign_references(child)
17
- child
15
+ (@_values || []).map do |attrs|
16
+ klass.load(attrs).tap do |child|
17
+ assign_references(child)
18
+ end
18
19
  end
19
20
  end
20
21
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
@@ -0,0 +1,40 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class OneEmbeddedProxy < Proxy
6
+ def build(attributes={})
7
+ @target = klass.new(attributes)
8
+ assign_references(@target)
9
+ loaded
10
+ @target
11
+ end
12
+
13
+ def replace(doc)
14
+ if doc.respond_to?(:attributes)
15
+ @target = klass.load(doc.attributes)
16
+ else
17
+ @target = klass.load(doc)
18
+ end
19
+ assign_references(@target)
20
+ loaded
21
+ @target
22
+ end
23
+
24
+ protected
25
+
26
+ def find_target
27
+ if @value
28
+ klass.load(@value).tap do |child|
29
+ assign_references(child)
30
+ end
31
+ end
32
+ end
33
+
34
+ def assign_references(doc)
35
+ doc._parent_document = proxy_owner if doc
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,9 +1,8 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
4
5
  class OneProxy < Proxy
5
- undef_method :object_id
6
-
7
6
  def build(attrs={})
8
7
  instantiate_target(:new, attrs)
9
8
  end
@@ -36,8 +35,9 @@ module MongoMapper
36
35
  reset
37
36
 
38
37
  unless doc.nil?
39
- owner.save if owner.new?
40
- doc[foreign_key] = owner.id
38
+ proxy_owner.save if proxy_owner.new?
39
+ doc = klass.new(doc) unless klass === doc
40
+ doc[foreign_key] = proxy_owner.id
41
41
  doc.save if doc.new?
42
42
  loaded
43
43
  @target = doc
@@ -46,11 +46,11 @@ module MongoMapper
46
46
 
47
47
  protected
48
48
  def find_target
49
- target_class.first(association.query_options.merge(foreign_key => owner.id))
49
+ target_class.first(association.query_options.merge(foreign_key => proxy_owner.id))
50
50
  end
51
51
 
52
52
  def instantiate_target(instantiator, attrs={})
53
- @target = target_class.send(instantiator, attrs.update(foreign_key => owner.id))
53
+ @target = target_class.send(instantiator, attrs.update(foreign_key => proxy_owner.id))
54
54
  loaded
55
55
  @target
56
56
  end
@@ -60,7 +60,7 @@ module MongoMapper
60
60
  end
61
61
 
62
62
  def foreign_key
63
- options[:foreign_key] || owner.class.name.foreign_key
63
+ options[:foreign_key] || proxy_owner.class.name.foreign_key
64
64
  end
65
65
  end
66
66
  end
@@ -1,24 +1,26 @@
1
+ # encoding: UTF-8
2
+ require 'forwardable'
1
3
  module MongoMapper
2
4
  module Plugins
3
5
  module Associations
4
6
  class Proxy
7
+ extend Forwardable
8
+
5
9
  alias :proxy_respond_to? :respond_to?
6
10
  alias :proxy_extend :extend
7
11
 
8
12
  instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
9
13
 
10
- attr_reader :owner, :association, :target
14
+ attr_reader :proxy_owner, :association, :target
11
15
 
12
- alias :proxy_owner :owner
13
16
  alias :proxy_target :target
14
17
  alias :proxy_association :association
15
18
 
16
- delegate :klass, :to => :proxy_association
17
- delegate :options, :to => :proxy_association
18
- delegate :collection, :to => :klass
19
+ def_delegators :proxy_association, :klass, :options
20
+ def_delegator :klass, :collection
19
21
 
20
22
  def initialize(owner, association)
21
- @owner, @association, @loaded = owner, association, false
23
+ @proxy_owner, @association, @loaded = owner, association, false
22
24
  Array(association.options[:extend]).each { |ext| proxy_extend(ext) }
23
25
  reset
24
26
  end
@@ -96,8 +98,14 @@ module MongoMapper
96
98
  end
97
99
 
98
100
  def load_target
99
- @target = find_target unless loaded?
100
- loaded
101
+ unless loaded?
102
+ if @target.is_a?(Array) && @target.any?
103
+ @target = find_target + @target.find_all { |record| record.new? }
104
+ else
105
+ @target = find_target
106
+ end
107
+ loaded
108
+ end
101
109
  @target
102
110
  rescue MongoMapper::DocumentNotFound
103
111
  reset
@@ -1,7 +1,13 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Associations
4
5
  module ClassMethods
6
+ def inherited(subclass)
7
+ subclass.associations = associations.dup
8
+ super
9
+ end
10
+
5
11
  def belongs_to(association_id, options={}, &extension)
6
12
  create_association(:belongs_to, association_id, options, &extension)
7
13
  end
@@ -22,11 +28,6 @@ module MongoMapper
22
28
  @associations = hash
23
29
  end
24
30
 
25
- def inherited(subclass)
26
- subclass.associations = associations.dup
27
- super
28
- end
29
-
30
31
  private
31
32
  def create_association(type, name, options, &extension)
32
33
  association = Associations::Base.new(type, name, options, &extension)
@@ -67,7 +68,6 @@ module MongoMapper
67
68
  self.class.associations
68
69
  end
69
70
 
70
- # @api private?
71
71
  def embedded_associations
72
72
  associations.select do |name, association|
73
73
  association.embeddable?
@@ -81,25 +81,17 @@ module MongoMapper
81
81
  proxy = association.proxy_class.new(self, association)
82
82
  self.instance_variable_set(association.ivar, proxy)
83
83
  end
84
-
85
84
  proxy
86
85
  end
87
- end
88
86
 
89
- autoload :Base, 'mongo_mapper/plugins/associations/base'
90
- autoload :Collection, 'mongo_mapper/plugins/associations/collection'
91
- autoload :EmbeddedCollection, 'mongo_mapper/plugins/associations/embedded_collection'
92
- autoload :ManyDocumentsProxy, 'mongo_mapper/plugins/associations/many_documents_proxy'
93
- autoload :BelongsToProxy, 'mongo_mapper/plugins/associations/belongs_to_proxy'
94
- autoload :BelongsToPolymorphicProxy, 'mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy'
95
- autoload :ManyPolymorphicProxy, 'mongo_mapper/plugins/associations/many_polymorphic_proxy'
96
- autoload :ManyEmbeddedProxy, 'mongo_mapper/plugins/associations/many_embedded_proxy'
97
- autoload :ManyEmbeddedPolymorphicProxy, 'mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy'
98
- autoload :ManyDocumentsAsProxy, 'mongo_mapper/plugins/associations/many_documents_as_proxy'
99
- autoload :OneProxy, 'mongo_mapper/plugins/associations/one_proxy'
100
- autoload :InArrayProxy, 'mongo_mapper/plugins/associations/in_array_proxy'
87
+ def save_to_collection(options={})
88
+ super
89
+ associations.each do |association_name, association|
90
+ proxy = get_proxy(association)
91
+ proxy.save_to_collection(options) if proxy.proxy_respond_to?(:save_to_collection)
92
+ end
93
+ end
94
+ end
101
95
  end
102
96
  end
103
97
  end
104
-
105
- require 'mongo_mapper/plugins/associations/proxy'
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Caching
5
+ module InstanceMethods
6
+ def cache_key(*suffixes)
7
+ cache_key = case
8
+ when new?
9
+ "#{self.class.name}/new"
10
+ when timestamp = self[:updated_at]
11
+ "#{self.class.name}/#{id}-#{timestamp.to_s(:number)}"
12
+ else
13
+ "#{self.class.name}/#{id}"
14
+ end
15
+ cache_key += "/#{suffixes.join('/')}" unless suffixes.empty?
16
+ cache_key
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  # Almost all of this callback stuff is pulled directly from ActiveSupport
2
3
  # in the interest of support rails 2 and 3 at the same time and is the
3
4
  # same copyright as rails.
@@ -76,8 +77,19 @@ module MongoMapper
76
77
  result
77
78
  end
78
79
 
79
- def run_callbacks(kind, options = {}, &block)
80
- self.class.send("#{kind}_callback_chain").run(self, options, &block)
80
+ def run_callbacks(kind, options={}, &block)
81
+ callback_chain_method = "#{kind}_callback_chain"
82
+ return unless self.class.respond_to?(callback_chain_method)
83
+ self.class.send(callback_chain_method).run(self, options, &block)
84
+ self.embedded_associations.each do |association|
85
+ if association.one?
86
+ self.send(association.name).run_callbacks(kind, options, &block)
87
+ else
88
+ self.send(association.name).each do |document|
89
+ document.run_callbacks(kind, options, &block)
90
+ end
91
+ end
92
+ end
81
93
  end
82
94
 
83
95
  private
@@ -111,7 +123,7 @@ module MongoMapper
111
123
  new(methods)
112
124
  end
113
125
 
114
- def run(object, options = {}, &terminator)
126
+ def run(object, options={}, &terminator)
115
127
  enumerator = options[:enumerator] || :each
116
128
 
117
129
  unless block_given?
@@ -158,7 +170,7 @@ module MongoMapper
158
170
  class Callback
159
171
  attr_reader :kind, :method, :identifier, :options
160
172
 
161
- def initialize(kind, method, options = {})
173
+ def initialize(kind, method, options={})
162
174
  @kind = kind
163
175
  @method = method
164
176
  @identifier = options[:identifier]
@@ -226,4 +238,4 @@ module MongoMapper
226
238
  end
227
239
  end
228
240
  end
229
- end
241
+ end
@@ -1,11 +1,17 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Clone
4
5
  module InstanceMethods
5
- def clone
6
- clone_attributes = self.attributes
7
- clone_attributes.delete("_id")
8
- self.class.new(clone_attributes)
6
+ def initialize_copy(other)
7
+ @_new = true
8
+ @_destroyed = false
9
+ default_id_value({})
10
+ self.attributes = other.attributes.clone.except(:_id).inject({}) do |hash, entry|
11
+ key, value = entry
12
+ hash[key] = value.duplicable? ? value.clone : value
13
+ hash
14
+ end
9
15
  end
10
16
  end
11
17
  end
@@ -1,14 +1,15 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Descendants
4
5
  module ClassMethods
5
6
  def inherited(descendant)
6
- (@descendants ||= []) << descendant
7
+ descendants << descendant
7
8
  super
8
9
  end
9
10
 
10
11
  def descendants
11
- @descendants
12
+ @descendants ||= []
12
13
  end
13
14
  end
14
15
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Dirty
@@ -0,0 +1,41 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Document
5
+ module ClassMethods
6
+ def embeddable?
7
+ false
8
+ end
9
+ end
10
+
11
+ module InstanceMethods
12
+ def new?
13
+ @_new
14
+ end
15
+
16
+ def destroyed?
17
+ @_destroyed == true
18
+ end
19
+
20
+ def reload
21
+ if doc = collection.find_one(:_id => id)
22
+ tap do |instance|
23
+ instance.class.associations.each_key do |association_name|
24
+ send(association_name).reset if respond_to?(association_name)
25
+ end
26
+ instance.attributes = doc
27
+ end
28
+ else
29
+ raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
30
+ end
31
+ end
32
+
33
+ # Used by embedded docs to find root easily without if/respond_to? stuff.
34
+ # Documents are always root documents.
35
+ def _root_document
36
+ self
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end