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,191 @@
1
+ require "spec_helper"
2
+
3
+ describe Humanoid::Associations::Options do
4
+
5
+ describe "#name" do
6
+
7
+ before do
8
+ @attributes = { :name => :addresses }
9
+ @options = Humanoid::Associations::Options.new(@attributes)
10
+ end
11
+
12
+ it "returns the association name" do
13
+ @options.name.should == "addresses"
14
+ end
15
+
16
+ end
17
+
18
+ describe "#extend" do
19
+
20
+ context "when extension exists" do
21
+
22
+ before do
23
+ @attributes = { :extend => lambda { "Test" } }
24
+ @options = Humanoid::Associations::Options.new(@attributes)
25
+ end
26
+
27
+ it "returns the proc" do
28
+ @options.extension.should == @attributes[:extend]
29
+ end
30
+
31
+ end
32
+
33
+ context "when extension doesnt exist" do
34
+
35
+ before do
36
+ @options = Humanoid::Associations::Options.new({})
37
+ end
38
+
39
+ it "returns nil" do
40
+ @options.extension.should be_nil
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ describe "extension?" do
48
+
49
+ context "when extension exists" do
50
+
51
+ before do
52
+ @attributes = { :extend => lambda { "Test" } }
53
+ @options = Humanoid::Associations::Options.new(@attributes)
54
+ end
55
+
56
+ it "returns true" do
57
+ @options.extension?.should be_true
58
+ end
59
+
60
+ end
61
+
62
+ context "when extension doesnt exist" do
63
+
64
+ before do
65
+ @options = Humanoid::Associations::Options.new({})
66
+ end
67
+
68
+ it "returns false" do
69
+ @options.extension?.should be_false
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+
76
+ describe "#foreign_key" do
77
+
78
+ before do
79
+ @attributes = { :name => :game }
80
+ @options = Humanoid::Associations::Options.new(@attributes)
81
+ end
82
+
83
+ it "returns the association foreign_key" do
84
+ @options.foreign_key.should == "game_id"
85
+ end
86
+
87
+ end
88
+
89
+ describe "#inverse_of" do
90
+
91
+ before do
92
+ @attributes = { :inverse_of => :addresses }
93
+ @options = Humanoid::Associations::Options.new(@attributes)
94
+ end
95
+
96
+ it "returns the inverse_of value" do
97
+ @options.inverse_of.should == :addresses
98
+ end
99
+
100
+ end
101
+
102
+ describe "#klass" do
103
+
104
+ context "when class_name provided" do
105
+
106
+ before do
107
+ @attributes = { :class_name => "Person" }
108
+ @options = Humanoid::Associations::Options.new(@attributes)
109
+ end
110
+
111
+ it "constantizes the class name" do
112
+ @options.klass.should == Person
113
+ end
114
+
115
+ end
116
+
117
+ context "when no class_name provided" do
118
+
119
+ context "when association name is singular" do
120
+
121
+ before do
122
+ @attributes = { :name => :person }
123
+ @options = Humanoid::Associations::Options.new(@attributes)
124
+ end
125
+
126
+ it "classifies and constantizes the association name" do
127
+ @options.klass.should == Person
128
+ end
129
+
130
+ end
131
+
132
+ context "when association name is plural" do
133
+
134
+ before do
135
+ @attributes = { :name => :people }
136
+ @options = Humanoid::Associations::Options.new(@attributes)
137
+ end
138
+
139
+ it "classifies and constantizes the association name" do
140
+ @options.klass.should == Person
141
+ end
142
+
143
+ end
144
+
145
+ end
146
+
147
+ end
148
+
149
+ describe "#parent_key" do
150
+
151
+ before do
152
+ @attributes = { :parent_key => :person_id }
153
+ @options = Humanoid::Associations::Options.new(@attributes)
154
+ end
155
+
156
+ it "returns the parent's foreign key value" do
157
+ @options.parent_key.should == :person_id
158
+ end
159
+
160
+ end
161
+
162
+ describe "#polymorphic" do
163
+
164
+ context "when attribute provided" do
165
+
166
+ before do
167
+ @attributes = { :polymorphic => true }
168
+ @options = Humanoid::Associations::Options.new(@attributes)
169
+ end
170
+
171
+ it "returns the attribute" do
172
+ @options.polymorphic.should be_true
173
+ end
174
+
175
+ end
176
+
177
+ context "when attribute not provided" do
178
+
179
+ before do
180
+ @options = Humanoid::Associations::Options.new
181
+ end
182
+
183
+ it "returns false" do
184
+ @options.polymorphic.should be_false
185
+ end
186
+
187
+ end
188
+
189
+ end
190
+
191
+ end
@@ -0,0 +1,545 @@
1
+ require "spec_helper"
2
+
3
+ describe Humanoid::Associations do
4
+
5
+ before do
6
+ @collection = stub(:name => "people")
7
+ @database = stub(:collection => @collection)
8
+ Humanoid.stubs(:database).returns(@database)
9
+ end
10
+
11
+ after do
12
+ Person.instance_variable_set(:@collection, nil)
13
+ @database = nil
14
+ @collection = nil
15
+ end
16
+
17
+ describe "#association=" do
18
+
19
+ context "when child is a has one" do
20
+
21
+ before do
22
+ @person = Person.new(:title => "Sir", :age => 30)
23
+ @name = Name.new(:first_name => "Test", :last_name => "User")
24
+ @person.name = @name
25
+ end
26
+
27
+ it "parentizes the association" do
28
+ @name._parent.should == @person
29
+ end
30
+
31
+ it "sets the child attributes on the parent" do
32
+ @person.attributes[:name].should ==
33
+ { "_id" => "test-user", "first_name" => "Test", "last_name" => "User", "_type" => "Name" }
34
+ end
35
+
36
+ end
37
+
38
+ context "when child and parent are namespaced" do
39
+
40
+ before do
41
+ @patient = Medical::Patient.new(:name => "Ridley")
42
+ @prescription = Medical::Prescription.new(:name => "Zoloft")
43
+ @patient.prescriptions << @prescription
44
+ @second = @patient.prescriptions.build(:name => "Codeine")
45
+ end
46
+
47
+ it "sets the correct association classes" do
48
+ @patient.prescriptions.first.should == @prescription
49
+ @patient.prescriptions.last.should == @second
50
+ end
51
+
52
+ end
53
+
54
+ context "when setting a parent" do
55
+
56
+ context "when the child is one level deep" do
57
+
58
+ before do
59
+ @person = Person.new(:title => "Mr")
60
+ @address = Address.new(:street => "Picadilly Circus")
61
+ @address.addressable = @person
62
+ end
63
+
64
+ it "re-parentizes the association" do
65
+ @address._parent.should == @person
66
+ end
67
+
68
+ it "adds the child attributes to the parent" do
69
+ @person.attributes[:addresses].should ==
70
+ [{ "_id" => "picadilly-circus", "street" => "Picadilly Circus", "_type" => "Address" }]
71
+ end
72
+
73
+ end
74
+
75
+ context "when the child is multiple levels deep" do
76
+
77
+ before do
78
+ @person = Person.new(:title => "Mr")
79
+ @phone = Phone.new(:number => "415-555-1212")
80
+ @person.phone_numbers = [@phone]
81
+ @country_code = CountryCode.new(:code => 1)
82
+ @phone.country_code = @country_code
83
+ end
84
+
85
+ it "properly decorates all parent references" do
86
+ @country_code.phone_number.should == @phone
87
+ @phone.person.should == @person
88
+ @country_code.phone_number.person.should == @person
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+
97
+ describe ".belongs_to" do
98
+
99
+ it "creates a reader for the association" do
100
+ address = Address.new
101
+ address.should respond_to(:addressable)
102
+ end
103
+
104
+ it "creates a writer for the association" do
105
+ address = Address.new
106
+ address.should respond_to(:addressable=)
107
+ end
108
+
109
+ it "allows the parent to be any type of class" do
110
+ phone_number = Phone.new(:number => "415-555-1212")
111
+ code = CountryCode.new(:code => 1)
112
+ phone_number.country_code = code
113
+ code.phone_number.should == phone_number
114
+ end
115
+
116
+ context "when adding an anonymous extension" do
117
+
118
+ before do
119
+ @person = Person.new(:title => "Dr")
120
+ @address = Address.new(:street => "Clarkenwell Road")
121
+ @person.addresses << @address
122
+ end
123
+
124
+ it "defines the method on the association" do
125
+ @address.addressable.extension.should == "Testing"
126
+ end
127
+
128
+ end
129
+
130
+ context "when inverse_of not supplied" do
131
+
132
+ it "raises an error" do
133
+ lambda { Person.class_eval { belongs_to :nothing } }.should raise_error
134
+ end
135
+
136
+ end
137
+
138
+ context "when navigating the graph" do
139
+
140
+ before do
141
+ @person = Person.new(:title => "Mr")
142
+ @name = Name.new(:first_name => "Mason")
143
+ @address = Address.new(:street => "King St.")
144
+ @person.name = @name
145
+ @person.addresses << @address
146
+ end
147
+
148
+ it "allows referencing another child through the parent" do
149
+ @name.person.addresses.first.should == @address
150
+ end
151
+
152
+ end
153
+
154
+ end
155
+
156
+ describe "#build_*" do
157
+
158
+ before do
159
+ @canvas = Canvas.new
160
+ end
161
+
162
+ context "when type is passed in" do
163
+
164
+ before do
165
+ @writer = @canvas.build_writer(:speed => 250, :_type => "HtmlWriter")
166
+ end
167
+
168
+ it "returns a new document" do
169
+ @writer.should_not be_nil
170
+ end
171
+
172
+ it "returns the properly typed document" do
173
+ @writer.should be_a_kind_of(HtmlWriter)
174
+ end
175
+
176
+ it "sets the appropriate attributes" do
177
+ @writer.speed.should == 250
178
+ end
179
+
180
+ end
181
+
182
+ context "when type is not passed in" do
183
+
184
+ before do
185
+ @writer = @canvas.build_writer(:speed => 250)
186
+ end
187
+
188
+ it "returns a new document" do
189
+ @writer.should_not be_nil
190
+ end
191
+
192
+ it "returns the properly typed document" do
193
+ @writer.should be_a_kind_of(Writer)
194
+ end
195
+
196
+ it "sets the appropriate attributes" do
197
+ @writer.speed.should == 250
198
+ end
199
+
200
+ end
201
+
202
+ context "when attributes are nil" do
203
+
204
+ before do
205
+ @writer = @canvas.build_writer(nil)
206
+ end
207
+
208
+ it "defaults them to empty" do
209
+ @writer.should be_a_kind_of(Writer)
210
+ end
211
+
212
+ end
213
+
214
+ end
215
+
216
+ describe "#create_*" do
217
+
218
+ before do
219
+ @canvas = Canvas.new
220
+ end
221
+
222
+ context "when type is passed in" do
223
+
224
+ before do
225
+ Humanoid::Commands::Save.expects(:execute)
226
+ @writer = @canvas.create_writer(:speed => 250, :_type => "HtmlWriter")
227
+ end
228
+
229
+ it "returns a new document" do
230
+ @writer.should_not be_nil
231
+ end
232
+
233
+ it "returns the properly typed document" do
234
+ @writer.should be_a_kind_of(HtmlWriter)
235
+ end
236
+
237
+ it "sets the appropriate attributes" do
238
+ @writer.speed.should == 250
239
+ end
240
+
241
+ end
242
+
243
+ context "when type is not passed in" do
244
+
245
+ before do
246
+ Humanoid::Commands::Save.expects(:execute)
247
+ @writer = @canvas.create_writer(:speed => 250, :_type => "HtmlWriter")
248
+ end
249
+
250
+ it "returns a new document" do
251
+ @writer.should_not be_nil
252
+ end
253
+
254
+ it "returns the properly typed document" do
255
+ @writer.should be_a_kind_of(Writer)
256
+ end
257
+
258
+ it "sets the appropriate attributes" do
259
+ @writer.speed.should == 250
260
+ end
261
+
262
+ end
263
+
264
+ end
265
+
266
+ describe ".has_many" do
267
+
268
+ it "adds a new Association to the collection" do
269
+ person = Person.new
270
+ person.addresses.should_not be_nil
271
+ end
272
+
273
+ it "creates a reader for the association" do
274
+ person = Person.new
275
+ person.should respond_to(:addresses)
276
+ end
277
+
278
+ it "creates a writer for the association" do
279
+ person = Person.new
280
+ person.should respond_to(:addresses=)
281
+ end
282
+
283
+ context "when adding an anonymous extension" do
284
+
285
+ it "defines the method on the association" do
286
+ person = Person.new
287
+ person.addresses.extension.should == "Testing"
288
+ end
289
+
290
+ end
291
+
292
+ context "when setting the association directly" do
293
+
294
+ before do
295
+ @attributes = { :title => "Sir",
296
+ :addresses => [
297
+ { :street => "Street 1" },
298
+ { :street => "Street 2" } ] }
299
+ @person = Person.new(@attributes)
300
+ end
301
+
302
+ it "sets the attributes for the association" do
303
+ address = Address.new(:street => "New Street")
304
+ @person.addresses = [address]
305
+ @person.addresses.first.street.should == "New Street"
306
+ end
307
+
308
+ end
309
+
310
+ context "when a class_name is supplied" do
311
+
312
+ before do
313
+ @attributes = { :title => "Sir",
314
+ :phone_numbers => [ { :number => "404-555-1212" } ]
315
+ }
316
+ @person = Person.new(@attributes)
317
+ end
318
+
319
+ it "sets the association name" do
320
+ @person.phone_numbers.first.should == Phone.new(:number => "404-555-1212")
321
+ end
322
+
323
+ end
324
+
325
+ context "when updating objects internally" do
326
+
327
+ before do
328
+ @address = Address.new(:street => "Bourke Street")
329
+ @person = Person.new(:title => "Sir")
330
+ @person.addresses << @address
331
+ @person.update_addresses
332
+ end
333
+
334
+ it "retains its references to the original objects" do
335
+ @address.street.should == "Updated Address"
336
+ end
337
+
338
+ end
339
+
340
+ end
341
+
342
+ describe ".has_one" do
343
+
344
+ before do
345
+ @person = Person.new
346
+ end
347
+
348
+ it "adds a new Association to the document" do
349
+ @person.name.should be_nil
350
+ end
351
+
352
+ it "creates a reader for the association" do
353
+ @person.should respond_to(:name)
354
+ end
355
+
356
+ it "creates a writer for the association" do
357
+ @person.should respond_to(:name=)
358
+ end
359
+
360
+ it "creates a builder for the association" do
361
+ @person.should respond_to(:build_name)
362
+ end
363
+
364
+ it "creates a creator for the association" do
365
+ @person.should respond_to(:create_name)
366
+ end
367
+
368
+ context "when adding an anonymous extension" do
369
+
370
+ it "defines the method on the association" do
371
+ @person.name = Name.new(:first_name => "Richard")
372
+ @person.name.extension.should == "Testing"
373
+ end
374
+
375
+ end
376
+
377
+ context "when setting the association directly" do
378
+
379
+ before do
380
+ @attributes = { :title => "Sir",
381
+ :name => { :first_name => "Test" } }
382
+ @person = Person.new(@attributes)
383
+ end
384
+
385
+ it "sets the attributes for the association" do
386
+ name = Name.new(:first_name => "New Name")
387
+ @person.name = name
388
+ @person.name.first_name.should == "New Name"
389
+ end
390
+
391
+ end
392
+
393
+ context "when a class_name is supplied" do
394
+
395
+ before do
396
+ @attributes = { :title => "Sir",
397
+ :pet => { :name => "Fido" }
398
+ }
399
+ @person = Person.new(@attributes)
400
+ end
401
+
402
+ it "sets the association name" do
403
+ @person.pet.should == Animal.new(:name => "Fido")
404
+ end
405
+
406
+ end
407
+
408
+ end
409
+
410
+ describe ".reflect_on_association" do
411
+
412
+ it "returns the association class for the name" do
413
+ Person.reflect_on_association(:addresses).should == :has_many
414
+ end
415
+
416
+ end
417
+
418
+ describe ".belongs_to_related" do
419
+
420
+ before do
421
+ @game = Game.new
422
+ end
423
+
424
+ it "creates an id field for the relationship" do
425
+ @game.should respond_to(:person_id)
426
+ end
427
+
428
+ it "creates a getter for the parent" do
429
+ @game.should respond_to(:person)
430
+ end
431
+
432
+ context "when document is root level" do
433
+
434
+ it "puts an index on the foreign key" do
435
+ Game.expects(:index).with("person_id")
436
+ Game.belongs_to_related :person
437
+ end
438
+
439
+ end
440
+
441
+ end
442
+
443
+ describe ".has_one_related" do
444
+
445
+ before do
446
+ @person = Person.new
447
+ @game = Game.new
448
+ @person.game = @game
449
+ end
450
+
451
+ it "creates a getter for the relationship" do
452
+ @person.should respond_to(:game)
453
+ end
454
+
455
+ it "creates a setter for the relationship" do
456
+ @person.should respond_to(:game=)
457
+ end
458
+
459
+ context "when adding an anonymous extension" do
460
+
461
+ it "defines the method on the association" do
462
+ @person.game.extension.should == "Testing"
463
+ end
464
+
465
+ end
466
+
467
+ end
468
+
469
+ describe ".has_many_related" do
470
+
471
+ it "creates a getter for the association" do
472
+ Person.new.should respond_to(:posts)
473
+ end
474
+
475
+ it "creates a setter for the association" do
476
+ Person.new.should respond_to(:posts=)
477
+ end
478
+
479
+ context "when adding an anonymous extension" do
480
+
481
+ before do
482
+ @person = Person.new
483
+ end
484
+
485
+ it "defines the method on the association" do
486
+ @person.posts.extension.should == "Testing"
487
+ end
488
+
489
+ end
490
+
491
+ end
492
+
493
+ describe "#update_associations" do
494
+
495
+ context "when associations exist" do
496
+
497
+ before do
498
+ @related = stub(:id => "100", :person= => true)
499
+ @person = Person.new
500
+ @person.posts = [@related]
501
+ end
502
+
503
+ it "saves each association" do
504
+ @related.expects(:save).returns(@related)
505
+ @person.update_associations(:posts)
506
+ end
507
+
508
+ end
509
+
510
+ context "when no associations exist" do
511
+
512
+ before do
513
+ @person = Person.new
514
+ end
515
+
516
+ it "does nothing" do
517
+ Post.expects(:find).returns([])
518
+ @person.update_associations(:posts)
519
+ @person.posts.first.should be_nil
520
+ end
521
+
522
+ end
523
+
524
+ end
525
+
526
+ describe "#update_association" do
527
+
528
+ context "when the association exists" do
529
+
530
+ before do
531
+ @related = stub(:id => "100", :person= => true)
532
+ @person = Person.new
533
+ @person.game = @related
534
+ end
535
+
536
+ it "saves each association" do
537
+ @related.expects(:save).returns(@related)
538
+ @person.update_association(:game)
539
+ end
540
+
541
+ end
542
+
543
+ end
544
+
545
+ end