humanoid 1.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. data/.gitignore +6 -0
  2. data/.watchr +29 -0
  3. data/HISTORY +342 -0
  4. data/MIT_LICENSE +20 -0
  5. data/README.rdoc +56 -0
  6. data/Rakefile +53 -0
  7. data/VERSION +1 -0
  8. data/caliper.yml +4 -0
  9. data/humanoid.gemspec +374 -0
  10. data/lib/humanoid.rb +111 -0
  11. data/lib/humanoid/associations.rb +258 -0
  12. data/lib/humanoid/associations/belongs_to.rb +64 -0
  13. data/lib/humanoid/associations/belongs_to_related.rb +62 -0
  14. data/lib/humanoid/associations/has_many.rb +180 -0
  15. data/lib/humanoid/associations/has_many_related.rb +109 -0
  16. data/lib/humanoid/associations/has_one.rb +95 -0
  17. data/lib/humanoid/associations/has_one_related.rb +81 -0
  18. data/lib/humanoid/associations/options.rb +57 -0
  19. data/lib/humanoid/associations/proxy.rb +31 -0
  20. data/lib/humanoid/attributes.rb +184 -0
  21. data/lib/humanoid/callbacks.rb +23 -0
  22. data/lib/humanoid/collection.rb +118 -0
  23. data/lib/humanoid/collections/cyclic_iterator.rb +34 -0
  24. data/lib/humanoid/collections/master.rb +28 -0
  25. data/lib/humanoid/collections/mimic.rb +46 -0
  26. data/lib/humanoid/collections/operations.rb +41 -0
  27. data/lib/humanoid/collections/slaves.rb +44 -0
  28. data/lib/humanoid/commands.rb +182 -0
  29. data/lib/humanoid/commands/create.rb +21 -0
  30. data/lib/humanoid/commands/delete.rb +16 -0
  31. data/lib/humanoid/commands/delete_all.rb +23 -0
  32. data/lib/humanoid/commands/deletion.rb +18 -0
  33. data/lib/humanoid/commands/destroy.rb +19 -0
  34. data/lib/humanoid/commands/destroy_all.rb +23 -0
  35. data/lib/humanoid/commands/save.rb +27 -0
  36. data/lib/humanoid/components.rb +24 -0
  37. data/lib/humanoid/config.rb +84 -0
  38. data/lib/humanoid/contexts.rb +25 -0
  39. data/lib/humanoid/contexts/enumerable.rb +117 -0
  40. data/lib/humanoid/contexts/ids.rb +25 -0
  41. data/lib/humanoid/contexts/mongo.rb +224 -0
  42. data/lib/humanoid/contexts/paging.rb +42 -0
  43. data/lib/humanoid/criteria.rb +259 -0
  44. data/lib/humanoid/criterion/complex.rb +21 -0
  45. data/lib/humanoid/criterion/exclusion.rb +65 -0
  46. data/lib/humanoid/criterion/inclusion.rb +91 -0
  47. data/lib/humanoid/criterion/optional.rb +128 -0
  48. data/lib/humanoid/cursor.rb +82 -0
  49. data/lib/humanoid/document.rb +300 -0
  50. data/lib/humanoid/enslavement.rb +38 -0
  51. data/lib/humanoid/errors.rb +77 -0
  52. data/lib/humanoid/extensions.rb +84 -0
  53. data/lib/humanoid/extensions/array/accessors.rb +17 -0
  54. data/lib/humanoid/extensions/array/aliasing.rb +4 -0
  55. data/lib/humanoid/extensions/array/assimilation.rb +26 -0
  56. data/lib/humanoid/extensions/array/conversions.rb +29 -0
  57. data/lib/humanoid/extensions/array/parentization.rb +13 -0
  58. data/lib/humanoid/extensions/boolean/conversions.rb +16 -0
  59. data/lib/humanoid/extensions/date/conversions.rb +15 -0
  60. data/lib/humanoid/extensions/datetime/conversions.rb +17 -0
  61. data/lib/humanoid/extensions/float/conversions.rb +16 -0
  62. data/lib/humanoid/extensions/hash/accessors.rb +38 -0
  63. data/lib/humanoid/extensions/hash/assimilation.rb +30 -0
  64. data/lib/humanoid/extensions/hash/conversions.rb +15 -0
  65. data/lib/humanoid/extensions/hash/criteria_helpers.rb +20 -0
  66. data/lib/humanoid/extensions/hash/scoping.rb +12 -0
  67. data/lib/humanoid/extensions/integer/conversions.rb +16 -0
  68. data/lib/humanoid/extensions/nil/assimilation.rb +13 -0
  69. data/lib/humanoid/extensions/object/conversions.rb +33 -0
  70. data/lib/humanoid/extensions/proc/scoping.rb +12 -0
  71. data/lib/humanoid/extensions/string/conversions.rb +15 -0
  72. data/lib/humanoid/extensions/string/inflections.rb +97 -0
  73. data/lib/humanoid/extensions/symbol/inflections.rb +36 -0
  74. data/lib/humanoid/extensions/time/conversions.rb +18 -0
  75. data/lib/humanoid/factory.rb +19 -0
  76. data/lib/humanoid/field.rb +39 -0
  77. data/lib/humanoid/fields.rb +62 -0
  78. data/lib/humanoid/finders.rb +224 -0
  79. data/lib/humanoid/identity.rb +39 -0
  80. data/lib/humanoid/indexes.rb +30 -0
  81. data/lib/humanoid/matchers.rb +36 -0
  82. data/lib/humanoid/matchers/all.rb +11 -0
  83. data/lib/humanoid/matchers/default.rb +26 -0
  84. data/lib/humanoid/matchers/exists.rb +13 -0
  85. data/lib/humanoid/matchers/gt.rb +11 -0
  86. data/lib/humanoid/matchers/gte.rb +11 -0
  87. data/lib/humanoid/matchers/in.rb +11 -0
  88. data/lib/humanoid/matchers/lt.rb +11 -0
  89. data/lib/humanoid/matchers/lte.rb +11 -0
  90. data/lib/humanoid/matchers/ne.rb +11 -0
  91. data/lib/humanoid/matchers/nin.rb +11 -0
  92. data/lib/humanoid/matchers/size.rb +11 -0
  93. data/lib/humanoid/memoization.rb +27 -0
  94. data/lib/humanoid/named_scope.rb +40 -0
  95. data/lib/humanoid/scope.rb +75 -0
  96. data/lib/humanoid/timestamps.rb +30 -0
  97. data/lib/humanoid/versioning.rb +28 -0
  98. data/perf/benchmark.rb +77 -0
  99. data/spec/integration/humanoid/associations_spec.rb +301 -0
  100. data/spec/integration/humanoid/attributes_spec.rb +22 -0
  101. data/spec/integration/humanoid/commands_spec.rb +216 -0
  102. data/spec/integration/humanoid/contexts/enumerable_spec.rb +33 -0
  103. data/spec/integration/humanoid/criteria_spec.rb +224 -0
  104. data/spec/integration/humanoid/document_spec.rb +587 -0
  105. data/spec/integration/humanoid/extensions_spec.rb +26 -0
  106. data/spec/integration/humanoid/finders_spec.rb +119 -0
  107. data/spec/integration/humanoid/inheritance_spec.rb +137 -0
  108. data/spec/integration/humanoid/named_scope_spec.rb +46 -0
  109. data/spec/models/address.rb +39 -0
  110. data/spec/models/animal.rb +6 -0
  111. data/spec/models/comment.rb +8 -0
  112. data/spec/models/country_code.rb +6 -0
  113. data/spec/models/employer.rb +5 -0
  114. data/spec/models/game.rb +6 -0
  115. data/spec/models/inheritance.rb +56 -0
  116. data/spec/models/location.rb +5 -0
  117. data/spec/models/mixed_drink.rb +4 -0
  118. data/spec/models/name.rb +13 -0
  119. data/spec/models/namespacing.rb +11 -0
  120. data/spec/models/patient.rb +4 -0
  121. data/spec/models/person.rb +98 -0
  122. data/spec/models/pet.rb +7 -0
  123. data/spec/models/pet_owner.rb +6 -0
  124. data/spec/models/phone.rb +7 -0
  125. data/spec/models/post.rb +15 -0
  126. data/spec/models/translation.rb +5 -0
  127. data/spec/models/vet_visit.rb +5 -0
  128. data/spec/spec.opts +3 -0
  129. data/spec/spec_helper.rb +31 -0
  130. data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +141 -0
  131. data/spec/unit/mongoid/associations/belongs_to_spec.rb +193 -0
  132. data/spec/unit/mongoid/associations/has_many_related_spec.rb +387 -0
  133. data/spec/unit/mongoid/associations/has_many_spec.rb +471 -0
  134. data/spec/unit/mongoid/associations/has_one_related_spec.rb +179 -0
  135. data/spec/unit/mongoid/associations/has_one_spec.rb +282 -0
  136. data/spec/unit/mongoid/associations/options_spec.rb +191 -0
  137. data/spec/unit/mongoid/associations_spec.rb +545 -0
  138. data/spec/unit/mongoid/attributes_spec.rb +484 -0
  139. data/spec/unit/mongoid/callbacks_spec.rb +55 -0
  140. data/spec/unit/mongoid/collection_spec.rb +171 -0
  141. data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
  142. data/spec/unit/mongoid/collections/master_spec.rb +41 -0
  143. data/spec/unit/mongoid/collections/mimic_spec.rb +43 -0
  144. data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
  145. data/spec/unit/mongoid/commands/create_spec.rb +30 -0
  146. data/spec/unit/mongoid/commands/delete_all_spec.rb +58 -0
  147. data/spec/unit/mongoid/commands/delete_spec.rb +35 -0
  148. data/spec/unit/mongoid/commands/destroy_all_spec.rb +23 -0
  149. data/spec/unit/mongoid/commands/destroy_spec.rb +44 -0
  150. data/spec/unit/mongoid/commands/save_spec.rb +105 -0
  151. data/spec/unit/mongoid/commands_spec.rb +282 -0
  152. data/spec/unit/mongoid/config_spec.rb +165 -0
  153. data/spec/unit/mongoid/contexts/enumerable_spec.rb +374 -0
  154. data/spec/unit/mongoid/contexts/mongo_spec.rb +505 -0
  155. data/spec/unit/mongoid/contexts_spec.rb +25 -0
  156. data/spec/unit/mongoid/criteria_spec.rb +769 -0
  157. data/spec/unit/mongoid/criterion/complex_spec.rb +19 -0
  158. data/spec/unit/mongoid/criterion/exclusion_spec.rb +91 -0
  159. data/spec/unit/mongoid/criterion/inclusion_spec.rb +211 -0
  160. data/spec/unit/mongoid/criterion/optional_spec.rb +329 -0
  161. data/spec/unit/mongoid/cursor_spec.rb +74 -0
  162. data/spec/unit/mongoid/document_spec.rb +986 -0
  163. data/spec/unit/mongoid/enslavement_spec.rb +63 -0
  164. data/spec/unit/mongoid/errors_spec.rb +103 -0
  165. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
  166. data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
  167. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +35 -0
  168. data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
  169. data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
  170. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +102 -0
  171. data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +70 -0
  172. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
  173. data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
  174. data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +46 -0
  175. data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +21 -0
  176. data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
  177. data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
  178. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
  179. data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +24 -0
  180. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +43 -0
  181. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
  182. data/spec/unit/mongoid/extensions/string/conversions_spec.rb +17 -0
  183. data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
  184. data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +91 -0
  185. data/spec/unit/mongoid/extensions/time/conversions_spec.rb +70 -0
  186. data/spec/unit/mongoid/factory_spec.rb +31 -0
  187. data/spec/unit/mongoid/field_spec.rb +81 -0
  188. data/spec/unit/mongoid/fields_spec.rb +158 -0
  189. data/spec/unit/mongoid/finders_spec.rb +368 -0
  190. data/spec/unit/mongoid/identity_spec.rb +88 -0
  191. data/spec/unit/mongoid/indexes_spec.rb +93 -0
  192. data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
  193. data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
  194. data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
  195. data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
  196. data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
  197. data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
  198. data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
  199. data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
  200. data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
  201. data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
  202. data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
  203. data/spec/unit/mongoid/matchers_spec.rb +329 -0
  204. data/spec/unit/mongoid/memoization_spec.rb +75 -0
  205. data/spec/unit/mongoid/named_scope_spec.rb +123 -0
  206. data/spec/unit/mongoid/scope_spec.rb +240 -0
  207. data/spec/unit/mongoid/timestamps_spec.rb +25 -0
  208. data/spec/unit/mongoid/versioning_spec.rb +41 -0
  209. data/spec/unit/mongoid_spec.rb +37 -0
  210. metadata +431 -0
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+
3
+ describe Humanoid::Contexts::Enumerable do
4
+
5
+ before do
6
+ @person = Person.new(:title => "Sir")
7
+ 10.times do |n|
8
+ @person.addresses << Address.new(:number => n, :street => "Upper Street")
9
+ end
10
+ end
11
+
12
+ describe "#paginate" do
13
+
14
+ it "paginates the embedded documents" do
15
+ addresses = @person.addresses.paginate(:page => nil, :per_page => 5)
16
+ addresses.current_page.should == 1
17
+ addresses.size.should == 5
18
+ end
19
+ end
20
+
21
+ describe "limit and skip" do
22
+
23
+ it "limits" do
24
+ @person.addresses.criteria.limit(5).size.should == 5
25
+ end
26
+
27
+ it "skips" do
28
+ @person.addresses.criteria.skip(5).limit(10).
29
+ map(&:number).should == [5, 6, 7, 8, 9]
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,224 @@
1
+ require "spec_helper"
2
+
3
+ describe Humanoid::Criteria do
4
+
5
+ before do
6
+ Person.delete_all
7
+ end
8
+
9
+ after do
10
+ Person.delete_all
11
+ end
12
+
13
+ describe "#excludes" do
14
+
15
+ before do
16
+ @person = Person.create(:title => "Sir", :age => 100, :aliases => ["D", "Durran"], :ssn => "666666666")
17
+ end
18
+
19
+ context "when passed id" do
20
+
21
+ it "it properly excludes ids" do
22
+ Person.criteria.excludes(:id => @person.id).entries.should be_empty
23
+ end
24
+
25
+ end
26
+
27
+ context "when passed _id" do
28
+
29
+ it "it properly excludes ids" do
30
+ Person.criteria.excludes(:_id => @person.id).entries.should be_empty
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ describe "#execute" do
38
+
39
+ context "when reiterating" do
40
+
41
+ before do
42
+ @person = Person.create(:title => "Sir", :age => 100, :aliases => ["D", "Durran"], :ssn => "666666666")
43
+ end
44
+
45
+ it "executes the query again" do
46
+ criteria = Person.all
47
+ criteria.size.should == 1
48
+ criteria.should_not be_empty
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#max" do
54
+
55
+ context "without results" do
56
+ it "should return nil" do
57
+ Person.max(:age).should == nil
58
+ end
59
+ end
60
+
61
+ context "with results" do
62
+ before do
63
+ 10.times do |n|
64
+ Person.create(:title => "Sir", :age => (n * 10), :aliases => ["D", "Durran"], :ssn => "#{n}")
65
+ end
66
+ end
67
+
68
+ it "provides max for the field provided" do
69
+ Person.max(:age).should == 90.0
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "#min" do
75
+
76
+ context "without results" do
77
+ it "should return nil" do
78
+ Person.min(:age).should == nil
79
+ end
80
+ end
81
+
82
+ context "with results" do
83
+ before do
84
+ 10.times do |n|
85
+ Person.create(:title => "Sir", :age => ((n + 1) * 10), :aliases => ["D", "Durran"], :ssn => "#{n}")
86
+ end
87
+ end
88
+
89
+ it "provides min for the field provided" do
90
+ Person.min(:age).should == 10.0
91
+ end
92
+ end
93
+ end
94
+
95
+ describe "#sum" do
96
+
97
+ context "without results" do
98
+ it "should return nil" do
99
+ Person.sum(:age).should == nil
100
+ end
101
+ end
102
+
103
+ context "with results" do
104
+ before do
105
+ 10.times do |n|
106
+ Person.create(:title => "Sir", :age => 5, :aliases => ["D", "Durran"], :ssn => "#{n}")
107
+ end
108
+ end
109
+
110
+ it "provides sum for the field provided" do
111
+ Person.where(:age.gt => 3).sum(:age).should == 50.0
112
+ end
113
+ end
114
+ end
115
+
116
+ describe "#where" do
117
+
118
+ before do
119
+ @person = Person.create(:title => "Sir", :age => 33, :aliases => ["D", "Durran"])
120
+ end
121
+
122
+ context "with complex criterion" do
123
+
124
+ context "#all" do
125
+
126
+ it "returns those matching an all clause" do
127
+ Person.criteria.where(:title.all => ["Sir"]).should == [@person]
128
+ end
129
+
130
+ end
131
+
132
+ context "#exists" do
133
+
134
+ it "returns those matching an exists clause" do
135
+ Person.criteria.where(:title.exists => true).should == [@person]
136
+ end
137
+
138
+ end
139
+
140
+ context "#gt" do
141
+
142
+ it "returns those matching a gt clause" do
143
+ Person.criteria.where(:age.gt => 30).should == [@person]
144
+ end
145
+
146
+ end
147
+
148
+ context "#gte" do
149
+
150
+ it "returns those matching a gte clause" do
151
+ Person.criteria.where(:age.gte => 33).should == [@person]
152
+ end
153
+
154
+ end
155
+
156
+ context "#in" do
157
+
158
+ it "returns those matching an in clause" do
159
+ Person.criteria.where(:title.in => ["Sir", "Madam"]).should == [@person]
160
+ end
161
+
162
+ end
163
+
164
+ context "#lt" do
165
+
166
+ it "returns those matching a lt clause" do
167
+ Person.criteria.where(:age.lt => 34).should == [@person]
168
+ end
169
+
170
+ end
171
+
172
+ context "#lte" do
173
+
174
+ it "returns those matching a lte clause" do
175
+ Person.criteria.where(:age.lte => 33).should == [@person]
176
+ end
177
+
178
+ end
179
+
180
+ context "#ne" do
181
+
182
+ it "returns those matching a ne clause" do
183
+ Person.criteria.where(:age.ne => 50).should == [@person]
184
+ end
185
+
186
+ end
187
+
188
+ context "#nin" do
189
+
190
+ it "returns those matching a nin clause" do
191
+ Person.criteria.where(:title.nin => ["Esquire", "Congressman"]).should == [@person]
192
+ end
193
+
194
+ end
195
+
196
+ context "#size" do
197
+
198
+ it "returns those matching a size clause" do
199
+ Person.criteria.where(:aliases.size => 2).should == [@person]
200
+ end
201
+
202
+ end
203
+
204
+ end
205
+
206
+ end
207
+
208
+ context "when caching" do
209
+
210
+ before do
211
+ 10.times do |n|
212
+ Person.create(:title => "Sir", :age => (n * 10), :aliases => ["D", "Durran"], :ssn => "#{n}")
213
+ end
214
+ end
215
+
216
+ it "iterates over the cursor only once" do
217
+ criteria = Person.where(:title => "Sir").cache
218
+ criteria.collect.to_a.size.should == 10
219
+ # Do it again!
220
+ criteria.collect.to_a.size.should == 10
221
+ end
222
+ end
223
+
224
+ end
@@ -0,0 +1,587 @@
1
+ require "spec_helper"
2
+
3
+ describe Humanoid::Document do
4
+
5
+ before do
6
+ Person.delete_all
7
+ end
8
+
9
+ describe "#db" do
10
+
11
+ it "returns the mongo database" do
12
+ Person.db.should == Humanoid.master
13
+ end
14
+ end
15
+
16
+ context "when document contains a hash field" do
17
+
18
+ before do
19
+ @map = { "first" => 10, "second" => "Blah" }
20
+ @person = Person.create(:map => @map)
21
+ end
22
+
23
+ it "properly gets and sets the has attributes" do
24
+ @person.map.should == @map
25
+ @from_db = Person.find(@person.id)
26
+ @from_db.map.should == @map
27
+ end
28
+
29
+ end
30
+
31
+ describe ".collection" do
32
+
33
+ context "on a subclass of a root document" do
34
+
35
+ it "returns the root document collection" do
36
+ Browser.collection.should == Canvas.collection
37
+ end
38
+
39
+ end
40
+
41
+ context "on a namespaced document" do
42
+ Medical::Patient.collection.name.should == "medical_patients"
43
+ end
44
+
45
+ end
46
+
47
+ describe "#new" do
48
+
49
+ it "gets a new or current database connection" do
50
+ person = Person.new
51
+ person.collection.should be_a_kind_of(Humanoid::Collection)
52
+ end
53
+
54
+ end
55
+
56
+ describe "#count" do
57
+
58
+ before do
59
+ 5.times do |n|
60
+ Person.create(:title => "Sir", :ssn => "#{n}")
61
+ end
62
+ end
63
+
64
+ it "returns the count" do
65
+ Person.count.should == 5
66
+ end
67
+
68
+ end
69
+
70
+ describe "#create" do
71
+
72
+ it "persists a new record to the database" do
73
+ person = Person.create(:title => "Test")
74
+ person.id.should be_a_kind_of(String)
75
+ person.attributes[:title].should == "Test"
76
+ end
77
+
78
+ context "when creating a has many" do
79
+
80
+ before do
81
+ @person = Person.new(:title => "Esquire")
82
+ @person.addresses.create(:street => "Nan Jing Dong Lu", :city => "Shanghai")
83
+ end
84
+
85
+ it "should create and save the entire graph" do
86
+ person = Person.find(@person.id)
87
+ person.addresses.first.street.should == "Nan Jing Dong Lu"
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
94
+ context "chaining criteria scopes" do
95
+
96
+ before do
97
+ @one = Person.create(:title => "Mr", :age => 55, :terms => true, :ssn => "q")
98
+ @two = Person.create(:title => "Sir", :age => 55, :terms => true, :ssn => "w")
99
+ @three = Person.create(:title => "Sir", :age => 35, :terms => true, :ssn => "e")
100
+ @four = Person.create(:title => "Sir", :age => 55, :terms => false, :ssn => "r")
101
+ end
102
+
103
+ it "finds by the merged criteria" do
104
+ people = Person.old.accepted.knight
105
+ people.count.should == 1
106
+ people.first.should == @two
107
+ end
108
+
109
+ end
110
+
111
+ context "#destroy" do
112
+
113
+ context "on a root document" do
114
+
115
+ before do
116
+ @person = Person.create(:title => "Sir")
117
+ end
118
+
119
+ it "deletes the document" do
120
+ @person.destroy
121
+ lambda { Person.find(@person.id) }.should raise_error
122
+ end
123
+
124
+ end
125
+
126
+ context "on an embedded document" do
127
+
128
+ before do
129
+ @person = Person.create(:title => "Lead")
130
+ address = @person.addresses.create(:street => "1st Street")
131
+ @person.create_name(:first_name => "Emmanuel")
132
+ @person.save
133
+ end
134
+
135
+ it "deletes the document" do
136
+ @person.addresses.first.destroy
137
+ @person.name.should_not be_nil
138
+ @person.name.destroy
139
+ @person.addresses.first.should be_nil
140
+ @person.name.should be_nil
141
+ end
142
+
143
+ end
144
+
145
+ end
146
+
147
+ context ".find_or_create_by" do
148
+
149
+ before do
150
+ @person = Person.create(:title => "Senior")
151
+ end
152
+
153
+ context "when the document is found" do
154
+
155
+ it "returns the document" do
156
+ Person.find_or_create_by(:title => "Senior").should == @person
157
+ end
158
+
159
+ end
160
+
161
+ context "when the document is not found" do
162
+
163
+ it "creates a new document" do
164
+ person = Person.find_or_create_by(:title => "Senorita", :ssn => "1234567")
165
+ person.title.should == "Senorita"
166
+ person.should_not be_a_new_record
167
+ end
168
+
169
+ end
170
+
171
+ end
172
+
173
+ context ".find_or_initialize_by" do
174
+
175
+ before do
176
+ @person = Person.create(:title => "Senior")
177
+ end
178
+
179
+ context "when the document is found" do
180
+
181
+ it "returns the document" do
182
+ Person.find_or_initialize_by(:title => "Senior").should == @person
183
+ end
184
+
185
+ end
186
+
187
+ context "when the document is not found" do
188
+
189
+ it "returns a new document" do
190
+ person = Person.find_or_initialize_by(:title => "Senorita")
191
+ person.title.should == "Senorita"
192
+ person.should be_a_new_record
193
+ end
194
+
195
+ end
196
+
197
+ end
198
+
199
+ describe "#find" do
200
+
201
+ before do
202
+ @person = Person.create(:title => "Test")
203
+ end
204
+
205
+ context "finding all documents" do
206
+
207
+ it "returns an array of documents based on the selector provided" do
208
+ documents = Person.find(:all, :conditions => { :title => "Test"})
209
+ documents.first.title.should == "Test"
210
+ end
211
+
212
+ end
213
+
214
+ context "finding first document" do
215
+
216
+ it "returns the first document based on the selector provided" do
217
+ person = Person.find(:first, :conditions => { :title => "Test" })
218
+ person.title.should == "Test"
219
+ end
220
+
221
+ end
222
+
223
+ context "finding by id" do
224
+
225
+ it "finds the document by the supplied id" do
226
+ person = Person.find(@person.id)
227
+ person.id.should == @person.id
228
+ end
229
+
230
+ end
231
+
232
+ context "limiting result fields" do
233
+
234
+ it "adds the type field to the options" do
235
+ people = Person.all(:fields => [ :title ])
236
+ people.first.title.should == "Test"
237
+ end
238
+
239
+ end
240
+
241
+ end
242
+
243
+ describe "#group" do
244
+
245
+ before do
246
+ 5.times do |num|
247
+ Person.create(:title => "Sir", :age => num)
248
+ end
249
+ end
250
+
251
+ it "returns grouped documents" do
252
+ grouped = Person.only(:title).group
253
+ people = grouped.first["group"]
254
+ person = people.first
255
+ person.should be_a_kind_of(Person)
256
+ person.title.should == "Sir"
257
+ end
258
+
259
+ end
260
+
261
+ context "when address is a has one" do
262
+
263
+ before do
264
+ @owner = PetOwner.create(:title => "AKC")
265
+ @address = Address.new(:street => "Fido Street")
266
+ @owner.address = @address
267
+ @owner.save
268
+ end
269
+
270
+ after do
271
+ PetOwner.delete_all
272
+ end
273
+
274
+ it "is a single object and not an array" do
275
+ @from_db = PetOwner.find(@owner.id)
276
+ @from_db.address.should == @address
277
+ end
278
+
279
+ end
280
+
281
+ describe "#inspect" do
282
+
283
+ before do
284
+ @person = Person.new
285
+ end
286
+
287
+ it "returns a pretty string of class name and attributes" do
288
+ attrs = Person.fields.map { |name, field| "#{name}: #{@person.attributes[name].nil? ? 'nil' : @person.attributes[name]}" } * ", "
289
+ @person.inspect.should == "#<Person _id: #{@person.id}, #{attrs}>"
290
+ end
291
+
292
+ end
293
+
294
+ describe "#paginate" do
295
+
296
+ before do
297
+ 10.times do |num|
298
+ Person.create(:title => "Test-#{num}", :ssn => "55#{num}")
299
+ end
300
+ end
301
+
302
+ it "returns paginated documents" do
303
+ Person.paginate(:per_page => 5, :page => 2).length.should == 5
304
+ end
305
+
306
+ it "returns a proper count" do
307
+ @criteria = Humanoid::Criteria.translate(Person, { :per_page => 5, :page => 1 })
308
+ @criteria.count.should == 10
309
+ end
310
+
311
+ end
312
+
313
+ describe "#reload" do
314
+
315
+ before do
316
+ @person = Person.new(:title => "Sir")
317
+ @person.save
318
+ @from_db = Person.find(@person.id)
319
+ @from_db.age = 35
320
+ @from_db.save
321
+ end
322
+
323
+ it "reloads the obejct attributes from the db" do
324
+ @person.reload
325
+ @person.age.should == 35
326
+ end
327
+
328
+ it "reload should return self" do
329
+ @person.reload.should == @from_db
330
+ end
331
+
332
+ end
333
+
334
+ describe "#save" do
335
+
336
+ context "on a has_one association" do
337
+
338
+ before do
339
+ @person = Person.new(:title => "Sir")
340
+ @name = Name.new(:first_name => "Test")
341
+ @person.name = @name
342
+ end
343
+
344
+ it "saves the parent document" do
345
+ @name.save
346
+ person = Person.find(@person.id)
347
+ person.name.first_name.should == @name.first_name
348
+ end
349
+
350
+ end
351
+
352
+ context "without validation" do
353
+
354
+ before do
355
+ @comment = Comment.new
356
+ end
357
+
358
+ it "always persists" do
359
+ @comment.save(false).should be_true
360
+ @from_db = Comment.find(@comment.id)
361
+ @from_db.should == @comment
362
+ end
363
+
364
+ end
365
+
366
+ context "with failing validation" do
367
+
368
+ before do
369
+ @comment = Comment.new
370
+ end
371
+
372
+ it "returns false" do
373
+ @comment.should_not be_valid
374
+ end
375
+
376
+ end
377
+
378
+ end
379
+
380
+ context ".store_in" do
381
+
382
+ after do
383
+ Canvas.store_in(:canvases)
384
+ end
385
+
386
+ it "switches the database collection" do
387
+ Canvas.collection.name.should == "canvases"
388
+ Canvas.store_in(:browsers)
389
+ Canvas.collection.name.should == "browsers"
390
+ end
391
+
392
+ end
393
+
394
+ context "when has many exists through a has one" do
395
+
396
+ before do
397
+ @owner = PetOwner.new(:title => "Sir")
398
+ @pet = Pet.new(:name => "Fido")
399
+ @visit = VetVisit.new(:date => Date.today)
400
+ @pet.vet_visits << @visit
401
+ @owner.pet = @pet
402
+ end
403
+
404
+ it "can clear the association" do
405
+ @owner.pet.vet_visits.size.should == 1
406
+ @owner.pet.vet_visits.clear
407
+ @owner.pet.vet_visits.size.should == 0
408
+ end
409
+
410
+ end
411
+
412
+ context "the lot" do
413
+
414
+ before do
415
+ @person = Person.new(:title => "Sir")
416
+ @name = Name.new(:first_name => "Syd", :last_name => "Vicious")
417
+ @home = Address.new(:street => "Oxford Street")
418
+ @business = Address.new(:street => "Upper Street")
419
+ @person.name = @name
420
+ @person.addresses << @home
421
+ @person.addresses << @business
422
+ end
423
+
424
+ it "allows adding multiples on a has_many in a row" do
425
+ @person.addresses.length.should == 2
426
+ end
427
+
428
+ context "when saving on a has_one" do
429
+
430
+ before do
431
+ @name.save
432
+ end
433
+
434
+ it "saves the entire graph up from the has_one" do
435
+ person = Person.first(:conditions => { :title => "Sir" })
436
+ person.should == @person
437
+ end
438
+
439
+ end
440
+
441
+ context "when saving on a has_many" do
442
+
443
+ before do
444
+ @home.save
445
+ end
446
+
447
+ it "saves the entire graph up from the has_many" do
448
+ person = Person.first(:conditions => { :title => "Sir" })
449
+ person.should == @person
450
+ end
451
+ end
452
+
453
+ end
454
+
455
+ context "setting belongs_to" do
456
+
457
+ before do
458
+ @person = Person.new(:title => "Mr")
459
+ @address = Address.new(:street => "Bloomsbury Ave")
460
+ @person.save!
461
+ end
462
+
463
+ it "allows the parent reference to change" do
464
+ @address.addressable = @person
465
+ @address.save!
466
+ @person.addresses.first.should == @address
467
+ end
468
+
469
+ end
470
+
471
+ describe "#to_json" do
472
+
473
+ before do
474
+ @person = Person.new(:title => "Sir", :age => 30)
475
+ @address = Address.new(:street => "Nan Jing Dong Lu")
476
+ @person.addresses << @address
477
+ end
478
+
479
+ context "on a new document" do
480
+
481
+ it "returns the json string" do
482
+ @person.to_json.should == @person.attributes.to_json
483
+ end
484
+
485
+ end
486
+
487
+ context "on a persisted document" do
488
+
489
+ it "returns the json string" do
490
+ @person.save
491
+ from_db = Person.find(@person.id)
492
+ from_db.to_json.should == from_db.attributes.to_json
493
+ end
494
+
495
+ end
496
+
497
+ end
498
+
499
+ context "typecasting" do
500
+
501
+ before do
502
+ @date = Date.new(1976, 7, 4)
503
+ @person = Person.new(:dob => @date)
504
+ @person.save
505
+ end
506
+
507
+ it "properly casts dates and times" do
508
+ person = Person.first
509
+ person.dob.should == @date
510
+ end
511
+
512
+ end
513
+
514
+ context "versioning" do
515
+
516
+ before do
517
+ @comment = Comment.new(:text => "Testing")
518
+ @comment.save
519
+ end
520
+
521
+ after do
522
+ Comment.collection.drop
523
+ end
524
+
525
+ context "first save" do
526
+
527
+ it "creates a new version" do
528
+ @from_db = Comment.find(@comment.id)
529
+ @from_db.text = "New"
530
+ @from_db.save
531
+ @from_db.versions.size.should == 1
532
+ @from_db.version.should == 2
533
+ end
534
+
535
+ end
536
+
537
+ context "multiple saves" do
538
+
539
+ before do
540
+ 5.times do |n|
541
+ @comment.save
542
+ end
543
+ end
544
+
545
+ it "creates new versions" do
546
+ @from_db = Comment.find(@comment.id)
547
+ @from_db.version.should == 6
548
+ @from_db.versions.size.should == 5
549
+ end
550
+
551
+ end
552
+
553
+ end
554
+
555
+ context "executing criteria with date comparisons" do
556
+
557
+ context "handling specific dates" do
558
+
559
+ before do
560
+ @person = Person.create(:dob => Date.new(2000, 10, 31))
561
+ end
562
+
563
+ it "handles comparisons with todays date"do
564
+ people = Person.where("this.dob < new Date()")
565
+ people.first.should == @person
566
+ end
567
+
568
+ it "handles conparisons with a date range" do
569
+ people = Person.where("new Date(1976, 10, 31) < this.dob && this.dob < new Date()")
570
+ people.first.should == @person
571
+ end
572
+
573
+ it "handles false comparisons in a date range" do
574
+ people = Person.where("new Date(2005, 10, 31) < this.dob && this.dob < new Date()")
575
+ people.should be_empty
576
+ end
577
+
578
+ it "handles comparisons with date objects"do
579
+ people = Person.where(:dob => { "$lt" => Date.today.midnight })
580
+ people.first.should == @person
581
+ end
582
+
583
+ end
584
+
585
+ end
586
+
587
+ end