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.
- data/.gitignore +6 -0
- data/.watchr +29 -0
- data/HISTORY +342 -0
- data/MIT_LICENSE +20 -0
- data/README.rdoc +56 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/caliper.yml +4 -0
- data/humanoid.gemspec +374 -0
- data/lib/humanoid.rb +111 -0
- data/lib/humanoid/associations.rb +258 -0
- data/lib/humanoid/associations/belongs_to.rb +64 -0
- data/lib/humanoid/associations/belongs_to_related.rb +62 -0
- data/lib/humanoid/associations/has_many.rb +180 -0
- data/lib/humanoid/associations/has_many_related.rb +109 -0
- data/lib/humanoid/associations/has_one.rb +95 -0
- data/lib/humanoid/associations/has_one_related.rb +81 -0
- data/lib/humanoid/associations/options.rb +57 -0
- data/lib/humanoid/associations/proxy.rb +31 -0
- data/lib/humanoid/attributes.rb +184 -0
- data/lib/humanoid/callbacks.rb +23 -0
- data/lib/humanoid/collection.rb +118 -0
- data/lib/humanoid/collections/cyclic_iterator.rb +34 -0
- data/lib/humanoid/collections/master.rb +28 -0
- data/lib/humanoid/collections/mimic.rb +46 -0
- data/lib/humanoid/collections/operations.rb +41 -0
- data/lib/humanoid/collections/slaves.rb +44 -0
- data/lib/humanoid/commands.rb +182 -0
- data/lib/humanoid/commands/create.rb +21 -0
- data/lib/humanoid/commands/delete.rb +16 -0
- data/lib/humanoid/commands/delete_all.rb +23 -0
- data/lib/humanoid/commands/deletion.rb +18 -0
- data/lib/humanoid/commands/destroy.rb +19 -0
- data/lib/humanoid/commands/destroy_all.rb +23 -0
- data/lib/humanoid/commands/save.rb +27 -0
- data/lib/humanoid/components.rb +24 -0
- data/lib/humanoid/config.rb +84 -0
- data/lib/humanoid/contexts.rb +25 -0
- data/lib/humanoid/contexts/enumerable.rb +117 -0
- data/lib/humanoid/contexts/ids.rb +25 -0
- data/lib/humanoid/contexts/mongo.rb +224 -0
- data/lib/humanoid/contexts/paging.rb +42 -0
- data/lib/humanoid/criteria.rb +259 -0
- data/lib/humanoid/criterion/complex.rb +21 -0
- data/lib/humanoid/criterion/exclusion.rb +65 -0
- data/lib/humanoid/criterion/inclusion.rb +91 -0
- data/lib/humanoid/criterion/optional.rb +128 -0
- data/lib/humanoid/cursor.rb +82 -0
- data/lib/humanoid/document.rb +300 -0
- data/lib/humanoid/enslavement.rb +38 -0
- data/lib/humanoid/errors.rb +77 -0
- data/lib/humanoid/extensions.rb +84 -0
- data/lib/humanoid/extensions/array/accessors.rb +17 -0
- data/lib/humanoid/extensions/array/aliasing.rb +4 -0
- data/lib/humanoid/extensions/array/assimilation.rb +26 -0
- data/lib/humanoid/extensions/array/conversions.rb +29 -0
- data/lib/humanoid/extensions/array/parentization.rb +13 -0
- data/lib/humanoid/extensions/boolean/conversions.rb +16 -0
- data/lib/humanoid/extensions/date/conversions.rb +15 -0
- data/lib/humanoid/extensions/datetime/conversions.rb +17 -0
- data/lib/humanoid/extensions/float/conversions.rb +16 -0
- data/lib/humanoid/extensions/hash/accessors.rb +38 -0
- data/lib/humanoid/extensions/hash/assimilation.rb +30 -0
- data/lib/humanoid/extensions/hash/conversions.rb +15 -0
- data/lib/humanoid/extensions/hash/criteria_helpers.rb +20 -0
- data/lib/humanoid/extensions/hash/scoping.rb +12 -0
- data/lib/humanoid/extensions/integer/conversions.rb +16 -0
- data/lib/humanoid/extensions/nil/assimilation.rb +13 -0
- data/lib/humanoid/extensions/object/conversions.rb +33 -0
- data/lib/humanoid/extensions/proc/scoping.rb +12 -0
- data/lib/humanoid/extensions/string/conversions.rb +15 -0
- data/lib/humanoid/extensions/string/inflections.rb +97 -0
- data/lib/humanoid/extensions/symbol/inflections.rb +36 -0
- data/lib/humanoid/extensions/time/conversions.rb +18 -0
- data/lib/humanoid/factory.rb +19 -0
- data/lib/humanoid/field.rb +39 -0
- data/lib/humanoid/fields.rb +62 -0
- data/lib/humanoid/finders.rb +224 -0
- data/lib/humanoid/identity.rb +39 -0
- data/lib/humanoid/indexes.rb +30 -0
- data/lib/humanoid/matchers.rb +36 -0
- data/lib/humanoid/matchers/all.rb +11 -0
- data/lib/humanoid/matchers/default.rb +26 -0
- data/lib/humanoid/matchers/exists.rb +13 -0
- data/lib/humanoid/matchers/gt.rb +11 -0
- data/lib/humanoid/matchers/gte.rb +11 -0
- data/lib/humanoid/matchers/in.rb +11 -0
- data/lib/humanoid/matchers/lt.rb +11 -0
- data/lib/humanoid/matchers/lte.rb +11 -0
- data/lib/humanoid/matchers/ne.rb +11 -0
- data/lib/humanoid/matchers/nin.rb +11 -0
- data/lib/humanoid/matchers/size.rb +11 -0
- data/lib/humanoid/memoization.rb +27 -0
- data/lib/humanoid/named_scope.rb +40 -0
- data/lib/humanoid/scope.rb +75 -0
- data/lib/humanoid/timestamps.rb +30 -0
- data/lib/humanoid/versioning.rb +28 -0
- data/perf/benchmark.rb +77 -0
- data/spec/integration/humanoid/associations_spec.rb +301 -0
- data/spec/integration/humanoid/attributes_spec.rb +22 -0
- data/spec/integration/humanoid/commands_spec.rb +216 -0
- data/spec/integration/humanoid/contexts/enumerable_spec.rb +33 -0
- data/spec/integration/humanoid/criteria_spec.rb +224 -0
- data/spec/integration/humanoid/document_spec.rb +587 -0
- data/spec/integration/humanoid/extensions_spec.rb +26 -0
- data/spec/integration/humanoid/finders_spec.rb +119 -0
- data/spec/integration/humanoid/inheritance_spec.rb +137 -0
- data/spec/integration/humanoid/named_scope_spec.rb +46 -0
- data/spec/models/address.rb +39 -0
- data/spec/models/animal.rb +6 -0
- data/spec/models/comment.rb +8 -0
- data/spec/models/country_code.rb +6 -0
- data/spec/models/employer.rb +5 -0
- data/spec/models/game.rb +6 -0
- data/spec/models/inheritance.rb +56 -0
- data/spec/models/location.rb +5 -0
- data/spec/models/mixed_drink.rb +4 -0
- data/spec/models/name.rb +13 -0
- data/spec/models/namespacing.rb +11 -0
- data/spec/models/patient.rb +4 -0
- data/spec/models/person.rb +98 -0
- data/spec/models/pet.rb +7 -0
- data/spec/models/pet_owner.rb +6 -0
- data/spec/models/phone.rb +7 -0
- data/spec/models/post.rb +15 -0
- data/spec/models/translation.rb +5 -0
- data/spec/models/vet_visit.rb +5 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +141 -0
- data/spec/unit/mongoid/associations/belongs_to_spec.rb +193 -0
- data/spec/unit/mongoid/associations/has_many_related_spec.rb +387 -0
- data/spec/unit/mongoid/associations/has_many_spec.rb +471 -0
- data/spec/unit/mongoid/associations/has_one_related_spec.rb +179 -0
- data/spec/unit/mongoid/associations/has_one_spec.rb +282 -0
- data/spec/unit/mongoid/associations/options_spec.rb +191 -0
- data/spec/unit/mongoid/associations_spec.rb +545 -0
- data/spec/unit/mongoid/attributes_spec.rb +484 -0
- data/spec/unit/mongoid/callbacks_spec.rb +55 -0
- data/spec/unit/mongoid/collection_spec.rb +171 -0
- data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
- data/spec/unit/mongoid/collections/master_spec.rb +41 -0
- data/spec/unit/mongoid/collections/mimic_spec.rb +43 -0
- data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
- data/spec/unit/mongoid/commands/create_spec.rb +30 -0
- data/spec/unit/mongoid/commands/delete_all_spec.rb +58 -0
- data/spec/unit/mongoid/commands/delete_spec.rb +35 -0
- data/spec/unit/mongoid/commands/destroy_all_spec.rb +23 -0
- data/spec/unit/mongoid/commands/destroy_spec.rb +44 -0
- data/spec/unit/mongoid/commands/save_spec.rb +105 -0
- data/spec/unit/mongoid/commands_spec.rb +282 -0
- data/spec/unit/mongoid/config_spec.rb +165 -0
- data/spec/unit/mongoid/contexts/enumerable_spec.rb +374 -0
- data/spec/unit/mongoid/contexts/mongo_spec.rb +505 -0
- data/spec/unit/mongoid/contexts_spec.rb +25 -0
- data/spec/unit/mongoid/criteria_spec.rb +769 -0
- data/spec/unit/mongoid/criterion/complex_spec.rb +19 -0
- data/spec/unit/mongoid/criterion/exclusion_spec.rb +91 -0
- data/spec/unit/mongoid/criterion/inclusion_spec.rb +211 -0
- data/spec/unit/mongoid/criterion/optional_spec.rb +329 -0
- data/spec/unit/mongoid/cursor_spec.rb +74 -0
- data/spec/unit/mongoid/document_spec.rb +986 -0
- data/spec/unit/mongoid/enslavement_spec.rb +63 -0
- data/spec/unit/mongoid/errors_spec.rb +103 -0
- data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
- data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
- data/spec/unit/mongoid/extensions/array/conversions_spec.rb +35 -0
- data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
- data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
- data/spec/unit/mongoid/extensions/date/conversions_spec.rb +102 -0
- data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +70 -0
- data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
- data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
- data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +46 -0
- data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +21 -0
- data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
- data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
- data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
- data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +24 -0
- data/spec/unit/mongoid/extensions/object/conversions_spec.rb +43 -0
- data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
- data/spec/unit/mongoid/extensions/string/conversions_spec.rb +17 -0
- data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
- data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +91 -0
- data/spec/unit/mongoid/extensions/time/conversions_spec.rb +70 -0
- data/spec/unit/mongoid/factory_spec.rb +31 -0
- data/spec/unit/mongoid/field_spec.rb +81 -0
- data/spec/unit/mongoid/fields_spec.rb +158 -0
- data/spec/unit/mongoid/finders_spec.rb +368 -0
- data/spec/unit/mongoid/identity_spec.rb +88 -0
- data/spec/unit/mongoid/indexes_spec.rb +93 -0
- data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
- data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
- data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
- data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
- data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
- data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
- data/spec/unit/mongoid/matchers_spec.rb +329 -0
- data/spec/unit/mongoid/memoization_spec.rb +75 -0
- data/spec/unit/mongoid/named_scope_spec.rb +123 -0
- data/spec/unit/mongoid/scope_spec.rb +240 -0
- data/spec/unit/mongoid/timestamps_spec.rb +25 -0
- data/spec/unit/mongoid/versioning_spec.rb +41 -0
- data/spec/unit/mongoid_spec.rb +37 -0
- 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
|