delete_paranoid 1.0.5 → 2.0.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/.gitignore +2 -2
- data/.rvmrc +1 -1
- data/.travis.yml +2 -3
- data/Rakefile +5 -7
- data/delete_paranoid.gemspec +4 -5
- data/lib/delete_paranoid.rb +3 -3
- data/lib/delete_paranoid/version.rb +1 -1
- data/spec/database.yml +4 -0
- data/{test → spec}/database_setup.rb +0 -3
- data/spec/delete_paranoid_spec.rb +128 -0
- data/spec/matchers/callback_matcher.rb +88 -0
- data/{test/helper.rb → spec/spec_helper.rb} +1 -10
- metadata +33 -84
- data/test/database.yml +0 -4
- data/test/matchers/callback_matcher.rb +0 -90
- data/test/matchers/destroy_matcher.rb +0 -80
- data/test/test_delete_paranoid.rb +0 -118
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6364ec095e36d9f9111d01ad59cea774ec4f28cc
|
4
|
+
data.tar.gz: e007bafd8d2968d9767d8e24c23ae7cfc9f7cfb3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6bd18535e8ee59e98a727d1eb6eb7012894f9371db76c079073d237286d473088c0502237033263f093be0c7460c0332b619085dc2fa690ede6eb63183aaf2d2
|
7
|
+
data.tar.gz: 71df17e6558d76b208aa27547e979f09473fe80edc813967eb0ccfff5c0cffa08de254379224952ca0da94cf68335be5d8e0f0ca67d2992969ef86da00ebccae
|
data/.gitignore
CHANGED
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm use @delete_paranoid --create
|
1
|
+
rvm use "ruby-1.9.3-p484@delete_paranoid" --create
|
data/.travis.yml
CHANGED
data/Rakefile
CHANGED
@@ -3,11 +3,9 @@ Bundler::GemHelper.install_tasks
|
|
3
3
|
|
4
4
|
require 'rake'
|
5
5
|
|
6
|
-
require '
|
7
|
-
Rake::TestTask.new(:test) do |test|
|
8
|
-
test.libs << 'lib' << 'test'
|
9
|
-
test.pattern = 'test/**/test_*.rb'
|
10
|
-
test.verbose = true
|
11
|
-
end
|
12
|
-
task :default => :test
|
6
|
+
require 'rspec/core/rake_task'
|
13
7
|
|
8
|
+
desc "Run specs"
|
9
|
+
RSpec::Core::RakeTask.new do |t|
|
10
|
+
end
|
11
|
+
task :default => :spec
|
data/delete_paranoid.gemspec
CHANGED
@@ -6,8 +6,8 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = "delete_paranoid"
|
7
7
|
s.version = DeleteParanoid::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ["Ryan Sonnek"]
|
10
|
-
s.email = ["
|
9
|
+
s.authors = ["Ryan Sonnek", "developers@socialcast.com"]
|
10
|
+
s.email = ["developers@socialcast.com"]
|
11
11
|
s.homepage = "http://github.com/socialcast/delete_paranoid"
|
12
12
|
s.summary = %q{soft delete Rails ActiveRecord objects}
|
13
13
|
s.description = %q{flag database records as deleted and hide them from subsequent queries}
|
@@ -17,16 +17,15 @@ Gem::Specification.new do |s|
|
|
17
17
|
%w[activerecord].each do |lib|
|
18
18
|
dep = case ENV[lib]
|
19
19
|
when 'stable', nil then nil
|
20
|
+
when /beta/ then ["= " + ENV[lib]]
|
20
21
|
when /(\d+\.)+\d+/ then ["~> " + ENV[lib]]
|
21
22
|
else [">= 3.0"]
|
22
23
|
end
|
23
24
|
s.add_runtime_dependency(lib, dep)
|
24
25
|
end
|
25
|
-
s.add_development_dependency(%q<
|
26
|
-
s.add_development_dependency(%q<mocha>, [">= 0"])
|
26
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
27
27
|
s.add_development_dependency(%q<bundler>, [">= 0"])
|
28
28
|
s.add_development_dependency(%q<sqlite3-ruby>, ["~> 1.3.2"])
|
29
|
-
s.add_development_dependency(%q<timecop>, [">= 0"])
|
30
29
|
s.add_development_dependency(%q<rake>, [">= 0.9.2.2"])
|
31
30
|
|
32
31
|
s.files = `git ls-files`.split("\n")
|
data/lib/delete_paranoid.rb
CHANGED
@@ -4,11 +4,11 @@ require 'active_record'
|
|
4
4
|
module ActiveRecord
|
5
5
|
class Relation
|
6
6
|
alias_method :delete_all_permanently, :delete_all
|
7
|
-
def delete_all
|
7
|
+
def delete_all
|
8
8
|
if @klass.paranoid?
|
9
|
-
update_all(
|
9
|
+
update_all(:deleted_at => Time.now.utc)
|
10
10
|
else
|
11
|
-
delete_all_permanently
|
11
|
+
delete_all_permanently
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
data/spec/database.yml
ADDED
@@ -24,20 +24,17 @@ class Blog < ActiveRecord::Base
|
|
24
24
|
has_many :comments, :dependent => :destroy
|
25
25
|
has_many :links, :dependent => :destroy
|
26
26
|
acts_as_paranoid
|
27
|
-
attr_accessible :title
|
28
27
|
include CallbackMatcher::ActiveRecordHooks
|
29
28
|
end
|
30
29
|
|
31
30
|
class Comment < ActiveRecord::Base
|
32
31
|
acts_as_paranoid
|
33
|
-
attr_accessible :text
|
34
32
|
belongs_to :blog
|
35
33
|
include CallbackMatcher::ActiveRecordHooks
|
36
34
|
end
|
37
35
|
|
38
36
|
class Link < ActiveRecord::Base
|
39
37
|
belongs_to :blog
|
40
|
-
attr_accessible :name
|
41
38
|
include CallbackMatcher::ActiveRecordHooks
|
42
39
|
end
|
43
40
|
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DeleteParanoid do
|
4
|
+
|
5
|
+
shared_examples_for "soft-deleted" do
|
6
|
+
it do
|
7
|
+
subject.class.where(:id => subject.id).should_not exist
|
8
|
+
subject.class.with_deleted do
|
9
|
+
subject.class.where(:id => subject.id).should exist
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
shared_examples_for "permanently-deleted" do
|
15
|
+
it do
|
16
|
+
subject.class.where(:id => subject.id).should_not exist
|
17
|
+
subject.class.with_deleted do
|
18
|
+
subject.class.where(:id => subject.id).should_not exist
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with non-paranoid activerecord class' do
|
24
|
+
it { Link.should_not be_paranoid }
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with paranoid activerecord class' do
|
28
|
+
it { Blog.should be_paranoid }
|
29
|
+
end
|
30
|
+
|
31
|
+
let!(:blog) { Blog.create! :title => 'foo' }
|
32
|
+
|
33
|
+
context 'with instance of paranoid class' do
|
34
|
+
subject { blog }
|
35
|
+
context 'when destroying instance with instance.destroy' do
|
36
|
+
before { blog.destroy }
|
37
|
+
it do
|
38
|
+
should be_destroyed
|
39
|
+
should be_frozen
|
40
|
+
should trigger_callbacks_for :destroy
|
41
|
+
should_not trigger_callbacks_for :update
|
42
|
+
end
|
43
|
+
it_behaves_like "soft-deleted"
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when destroying instance with Class.destroy_all' do
|
47
|
+
before { Blog.where(:id => blog.id).destroy_all }
|
48
|
+
it_behaves_like "soft-deleted"
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when destroying instance with Class.delete_all_permanently" do
|
52
|
+
before { Blog.where(:id => blog.id).delete_all_permanently }
|
53
|
+
it_behaves_like "permanently-deleted"
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when destroying instance with Class.delete_permanently" do
|
57
|
+
before { Blog.delete_permanently blog.id }
|
58
|
+
it_behaves_like "permanently-deleted"
|
59
|
+
end
|
60
|
+
context 'when destroying instance with instance.destroy_permanently' do
|
61
|
+
before { blog.destroy_permanently }
|
62
|
+
it_behaves_like "permanently-deleted"
|
63
|
+
it do
|
64
|
+
should trigger_callbacks_for :destroy
|
65
|
+
should_not trigger_callbacks_for :update
|
66
|
+
end
|
67
|
+
end
|
68
|
+
context 'when destroying instance with instance.delete_permanently' do
|
69
|
+
before { blog.delete_permanently }
|
70
|
+
it_behaves_like "permanently-deleted"
|
71
|
+
it do
|
72
|
+
should_not trigger_callbacks_for :destroy
|
73
|
+
should_not trigger_callbacks_for :update
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'with paranoid instance that belongs to paranoid instance via dependent => destroy' do
|
79
|
+
let!(:comment) { blog.comments.create! :text => 'bar' }
|
80
|
+
subject { comment }
|
81
|
+
|
82
|
+
context 'when destroying parent paranoid instance with destroy' do
|
83
|
+
before { blog.destroy }
|
84
|
+
it do
|
85
|
+
should be_destroyed
|
86
|
+
should be_frozen
|
87
|
+
should trigger_callbacks_for :destroy
|
88
|
+
should_not trigger_callbacks_for :update
|
89
|
+
end
|
90
|
+
end
|
91
|
+
context 'when destroying parent paranoid instance with delete_all_permanently' do
|
92
|
+
before { Blog.where(:id => blog.id).delete_all_permanently }
|
93
|
+
it do
|
94
|
+
should_not be_destroyed
|
95
|
+
should_not be_frozen
|
96
|
+
should_not trigger_callbacks_for :destroy
|
97
|
+
Comment.where(:id => comment.id).should exist
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'with non-paranoid instance that belongs to paranoid instance via dependent => destroy' do
|
103
|
+
let!(:link) { blog.links.create! :name => 'bar' }
|
104
|
+
subject { link }
|
105
|
+
|
106
|
+
context 'when destroying parent paranoid instance with destroy' do
|
107
|
+
before { blog.destroy }
|
108
|
+
it do
|
109
|
+
should be_destroyed
|
110
|
+
should be_frozen
|
111
|
+
should trigger_callbacks_for :destroy
|
112
|
+
should_not trigger_callbacks_for :update
|
113
|
+
Link.where(:id => link.id).should_not exist
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when destroying parent paranoid instance with delete_all_permanently' do
|
118
|
+
before { Blog.where(:id => blog.id).delete_all_permanently }
|
119
|
+
it do
|
120
|
+
should_not be_destroyed
|
121
|
+
should_not be_frozen
|
122
|
+
should_not trigger_callbacks_for :destroy
|
123
|
+
Link.where(:id => link.id).should exist
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
|
2
|
+
class CallbackMatcher
|
3
|
+
CALLBACK_EVENTS = [:before, :after]
|
4
|
+
CALLBACK_TYPES = [:create, :update, :destroy, :save, :commit]
|
5
|
+
|
6
|
+
module ActiveRecordHooks
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.class_eval do
|
10
|
+
class_attribute :callback_tester_attrs
|
11
|
+
self.callback_tester_attrs = []
|
12
|
+
|
13
|
+
CALLBACK_EVENTS.each do |ce|
|
14
|
+
CALLBACK_TYPES.each do |ct|
|
15
|
+
next if ce == :before && ct == :commit
|
16
|
+
callback_name = :"#{ce}_#{ct}"
|
17
|
+
callback_attr = :"called_#{callback_name}"
|
18
|
+
|
19
|
+
callback_tester_attrs << callback_attr
|
20
|
+
attr_accessor callback_attr
|
21
|
+
|
22
|
+
send( callback_name ) {
|
23
|
+
send(:"#{callback_attr}=", true)
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
alias_method_chain :initialize, :callback_init
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize_with_callback_init(*args)
|
32
|
+
reset_callback_flags!
|
33
|
+
initialize_without_callback_init(*args)
|
34
|
+
end
|
35
|
+
|
36
|
+
def reset_callback_flags!
|
37
|
+
self.class.callback_tester_attrs.each do |attr|
|
38
|
+
send("#{attr}=", false)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
require 'rspec/matchers'
|
47
|
+
|
48
|
+
RSpec::Matchers.define :trigger_callbacks_for do |types|
|
49
|
+
|
50
|
+
check_for_match = ->(model_instance, types) {
|
51
|
+
@called = []
|
52
|
+
@not_called = []
|
53
|
+
Array.wrap(types).each do |ct|
|
54
|
+
CallbackMatcher::CALLBACK_EVENTS.each do |ce|
|
55
|
+
callback_name = "#{ce}_#{ct}"
|
56
|
+
result = model_instance.send("called_#{callback_name}".to_sym)
|
57
|
+
@called << callback_name if result
|
58
|
+
@not_called << callback_name unless result
|
59
|
+
end
|
60
|
+
end
|
61
|
+
}
|
62
|
+
|
63
|
+
match_for_should do |model_instance|
|
64
|
+
check_for_match.call(model_instance, types)
|
65
|
+
result = true
|
66
|
+
result = false unless @called.present?
|
67
|
+
result = false if @not_called.present?
|
68
|
+
result
|
69
|
+
end
|
70
|
+
|
71
|
+
match_for_should_not do |model_instance|
|
72
|
+
check_for_match.call(model_instance, types)
|
73
|
+
result = true
|
74
|
+
result = false unless @not_called.present?
|
75
|
+
result = false if @called.present?
|
76
|
+
result
|
77
|
+
end
|
78
|
+
|
79
|
+
failure_message_for_should do |actual|
|
80
|
+
["Called:\t#{@called.join("\n\t")}", "Not called:\t#{@called.join("\n\t")}"].join("\n")
|
81
|
+
end
|
82
|
+
|
83
|
+
failure_message_for_should_not do |actual|
|
84
|
+
["Called:\t#{@called.join("\n\t")}", "Not called:\t#{@called.join("\n\t")}"].join("\n")
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
@@ -7,20 +7,11 @@ rescue Bundler::BundlerError => e
|
|
7
7
|
$stderr.puts "Run `bundle install` to install missing gems"
|
8
8
|
exit e.status_code
|
9
9
|
end
|
10
|
-
require '
|
11
|
-
require 'shoulda'
|
12
|
-
require 'mocha'
|
13
|
-
require 'timecop'
|
10
|
+
require 'rspec/matchers'
|
14
11
|
|
15
12
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
16
13
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
17
14
|
require 'delete_paranoid'
|
18
|
-
require 'matchers/destroy_matcher'
|
19
15
|
require 'matchers/callback_matcher'
|
20
16
|
require 'database_setup'
|
21
17
|
|
22
|
-
class Test::Unit::TestCase
|
23
|
-
extend DestroyMatcher::MatcherMethods
|
24
|
-
extend CallbackMatcher::MatcherMethods
|
25
|
-
end
|
26
|
-
|
metadata
CHANGED
@@ -1,138 +1,96 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delete_paranoid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 2.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Ryan Sonnek
|
8
|
+
- developers@socialcast.com
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-06-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
17
|
requirements:
|
19
|
-
- -
|
18
|
+
- - ">="
|
20
19
|
- !ruby/object:Gem::Version
|
21
20
|
version: '0'
|
22
21
|
type: :runtime
|
23
22
|
prerelease: false
|
24
23
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
24
|
requirements:
|
27
|
-
- -
|
25
|
+
- - ">="
|
28
26
|
- !ruby/object:Gem::Version
|
29
27
|
version: '0'
|
30
28
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
29
|
+
name: rspec
|
32
30
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
31
|
requirements:
|
35
|
-
- -
|
32
|
+
- - ">="
|
36
33
|
- !ruby/object:Gem::Version
|
37
34
|
version: '0'
|
38
35
|
type: :development
|
39
36
|
prerelease: false
|
40
37
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
38
|
requirements:
|
43
|
-
- -
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: '0'
|
46
|
-
- !ruby/object:Gem::Dependency
|
47
|
-
name: mocha
|
48
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
|
-
requirements:
|
51
|
-
- - ! '>='
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
54
|
-
type: :development
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
|
-
requirements:
|
59
|
-
- - ! '>='
|
39
|
+
- - ">="
|
60
40
|
- !ruby/object:Gem::Version
|
61
41
|
version: '0'
|
62
42
|
- !ruby/object:Gem::Dependency
|
63
43
|
name: bundler
|
64
44
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
45
|
requirements:
|
67
|
-
- -
|
46
|
+
- - ">="
|
68
47
|
- !ruby/object:Gem::Version
|
69
48
|
version: '0'
|
70
49
|
type: :development
|
71
50
|
prerelease: false
|
72
51
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
52
|
requirements:
|
75
|
-
- -
|
53
|
+
- - ">="
|
76
54
|
- !ruby/object:Gem::Version
|
77
55
|
version: '0'
|
78
56
|
- !ruby/object:Gem::Dependency
|
79
57
|
name: sqlite3-ruby
|
80
58
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
59
|
requirements:
|
83
|
-
- - ~>
|
60
|
+
- - "~>"
|
84
61
|
- !ruby/object:Gem::Version
|
85
62
|
version: 1.3.2
|
86
63
|
type: :development
|
87
64
|
prerelease: false
|
88
65
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
66
|
requirements:
|
91
|
-
- - ~>
|
67
|
+
- - "~>"
|
92
68
|
- !ruby/object:Gem::Version
|
93
69
|
version: 1.3.2
|
94
|
-
- !ruby/object:Gem::Dependency
|
95
|
-
name: timecop
|
96
|
-
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
|
-
requirements:
|
99
|
-
- - ! '>='
|
100
|
-
- !ruby/object:Gem::Version
|
101
|
-
version: '0'
|
102
|
-
type: :development
|
103
|
-
prerelease: false
|
104
|
-
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
|
-
requirements:
|
107
|
-
- - ! '>='
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
version: '0'
|
110
70
|
- !ruby/object:Gem::Dependency
|
111
71
|
name: rake
|
112
72
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
73
|
requirements:
|
115
|
-
- -
|
74
|
+
- - ">="
|
116
75
|
- !ruby/object:Gem::Version
|
117
76
|
version: 0.9.2.2
|
118
77
|
type: :development
|
119
78
|
prerelease: false
|
120
79
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
80
|
requirements:
|
123
|
-
- -
|
81
|
+
- - ">="
|
124
82
|
- !ruby/object:Gem::Version
|
125
83
|
version: 0.9.2.2
|
126
84
|
description: flag database records as deleted and hide them from subsequent queries
|
127
85
|
email:
|
128
|
-
-
|
86
|
+
- developers@socialcast.com
|
129
87
|
executables: []
|
130
88
|
extensions: []
|
131
89
|
extra_rdoc_files: []
|
132
90
|
files:
|
133
|
-
- .gitignore
|
134
|
-
- .rvmrc
|
135
|
-
- .travis.yml
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rvmrc"
|
93
|
+
- ".travis.yml"
|
136
94
|
- CONTRIBUTORS.txt
|
137
95
|
- Gemfile
|
138
96
|
- LICENSE.txt
|
@@ -141,46 +99,37 @@ files:
|
|
141
99
|
- delete_paranoid.gemspec
|
142
100
|
- lib/delete_paranoid.rb
|
143
101
|
- lib/delete_paranoid/version.rb
|
144
|
-
-
|
145
|
-
-
|
146
|
-
-
|
147
|
-
-
|
148
|
-
-
|
149
|
-
- test/test_delete_paranoid.rb
|
102
|
+
- spec/database.yml
|
103
|
+
- spec/database_setup.rb
|
104
|
+
- spec/delete_paranoid_spec.rb
|
105
|
+
- spec/matchers/callback_matcher.rb
|
106
|
+
- spec/spec_helper.rb
|
150
107
|
homepage: http://github.com/socialcast/delete_paranoid
|
151
108
|
licenses: []
|
109
|
+
metadata: {}
|
152
110
|
post_install_message:
|
153
111
|
rdoc_options: []
|
154
112
|
require_paths:
|
155
113
|
- lib
|
156
114
|
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
-
none: false
|
158
115
|
requirements:
|
159
|
-
- -
|
116
|
+
- - ">="
|
160
117
|
- !ruby/object:Gem::Version
|
161
118
|
version: '0'
|
162
|
-
segments:
|
163
|
-
- 0
|
164
|
-
hash: -2970473381417290609
|
165
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
|
-
none: false
|
167
120
|
requirements:
|
168
|
-
- -
|
121
|
+
- - ">="
|
169
122
|
- !ruby/object:Gem::Version
|
170
123
|
version: '0'
|
171
|
-
segments:
|
172
|
-
- 0
|
173
|
-
hash: -2970473381417290609
|
174
124
|
requirements: []
|
175
125
|
rubyforge_project: delete_paranoid
|
176
|
-
rubygems_version:
|
126
|
+
rubygems_version: 2.2.2
|
177
127
|
signing_key:
|
178
|
-
specification_version:
|
128
|
+
specification_version: 4
|
179
129
|
summary: soft delete Rails ActiveRecord objects
|
180
130
|
test_files:
|
181
|
-
-
|
182
|
-
-
|
183
|
-
-
|
184
|
-
-
|
185
|
-
-
|
186
|
-
- test/test_delete_paranoid.rb
|
131
|
+
- spec/database.yml
|
132
|
+
- spec/database_setup.rb
|
133
|
+
- spec/delete_paranoid_spec.rb
|
134
|
+
- spec/matchers/callback_matcher.rb
|
135
|
+
- spec/spec_helper.rb
|
data/test/database.yml
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
|
2
|
-
class CallbackMatcher
|
3
|
-
CALLBACK_EVENTS = [:before, :after, :after_commit_on]
|
4
|
-
CALLBACK_TYPES = [:create, :update, :destroy, :save]
|
5
|
-
|
6
|
-
module MatcherMethods
|
7
|
-
|
8
|
-
def trigger_callbacks_for(callback_types)
|
9
|
-
CallbackMatcher.new Array.wrap(callback_types)
|
10
|
-
end
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
module ActiveRecordHooks
|
15
|
-
|
16
|
-
def self.included(base)
|
17
|
-
base.class_eval do
|
18
|
-
class << self
|
19
|
-
attr_accessor :callback_tester_attrs
|
20
|
-
end
|
21
|
-
@callback_tester_attrs = []
|
22
|
-
CALLBACK_EVENTS.each do |ce|
|
23
|
-
CALLBACK_TYPES.each do |ct|
|
24
|
-
callback_name = :"#{ce}_#{ct}"
|
25
|
-
callback_attr = :"called_#{callback_name}"
|
26
|
-
callback_method, has_on_option = (ce.to_s =~ /_on/ ? [ce.to_s.gsub('_on',''), true] : [callback_name, false])
|
27
|
-
@callback_tester_attrs << callback_attr
|
28
|
-
attr_accessor callback_attr
|
29
|
-
send( callback_method, (has_on_option ? {:on => ct} : {})) {
|
30
|
-
instance_variable_set(:"@#{callback_attr}", true)
|
31
|
-
}
|
32
|
-
|
33
|
-
define_method :"#{callback_attr}?" do
|
34
|
-
instance_variable_get(:"@#{callback_attr}")
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
alias_method_chain :initialize, :callback_init
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def initialize_with_callback_init(*args)
|
43
|
-
reset_callback_flags!
|
44
|
-
initialize_without_callback_init(*args)
|
45
|
-
end
|
46
|
-
|
47
|
-
def reset_callback_flags!
|
48
|
-
self.class.callback_tester_attrs.each do |attr|
|
49
|
-
send("#{attr}=", false)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
def initialize(callback_types)
|
56
|
-
@callback_types = callback_types
|
57
|
-
end
|
58
|
-
|
59
|
-
def failure_message
|
60
|
-
"Expected #{@subject} #{expectation}:"
|
61
|
-
end
|
62
|
-
|
63
|
-
def negative_failure_message
|
64
|
-
"Did not expect #{@subject} #{expectation}:"
|
65
|
-
end
|
66
|
-
|
67
|
-
def description
|
68
|
-
"check that #{@callback_types.join(', ')} callbacks were called"
|
69
|
-
end
|
70
|
-
|
71
|
-
def expectation
|
72
|
-
@expectations.join("\n")
|
73
|
-
end
|
74
|
-
|
75
|
-
def matches?(subject)
|
76
|
-
@subject = subject
|
77
|
-
@expectations = []
|
78
|
-
result = true
|
79
|
-
@callback_types.each do |ct|
|
80
|
-
CALLBACK_EVENTS.each do |ce|
|
81
|
-
called = @subject.send(:"called_#{ce}_#{ct}?")
|
82
|
-
result &&= called
|
83
|
-
@expectations << "#{ce}_#{ct} callbacks to be triggered"
|
84
|
-
end
|
85
|
-
end
|
86
|
-
result
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
|
@@ -1,80 +0,0 @@
|
|
1
|
-
module DeleteParanoid
|
2
|
-
class DestroyMatcher
|
3
|
-
def softly
|
4
|
-
@softly = true
|
5
|
-
self
|
6
|
-
end
|
7
|
-
def and_freeze
|
8
|
-
@frozen = true
|
9
|
-
self
|
10
|
-
end
|
11
|
-
def and_mark_as_destroyed
|
12
|
-
@destroyed = true
|
13
|
-
self
|
14
|
-
end
|
15
|
-
def description
|
16
|
-
"destroy the subject"
|
17
|
-
end
|
18
|
-
def matches?(subject)
|
19
|
-
@subject = subject
|
20
|
-
errors.empty?
|
21
|
-
end
|
22
|
-
def failure_message
|
23
|
-
"Expected #{@subject.inspect} to be destroyed: #{errors.join("\n")}"
|
24
|
-
end
|
25
|
-
def errors
|
26
|
-
return @errors if @errors
|
27
|
-
@errors = []
|
28
|
-
@errors << "was found in database" if subject_found?
|
29
|
-
@errors << "was not found with_deleted in database" if softly? && !subject_found_with_deleted?
|
30
|
-
@errors << "did not populate deleted_at timestamp" if softly? && !subject_deleted_at?
|
31
|
-
@errors << "did not freeze instance" if frozen? && !@subject.frozen?
|
32
|
-
@errors << "did not destroy instance" if destroyed? && !@subject.destroyed?
|
33
|
-
@errors
|
34
|
-
end
|
35
|
-
def softly?
|
36
|
-
!!@softly
|
37
|
-
end
|
38
|
-
def frozen?
|
39
|
-
!!@frozen
|
40
|
-
end
|
41
|
-
def destroyed?
|
42
|
-
!!@destroyed
|
43
|
-
end
|
44
|
-
def subject_found?
|
45
|
-
!!@subject.class.find(@subject.id)
|
46
|
-
rescue ActiveRecord::RecordNotFound
|
47
|
-
false
|
48
|
-
end
|
49
|
-
def subject_found_with_deleted?
|
50
|
-
@subject.class.with_deleted do
|
51
|
-
!!@subject.class.find(@subject.id)
|
52
|
-
end
|
53
|
-
rescue ActiveRecord::RecordNotFound
|
54
|
-
false
|
55
|
-
end
|
56
|
-
def subject_deleted_at?
|
57
|
-
@subject.class.with_deleted do
|
58
|
-
@subject.class.find(@subject.id).deleted_at
|
59
|
-
end
|
60
|
-
rescue ActiveRecord::RecordNotFound
|
61
|
-
false
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
class DestroyMatcher
|
68
|
-
module MatcherMethods
|
69
|
-
def soft_destroy
|
70
|
-
DestroyMatcher.new :soft
|
71
|
-
end
|
72
|
-
def hard_destroy
|
73
|
-
DestroyMatcher.new :hard
|
74
|
-
end
|
75
|
-
def destroy_subject
|
76
|
-
DeleteParanoid::DestroyMatcher.new
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
@@ -1,118 +0,0 @@
|
|
1
|
-
require File.join(File.expand_path(File.dirname(__FILE__)), 'helper.rb')
|
2
|
-
|
3
|
-
class TestDeleteParanoid < Test::Unit::TestCase
|
4
|
-
context 'with non-paranoid activerecord class' do
|
5
|
-
should 'not be paranoid' do
|
6
|
-
assert !Link.paranoid?
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
context 'with paranoid activerecord class' do
|
11
|
-
should 'be paranoid' do
|
12
|
-
assert Blog.paranoid?
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
context 'with instance of paranoid class' do
|
17
|
-
setup do
|
18
|
-
@blog = Blog.create! :title => 'foo'
|
19
|
-
end
|
20
|
-
context 'when destroying instance with instance.destroy' do
|
21
|
-
subject do
|
22
|
-
@blog.destroy
|
23
|
-
@blog
|
24
|
-
end
|
25
|
-
should destroy_subject.softly.and_freeze.and_mark_as_destroyed
|
26
|
-
should trigger_callbacks_for :destroy
|
27
|
-
should_not trigger_callbacks_for :update
|
28
|
-
end
|
29
|
-
context 'when destroying instance with Class.destroy_all' do
|
30
|
-
subject do
|
31
|
-
Blog.destroy_all :id => @blog.id
|
32
|
-
@blog
|
33
|
-
end
|
34
|
-
should destroy_subject.softly
|
35
|
-
end
|
36
|
-
context "when destroying instance with Class.delete_all_permanently" do
|
37
|
-
subject do
|
38
|
-
Blog.where({:id => @blog.id}).delete_all_permanently
|
39
|
-
@blog
|
40
|
-
end
|
41
|
-
should destroy_subject
|
42
|
-
end
|
43
|
-
context "when destroying instance with Class.delete_permanently" do
|
44
|
-
subject do
|
45
|
-
Blog.delete_permanently @blog.id
|
46
|
-
@blog
|
47
|
-
end
|
48
|
-
should destroy_subject
|
49
|
-
end
|
50
|
-
context 'when destroying instance with instance.destroy_permanently' do
|
51
|
-
subject do
|
52
|
-
@blog.destroy_permanently
|
53
|
-
@blog
|
54
|
-
end
|
55
|
-
should destroy_subject
|
56
|
-
should trigger_callbacks_for :destroy
|
57
|
-
should_not trigger_callbacks_for :update
|
58
|
-
end
|
59
|
-
context 'when destroying instance with instance.delete_permanently' do
|
60
|
-
subject do
|
61
|
-
@blog.delete_permanently
|
62
|
-
@blog
|
63
|
-
end
|
64
|
-
should destroy_subject
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
context 'with paranoid instance that has belongs to paranoid instance' do
|
69
|
-
setup do
|
70
|
-
@blog = Blog.create!(:title => 'foo')
|
71
|
-
@comment = @blog.comments.create! :text => 'bar'
|
72
|
-
end
|
73
|
-
context 'when destroying parent paranoid instance with destroy' do
|
74
|
-
subject do
|
75
|
-
@blog.destroy
|
76
|
-
@comment
|
77
|
-
end
|
78
|
-
|
79
|
-
should destroy_subject.softly.and_freeze.and_mark_as_destroyed
|
80
|
-
should trigger_callbacks_for :destroy
|
81
|
-
#should_not trigger_callbacks_for :update
|
82
|
-
end
|
83
|
-
context 'when destroying parent paranoid instance with delete_all_permanently' do
|
84
|
-
subject do
|
85
|
-
Blog.where({:id => @blog.id}).delete_all_permanently
|
86
|
-
@comment
|
87
|
-
end
|
88
|
-
|
89
|
-
should_not destroy_subject
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
context 'with non-paranoid instance that has belongs to paranoid instance' do
|
94
|
-
setup do
|
95
|
-
@blog = Blog.create!(:title => 'foo')
|
96
|
-
@link = @blog.links.create! :name => 'bar'
|
97
|
-
end
|
98
|
-
context 'when destroying parent paranoid instance with destroy' do
|
99
|
-
subject do
|
100
|
-
@blog.destroy
|
101
|
-
@link
|
102
|
-
end
|
103
|
-
|
104
|
-
should destroy_subject.and_freeze.and_mark_as_destroyed
|
105
|
-
should trigger_callbacks_for :destroy
|
106
|
-
#should_not trigger_callbacks_for :update
|
107
|
-
end
|
108
|
-
context 'when destroying parent paranoid instance with delete_all_permanently' do
|
109
|
-
subject do
|
110
|
-
Blog.where({:id => @blog.id}).delete_all_permanently
|
111
|
-
@link
|
112
|
-
end
|
113
|
-
|
114
|
-
should_not destroy_subject
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|