humanoid 1.2.7

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