amoeba 0.1.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +47 -1
- data/lib/amoeba.rb +106 -19
- data/lib/amoeba/version.rb +1 -1
- data/spec/lib/amoeba_spec.rb +23 -0
- data/spec/support/data.rb +33 -3
- data/spec/support/models.rb +38 -1
- data/spec/support/schema.rb +26 -1
- metadata +10 -10
data/README.md
CHANGED
@@ -25,9 +25,11 @@ Rails 3.2 compatible.
|
|
25
25
|
- `has_and_belongs_to_many`
|
26
26
|
- A simple DSL for configuration of which fields to copy. The DSL can be applied to your rails models or used on the fly.
|
27
27
|
- Multiple configuration styles such as inclusive, exclusive and indiscriminate (aka copy everything).
|
28
|
+
- Supports cloning of the children of Many-to-Many records as well as not cloning the child records but merely maintaining original associations
|
28
29
|
- Supports recursive copying of child and grandchild records.
|
29
30
|
- Supports preprocessing of fields to help indicate uniqueness and ensure the integrity of your data depending on your business logic needs, e.g. prepending "Copy of " or similar text.
|
30
31
|
- Amoeba can perform the following preprocessing operations on fields of copied records
|
32
|
+
- set
|
31
33
|
- prepend
|
32
34
|
- append
|
33
35
|
- nullify
|
@@ -133,7 +135,7 @@ Using the inclusive style within the amoeba block actually implies that you wish
|
|
133
135
|
belongs_to :post
|
134
136
|
end
|
135
137
|
|
136
|
-
You may also specify fields to be copied by passing an array.
|
138
|
+
You may also specify fields to be copied by passing an array. If you call the `include_field` with a single value, it will be appended to the list of already included fields. If you pass an array, your array will overwrite the original values.
|
137
139
|
|
138
140
|
class Post < ActiveRecord::Base
|
139
141
|
has_many :comments
|
@@ -171,6 +173,38 @@ If you have more fields to include than to exclude, you may wish to shorten the
|
|
171
173
|
|
172
174
|
This example does the same thing as the inclusive style example, it will copy the post's tags and authors but not its comments. As with inclusive style, there is no need to explicitly enable amoeba when specifying fields to exclude.
|
173
175
|
|
176
|
+
### Cloning
|
177
|
+
|
178
|
+
If you are using a Many-to-Many relationship, you may tell amoeba to actually make duplicates of the original related records rather than merely maintaining association with the original records. Cloning is easy, merely tell amoeba which fields to clone in the same way you tell it which fields to include or exclude.
|
179
|
+
|
180
|
+
class Post < ActiveRecord::Base
|
181
|
+
has_and_belongs_to_many :warnings
|
182
|
+
|
183
|
+
has_many :post_widgets
|
184
|
+
has_many :widgets, :through => :post_widgets
|
185
|
+
|
186
|
+
amoeba do
|
187
|
+
enable
|
188
|
+
clone [:widgets, :tags]
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
class Warning < ActiveRecord::Base
|
193
|
+
has_and_belongs_to_many :posts
|
194
|
+
end
|
195
|
+
|
196
|
+
class PostWidget < ActiveRecord::Base
|
197
|
+
belongs_to :widget
|
198
|
+
belongs_to :post
|
199
|
+
end
|
200
|
+
|
201
|
+
class Widget < ActiveRecord::Base
|
202
|
+
has_many :post_widgets
|
203
|
+
has_many :posts, :through => :post_widgets
|
204
|
+
end
|
205
|
+
|
206
|
+
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.
|
207
|
+
|
174
208
|
### Limiting Association Types
|
175
209
|
|
176
210
|
By default, amoeba recognizes and attemps to copy any children of the following association types:
|
@@ -230,6 +264,18 @@ This example will copy all of a post's comments. It will also nullify the publis
|
|
230
264
|
|
231
265
|
Unlike inclusive and exclusive styles, specifying null fields will not automatically enable amoeba to copy all child records. As with any active record object, the default field value will be used instead of `nil` if a default value exists on the migration.
|
232
266
|
|
267
|
+
#### Set
|
268
|
+
|
269
|
+
If you wish to just set a field to an aribrary value on all duplicated objects you may use the `set` directive. For example, if you wanted to copy an object that has some kind of approval process associated with it, you likely may wish to set the new object's state to be open or "in progress" again.
|
270
|
+
|
271
|
+
class Post < ActiveRecord::Base
|
272
|
+
amoeba do
|
273
|
+
set :state_tracker => "open_for_editing"
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
In this example, when a post is duplicated, it's `state_tracker` field will always be given a value of `open_for_editing` to start.
|
278
|
+
|
233
279
|
#### Prepend
|
234
280
|
|
235
281
|
You may add a string to the beginning of a copied object's field during the copy phase:
|
data/lib/amoeba.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "active_record"
|
1
2
|
require "amoeba/version"
|
2
3
|
|
3
4
|
module Amoeba
|
@@ -20,6 +21,11 @@ module Amoeba
|
|
20
21
|
@do_preproc
|
21
22
|
end
|
22
23
|
|
24
|
+
def known_macros
|
25
|
+
@known_macros ||= [:has_one, :has_many, :has_and_belongs_to_many]
|
26
|
+
@known_macros
|
27
|
+
end
|
28
|
+
|
23
29
|
def includes
|
24
30
|
@includes ||= []
|
25
31
|
@includes
|
@@ -30,9 +36,9 @@ module Amoeba
|
|
30
36
|
@excludes
|
31
37
|
end
|
32
38
|
|
33
|
-
def
|
34
|
-
@
|
35
|
-
@
|
39
|
+
def clones
|
40
|
+
@clones ||= []
|
41
|
+
@clones
|
36
42
|
end
|
37
43
|
|
38
44
|
def null_fields
|
@@ -40,6 +46,11 @@ module Amoeba
|
|
40
46
|
@null_fields
|
41
47
|
end
|
42
48
|
|
49
|
+
def coercions
|
50
|
+
@coercions ||= {}
|
51
|
+
@coercions
|
52
|
+
end
|
53
|
+
|
43
54
|
def prefixes
|
44
55
|
@prefixes ||= {}
|
45
56
|
@prefixes
|
@@ -87,6 +98,17 @@ module Amoeba
|
|
87
98
|
@excludes
|
88
99
|
end
|
89
100
|
|
101
|
+
def clone(value=nil)
|
102
|
+
@enabled ||= true
|
103
|
+
@clones ||= []
|
104
|
+
if value.is_a?(Array)
|
105
|
+
@clones = value
|
106
|
+
else
|
107
|
+
@clones << value if value
|
108
|
+
end
|
109
|
+
@clones
|
110
|
+
end
|
111
|
+
|
90
112
|
def recognize(value=nil)
|
91
113
|
@enabled ||= true
|
92
114
|
@known_macros ||= []
|
@@ -109,6 +131,25 @@ module Amoeba
|
|
109
131
|
@null_fields
|
110
132
|
end
|
111
133
|
|
134
|
+
def set(defs=nil)
|
135
|
+
@do_preproc ||= true
|
136
|
+
@coercions ||= {}
|
137
|
+
if defs.is_a?(Array)
|
138
|
+
@coercions = {}
|
139
|
+
|
140
|
+
defs.each do |d|
|
141
|
+
d.each do |k,v|
|
142
|
+
@coercions[k] = v if v
|
143
|
+
end
|
144
|
+
end
|
145
|
+
else
|
146
|
+
defs.each do |k,v|
|
147
|
+
@coercions[k] = v if v
|
148
|
+
end
|
149
|
+
end
|
150
|
+
@coercions
|
151
|
+
end
|
152
|
+
|
112
153
|
def prepend(defs=nil)
|
113
154
|
@do_preproc ||= true
|
114
155
|
@prefixes ||= {}
|
@@ -194,25 +235,54 @@ module Amoeba
|
|
194
235
|
@result.send(:"#{relation_name}=", copy_of_obj)
|
195
236
|
end
|
196
237
|
when :has_many
|
197
|
-
|
198
|
-
|
199
|
-
#
|
200
|
-
#
|
201
|
-
|
202
|
-
|
238
|
+
clone = amoeba_conf.clones.include?(:"#{relation_name}")
|
239
|
+
|
240
|
+
# this could be DRYed up for better readability by
|
241
|
+
# duplicating the loop code, but I'm duplicating the
|
242
|
+
# loops to avoid that extra check on each iteration
|
243
|
+
if clone
|
244
|
+
# This is a M:M "has many through" where we
|
245
|
+
# actually copy and reassociate the new children
|
246
|
+
# rather than only maintaining the associations
|
247
|
+
self.send(relation_name).each do |old_obj|
|
248
|
+
copy_of_obj = old_obj.dup
|
249
|
+
|
250
|
+
# associate this new child to the new parent object
|
251
|
+
@result.send(relation_name) << copy_of_obj
|
252
|
+
end
|
253
|
+
else
|
254
|
+
# This is a regular 1:M "has many"
|
255
|
+
#
|
256
|
+
# copying the children of the regular has many will
|
257
|
+
# effectively do what is desired anyway, the through
|
258
|
+
# association is really just for convenience usage
|
259
|
+
# on the model
|
260
|
+
return if settings.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
261
|
+
|
262
|
+
self.send(relation_name).each do |old_obj|
|
263
|
+
copy_of_obj = old_obj.dup
|
264
|
+
copy_of_obj[:"#{settings.foreign_key}"] = nil
|
265
|
+
|
266
|
+
# associate this new child to the new parent object
|
267
|
+
@result.send(relation_name) << copy_of_obj
|
268
|
+
end
|
203
269
|
end
|
204
270
|
|
205
|
-
self.send(relation_name).each do |old_obj|
|
206
|
-
copy_of_obj = old_obj.dup
|
207
|
-
copy_of_obj[:"#{settings.foreign_key}"] = nil
|
208
|
-
|
209
|
-
# associate this new child to the new parent object
|
210
|
-
@result.send(relation_name) << copy_of_obj
|
211
|
-
end
|
212
271
|
when :has_and_belongs_to_many
|
213
|
-
|
214
|
-
|
215
|
-
|
272
|
+
clone = amoeba_conf.clones.include?(relation_name)
|
273
|
+
|
274
|
+
if clone
|
275
|
+
self.send(relation_name).each do |old_obj|
|
276
|
+
copy_of_obj = old_obj.dup
|
277
|
+
|
278
|
+
# associate this new child to the new parent object
|
279
|
+
@result.send(relation_name) << copy_of_obj
|
280
|
+
end
|
281
|
+
else
|
282
|
+
self.send(relation_name).each do |old_obj|
|
283
|
+
# associate this new child to the new parent object
|
284
|
+
@result.send(relation_name) << old_obj
|
285
|
+
end
|
216
286
|
end
|
217
287
|
end
|
218
288
|
end
|
@@ -220,6 +290,18 @@ module Amoeba
|
|
220
290
|
def dup(options={})
|
221
291
|
@result = super()
|
222
292
|
|
293
|
+
amoeba_conf.clones.each do |clone_field|
|
294
|
+
r = self.class.reflect_on_association clone_field
|
295
|
+
|
296
|
+
# if this is a has many through and we're gonna deep
|
297
|
+
# copy the child records, exclude the regular join
|
298
|
+
# table from copying so we don't end up with the new
|
299
|
+
# and old children on the copy
|
300
|
+
if r.macro == :has_many && r.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
301
|
+
amoeba_conf.exclude_field r.options[:through]
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
223
305
|
if amoeba_conf.enabled
|
224
306
|
if amoeba_conf.includes.count > 0
|
225
307
|
amoeba_conf.includes.each do |i|
|
@@ -252,6 +334,11 @@ module Amoeba
|
|
252
334
|
@result[n] = nil
|
253
335
|
end
|
254
336
|
|
337
|
+
# prepend any extra strings to indicate uniqueness of the new record(s)
|
338
|
+
amoeba_conf.coercions.each do |field,coercion|
|
339
|
+
@result[field] = "#{coercion}"
|
340
|
+
end
|
341
|
+
|
255
342
|
# prepend any extra strings to indicate uniqueness of the new record(s)
|
256
343
|
amoeba_conf.prefixes.each do |field,prefix|
|
257
344
|
@result[field] = "#{prefix}#{@result[field]}"
|
data/lib/amoeba/version.rb
CHANGED
data/spec/lib/amoeba_spec.rb
CHANGED
@@ -18,12 +18,18 @@ describe "amoeba" do
|
|
18
18
|
start_cat_count = Category.all.count
|
19
19
|
start_supercat_count = Supercat.all.count
|
20
20
|
start_tag_count = Tag.all.count
|
21
|
+
start_note_count = Note.all.count
|
22
|
+
start_widget_count = Widget.all.count
|
21
23
|
start_post_count = Post.all.count
|
22
24
|
start_comment_count = Comment.all.count
|
23
25
|
start_rating_count = Rating.all.count
|
24
26
|
start_postconfig_count = PostConfig.all.count
|
27
|
+
start_postwidget_count = PostWidget.all.count
|
28
|
+
start_superkitten_count = Superkitten.all.count
|
25
29
|
rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS tag_count FROM posts_tags')
|
26
30
|
start_posttag_count = rs["tag_count"]
|
31
|
+
rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS note_count FROM notes_posts')
|
32
|
+
start_postnote_count = rs["note_count"]
|
27
33
|
|
28
34
|
new_post.save
|
29
35
|
|
@@ -32,12 +38,18 @@ describe "amoeba" do
|
|
32
38
|
end_cat_count = Category.all.count
|
33
39
|
end_supercat_count = Supercat.all.count
|
34
40
|
end_tag_count = Tag.all.count
|
41
|
+
end_note_count = Note.all.count
|
42
|
+
end_widget_count = Widget.all.count
|
35
43
|
end_post_count = Post.all.count
|
36
44
|
end_comment_count = Comment.all.count
|
37
45
|
end_rating_count = Rating.all.count
|
38
46
|
end_postconfig_count = PostConfig.all.count
|
47
|
+
end_postwidget_count = PostWidget.all.count
|
48
|
+
end_superkitten_count = Superkitten.all.count
|
39
49
|
rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS tag_count FROM posts_tags')
|
40
50
|
end_posttag_count = rs["tag_count"]
|
51
|
+
rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS note_count FROM notes_posts')
|
52
|
+
end_postnote_count = rs["note_count"]
|
41
53
|
|
42
54
|
end_tag_count.should == start_tag_count
|
43
55
|
end_cat_count.should == start_cat_count
|
@@ -49,10 +61,21 @@ describe "amoeba" do
|
|
49
61
|
end_rating_count.should == start_rating_count * 2
|
50
62
|
end_postconfig_count.should == start_postconfig_count * 2
|
51
63
|
end_posttag_count.should == start_posttag_count * 2
|
64
|
+
end_widget_count.should == start_widget_count * 2
|
65
|
+
end_postwidget_count.should == start_postwidget_count * 2
|
66
|
+
end_note_count.should == start_note_count * 2
|
67
|
+
end_postnote_count.should == start_postnote_count * 2
|
68
|
+
end_superkitten_count.should == start_superkitten_count * 2
|
52
69
|
|
53
70
|
new_post.supercats.map(&:ramblings).include?("Copy of zomg").should be true
|
71
|
+
new_post.supercats.map(&:other_ramblings).uniq.length.should == 1
|
72
|
+
new_post.supercats.map(&:other_ramblings).uniq.include?("La la la").should be true
|
54
73
|
new_post.title.should == "Copy of #{old_post.title}"
|
55
74
|
new_post.contents.should == "Here's a copy: #{old_post.contents.gsub(/dog/, 'cat')} (copied version)"
|
75
|
+
|
76
|
+
new_post.widgets.map(&:id).each do |id|
|
77
|
+
old_post.widgets.map(&:id).include?(id).should_not be true
|
78
|
+
end
|
56
79
|
end
|
57
80
|
end
|
58
81
|
end
|
data/spec/support/data.rb
CHANGED
@@ -41,11 +41,41 @@ p1.tags << t2
|
|
41
41
|
p1.tags << t3
|
42
42
|
p1.save
|
43
43
|
|
44
|
+
w1 = Widget.create(:value => "My Sidebar")
|
45
|
+
w2 = Widget.create(:value => "Photo Gallery")
|
46
|
+
w3 = Widget.create(:value => "Share & Like")
|
47
|
+
|
48
|
+
p1.widgets << w1
|
49
|
+
p1.widgets << w2
|
50
|
+
p1.widgets << w3
|
51
|
+
p1.save
|
52
|
+
|
53
|
+
n1 = Note.create(:value => "This is important")
|
54
|
+
n2 = Note.create(:value => "You've been warned")
|
55
|
+
n3 = Note.create(:value => "Don't forget")
|
56
|
+
|
57
|
+
p1.notes << n1
|
58
|
+
p1.notes << n2
|
59
|
+
p1.notes << n3
|
60
|
+
p1.save
|
61
|
+
|
44
62
|
c1 = Category.create(:title => "Umbrellas", :description => "Clown fart")
|
45
63
|
c2 = Category.create(:title => "Widgets", :description => "Humpty dumpty")
|
46
64
|
c3 = Category.create(:title => "Wombats", :description => "Slushy mushy")
|
47
65
|
|
48
|
-
Supercat.create(:post => p1, :category => c1, :ramblings => "zomg")
|
49
|
-
Supercat.create(:post => p1, :category => c2, :ramblings => "why")
|
50
|
-
Supercat.create(:post => p1, :category => c3, :ramblings => "ohnoes")
|
66
|
+
s1 = Supercat.create(:post => p1, :category => c1, :ramblings => "zomg", :other_ramblings => "nerp")
|
67
|
+
s2 = Supercat.create(:post => p1, :category => c2, :ramblings => "why", :other_ramblings => "narp")
|
68
|
+
s3 = Supercat.create(:post => p1, :category => c3, :ramblings => "ohnoes", :other_ramblings => "blap")
|
69
|
+
|
70
|
+
s1.superkittens.create(:value => "Fluffy")
|
71
|
+
s1.superkittens.create(:value => "Buffy")
|
72
|
+
s1.superkittens.create(:value => "Fuzzy")
|
73
|
+
|
74
|
+
s2.superkittens.create(:value => "Hairball")
|
75
|
+
s2.superkittens.create(:value => "Crosseye")
|
76
|
+
s2.superkittens.create(:value => "Spot")
|
77
|
+
|
78
|
+
s3.superkittens.create(:value => "Dopey")
|
79
|
+
s3.superkittens.create(:value => "Sneezy")
|
80
|
+
s3.superkittens.create(:value => "Sleepy")
|
51
81
|
# }}}
|
data/spec/support/models.rb
CHANGED
@@ -11,10 +11,15 @@ class Post < ActiveRecord::Base
|
|
11
11
|
has_many :comments
|
12
12
|
has_many :supercats
|
13
13
|
has_many :categories, :through => :supercats
|
14
|
+
has_many :post_widgets
|
15
|
+
has_many :widgets, :through => :post_widgets
|
14
16
|
has_and_belongs_to_many :tags
|
17
|
+
has_and_belongs_to_many :notes
|
18
|
+
#has_and_belongs_to_many :tags
|
15
19
|
|
16
20
|
amoeba do
|
17
21
|
enable
|
22
|
+
clone [:widgets, :notes]
|
18
23
|
prepend :title => "Copy of "
|
19
24
|
append :contents => " (copied version)"
|
20
25
|
regex :contents => {:replace => /dog/, :with => 'cat'}
|
@@ -37,17 +42,30 @@ end
|
|
37
42
|
class Category < ActiveRecord::Base
|
38
43
|
has_many :supercats
|
39
44
|
has_many :posts, :through => :supercats
|
45
|
+
|
46
|
+
amoeba do
|
47
|
+
enable
|
48
|
+
prepend :ramblings => "Copy of "
|
49
|
+
set :other_ramblings => "La la la"
|
50
|
+
end
|
40
51
|
end
|
41
52
|
|
42
53
|
class Supercat < ActiveRecord::Base
|
43
54
|
belongs_to :post
|
44
55
|
belongs_to :category
|
56
|
+
has_many :superkittens
|
45
57
|
|
46
58
|
amoeba do
|
59
|
+
include_field :superkittens
|
47
60
|
prepend :ramblings => "Copy of "
|
61
|
+
set :other_ramblings => "La la la"
|
48
62
|
end
|
49
63
|
end
|
50
64
|
|
65
|
+
class Superkitten < ActiveRecord::Base
|
66
|
+
belongs_to :supercat
|
67
|
+
end
|
68
|
+
|
51
69
|
class PostConfig < ActiveRecord::Base
|
52
70
|
belongs_to :post
|
53
71
|
end
|
@@ -55,20 +73,39 @@ end
|
|
55
73
|
class Comment < ActiveRecord::Base
|
56
74
|
belongs_to :post
|
57
75
|
has_many :ratings
|
76
|
+
has_many :reviews
|
58
77
|
|
59
78
|
amoeba do
|
60
|
-
|
79
|
+
exclude_field :reviews
|
61
80
|
end
|
62
81
|
end
|
63
82
|
|
83
|
+
class Review < ActiveRecord::Base
|
84
|
+
belongs_to :comment
|
85
|
+
end
|
86
|
+
|
64
87
|
class Rating < ActiveRecord::Base
|
65
88
|
belongs_to :comment
|
66
89
|
end
|
67
90
|
|
91
|
+
class Widget < ActiveRecord::Base
|
92
|
+
has_many :post_widgets
|
93
|
+
has_many :posts, :through => :post_widgets
|
94
|
+
end
|
95
|
+
|
96
|
+
class PostWidget < ActiveRecord::Base
|
97
|
+
belongs_to :post
|
98
|
+
belongs_to :widget
|
99
|
+
end
|
100
|
+
|
68
101
|
class Tag < ActiveRecord::Base
|
69
102
|
has_and_belongs_to_many :posts
|
70
103
|
end
|
71
104
|
|
105
|
+
class Note < ActiveRecord::Base
|
106
|
+
has_and_belongs_to_many :posts
|
107
|
+
end
|
108
|
+
|
72
109
|
class User < ActiveRecord::Base
|
73
110
|
has_many :posts
|
74
111
|
end
|
data/spec/support/schema.rb
CHANGED
@@ -42,7 +42,6 @@ ActiveRecord::Schema.define do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
create_table :tags, :force => true do |t|
|
45
|
-
t.integer :post_id
|
46
45
|
t.string :value
|
47
46
|
t.timestamps
|
48
47
|
end
|
@@ -59,6 +58,25 @@ ActiveRecord::Schema.define do
|
|
59
58
|
t.integer :tag_id
|
60
59
|
end
|
61
60
|
|
61
|
+
create_table :notes, :force => true do |t|
|
62
|
+
t.string :value
|
63
|
+
t.timestamps
|
64
|
+
end
|
65
|
+
|
66
|
+
create_table :notes_posts, :force => true do |t|
|
67
|
+
t.integer :post_id
|
68
|
+
t.integer :note_id
|
69
|
+
end
|
70
|
+
|
71
|
+
create_table :widgets, :force => true do |t|
|
72
|
+
t.string :value
|
73
|
+
end
|
74
|
+
|
75
|
+
create_table :post_widgets, :force => true do |t|
|
76
|
+
t.integer :post_id
|
77
|
+
t.integer :widget_id
|
78
|
+
end
|
79
|
+
|
62
80
|
create_table :categories, :force => true do |t|
|
63
81
|
t.string :title
|
64
82
|
t.string :description
|
@@ -68,6 +86,13 @@ ActiveRecord::Schema.define do
|
|
68
86
|
t.integer :post_id
|
69
87
|
t.integer :category_id
|
70
88
|
t.string :ramblings
|
89
|
+
t.string :other_ramblings
|
90
|
+
t.timestamps
|
91
|
+
end
|
92
|
+
|
93
|
+
create_table :superkittens, :force => true do |t|
|
94
|
+
t.integer :supercat_id
|
95
|
+
t.string :value
|
71
96
|
t.timestamps
|
72
97
|
end
|
73
98
|
|
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: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
16
|
-
requirement: &
|
16
|
+
requirement: &12789100 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.0.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *12789100
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &12788540 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '2.3'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *12788540
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: sqlite3-ruby
|
38
|
-
requirement: &
|
38
|
+
requirement: &12788080 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *12788080
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: activerecord
|
49
|
-
requirement: &
|
49
|
+
requirement: &12787380 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '3.0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *12787380
|
58
58
|
description: ! 'An extension to ActiveRecord to allow the duplication method to also
|
59
59
|
copy associated children, with recursive support for nested of grandchildren. The
|
60
60
|
behavior is controllable with a simple DSL both on your rails models and on the
|