poly_belongs_to 0.1.8 → 0.1.9
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.
- 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
|