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