amoeba 1.2.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rvmrc +1 -1
- data/README.md +105 -95
- data/lib/amoeba.rb +6 -6
- data/lib/amoeba/version.rb +1 -1
- data/spec/lib/amoeba_spec.rb +14 -5
- data/spec/support/data.rb +2 -0
- data/spec/support/models.rb +25 -0
- data/spec/support/schema.rb +1 -0
- metadata +9 -4
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm use --create 1.9.3-
|
1
|
+
rvm use --create 1.9.3-p194@amoeba
|
data/README.md
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
#
|
1
|
+
# IMPORTANT NEWS
|
2
|
+
|
3
|
+
* As of December 11th, 2012 Amoeba no longer overrides the built in `ActiveRecord::Base#dup` method and instead implements its own method called `amoeba_dup`. Make sure to update your code if you do a bundle update and or double check that your gemfile has a version restriction bound to v1.x e.g. '~> 1.2' listed for amoeba.
|
4
|
+
|
5
|
+
## Amoeba
|
2
6
|
|
3
7
|
Easy copying of rails associations such as `has_many`.
|
4
8
|
|
@@ -12,7 +16,7 @@ This gem is named "Amoeba" because amoebas are (small life forms that are) good
|
|
12
16
|
|
13
17
|
### Technical Details
|
14
18
|
|
15
|
-
An ActiveRecord extension gem to allow the duplication of associated child record objects when duplicating an active record model.
|
19
|
+
An ActiveRecord extension gem to allow the duplication of associated child record objects when duplicating an active record model.
|
16
20
|
|
17
21
|
Rails 3.2 compatible.
|
18
22
|
|
@@ -50,7 +54,7 @@ or just add it to your Gemfile:
|
|
50
54
|
|
51
55
|
gem 'amoeba'
|
52
56
|
|
53
|
-
Configure your models with one of the styles below and then just run the `
|
57
|
+
Configure your models with one of the styles below and then just run the `amoeba_dup` method on your model where you would run the `dup` method normally:
|
54
58
|
|
55
59
|
p = Post.create(:title => "Hello World!", :content => "Lorum ipsum dolor")
|
56
60
|
p.comments.create(:content => "I love it!")
|
@@ -58,7 +62,7 @@ Configure your models with one of the styles below and then just run the `dup` m
|
|
58
62
|
|
59
63
|
puts Comment.all.count # should be 2
|
60
64
|
|
61
|
-
my_copy = p.
|
65
|
+
my_copy = p.amoeba_dup
|
62
66
|
my_copy.save
|
63
67
|
|
64
68
|
puts Comment.all.count # should be 4
|
@@ -99,7 +103,7 @@ simply add the amoeba configuration block to your model and call the enable meth
|
|
99
103
|
belongs_to :post
|
100
104
|
end
|
101
105
|
|
102
|
-
Child records will be automatically copied when you run the
|
106
|
+
Child records will be automatically copied when you run the `amoeba_dup` method.
|
103
107
|
|
104
108
|
#### Inclusive Style
|
105
109
|
|
@@ -212,7 +216,7 @@ If you are using a Many-to-Many relationship, you may tell amoeba to actually ma
|
|
212
216
|
|
213
217
|
This example will actually duplicate the warnings and widgets in the database. If there were originally 3 warnings in the database then, upon duplicating a post, you will end up with 6 warnings in the database. This is in contrast to the default behavior where your new post would merely be re-associated with any previously existing warnings and those warnings themselves would not be duplicated.
|
214
218
|
|
215
|
-
|
219
|
+
#### Limiting Association Types
|
216
220
|
|
217
221
|
By default, amoeba recognizes and attemps to copy any children of the following association types:
|
218
222
|
|
@@ -242,90 +246,6 @@ You may control which association types amoeba applies itself to by using the `r
|
|
242
246
|
|
243
247
|
This example will copy the post's configuration data and keep tags associated with the new post, but will not copy the post's comments because amoeba will only recognize and copy children of `has_one` and `has_and_belongs_to_many` associations and in this example, comments are not an `has_and_belongs_to_many` association.
|
244
248
|
|
245
|
-
### Nested Association Validation
|
246
|
-
|
247
|
-
If you end up with some validation issues when trying to validate the presence of a child's `belongs_to` association, just be sure to include the `:inverse_of` declaration on your relationships and all should be well.
|
248
|
-
|
249
|
-
For example this will throw a validation error saying that your posts are invalid:
|
250
|
-
|
251
|
-
class Author < ActiveRecord::Base
|
252
|
-
has_many :posts
|
253
|
-
|
254
|
-
amoeba do
|
255
|
-
enable
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
class Post < ActiveRecord::Base
|
260
|
-
belongs_to :author
|
261
|
-
validates_presence_of :author
|
262
|
-
|
263
|
-
amoeba do
|
264
|
-
enable
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
author = Author.find(1)
|
269
|
-
author.dup
|
270
|
-
|
271
|
-
author.save # this will fail validation
|
272
|
-
|
273
|
-
Wheras this will work fine:
|
274
|
-
|
275
|
-
class Author < ActiveRecord::Base
|
276
|
-
has_many :posts, :inverse_of => :author
|
277
|
-
|
278
|
-
amoeba do
|
279
|
-
enable
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
class Post < ActiveRecord::Base
|
284
|
-
belongs_to :author, :inverse_of => :posts
|
285
|
-
validates_presence_of :author
|
286
|
-
|
287
|
-
amoeba do
|
288
|
-
enable
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
author = Author.find(1)
|
293
|
-
author.dup
|
294
|
-
|
295
|
-
author.save # this will pass validation
|
296
|
-
|
297
|
-
This issue is not amoeba specific and also occurs when creating new objects using `accepts_nested_attributes_for`, like this:
|
298
|
-
|
299
|
-
class Author < ActiveRecord::Base
|
300
|
-
has_many :posts
|
301
|
-
accepts_nested_attributes_for :posts
|
302
|
-
end
|
303
|
-
|
304
|
-
class Post < ActiveRecord::Base
|
305
|
-
belongs_to :author
|
306
|
-
validates_presence_of :author
|
307
|
-
end
|
308
|
-
|
309
|
-
# this will fail validation
|
310
|
-
author = Author.create({:name => "Jim Smith", :posts => [{:title => "Hello World", :contents => "Lorum ipsum dolor}]})
|
311
|
-
|
312
|
-
This issue with `accepts_nested_attributes_for` can also be solved by using `:inverse_of`, like this:
|
313
|
-
|
314
|
-
class Author < ActiveRecord::Base
|
315
|
-
has_many :posts, :inverse_of => :author
|
316
|
-
accepts_nested_attributes_for :posts
|
317
|
-
end
|
318
|
-
|
319
|
-
class Post < ActiveRecord::Base
|
320
|
-
belongs_to :author, :inverse_of => :posts
|
321
|
-
validates_presence_of :author
|
322
|
-
end
|
323
|
-
|
324
|
-
# this will pass validation
|
325
|
-
author = Author.create({:name => "Jim Smith", :posts => [{:title => "Hello World", :contents => "Lorum ipsum dolor}]})
|
326
|
-
|
327
|
-
The crux of the issue is that upon duplication, the new `Author` instance does not yet have an ID because it has not yet been persisted, so the `:posts` do not yet have an `:author_id` either, and thus no `:author` and thus they will fail validation. This issue may likely affect amoeba usage so if you get some validation failures, be sure to add `:inverse_of` to your models.
|
328
|
-
|
329
249
|
### Field Preprocessors
|
330
250
|
|
331
251
|
#### Nullify
|
@@ -488,7 +408,7 @@ This example should result in something like this:
|
|
488
408
|
:contents => "I like dogs, dogs are awesome."
|
489
409
|
)
|
490
410
|
|
491
|
-
new_post = post.
|
411
|
+
new_post = post.amoeba_dup
|
492
412
|
|
493
413
|
new_post.title # "Copy of Hello world"
|
494
414
|
new_post.contents # "Original contents: I like cats, cats are awesome. (copied version)"
|
@@ -612,7 +532,7 @@ Copying of `has_many :through` associations works automatically. They perform th
|
|
612
532
|
belongs_to :part
|
613
533
|
|
614
534
|
amoeba do
|
615
|
-
|
535
|
+
prepend :notes => "Copy of "
|
616
536
|
end
|
617
537
|
end
|
618
538
|
|
@@ -653,7 +573,7 @@ You may control how amoeba copies your object, on the fly, by passing a configur
|
|
653
573
|
prepend :contents => "Here's a copy: "
|
654
574
|
end
|
655
575
|
|
656
|
-
new_post = old_post.
|
576
|
+
new_post = old_post.amoeba_dup
|
657
577
|
|
658
578
|
new_post.title # should be "Copy of Hello world"
|
659
579
|
new_post.contents # should be "Here's a copy: Lorum ipsum"
|
@@ -700,7 +620,7 @@ If you are using the Single Table Inheritance provided by ActiveRecord, you may
|
|
700
620
|
class ProductsController
|
701
621
|
def some_method
|
702
622
|
my_shirt = Shirt.find(1)
|
703
|
-
my_shirt.
|
623
|
+
my_shirt.amoeba_dup
|
704
624
|
my_shirt.save
|
705
625
|
|
706
626
|
# this shirt should now:
|
@@ -843,6 +763,90 @@ The next version will use only the parent settings because passing an array will
|
|
843
763
|
include_field :sections
|
844
764
|
end
|
845
765
|
|
766
|
+
### Validating Nested Attributes
|
767
|
+
|
768
|
+
If you end up with some validation issues when trying to validate the presence of a child's `belongs_to` association, just be sure to include the `:inverse_of` declaration on your relationships and all should be well.
|
769
|
+
|
770
|
+
For example this will throw a validation error saying that your posts are invalid:
|
771
|
+
|
772
|
+
class Author < ActiveRecord::Base
|
773
|
+
has_many :posts
|
774
|
+
|
775
|
+
amoeba do
|
776
|
+
enable
|
777
|
+
end
|
778
|
+
end
|
779
|
+
|
780
|
+
class Post < ActiveRecord::Base
|
781
|
+
belongs_to :author
|
782
|
+
validates_presence_of :author
|
783
|
+
|
784
|
+
amoeba do
|
785
|
+
enable
|
786
|
+
end
|
787
|
+
end
|
788
|
+
|
789
|
+
author = Author.find(1)
|
790
|
+
author.amoeba_dup
|
791
|
+
|
792
|
+
author.save # this will fail validation
|
793
|
+
|
794
|
+
Wheras this will work fine:
|
795
|
+
|
796
|
+
class Author < ActiveRecord::Base
|
797
|
+
has_many :posts, :inverse_of => :author
|
798
|
+
|
799
|
+
amoeba do
|
800
|
+
enable
|
801
|
+
end
|
802
|
+
end
|
803
|
+
|
804
|
+
class Post < ActiveRecord::Base
|
805
|
+
belongs_to :author, :inverse_of => :posts
|
806
|
+
validates_presence_of :author
|
807
|
+
|
808
|
+
amoeba do
|
809
|
+
enable
|
810
|
+
end
|
811
|
+
end
|
812
|
+
|
813
|
+
author = Author.find(1)
|
814
|
+
author.amoeba_dup
|
815
|
+
|
816
|
+
author.save # this will pass validation
|
817
|
+
|
818
|
+
This issue is not amoeba specific and also occurs when creating new objects using `accepts_nested_attributes_for`, like this:
|
819
|
+
|
820
|
+
class Author < ActiveRecord::Base
|
821
|
+
has_many :posts
|
822
|
+
accepts_nested_attributes_for :posts
|
823
|
+
end
|
824
|
+
|
825
|
+
class Post < ActiveRecord::Base
|
826
|
+
belongs_to :author
|
827
|
+
validates_presence_of :author
|
828
|
+
end
|
829
|
+
|
830
|
+
# this will fail validation
|
831
|
+
author = Author.create({:name => "Jim Smith", :posts => [{:title => "Hello World", :contents => "Lorum ipsum dolor}]})
|
832
|
+
|
833
|
+
This issue with `accepts_nested_attributes_for` can also be solved by using `:inverse_of`, like this:
|
834
|
+
|
835
|
+
class Author < ActiveRecord::Base
|
836
|
+
has_many :posts, :inverse_of => :author
|
837
|
+
accepts_nested_attributes_for :posts
|
838
|
+
end
|
839
|
+
|
840
|
+
class Post < ActiveRecord::Base
|
841
|
+
belongs_to :author, :inverse_of => :posts
|
842
|
+
validates_presence_of :author
|
843
|
+
end
|
844
|
+
|
845
|
+
# this will pass validation
|
846
|
+
author = Author.create({:name => "Jim Smith", :posts => [{:title => "Hello World", :contents => "Lorum ipsum dolor}]})
|
847
|
+
|
848
|
+
The crux of the issue is that upon duplication, the new `Author` instance does not yet have an ID because it has not yet been persisted, so the `:posts` do not yet have an `:author_id` either, and thus no `:author` and thus they will fail validation. This issue may likely affect amoeba usage so if you get some validation failures, be sure to add `:inverse_of` to your models.
|
849
|
+
|
846
850
|
## Configuration Reference
|
847
851
|
|
848
852
|
Here is a static reference to the available configuration methods, usable within the amoeba block on your rails models.
|
@@ -915,9 +919,15 @@ Here is a static reference to the available configuration methods, usable within
|
|
915
919
|
|
916
920
|
Globally search and replace the field for a given pattern. Accepts a hash of fields to run search and replace upon. The keys are the field names and the values are each a hash with information about what to find and what to replace it with. in the form of . An example would be to replace all occurrences of the word "dog" with the word "cat", the parameter hash would look like this `:contents => {:replace => /dog/, :with => "cat"}`. Passing a hash will add each key value pair to the list of regex directives. If you wish to empty the list of directives, you may pass the hash inside of an array like this `[{:contents => {:replace => /dog/, :with => "cat"}]`.
|
917
921
|
|
922
|
+
#### override
|
923
|
+
|
924
|
+
Runs a custom method so you can do basically whatever you want. All you need to do is pass a lambda block or an array of lambda blocks that take two parameters, the original object and the new object copy. These blocks will run before any other duplication or field processing.
|
925
|
+
|
926
|
+
This method may be called multiple times, once per desired customizer block, or you may pass an array of lambdas. Passing a single lambda will add to the list of processing directives. Passing an array will empty the list and replace it with the array you pass.
|
927
|
+
|
918
928
|
#### customize
|
919
929
|
|
920
|
-
Runs a custom method so you can do basically whatever you want. All you need to do is pass a lambda block or an array of lambda blocks that take two parameters, the original object and the new object copy
|
930
|
+
Runs a custom method so you can do basically whatever you want. All you need to do is pass a lambda block or an array of lambda blocks that take two parameters, the original object and the new object copy. These blocks will run after all copying and field processing.
|
921
931
|
|
922
932
|
This method may be called multiple times, once per desired customizer block, or you may pass an array of lambdas. Passing a single lambda will add to the list of processing directives. Passing an array will empty the list and replace it with the array you pass.
|
923
933
|
|
data/lib/amoeba.rb
CHANGED
@@ -323,8 +323,8 @@ module Amoeba
|
|
323
323
|
end
|
324
324
|
# }}}
|
325
325
|
|
326
|
-
def
|
327
|
-
@result =
|
326
|
+
def amoeba_dup(options={})
|
327
|
+
@result = self.dup()
|
328
328
|
|
329
329
|
# Inherit Parent Settings {{{
|
330
330
|
if !amoeba_conf.enabled && parent_amoeba_conf.inherit
|
@@ -422,7 +422,7 @@ module Amoeba
|
|
422
422
|
old_obj = self.send(relation_name)
|
423
423
|
|
424
424
|
if not old_obj.nil?
|
425
|
-
copy_of_obj = old_obj.
|
425
|
+
copy_of_obj = old_obj.amoeba_dup
|
426
426
|
copy_of_obj[:"#{settings.foreign_key}"] = nil
|
427
427
|
|
428
428
|
@result.send(:"#{relation_name}=", copy_of_obj)
|
@@ -439,7 +439,7 @@ module Amoeba
|
|
439
439
|
# rather than only maintaining the associations
|
440
440
|
self.send(relation_name).each do |old_obj|
|
441
441
|
|
442
|
-
copy_of_obj = old_obj.
|
442
|
+
copy_of_obj = old_obj.amoeba_dup
|
443
443
|
|
444
444
|
# associate this new child to the new parent object
|
445
445
|
@result.send(relation_name) << copy_of_obj
|
@@ -454,7 +454,7 @@ module Amoeba
|
|
454
454
|
return if settings.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
455
455
|
|
456
456
|
self.send(relation_name).each do |old_obj|
|
457
|
-
copy_of_obj = old_obj.
|
457
|
+
copy_of_obj = old_obj.amoeba_dup
|
458
458
|
copy_of_obj[:"#{settings.foreign_key}"] = nil
|
459
459
|
|
460
460
|
# associate this new child to the new parent object
|
@@ -467,7 +467,7 @@ module Amoeba
|
|
467
467
|
|
468
468
|
if clone
|
469
469
|
self.send(relation_name).each do |old_obj|
|
470
|
-
copy_of_obj = old_obj.
|
470
|
+
copy_of_obj = old_obj.amoeba_dup
|
471
471
|
|
472
472
|
# associate this new child to the new parent object
|
473
473
|
@result.send(relation_name) << copy_of_obj
|
data/lib/amoeba/version.rb
CHANGED
data/spec/lib/amoeba_spec.rb
CHANGED
@@ -12,7 +12,7 @@ describe "amoeba" do
|
|
12
12
|
prepend :contents => "Here's a copy: "
|
13
13
|
end
|
14
14
|
|
15
|
-
new_post = old_post.
|
15
|
+
new_post = old_post.amoeba_dup
|
16
16
|
|
17
17
|
start_account_count = Account.all.count
|
18
18
|
start_history_count = History.all.count
|
@@ -83,12 +83,21 @@ describe "amoeba" do
|
|
83
83
|
new_post.widgets.map(&:id).each do |id|
|
84
84
|
old_post.widgets.map(&:id).include?(id).should_not be true
|
85
85
|
end
|
86
|
+
|
87
|
+
new_post.custom_things.length.should == 3
|
88
|
+
new_post.custom_things.select{ |ct| ct.value == [] }.length.should == 1
|
89
|
+
new_post.custom_things.select{ |ct| ct.value == [1,2]}.length.should == 1
|
90
|
+
new_post.custom_things.select{ |ct| ct.value == [78]}.length.should == 1
|
86
91
|
# }}}
|
87
92
|
# Author {{{
|
88
93
|
old_author = Author.find(1)
|
89
|
-
new_author = old_author.
|
94
|
+
new_author = old_author.amoeba_dup
|
90
95
|
new_author.save
|
91
96
|
new_author.errors.messages.length.should == 0
|
97
|
+
new_author.posts.first.custom_things.length.should == 3
|
98
|
+
new_author.posts.first.custom_things.select{ |ct| ct.value == [] }.length.should == 1
|
99
|
+
new_author.posts.first.custom_things.select{ |ct| ct.value == [1,2]}.length.should == 1
|
100
|
+
new_author.posts.first.custom_things.select{ |ct| ct.value == [78]}.length.should == 1
|
92
101
|
# }}}
|
93
102
|
# Products {{{
|
94
103
|
# Base Class {{{
|
@@ -99,7 +108,7 @@ describe "amoeba" do
|
|
99
108
|
rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', old_product.id)
|
100
109
|
start_prodsection_count = rs["section_count"]
|
101
110
|
|
102
|
-
new_product = old_product.
|
111
|
+
new_product = old_product.amoeba_dup
|
103
112
|
new_product.save
|
104
113
|
new_product.errors.messages.length.should == 0
|
105
114
|
|
@@ -127,7 +136,7 @@ describe "amoeba" do
|
|
127
136
|
rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', old_product.id)
|
128
137
|
start_prodsection_count = rs["section_count"]
|
129
138
|
|
130
|
-
new_product = old_product.
|
139
|
+
new_product = old_product.amoeba_dup
|
131
140
|
new_product.save
|
132
141
|
new_product.errors.messages.length.should == 0
|
133
142
|
|
@@ -154,7 +163,7 @@ describe "amoeba" do
|
|
154
163
|
rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', old_product.id)
|
155
164
|
start_prodsection_count = rs["section_count"]
|
156
165
|
|
157
|
-
new_product = old_product.
|
166
|
+
new_product = old_product.amoeba_dup
|
158
167
|
new_product.save
|
159
168
|
new_product.errors.messages.length.should == 0
|
160
169
|
|
data/spec/support/data.rb
CHANGED
@@ -81,6 +81,8 @@ s2.superkittens.create(:value => "Spot")
|
|
81
81
|
s3.superkittens.create(:value => "Dopey")
|
82
82
|
s3.superkittens.create(:value => "Sneezy")
|
83
83
|
s3.superkittens.create(:value => "Sleepy")
|
84
|
+
|
85
|
+
p1.custom_things.create([{:value => [1,2]}, {:value => []}, {:value => [78]}])
|
84
86
|
# }}}
|
85
87
|
|
86
88
|
# Product {{{
|
data/spec/support/models.rb
CHANGED
@@ -25,6 +25,7 @@ class Post < ActiveRecord::Base
|
|
25
25
|
has_many :categories, :through => :supercats
|
26
26
|
has_many :post_widgets
|
27
27
|
has_many :widgets, :through => :post_widgets
|
28
|
+
has_many :custom_things
|
28
29
|
has_and_belongs_to_many :tags
|
29
30
|
has_and_belongs_to_many :notes
|
30
31
|
|
@@ -73,6 +74,30 @@ end
|
|
73
74
|
|
74
75
|
class CustomThing < ActiveRecord::Base
|
75
76
|
belongs_to :post
|
77
|
+
class ArrayPack
|
78
|
+
def self.load(str)
|
79
|
+
unless str.present? && str.length > 0
|
80
|
+
return []
|
81
|
+
end
|
82
|
+
if str.is_a?(Array)
|
83
|
+
return str
|
84
|
+
end
|
85
|
+
str.split(',').collect(&:to_i)
|
86
|
+
end
|
87
|
+
def self.dump(int_array)
|
88
|
+
unless int_array.present? && int_array.length > 0
|
89
|
+
return ""
|
90
|
+
end
|
91
|
+
int_array.join(',')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
serialize :value, ArrayPack
|
96
|
+
|
97
|
+
before_create :hydrate_me
|
98
|
+
def hydrate_me
|
99
|
+
self.value = self.value
|
100
|
+
end
|
76
101
|
end
|
77
102
|
|
78
103
|
class Account < ActiveRecord::Base
|
data/spec/support/schema.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amoeba
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -143,8 +143,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
143
143
|
version: '0'
|
144
144
|
requirements: []
|
145
145
|
rubyforge_project: amoeba
|
146
|
-
rubygems_version: 1.8.
|
146
|
+
rubygems_version: 1.8.24
|
147
147
|
signing_key:
|
148
148
|
specification_version: 3
|
149
149
|
summary: Easy copying of rails models and their child associations.
|
150
|
-
test_files:
|
150
|
+
test_files:
|
151
|
+
- spec/lib/amoeba_spec.rb
|
152
|
+
- spec/spec_helper.rb
|
153
|
+
- spec/support/data.rb
|
154
|
+
- spec/support/models.rb
|
155
|
+
- spec/support/schema.rb
|