joshuaclayton-paranoia 0.0.1
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/MIT-LICENSE +20 -0
- data/Manifest +12 -0
- data/README.textile +7 -0
- data/Rakefile +13 -0
- data/lib/paranoia.rb +29 -0
- data/paranoia.gemspec +38 -0
- data/rails/init.rb +1 -0
- data/test/database.yml +3 -0
- data/test/factories.rb +8 -0
- data/test/models.rb +95 -0
- data/test/paranoia_test.rb +80 -0
- data/test/schema.rb +49 -0
- data/test/test_helper.rb +28 -0
- metadata +97 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Joshua Clayton
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
data/README.textile
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
h1. Paranoia
|
2
|
+
|
3
|
+
Essentially, paranoia is a ripoff of is_paranoid; I'm just trying to get the paranoid scope to work without using `with_exclusive_scope`, since it nullifies any other named scopes etc.
|
4
|
+
|
5
|
+
It's purely test-driven, since I'm planning on hacking on it 'til everything passes. Until then, consider this alpha software.
|
6
|
+
|
7
|
+
Copyright (c) 2009 Joshua Clayton, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
Echoe.new("paranoia", "0.0.1") do |p|
|
7
|
+
p.description = "Paranoid models"
|
8
|
+
p.url = "http://github.com/joshuaclayton/paranoia"
|
9
|
+
p.author = "Joshua Clayton"
|
10
|
+
p.email = "joshua.clayton@gmail.com"
|
11
|
+
p.ignore_pattern = ["tmp/*"]
|
12
|
+
p.development_dependencies = ["activerecord >= 2.3.0", "activesupport >= 2.1.0"]
|
13
|
+
end
|
data/lib/paranoia.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "active_record"
|
2
|
+
|
3
|
+
module Paranoia
|
4
|
+
|
5
|
+
def paranoia(opts = {})
|
6
|
+
opts[:field] ||= [:deleted_at, Proc.new { Time.now.utc }, nil]
|
7
|
+
class_inheritable_accessor :destroyed_field, :field_destroyed, :field_not_destroyed
|
8
|
+
self.destroyed_field, self.field_destroyed, self.field_not_destroyed = opts[:field]
|
9
|
+
|
10
|
+
extend ClassMethods
|
11
|
+
include InstanceMethods
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def with_destroyed
|
16
|
+
scoped({})
|
17
|
+
end
|
18
|
+
|
19
|
+
def only_destroyed
|
20
|
+
scoped({:conditions => ["#{self.quoted_table_name}.#{self.destroyed_field} IS NOT ?", self.field_not_destroyed]})
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module InstanceMethods
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
ActiveRecord::Base.send(:extend, Paranoia)
|
data/paranoia.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{paranoia}
|
5
|
+
s.version = "0.0.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Joshua Clayton"]
|
9
|
+
s.date = %q{2009-05-30}
|
10
|
+
s.description = %q{Paranoid models}
|
11
|
+
s.email = %q{joshua.clayton@gmail.com}
|
12
|
+
s.extra_rdoc_files = ["lib/paranoia.rb", "README.textile"]
|
13
|
+
s.files = ["lib/paranoia.rb", "MIT-LICENSE", "rails/init.rb", "Rakefile", "README.textile", "test/database.yml", "test/factories.rb", "test/models.rb", "test/paranoia_test.rb", "test/schema.rb", "test/test_helper.rb", "Manifest", "paranoia.gemspec"]
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.homepage = %q{http://github.com/joshuaclayton/paranoia}
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Paranoia", "--main", "README.textile"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{paranoia}
|
19
|
+
s.rubygems_version = %q{1.3.2}
|
20
|
+
s.summary = %q{Paranoid models}
|
21
|
+
s.test_files = ["test/paranoia_test.rb", "test/test_helper.rb"]
|
22
|
+
|
23
|
+
if s.respond_to? :specification_version then
|
24
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
25
|
+
s.specification_version = 3
|
26
|
+
|
27
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
28
|
+
s.add_development_dependency(%q<activerecord>, [">= 0", ">= 2.3.0"])
|
29
|
+
s.add_development_dependency(%q<activesupport>, [">= 0", ">= 2.1.0"])
|
30
|
+
else
|
31
|
+
s.add_dependency(%q<activerecord>, [">= 0", ">= 2.3.0"])
|
32
|
+
s.add_dependency(%q<activesupport>, [">= 0", ">= 2.1.0"])
|
33
|
+
end
|
34
|
+
else
|
35
|
+
s.add_dependency(%q<activerecord>, [">= 0", ">= 2.3.0"])
|
36
|
+
s.add_dependency(%q<activesupport>, [">= 0", ">= 2.1.0"])
|
37
|
+
end
|
38
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "paranoia"
|
data/test/database.yml
ADDED
data/test/factories.rb
ADDED
data/test/models.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
class Person < ActiveRecord::Base
|
2
|
+
validates_uniqueness_of :name
|
3
|
+
has_many :androids, :foreign_key => :owner_id, :dependent => :destroy
|
4
|
+
end
|
5
|
+
|
6
|
+
class Android < ActiveRecord::Base
|
7
|
+
validates_uniqueness_of :name
|
8
|
+
has_many :components, :dependent => :destroy
|
9
|
+
has_one :sticker
|
10
|
+
has_many :memories, :foreign_key => "parent_id"
|
11
|
+
|
12
|
+
named_scope :active, :conditions => {:active => true}
|
13
|
+
paranoia
|
14
|
+
|
15
|
+
# this code is to ensure that our destroy and restore methods
|
16
|
+
# work without triggering before/after_update callbacks
|
17
|
+
before_update :raise_hell
|
18
|
+
def raise_hell
|
19
|
+
raise RuntimeError, "hell"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Component < ActiveRecord::Base
|
24
|
+
paranoia
|
25
|
+
belongs_to :android, :dependent => :destroy
|
26
|
+
has_many :sub_components, :dependent => :destroy
|
27
|
+
NEW_NAME = "Something Else!"
|
28
|
+
|
29
|
+
after_destroy :change_name
|
30
|
+
def change_name
|
31
|
+
self.update_attribute(:name, NEW_NAME)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class SubComponent < ActiveRecord::Base
|
36
|
+
paranoia
|
37
|
+
belongs_to :component, :dependent => :destroy
|
38
|
+
end
|
39
|
+
|
40
|
+
class Memory < ActiveRecord::Base
|
41
|
+
paranoia
|
42
|
+
belongs_to :android, :class_name => "Android", :foreign_key => "parent_id"
|
43
|
+
end
|
44
|
+
|
45
|
+
class Sticker < ActiveRecord::Base
|
46
|
+
MM_NAME = "You've got method_missing"
|
47
|
+
|
48
|
+
# this simply serves to ensure that we don't break method_missing
|
49
|
+
# if it is implemented on a class and called before paranoia
|
50
|
+
def method_missing(name, *args, &block)
|
51
|
+
self.name = MM_NAME
|
52
|
+
end
|
53
|
+
|
54
|
+
paranoia
|
55
|
+
belongs_to :android
|
56
|
+
end
|
57
|
+
|
58
|
+
class AndroidWithScopedUniqueness < ActiveRecord::Base
|
59
|
+
set_table_name :androids
|
60
|
+
validates_uniqueness_of :name, :scope => :deleted_at
|
61
|
+
paranoia
|
62
|
+
end
|
63
|
+
|
64
|
+
class Ninja < ActiveRecord::Base
|
65
|
+
validates_uniqueness_of :name, :scope => :visible
|
66
|
+
paranoia :field => [:visible, false, true]
|
67
|
+
|
68
|
+
alias_method :vanish, :destroy
|
69
|
+
end
|
70
|
+
|
71
|
+
class Pirate < ActiveRecord::Base
|
72
|
+
paranoia :field => [:alive, false, true]
|
73
|
+
end
|
74
|
+
|
75
|
+
class DeadPirate < ActiveRecord::Base
|
76
|
+
set_table_name :pirates
|
77
|
+
paranoia :field => [:alive, true, false]
|
78
|
+
end
|
79
|
+
|
80
|
+
class RandomPirate < ActiveRecord::Base
|
81
|
+
set_table_name :pirates
|
82
|
+
|
83
|
+
def after_destroy
|
84
|
+
raise "after_destroy works"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class UndestroyablePirate < ActiveRecord::Base
|
89
|
+
set_table_name :pirates
|
90
|
+
paranoia :field => [:alive, false, true]
|
91
|
+
|
92
|
+
def before_destroy
|
93
|
+
false
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ParanoiaTest < ActiveSupport::TestCase
|
4
|
+
context "A model without paranoia" do
|
5
|
+
setup { @person = Factory(:person) }
|
6
|
+
|
7
|
+
context "when destroyed" do
|
8
|
+
setup { @person.destroy }
|
9
|
+
should_change "Person.count", :by => -1
|
10
|
+
end
|
11
|
+
|
12
|
+
should "not be paranoid" do
|
13
|
+
assert_raise NoMethodError do
|
14
|
+
Person.count_with_destroyed
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "A model with paranoia" do
|
20
|
+
setup { @android = Factory(:android); Factory(:android, :active => false) }
|
21
|
+
teardown { DatabaseCleaner.clean }
|
22
|
+
|
23
|
+
context "when saved" do
|
24
|
+
should "trigger callbacks normally" do
|
25
|
+
assert_raise RuntimeError do
|
26
|
+
@android.update_attribute :name, "Junk"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
should "not trigger callbacks when destroyed" do
|
31
|
+
assert_nothing_raised do
|
32
|
+
@android.destroy
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when destroyed" do
|
38
|
+
context "as an instance" do
|
39
|
+
setup { @android.destroy }
|
40
|
+
should_change "Android.count", :by => -1
|
41
|
+
|
42
|
+
should "count the correct number of models" do
|
43
|
+
assert_equal 1, Android.count
|
44
|
+
assert_equal 2, Android.with_destroyed.count
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "without additional named scopes" do
|
49
|
+
setup { Android.destroy_all }
|
50
|
+
should_change "Android.count", :from => 2, :to => 0
|
51
|
+
should_change "Android.only_destroyed.count", :from => 0, :to => 2
|
52
|
+
end
|
53
|
+
|
54
|
+
context "with additional named scopes" do
|
55
|
+
setup { Android.active.destroy_all }
|
56
|
+
should_change "Android.count", :from => 2, :to => 1
|
57
|
+
should_change "Android.only_destroyed.count", :from => 0, :to => 1
|
58
|
+
should_change "Android.active.count", :from => 1, :to => 0
|
59
|
+
should_change "Android.active.only_destroyed.count", :from => 0, :to => 1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when deleted" do
|
64
|
+
context "without additional named scopes" do
|
65
|
+
setup { Android.delete_all }
|
66
|
+
should_change "Android.with_destroyed.count", :from => 2, :to => 0
|
67
|
+
should_not_change "Android.only_destroyed.count"
|
68
|
+
end
|
69
|
+
|
70
|
+
context "with additional named scopes" do
|
71
|
+
setup { Android.active.delete_all }
|
72
|
+
should_change "Android.with_destroyed.count", :from => 2, :to => 1
|
73
|
+
should_not_change "Android.only_destroyed.count"
|
74
|
+
should_change "Android.active.with_destroyed.count", :from => 1, :to => 0
|
75
|
+
should_not_change "Android.active.only_destroyed.count"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
data/test/schema.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 20090529222000) do
|
2
|
+
create_table :androids, :force => true do |table|
|
3
|
+
table.string :name
|
4
|
+
table.belongs_to :owner
|
5
|
+
table.boolean :active, :default => true
|
6
|
+
table.timestamps
|
7
|
+
table.datetime :deleted_at
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table :people, :force => true do |table|
|
11
|
+
table.string :name
|
12
|
+
table.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :components, :force => true do |table|
|
16
|
+
table.string :name
|
17
|
+
table.belongs_to :android
|
18
|
+
table.timestamps
|
19
|
+
table.datetime :deleted_at
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table :sub_components, :force => true do |table|
|
23
|
+
table.string :name
|
24
|
+
table.belongs_to :component
|
25
|
+
table.datetime :deleted_at
|
26
|
+
end
|
27
|
+
|
28
|
+
create_table :memories, :force => true do |table|
|
29
|
+
table.string :name
|
30
|
+
table.belongs_to :parent
|
31
|
+
table.datetime :deleted_at
|
32
|
+
end
|
33
|
+
|
34
|
+
create_table :stickers, :force => true do |table|
|
35
|
+
table.string :name
|
36
|
+
table.belongs_to :android
|
37
|
+
table.datetime :deleted_at
|
38
|
+
end
|
39
|
+
|
40
|
+
create_table :ninjas, :force => true do |table|
|
41
|
+
table.string :name
|
42
|
+
table.boolean :visible, :default => false
|
43
|
+
end
|
44
|
+
|
45
|
+
create_table :pirates, :force => true do |table|
|
46
|
+
table.string :name
|
47
|
+
table.boolean :alive, :default => true
|
48
|
+
end
|
49
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "test/unit"
|
3
|
+
|
4
|
+
gem "sqlite3-ruby"
|
5
|
+
|
6
|
+
require "active_record"
|
7
|
+
require "active_support"
|
8
|
+
require "active_support/test_case"
|
9
|
+
|
10
|
+
gem "thoughtbot-shoulda", ">= 2.10.1"
|
11
|
+
gem "thoughtbot-factory_girl", ">= 1.2.1"
|
12
|
+
|
13
|
+
require "shoulda"
|
14
|
+
require "mocha"
|
15
|
+
require "factory_girl"
|
16
|
+
|
17
|
+
require File.join(File.dirname(__FILE__), "..", "rails", "init")
|
18
|
+
|
19
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + "/database.yml"))
|
20
|
+
ActiveRecord::Base.establish_connection(config["test"])
|
21
|
+
|
22
|
+
load(File.dirname(__FILE__) + "/schema.rb")
|
23
|
+
|
24
|
+
require File.join(File.dirname(__FILE__), "models")
|
25
|
+
|
26
|
+
require "database_cleaner"
|
27
|
+
DatabaseCleaner.strategy = :truncation
|
28
|
+
DatabaseCleaner.clean
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: joshuaclayton-paranoia
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joshua Clayton
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-30 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.3.0
|
27
|
+
version:
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: activesupport
|
30
|
+
type: :development
|
31
|
+
version_requirement:
|
32
|
+
version_requirements: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: "0"
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 2.1.0
|
40
|
+
version:
|
41
|
+
description: Paranoid models
|
42
|
+
email: joshua.clayton@gmail.com
|
43
|
+
executables: []
|
44
|
+
|
45
|
+
extensions: []
|
46
|
+
|
47
|
+
extra_rdoc_files:
|
48
|
+
- lib/paranoia.rb
|
49
|
+
- README.textile
|
50
|
+
files:
|
51
|
+
- lib/paranoia.rb
|
52
|
+
- MIT-LICENSE
|
53
|
+
- rails/init.rb
|
54
|
+
- Rakefile
|
55
|
+
- README.textile
|
56
|
+
- test/database.yml
|
57
|
+
- test/factories.rb
|
58
|
+
- test/models.rb
|
59
|
+
- test/paranoia_test.rb
|
60
|
+
- test/schema.rb
|
61
|
+
- test/test_helper.rb
|
62
|
+
- Manifest
|
63
|
+
- paranoia.gemspec
|
64
|
+
has_rdoc: true
|
65
|
+
homepage: http://github.com/joshuaclayton/paranoia
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options:
|
68
|
+
- --line-numbers
|
69
|
+
- --inline-source
|
70
|
+
- --title
|
71
|
+
- Paranoia
|
72
|
+
- --main
|
73
|
+
- README.textile
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: "0"
|
81
|
+
version:
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: "1.2"
|
87
|
+
version:
|
88
|
+
requirements: []
|
89
|
+
|
90
|
+
rubyforge_project: paranoia
|
91
|
+
rubygems_version: 1.2.0
|
92
|
+
signing_key:
|
93
|
+
specification_version: 3
|
94
|
+
summary: Paranoid models
|
95
|
+
test_files:
|
96
|
+
- test/paranoia_test.rb
|
97
|
+
- test/test_helper.rb
|