amoeba 1.2.1 → 3.2.0
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 +7 -0
- data/.cane +4 -0
- data/.gitignore +4 -1
- data/.rspec +2 -0
- data/.rubocop.yml +17 -0
- data/.travis.yml +110 -0
- data/Appraisals +76 -0
- data/Gemfile +11 -3
- data/README.md +763 -529
- data/Rakefile +6 -1
- data/amoeba.gemspec +20 -15
- data/defaults.reek +11 -0
- data/gemfiles/activerecord_4.2.gemfile +18 -0
- data/gemfiles/activerecord_5.0.gemfile +18 -0
- data/gemfiles/activerecord_5.1.gemfile +18 -0
- data/gemfiles/activerecord_5.2.gemfile +18 -0
- data/gemfiles/activerecord_6.0.gemfile +18 -0
- data/gemfiles/activerecord_6.1.gemfile +18 -0
- data/gemfiles/activerecord_head.gemfile +24 -0
- data/gemfiles/jruby_activerecord_6.1.gemfile +19 -0
- data/gemfiles/jruby_activerecord_head.gemfile +28 -0
- data/lib/amoeba.rb +13 -517
- data/lib/amoeba/class_methods.rb +28 -0
- data/lib/amoeba/cloner.rb +172 -0
- data/lib/amoeba/config.rb +182 -0
- data/lib/amoeba/instance_methods.rb +37 -0
- data/lib/amoeba/macros.rb +14 -0
- data/lib/amoeba/macros/base.rb +26 -0
- data/lib/amoeba/macros/has_and_belongs_to_many.rb +19 -0
- data/lib/amoeba/macros/has_many.rb +42 -0
- data/lib/amoeba/macros/has_one.rb +15 -0
- data/lib/amoeba/version.rb +1 -1
- data/spec/lib/amoeba_spec.rb +336 -111
- data/spec/spec_helper.rb +24 -3
- data/spec/support/data.rb +65 -84
- data/spec/support/models.rb +241 -25
- data/spec/support/schema.rb +102 -41
- metadata +63 -70
- data/.rvmrc +0 -1
@@ -0,0 +1,19 @@
|
|
1
|
+
module Amoeba
|
2
|
+
module Macros
|
3
|
+
class HasAndBelongsToMany < ::Amoeba::Macros::Base
|
4
|
+
def follow(relation_name, _association)
|
5
|
+
clone = @cloner.amoeba.clones.include?(relation_name.to_sym)
|
6
|
+
@old_object.__send__(relation_name).each do |old_obj|
|
7
|
+
fill_relation(relation_name, old_obj, clone)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def fill_relation(relation_name, old_obj, clone)
|
12
|
+
# associate this new child to the new parent object
|
13
|
+
old_obj = old_obj.amoeba_dup if clone
|
14
|
+
relation_name = remapped_relation_name(relation_name)
|
15
|
+
@new_object.__send__(relation_name) << old_obj
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Amoeba
|
2
|
+
module Macros
|
3
|
+
class HasMany < ::Amoeba::Macros::Base
|
4
|
+
def follow(relation_name, association)
|
5
|
+
if @cloner.amoeba.clones.include?(relation_name.to_sym)
|
6
|
+
follow_with_clone(relation_name)
|
7
|
+
else
|
8
|
+
follow_without_clone(relation_name, association)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def follow_with_clone(relation_name)
|
13
|
+
# This is a M:M "has many through" where we
|
14
|
+
# actually copy and reassociate the new children
|
15
|
+
# rather than only maintaining the associations
|
16
|
+
@old_object.__send__(relation_name).each do |old_obj|
|
17
|
+
relation_name = remapped_relation_name(relation_name)
|
18
|
+
# associate this new child to the new parent object
|
19
|
+
@new_object.__send__(relation_name) << old_obj.amoeba_dup
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def follow_without_clone(relation_name, association)
|
24
|
+
# This is a regular 1:M "has many"
|
25
|
+
#
|
26
|
+
# copying the children of the regular has many will
|
27
|
+
# effectively do what is desired anyway, the through
|
28
|
+
# association is really just for convenience usage
|
29
|
+
# on the model
|
30
|
+
return if association.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
31
|
+
|
32
|
+
@old_object.__send__(relation_name).each do |old_obj|
|
33
|
+
copy_of_obj = old_obj.amoeba_dup(@options)
|
34
|
+
copy_of_obj[:"#{association.foreign_key}"] = nil
|
35
|
+
relation_name = remapped_relation_name(relation_name)
|
36
|
+
# associate this new child to the new parent object
|
37
|
+
@new_object.__send__(relation_name) << copy_of_obj
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Amoeba
|
2
|
+
module Macros
|
3
|
+
class HasOne < ::Amoeba::Macros::Base
|
4
|
+
def follow(relation_name, association)
|
5
|
+
return if association.is_a?(::ActiveRecord::Reflection::ThroughReflection)
|
6
|
+
old_obj = @old_object.__send__(relation_name)
|
7
|
+
return unless old_obj
|
8
|
+
copy_of_obj = old_obj.amoeba_dup(@options)
|
9
|
+
copy_of_obj[:"#{association.foreign_key}"] = nil
|
10
|
+
relation_name = remapped_relation_name(relation_name)
|
11
|
+
@new_object.__send__(:"#{relation_name}=", copy_of_obj)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/amoeba/version.rb
CHANGED
data/spec/lib/amoeba_spec.rb
CHANGED
@@ -1,18 +1,23 @@
|
|
1
|
-
require 'active_record'
|
2
1
|
require 'spec_helper'
|
3
2
|
|
4
|
-
describe
|
5
|
-
context
|
6
|
-
|
3
|
+
describe 'amoeba' do
|
4
|
+
context 'dup' do
|
5
|
+
before :each do
|
6
|
+
require ::File.dirname(__FILE__) + '/../support/data.rb'
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:first_product) { Product.find(1) }
|
10
|
+
|
11
|
+
it 'duplicates associated child records' do
|
7
12
|
# Posts {{{
|
8
|
-
old_post = Post.find(1)
|
9
|
-
old_post.comments.map(&:contents).include?(
|
13
|
+
old_post = ::Post.find(1)
|
14
|
+
expect(old_post.comments.map(&:contents).include?('I love it!')).to be_truthy
|
10
15
|
|
11
16
|
old_post.class.amoeba do
|
12
|
-
prepend :
|
17
|
+
prepend contents: "Here's a copy: "
|
13
18
|
end
|
14
19
|
|
15
|
-
new_post = old_post.
|
20
|
+
new_post = old_post.amoeba_dup
|
16
21
|
|
17
22
|
start_account_count = Account.all.count
|
18
23
|
start_history_count = History.all.count
|
@@ -27,18 +32,16 @@ describe "amoeba" do
|
|
27
32
|
start_postconfig_count = PostConfig.all.count
|
28
33
|
start_postwidget_count = PostWidget.all.count
|
29
34
|
start_superkitten_count = Superkitten.all.count
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end_cat_count = Category.all.count
|
41
|
-
end_supercat_count = Supercat.all.count
|
35
|
+
start_posttag_count = Post.tag_count
|
36
|
+
start_postnote_count = Post.note_count
|
37
|
+
|
38
|
+
expect(new_post.save!).to be_truthy
|
39
|
+
expect(new_post.title).to eq("Copy of #{old_post.title}")
|
40
|
+
|
41
|
+
end_account_count = Account.count
|
42
|
+
end_history_count = History.count
|
43
|
+
end_cat_count = Category.count
|
44
|
+
end_supercat_count = Supercat.count
|
42
45
|
end_tag_count = Tag.all.count
|
43
46
|
end_note_count = Note.all.count
|
44
47
|
end_widget_count = Widget.all.count
|
@@ -48,132 +51,354 @@ describe "amoeba" do
|
|
48
51
|
end_postconfig_count = PostConfig.all.count
|
49
52
|
end_postwidget_count = PostWidget.all.count
|
50
53
|
end_superkitten_count = Superkitten.all.count
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
new_post.supercats.map(&:
|
73
|
-
new_post.
|
74
|
-
new_post.
|
75
|
-
new_post.
|
76
|
-
new_post.
|
77
|
-
new_post.comments.
|
78
|
-
new_post.comments.select{ |c| c.nerf == '
|
79
|
-
new_post.comments.select{ |c| c.nerf == 'ratatat' }.length.should == 2
|
80
|
-
new_post.comments.select{ |c| c.nerf == 'bonk' }.length.should == 1
|
81
|
-
new_post.comments.select{ |c| c.nerf == 'bonkers' && c.contents.nil? }.length.should == 1
|
54
|
+
end_posttag_count = Post.tag_count
|
55
|
+
end_postnote_count = Post.note_count
|
56
|
+
|
57
|
+
expect(end_tag_count).to eq(start_tag_count)
|
58
|
+
expect(end_cat_count).to eq(start_cat_count)
|
59
|
+
expect(end_account_count).to eq(start_account_count * 2)
|
60
|
+
expect(end_history_count).to eq(start_history_count * 2)
|
61
|
+
expect(end_supercat_count).to eq(start_supercat_count * 2)
|
62
|
+
expect(end_post_count).to eq(start_post_count * 2)
|
63
|
+
expect(end_comment_count).to eq((start_comment_count * 2) + 2)
|
64
|
+
expect(end_rating_count).to eq(start_rating_count * 2)
|
65
|
+
expect(end_postconfig_count).to eq(start_postconfig_count * 2)
|
66
|
+
expect(end_posttag_count).to eq(start_posttag_count * 2)
|
67
|
+
expect(end_widget_count).to eq(start_widget_count * 2)
|
68
|
+
expect(end_postwidget_count).to eq(start_postwidget_count * 2)
|
69
|
+
expect(end_note_count).to eq(start_note_count * 2)
|
70
|
+
expect(end_postnote_count).to eq(start_postnote_count * 2)
|
71
|
+
expect(end_superkitten_count).to eq(start_superkitten_count * 2)
|
72
|
+
|
73
|
+
expect(new_post.supercats.map(&:ramblings)).to include('Copy of zomg')
|
74
|
+
expect(new_post.supercats.map(&:other_ramblings).uniq.length).to eq(1)
|
75
|
+
expect(new_post.supercats.map(&:other_ramblings).uniq).to include('La la la')
|
76
|
+
expect(new_post.contents).to eq("Here's a copy: #{old_post.contents.gsub(/dog/, 'cat')} (copied version)")
|
77
|
+
expect(new_post.comments.length).to eq(5)
|
78
|
+
expect(new_post.comments.select { |c| c.nerf == 'ratatat' && c.contents.nil? }.length).to eq(1)
|
79
|
+
expect(new_post.comments.select { |c| c.nerf == 'ratatat' }.length).to eq(2)
|
80
|
+
expect(new_post.comments.select { |c| c.nerf == 'bonk' }.length).to eq(1)
|
81
|
+
expect(new_post.comments.select { |c| c.nerf == 'bonkers' && c.contents.nil? }.length).to eq(1)
|
82
82
|
|
83
83
|
new_post.widgets.map(&:id).each do |id|
|
84
|
-
old_post.widgets.map(&:id).include
|
84
|
+
expect(old_post.widgets.map(&:id)).not_to include(id)
|
85
85
|
end
|
86
|
+
|
87
|
+
expect(new_post.custom_things.length).to eq(3)
|
88
|
+
expect(new_post.custom_things.select { |ct| ct.value == [] }.length).to eq(1)
|
89
|
+
expect(new_post.custom_things.select { |ct| ct.value == [1, 2] }.length).to eq(1)
|
90
|
+
expect(new_post.custom_things.select { |ct| ct.value == [78] }.length).to eq(1)
|
86
91
|
# }}}
|
87
92
|
# Author {{{
|
88
93
|
old_author = Author.find(1)
|
89
|
-
new_author = old_author.
|
90
|
-
new_author.save
|
91
|
-
new_author.errors.messages.
|
94
|
+
new_author = old_author.amoeba_dup
|
95
|
+
new_author.save!
|
96
|
+
expect(new_author.errors.messages).to be_empty
|
97
|
+
expect(new_author.posts.first.custom_things.length).to eq(3)
|
98
|
+
expect(new_author.posts.first.custom_things.select { |ct| ct.value == [] }.length).to eq(1)
|
99
|
+
expect(new_author.posts.first.custom_things.select { |ct| ct.value == [1, 2] }.length).to eq(1)
|
100
|
+
expect(new_author.posts.first.custom_things.select { |ct| ct.value == [78] }.length).to eq(1)
|
92
101
|
# }}}
|
93
102
|
# Products {{{
|
94
103
|
# Base Class {{{
|
95
|
-
old_product = Product.find(1)
|
96
104
|
|
97
|
-
start_image_count =
|
105
|
+
start_image_count = first_product.images.count
|
98
106
|
start_section_count = Section.all.length
|
99
|
-
|
100
|
-
start_prodsection_count = rs["section_count"]
|
107
|
+
start_prodsection_count = first_product.section_count
|
101
108
|
|
102
|
-
new_product =
|
109
|
+
new_product = first_product.amoeba_dup
|
103
110
|
new_product.save
|
104
|
-
new_product.errors.messages.
|
111
|
+
expect(new_product.errors.messages).to be_empty
|
105
112
|
|
106
|
-
end_image_count =
|
107
|
-
end_newimage_count =
|
113
|
+
end_image_count = first_product.images.count
|
114
|
+
end_newimage_count = new_product.images.count
|
108
115
|
end_section_count = Section.all.length
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
end_prodsection_count.should == start_prodsection_count
|
118
|
-
end_newprodsection_count.should == start_prodsection_count
|
116
|
+
end_prodsection_count = first_product.section_count
|
117
|
+
end_newprodsection_count = new_product.section_count
|
118
|
+
|
119
|
+
expect(end_image_count).to eq(start_image_count)
|
120
|
+
expect(end_newimage_count).to eq(start_image_count)
|
121
|
+
expect(end_section_count).to eq(start_section_count)
|
122
|
+
expect(end_prodsection_count).to eq(start_prodsection_count)
|
123
|
+
expect(end_newprodsection_count).to eq(start_prodsection_count)
|
119
124
|
# }}}
|
120
125
|
|
121
126
|
# Inherited Class {{{
|
122
127
|
# Shirt {{{
|
123
128
|
old_product = Shirt.find(2)
|
124
129
|
|
125
|
-
start_image_count =
|
126
|
-
start_section_count = Section.
|
127
|
-
|
128
|
-
start_prodsection_count = rs["section_count"]
|
130
|
+
start_image_count = old_product.images.count
|
131
|
+
start_section_count = Section.count
|
132
|
+
start_prodsection_count = old_product.section_count
|
129
133
|
|
130
|
-
new_product = old_product.
|
134
|
+
new_product = old_product.amoeba_dup
|
131
135
|
new_product.save
|
132
|
-
new_product.errors.messages.
|
136
|
+
expect(new_product.errors.messages).to be_empty
|
133
137
|
|
134
|
-
end_image_count =
|
135
|
-
end_newimage_count =
|
136
|
-
end_section_count = Section.
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
end_prodsection_count.should == start_prodsection_count
|
146
|
-
end_newprodsection_count.should == start_prodsection_count
|
138
|
+
end_image_count = old_product.images.count
|
139
|
+
end_newimage_count = new_product.images.count
|
140
|
+
end_section_count = Section.count
|
141
|
+
end_prodsection_count = first_product.section_count
|
142
|
+
end_newprodsection_count = new_product.section_count
|
143
|
+
|
144
|
+
expect(end_image_count).to eq(start_image_count)
|
145
|
+
expect(end_newimage_count).to eq(start_image_count)
|
146
|
+
expect(end_section_count).to eq(start_section_count)
|
147
|
+
expect(end_prodsection_count).to eq(start_prodsection_count)
|
148
|
+
expect(end_newprodsection_count).to eq(start_prodsection_count)
|
147
149
|
# }}}
|
148
150
|
|
149
151
|
# Necklace {{{
|
150
152
|
old_product = Necklace.find(3)
|
151
153
|
|
152
|
-
start_image_count =
|
153
|
-
start_section_count = Section.
|
154
|
-
|
155
|
-
start_prodsection_count = rs["section_count"]
|
154
|
+
start_image_count = old_product.images.count
|
155
|
+
start_section_count = Section.count
|
156
|
+
start_prodsection_count = old_product.section_count
|
156
157
|
|
157
|
-
new_product = old_product.
|
158
|
+
new_product = old_product.amoeba_dup
|
158
159
|
new_product.save
|
159
|
-
new_product.errors.messages.
|
160
|
+
expect(new_product.errors.messages).to be_empty
|
160
161
|
|
161
|
-
end_image_count =
|
162
|
-
end_newimage_count =
|
163
|
-
end_section_count = Section.
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
end_prodsection_count.should == start_prodsection_count
|
173
|
-
end_newprodsection_count.should == start_prodsection_count
|
162
|
+
end_image_count = old_product.images.count
|
163
|
+
end_newimage_count = new_product.images.count
|
164
|
+
end_section_count = Section.count
|
165
|
+
end_prodsection_count = first_product.section_count
|
166
|
+
end_newprodsection_count = new_product.section_count
|
167
|
+
|
168
|
+
expect(end_image_count).to eq(start_image_count)
|
169
|
+
expect(end_newimage_count).to eq(start_image_count)
|
170
|
+
expect(end_section_count).to eq(start_section_count)
|
171
|
+
expect(end_prodsection_count).to eq(start_prodsection_count)
|
172
|
+
expect(end_newprodsection_count).to eq(start_prodsection_count)
|
174
173
|
# }}}
|
175
174
|
# }}}
|
176
175
|
# }}}
|
177
176
|
end
|
178
177
|
end
|
178
|
+
|
179
|
+
context 'Using a if condition' do
|
180
|
+
before(:all) do
|
181
|
+
require ::File.dirname(__FILE__) + '/../support/data.rb'
|
182
|
+
end
|
183
|
+
before { ::Post.fresh_amoeba }
|
184
|
+
|
185
|
+
subject { post.amoeba_dup.save! }
|
186
|
+
let(:post) { Post.first }
|
187
|
+
|
188
|
+
it 'includes an association with truthy condition' do
|
189
|
+
::Post.amoeba do
|
190
|
+
include_association :comments, if: :truthy?
|
191
|
+
end
|
192
|
+
expect { subject }.to change { Comment.count }.by(3)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'does not include an association with a falsey condition' do
|
196
|
+
::Post.amoeba do
|
197
|
+
include_association :comments, if: :falsey?
|
198
|
+
end
|
199
|
+
expect { subject }.not_to change { Comment.count }
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'excludes an association with a truthy condition' do
|
203
|
+
::Post.amoeba do
|
204
|
+
exclude_association :comments, if: :truthy?
|
205
|
+
end
|
206
|
+
expect { subject }.not_to change { Comment.count }
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'does not exclude an association with a falsey condition' do
|
210
|
+
::Post.amoeba do
|
211
|
+
exclude_association :comments, if: :falsey?
|
212
|
+
end
|
213
|
+
expect { subject }.to change { Comment.count }.by(3)
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'includes associations from a given array with a truthy condition' do
|
217
|
+
::Post.amoeba do
|
218
|
+
include_association [:comments], if: :truthy?
|
219
|
+
end
|
220
|
+
expect { subject }.to change { Comment.count }.by(3)
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'does not include associations from a given array with a falsey condition' do
|
224
|
+
::Post.amoeba do
|
225
|
+
include_association [:comments], if: :falsey?
|
226
|
+
end
|
227
|
+
expect { subject }.not_to change { Comment.count }
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'does exclude associations from a given array with a truthy condition' do
|
231
|
+
::Post.amoeba do
|
232
|
+
exclude_association [:comments], if: :truthy?
|
233
|
+
end
|
234
|
+
expect { subject }.not_to change { Comment.count }
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'does not exclude associations from a given array with a falsey condition' do
|
238
|
+
::Post.amoeba do
|
239
|
+
exclude_association [:comments], if: :falsey?
|
240
|
+
end
|
241
|
+
expect { subject }.to change { Comment.count }.by(3)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
context 'override' do
|
246
|
+
before :each do
|
247
|
+
::Image.fresh_amoeba
|
248
|
+
::Image.amoeba do
|
249
|
+
override ->(old, new) { new.product_id = 13 if old.filename == 'test.jpg' }
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'should override fields' do
|
254
|
+
image = ::Image.create(filename: 'test.jpg', product_id: 12)
|
255
|
+
image_dup = image.amoeba_dup
|
256
|
+
expect(image_dup.save).to be_truthy
|
257
|
+
expect(image_dup.product_id).to eq(13)
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'should not override fields' do
|
261
|
+
image = ::Image.create(filename: 'test2.jpg', product_id: 12)
|
262
|
+
image_dup = image.amoeba_dup
|
263
|
+
expect(image_dup.save).to be_truthy
|
264
|
+
expect(image_dup.product_id).to eq(12)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
context 'nullify' do
|
269
|
+
before :each do
|
270
|
+
::Image.fresh_amoeba
|
271
|
+
::Image.amoeba do
|
272
|
+
nullify :product_id
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
let(:image) { ::Image.create(filename: 'test.jpg', product_id: 12) }
|
277
|
+
let(:image_dup) { image.amoeba_dup }
|
278
|
+
|
279
|
+
it 'should nullify fields' do
|
280
|
+
expect(image_dup.save).to be_truthy
|
281
|
+
expect(image_dup.product_id).to be_nil
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context 'strict propagate' do
|
286
|
+
it 'should call #reset_amoeba' do
|
287
|
+
expect(::SuperBlackBox).to receive(:reset_amoeba).and_call_original
|
288
|
+
box = ::SuperBlackBox.create(title: 'Super Black Box', price: 9.99, length: 1, metal: '1')
|
289
|
+
new_box = box.amoeba_dup
|
290
|
+
expect(new_box.save).to be_truthy
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
context 'remapping and custom dup method' do
|
295
|
+
let(:prototype) { ObjectPrototype.new }
|
296
|
+
|
297
|
+
context 'through' do
|
298
|
+
it do
|
299
|
+
real_object = prototype.amoeba_dup
|
300
|
+
expect(real_object).to be_a(::RealObject)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context 'remapper' do
|
305
|
+
it do
|
306
|
+
prototype.subobject_prototypes << SubobjectPrototype.new
|
307
|
+
real_object = prototype.amoeba_dup
|
308
|
+
expect(real_object.subobjects.length).to eq(1)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
context 'preprocessing fields' do
|
314
|
+
subject { super_admin.amoeba_dup }
|
315
|
+
let(:super_admin) { ::SuperAdmin.create!(email: 'user@example.com', active: true, password: 'password') }
|
316
|
+
|
317
|
+
it 'should accept "set" to set false to attribute' do
|
318
|
+
expect(subject.active).to be false
|
319
|
+
end
|
320
|
+
|
321
|
+
it 'should skip "prepend" if it equal to false' do
|
322
|
+
expect(subject.password).to eq('password')
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
context 'inheritance' do
|
327
|
+
let(:box) { Box.create }
|
328
|
+
|
329
|
+
it 'does not fail with a deep inheritance' do
|
330
|
+
sub_sub_product = BoxSubSubProduct.create(title: 'Awesome shoes')
|
331
|
+
another_product = BoxAnotherProduct.create(title: 'Cleaning product')
|
332
|
+
sub_sub_product.update(box: box, another_product: another_product)
|
333
|
+
expect(box.sub_products.first.another_product.title).to eq('Cleaning product')
|
334
|
+
expect(box.amoeba_dup.sub_products.first.another_product.title).to eq('Cleaning product')
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
context 'inheritance extended' do
|
339
|
+
let(:stage) do
|
340
|
+
stage = CustomStage.new(title: 'My Stage', external_id: 213)
|
341
|
+
stage.listeners.build(name: 'John')
|
342
|
+
stage.listeners.build(name: 'Helen')
|
343
|
+
stage.specialists.build(name: 'Jack')
|
344
|
+
stage.custom_rules.build(description: 'Kill all humans')
|
345
|
+
stage.save!
|
346
|
+
stage
|
347
|
+
end
|
348
|
+
|
349
|
+
subject { stage.amoeba_dup }
|
350
|
+
|
351
|
+
it 'contains parent association and own associations', :aggregate_failures do
|
352
|
+
subject
|
353
|
+
expect { subject.save! }.to change(Listener, :count).by(2).
|
354
|
+
and change(Specialist, :count).by(1).
|
355
|
+
and change(CustomRule, :count).by(1)
|
356
|
+
|
357
|
+
expect(subject.title).to eq 'My Stage'
|
358
|
+
expect(subject.external_id).to be_nil
|
359
|
+
expect(subject.listeners.find_by(name: 'John')).to_not be_nil
|
360
|
+
expect(subject.listeners.find_by(name: 'Helen')).to_not be_nil
|
361
|
+
expect(subject.specialists.find_by(name: 'Jack')).to_not be_nil
|
362
|
+
expect(subject.custom_rules.first.description).to eq 'Kill all humans'
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
context 'polymorphic' do
|
367
|
+
let(:company) { Company.find_by(name: 'ABC Industries') }
|
368
|
+
let(:new_company) { company.amoeba_dup }
|
369
|
+
|
370
|
+
it 'does not fail with a deep inheritance' do
|
371
|
+
# employee = company.employees.where(name:'Joe').first
|
372
|
+
start_company_count = Company.count
|
373
|
+
start_customer_count = Customer.count
|
374
|
+
start_employee_count = Employee.count
|
375
|
+
start_address_count = Address.count
|
376
|
+
start_photo_count = Photo.count
|
377
|
+
new_company.name = "Copy of #{new_company.name}"
|
378
|
+
new_company.save
|
379
|
+
expect(Company.count).to eq(start_company_count + 1)
|
380
|
+
expect(Customer.count).to eq(start_customer_count + 1)
|
381
|
+
expect(Employee.count).to eq(start_employee_count + 1)
|
382
|
+
expect(Address.count).to eq(start_address_count + 4)
|
383
|
+
expect(Photo.count).to eq(start_photo_count + 2)
|
384
|
+
|
385
|
+
new_company.reload # fully reload from database
|
386
|
+
new_company_employees = new_company.employees
|
387
|
+
expect(new_company_employees.count).to eq(1)
|
388
|
+
new_company_employee_joe = new_company_employees.find_by(name: 'Joe')
|
389
|
+
expect(new_company_employee_joe.photos.count).to eq(1)
|
390
|
+
expect(new_company_employee_joe.photos.first.size).to eq(12_345)
|
391
|
+
expect(new_company_employee_joe.addresses.count).to eq(2)
|
392
|
+
expect(new_company_employee_joe.addresses.where(street: '123 My Street').count).to eq(1)
|
393
|
+
expect(new_company_employee_joe.addresses.where(street: '124 My Street').count).to eq(1)
|
394
|
+
new_company_customers = new_company.customers
|
395
|
+
expect(new_company_customers.count).to eq(1)
|
396
|
+
new_company_customer_my = new_company_customers.where(email: 'my@email.address').first
|
397
|
+
expect(new_company_customer_my.photos.count).to eq(1)
|
398
|
+
expect(new_company_customer_my.photos.first.size).to eq(54_321)
|
399
|
+
expect(new_company_customer_my.addresses.count).to eq(2)
|
400
|
+
expect(new_company_customer_my.addresses.where(street: '321 My Street').count).to eq(1)
|
401
|
+
expect(new_company_customer_my.addresses.where(street: '321 My Drive').count).to eq(1)
|
402
|
+
end
|
403
|
+
end
|
179
404
|
end
|