paranoid 0.0.1 → 0.0.2
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/README.textile +15 -5
- data/Rakefile +11 -0
- data/VERSION.yml +3 -2
- data/lib/paranoid.rb +1 -0
- data/lib/paranoid/base.rb +21 -65
- data/lib/paranoid/paranoid_methods.rb +79 -0
- data/lib/paranoid/relation.rb +34 -2
- data/paranoid.gemspec +4 -2
- data/rdoc/template.rb +613 -0
- data/spec/paranoid_spec.rb +97 -54
- metadata +4 -2
data/README.textile
CHANGED
|
@@ -38,10 +38,10 @@ Automobile.count # => 1
|
|
|
38
38
|
|
|
39
39
|
that_large_automobile.destroy
|
|
40
40
|
Automobile.count # => 0
|
|
41
|
-
Automobile.
|
|
41
|
+
Automobile.with_destroyed.count # => 1
|
|
42
42
|
|
|
43
43
|
# where is that large automobile?
|
|
44
|
-
that_large_automobile = Automobile.
|
|
44
|
+
that_large_automobile = Automobile.with_destroyed.first
|
|
45
45
|
that_large_automobile.restore
|
|
46
46
|
Automobile.count # => 1
|
|
47
47
|
</pre>
|
|
@@ -51,14 +51,24 @@ One thing to note, destroying is always undo-able, but deleting is not. This is
|
|
|
51
51
|
<pre>
|
|
52
52
|
Automobile.destroy_all
|
|
53
53
|
Automobile.count # => 0
|
|
54
|
-
Automobile.
|
|
54
|
+
Automobile.with_destroyed.count # => 1
|
|
55
55
|
|
|
56
56
|
Automobile.delete_all
|
|
57
|
-
Automobile.
|
|
57
|
+
Automobile.with_destroyed.count # => 0
|
|
58
58
|
# And you may say to yourself, "My god! What have I done?"
|
|
59
59
|
</pre>
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
You can also lookup only destroyed record with with_destroyed_only.
|
|
62
|
+
|
|
63
|
+
<pre>
|
|
64
|
+
auto1 = Automobile.create()
|
|
65
|
+
auto2 = Automobile.create()
|
|
66
|
+
auto2.destroy
|
|
67
|
+
Automobile.count # => 1
|
|
68
|
+
Automobile.with_destroyed.count # => 2
|
|
69
|
+
Automobile.with_destroyed_only.count # => 1
|
|
70
|
+
Automobile.with_destroyed_only.first # => auto2
|
|
71
|
+
</pre>
|
|
62
72
|
|
|
63
73
|
h3. Specifying alternate rules for what should be considered destroyed
|
|
64
74
|
|
data/Rakefile
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'rake/rdoctask'
|
|
1
2
|
require "spec"
|
|
2
3
|
require "spec/rake/spectask"
|
|
3
4
|
|
|
@@ -22,4 +23,14 @@ rescue LoadError
|
|
|
22
23
|
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
|
23
24
|
end
|
|
24
25
|
|
|
26
|
+
Rake::RDocTask.new { |rdoc|
|
|
27
|
+
rdoc.rdoc_dir = 'doc'
|
|
28
|
+
rdoc.title = "Paranoid"
|
|
29
|
+
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
|
30
|
+
rdoc.options << '--charset' << 'utf-8'
|
|
31
|
+
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : './rdoc/template.rb'
|
|
32
|
+
rdoc.rdoc_files.include('README.textile')
|
|
33
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
34
|
+
}
|
|
35
|
+
|
|
25
36
|
task :default => :spec
|
data/VERSION.yml
CHANGED
data/lib/paranoid.rb
CHANGED
data/lib/paranoid/base.rb
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
module Paranoid
|
|
2
2
|
module Base
|
|
3
|
+
# Call this in your model to enable paranoid.
|
|
4
|
+
#
|
|
5
|
+
# === Examples
|
|
6
|
+
#
|
|
7
|
+
# Post < ActiveRecord::Base
|
|
8
|
+
# paranoid
|
|
9
|
+
# end
|
|
10
|
+
#
|
|
11
|
+
# Item < ActiveRecord::Base
|
|
12
|
+
# paranoid :field => [:available, fales, true]
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# === Options
|
|
16
|
+
#
|
|
17
|
+
# [:field]
|
|
18
|
+
# Must be a 3 element array in the form
|
|
19
|
+
# [:field_name, 'destroyed value', 'not destroyed value']
|
|
20
|
+
# Default: [:deleted_at, Proc.new{Time.now.utc}, nil]
|
|
3
21
|
def paranoid(opts = {})
|
|
4
22
|
return if paranoid?
|
|
5
23
|
@paranoid = true
|
|
@@ -8,82 +26,20 @@ module Paranoid
|
|
|
8
26
|
class_inheritable_accessor :destroyed_field, :field_destroyed, :field_not_destroyed
|
|
9
27
|
self.destroyed_field, self.field_destroyed, self.field_not_destroyed = opts[:field]
|
|
10
28
|
|
|
11
|
-
|
|
12
|
-
include InstanceMethods
|
|
29
|
+
include Paranoid::ParanoidMethods
|
|
13
30
|
|
|
14
31
|
class_eval do
|
|
15
32
|
class << self
|
|
16
|
-
delegate :with_destroyed, :to => :scoped
|
|
33
|
+
delegate :with_destroyed, :with_destroyed_only, :to => :scoped
|
|
17
34
|
end
|
|
18
35
|
end
|
|
19
36
|
end
|
|
20
37
|
|
|
38
|
+
# Returns true if the model is paranoid and paranoid is enabled
|
|
21
39
|
def paranoid?
|
|
22
40
|
@paranoid = false unless defined?(@paranoid)
|
|
23
41
|
@paranoid
|
|
24
42
|
end
|
|
25
|
-
|
|
26
|
-
module ClassMethods
|
|
27
|
-
def paranoid_condition
|
|
28
|
-
{destroyed_field => field_not_destroyed}
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def paranoid_only_condition
|
|
32
|
-
["#{table_name}.#{destroyed_field} IS NOT ?", field_not_destroyed]
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def disable_paranoid
|
|
36
|
-
if block_given?
|
|
37
|
-
@paranoid = false
|
|
38
|
-
yield
|
|
39
|
-
end
|
|
40
|
-
ensure
|
|
41
|
-
@paranoid = true
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
module InstanceMethods
|
|
46
|
-
extend ActiveSupport::Concern
|
|
47
|
-
|
|
48
|
-
included do
|
|
49
|
-
alias_method_chain :create_or_update, :paranoid
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def restore
|
|
53
|
-
set_destroyed(field_not_destroyed.respond_to?(:call) ? field_not_destroyed.call : field_not_destroyed)
|
|
54
|
-
@destroyed = false
|
|
55
|
-
|
|
56
|
-
self
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# Override the default destroy to allow us to soft delete records.
|
|
60
|
-
# This preserves the before_destroy and after_destroy callbacks.
|
|
61
|
-
# Because this is also called internally by Model.destroy_all and
|
|
62
|
-
# the Model.destroy(id), we don't need to specify those methods
|
|
63
|
-
# separately.
|
|
64
|
-
def destroy
|
|
65
|
-
_run_destroy_callbacks do
|
|
66
|
-
set_destroyed(field_destroyed.respond_to?(:call) ? field_destroyed.call : field_destroyed)
|
|
67
|
-
@destroyed = true
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
self
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
protected
|
|
74
|
-
|
|
75
|
-
def create_or_update_with_paranoid
|
|
76
|
-
self.class.disable_paranoid { create_or_update_without_paranoid }
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# Set the value for the destroyed field.
|
|
80
|
-
def set_destroyed(val)
|
|
81
|
-
self[destroyed_field] = val
|
|
82
|
-
updates = self.class.send(:sanitize_sql_for_assignment, {destroyed_field => val})
|
|
83
|
-
self.class.unscoped.with_destroyed.where(self.class.arel_table[self.class.primary_key].eq(id)).arel.update(updates)
|
|
84
|
-
@destroyed = true
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
43
|
end
|
|
88
44
|
end
|
|
89
45
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
module Paranoid
|
|
2
|
+
module ParanoidMethods
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
extend ClassMethods
|
|
7
|
+
alias_method_chain :create_or_update, :paranoid
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
# Returns the condition used to scope the return to exclude
|
|
12
|
+
# soft deleted records
|
|
13
|
+
def paranoid_condition
|
|
14
|
+
{destroyed_field => field_not_destroyed}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Returns the condition used to scope the return to contain
|
|
18
|
+
# only soft deleted records
|
|
19
|
+
def paranoid_only_condition
|
|
20
|
+
val = field_not_destroyed.respond_to?(:call) ? field_not_destroyed.call : field_not_destroyed
|
|
21
|
+
column_sql = arel_table[destroyed_field].to_sql
|
|
22
|
+
case val
|
|
23
|
+
when nil then "#{column_sql} IS NOT NULL"
|
|
24
|
+
else ["#{column_sql} != ?", val]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Temporarily disables paranoid on the model
|
|
29
|
+
def disable_paranoid
|
|
30
|
+
if block_given?
|
|
31
|
+
@paranoid = false
|
|
32
|
+
yield
|
|
33
|
+
else
|
|
34
|
+
raise 'Only block form is supported'
|
|
35
|
+
end
|
|
36
|
+
ensure
|
|
37
|
+
@paranoid = true
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Restores the record
|
|
42
|
+
def restore
|
|
43
|
+
set_destroyed(field_not_destroyed.respond_to?(:call) ? field_not_destroyed.call : field_not_destroyed)
|
|
44
|
+
@destroyed = false
|
|
45
|
+
|
|
46
|
+
self
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Override the default destroy to allow us to soft delete records.
|
|
50
|
+
# This preserves the before_destroy and after_destroy callbacks.
|
|
51
|
+
# Because this is also called internally by Model.destroy_all and
|
|
52
|
+
# the Model.destroy(id), we don't need to specify those methods
|
|
53
|
+
# separately.
|
|
54
|
+
def destroy
|
|
55
|
+
_run_destroy_callbacks do
|
|
56
|
+
set_destroyed(field_destroyed.respond_to?(:call) ? field_destroyed.call : field_destroyed)
|
|
57
|
+
@destroyed = true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
protected
|
|
64
|
+
|
|
65
|
+
# Overrides ActiveRecord::Base#create_or_update
|
|
66
|
+
# to disable paranoid during the create and update operations
|
|
67
|
+
def create_or_update_with_paranoid
|
|
68
|
+
self.class.disable_paranoid { create_or_update_without_paranoid }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Set the value for the destroyed field.
|
|
72
|
+
def set_destroyed(val)
|
|
73
|
+
self[destroyed_field] = val
|
|
74
|
+
updates = self.class.send(:sanitize_sql_for_assignment, {destroyed_field => val})
|
|
75
|
+
self.class.unscoped.with_destroyed.where(self.class.arel_table[self.class.primary_key].eq(id)).arel.update(updates)
|
|
76
|
+
@destroyed = true
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
data/lib/paranoid/relation.rb
CHANGED
|
@@ -5,13 +5,18 @@ module Paranoid
|
|
|
5
5
|
included do
|
|
6
6
|
alias_method_chain :arel, :paranoid
|
|
7
7
|
alias_method_chain :delete_all, :paranoid
|
|
8
|
+
alias_method_chain :except, :paranoid
|
|
9
|
+
alias_method_chain :only, :paranoid
|
|
8
10
|
end
|
|
9
11
|
|
|
12
|
+
# Returns true if the relation should be scoped to
|
|
13
|
+
# exclude soft deleted records
|
|
10
14
|
def add_paranoid_condition?
|
|
11
15
|
@add_paranoid = true unless defined?(@add_paranoid)
|
|
12
16
|
@klass.paranoid? && @add_paranoid
|
|
13
17
|
end
|
|
14
18
|
|
|
19
|
+
# Overrides ActiveRecord::Relation#arel
|
|
15
20
|
def arel_with_paranoid
|
|
16
21
|
if add_paranoid_condition?
|
|
17
22
|
@arel ||= without_destroyed.arel_without_paranoid
|
|
@@ -20,6 +25,8 @@ module Paranoid
|
|
|
20
25
|
end
|
|
21
26
|
end
|
|
22
27
|
|
|
28
|
+
# Overrides ActiveRecord::Relation#delete_all
|
|
29
|
+
# forcing delete_all to ignore deleted flag
|
|
23
30
|
def delete_all_with_paranoid(*args)
|
|
24
31
|
if add_paranoid_condition?
|
|
25
32
|
with_destroyed.delete_all_without_paranoid(*args)
|
|
@@ -28,21 +35,46 @@ module Paranoid
|
|
|
28
35
|
end
|
|
29
36
|
end
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
# Overrides ActiveRecord::Relation#except
|
|
39
|
+
def except_with_paranoid(*args)
|
|
40
|
+
result = except_without_paranoid(*args)
|
|
41
|
+
result.instance_variable_set(:@add_paranoid, @add_paranoid) if defined?(@add_paranoid)
|
|
42
|
+
result
|
|
33
43
|
end
|
|
34
44
|
|
|
45
|
+
# Overrides ActiveRecord::Relation#only
|
|
46
|
+
def only_with_paranoid(*args)
|
|
47
|
+
result = only_without_paranoid(*args)
|
|
48
|
+
result.instance_variable_set(:@add_paranoid, @add_paranoid) if defined?(@add_paranoid)
|
|
49
|
+
result
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns a new relation scoped to include soft deleted records
|
|
35
53
|
def with_destroyed
|
|
36
54
|
spawn.tap {|relation| relation.skip_paranoid_condition }
|
|
37
55
|
end
|
|
38
56
|
|
|
57
|
+
# Returns a new relation scoped to include only deleted records
|
|
39
58
|
def with_destroyed_only
|
|
40
59
|
where(@klass.paranoid_only_condition).tap {|relation| relation.skip_paranoid_condition }
|
|
41
60
|
end
|
|
42
61
|
|
|
62
|
+
# Can be used to force the exclusion of soft deleted records down
|
|
63
|
+
# the chain from a with_destroyed call. *WARNING*: with_destroyed
|
|
64
|
+
# will do nothing after this has been called! So
|
|
65
|
+
# Model.without_destroyed.with_destroyed.all will *NOT* return
|
|
66
|
+
# soft deleted records
|
|
43
67
|
def without_destroyed
|
|
44
68
|
where(@klass.paranoid_condition).tap {|relation| relation.skip_paranoid_condition }
|
|
45
69
|
end
|
|
70
|
+
|
|
71
|
+
protected
|
|
72
|
+
|
|
73
|
+
# Tell the relation to skip adding the paranoid conditions. DO NOT
|
|
74
|
+
# call directly. Call with_destroyed.
|
|
75
|
+
def skip_paranoid_condition
|
|
76
|
+
@add_paranoid = false
|
|
77
|
+
end
|
|
46
78
|
end
|
|
47
79
|
end
|
|
48
80
|
|
data/paranoid.gemspec
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{paranoid}
|
|
8
|
-
s.version = "0.0.
|
|
8
|
+
s.version = "0.0.2"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["David Genord II"]
|
|
12
|
-
s.date = %q{2010-02-
|
|
12
|
+
s.date = %q{2010-02-19}
|
|
13
13
|
s.description = %q{}
|
|
14
14
|
s.email = %q{github@xspond.com}
|
|
15
15
|
s.extra_rdoc_files = [
|
|
@@ -23,8 +23,10 @@ Gem::Specification.new do |s|
|
|
|
23
23
|
"init.rb",
|
|
24
24
|
"lib/paranoid.rb",
|
|
25
25
|
"lib/paranoid/base.rb",
|
|
26
|
+
"lib/paranoid/paranoid_methods.rb",
|
|
26
27
|
"lib/paranoid/relation.rb",
|
|
27
28
|
"paranoid.gemspec",
|
|
29
|
+
"rdoc/template.rb",
|
|
28
30
|
"spec/database.yml",
|
|
29
31
|
"spec/models.rb",
|
|
30
32
|
"spec/paranoid_spec.rb",
|
data/rdoc/template.rb
ADDED
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
# Horo RDoc template
|
|
2
|
+
# Author: Hongli Lai - http://izumi.plan99.net/blog/
|
|
3
|
+
#
|
|
4
|
+
# Based on the Jamis template:
|
|
5
|
+
# http://weblog.jamisbuck.org/2005/4/8/rdoc-template
|
|
6
|
+
|
|
7
|
+
if defined?(RDoc::Diagram)
|
|
8
|
+
RDoc::Diagram.class_eval do
|
|
9
|
+
remove_const(:FONT)
|
|
10
|
+
const_set(:FONT, "\"Bitstream Vera Sans\"")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module RDoc
|
|
15
|
+
module Page
|
|
16
|
+
|
|
17
|
+
FONTS = "\"Bitstream Vera Sans\", Verdana, Arial, Helvetica, sans-serif"
|
|
18
|
+
|
|
19
|
+
STYLE = <<CSS
|
|
20
|
+
a {
|
|
21
|
+
color: #00F;
|
|
22
|
+
text-decoration: none;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
a:hover {
|
|
26
|
+
color: #77F;
|
|
27
|
+
text-decoration: underline;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
body, td, p {
|
|
31
|
+
font-family: %fonts%;
|
|
32
|
+
background: #FFF;
|
|
33
|
+
color: #000;
|
|
34
|
+
margin: 0px;
|
|
35
|
+
font-size: small;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
p {
|
|
39
|
+
margin-top: 0.5em;
|
|
40
|
+
margin-bottom: 0.5em;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#content {
|
|
44
|
+
margin: 2em;
|
|
45
|
+
margin-left: 3.5em;
|
|
46
|
+
margin-right: 3.5em;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#description p {
|
|
50
|
+
margin-bottom: 0.5em;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.sectiontitle {
|
|
54
|
+
margin-top: 1em;
|
|
55
|
+
margin-bottom: 1em;
|
|
56
|
+
padding: 0.5em;
|
|
57
|
+
padding-left: 2em;
|
|
58
|
+
background: #005;
|
|
59
|
+
color: #FFF;
|
|
60
|
+
font-weight: bold;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.attr-rw {
|
|
64
|
+
padding-left: 1em;
|
|
65
|
+
padding-right: 1em;
|
|
66
|
+
text-align: center;
|
|
67
|
+
color: #055;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.attr-name {
|
|
71
|
+
font-weight: bold;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.attr-desc {
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.attr-value {
|
|
78
|
+
font-family: monospace;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.file-title-prefix {
|
|
82
|
+
font-size: large;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.file-title {
|
|
86
|
+
font-size: large;
|
|
87
|
+
font-weight: bold;
|
|
88
|
+
background: #005;
|
|
89
|
+
color: #FFF;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.banner {
|
|
93
|
+
background: #005;
|
|
94
|
+
color: #FFF;
|
|
95
|
+
border: 1px solid black;
|
|
96
|
+
padding: 1em;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.banner td {
|
|
100
|
+
background: transparent;
|
|
101
|
+
color: #FFF;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
h1 a, h2 a, .sectiontitle a, .banner a {
|
|
105
|
+
color: #FF0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
h1 a:hover, h2 a:hover, .sectiontitle a:hover, .banner a:hover {
|
|
109
|
+
color: #FF7;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.dyn-source {
|
|
113
|
+
display: none;
|
|
114
|
+
background: #fffde8;
|
|
115
|
+
color: #000;
|
|
116
|
+
border: #ffe0bb dotted 1px;
|
|
117
|
+
margin: 0.5em 2em 0.5em 2em;
|
|
118
|
+
padding: 0.5em;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.dyn-source .cmt {
|
|
122
|
+
color: #00F;
|
|
123
|
+
font-style: italic;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.dyn-source .kw {
|
|
127
|
+
color: #070;
|
|
128
|
+
font-weight: bold;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.method {
|
|
132
|
+
margin-left: 1em;
|
|
133
|
+
margin-right: 1em;
|
|
134
|
+
margin-bottom: 1em;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.description pre {
|
|
138
|
+
padding: 0.5em;
|
|
139
|
+
border: #ffe0bb dotted 1px;
|
|
140
|
+
background: #fffde8;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.method .title {
|
|
144
|
+
font-family: monospace;
|
|
145
|
+
font-size: large;
|
|
146
|
+
border-bottom: 1px dashed black;
|
|
147
|
+
margin-bottom: 0.3em;
|
|
148
|
+
padding-bottom: 0.1em;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.method .description, .method .sourcecode {
|
|
152
|
+
margin-left: 1em;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.description p, .sourcecode p {
|
|
156
|
+
margin-bottom: 0.5em;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.method .sourcecode p.source-link {
|
|
160
|
+
text-indent: 0em;
|
|
161
|
+
margin-top: 0.5em;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.method .aka {
|
|
165
|
+
margin-top: 0.3em;
|
|
166
|
+
margin-left: 1em;
|
|
167
|
+
font-style: italic;
|
|
168
|
+
text-indent: 2em;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
h1 {
|
|
172
|
+
padding: 1em;
|
|
173
|
+
margin-left: -1.5em;
|
|
174
|
+
font-size: x-large;
|
|
175
|
+
font-weight: bold;
|
|
176
|
+
color: #FFF;
|
|
177
|
+
background: #007;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
h2 {
|
|
181
|
+
padding: 0.5em 1em 0.5em 1em;
|
|
182
|
+
margin-left: -1.5em;
|
|
183
|
+
font-size: large;
|
|
184
|
+
font-weight: bold;
|
|
185
|
+
color: #FFF;
|
|
186
|
+
background: #009;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
h3, h4, h5, h6 {
|
|
190
|
+
color: #220088;
|
|
191
|
+
border-bottom: #5522bb solid 1px;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.sourcecode > pre {
|
|
195
|
+
padding: 0.5em;
|
|
196
|
+
border: 1px dotted black;
|
|
197
|
+
background: #FFE;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
dt {
|
|
201
|
+
font-weight: bold
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
dd {
|
|
205
|
+
margin-bottom: 0.7em;
|
|
206
|
+
}
|
|
207
|
+
CSS
|
|
208
|
+
|
|
209
|
+
XHTML_PREAMBLE = %{<?xml version="1.0" encoding="%charset%"?>
|
|
210
|
+
<!DOCTYPE html
|
|
211
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
212
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
XHTML_FRAMESET_PREAMBLE = %{
|
|
216
|
+
<!DOCTYPE html
|
|
217
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
|
|
218
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
HEADER = XHTML_PREAMBLE + <<ENDHEADER
|
|
222
|
+
<html>
|
|
223
|
+
<head>
|
|
224
|
+
<title>%title%</title>
|
|
225
|
+
<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
|
|
226
|
+
<link rel="stylesheet" href="%style_url%" type="text/css" media="screen" />
|
|
227
|
+
|
|
228
|
+
<script language="JavaScript" type="text/javascript">
|
|
229
|
+
// <![CDATA[
|
|
230
|
+
|
|
231
|
+
function toggleSource( id )
|
|
232
|
+
{
|
|
233
|
+
var elem
|
|
234
|
+
var link
|
|
235
|
+
|
|
236
|
+
if( document.getElementById )
|
|
237
|
+
{
|
|
238
|
+
elem = document.getElementById( id )
|
|
239
|
+
link = document.getElementById( "l_" + id )
|
|
240
|
+
}
|
|
241
|
+
else if ( document.all )
|
|
242
|
+
{
|
|
243
|
+
elem = eval( "document.all." + id )
|
|
244
|
+
link = eval( "document.all.l_" + id )
|
|
245
|
+
}
|
|
246
|
+
else
|
|
247
|
+
return false;
|
|
248
|
+
|
|
249
|
+
if( elem.style.display == "block" )
|
|
250
|
+
{
|
|
251
|
+
elem.style.display = "none"
|
|
252
|
+
link.innerHTML = "show source"
|
|
253
|
+
}
|
|
254
|
+
else
|
|
255
|
+
{
|
|
256
|
+
elem.style.display = "block"
|
|
257
|
+
link.innerHTML = "hide source"
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function openCode( url )
|
|
262
|
+
{
|
|
263
|
+
window.open( url, "SOURCE_CODE", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=480,width=750" ).focus();
|
|
264
|
+
}
|
|
265
|
+
// ]]>
|
|
266
|
+
</script>
|
|
267
|
+
</head>
|
|
268
|
+
|
|
269
|
+
<body>
|
|
270
|
+
ENDHEADER
|
|
271
|
+
|
|
272
|
+
FILE_PAGE = <<HTML
|
|
273
|
+
<table border='0' cellpadding='0' cellspacing='0' width="100%" class='banner'>
|
|
274
|
+
<tr><td>
|
|
275
|
+
<table width="100%" border='0' cellpadding='0' cellspacing='0'><tr>
|
|
276
|
+
<td class="file-title" colspan="2"><span class="file-title-prefix">File</span><br />%short_name%</td>
|
|
277
|
+
<td align="right">
|
|
278
|
+
<table border='0' cellspacing="0" cellpadding="2">
|
|
279
|
+
<tr>
|
|
280
|
+
<td>Path:</td>
|
|
281
|
+
<td>%full_path%
|
|
282
|
+
IF:cvsurl
|
|
283
|
+
(<a href="%cvsurl%">CVS</a>)
|
|
284
|
+
ENDIF:cvsurl
|
|
285
|
+
</td>
|
|
286
|
+
</tr>
|
|
287
|
+
<tr>
|
|
288
|
+
<td>Modified:</td>
|
|
289
|
+
<td>%dtm_modified%</td>
|
|
290
|
+
</tr>
|
|
291
|
+
</table>
|
|
292
|
+
</td></tr>
|
|
293
|
+
</table>
|
|
294
|
+
</td></tr>
|
|
295
|
+
</table><br />
|
|
296
|
+
HTML
|
|
297
|
+
|
|
298
|
+
###################################################################
|
|
299
|
+
|
|
300
|
+
CLASS_PAGE = <<HTML
|
|
301
|
+
<table width="100%" border='0' cellpadding='0' cellspacing='0' class='banner'><tr>
|
|
302
|
+
<td class="file-title"><span class="file-title-prefix">%classmod%</span><br />%full_name%</td>
|
|
303
|
+
<td align="right">
|
|
304
|
+
<table cellspacing="0" cellpadding="2">
|
|
305
|
+
<tr valign="top">
|
|
306
|
+
<td>In:</td>
|
|
307
|
+
<td>
|
|
308
|
+
START:infiles
|
|
309
|
+
HREF:full_path_url:full_path:
|
|
310
|
+
IF:cvsurl
|
|
311
|
+
(<a href="%cvsurl%">CVS</a>)
|
|
312
|
+
ENDIF:cvsurl
|
|
313
|
+
END:infiles
|
|
314
|
+
</td>
|
|
315
|
+
</tr>
|
|
316
|
+
IF:parent
|
|
317
|
+
<tr>
|
|
318
|
+
<td>Parent:</td>
|
|
319
|
+
<td>
|
|
320
|
+
IF:par_url
|
|
321
|
+
<a href="%par_url%">
|
|
322
|
+
ENDIF:par_url
|
|
323
|
+
%parent%
|
|
324
|
+
IF:par_url
|
|
325
|
+
</a>
|
|
326
|
+
ENDIF:par_url
|
|
327
|
+
</td>
|
|
328
|
+
</tr>
|
|
329
|
+
ENDIF:parent
|
|
330
|
+
</table>
|
|
331
|
+
</td>
|
|
332
|
+
</tr>
|
|
333
|
+
</table>
|
|
334
|
+
HTML
|
|
335
|
+
|
|
336
|
+
###################################################################
|
|
337
|
+
|
|
338
|
+
METHOD_LIST = <<HTML
|
|
339
|
+
<div id="content">
|
|
340
|
+
IF:diagram
|
|
341
|
+
<table cellpadding='0' cellspacing='0' border='0' width="100%"><tr><td align="center">
|
|
342
|
+
%diagram%
|
|
343
|
+
</td></tr></table>
|
|
344
|
+
ENDIF:diagram
|
|
345
|
+
|
|
346
|
+
IF:description
|
|
347
|
+
<div class="description">%description%</div>
|
|
348
|
+
ENDIF:description
|
|
349
|
+
|
|
350
|
+
IF:requires
|
|
351
|
+
<div class="sectiontitle">Required Files</div>
|
|
352
|
+
<ul>
|
|
353
|
+
START:requires
|
|
354
|
+
<li>HREF:aref:name:</li>
|
|
355
|
+
END:requires
|
|
356
|
+
</ul>
|
|
357
|
+
ENDIF:requires
|
|
358
|
+
|
|
359
|
+
IF:toc
|
|
360
|
+
<div class="sectiontitle">Contents</div>
|
|
361
|
+
<ul>
|
|
362
|
+
START:toc
|
|
363
|
+
<li><a href="#%href%">%secname%</a></li>
|
|
364
|
+
END:toc
|
|
365
|
+
</ul>
|
|
366
|
+
ENDIF:toc
|
|
367
|
+
|
|
368
|
+
IF:methods
|
|
369
|
+
<div class="sectiontitle">Methods</div>
|
|
370
|
+
<ul>
|
|
371
|
+
START:methods
|
|
372
|
+
<li>HREF:aref:name:</li>
|
|
373
|
+
END:methods
|
|
374
|
+
</ul>
|
|
375
|
+
ENDIF:methods
|
|
376
|
+
|
|
377
|
+
IF:includes
|
|
378
|
+
<div class="sectiontitle">Included Modules</div>
|
|
379
|
+
<ul>
|
|
380
|
+
START:includes
|
|
381
|
+
<li>HREF:aref:name:</li>
|
|
382
|
+
END:includes
|
|
383
|
+
</ul>
|
|
384
|
+
ENDIF:includes
|
|
385
|
+
|
|
386
|
+
START:sections
|
|
387
|
+
IF:sectitle
|
|
388
|
+
<div class="sectiontitle"><a name="%secsequence%">%sectitle%</a></div>
|
|
389
|
+
IF:seccomment
|
|
390
|
+
<div class="description">
|
|
391
|
+
%seccomment%
|
|
392
|
+
</div>
|
|
393
|
+
ENDIF:seccomment
|
|
394
|
+
ENDIF:sectitle
|
|
395
|
+
|
|
396
|
+
IF:classlist
|
|
397
|
+
<div class="sectiontitle">Classes and Modules</div>
|
|
398
|
+
%classlist%
|
|
399
|
+
ENDIF:classlist
|
|
400
|
+
|
|
401
|
+
IF:constants
|
|
402
|
+
<div class="sectiontitle">Constants</div>
|
|
403
|
+
<table border='0' cellpadding='5'>
|
|
404
|
+
START:constants
|
|
405
|
+
<tr valign='top'>
|
|
406
|
+
<td class="attr-name">%name%</td>
|
|
407
|
+
<td>=</td>
|
|
408
|
+
<td class="attr-value">%value%</td>
|
|
409
|
+
</tr>
|
|
410
|
+
IF:desc
|
|
411
|
+
<tr valign='top'>
|
|
412
|
+
<td> </td>
|
|
413
|
+
<td colspan="2" class="attr-desc">%desc%</td>
|
|
414
|
+
</tr>
|
|
415
|
+
ENDIF:desc
|
|
416
|
+
END:constants
|
|
417
|
+
</table>
|
|
418
|
+
ENDIF:constants
|
|
419
|
+
|
|
420
|
+
IF:attributes
|
|
421
|
+
<div class="sectiontitle">Attributes</div>
|
|
422
|
+
<table border='0' cellpadding='5'>
|
|
423
|
+
START:attributes
|
|
424
|
+
<tr valign='top'>
|
|
425
|
+
<td class='attr-rw'>
|
|
426
|
+
IF:rw
|
|
427
|
+
[%rw%]
|
|
428
|
+
ENDIF:rw
|
|
429
|
+
</td>
|
|
430
|
+
<td class='attr-name'>%name%</td>
|
|
431
|
+
<td class='attr-desc'>%a_desc%</td>
|
|
432
|
+
</tr>
|
|
433
|
+
END:attributes
|
|
434
|
+
</table>
|
|
435
|
+
ENDIF:attributes
|
|
436
|
+
|
|
437
|
+
IF:method_list
|
|
438
|
+
START:method_list
|
|
439
|
+
IF:methods
|
|
440
|
+
<div class="sectiontitle">%type% %category% methods</div>
|
|
441
|
+
START:methods
|
|
442
|
+
<div class="method">
|
|
443
|
+
<div class="title">
|
|
444
|
+
IF:callseq
|
|
445
|
+
<a name="%aref%"></a><b>%callseq%</b>
|
|
446
|
+
ENDIF:callseq
|
|
447
|
+
IFNOT:callseq
|
|
448
|
+
<a name="%aref%"></a><b>%name%</b>%params%
|
|
449
|
+
ENDIF:callseq
|
|
450
|
+
IF:codeurl
|
|
451
|
+
[ <a href="%codeurl%" target="SOURCE_CODE" onclick="javascript:openCode('%codeurl%'); return false;">source</a> ]
|
|
452
|
+
ENDIF:codeurl
|
|
453
|
+
</div>
|
|
454
|
+
IF:m_desc
|
|
455
|
+
<div class="description">
|
|
456
|
+
%m_desc%
|
|
457
|
+
</div>
|
|
458
|
+
ENDIF:m_desc
|
|
459
|
+
IF:aka
|
|
460
|
+
<div class="aka">
|
|
461
|
+
This method is also aliased as
|
|
462
|
+
START:aka
|
|
463
|
+
<a href="%aref%">%name%</a>
|
|
464
|
+
END:aka
|
|
465
|
+
</div>
|
|
466
|
+
ENDIF:aka
|
|
467
|
+
IF:sourcecode
|
|
468
|
+
<div class="sourcecode">
|
|
469
|
+
<p class="source-link">[ <a href="javascript:toggleSource('%aref%_source')" id="l_%aref%_source">show source</a> ]</p>
|
|
470
|
+
<div id="%aref%_source" class="dyn-source">
|
|
471
|
+
<pre>
|
|
472
|
+
%sourcecode%
|
|
473
|
+
</pre>
|
|
474
|
+
</div>
|
|
475
|
+
</div>
|
|
476
|
+
ENDIF:sourcecode
|
|
477
|
+
</div>
|
|
478
|
+
END:methods
|
|
479
|
+
ENDIF:methods
|
|
480
|
+
END:method_list
|
|
481
|
+
ENDIF:method_list
|
|
482
|
+
END:sections
|
|
483
|
+
</div>
|
|
484
|
+
HTML
|
|
485
|
+
|
|
486
|
+
FOOTER = <<ENDFOOTER
|
|
487
|
+
</body>
|
|
488
|
+
</html>
|
|
489
|
+
ENDFOOTER
|
|
490
|
+
|
|
491
|
+
BODY = HEADER + <<ENDBODY
|
|
492
|
+
!INCLUDE! <!-- banner header -->
|
|
493
|
+
|
|
494
|
+
<div id="bodyContent">
|
|
495
|
+
#{METHOD_LIST}
|
|
496
|
+
</div>
|
|
497
|
+
|
|
498
|
+
#{FOOTER}
|
|
499
|
+
ENDBODY
|
|
500
|
+
|
|
501
|
+
########################## Source code ##########################
|
|
502
|
+
|
|
503
|
+
SRC_PAGE = XHTML_PREAMBLE + <<HTML
|
|
504
|
+
<html>
|
|
505
|
+
<head><title>%title%</title>
|
|
506
|
+
<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
|
|
507
|
+
<style type="text/css">
|
|
508
|
+
.ruby-comment { color: green; font-style: italic }
|
|
509
|
+
.ruby-constant { color: #4433aa; font-weight: bold; }
|
|
510
|
+
.ruby-identifier { color: #222222; }
|
|
511
|
+
.ruby-ivar { color: #2233dd; }
|
|
512
|
+
.ruby-keyword { color: #3333FF; font-weight: bold }
|
|
513
|
+
.ruby-node { color: #777777; }
|
|
514
|
+
.ruby-operator { color: #111111; }
|
|
515
|
+
.ruby-regexp { color: #662222; }
|
|
516
|
+
.ruby-value { color: #662222; font-style: italic }
|
|
517
|
+
.kw { color: #3333FF; font-weight: bold }
|
|
518
|
+
.cmt { color: green; font-style: italic }
|
|
519
|
+
.str { color: #662222; font-style: italic }
|
|
520
|
+
.re { color: #662222; }
|
|
521
|
+
</style>
|
|
522
|
+
</head>
|
|
523
|
+
<body bgcolor="white">
|
|
524
|
+
<pre>%code%</pre>
|
|
525
|
+
</body>
|
|
526
|
+
</html>
|
|
527
|
+
HTML
|
|
528
|
+
|
|
529
|
+
########################## Index ################################
|
|
530
|
+
|
|
531
|
+
FR_INDEX_BODY = <<HTML
|
|
532
|
+
!INCLUDE!
|
|
533
|
+
HTML
|
|
534
|
+
|
|
535
|
+
FILE_INDEX = XHTML_PREAMBLE + <<HTML
|
|
536
|
+
<html>
|
|
537
|
+
<head>
|
|
538
|
+
<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
|
|
539
|
+
<title>Index</title>
|
|
540
|
+
<style type="text/css">
|
|
541
|
+
<!--
|
|
542
|
+
body {
|
|
543
|
+
background-color: #EEE;
|
|
544
|
+
font-family: #{FONTS};
|
|
545
|
+
color: #000;
|
|
546
|
+
margin: 0px;
|
|
547
|
+
}
|
|
548
|
+
.banner {
|
|
549
|
+
background: #005;
|
|
550
|
+
color: #FFF;
|
|
551
|
+
padding: 0.2em;
|
|
552
|
+
font-size: small;
|
|
553
|
+
font-weight: bold;
|
|
554
|
+
text-align: center;
|
|
555
|
+
}
|
|
556
|
+
.entries {
|
|
557
|
+
margin: 0.25em 1em 0 1em;
|
|
558
|
+
font-size: x-small;
|
|
559
|
+
}
|
|
560
|
+
a {
|
|
561
|
+
color: #00F;
|
|
562
|
+
text-decoration: none;
|
|
563
|
+
white-space: nowrap;
|
|
564
|
+
}
|
|
565
|
+
a:hover {
|
|
566
|
+
color: #77F;
|
|
567
|
+
text-decoration: underline;
|
|
568
|
+
}
|
|
569
|
+
-->
|
|
570
|
+
</style>
|
|
571
|
+
<base target="docwin" />
|
|
572
|
+
</head>
|
|
573
|
+
<body>
|
|
574
|
+
<div class="banner">%list_title%</div>
|
|
575
|
+
<div class="entries">
|
|
576
|
+
START:entries
|
|
577
|
+
<a href="%href%">%name%</a><br />
|
|
578
|
+
END:entries
|
|
579
|
+
</div>
|
|
580
|
+
</body></html>
|
|
581
|
+
HTML
|
|
582
|
+
|
|
583
|
+
CLASS_INDEX = FILE_INDEX
|
|
584
|
+
METHOD_INDEX = FILE_INDEX
|
|
585
|
+
|
|
586
|
+
INDEX = XHTML_FRAMESET_PREAMBLE + <<HTML
|
|
587
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
588
|
+
<head>
|
|
589
|
+
<title>%title%</title>
|
|
590
|
+
<meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
|
|
591
|
+
</head>
|
|
592
|
+
|
|
593
|
+
<frameset cols="20%,*">
|
|
594
|
+
<frameset rows="15%,55%,30%">
|
|
595
|
+
<frame src="fr_file_index.html" title="Files" name="Files" />
|
|
596
|
+
<frame src="fr_class_index.html" name="Classes" />
|
|
597
|
+
<frame src="fr_method_index.html" name="Methods" />
|
|
598
|
+
</frameset>
|
|
599
|
+
<frame src="%initial_page%" name="docwin" />
|
|
600
|
+
<noframes>
|
|
601
|
+
<body bgcolor="white">
|
|
602
|
+
Click <a href="html/index.html">here</a> for a non-frames
|
|
603
|
+
version of this page.
|
|
604
|
+
</body>
|
|
605
|
+
</noframes>
|
|
606
|
+
</frameset>
|
|
607
|
+
|
|
608
|
+
</html>
|
|
609
|
+
HTML
|
|
610
|
+
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
|
data/spec/paranoid_spec.rb
CHANGED
|
@@ -5,81 +5,108 @@ LUKE = 'Luke Skywalker'
|
|
|
5
5
|
|
|
6
6
|
describe Paranoid do
|
|
7
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
|
|
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
24
|
end
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
it 'should recognize a class as paranoid' do
|
|
33
|
+
Person.paranoid?.should be_false
|
|
34
|
+
Place.paranoid?.should be_true
|
|
35
|
+
end
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
it 'should hide destroyed records' do
|
|
38
|
+
@tatooine.update_attribute('deleted_at', Time.now)
|
|
39
|
+
Place.first(:conditions => {:name => 'Tatooine'}).should be_nil
|
|
40
|
+
end
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
it 'should reveal destroyed records when with_destroyed' do
|
|
43
|
+
@tatooine.update_attribute('deleted_at', Time.now)
|
|
44
|
+
Place.with_destroyed.first(:conditions => {:name => 'Tatooine'}).should_not be_nil
|
|
45
|
+
end
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
it 'should restore the destroyed record' do
|
|
48
|
+
@tatooine.update_attribute('deleted_at', Time.now)
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
@tatooine = Place.with_destroyed.first(:conditions => {:name => 'Tatooine'})
|
|
51
|
+
@tatooine.restore
|
|
49
52
|
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
Place.first(:conditions => {:name => 'Tatooine'}).should_not be_nil
|
|
54
|
+
end
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
record.deleted_at.should_not be_nil
|
|
56
|
-
end
|
|
56
|
+
it 'should soft delete paranoid records' do
|
|
57
|
+
@tatooine.destroy
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
record = Place.with_destroyed.first(:conditions => {:name => 'Tatooine'})
|
|
60
|
+
record.should_not be_nil
|
|
61
|
+
record.deleted_at.should_not be_nil
|
|
62
|
+
end
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
it 'should mark the record destroyed' do
|
|
65
|
+
@tatooine.destroy
|
|
66
|
+
@tatooine.destroyed?.should be_true
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'should set the deleted_field' do
|
|
70
|
+
@tatooine.destroy
|
|
71
|
+
@tatooine.deleted_at.should_not be_nil
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'should show deleted_only' do
|
|
75
|
+
@tatooine.destroy
|
|
76
|
+
destroyed = Place.with_destroyed_only.all
|
|
77
|
+
destroyed.size.should == 1
|
|
78
|
+
destroyed[0].should == @tatooine
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'should properly count records' do
|
|
82
|
+
Place.count.should == 3
|
|
83
|
+
|
|
84
|
+
@tatooine.destroy
|
|
85
|
+
Place.count.should == 2
|
|
86
|
+
Place.with_destroyed.count.should == 3
|
|
87
|
+
Place.with_destroyed_only.count.should == 1
|
|
88
|
+
end
|
|
66
89
|
end
|
|
67
90
|
|
|
68
91
|
describe 'for alternate field information' do
|
|
69
92
|
before(:each) do
|
|
70
93
|
Ninja.delete_all
|
|
71
|
-
@
|
|
94
|
+
@steve, @bob, @tim = Ninja.create([{:name => 'Steve', :visible => true}, {:name => 'Bob', :visible => true}, {:name => 'Tim', :visible => true}])
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it 'should have 3 visible ninjas' do
|
|
98
|
+
Ninja.all.size.should == 3
|
|
72
99
|
end
|
|
73
100
|
|
|
74
101
|
it 'should vanish the ninja' do
|
|
75
|
-
@
|
|
102
|
+
@steve.destroy
|
|
76
103
|
|
|
77
104
|
record = Ninja.first(:conditions => {:name => 'Steve'})
|
|
78
105
|
record.should be_nil
|
|
79
106
|
end
|
|
80
107
|
|
|
81
108
|
it 'should not delete the ninja' do
|
|
82
|
-
@
|
|
109
|
+
@steve.destroy
|
|
83
110
|
|
|
84
111
|
record = Ninja.with_destroyed.first(:conditions => {:name => 'Steve'})
|
|
85
112
|
record.should_not be_nil
|
|
@@ -87,13 +114,29 @@ describe Paranoid do
|
|
|
87
114
|
end
|
|
88
115
|
|
|
89
116
|
it 'should mark the ninja vanished' do
|
|
90
|
-
@
|
|
91
|
-
@
|
|
117
|
+
@steve.destroy
|
|
118
|
+
@steve.destroyed?.should be_true
|
|
92
119
|
end
|
|
93
120
|
|
|
94
121
|
it 'should set visible to false' do
|
|
95
|
-
@
|
|
96
|
-
@
|
|
122
|
+
@steve.destroy
|
|
123
|
+
@steve.visible.should be_false
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it 'should show deleted_only' do
|
|
127
|
+
@steve.destroy
|
|
128
|
+
destroyed = Ninja.with_destroyed_only.all
|
|
129
|
+
destroyed.size.should == 1
|
|
130
|
+
destroyed[0].should == @steve
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'should properly count records' do
|
|
134
|
+
Ninja.count.should == 3
|
|
135
|
+
|
|
136
|
+
@steve.destroy
|
|
137
|
+
Ninja.count.should == 2
|
|
138
|
+
Ninja.with_destroyed.count.should == 3
|
|
139
|
+
Ninja.with_destroyed_only.count.should == 1
|
|
97
140
|
end
|
|
98
141
|
end
|
|
99
142
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: paranoid
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Genord II
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2010-02-
|
|
12
|
+
date: 2010-02-19 00:00:00 -05:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
@@ -38,8 +38,10 @@ files:
|
|
|
38
38
|
- init.rb
|
|
39
39
|
- lib/paranoid.rb
|
|
40
40
|
- lib/paranoid/base.rb
|
|
41
|
+
- lib/paranoid/paranoid_methods.rb
|
|
41
42
|
- lib/paranoid/relation.rb
|
|
42
43
|
- paranoid.gemspec
|
|
44
|
+
- rdoc/template.rb
|
|
43
45
|
- spec/database.yml
|
|
44
46
|
- spec/models.rb
|
|
45
47
|
- spec/paranoid_spec.rb
|