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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2485663b8e0b1364a05b151975b527c56e95bada
|
4
|
+
data.tar.gz: 33338ae33151a22083b535ea79a706b237cf64aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52ceb7ef74ed74c91012ae7ac3fa662da98653ee5258f538544911147ff873eaafad836b39bd095532ae28c79bbe07071ab62a7b636f4cc000a5748f69f0310c
|
7
|
+
data.tar.gz: 5c0e6bd0b258619346e12753beb23a15ea830f884d19eee585a137b692ac1309575dfc2c9e7f7e041794c3044fae8ab4facf597e29fc2ab2e6f712cc908f72d8
|
data/README.md
CHANGED
@@ -144,25 +144,18 @@ otherwise**. You can duplicate a record, or use a self recursive command **pbt_
|
|
144
144
|
to duplicate a record and all of it's has_one/has_many children records at once. Afterwards
|
145
145
|
be sure to use the save method.
|
146
146
|
|
147
|
-
> NOTE: This will need to be included manually. The reason for this is because you need to
|
148
|
-
know what's involved when using this. It's purposefully done this way to lead to reading
|
149
|
-
the documentation for PolyBelongsTo's duplication methods.
|
150
147
|
|
151
148
|
####Known Issues
|
152
149
|
- Carrierwave records won't duplicate. To ensure that other records will still save and
|
153
150
|
prevent any rollback issues use .save(validate: false) ... I'm considering possible options
|
154
151
|
to remedy this and
|
155
152
|
other scenarios.
|
156
|
-
- For deep duplication you need to be very aware of the potential for infinite loops with
|
157
|
-
your records if there are any circular references
|
153
|
+
- **PROBLEM SOLVED** ~~For deep duplication you need to be very aware of the potential for infinite loops with
|
154
|
+
your records if there are any circular references.~~
|
158
155
|
|
159
156
|
###How To Use
|
160
157
|
|
161
|
-
|
162
|
-
```ruby
|
163
|
-
ActiveRecord::Base.send(:include, PolyBelongsTo::Dup)
|
164
|
-
```
|
165
|
-
Then use the dup/build methods as follows
|
158
|
+
Use the dup/build methods as follows
|
166
159
|
|
167
160
|
```ruby
|
168
161
|
# If you were to create a new contact for example
|
@@ -183,11 +176,6 @@ contact.pbt_deep_dup_build( User.last.profile )
|
|
183
176
|
contact.save
|
184
177
|
```
|
185
178
|
|
186
|
-
##Planning
|
187
|
-
|
188
|
-
I'm in the process of planning mapping out record hierarchy. Also with this
|
189
|
-
it will add recognition for circular references.
|
190
|
-
|
191
179
|
##Contributing
|
192
180
|
|
193
181
|
Feel free to fork and make pull requests. Please bring up an issue before a pull
|
data/lib/poly_belongs_to.rb
CHANGED
@@ -2,103 +2,13 @@
|
|
2
2
|
# The MIT License (MIT)
|
3
3
|
# Copyright (C) 2015 by Daniel P. Clark
|
4
4
|
$: << File.join(File.dirname(__FILE__), "/poly_belongs_to")
|
5
|
+
require 'active_support/concern'
|
5
6
|
require 'poly_belongs_to/version'
|
7
|
+
require 'poly_belongs_to/core'
|
8
|
+
require 'poly_belongs_to/singleton_set'
|
6
9
|
require 'poly_belongs_to/dup'
|
7
|
-
require 'poly_belongs_to/
|
10
|
+
require 'poly_belongs_to/pbt'
|
8
11
|
require 'poly_belongs_to/faked_collection'
|
9
|
-
|
10
|
-
|
11
|
-
module PolyBelongsTo
|
12
|
-
module Core
|
13
|
-
extend ActiveSupport::Concern
|
14
|
-
|
15
|
-
included do
|
16
|
-
def self.pbt
|
17
|
-
reflect_on_all_associations(:belongs_to).first.try(:name)
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.pbts
|
21
|
-
reflect_on_all_associations(:belongs_to).map(&:name)
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.poly?
|
25
|
-
!!reflect_on_all_associations(:belongs_to).first.try {|i| i.options[:polymorphic] }
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.pbt_params_name(allow_as_nested = true)
|
29
|
-
if poly?
|
30
|
-
allow_as_nested ? "#{table_name}_attributes".to_sym : name.downcase.to_sym
|
31
|
-
else
|
32
|
-
name.downcase.to_sym
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.pbt_id_sym
|
37
|
-
val = pbt
|
38
|
-
val ? "#{val}_id".to_sym : nil
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.pbt_type_sym
|
42
|
-
poly? ? "#{pbt}_type".to_sym : nil
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def pbt
|
47
|
-
self.class.pbt
|
48
|
-
end
|
49
|
-
|
50
|
-
def pbts
|
51
|
-
self.class.pbts
|
52
|
-
end
|
53
|
-
|
54
|
-
def poly?
|
55
|
-
self.class.poly?
|
56
|
-
end
|
57
|
-
|
58
|
-
def pbt_id
|
59
|
-
val = pbt
|
60
|
-
val ? eval("self.#{val}_id") : nil
|
61
|
-
end
|
62
|
-
|
63
|
-
def pbt_type
|
64
|
-
poly? ? eval("self.#{pbt}_type") : nil
|
65
|
-
end
|
66
|
-
|
67
|
-
def pbt_parent
|
68
|
-
val = pbt
|
69
|
-
if val
|
70
|
-
if poly?
|
71
|
-
eval "#{pbt_type}.find(#{pbt_id})"
|
72
|
-
else
|
73
|
-
eval "#{val.capitalize.to_s}.find(#{pbt_id})"
|
74
|
-
end
|
75
|
-
else
|
76
|
-
nil
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def pbt_parents
|
81
|
-
if poly?
|
82
|
-
Array[pbt_parent].compact
|
83
|
-
else
|
84
|
-
self.class.pbts.map {|i|
|
85
|
-
try{ eval("#{i.capitalize}").find eval("self.#{i}_id") }
|
86
|
-
}.compact
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def pbt_id_sym
|
91
|
-
self.class.pbt_id_sym
|
92
|
-
end
|
93
|
-
|
94
|
-
def pbt_type_sym
|
95
|
-
self.class.pbt_type_sym
|
96
|
-
end
|
97
|
-
|
98
|
-
def pbt_params_name(allow_as_nested = true)
|
99
|
-
self.class.pbt_params_name(allow_as_nested)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
12
|
+
ActiveRecord::Base.send(:include, PolyBelongsTo::Core )
|
13
|
+
ActiveRecord::Base.send(:include, PolyBelongsTo::Dup )
|
103
14
|
|
104
|
-
ActiveRecord::Base.send(:include, PolyBelongsTo::Core)
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module PolyBelongsTo
|
2
|
+
module Core
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def self.pbt
|
7
|
+
reflect_on_all_associations(:belongs_to).first.try(:name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.pbts
|
11
|
+
reflect_on_all_associations(:belongs_to).map(&:name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.poly?
|
15
|
+
!!reflect_on_all_associations(:belongs_to).first.try {|i| i.options[:polymorphic] }
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.pbt_params_name(allow_as_nested = true)
|
19
|
+
if poly?
|
20
|
+
allow_as_nested ? "#{table_name}_attributes".to_sym : name.downcase.to_sym
|
21
|
+
else
|
22
|
+
name.downcase.to_sym
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.pbt_id_sym
|
27
|
+
val = pbt
|
28
|
+
val ? "#{val}_id".to_sym : nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.pbt_type_sym
|
32
|
+
poly? ? "#{pbt}_type".to_sym : nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def pbt
|
37
|
+
self.class.pbt
|
38
|
+
end
|
39
|
+
|
40
|
+
def pbts
|
41
|
+
self.class.pbts
|
42
|
+
end
|
43
|
+
|
44
|
+
def poly?
|
45
|
+
self.class.poly?
|
46
|
+
end
|
47
|
+
|
48
|
+
def pbt_id
|
49
|
+
val = pbt
|
50
|
+
val ? self.send("#{val}_id") : nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def pbt_type
|
54
|
+
poly? ? self.send("#{pbt}_type") : nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def pbt_parent
|
58
|
+
val = pbt
|
59
|
+
if val
|
60
|
+
if poly?
|
61
|
+
"#{pbt_type}".constantize.find(pbt_id)
|
62
|
+
else
|
63
|
+
"#{val.capitalize}".constantize.find(pbt_id)
|
64
|
+
end
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def pbt_parents
|
71
|
+
if poly?
|
72
|
+
Array[pbt_parent].compact
|
73
|
+
else
|
74
|
+
self.class.pbts.map {|i|
|
75
|
+
try{ "#{i.capitalize}".constantize.find(self.send("#{i}_id")) }
|
76
|
+
}.compact
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def pbt_id_sym
|
81
|
+
self.class.pbt_id_sym
|
82
|
+
end
|
83
|
+
|
84
|
+
def pbt_type_sym
|
85
|
+
self.class.pbt_type_sym
|
86
|
+
end
|
87
|
+
|
88
|
+
def pbt_params_name(allow_as_nested = true)
|
89
|
+
self.class.pbt_params_name(allow_as_nested)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/poly_belongs_to/dup.rb
CHANGED
@@ -4,34 +4,37 @@ module PolyBelongsTo
|
|
4
4
|
|
5
5
|
included do
|
6
6
|
def self.pbt_dup_build(item_to_build_on, item_to_duplicate)
|
7
|
+
singleton_record = yield if block_given?
|
7
8
|
if PolyBelongsTo::Pbt::IsReflected[item_to_build_on, item_to_duplicate]
|
8
9
|
PolyBelongsTo::Pbt::AsCollectionProxy[item_to_build_on, item_to_duplicate].
|
9
|
-
build PolyBelongsTo::Pbt::AttrSanitizer[item_to_duplicate]
|
10
|
+
build PolyBelongsTo::Pbt::AttrSanitizer[item_to_duplicate] if (
|
11
|
+
block_given? ? singleton_record.add?(item_to_duplicate) : true)
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
13
15
|
def self.pbt_deep_dup_build(item_to_build_on, item_to_duplicate)
|
14
|
-
|
16
|
+
singleton_record = (block_given? ? yield : PolyBelongsTo::SingletonSet.new)
|
17
|
+
pbt_dup_build(item_to_build_on, item_to_duplicate) {singleton_record}
|
15
18
|
PolyBelongsTo::Pbt::Reflects[item_to_duplicate].each do |ref|
|
16
|
-
child =
|
19
|
+
child = item_to_duplicate.send(ref)
|
17
20
|
PolyBelongsTo::Pbt::AsCollectionProxy[item_to_build_on, item_to_duplicate].
|
18
21
|
each do |builder|
|
19
22
|
child.respond_to?(:build) ? child.each {|spawn|
|
20
|
-
builder.pbt_deep_dup_build(spawn)
|
21
|
-
} : builder.pbt_deep_dup_build(child)
|
22
|
-
|
23
|
+
builder.pbt_deep_dup_build(spawn) {singleton_record}
|
24
|
+
} : builder.pbt_deep_dup_build(child) {singleton_record}
|
25
|
+
end unless singleton_record.include?(item_to_build_on)
|
23
26
|
end
|
24
27
|
item_to_build_on
|
25
28
|
end
|
26
29
|
|
27
30
|
end
|
28
31
|
|
29
|
-
def pbt_dup_build(item_to_duplicate)
|
30
|
-
self.class.pbt_dup_build(self, item_to_duplicate)
|
32
|
+
def pbt_dup_build(item_to_duplicate, &block)
|
33
|
+
self.class.pbt_dup_build(self, item_to_duplicate, &block)
|
31
34
|
end
|
32
35
|
|
33
|
-
def pbt_deep_dup_build(item_to_duplicate)
|
34
|
-
self.class.pbt_deep_dup_build(self, item_to_duplicate)
|
36
|
+
def pbt_deep_dup_build(item_to_duplicate, &block)
|
37
|
+
self.class.pbt_deep_dup_build(self, item_to_duplicate, &block)
|
35
38
|
end
|
36
39
|
|
37
40
|
end
|
@@ -4,10 +4,14 @@ module PolyBelongsTo
|
|
4
4
|
raise "Not a has_one rleationship for FakedCollection" unless PolyBelongsTo::Pbt::IsSingular[obj,child]
|
5
5
|
@obj = obj
|
6
6
|
@child = child
|
7
|
-
@instance =
|
7
|
+
@instance = @obj.send(PolyBelongsTo::Pbt::CollectionProxy[@obj,@child])
|
8
8
|
self
|
9
9
|
end
|
10
10
|
|
11
|
+
def id
|
12
|
+
@instance.try(:id)
|
13
|
+
end
|
14
|
+
|
11
15
|
def all
|
12
16
|
Array[@instance].compact
|
13
17
|
end
|
@@ -45,7 +49,7 @@ module PolyBelongsTo
|
|
45
49
|
end
|
46
50
|
|
47
51
|
def build(*args)
|
48
|
-
@instance =
|
52
|
+
@instance = @obj.send(PolyBelongsTo::Pbt::BuildCmd[@obj, @child], *args)
|
49
53
|
self
|
50
54
|
end
|
51
55
|
|
@@ -9,25 +9,25 @@ module PolyBelongsTo
|
|
9
9
|
|
10
10
|
BuildCmd = lambda {|obj, child|
|
11
11
|
return nil unless obj && child
|
12
|
-
dup_name =
|
12
|
+
dup_name = CollectionProxy[obj, child]
|
13
13
|
IsSingular[obj, child] ? "build_#{dup_name}" : IsPlural[obj, child] ? "#{dup_name}.build" : nil
|
14
14
|
}
|
15
15
|
|
16
16
|
Reflects = lambda {|obj|
|
17
17
|
return [] unless obj
|
18
18
|
[:has_one, :has_many].map { |has|
|
19
|
-
|
19
|
+
obj.class.name.constantize.reflect_on_all_associations(has).map(&:name).map(&:to_sym)
|
20
20
|
}.flatten
|
21
21
|
}
|
22
22
|
|
23
23
|
ReflectsAsClasses = lambda {|obj|
|
24
24
|
Reflects[obj].map {|ref|
|
25
|
-
|
25
|
+
(obj.send(ref).try(:klass) || obj.send(ref).class).name.constantize
|
26
26
|
}
|
27
27
|
}
|
28
28
|
|
29
|
-
IsReflected = lambda {|obj,child|
|
30
|
-
!!
|
29
|
+
IsReflected = lambda {|obj, child|
|
30
|
+
!!CollectionProxy[obj, child]
|
31
31
|
}
|
32
32
|
|
33
33
|
SingularOrPlural = lambda {|obj, child|
|
@@ -35,7 +35,7 @@ module PolyBelongsTo
|
|
35
35
|
reflects = Reflects[obj]
|
36
36
|
if reflects.include?(ActiveModel::Naming.singular(child).to_sym)
|
37
37
|
:singular
|
38
|
-
elsif
|
38
|
+
elsif CollectionProxy[obj, child]
|
39
39
|
:plural
|
40
40
|
else
|
41
41
|
nil
|
@@ -52,20 +52,14 @@ module PolyBelongsTo
|
|
52
52
|
|
53
53
|
CollectionProxy = lambda {|obj, child|
|
54
54
|
return nil unless obj && child
|
55
|
-
|
56
|
-
|
57
|
-
return proxy if reflects.include? proxy
|
58
|
-
proxy = ActiveModel::Naming.plural(child).to_sym
|
59
|
-
reflects.include?(proxy) ? proxy : nil
|
55
|
+
names = [ActiveModel::Naming.singular(child).to_s, ActiveModel::Naming.plural(child).to_s].uniq
|
56
|
+
Reflects[obj].detect {|ref| "#{ref}"[/(?:#{ names.join('|') }).{,3}/]}
|
60
57
|
}
|
61
58
|
|
62
59
|
AsCollectionProxy = lambda {|obj, child|
|
63
60
|
return [] unless obj && child
|
64
|
-
|
65
|
-
|
66
|
-
return PolyBelongsTo::FakedCollection.new(obj, child) if reflects.include? proxy
|
67
|
-
proxy = ActiveModel::Naming.plural(child).to_sym
|
68
|
-
reflects.include?(proxy) ? eval("obj.#{PolyBelongsTo::Pbt::CollectionProxy[obj, child]}") : []
|
61
|
+
return PolyBelongsTo::FakedCollection.new(obj, child) if IsSingular[obj, child]
|
62
|
+
!!CollectionProxy[obj, child] ? obj.send(PolyBelongsTo::Pbt::CollectionProxy[obj, child]) : []
|
69
63
|
}
|
70
64
|
end
|
71
65
|
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'set'
|
2
|
+
module PolyBelongsTo
|
3
|
+
class SingletonSet
|
4
|
+
def initialize
|
5
|
+
@set = Set.new
|
6
|
+
@flagged = Set.new
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
def formatted_name(record)
|
11
|
+
"#{record.class.name}-#{record.id}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def add?(record)
|
15
|
+
result = @set.add?( formatted_name( record ) )
|
16
|
+
return result if result
|
17
|
+
flag(record)
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(record)
|
22
|
+
add?(record)
|
23
|
+
end
|
24
|
+
|
25
|
+
def <<(record)
|
26
|
+
add?(record)
|
27
|
+
end
|
28
|
+
|
29
|
+
def include?(record)
|
30
|
+
@set.include?(formatted_name(record))
|
31
|
+
end
|
32
|
+
|
33
|
+
def flag(record)
|
34
|
+
@flagged << formatted_name(record)
|
35
|
+
end
|
36
|
+
|
37
|
+
def flagged?(record)
|
38
|
+
@flagged.include?(formatted_name(record))
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_missing(mthd)
|
42
|
+
@set.send(mthd)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|