mongoid-locomotive 2.0.0.beta9

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 (274) hide show
  1. data/MIT_LICENSE +20 -0
  2. data/README.rdoc +47 -0
  3. data/lib/mongoid.rb +141 -0
  4. data/lib/mongoid/associations.rb +306 -0
  5. data/lib/mongoid/associations/embedded_in.rb +74 -0
  6. data/lib/mongoid/associations/embeds_many.rb +280 -0
  7. data/lib/mongoid/associations/embeds_one.rb +97 -0
  8. data/lib/mongoid/associations/foreign_key.rb +35 -0
  9. data/lib/mongoid/associations/meta_data.rb +38 -0
  10. data/lib/mongoid/associations/options.rb +62 -0
  11. data/lib/mongoid/associations/proxy.rb +33 -0
  12. data/lib/mongoid/associations/referenced_in.rb +59 -0
  13. data/lib/mongoid/associations/references_many.rb +245 -0
  14. data/lib/mongoid/associations/references_many_as_array.rb +78 -0
  15. data/lib/mongoid/associations/references_one.rb +99 -0
  16. data/lib/mongoid/atomicity.rb +55 -0
  17. data/lib/mongoid/attributes.rb +242 -0
  18. data/lib/mongoid/callbacks.rb +21 -0
  19. data/lib/mongoid/collection.rb +120 -0
  20. data/lib/mongoid/collections.rb +71 -0
  21. data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
  22. data/lib/mongoid/collections/master.rb +29 -0
  23. data/lib/mongoid/collections/operations.rb +41 -0
  24. data/lib/mongoid/collections/slaves.rb +45 -0
  25. data/lib/mongoid/components.rb +34 -0
  26. data/lib/mongoid/config.rb +263 -0
  27. data/lib/mongoid/contexts.rb +24 -0
  28. data/lib/mongoid/contexts/enumerable.rb +156 -0
  29. data/lib/mongoid/contexts/ids.rb +25 -0
  30. data/lib/mongoid/contexts/mongo.rb +285 -0
  31. data/lib/mongoid/contexts/paging.rb +50 -0
  32. data/lib/mongoid/criteria.rb +248 -0
  33. data/lib/mongoid/criterion/complex.rb +21 -0
  34. data/lib/mongoid/criterion/exclusion.rb +65 -0
  35. data/lib/mongoid/criterion/inclusion.rb +110 -0
  36. data/lib/mongoid/criterion/optional.rb +189 -0
  37. data/lib/mongoid/cursor.rb +81 -0
  38. data/lib/mongoid/deprecation.rb +21 -0
  39. data/lib/mongoid/dirty.rb +252 -0
  40. data/lib/mongoid/document.rb +210 -0
  41. data/lib/mongoid/errors.rb +131 -0
  42. data/lib/mongoid/extensions.rb +115 -0
  43. data/lib/mongoid/extensions/array/accessors.rb +17 -0
  44. data/lib/mongoid/extensions/array/assimilation.rb +26 -0
  45. data/lib/mongoid/extensions/array/conversions.rb +23 -0
  46. data/lib/mongoid/extensions/array/parentization.rb +13 -0
  47. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  48. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  49. data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
  50. data/lib/mongoid/extensions/date/conversions.rb +24 -0
  51. data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
  52. data/lib/mongoid/extensions/false_class/equality.rb +13 -0
  53. data/lib/mongoid/extensions/float/conversions.rb +20 -0
  54. data/lib/mongoid/extensions/hash/accessors.rb +42 -0
  55. data/lib/mongoid/extensions/hash/assimilation.rb +40 -0
  56. data/lib/mongoid/extensions/hash/conversions.rb +42 -0
  57. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  58. data/lib/mongoid/extensions/hash/scoping.rb +12 -0
  59. data/lib/mongoid/extensions/integer/conversions.rb +20 -0
  60. data/lib/mongoid/extensions/nil/assimilation.rb +17 -0
  61. data/lib/mongoid/extensions/object/conversions.rb +21 -0
  62. data/lib/mongoid/extensions/objectid/conversions.rb +15 -0
  63. data/lib/mongoid/extensions/proc/scoping.rb +12 -0
  64. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  65. data/lib/mongoid/extensions/string/conversions.rb +15 -0
  66. data/lib/mongoid/extensions/string/inflections.rb +97 -0
  67. data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
  68. data/lib/mongoid/extensions/time_conversions.rb +35 -0
  69. data/lib/mongoid/extensions/true_class/equality.rb +13 -0
  70. data/lib/mongoid/extras.rb +61 -0
  71. data/lib/mongoid/factory.rb +20 -0
  72. data/lib/mongoid/field.rb +83 -0
  73. data/lib/mongoid/fields.rb +62 -0
  74. data/lib/mongoid/finders.rb +145 -0
  75. data/lib/mongoid/hierarchy.rb +74 -0
  76. data/lib/mongoid/identity.rb +47 -0
  77. data/lib/mongoid/indexes.rb +27 -0
  78. data/lib/mongoid/javascript.rb +21 -0
  79. data/lib/mongoid/javascript/functions.yml +37 -0
  80. data/lib/mongoid/logger.rb +19 -0
  81. data/lib/mongoid/matchers.rb +35 -0
  82. data/lib/mongoid/matchers/all.rb +11 -0
  83. data/lib/mongoid/matchers/default.rb +26 -0
  84. data/lib/mongoid/matchers/exists.rb +13 -0
  85. data/lib/mongoid/matchers/gt.rb +11 -0
  86. data/lib/mongoid/matchers/gte.rb +11 -0
  87. data/lib/mongoid/matchers/in.rb +11 -0
  88. data/lib/mongoid/matchers/lt.rb +11 -0
  89. data/lib/mongoid/matchers/lte.rb +11 -0
  90. data/lib/mongoid/matchers/ne.rb +11 -0
  91. data/lib/mongoid/matchers/nin.rb +11 -0
  92. data/lib/mongoid/matchers/size.rb +11 -0
  93. data/lib/mongoid/memoization.rb +33 -0
  94. data/lib/mongoid/named_scope.rb +37 -0
  95. data/lib/mongoid/paranoia.rb +106 -0
  96. data/lib/mongoid/paths.rb +61 -0
  97. data/lib/mongoid/persistence.rb +216 -0
  98. data/lib/mongoid/persistence/command.rb +39 -0
  99. data/lib/mongoid/persistence/insert.rb +48 -0
  100. data/lib/mongoid/persistence/insert_embedded.rb +44 -0
  101. data/lib/mongoid/persistence/remove.rb +39 -0
  102. data/lib/mongoid/persistence/remove_all.rb +38 -0
  103. data/lib/mongoid/persistence/remove_embedded.rb +50 -0
  104. data/lib/mongoid/persistence/update.rb +71 -0
  105. data/lib/mongoid/railtie.rb +67 -0
  106. data/lib/mongoid/railties/database.rake +60 -0
  107. data/lib/mongoid/scope.rb +75 -0
  108. data/lib/mongoid/state.rb +32 -0
  109. data/lib/mongoid/timestamps.rb +27 -0
  110. data/lib/mongoid/validations.rb +51 -0
  111. data/lib/mongoid/validations/associated.rb +32 -0
  112. data/lib/mongoid/validations/locale/en.yml +5 -0
  113. data/lib/mongoid/validations/uniqueness.rb +56 -0
  114. data/lib/mongoid/version.rb +4 -0
  115. data/lib/mongoid/versioning.rb +26 -0
  116. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  117. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +24 -0
  118. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  119. data/lib/rails/generators/mongoid/model/templates/model.rb +15 -0
  120. data/lib/rails/generators/mongoid_generator.rb +61 -0
  121. data/spec/integration/mongoid/association_attributes_spec.rb +71 -0
  122. data/spec/integration/mongoid/associations_spec.rb +768 -0
  123. data/spec/integration/mongoid/attributes_spec.rb +59 -0
  124. data/spec/integration/mongoid/callback_spec.rb +33 -0
  125. data/spec/integration/mongoid/contexts/enumerable_spec.rb +33 -0
  126. data/spec/integration/mongoid/criteria_spec.rb +281 -0
  127. data/spec/integration/mongoid/dirty_spec.rb +85 -0
  128. data/spec/integration/mongoid/document_spec.rb +741 -0
  129. data/spec/integration/mongoid/extensions_spec.rb +22 -0
  130. data/spec/integration/mongoid/finders_spec.rb +119 -0
  131. data/spec/integration/mongoid/inheritance_spec.rb +171 -0
  132. data/spec/integration/mongoid/named_scope_spec.rb +58 -0
  133. data/spec/integration/mongoid/paranoia_spec.rb +44 -0
  134. data/spec/integration/mongoid/persistence/update_spec.rb +46 -0
  135. data/spec/integration/mongoid/persistence_spec.rb +311 -0
  136. data/spec/integration/mongoid/validations/uniqueness_spec.rb +206 -0
  137. data/spec/models/account.rb +5 -0
  138. data/spec/models/address.rb +40 -0
  139. data/spec/models/agent.rb +7 -0
  140. data/spec/models/animal.rb +15 -0
  141. data/spec/models/answer.rb +4 -0
  142. data/spec/models/callbacks.rb +47 -0
  143. data/spec/models/category.rb +13 -0
  144. data/spec/models/comment.rb +10 -0
  145. data/spec/models/country_code.rb +6 -0
  146. data/spec/models/employer.rb +5 -0
  147. data/spec/models/favorite.rb +8 -0
  148. data/spec/models/game.rb +9 -0
  149. data/spec/models/inheritance.rb +72 -0
  150. data/spec/models/location.rb +5 -0
  151. data/spec/models/login.rb +6 -0
  152. data/spec/models/mixed_drink.rb +4 -0
  153. data/spec/models/name.rb +13 -0
  154. data/spec/models/namespacing.rb +11 -0
  155. data/spec/models/paranoid_post.rb +18 -0
  156. data/spec/models/parents.rb +32 -0
  157. data/spec/models/patient.rb +15 -0
  158. data/spec/models/person.rb +106 -0
  159. data/spec/models/pet.rb +7 -0
  160. data/spec/models/pet_owner.rb +6 -0
  161. data/spec/models/phone.rb +7 -0
  162. data/spec/models/post.rb +25 -0
  163. data/spec/models/preference.rb +7 -0
  164. data/spec/models/question.rb +8 -0
  165. data/spec/models/survey.rb +6 -0
  166. data/spec/models/translation.rb +5 -0
  167. data/spec/models/user.rb +6 -0
  168. data/spec/models/user_accout.rb +5 -0
  169. data/spec/models/vet_visit.rb +5 -0
  170. data/spec/models/video.rb +5 -0
  171. data/spec/spec_helper.rb +33 -0
  172. data/spec/unit/mongoid/associations/embedded_in_spec.rb +193 -0
  173. data/spec/unit/mongoid/associations/embeds_many_spec.rb +626 -0
  174. data/spec/unit/mongoid/associations/embeds_one_spec.rb +287 -0
  175. data/spec/unit/mongoid/associations/foreign_key_spec.rb +90 -0
  176. data/spec/unit/mongoid/associations/meta_data_spec.rb +110 -0
  177. data/spec/unit/mongoid/associations/options_spec.rb +215 -0
  178. data/spec/unit/mongoid/associations/referenced_in_spec.rb +145 -0
  179. data/spec/unit/mongoid/associations/references_many_as_array_spec.rb +424 -0
  180. data/spec/unit/mongoid/associations/references_many_spec.rb +502 -0
  181. data/spec/unit/mongoid/associations/references_one_spec.rb +204 -0
  182. data/spec/unit/mongoid/associations_spec.rb +688 -0
  183. data/spec/unit/mongoid/atomicity_spec.rb +164 -0
  184. data/spec/unit/mongoid/attributes_spec.rb +646 -0
  185. data/spec/unit/mongoid/callbacks_spec.rb +85 -0
  186. data/spec/unit/mongoid/collection_spec.rb +187 -0
  187. data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
  188. data/spec/unit/mongoid/collections/master_spec.rb +41 -0
  189. data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
  190. data/spec/unit/mongoid/collections_spec.rb +98 -0
  191. data/spec/unit/mongoid/config_spec.rb +298 -0
  192. data/spec/unit/mongoid/contexts/enumerable_spec.rb +447 -0
  193. data/spec/unit/mongoid/contexts/mongo_spec.rb +703 -0
  194. data/spec/unit/mongoid/contexts_spec.rb +25 -0
  195. data/spec/unit/mongoid/criteria_spec.rb +873 -0
  196. data/spec/unit/mongoid/criterion/complex_spec.rb +17 -0
  197. data/spec/unit/mongoid/criterion/exclusion_spec.rb +121 -0
  198. data/spec/unit/mongoid/criterion/inclusion_spec.rb +274 -0
  199. data/spec/unit/mongoid/criterion/optional_spec.rb +483 -0
  200. data/spec/unit/mongoid/cursor_spec.rb +80 -0
  201. data/spec/unit/mongoid/deprecation_spec.rb +24 -0
  202. data/spec/unit/mongoid/dirty_spec.rb +430 -0
  203. data/spec/unit/mongoid/document_spec.rb +623 -0
  204. data/spec/unit/mongoid/errors_spec.rb +154 -0
  205. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
  206. data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
  207. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +52 -0
  208. data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
  209. data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +36 -0
  210. data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +22 -0
  211. data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
  212. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +145 -0
  213. data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +14 -0
  214. data/spec/unit/mongoid/extensions/false_class/equality_spec.rb +35 -0
  215. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
  216. data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
  217. data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +59 -0
  218. data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +35 -0
  219. data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
  220. data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
  221. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
  222. data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +29 -0
  223. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +44 -0
  224. data/spec/unit/mongoid/extensions/objectid/conversions_spec.rb +22 -0
  225. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
  226. data/spec/unit/mongoid/extensions/set/conversions_spec.rb +21 -0
  227. data/spec/unit/mongoid/extensions/string/conversions_spec.rb +28 -0
  228. data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
  229. data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +107 -0
  230. data/spec/unit/mongoid/extensions/time_conversions_spec.rb +186 -0
  231. data/spec/unit/mongoid/extensions/true_class/equality_spec.rb +35 -0
  232. data/spec/unit/mongoid/extras_spec.rb +102 -0
  233. data/spec/unit/mongoid/factory_spec.rb +31 -0
  234. data/spec/unit/mongoid/field_spec.rb +169 -0
  235. data/spec/unit/mongoid/fields_spec.rb +181 -0
  236. data/spec/unit/mongoid/finders_spec.rb +439 -0
  237. data/spec/unit/mongoid/hierarchy_spec.rb +68 -0
  238. data/spec/unit/mongoid/identity_spec.rb +109 -0
  239. data/spec/unit/mongoid/indexes_spec.rb +99 -0
  240. data/spec/unit/mongoid/javascript_spec.rb +48 -0
  241. data/spec/unit/mongoid/logger_spec.rb +38 -0
  242. data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
  243. data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
  244. data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
  245. data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
  246. data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
  247. data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
  248. data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
  249. data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
  250. data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
  251. data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
  252. data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
  253. data/spec/unit/mongoid/matchers_spec.rb +329 -0
  254. data/spec/unit/mongoid/memoization_spec.rb +75 -0
  255. data/spec/unit/mongoid/named_scope_spec.rb +123 -0
  256. data/spec/unit/mongoid/paranoia_spec.rb +108 -0
  257. data/spec/unit/mongoid/paths_spec.rb +272 -0
  258. data/spec/unit/mongoid/persistence/insert_embedded_spec.rb +154 -0
  259. data/spec/unit/mongoid/persistence/insert_spec.rb +144 -0
  260. data/spec/unit/mongoid/persistence/remove_all_spec.rb +82 -0
  261. data/spec/unit/mongoid/persistence/remove_embedded_spec.rb +152 -0
  262. data/spec/unit/mongoid/persistence/remove_spec.rb +89 -0
  263. data/spec/unit/mongoid/persistence/update_spec.rb +177 -0
  264. data/spec/unit/mongoid/persistence_spec.rb +452 -0
  265. data/spec/unit/mongoid/scope_spec.rb +240 -0
  266. data/spec/unit/mongoid/serialization_spec.rb +43 -0
  267. data/spec/unit/mongoid/state_spec.rb +94 -0
  268. data/spec/unit/mongoid/timestamps_spec.rb +30 -0
  269. data/spec/unit/mongoid/validations/associated_spec.rb +103 -0
  270. data/spec/unit/mongoid/validations/uniqueness_spec.rb +201 -0
  271. data/spec/unit/mongoid/validations_spec.rb +43 -0
  272. data/spec/unit/mongoid/versioning_spec.rb +41 -0
  273. data/spec/unit/mongoid_spec.rb +46 -0
  274. metadata +433 -0
@@ -0,0 +1,80 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Cursor do
4
+
5
+ let(:collection) do
6
+ stub.quacks_like(Mongoid::Collection.allocate)
7
+ end
8
+
9
+ let(:mongo_cursor) do
10
+ Mongo::Cursor.allocate.tap do |cursor|
11
+ cursor.stubs(:inspect => "<Mongo::Cursor>")
12
+ end
13
+ end
14
+
15
+ let(:proxy) do
16
+ stub.quacks_like(mongo_cursor)
17
+ end
18
+
19
+ let(:cursor) do
20
+ Mongoid::Cursor.new(Person, collection, proxy)
21
+ end
22
+
23
+ (Mongoid::Cursor::OPERATIONS - [ :timeout ]).each do |name|
24
+
25
+ describe "##{name}" do
26
+
27
+ before do
28
+ proxy.expects(name)
29
+ end
30
+
31
+ it "delegates to the proxy" do
32
+ cursor.send(name)
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "#collection" do
38
+
39
+ it "returns the mongoid collection" do
40
+ cursor.collection.should == collection
41
+ end
42
+ end
43
+
44
+ describe "#each" do
45
+
46
+ before do
47
+ proxy.expects(:each).yields({ "_type" => "Person" })
48
+ end
49
+
50
+ it "yields to the next document" do
51
+ cursor.each do |doc|
52
+ doc.attributes.except(:_id).should == Person.new.attributes.except(:_id)
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "#next_document" do
58
+
59
+ before do
60
+ proxy.expects(:next_document).returns({ "_type" => "Person" })
61
+ end
62
+
63
+ it "returns the next document from the proxied cursor" do
64
+ doc = cursor.next_document
65
+ doc.attributes.except(:_id).should == Person.new.attributes.except(:_id)
66
+ end
67
+ end
68
+
69
+ describe "#to_a" do
70
+
71
+ before do
72
+ proxy.expects(:to_a).returns([{ "_type" => "Person" }])
73
+ end
74
+
75
+ it "converts the proxy cursor to an array of documents" do
76
+ docs = cursor.to_a
77
+ docs[0].attributes.except(:_id).should == Person.new.attributes.except(:_id)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Deprecation do
4
+
5
+ let(:logger) do
6
+ stub.quacks_like(Logger.allocate)
7
+ end
8
+
9
+ before do
10
+ Mongoid::Logger.expects(:new).returns(logger)
11
+ end
12
+
13
+ describe "#alert" do
14
+
15
+ let(:deprecation) do
16
+ Mongoid::Deprecation.instance
17
+ end
18
+
19
+ it "calls warn on the memoized logger" do
20
+ logger.expects(:warn).with("Deprecation: testing")
21
+ deprecation.alert("testing")
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,430 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Dirty do
4
+
5
+ describe "#attribute_change" do
6
+
7
+ context "when the attribute has changed" do
8
+
9
+ before do
10
+ @person = Person.new(:title => "Grand Poobah")
11
+ @person.title = "Captain Obvious"
12
+ end
13
+
14
+ it "returns an array of the old value and new value" do
15
+ @person.attribute_change("title").should ==
16
+ [ "Grand Poobah", "Captain Obvious" ]
17
+ end
18
+
19
+ it "allows access via (attribute)_change" do
20
+ @person.title_change.should ==
21
+ [ "Grand Poobah", "Captain Obvious" ]
22
+ end
23
+ end
24
+
25
+ context "when the attribute changes multiple times" do
26
+
27
+ before do
28
+ @person = Person.new(:title => "Grand Poobah")
29
+ @person.title = "Captain Obvious"
30
+ @person.title = "Dark Helmet"
31
+ end
32
+
33
+ it "returns an array of the original value and new value" do
34
+ @person.attribute_change("title").should ==
35
+ [ "Grand Poobah", "Dark Helmet" ]
36
+ end
37
+
38
+ it "allows access via (attribute)_change" do
39
+ @person.title_change.should ==
40
+ [ "Grand Poobah", "Dark Helmet" ]
41
+ end
42
+ end
43
+
44
+ context "when the attribute is modified in place" do
45
+
46
+ context "when the attribute is an array" do
47
+
48
+ before do
49
+ @person = Person.new(:aliases => [ "Grand Poobah" ])
50
+ @person.aliases[0] = "Dark Helmet"
51
+ end
52
+
53
+ it "returns an array of the original value and new value" do
54
+ @person.attribute_change("aliases").should ==
55
+ [ [ "Grand Poobah" ], [ "Dark Helmet" ] ]
56
+ end
57
+
58
+ it "allows access via (attribute)_change" do
59
+ @person.aliases_change.should ==
60
+ [ [ "Grand Poobah" ], [ "Dark Helmet" ] ]
61
+ end
62
+
63
+ context "when the attribute changes multiple times" do
64
+
65
+ before do
66
+ @person.aliases << "Colonel Sanders"
67
+ end
68
+
69
+ it "returns an array of the original value and new value" do
70
+ @person.attribute_change("aliases").should ==
71
+ [ [ "Grand Poobah" ], [ "Dark Helmet", "Colonel Sanders" ] ]
72
+ end
73
+ end
74
+ end
75
+
76
+ context "when the attribute is a hash" do
77
+
78
+ before do
79
+ @person = Person.new(:map => { :location => "Home" })
80
+ @person.map[:location] = "Work"
81
+ end
82
+
83
+ it "returns an array of the original value and new value" do
84
+ @person.attribute_change("map").should ==
85
+ [ { :location => "Home" }, { :location => "Work" } ]
86
+ end
87
+
88
+ it "allows access via (attribute)_change" do
89
+ @person.map_change.should ==
90
+ [ { :location => "Home" }, { :location => "Work" } ]
91
+ end
92
+
93
+ context "when the attribute changes multiple times" do
94
+
95
+ before do
96
+ @person.map[:lat] = 20.0
97
+ end
98
+
99
+ it "returns an array of the original value and new value" do
100
+ @person.attribute_change("map").should ==
101
+ [ { :location => "Home" }, { :location => "Work", :lat => 20.0 } ]
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ context "when the attribute has not changed" do
108
+
109
+ before do
110
+ @person = Person.new(:title => "Grand Poobah")
111
+ end
112
+
113
+ it "returns an empty array" do
114
+ @person.attribute_change("title").should be_nil
115
+ end
116
+ end
117
+
118
+ context "when the attribute has been set with the same value" do
119
+
120
+ before do
121
+ @person = Person.new(:title => "Grand Poobah")
122
+ @person.title = "Grand Poobah"
123
+ end
124
+
125
+ it "returns an empty array" do
126
+ @person.attribute_change("title").should be_nil
127
+ end
128
+ end
129
+
130
+ context "when the attribute is removed" do
131
+
132
+ before do
133
+ @person = Person.new(:title => "Grand Poobah")
134
+ @person.remove_attribute(:title)
135
+ end
136
+
137
+ it "returns an empty array" do
138
+ @person.attribute_change("title").should ==
139
+ [ "Grand Poobah", nil ]
140
+ end
141
+ end
142
+ end
143
+
144
+ describe "#attribute_changed?" do
145
+
146
+ context "when the attribute has changed" do
147
+
148
+ before do
149
+ @person = Person.new(:title => "Grand Poobah")
150
+ @person.title = "Captain Obvious"
151
+ end
152
+
153
+ it "returns true" do
154
+ @person.attribute_changed?("title").should == true
155
+ end
156
+
157
+ it "allows access via (attribute)_changed?" do
158
+ @person.title_changed?.should == true
159
+ end
160
+ end
161
+
162
+ context "when the attribute has not changed" do
163
+
164
+ before do
165
+ @person = Person.new(:title => "Grand Poobah")
166
+ end
167
+
168
+ it "returns false" do
169
+ @person.attribute_changed?("title").should == false
170
+ end
171
+ end
172
+ end
173
+
174
+ describe "#attribute_was" do
175
+
176
+ context "when the attribute has changed" do
177
+
178
+ before do
179
+ @person = Person.new(:title => "Grand Poobah")
180
+ @person.title = "Captain Obvious"
181
+ end
182
+
183
+ it "returns the old value" do
184
+ @person.attribute_was("title").should == "Grand Poobah"
185
+ end
186
+
187
+ it "allows access via (attribute)_was" do
188
+ @person.title_was.should == "Grand Poobah"
189
+ end
190
+ end
191
+
192
+ context "when the attribute has not changed" do
193
+
194
+ before do
195
+ @person = Person.new(:title => "Grand Poobah")
196
+ end
197
+
198
+ it "returns nil" do
199
+ @person.attribute_was("title").should be_nil
200
+ end
201
+ end
202
+ end
203
+
204
+ describe "#changed" do
205
+
206
+ context "when the document has changed" do
207
+
208
+ before do
209
+ @person = Person.new(:title => "Grand Poobah")
210
+ @person.title = "Captain Obvious"
211
+ end
212
+
213
+ it "returns an array of changed field names" do
214
+ @person.changed.should == [ "title" ]
215
+ end
216
+ end
217
+
218
+ context "when the document has not changed" do
219
+
220
+ before do
221
+ @person = Person.new(:title => "Grand Poobah")
222
+ end
223
+
224
+ it "returns an empty array" do
225
+ @person.changed.should == []
226
+ end
227
+ end
228
+ end
229
+
230
+ describe "#changed?" do
231
+
232
+ context "when the document has changed" do
233
+
234
+ before do
235
+ @person = Person.new(:title => "Grand Poobah")
236
+ @person.title = "Captain Obvious"
237
+ end
238
+
239
+ it "returns true" do
240
+ @person.should be_changed
241
+ end
242
+ end
243
+
244
+ context "when the document has not changed" do
245
+
246
+ before do
247
+ @person = Person.new(:title => "Grand Poobah")
248
+ end
249
+
250
+ it "returns false" do
251
+ @person.should_not be_changed
252
+ end
253
+ end
254
+ end
255
+
256
+ describe "#changes" do
257
+
258
+ context "when the document has changed" do
259
+
260
+ before do
261
+ @person = Person.new(:title => "Grand Poobah")
262
+ @person.title = "Captain Obvious"
263
+ end
264
+
265
+ it "returns a hash of changes" do
266
+ @person.changes.should ==
267
+ { "title" => [ "Grand Poobah", "Captain Obvious" ] }
268
+ end
269
+ end
270
+
271
+ context "when the document has not changed" do
272
+
273
+ before do
274
+ @person = Person.new(:title => "Grand Poobah")
275
+ end
276
+
277
+ it "returns an empty hash" do
278
+ @person.changes.should == {}
279
+ end
280
+ end
281
+ end
282
+
283
+ describe "#setters" do
284
+
285
+ context "when the document has changed" do
286
+
287
+ context "when the document is a root document" do
288
+
289
+ before do
290
+ @person = Person.new(:title => "Grand Poobah")
291
+ @person.title = "Captain Obvious"
292
+ end
293
+
294
+ it "returns a hash of field names and new values" do
295
+ @person.setters.should ==
296
+ { "title" => "Captain Obvious" }
297
+ end
298
+ end
299
+
300
+ context "when the document is embedded" do
301
+
302
+ before do
303
+ @person = Person.new(:title => "Grand Poobah")
304
+ @address = Address.new(:street => "Oxford St")
305
+ @person.addresses << @address
306
+ @person.instance_variable_set(:@new_record, false)
307
+ @address.instance_variable_set(:@new_record, false)
308
+ @address.street = "Bond St"
309
+ end
310
+
311
+ it "returns a hash of field names and new values" do
312
+ @address.setters.should ==
313
+ { "addresses.0.street" => "Bond St" }
314
+ end
315
+
316
+ context "when the document is embedded multiple levels" do
317
+
318
+ before do
319
+ @location = Location.new(:name => "Home")
320
+ @location.instance_variable_set(:@new_record, false)
321
+ @address.locations << @location
322
+ @location.name = "Work"
323
+ end
324
+
325
+ it "returns the proper hash with locations" do
326
+ @location.setters.should ==
327
+ { "addresses.0.locations.0.name" => "Work" }
328
+ end
329
+ end
330
+ end
331
+ end
332
+
333
+ context "when the document has not changed" do
334
+
335
+ before do
336
+ @person = Person.new(:title => "Grand Poobah")
337
+ end
338
+
339
+ it "returns an empty hash" do
340
+ @person.setters.should == {}
341
+ end
342
+ end
343
+ end
344
+
345
+ describe "#previous_changes" do
346
+
347
+ before do
348
+ @person = Person.new(:title => "Grand Poobah")
349
+ @person.title = "Captain Obvious"
350
+ end
351
+
352
+ context "when the document has been saved" do
353
+
354
+ before do
355
+ @person.collection.expects(:insert).returns(true)
356
+ @person.save!
357
+ end
358
+
359
+ it "returns the changes before the save" do
360
+ @person.previous_changes["title"].should ==
361
+ [ "Grand Poobah", "Captain Obvious" ]
362
+ end
363
+ end
364
+
365
+ context "when the document has not been saved" do
366
+
367
+ it "returns an empty hash" do
368
+ @person.previous_changes.should == {}
369
+ end
370
+ end
371
+ end
372
+
373
+ describe "#reset_attribute!" do
374
+
375
+ context "when the attribute has changed" do
376
+
377
+ before do
378
+ @person = Person.new(:title => "Grand Poobah")
379
+ @person.title = "Captain Obvious"
380
+ end
381
+
382
+ it "resets the value to the original" do
383
+ @person.reset_attribute!("title")
384
+ @person.title.should == "Grand Poobah"
385
+ end
386
+
387
+ it "allows access via reset_(attribute)!" do
388
+ @person.reset_title!
389
+ @person.title.should == "Grand Poobah"
390
+ end
391
+
392
+ it "removes the field from the changes" do
393
+ @person.reset_title!
394
+ @person.changed.should == []
395
+ end
396
+ end
397
+
398
+ context "when the attribute has not changed" do
399
+
400
+ before do
401
+ @person = Person.new(:title => "Grand Poobah")
402
+ end
403
+
404
+ it "does nothing" do
405
+ @person.reset_attribute!("title")
406
+ @person.title.should == "Grand Poobah"
407
+ end
408
+ end
409
+ end
410
+
411
+ describe "#reset_modifications" do
412
+
413
+ context "when the attribute has changed" do
414
+
415
+ before do
416
+ @person = Person.new(:title => "Grand Poobah")
417
+ @person.title = "Captain Obvious"
418
+ @person.reset_modifications
419
+ end
420
+
421
+ it "does not reset the value" do
422
+ @person.title.should == "Captain Obvious"
423
+ end
424
+
425
+ it "removes the note of the change" do
426
+ @person.changed?.should == false
427
+ end
428
+ end
429
+ end
430
+ end