lookout-mongo_mapper 0.11.3

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 (176) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +33 -0
  3. data/UPGRADES +26 -0
  4. data/bin/mmconsole +59 -0
  5. data/examples/attr_accessible.rb +22 -0
  6. data/examples/attr_protected.rb +22 -0
  7. data/examples/cache_key.rb +24 -0
  8. data/examples/custom_types.rb +24 -0
  9. data/examples/identity_map.rb +33 -0
  10. data/examples/identity_map/automatic.rb +2 -0
  11. data/examples/keys.rb +40 -0
  12. data/examples/modifiers/set.rb +25 -0
  13. data/examples/plugins.rb +38 -0
  14. data/examples/querying.rb +35 -0
  15. data/examples/safe.rb +43 -0
  16. data/examples/scopes.rb +52 -0
  17. data/examples/validating/embedded_docs.rb +29 -0
  18. data/lib/mongo_mapper.rb +94 -0
  19. data/lib/mongo_mapper/connection.rb +96 -0
  20. data/lib/mongo_mapper/document.rb +42 -0
  21. data/lib/mongo_mapper/embedded_document.rb +32 -0
  22. data/lib/mongo_mapper/exceptions.rb +30 -0
  23. data/lib/mongo_mapper/extensions/array.rb +19 -0
  24. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  25. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  26. data/lib/mongo_mapper/extensions/date.rb +25 -0
  27. data/lib/mongo_mapper/extensions/float.rb +14 -0
  28. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  29. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  30. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  31. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  32. data/lib/mongo_mapper/extensions/object.rb +26 -0
  33. data/lib/mongo_mapper/extensions/object_id.rb +32 -0
  34. data/lib/mongo_mapper/extensions/set.rb +20 -0
  35. data/lib/mongo_mapper/extensions/string.rb +18 -0
  36. data/lib/mongo_mapper/extensions/time.rb +28 -0
  37. data/lib/mongo_mapper/locale/en.yml +5 -0
  38. data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
  39. data/lib/mongo_mapper/plugins.rb +22 -0
  40. data/lib/mongo_mapper/plugins/accessible.rb +52 -0
  41. data/lib/mongo_mapper/plugins/active_model.rb +18 -0
  42. data/lib/mongo_mapper/plugins/associations.rb +90 -0
  43. data/lib/mongo_mapper/plugins/associations/base.rb +92 -0
  44. data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +54 -0
  45. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +34 -0
  46. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +52 -0
  47. data/lib/mongo_mapper/plugins/associations/collection.rb +27 -0
  48. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +44 -0
  49. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +133 -0
  50. data/lib/mongo_mapper/plugins/associations/many_association.rb +63 -0
  51. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  52. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +118 -0
  53. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  54. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  55. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  56. data/lib/mongo_mapper/plugins/associations/one_as_proxy.rb +22 -0
  57. data/lib/mongo_mapper/plugins/associations/one_association.rb +48 -0
  58. data/lib/mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +30 -0
  59. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +44 -0
  60. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +95 -0
  61. data/lib/mongo_mapper/plugins/associations/proxy.rb +134 -0
  62. data/lib/mongo_mapper/plugins/associations/single_association.rb +46 -0
  63. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  64. data/lib/mongo_mapper/plugins/callbacks.rb +29 -0
  65. data/lib/mongo_mapper/plugins/clone.rb +22 -0
  66. data/lib/mongo_mapper/plugins/dirty.rb +60 -0
  67. data/lib/mongo_mapper/plugins/document.rb +41 -0
  68. data/lib/mongo_mapper/plugins/dynamic_querying.rb +45 -0
  69. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  70. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +56 -0
  71. data/lib/mongo_mapper/plugins/embedded_document.rb +53 -0
  72. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  73. data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
  74. data/lib/mongo_mapper/plugins/indexes.rb +13 -0
  75. data/lib/mongo_mapper/plugins/inspect.rb +16 -0
  76. data/lib/mongo_mapper/plugins/keys.rb +313 -0
  77. data/lib/mongo_mapper/plugins/keys/key.rb +61 -0
  78. data/lib/mongo_mapper/plugins/logger.rb +18 -0
  79. data/lib/mongo_mapper/plugins/modifiers.rb +134 -0
  80. data/lib/mongo_mapper/plugins/pagination.rb +16 -0
  81. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  82. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  83. data/lib/mongo_mapper/plugins/querying.rb +165 -0
  84. data/lib/mongo_mapper/plugins/querying/decorator.rb +36 -0
  85. data/lib/mongo_mapper/plugins/rails.rb +58 -0
  86. data/lib/mongo_mapper/plugins/rails/active_record_association_adapter.rb +33 -0
  87. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  88. data/lib/mongo_mapper/plugins/sci.rb +36 -0
  89. data/lib/mongo_mapper/plugins/scopes.rb +27 -0
  90. data/lib/mongo_mapper/plugins/serialization.rb +109 -0
  91. data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
  92. data/lib/mongo_mapper/plugins/touch.rb +18 -0
  93. data/lib/mongo_mapper/plugins/userstamps.rb +18 -0
  94. data/lib/mongo_mapper/plugins/validations.rb +86 -0
  95. data/lib/mongo_mapper/railtie.rb +48 -0
  96. data/lib/mongo_mapper/railtie/database.rake +65 -0
  97. data/lib/mongo_mapper/translation.rb +10 -0
  98. data/lib/mongo_mapper/version.rb +4 -0
  99. data/lib/rails/generators/mongo_mapper/config/config_generator.rb +24 -0
  100. data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +18 -0
  101. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +23 -0
  102. data/lib/rails/generators/mongo_mapper/model/templates/model.rb +13 -0
  103. data/test/_NOTE_ON_TESTING +1 -0
  104. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +64 -0
  105. data/test/functional/associations/test_belongs_to_proxy.rb +238 -0
  106. data/test/functional/associations/test_in_array_proxy.rb +349 -0
  107. data/test/functional/associations/test_many_documents_as_proxy.rb +231 -0
  108. data/test/functional/associations/test_many_documents_proxy.rb +866 -0
  109. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +239 -0
  110. data/test/functional/associations/test_many_embedded_proxy.rb +289 -0
  111. data/test/functional/associations/test_many_polymorphic_proxy.rb +303 -0
  112. data/test/functional/associations/test_one_as_proxy.rb +491 -0
  113. data/test/functional/associations/test_one_embedded_polymorphic_proxy.rb +208 -0
  114. data/test/functional/associations/test_one_embedded_proxy.rb +100 -0
  115. data/test/functional/associations/test_one_proxy.rb +383 -0
  116. data/test/functional/test_accessible.rb +198 -0
  117. data/test/functional/test_associations.rb +46 -0
  118. data/test/functional/test_binary.rb +27 -0
  119. data/test/functional/test_caching.rb +77 -0
  120. data/test/functional/test_callbacks.rb +232 -0
  121. data/test/functional/test_dirty.rb +301 -0
  122. data/test/functional/test_document.rb +282 -0
  123. data/test/functional/test_dynamic_querying.rb +75 -0
  124. data/test/functional/test_embedded_document.rb +288 -0
  125. data/test/functional/test_equality.rb +20 -0
  126. data/test/functional/test_identity_map.rb +513 -0
  127. data/test/functional/test_indexes.rb +50 -0
  128. data/test/functional/test_logger.rb +20 -0
  129. data/test/functional/test_modifiers.rb +537 -0
  130. data/test/functional/test_pagination.rb +91 -0
  131. data/test/functional/test_protected.rb +201 -0
  132. data/test/functional/test_querying.rb +935 -0
  133. data/test/functional/test_safe.rb +76 -0
  134. data/test/functional/test_sci.rb +240 -0
  135. data/test/functional/test_scopes.rb +171 -0
  136. data/test/functional/test_timestamps.rb +62 -0
  137. data/test/functional/test_touch.rb +125 -0
  138. data/test/functional/test_userstamps.rb +44 -0
  139. data/test/functional/test_validations.rb +414 -0
  140. data/test/models.rb +261 -0
  141. data/test/support/railtie.rb +4 -0
  142. data/test/support/railtie/autoloaded.rb +2 -0
  143. data/test/support/railtie/not_autoloaded.rb +3 -0
  144. data/test/support/railtie/parent.rb +3 -0
  145. data/test/test_active_model_lint.rb +18 -0
  146. data/test/test_helper.rb +93 -0
  147. data/test/unit/associations/test_base.rb +146 -0
  148. data/test/unit/associations/test_belongs_to_association.rb +29 -0
  149. data/test/unit/associations/test_many_association.rb +63 -0
  150. data/test/unit/associations/test_one_association.rb +47 -0
  151. data/test/unit/associations/test_proxy.rb +100 -0
  152. data/test/unit/serializers/test_json_serializer.rb +216 -0
  153. data/test/unit/serializers/test_xml_serializer.rb +196 -0
  154. data/test/unit/test_clone.rb +69 -0
  155. data/test/unit/test_document.rb +249 -0
  156. data/test/unit/test_dynamic_finder.rb +125 -0
  157. data/test/unit/test_embedded_document.rb +682 -0
  158. data/test/unit/test_equality.rb +38 -0
  159. data/test/unit/test_exceptions.rb +12 -0
  160. data/test/unit/test_extensions.rb +380 -0
  161. data/test/unit/test_identity_map_middleware.rb +34 -0
  162. data/test/unit/test_inspect.rb +47 -0
  163. data/test/unit/test_key.rb +205 -0
  164. data/test/unit/test_keys.rb +65 -0
  165. data/test/unit/test_mongo_mapper.rb +143 -0
  166. data/test/unit/test_pagination.rb +11 -0
  167. data/test/unit/test_plugins.rb +89 -0
  168. data/test/unit/test_rails.rb +183 -0
  169. data/test/unit/test_rails_compatibility.rb +38 -0
  170. data/test/unit/test_rails_reflect_on_association.rb +118 -0
  171. data/test/unit/test_railtie.rb +66 -0
  172. data/test/unit/test_serialization.rb +166 -0
  173. data/test/unit/test_time_zones.rb +44 -0
  174. data/test/unit/test_translation.rb +27 -0
  175. data/test/unit/test_validations.rb +562 -0
  176. metadata +285 -0
@@ -0,0 +1,198 @@
1
+ require 'test_helper'
2
+
3
+ class AccessibleTest < Test::Unit::TestCase
4
+ context 'A document with accessible attributes' do
5
+ setup do
6
+ @doc_class = Doc do
7
+ key :name, String
8
+ key :admin, Boolean, :default => false
9
+
10
+ attr_accessible :name
11
+ end
12
+
13
+ @doc = @doc_class.create(:name => 'Steve Sloan')
14
+ end
15
+
16
+ should 'have accessible attributes class method' do
17
+ @doc_class.accessible_attributes.should == [:name].to_set
18
+ end
19
+
20
+ should "default accessible attributes to nil" do
21
+ Doc().accessible_attributes.should be_nil
22
+ end
23
+
24
+ should "have accessible_attributes instance method" do
25
+ @doc.accessible_attributes.should equal(@doc_class.accessible_attributes)
26
+ end
27
+
28
+ should "raise error if there are protected attributes" do
29
+ doc = Doc('Post')
30
+ doc.attr_protected :admin
31
+ lambda { doc.attr_accessible :name }.
32
+ should raise_error(/Declare either attr_protected or attr_accessible for Post/)
33
+ end
34
+
35
+ should "know if using accessible attributes" do
36
+ @doc_class.accessible_attributes?.should be(true)
37
+ Doc().accessible_attributes?.should be(false)
38
+ end
39
+
40
+ should "assign inaccessible attribute through accessor" do
41
+ @doc.admin = true
42
+ @doc.admin.should be_true
43
+ end
44
+
45
+ should "ignore inaccessible attribute on #initialize" do
46
+ doc = @doc_class.new(:name => 'John', :admin => true)
47
+ doc.admin.should be_false
48
+ doc.name.should == 'John'
49
+ end
50
+
51
+ should "not ignore inaccessible attributes on #initialize from the database" do
52
+ doc = @doc_class.new(:name => 'John')
53
+ doc.admin = true
54
+ doc.save!
55
+
56
+ doc = @doc_class.first(:name => 'John')
57
+ doc.admin.should be_true
58
+ doc.name.should == 'John'
59
+ end
60
+
61
+ should "not ignore inaccessible attributes on #reload" do
62
+ doc = @doc_class.new(:name => 'John')
63
+ doc.admin = true
64
+ doc.save!
65
+
66
+ doc.reload
67
+ doc.admin.should be_true
68
+ doc.name.should == 'John'
69
+ end
70
+
71
+ should "not ignore inaccessible attribute on #update_attribute" do
72
+ @doc.update_attribute('admin', true)
73
+ @doc.admin.should be_true
74
+ end
75
+
76
+ should "ignore inaccessible attribute on #update_attributes" do
77
+ @doc.update_attributes(:name => 'Ren Hoek', :admin => true)
78
+ @doc.name.should == 'Ren Hoek'
79
+ @doc.admin.should be_false
80
+ end
81
+
82
+ should "ignore inaccessible attribute on #update_attributes!" do
83
+ @doc.update_attributes!(:name => 'Stimpson J. Cat', :admin => true)
84
+ @doc.name.should == 'Stimpson J. Cat'
85
+ @doc.admin.should be_false
86
+ end
87
+
88
+ should "ignore inaccessible attribute on #attributes=" do
89
+ @doc.attributes = {:name => 'Ren Hoek', :admin => true}
90
+ @doc.name.should == 'Ren Hoek'
91
+ @doc.admin.should be_false
92
+ end
93
+
94
+ should "be indifferent to whether the accessible keys are strings or symbols" do
95
+ @doc.update_attributes!("name" => 'Stimpson J. Cat', "admin" => true)
96
+ @doc.name.should == 'Stimpson J. Cat'
97
+ @doc.admin.should be_false
98
+ end
99
+
100
+ should "accept nil as constructor's argument without raising exception" do
101
+ lambda { @doc_class.new(nil) }.should_not raise_error
102
+ end
103
+
104
+ should "ignore all attributes if called with no args" do
105
+ @doc_class = Doc do
106
+ key :name
107
+ attr_accessible
108
+ end
109
+
110
+ @doc_class.new(:name => 'Steve Sloan').name.should be_nil
111
+ end
112
+ end
113
+
114
+ context "Single collection inherited accessible attributes" do
115
+ setup do
116
+ class ::GrandParent
117
+ include MongoMapper::Document
118
+ attr_accessible :name
119
+ key :name, String
120
+ key :site_id, ObjectId
121
+ end
122
+ GrandParent.collection.remove
123
+
124
+ class ::Child < ::GrandParent
125
+ attr_accessible :position
126
+ key :position, Integer
127
+ end
128
+
129
+ class ::GrandChild < ::Child; end
130
+
131
+ class ::OtherChild < ::GrandParent
132
+ attr_accessible :favorite_color
133
+ key :favorite_color, String
134
+ key :blog_id, ObjectId
135
+ end
136
+ end
137
+
138
+ teardown do
139
+ Object.send :remove_const, 'GrandParent' if defined?(::GrandParent)
140
+ Object.send :remove_const, 'Child' if defined?(::Child)
141
+ Object.send :remove_const, 'GrandChild' if defined?(::GrandChild)
142
+ Object.send :remove_const, 'OtherChild' if defined?(::OtherChild)
143
+ end
144
+
145
+ should "share keys down the inheritance trail" do
146
+ GrandParent.accessible_attributes.should == [:name].to_set
147
+ Child.accessible_attributes.should == [:name, :position].to_set
148
+ GrandChild.accessible_attributes.should == [:name, :position].to_set
149
+ OtherChild.accessible_attributes.should == [:name, :favorite_color].to_set
150
+ end
151
+ end
152
+
153
+ context "An embedded document with accessible attributes" do
154
+ setup do
155
+ @doc_class = Doc('Project')
156
+ @edoc_class = EDoc('Person') do
157
+ key :name, String
158
+ key :admin, Boolean, :default => false
159
+
160
+ attr_accessible :name
161
+ end
162
+ @doc_class.many :people, :class => @edoc_class
163
+
164
+ @doc = @doc_class.create(:title => 'MongoMapper')
165
+ @edoc = @edoc_class.new(:name => 'Steve Sloan')
166
+ @doc.people << @edoc
167
+ end
168
+
169
+ should "have accessible attributes class method" do
170
+ @edoc_class.accessible_attributes.should == [:name].to_set
171
+ end
172
+
173
+ should "default accessible attributes to nil" do
174
+ EDoc().accessible_attributes.should be_nil
175
+ end
176
+
177
+ should "have accessible attributes instance method" do
178
+ @edoc.accessible_attributes.should equal(@edoc_class.accessible_attributes)
179
+ end
180
+
181
+ should "assign inaccessible attribute through accessor" do
182
+ @edoc.admin = true
183
+ @edoc.admin.should be_true
184
+ end
185
+
186
+ should "ignore inaccessible attribute on #update_attributes" do
187
+ @edoc.update_attributes(:name => 'Ren Hoek', :admin => true)
188
+ @edoc.name.should == 'Ren Hoek'
189
+ @edoc.admin.should be_false
190
+ end
191
+
192
+ should "ignore inaccessible attribute on #update_attributes!" do
193
+ @edoc.update_attributes!(:name => 'Stimpson J. Cat', :admin => true)
194
+ @edoc.name.should == 'Stimpson J. Cat'
195
+ @edoc.admin.should be_false
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class AssociationsTest < Test::Unit::TestCase
5
+ should "allow changing class names" do
6
+ class AwesomeUser
7
+ include MongoMapper::Document
8
+
9
+ many :posts, :class_name => 'AssociationsTest::AwesomePost', :foreign_key => :creator_id
10
+ end
11
+ AwesomeUser.collection.remove
12
+
13
+ class AwesomeTag
14
+ include MongoMapper::EmbeddedDocument
15
+
16
+ key :name, String
17
+ key :post_id, ObjectId
18
+
19
+ belongs_to :post, :class_name => 'AssociationsTest::AwesomeUser'
20
+ end
21
+
22
+ class AwesomePost
23
+ include MongoMapper::Document
24
+
25
+ key :creator_id, ObjectId
26
+
27
+ belongs_to :creator, :class_name => 'AssociationsTest::AwesomeUser'
28
+ many :tags, :class_name => 'AssociationsTest::AwesomeTag', :foreign_key => :post_id
29
+ end
30
+
31
+ AwesomeUser.collection.remove
32
+ AwesomePost.collection.remove
33
+
34
+ user = AwesomeUser.create
35
+ tag1 = AwesomeTag.new(:name => 'awesome')
36
+ tag2 = AwesomeTag.new(:name => 'grand')
37
+ post1 = AwesomePost.create(:creator => user, :tags => [tag1])
38
+ post2 = AwesomePost.create(:creator => user, :tags => [tag2])
39
+
40
+ user.reload
41
+ user.posts.should == [post1, post2]
42
+
43
+ post1 = post1.reload
44
+ post1.tags.should == [tag1]
45
+ end
46
+ end
@@ -0,0 +1,27 @@
1
+ require 'test_helper'
2
+
3
+ class BinaryTest < Test::Unit::TestCase
4
+ should "serialize and deserialize correctly" do
5
+ klass = Doc do
6
+ key :contents, Binary
7
+ end
8
+
9
+ doc = klass.new(:contents => '010101')
10
+ doc.save
11
+
12
+ doc = doc.reload
13
+ doc.contents.to_s.should == BSON::Binary.new('010101').to_s
14
+ end
15
+
16
+ context "Saving a document with a blank binary value" do
17
+ setup do
18
+ @document = Doc do
19
+ key :file, Binary
20
+ end
21
+ end
22
+
23
+ should "not fail" do
24
+ assert_nothing_raised { @document.new(:file => nil).save }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,77 @@
1
+ require 'test_helper'
2
+
3
+ class CachingTest < Test::Unit::TestCase
4
+ context "Caching" do
5
+ setup do
6
+ @klass = Class.new do
7
+ extend MongoMapper::Plugins
8
+ plugin MongoMapper::Plugins::Caching
9
+ end
10
+ @klass.stubs(:name).returns('Post')
11
+ @klass.any_instance.stubs(:persisted?).returns(true)
12
+ @klass.any_instance.stubs(:[]).returns(nil)
13
+ @klass.any_instance.stubs(:[]=).returns(nil)
14
+ end
15
+
16
+ context "new" do
17
+ setup do
18
+ @doc = @klass.new
19
+ @doc.stubs(:persisted?).returns(false)
20
+ end
21
+
22
+ should "be class/new" do
23
+ @doc.cache_key.should == 'Post/new'
24
+ end
25
+
26
+ should "work with suffix" do
27
+ @doc.cache_key(:foo).
28
+ should == 'Post/new/foo'
29
+
30
+ @doc.cache_key(:foo, :bar).
31
+ should == 'Post/new/foo/bar'
32
+ end
33
+ end
34
+
35
+ context "not new" do
36
+ setup do
37
+ @object_id = BSON::ObjectId.new
38
+ @doc = @klass.new
39
+ @doc.stubs(:persisted).returns(true)
40
+ @doc.stubs(:id).returns(@object_id)
41
+ end
42
+
43
+ context "with updated_at" do
44
+ setup do
45
+ time = Time.utc(2010, 6, 20, 8, 10, 7)
46
+ @doc.stubs(:[]).with(:updated_at).returns(time)
47
+ end
48
+
49
+ should "be class/id-timestamp" do
50
+ @doc.cache_key.should == "Post/#{@object_id}-20100620081007"
51
+ end
52
+
53
+ should "work with suffix" do
54
+ @doc.cache_key(:foo).
55
+ should == "Post/#{@object_id}-20100620081007/foo"
56
+
57
+ @doc.cache_key(:foo, :bar).
58
+ should == "Post/#{@object_id}-20100620081007/foo/bar"
59
+ end
60
+ end
61
+
62
+ context "without updated_at" do
63
+ should "be class/id" do
64
+ @doc.cache_key.should == "Post/#{@object_id}"
65
+ end
66
+
67
+ should "work with suffix" do
68
+ @doc.cache_key(:foo).
69
+ should == "Post/#{@object_id}/foo"
70
+
71
+ @doc.cache_key(:foo, :bar, :baz).
72
+ should == "Post/#{@object_id}/foo/bar/baz"
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,232 @@
1
+ require 'test_helper'
2
+
3
+ module CallbacksSupport
4
+ def self.included base
5
+ base.key :name, String
6
+
7
+ [ :before_validation, :after_validation,
8
+ :before_create, :after_create,
9
+ :before_update, :after_update,
10
+ :before_save, :after_save,
11
+ :before_destroy, :after_destroy
12
+ ].each do |callback|
13
+ base.send(callback) do
14
+ history << callback.to_sym
15
+ end
16
+ end
17
+ end
18
+
19
+ def history
20
+ @history ||= []
21
+ end
22
+
23
+ def clear_history
24
+ embedded_associations.each { |a| self.send(a.name).each(&:clear_history) }
25
+ @history = nil
26
+ end
27
+ end
28
+
29
+ class CallbacksTest < Test::Unit::TestCase
30
+ CreateCallbackOrder = [
31
+ :before_validation,
32
+ :after_validation,
33
+ :before_save,
34
+ :before_create,
35
+ :after_create,
36
+ :after_save
37
+ ]
38
+
39
+ UpdateCallbackOrder = [
40
+ :before_validation,
41
+ :after_validation,
42
+ :before_save,
43
+ :before_update,
44
+ :after_update,
45
+ :after_save
46
+ ]
47
+
48
+ context "Defining and running callbacks on documents" do
49
+ setup do
50
+ @document = Doc { include CallbacksSupport }
51
+ end
52
+
53
+ should "get the order right for creating documents" do
54
+ doc = @document.create(:name => 'John Nunemaker')
55
+ doc.history.should == CreateCallbackOrder
56
+ end
57
+
58
+ should "get the order right for updating documents" do
59
+ doc = @document.create(:name => 'John Nunemaker')
60
+ doc.clear_history
61
+ doc.name = 'John'
62
+ doc.save
63
+ doc.history.should == UpdateCallbackOrder
64
+ end
65
+
66
+ should "work for before and after validation" do
67
+ doc = @document.new(:name => 'John Nunemaker')
68
+ doc.valid?
69
+ doc.history.should include(:before_validation)
70
+ doc.history.should include(:after_validation)
71
+ end
72
+
73
+ should "work for before and after create" do
74
+ doc = @document.create(:name => 'John Nunemaker')
75
+ doc.history.should include(:before_create)
76
+ doc.history.should include(:after_create)
77
+ end
78
+
79
+ should "work for before and after update" do
80
+ doc = @document.create(:name => 'John Nunemaker')
81
+ doc.name = 'John Doe'
82
+ doc.save
83
+ doc.history.should include(:before_update)
84
+ doc.history.should include(:after_update)
85
+ end
86
+
87
+ should "work for before and after save" do
88
+ doc = @document.new
89
+ doc.name = 'John Doe'
90
+ doc.save
91
+ doc.history.should include(:before_save)
92
+ doc.history.should include(:after_save)
93
+ end
94
+
95
+ should "work for before and after destroy" do
96
+ doc = @document.create(:name => 'John Nunemaker')
97
+ doc.destroy
98
+ doc.history.should include(:before_destroy)
99
+ doc.history.should include(:after_destroy)
100
+ end
101
+ end
102
+
103
+ context "Defining and running callbacks on many embedded documents" do
104
+ setup do
105
+ @root_class = Doc { include CallbacksSupport }
106
+ @child_class = EDoc { include CallbacksSupport }
107
+ @grand_child_class = EDoc { include CallbacksSupport }
108
+
109
+ @root_class.many :children, :class => @child_class
110
+ @child_class.many :children, :class => @grand_child_class
111
+ end
112
+
113
+ should "get the order right based on root document creation" do
114
+ grand = @grand_child_class.new(:name => 'Grand Child')
115
+ child = @child_class.new(:name => 'Child', :children => [grand])
116
+ root = @root_class.create(:name => 'Parent', :children => [child])
117
+
118
+ root.children.first.history.should == CreateCallbackOrder
119
+ root.children.first.children.first.history.should == CreateCallbackOrder
120
+ end
121
+
122
+ should "get the order right based on root document updating" do
123
+ grand = @grand_child_class.new(:name => 'Grand Child')
124
+ child = @child_class.new(:name => 'Child', :children => [grand])
125
+ root = @root_class.create(:name => 'Parent', :children => [child])
126
+ root.clear_history
127
+ root.update_attributes(:name => 'Updated Parent')
128
+
129
+ root.children.first.history.should == UpdateCallbackOrder
130
+ root.children.first.children.first.history.should == UpdateCallbackOrder
131
+ end
132
+
133
+ should "work for before and after destroy" do
134
+ grand = @grand_child_class.new(:name => 'Grand Child')
135
+ child = @child_class.new(:name => 'Child', :children => [grand])
136
+ root = @root_class.create(:name => 'Parent', :children => [child])
137
+ root.destroy
138
+ child = root.children.first
139
+ child.history.should include(:before_destroy)
140
+ child.history.should include(:after_destroy)
141
+
142
+ grand = root.children.first.children.first
143
+ grand.history.should include(:before_destroy)
144
+ grand.history.should include(:after_destroy)
145
+ end
146
+
147
+ should "not attempt to run callback defined on root that is not defined on embedded association" do
148
+ @root_class.define_callbacks :after_publish
149
+ @root_class.after_save { |d| d.run_callbacks(:after_publish) }
150
+
151
+ assert_nothing_raised do
152
+ child = @child_class.new(:name => 'Child')
153
+ root = @root_class.create(:name => 'Parent', :children => [child])
154
+ child.history.should_not include(:after_publish)
155
+ end
156
+ end
157
+ end
158
+
159
+ context "Turning embedded callbacks off" do
160
+ setup do
161
+ @root_class = Doc { include CallbacksSupport; embedded_callbacks_off }
162
+ @child_class = EDoc { include CallbacksSupport; embedded_callbacks_off }
163
+ @grand_child_class = EDoc { include CallbacksSupport; embedded_callbacks_off }
164
+
165
+ @root_class.many :children, :class => @child_class
166
+ @child_class.many :children, :class => @grand_child_class
167
+
168
+ @root_class.many :children, :class => @child_class
169
+ @child_class.many :children, :class => @grand_child_class
170
+ end
171
+
172
+ should "not run create callbacks" do
173
+ grand = @grand_child_class.new(:name => 'Grand Child')
174
+ child = @child_class.new(:name => 'Child', :children => [grand])
175
+ root = @root_class.create(:name => 'Parent', :children => [child])
176
+
177
+ root.children.first.history.should == []
178
+ root.children.first.children.first.history.should == []
179
+ end
180
+
181
+ should "not run update callbacks" do
182
+ grand = @grand_child_class.new(:name => 'Grand Child')
183
+ child = @child_class.new(:name => 'Child', :children => [grand])
184
+ root = @root_class.create(:name => 'Parent', :children => [child])
185
+ root.clear_history
186
+ root.update_attributes(:name => 'Updated Parent')
187
+
188
+ root.children.first.history.should == []
189
+ root.children.first.children.first.history.should == []
190
+ end
191
+
192
+ should "not run destroy callbacks" do
193
+ grand = @grand_child_class.new(:name => 'Grand Child')
194
+ child = @child_class.new(:name => 'Child', :children => [grand])
195
+ root = @root_class.create(:name => 'Parent', :children => [child])
196
+ root.destroy
197
+ child = root.children.first
198
+ child.history.should == []
199
+
200
+ grand = root.children.first.children.first
201
+ grand.history.should == []
202
+ end
203
+ end
204
+
205
+ context "Running validation callbacks with conditional execution" do
206
+ setup do
207
+ @document = Doc do
208
+ include CallbacksSupport
209
+ key :message, String
210
+
211
+ before_validation :set_message, :on => 'create'
212
+
213
+ def set_message
214
+ self['message'] = 'Hi!'
215
+ end
216
+ end
217
+ end
218
+
219
+ should 'run callback on create' do
220
+ doc = @document.create
221
+ doc.history.should include(:before_validation)
222
+ doc.message.should == 'Hi!'
223
+ end
224
+
225
+ should 'skip callback on update' do
226
+ doc = @document.create
227
+ doc.message = 'Ho!'
228
+ doc.save
229
+ doc.message.should == 'Ho!'
230
+ end
231
+ end
232
+ end