poly_belongs_to 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -15
- data/lib/poly_belongs_to.rb +6 -96
- data/lib/poly_belongs_to/core.rb +92 -0
- data/lib/poly_belongs_to/dup.rb +13 -10
- data/lib/poly_belongs_to/faked_collection.rb +6 -2
- data/lib/poly_belongs_to/{poly_belongs_to.rb → pbt.rb} +10 -16
- data/lib/poly_belongs_to/singleton_set.rb +45 -0
- data/lib/poly_belongs_to/version.rb +1 -1
- data/test/core_test.rb +203 -0
- data/test/dummy/app/models/alpha.rb +4 -0
- data/test/dummy/app/models/beta.rb +4 -0
- data/test/dummy/app/models/capa.rb +4 -0
- data/test/dummy/app/models/delta.rb +4 -0
- data/test/dummy/db/migrate/20150322233720_create_alphas.rb +10 -0
- data/test/dummy/db/migrate/20150322233733_create_beta.rb +10 -0
- data/test/dummy/db/migrate/20150322233743_create_capas.rb +10 -0
- data/test/dummy/db/migrate/20150322233755_create_delta.rb +10 -0
- data/test/dummy/db/schema.rb +37 -1
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +145 -0
- data/test/dummy/log/test.log +133008 -0
- data/test/dup_test.rb +66 -33
- data/test/faked_collection_test.rb +77 -62
- data/test/pbt_test.rb +93 -89
- data/test/singleton_set_test.rb +44 -0
- data/test/test_helper.rb +2 -2
- metadata +26 -6
- data/test/poly_belongs_to_test.rb +0 -200
data/test/dup_test.rb
CHANGED
@@ -4,41 +4,74 @@ require 'minitest/autorun'
|
|
4
4
|
class DupTest < ActiveSupport::TestCase
|
5
5
|
fixtures :all
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
describe PolyBelongsTo::Dup do
|
8
|
+
it "has method :pbt_dup_build" do
|
9
|
+
User.instance_methods.must_include(:pbt_dup_build)
|
10
|
+
User.methods.must_include(:pbt_dup_build)
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
it "has method :pbt_deep_dup_build" do
|
14
|
+
User.instance_methods.must_include(:pbt_deep_dup_build)
|
15
|
+
User.methods.must_include(:pbt_deep_dup_build)
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
it "#pbt_dup_build builds copy from dup'd attributes" do
|
19
|
+
user = users(:bob)
|
20
|
+
susan_prof = profiles(:susan_prof)
|
21
|
+
contact = user.contacts.new
|
22
|
+
contact.pbt_dup_build( susan_prof )
|
23
|
+
CleanAttrs[contact.profile].must_equal CleanAttrs[susan_prof]
|
24
|
+
end
|
25
|
+
|
26
|
+
it "#pbt_deep_dup_build builds deep copy of dup'd attributes" do
|
27
|
+
user1 = users(:steve)
|
28
|
+
bob_prof = profiles(:bob_prof)
|
29
|
+
contact = user1.contacts.new
|
30
|
+
contact.pbt_deep_dup_build(bob_prof)
|
31
|
+
CleanAttrs[contact.profile ].
|
32
|
+
must_equal CleanAttrs[bob_prof]
|
33
|
+
CleanAttrs[contact.profile.addresses.first ].
|
34
|
+
must_equal CleanAttrs[bob_prof.addresses.first]
|
35
|
+
CleanAttrs[contact.profile.addresses.first.squishies.first ].
|
36
|
+
must_equal CleanAttrs[bob_prof.addresses.first.squishies.first]
|
37
|
+
CleanAttrs[contact.profile.addresses.first.geo_location ].
|
38
|
+
must_equal CleanAttrs[bob_prof.addresses.first.geo_location]
|
39
|
+
CleanAttrs[contact.profile.addresses.first.geo_location.squishies.first ].
|
40
|
+
must_equal CleanAttrs[bob_prof.addresses.first.geo_location.squishies.first]
|
41
|
+
CleanAttrs[contact.profile.addresses.last ].
|
42
|
+
must_equal CleanAttrs[bob_prof.addresses.last]
|
43
|
+
CleanAttrs[contact.profile.phones.first ].
|
44
|
+
must_equal CleanAttrs[bob_prof.phones.first]
|
45
|
+
CleanAttrs[contact.profile.phones.first.squishy ].
|
46
|
+
must_equal CleanAttrs[bob_prof.phones.first.squishy]
|
47
|
+
CleanAttrs[contact.profile.phones.last ].
|
48
|
+
must_equal CleanAttrs[bob_prof.phones.last]
|
49
|
+
CleanAttrs[contact.profile.photo ].
|
50
|
+
must_equal CleanAttrs[bob_prof.photo]
|
51
|
+
end
|
23
52
|
end
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
53
|
+
|
54
|
+
describe "PolyBelongsTo::Dup #pbt_deep_dup_build handles circular references like a champ!" do
|
55
|
+
alpha = Alpha.new; alpha.save
|
56
|
+
beta = alpha.betas.build; beta.save
|
57
|
+
capa = beta.capas.build; capa.save
|
58
|
+
delta = capa.deltas.build; delta.save
|
59
|
+
alpha.update(delta_id: delta.id)
|
60
|
+
it "is a circle" do
|
61
|
+
alpha.pbt_parent.must_equal delta
|
62
|
+
beta.pbt_parent.must_equal alpha
|
63
|
+
capa.pbt_parent.must_equal beta
|
64
|
+
delta.pbt_parent.must_equal capa
|
65
|
+
end
|
66
|
+
it "clones without duplicating cirular reference" do
|
67
|
+
alpha2 = Alpha.new( CleanAttrs[alpha] )
|
68
|
+
CleanAttrs[alpha2].must_equal CleanAttrs[alpha]
|
69
|
+
alpha2.pbt_deep_dup_build(beta)
|
70
|
+
CleanAttrs[alpha2.betas.first].must_equal CleanAttrs[beta]
|
71
|
+
CleanAttrs[alpha2.betas.first.capas.first].must_equal CleanAttrs[capa]
|
72
|
+
CleanAttrs[alpha2.betas.first.capas.first.deltas.first].must_equal CleanAttrs[delta]
|
73
|
+
CleanAttrs[alpha2.betas.first.capas.first.deltas.first.alphas.first].must_equal CleanAttrs[alpha]
|
74
|
+
alpha2.betas.first.capas.first.deltas.first.alphas.first.betas.first.must_be_nil
|
75
|
+
end
|
43
76
|
end
|
44
77
|
end
|
@@ -4,88 +4,103 @@ require 'minitest/autorun'
|
|
4
4
|
class FakedCollectionTest < ActiveSupport::TestCase
|
5
5
|
fixtures :all
|
6
6
|
|
7
|
-
let(:
|
7
|
+
let(:steve_photos){
|
8
8
|
steve_prof = users(:steve).profiles.first
|
9
9
|
PolyBelongsTo::FakedCollection.new(steve_prof, Photo)
|
10
10
|
}
|
11
11
|
|
12
|
-
|
13
|
-
photos.class.name.must_equal "PolyBelongsTo::FakedCollection"
|
14
|
-
end
|
12
|
+
describe PolyBelongsTo::FakedCollection do
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
it "#class.name is named correctly" do
|
15
|
+
steve_photos.class.name.must_equal "PolyBelongsTo::FakedCollection"
|
16
|
+
end
|
19
17
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
18
|
+
it "#superclass knows its superclass" do
|
19
|
+
PolyBelongsTo::FakedCollection.superclass.must_equal Object
|
20
|
+
end
|
24
21
|
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
it "IDs the inner ited on :id" do
|
23
|
+
[nil, photos(:steve_photo).id].must_include steve_photos.id
|
24
|
+
end
|
28
25
|
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
it "#all is an Array" do
|
27
|
+
steve_photos.all.is_a?(Array).must_be_same_as true
|
28
|
+
steve_photos.all.must_be_kind_of(Array)
|
29
|
+
steve_photos.all.must_be_instance_of(Array)
|
30
|
+
end
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
32
|
+
it "#first is the item" do
|
33
|
+
steve_photos.first.class.name.must_equal "Photo"
|
34
|
+
end
|
37
35
|
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
it "#last is the item" do
|
37
|
+
steve_photos.last.class.name.must_equal "Photo"
|
38
|
+
end
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
it "#count and #size counts as 1 or 0" do
|
41
|
+
steve_photos.count.between?(0,1).must_be_same_as true
|
42
|
+
[0,1].must_include steve_photos.count
|
43
|
+
steve_photos.size.between?(0,1).must_be_same_as true
|
44
|
+
[0,1].must_include steve_photos.size
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
it "#ancestors has ActiveRecord::Base ancestor" do
|
48
|
+
steve_photos.ancestors.must_include(ActiveRecord::Base)
|
49
|
+
end
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
it "builds appropriately" do
|
55
|
-
photos.build({content: "cheese"})
|
56
|
-
photos.first.content.must_equal "cheese"
|
57
|
-
end
|
51
|
+
it "build #kind_of? FakedCollection object" do
|
52
|
+
steve_photos.must_be_kind_of(PolyBelongsTo::FakedCollection)
|
53
|
+
end
|
58
54
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
res.class.name.must_equal photos.class.name
|
63
|
-
res.first.content.must_equal "cheese"
|
64
|
-
photos.first.content.must_equal "cheese"
|
65
|
-
end
|
55
|
+
it "build #is_a? FakedCollection object" do
|
56
|
+
steve_photos.is_a?(PolyBelongsTo::FakedCollection).must_be_same_as true
|
57
|
+
end
|
66
58
|
|
67
|
-
|
68
|
-
|
69
|
-
|
59
|
+
it "build #instance_of? FakedCollection object" do
|
60
|
+
steve_photos.must_be_instance_of(PolyBelongsTo::FakedCollection)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "#build builds appropriately" do
|
64
|
+
steve_photos.build({content: "cheese"})
|
65
|
+
steve_photos.first.content.must_equal "cheese"
|
70
66
|
end
|
71
|
-
end
|
72
67
|
|
73
|
-
|
74
|
-
|
75
|
-
|
68
|
+
it "#build returns self and not nil" do
|
69
|
+
res = steve_photos.build({content: "cheese"})
|
70
|
+
res.wont_be_nil
|
71
|
+
res.class.name.must_equal steve_photos.class.name
|
72
|
+
res.first.content.must_equal "cheese"
|
73
|
+
steve_photos.first.content.must_equal "cheese"
|
74
|
+
end
|
76
75
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
76
|
+
it "#each loops appropriately" do
|
77
|
+
steve_photos.each do |photo|
|
78
|
+
photo.class.name.must_equal "Photo"
|
79
|
+
end
|
80
|
+
end
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
82
|
+
it "defines #klass to point to inner items class" do
|
83
|
+
steve_photos.klass.name.must_equal "Photo"
|
84
|
+
end
|
85
|
+
|
86
|
+
it "#respond_to? :first and :last" do
|
87
|
+
steve_photos.must_respond_to(:first)
|
88
|
+
steve_photos.must_respond_to(:last)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "knows sneeze is a missing method" do
|
92
|
+
->{steve_photos.sneeze}.must_raise NoMethodError
|
93
|
+
end
|
94
|
+
|
95
|
+
it "has method_missing forward appropriate calls" do
|
96
|
+
steve_photos.method_missing(:nil?).must_equal false
|
97
|
+
end
|
98
|
+
|
99
|
+
it "will not initialize on has_many" do
|
100
|
+
steve = users(:steve)
|
101
|
+
->{ PolyBelongsTo::FakedCollection.new(steve, Profile) }.must_raise RuntimeError
|
102
|
+
end
|
85
103
|
|
86
|
-
it "will not initialize on has_many" do
|
87
|
-
steve = users(:steve)
|
88
|
-
->{ PolyBelongsTo::FakedCollection.new(steve, Profile) }.must_raise RuntimeError
|
89
104
|
end
|
90
105
|
|
91
106
|
end
|
data/test/pbt_test.rb
CHANGED
@@ -4,106 +4,110 @@ require 'minitest/autorun'
|
|
4
4
|
class PbtTest < ActiveSupport::TestCase
|
5
5
|
fixtures :all
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
describe PolyBelongsTo::Pbt do
|
8
|
+
it "AttrSanitizer removes conflicting attributes" do
|
9
|
+
user = users(:bob)
|
10
|
+
PolyBelongsTo::Pbt::AttrSanitizer[user].must_equal Hash[id: nil, content: user.content].stringify_keys
|
11
|
+
PolyBelongsTo::Pbt::AttrSanitizer[nil ].must_equal Hash[]
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
it "BuildCmd returns build command" do
|
15
|
+
profile = profiles(:bob_prof)
|
16
|
+
"#{PolyBelongsTo::Pbt::BuildCmd[profile,Phone]}".must_equal "phones.build"
|
17
|
+
"#{PolyBelongsTo::Pbt::BuildCmd[profile,Photo]}".must_equal "build_photo"
|
18
|
+
PolyBelongsTo::Pbt::BuildCmd[nil, Photo].must_be_nil
|
19
|
+
PolyBelongsTo::Pbt::BuildCmd[profile, nil].must_be_nil
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
it "Reflects retruns has_one and has_many relationships" do
|
23
|
+
profile = profiles(:bob_prof)
|
24
|
+
PolyBelongsTo::Pbt::Reflects[profile].sort.must_equal [:phones, :addresses, :photo].sort
|
25
|
+
PolyBelongsTo::Pbt::Reflects[nil ].must_equal Array[]
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
it "ReflectsAsClasses one and many relations as classes" do
|
29
|
+
profile = profiles(:bob_prof)
|
30
|
+
PolyBelongsTo::Pbt::ReflectsAsClasses[profile].map(&:hash).sort.must_equal [Phone, Address, Photo].map(&:hash).sort
|
31
|
+
PolyBelongsTo::Pbt::ReflectsAsClasses[nil ].must_equal Array[]
|
32
|
+
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
it "IsReflected gives boolean of child" do
|
35
|
+
profile = profiles(:bob_prof)
|
36
|
+
PolyBelongsTo::Pbt::IsReflected[profile, Phone].must_equal true
|
37
|
+
PolyBelongsTo::Pbt::IsReflected[profile,Address].must_equal true
|
38
|
+
PolyBelongsTo::Pbt::IsReflected[profile, Photo].must_equal true
|
39
|
+
PolyBelongsTo::Pbt::IsReflected[profile, User].must_equal false
|
40
|
+
PolyBelongsTo::Pbt::IsReflected[nil, User].must_equal false
|
41
|
+
PolyBelongsTo::Pbt::IsReflected[profile, nil].must_equal false
|
42
|
+
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
it "SingularOrPlural responds for child relations" do
|
45
|
+
profile = profiles(:susan_prof)
|
46
|
+
PolyBelongsTo::Pbt::SingularOrPlural[profile,Phone].must_equal :plural
|
47
|
+
PolyBelongsTo::Pbt::SingularOrPlural[profile,Photo].must_equal :singular
|
48
|
+
PolyBelongsTo::Pbt::SingularOrPlural[profile, User].must_be_nil
|
49
|
+
PolyBelongsTo::Pbt::SingularOrPlural[nil, User].must_be_nil
|
50
|
+
PolyBelongsTo::Pbt::SingularOrPlural[profile, nil].must_be_nil
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
53
|
+
it "IsSingular tells child singleness" do
|
54
|
+
profile = profiles(:steve_prof)
|
55
|
+
PolyBelongsTo::Pbt::IsSingular[profile,Phone].must_be_same_as false
|
56
|
+
PolyBelongsTo::Pbt::IsSingular[nil, Phone].must_be_same_as false
|
57
|
+
PolyBelongsTo::Pbt::IsSingular[profile, nil].must_be_same_as false
|
58
|
+
PolyBelongsTo::Pbt::IsSingular[profile,Photo].must_be_same_as true
|
59
|
+
end
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
it "IsPlural tells child pluralness" do
|
62
|
+
profile = profiles(:bob_prof)
|
63
|
+
PolyBelongsTo::Pbt::IsPlural[profile,Phone].must_be_same_as true
|
64
|
+
PolyBelongsTo::Pbt::IsPlural[profile,Photo].must_be_same_as false
|
65
|
+
PolyBelongsTo::Pbt::IsPlural[nil, Photo].must_be_same_as false
|
66
|
+
PolyBelongsTo::Pbt::IsPlural[profile, nil].must_be_same_as false
|
67
|
+
end
|
67
68
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
69
|
+
it "CollectionProxy singular or plural proxy name" do
|
70
|
+
profile = profiles(:steve_prof)
|
71
|
+
PolyBelongsTo::Pbt::CollectionProxy[profile,Phone].must_equal :phones
|
72
|
+
PolyBelongsTo::Pbt::CollectionProxy[profile,Photo].must_equal :photo
|
73
|
+
PolyBelongsTo::Pbt::CollectionProxy[profile, User].must_be_nil
|
74
|
+
PolyBelongsTo::Pbt::CollectionProxy[nil, User].must_be_nil
|
75
|
+
PolyBelongsTo::Pbt::CollectionProxy[profile, nil].must_be_nil
|
76
|
+
end
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
78
|
+
it "AsCollectionProxy has_one emulated collectionproxy" do
|
79
|
+
address = profiles(:bob_prof).addresses.first
|
80
|
+
address_to_geo = PolyBelongsTo::Pbt::AsCollectionProxy[address, GeoLocation]
|
81
|
+
address_to_geo.must_respond_to(:klass)
|
82
|
+
address_to_geo.must_respond_to(:build)
|
83
|
+
address_to_geo.must_respond_to(:each )
|
84
|
+
address_to_geo.must_respond_to(:all )
|
85
|
+
address_to_geo.must_respond_to(:first)
|
86
|
+
address_to_geo.must_respond_to(:last )
|
87
|
+
address_to_geo.must_be_kind_of(PolyBelongsTo::FakedCollection)
|
88
|
+
end
|
88
89
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
90
|
+
it "AsCollectionProxy has one or zero items" do
|
91
|
+
address = profiles(:bob_prof).addresses.first
|
92
|
+
address_to_geo = PolyBelongsTo::Pbt::AsCollectionProxy[address, GeoLocation]
|
93
|
+
address_to_geo.count.between?(0,1).must_be_same_as true
|
94
|
+
[0,1].must_include address_to_geo.count
|
95
|
+
address_to_geo.size.between?(0,1).must_be_same_as true
|
96
|
+
[0,1].must_include address_to_geo.size
|
97
|
+
end
|
95
98
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
99
|
+
|
100
|
+
it "AsCollectionProxy has_many uses ActiveRecord::Associations::CollectionProxy" do
|
101
|
+
bob = users(:bob)
|
102
|
+
bob_to_prof = PolyBelongsTo::Pbt::AsCollectionProxy[bob, Profile]
|
103
|
+
bob_to_prof.must_respond_to(:klass)
|
104
|
+
bob_to_prof.must_respond_to(:build)
|
105
|
+
bob_to_prof.must_respond_to(:each )
|
106
|
+
bob_to_prof.must_respond_to(:all )
|
107
|
+
bob_to_prof.must_respond_to(:first)
|
108
|
+
bob_to_prof.must_respond_to(:last )
|
109
|
+
bob_to_prof.must_be_kind_of(ActiveRecord::Associations::CollectionProxy)
|
110
|
+
end
|
107
111
|
end
|
108
112
|
|
109
113
|
end
|