never_wastes 0.0.4 → 0.0.5
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/.rspec +2 -0
- data/lib/never_wastes.rb +15 -3
- data/lib/never_wastes/version.rb +1 -1
- data/never_wastes.gemspec +12 -3
- data/spec/fake_app.rb +29 -0
- data/spec/never_wastes_spec.rb +117 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/database_cleaner.rb +13 -0
- metadata +134 -4
data/.rspec
ADDED
data/lib/never_wastes.rb
CHANGED
@@ -26,7 +26,7 @@ module NeverWastes
|
|
26
26
|
@never_wastes_datetime_column_name = :deleted_at
|
27
27
|
def self.soft_destroy_stamps
|
28
28
|
stamps = {@never_wastes_boolean_column_name => true}
|
29
|
-
stamps[@never_wastes_datetime_column_name] =
|
29
|
+
stamps[@never_wastes_datetime_column_name] = self.current_time if column_names.include?(@never_wastes_datetime_column_name.to_s)
|
30
30
|
stamps
|
31
31
|
end
|
32
32
|
|
@@ -50,8 +50,16 @@ module NeverWastes
|
|
50
50
|
|
51
51
|
default_scope {where(:deleted => false)}
|
52
52
|
|
53
|
-
|
54
|
-
|
53
|
+
class << self
|
54
|
+
def with_deleted
|
55
|
+
unscoped
|
56
|
+
end
|
57
|
+
|
58
|
+
alias_method :delete_all!, :delete_all
|
59
|
+
def delete_all_softly
|
60
|
+
update_all(deleted: true, deleted_at: self.current_time)
|
61
|
+
end
|
62
|
+
alias_method :delete_all, :delete_all_softly
|
55
63
|
end
|
56
64
|
|
57
65
|
private
|
@@ -59,6 +67,10 @@ module NeverWastes
|
|
59
67
|
def destroying_softly?
|
60
68
|
@destroying_softly
|
61
69
|
end
|
70
|
+
|
71
|
+
def self.current_time
|
72
|
+
default_timezone == :utc ? Time.now.utc : Time.now
|
73
|
+
end
|
62
74
|
end
|
63
75
|
end
|
64
76
|
|
data/lib/never_wastes/version.rb
CHANGED
data/never_wastes.gemspec
CHANGED
@@ -18,7 +18,16 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
%w{ activesupport actionpack railties }.each do |gem|
|
22
|
+
s.add_dependency gem, ['>= 3.0.0']
|
23
|
+
end
|
24
|
+
s.add_development_dependency 'bundler', ['>= 1.0.0']
|
25
|
+
s.add_development_dependency 'sqlite3', ['>= 0']
|
26
|
+
%w{ activerecord activemodel }.each do |gem|
|
27
|
+
s.add_development_dependency gem, ['>= 3.0.0']
|
28
|
+
end
|
29
|
+
s.add_development_dependency 'rspec', ['>= 0']
|
30
|
+
s.add_development_dependency 'rspec-rails', ['>= 0']
|
31
|
+
s.add_development_dependency 'factory_girl_rails', ['>= 0']
|
32
|
+
s.add_development_dependency 'database_cleaner', ['>= 0']
|
24
33
|
end
|
data/spec/fake_app.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'action_controller/railtie'
|
2
|
+
require 'factory_girl'
|
3
|
+
require 'database_cleaner'
|
4
|
+
|
5
|
+
# database
|
6
|
+
ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
|
7
|
+
ActiveRecord::Base.establish_connection('test')
|
8
|
+
|
9
|
+
#migrations
|
10
|
+
class CreateAllTables < ActiveRecord::Migration
|
11
|
+
def self.up
|
12
|
+
create_table(:users) {|t| t.string :name; t.boolean :deleted; t.datetime :deleted_at }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# models
|
17
|
+
class User < ActiveRecord::Base
|
18
|
+
never_wastes
|
19
|
+
validates_uniqueness_of :name, :scope => [:name, :deleted]
|
20
|
+
end
|
21
|
+
|
22
|
+
# factory
|
23
|
+
FactoryGirl.define do
|
24
|
+
factory :user do
|
25
|
+
sequence(:name) {|n| "test %03d" %n }
|
26
|
+
deleted false
|
27
|
+
deleted_at "2012-03-12 17:37:19"
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe User do
|
4
|
+
describe "validation" do
|
5
|
+
describe "uniqueness" do
|
6
|
+
let!(:user) { Factory.create :user, name: "test_name", deleted: false, deleted_at: nil }
|
7
|
+
context "when the same name user don't already exists" do
|
8
|
+
subject { User.new(name: "new user name") }
|
9
|
+
it { should be_valid }
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when the same name user already exists" do
|
13
|
+
subject { User.new(name: user.name) }
|
14
|
+
it { should_not be_valid }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when the same name user exists and is deleted" do
|
18
|
+
before { user.destroy }
|
19
|
+
subject { User.new(name: user.name) }
|
20
|
+
it { should be_valid }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'columns' do
|
26
|
+
let!(:user) { Factory.create :user, name: "test_name", deleted: false, deleted_at: nil }
|
27
|
+
subject { user }
|
28
|
+
|
29
|
+
context 'when user is not deleted' do
|
30
|
+
its(:deleted) { should be_false }
|
31
|
+
its(:deleted_at) { should be_nil}
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when user is deleted' do
|
35
|
+
before { user.destroy }
|
36
|
+
its(:deleted) { should be_true }
|
37
|
+
its(:deleted_at) { should_not be_nil }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "soft delete" do
|
42
|
+
let!(:user) { Factory.create :user, name: "test_name", deleted: false, deleted_at: nil }
|
43
|
+
|
44
|
+
it "should be successful" do
|
45
|
+
expect { user.destroy }.to change(User, :count).by(-1)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "delete user *soft*ly" do
|
49
|
+
expect { user.destroy }.not_to change(User.unscoped, :count)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "default_scope" do
|
54
|
+
context 'when 1 user and 1 deleted user exists' do
|
55
|
+
let!(:user) { Factory.create :user, name: "test_name", deleted: false, deleted_at: nil }
|
56
|
+
let!(:deleted_user) { Factory.create :user, deleted: true, deleted_at:Time.now }
|
57
|
+
|
58
|
+
subject { User.all }
|
59
|
+
it { should have(1).items }
|
60
|
+
it { should include(user) }
|
61
|
+
|
62
|
+
describe "able to get deleted user" do
|
63
|
+
subject { User.unscoped.where(deleted: true).first }
|
64
|
+
it { should == deleted_user }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe ".delete_all_softly" do
|
70
|
+
let!(:delete_users) { (1..3).inject([]) { |result, i| result << Factory.create(:user, deleted: false, deleted_at: nil) } }
|
71
|
+
let!(:undelete_user) { Factory.create(:user, name: 'undeleted', deleted: false, deleted_at: nil) }
|
72
|
+
|
73
|
+
it "should be successful" do
|
74
|
+
expect { User.where(User.arel_table[:name].not_eq('undeleted')).delete_all_softly }.to change(User, :count).by(-3)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should delete users *soft*ly" do
|
78
|
+
expect { User.where(User.arel_table[:name].not_eq('undeleted')).delete_all_softly }.not_to change(User.unscoped, :count)
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'after' do
|
82
|
+
before do
|
83
|
+
User.where(User.arel_table[:name].not_eq('undeleted')).delete_all_softly
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should find undeleted users" do
|
87
|
+
User.where(User.arel_table[:name].eq('undeleted')).length.should == 1
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'columns' do
|
91
|
+
context 'when user is not deleted' do
|
92
|
+
subject { undelete_user.reload }
|
93
|
+
its(:deleted) { should be_false }
|
94
|
+
its(:deleted_at) { should be_nil}
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when user is deleted' do
|
98
|
+
subject { delete_users.first.reload }
|
99
|
+
its(:deleted) { should be_true }
|
100
|
+
its(:deleted_at) { should_not be_nil }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe ".delete_all!" do
|
107
|
+
let!(:delete_users) { (1..3).inject([]) { |result, i| result << Factory.create(:user, deleted: false, deleted_at: nil) } }
|
108
|
+
let!(:undelete_user) { Factory.create(:user, name: 'undeleted', deleted: false, deleted_at: nil) }
|
109
|
+
it "should be successful" do
|
110
|
+
expect { User.where(User.arel_table[:name].not_eq('undeleted')).delete_all! }.to change(User, :count).by(-3)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should delete users" do
|
114
|
+
expect { User.where(User.arel_table[:name].not_eq('undeleted')).delete_all! }.to change(User.unscoped, :count).by(-3)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rails'
|
4
|
+
# Ensure we use 'syck' instead of 'psych' in 1.9.2
|
5
|
+
# RubyGems >= 1.5.0 uses 'psych' on 1.9.2, but
|
6
|
+
# Psych does not yet support YAML 1.1 merge keys.
|
7
|
+
# Merge keys is often used in mongoid.yml
|
8
|
+
# See: http://redmine.ruby-lang.org/issues/show/4300
|
9
|
+
if RUBY_VERSION >= '1.9.2'
|
10
|
+
YAML::ENGINE.yamler = 'syck'
|
11
|
+
end
|
12
|
+
require 'active_record'
|
13
|
+
require 'never_wastes'
|
14
|
+
require 'fake_app'
|
15
|
+
|
16
|
+
require 'rspec/rails'
|
17
|
+
# Requires supporting files with custom matchers and macros, etc,
|
18
|
+
# in ./support/ and its subdirectories.
|
19
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
20
|
+
|
21
|
+
RSpec.configure do |config|
|
22
|
+
config.before :all do
|
23
|
+
# ActiveRecord::Base.connection.execute 'CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255))' unless ActiveRecord::Base.connection.table_exists? 'users'
|
24
|
+
CreateAllTables.up unless ActiveRecord::Base.connection.table_exists? 'users'
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
DatabaseCleaner.strategy = :transaction
|
2
|
+
|
3
|
+
RSpec.configure do |config|
|
4
|
+
config.before :suite do
|
5
|
+
DatabaseCleaner.clean_with :truncation
|
6
|
+
end
|
7
|
+
config.before :each do
|
8
|
+
DatabaseCleaner.start
|
9
|
+
end
|
10
|
+
config.after :each do
|
11
|
+
DatabaseCleaner.clean
|
12
|
+
end
|
13
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: never_wastes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,129 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-03-
|
13
|
-
dependencies:
|
12
|
+
date: 2012-03-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: &2156605780 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2156605780
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: actionpack
|
27
|
+
requirement: &2156605220 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2156605220
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: railties
|
38
|
+
requirement: &2156604700 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 3.0.0
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2156604700
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: bundler
|
49
|
+
requirement: &2156604180 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.0.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2156604180
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: sqlite3
|
60
|
+
requirement: &2156603620 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2156603620
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activerecord
|
71
|
+
requirement: &2156603000 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 3.0.0
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *2156603000
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: activemodel
|
82
|
+
requirement: &2156602340 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 3.0.0
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *2156602340
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: rspec
|
93
|
+
requirement: &2156601660 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *2156601660
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: rspec-rails
|
104
|
+
requirement: &2156600780 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *2156600780
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: factory_girl_rails
|
115
|
+
requirement: &2156600260 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *2156600260
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: database_cleaner
|
126
|
+
requirement: &2156599740 !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: *2156599740
|
14
135
|
description: It changes ActiveRecord::Base#destroy to support soft delete. Kind of
|
15
136
|
simple acts_as_paranoid.
|
16
137
|
email:
|
@@ -20,6 +141,7 @@ extensions: []
|
|
20
141
|
extra_rdoc_files: []
|
21
142
|
files:
|
22
143
|
- .gitignore
|
144
|
+
- .rspec
|
23
145
|
- Gemfile
|
24
146
|
- LICENSE
|
25
147
|
- README.md
|
@@ -27,6 +149,10 @@ files:
|
|
27
149
|
- lib/never_wastes.rb
|
28
150
|
- lib/never_wastes/version.rb
|
29
151
|
- never_wastes.gemspec
|
152
|
+
- spec/fake_app.rb
|
153
|
+
- spec/never_wastes_spec.rb
|
154
|
+
- spec/spec_helper.rb
|
155
|
+
- spec/support/database_cleaner.rb
|
30
156
|
homepage: ''
|
31
157
|
licenses: []
|
32
158
|
post_install_message:
|
@@ -51,4 +177,8 @@ rubygems_version: 1.8.17
|
|
51
177
|
signing_key:
|
52
178
|
specification_version: 3
|
53
179
|
summary: simple soft delete for ActiveRecord
|
54
|
-
test_files:
|
180
|
+
test_files:
|
181
|
+
- spec/fake_app.rb
|
182
|
+
- spec/never_wastes_spec.rb
|
183
|
+
- spec/spec_helper.rb
|
184
|
+
- spec/support/database_cleaner.rb
|