paranoid_create 0.0.10

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.
data/spec/models.rb ADDED
@@ -0,0 +1,159 @@
1
+ class Person < ActiveRecord::Base #:nodoc:
2
+ validates_uniqueness_of :name
3
+ has_many :androids, :foreign_key => :owner_id, :dependent => :destroy
4
+ end
5
+
6
+ class Android < ActiveRecord::Base #:nodoc:
7
+ paranoid
8
+ validates_uniqueness_of :name
9
+ has_many :components, :dependent => :destroy
10
+ has_one :sticker
11
+ has_many :memories, :foreign_key => 'parent_id'
12
+ has_many :dents
13
+ has_many :dings, :through => :dents
14
+ has_many :scratches, :through => :dents
15
+ has_and_belongs_to_many :places
16
+
17
+ # this code is to ensure that our destroy and restore methods
18
+ # work without triggering before/after_update callbacks
19
+ before_update :raise_hell
20
+ def raise_hell
21
+ raise "hell"
22
+ end
23
+ end
24
+
25
+ class Biped < Android
26
+ end
27
+
28
+ class Dent < ActiveRecord::Base #:nodoc:
29
+ paranoid
30
+ belongs_to :android
31
+ has_many :dings
32
+ has_many :scratches
33
+ end
34
+
35
+ class Ding < ActiveRecord::Base #:nodoc:
36
+ paranoid :field => :not_deleted, :destroyed_value => true, :not_destroyed_value => false
37
+ belongs_to :dent
38
+ end
39
+
40
+ class Scratch < ActiveRecord::Base #:nodoc:
41
+ paranoid
42
+ belongs_to :dent
43
+ end
44
+
45
+ class Component < ActiveRecord::Base #:nodoc:
46
+ paranoid
47
+ belongs_to :android, :dependent => :destroy
48
+ has_many :sub_components, :dependent => :destroy
49
+ NEW_NAME = 'Something Else!'
50
+
51
+ after_destroy :change_name
52
+ def change_name
53
+ self.update_attribute(:name, NEW_NAME)
54
+ end
55
+ end
56
+
57
+ class SubComponent < ActiveRecord::Base #:nodoc:
58
+ paranoid
59
+ belongs_to :component, :dependent => :destroy
60
+ end
61
+
62
+ class Memory < ActiveRecord::Base #:nodoc:
63
+ paranoid
64
+ belongs_to :android, :class_name => "Android", :foreign_key => "parent_id"
65
+ end
66
+
67
+ class Sticker < ActiveRecord::Base #:nodoc:
68
+ MM_NAME = "You've got method_missing"
69
+
70
+ # this simply serves to ensure that we don't break method_missing
71
+ # if it is implemented on a class and called before is_paranoid
72
+ def method_missing name, *args, &block
73
+ self.name = MM_NAME
74
+ end
75
+
76
+ paranoid
77
+ belongs_to :android
78
+ end
79
+
80
+ class AndroidWithScopedUniqueness < ActiveRecord::Base #:nodoc:
81
+ set_table_name :androids
82
+ validates_uniqueness_of :name, :scope => :deleted_at
83
+ paranoid
84
+ end
85
+
86
+ class Place < ActiveRecord::Base #:nodoc:
87
+ paranoid
88
+ has_and_belongs_to_many :androids
89
+
90
+ # this code is to ensure that our destroy and restore methods
91
+ # work without triggering before/after_update callbacks
92
+ before_update :raise_hell
93
+ def raise_hell
94
+ raise "hell"
95
+ end
96
+ end
97
+
98
+ class AndroidsPlaces < ActiveRecord::Base #:nodoc:
99
+ end
100
+
101
+ class Ninja < ActiveRecord::Base #:nodoc:
102
+ validates_uniqueness_of :name, :scope => :visible
103
+ paranoid :field => [:visible, false, true]
104
+
105
+ alias_method :vanish, :destroy
106
+
107
+ # this code is to ensure that our destroy and restore methods
108
+ # work without triggering before/after_update callbacks
109
+ before_update :raise_hell
110
+ def raise_hell
111
+ raise "hell"
112
+ end
113
+ end
114
+
115
+ class Pirate < ActiveRecord::Base #:nodoc:
116
+ paranoid :field => :alive, :destroyed_value => false, :not_destroyed_value => true
117
+
118
+ # this code is to ensure that our destroy and restore methods
119
+ # work without triggering before/after_update callbacks
120
+ before_update :raise_hell
121
+ def raise_hell
122
+ raise "hell"
123
+ end
124
+ end
125
+
126
+ class DeadPirate < ActiveRecord::Base #:nodoc:
127
+ set_table_name :pirates
128
+ paranoid :field => :alive, :destroyed_value => true, :not_destroyed_value => false
129
+ end
130
+
131
+ class RandomPirate < ActiveRecord::Base #:nodoc:
132
+ set_table_name :pirates
133
+
134
+ after_destroy :raise_an_error
135
+ def raise_an_error
136
+ raise 'after_destroy works'
137
+ end
138
+ end
139
+
140
+ class UndestroyablePirate < ActiveRecord::Base #:nodoc:
141
+ set_table_name :pirates
142
+ paranoid :field => :alive, :destroyed_value => false, :not_destroyed_value => true
143
+
144
+ before_destroy :ret_false
145
+ def ret_false
146
+ false
147
+ end
148
+ end
149
+
150
+ class Uuid < ActiveRecord::Base #:nodoc:
151
+ set_primary_key "uuid"
152
+
153
+ before_create :set_uuid
154
+ def set_uuid
155
+ self.uuid = "295b3430-85b8-012c-cfe4-002332cf7d5e"
156
+ end
157
+
158
+ paranoid
159
+ end
@@ -0,0 +1,298 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/models')
3
+
4
+ LUKE = 'Luke Skywalker'
5
+
6
+ describe Paranoid do
7
+ before(:each) do
8
+ # Sticker.delete_all
9
+ # Place.delete_all
10
+ # Android.delete_all
11
+ # Person.delete_all
12
+ # Component.delete_all
13
+ #
14
+ # @luke = Person.create(:name => LUKE)
15
+ # @r2d2 = Android.create(:name => 'R2D2', :owner_id => @luke.id)
16
+ # @c3p0 = Android.create(:name => 'C3P0', :owner_id => @luke.id)
17
+ #
18
+ # @r2d2.components.create(:name => 'Rotors')
19
+ #
20
+ # @r2d2.memories.create(:name => 'A pretty sunset')
21
+ # @c3p0.sticker = Sticker.create(:name => 'OMG, PONIES!')
22
+ # @tatooine = Place.create(:name => "Tatooine")
23
+ # @r2d2.places << @tatooine
24
+ end
25
+
26
+ describe 'basic functionality' do
27
+ before(:each) do
28
+ Place.delete_all
29
+ @tatooine, @mos_eisley, @coruscant = Place.create([{:name => "Tatooine"}, {:name => 'Mos Eisley'}, {:name => 'Coruscant'}])
30
+ end
31
+
32
+ it 'should recognize a class as paranoid' do
33
+ Person.paranoid?.should be_false
34
+ Place.paranoid?.should be_true
35
+ end
36
+
37
+ it 'should recognize an STI class as paranoid' do
38
+ Biped.paranoid?.should be_true
39
+ end
40
+
41
+ it 'should hide destroyed records' do
42
+ @tatooine.destroy
43
+ Place.first(:conditions => {:name => 'Tatooine'}).should be_nil
44
+ end
45
+
46
+ it 'should reveal destroyed records when with_destroyed' do
47
+ @tatooine.destroy
48
+ Place.with_destroyed.first(:conditions => {:name => 'Tatooine'}).should_not be_nil
49
+ end
50
+
51
+ it 'should restore the destroyed record' do
52
+ @tatooine.destroy
53
+
54
+ @tatooine = Place.with_destroyed.first(:conditions => {:name => 'Tatooine'})
55
+ @tatooine.restore
56
+
57
+ Place.first(:conditions => {:name => 'Tatooine'}).should_not be_nil
58
+ end
59
+
60
+ it 'should soft delete paranoid records' do
61
+ @tatooine.destroy
62
+
63
+ record = Place.with_destroyed.first(:conditions => {:name => 'Tatooine'})
64
+ record.should_not be_nil
65
+ record.deleted_at.should_not be_nil
66
+ end
67
+
68
+ it 'should mark the record destroyed' do
69
+ @tatooine.destroy
70
+ @tatooine.destroyed?.should be_true
71
+ end
72
+
73
+ it 'should set the deleted_field' do
74
+ @tatooine.destroy
75
+ @tatooine.deleted_at.should_not be_nil
76
+ end
77
+
78
+ it 'should show deleted_only' do
79
+ @tatooine.destroy
80
+ destroyed = Place.with_destroyed_only.all
81
+ destroyed.size.should == 1
82
+ destroyed[0].should == @tatooine
83
+ end
84
+
85
+ it 'should properly count records' do
86
+ Place.count.should == 3
87
+
88
+ @tatooine.destroy
89
+ Place.count.should == 2
90
+ Place.with_destroyed.count.should == 3
91
+ Place.with_destroyed_only.count.should == 1
92
+ end
93
+ end
94
+
95
+ describe 'for alternate field information' do
96
+ before(:each) do
97
+ Pirate.delete_all
98
+ @roberts, @jack, @hook = Pirate.create([{:name => 'Roberts'}, {:name => 'Jack'}, {:name => 'Hook'}])
99
+ end
100
+
101
+ it 'should have 3 alive pirates' do
102
+ Pirate.all.size.should == 3
103
+ end
104
+
105
+ it 'should kill the pirate' do
106
+ @roberts.destroy
107
+
108
+ record = Pirate.first(:conditions => {:name => 'Roberts'})
109
+ record.should be_nil
110
+ end
111
+
112
+ it 'should not remove the pirate record' do
113
+ @roberts.destroy
114
+
115
+ record = Pirate.with_destroyed.first(:conditions => {:name => 'Roberts'})
116
+ record.should_not be_nil
117
+ record.alive.should be_false
118
+ end
119
+
120
+ it 'should mark the pirate dead' do
121
+ @roberts.destroy
122
+ @roberts.destroyed?.should be_true
123
+ end
124
+
125
+ it 'should set alive to false' do
126
+ @roberts.destroy
127
+ @roberts.alive.should be_false
128
+ end
129
+
130
+ it 'should show deleted_only' do
131
+ @roberts.destroy
132
+ destroyed = Pirate.with_destroyed_only.all
133
+ destroyed.size.should == 1
134
+ destroyed[0].should == @roberts
135
+ end
136
+
137
+ it 'should properly count records' do
138
+ Pirate.count.should == 3
139
+
140
+ @roberts.destroy
141
+ Pirate.count.should == 2
142
+ Pirate.with_destroyed.count.should == 3
143
+ Pirate.with_destroyed_only.count.should == 1
144
+ end
145
+ end
146
+
147
+ describe 'for alternate field information with is_paranoid format field information' do
148
+ before(:each) do
149
+ Ninja.delete_all
150
+ @steve, @bob, @tim = Ninja.create([{:name => 'Steve', :visible => true}, {:name => 'Bob', :visible => true}, {:name => 'Tim', :visible => true}])
151
+ end
152
+
153
+ it 'should have 3 visible ninjas' do
154
+ Ninja.all.size.should == 3
155
+ end
156
+
157
+ it 'should vanish the ninja' do
158
+ @steve.destroy
159
+
160
+ record = Ninja.first(:conditions => {:name => 'Steve'})
161
+ record.should be_nil
162
+ end
163
+
164
+ it 'should not delete the ninja' do
165
+ @steve.destroy
166
+
167
+ record = Ninja.with_destroyed.first(:conditions => {:name => 'Steve'})
168
+ record.should_not be_nil
169
+ record.visible.should be_false
170
+ end
171
+
172
+ it 'should mark the ninja vanished' do
173
+ @steve.destroy
174
+ @steve.destroyed?.should be_true
175
+ end
176
+
177
+ it 'should set visible to false' do
178
+ @steve.destroy
179
+ @steve.visible.should be_false
180
+ end
181
+
182
+ it 'should show deleted_only' do
183
+ @steve.destroy
184
+ destroyed = Ninja.with_destroyed_only.all
185
+ destroyed.size.should == 1
186
+ destroyed[0].should == @steve
187
+ end
188
+
189
+ it 'should properly count records' do
190
+ Ninja.count.should == 3
191
+
192
+ @steve.destroy
193
+ Ninja.count.should == 2
194
+ Ninja.with_destroyed.count.should == 3
195
+ Ninja.with_destroyed_only.count.should == 1
196
+ end
197
+ end
198
+
199
+ describe 'has_many association' do
200
+ before(:each) do
201
+ Android.delete_all
202
+ Dent.delete_all
203
+
204
+ @r2d2 = Android.create(:name => 'R2D2')
205
+ @dents = Dent.create([
206
+ {:android => @r2d2, :description => 'Hit by debris'},
207
+ {:android => @r2d2, :description => 'Dropped while loading into X-Wing'},
208
+ {:android => @r2d2, :description => 'Blaster hit'}
209
+ ])
210
+
211
+ @dents[2].destroy
212
+ end
213
+
214
+ it 'should hide the soft deleted dent' do
215
+ @r2d2.dents.to_a.should == @dents[0,2]
216
+ end
217
+
218
+ it 'should show all dents with_destroyed' do
219
+ @r2d2.dents.with_destroyed.to_a.should == @dents
220
+ end
221
+
222
+ it 'should show only soft deleted with destroyed_only' do
223
+ @r2d2.dents.with_destroyed_only.to_a.should == [@dents[2]]
224
+ end
225
+
226
+ it 'should show the correct counts' do
227
+ @r2d2.dents.size.should == 2
228
+ @r2d2.dents.with_destroyed.size.should == 3
229
+ @r2d2.dents.with_destroyed_only.size.should == 1
230
+ end
231
+
232
+ it 'should load correctly through an eager load' do
233
+ @r2d2 = Android.eager_load(:dents).first
234
+ @r2d2.dents.loaded?.should be_true
235
+ @r2d2.dents.size.should == 2
236
+ @r2d2.dents.to_a.should == @dents[0,2]
237
+ end
238
+
239
+ it 'should load correctly through an include' do
240
+ @r2d2 = Android.includes(:dents).first
241
+ @r2d2.dents.loaded?.should be_true
242
+ @r2d2.dents.size.should == 2
243
+ @r2d2.dents.to_a.should == @dents[0,2]
244
+ end
245
+
246
+ it 'should work correctly for a include dependency' do
247
+ @nil = Android.includes(:dents).where('dents.description' => 'Blaster hit').first
248
+ @nil.should be_nil
249
+ end
250
+ end
251
+
252
+ describe 'callbacks' do
253
+ before(:each) do
254
+ Pirate.delete_all
255
+ end
256
+
257
+ it 'should not destroy the record when before_destroy returns false' do
258
+ pirate = UndestroyablePirate.create!(:name => 'Roberts')
259
+ lambda { pirate.destroy }.should_not change(UndestroyablePirate, :count)
260
+ end
261
+
262
+ it 'should run after_destroy callbacks' do
263
+ pirate = RandomPirate.create!(:name => 'Roberts')
264
+ lambda { pirate.destroy }.should raise_error(/after_destroy works/)
265
+ end
266
+
267
+ it 'should rollback on after_destroy error' do
268
+ pirate = RandomPirate.create!(:name => 'Roberts')
269
+ lambda { pirate.destroy rescue nil }.should_not change(RandomPirate, :count)
270
+ end
271
+ end
272
+
273
+ describe 'association destroy' do
274
+ before(:each) do
275
+ Android.delete_all
276
+ Component.delete_all
277
+ @r2d2 = Android.create(:name => 'R2D2')
278
+ @components = Component.create([{ :android => @r2d2, :name => 'Rotors' }, { :android => @r2d2, :name => 'Wheels' }])
279
+ end
280
+
281
+ it 'should delete associated models' do
282
+ Android.count.should == 1
283
+ @r2d2.components.count.should == 2
284
+ @r2d2.destroy
285
+ Android.count.should == 0
286
+ @r2d2.components.count.should == 0
287
+ end
288
+
289
+ it 'should restore associated models' do
290
+ @r2d2.destroy
291
+ Android.count.should == 0
292
+ @r2d2.components.count.should == 0
293
+ Android.with_destroyed_only.first.restore
294
+ Android.count.should == 1
295
+ @r2d2.components.count.should == 2
296
+ end
297
+ end
298
+ end
data/spec/schema.rb ADDED
@@ -0,0 +1,86 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table "androids", :force => true do |t|
3
+ t.string "name"
4
+ t.integer "owner_id"
5
+ t.datetime "deleted_at"
6
+ t.datetime "created_at"
7
+ t.datetime "updated_at"
8
+ end
9
+
10
+ create_table "dents", :force => true do |t|
11
+ t.integer "android_id"
12
+ t.string "description"
13
+ t.datetime "deleted_at"
14
+ end
15
+
16
+ create_table "dings", :force => true do |t|
17
+ t.integer "dent_id"
18
+ t.string "description"
19
+ t.boolean "not_deleted"
20
+ end
21
+
22
+ create_table "scratches", :force => true do |t|
23
+ t.integer "dent_id"
24
+ t.string "description"
25
+ t.datetime "deleted_at"
26
+ end
27
+
28
+ create_table "androids_places", :force => true, :id => false do |t|
29
+ t.integer "android_id"
30
+ t.integer "place_id"
31
+ end
32
+
33
+ create_table "places", :force => true do |t|
34
+ t.string "name"
35
+ t.datetime "deleted_at"
36
+ end
37
+
38
+ create_table "people", :force => true do |t|
39
+ t.string "name"
40
+ t.datetime "created_at"
41
+ t.datetime "updated_at"
42
+ end
43
+
44
+ create_table "components", :force => true do |t|
45
+ t.string "name"
46
+ t.integer "android_id"
47
+ t.datetime "deleted_at"
48
+ t.datetime "created_at"
49
+ t.datetime "updated_at"
50
+ end
51
+
52
+ create_table "sub_components", :force => true do |t|
53
+ t.string "name"
54
+ t.integer "component_id"
55
+ t.datetime "deleted_at"
56
+ end
57
+
58
+ create_table "memories", :force => true do |t|
59
+ t.string "name"
60
+ t.integer "parent_id"
61
+ t.datetime "deleted_at"
62
+ end
63
+
64
+ create_table "stickers", :force => true do |t|
65
+ t.string "name"
66
+ t.integer "android_id"
67
+ t.datetime "deleted_at"
68
+ end
69
+
70
+ create_table "ninjas", :force => true do |t|
71
+ t.string "name"
72
+ t.boolean "visible", :default => false
73
+ end
74
+
75
+ create_table "pirates", :force => true do |t|
76
+ t.string "name"
77
+ t.boolean "alive", :default => true
78
+ end
79
+
80
+ create_table "uuids", :id => false, :force => true do |t|
81
+ t.string "uuid", :limit => 36, :primary => true
82
+ t.string "name"
83
+ t.datetime "deleted_at"
84
+ end
85
+
86
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,27 @@
1
+ require 'paranoid'
2
+
3
+ $enabled = false
4
+
5
+ ActiveSupport::Notifications.subscribe(/sql/i) do |*args|
6
+ if $enabled
7
+ event = ActiveSupport::Notifications::Event.new(*args)
8
+ puts "SQL #{event.duration}: #{event.payload[:sql]}"
9
+ end
10
+ end
11
+
12
+ def connect(environment)
13
+ conf = YAML::load(File.open(File.dirname(__FILE__) + '/database.yml'))
14
+ ActiveRecord::Base.establish_connection(conf[environment])
15
+ end
16
+
17
+ # Open ActiveRecord connection
18
+ connect('test')
19
+
20
+ original_stdout = $stdout
21
+ $stdout = StringIO.new
22
+
23
+ begin
24
+ load(File.dirname(__FILE__) + "/schema.rb")
25
+ ensure
26
+ $stdout = original_stdout
27
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paranoid_create
3
+ version: !ruby/object:Gem::Version
4
+ hash: 11
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 10
10
+ version: 0.0.10
11
+ platform: ruby
12
+ authors:
13
+ - Philipp Ullmann
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-01 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 27
30
+ segments:
31
+ - 2
32
+ - 5
33
+ - 0
34
+ version: 2.5.0
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: sqlite3-ruby
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 29
46
+ segments:
47
+ - 1
48
+ - 3
49
+ - 3
50
+ version: 1.3.3
51
+ type: :development
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: activerecord
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 13
62
+ segments:
63
+ - 3
64
+ - 0
65
+ - 5
66
+ version: 3.0.5
67
+ type: :development
68
+ version_requirements: *id003
69
+ description:
70
+ email: philipp.ullmann@create.at
71
+ executables: []
72
+
73
+ extensions: []
74
+
75
+ extra_rdoc_files: []
76
+
77
+ files:
78
+ - .gitignore
79
+ - Gemfile
80
+ - MIT-LICENSE
81
+ - README.textile
82
+ - Rakefile
83
+ - init.rb
84
+ - lib/paranoid.rb
85
+ - lib/paranoid/base.rb
86
+ - lib/paranoid/join_association.rb
87
+ - lib/paranoid/paranoid_methods.rb
88
+ - lib/paranoid/relation.rb
89
+ - lib/paranoid/version.rb
90
+ - paranoid.gemspec
91
+ - rdoc/template.rb
92
+ - spec/database.yml
93
+ - spec/models.rb
94
+ - spec/paranoid_spec.rb
95
+ - spec/schema.rb
96
+ - spec/spec.opts
97
+ - spec/spec_helper.rb
98
+ has_rdoc: true
99
+ homepage: http://github.com/create-philipp-ullmann/paranoid/
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options: []
104
+
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 3
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ hash: 3
122
+ segments:
123
+ - 0
124
+ version: "0"
125
+ requirements: []
126
+
127
+ rubyforge_project: paranoid_create
128
+ rubygems_version: 1.3.7
129
+ signing_key:
130
+ specification_version: 3
131
+ summary: Enable soft delete of ActiveRecord records. Based off defunct ActsAsParanoid and IsParanoid
132
+ test_files:
133
+ - spec/database.yml
134
+ - spec/models.rb
135
+ - spec/paranoid_spec.rb
136
+ - spec/schema.rb
137
+ - spec/spec.opts
138
+ - spec/spec_helper.rb