mongo_mapper-unstable 2010.3.8 → 2010.06.23

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 (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