immortal 1.0.1 → 1.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.md +1 -0
- data/immortal.gemspec +1 -2
- data/lib/immortal.rb +12 -0
- data/lib/immortal/belongs_to_builder.rb +46 -0
- data/lib/immortal/singular_association.rb +57 -0
- data/spec/immortal_spec.rb +49 -0
- data/spec/spec_helper.rb +29 -0
- metadata +9 -7
data/README.md
CHANGED
data/immortal.gemspec
CHANGED
@@ -3,8 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "immortal"
|
6
|
-
s.version = '1.0.
|
7
|
-
s.platform = Gem::Platform::RUBY
|
6
|
+
s.version = '1.0.2'
|
8
7
|
s.authors = ["Jordi Romero", "Saimon Moore"]
|
9
8
|
s.email = ["jordi@jrom.net", "saimon@saimonmoore.net"]
|
10
9
|
s.homepage = "http://github.com/teambox/immortal"
|
data/lib/immortal.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'immortal/belongs_to_builder'
|
2
|
+
|
1
3
|
module Immortal
|
2
4
|
|
3
5
|
def self.included(base)
|
@@ -5,6 +7,12 @@ module Immortal
|
|
5
7
|
base.send :include, InstanceMethods
|
6
8
|
base.class_eval do
|
7
9
|
class << self
|
10
|
+
|
11
|
+
# Add with/how_deleted singular association readers
|
12
|
+
def belongs_to_mortal(name, options = {})
|
13
|
+
::Immortal::BelongsToBuilder.build(self, name, options)
|
14
|
+
end
|
15
|
+
|
8
16
|
# In has_many :through => join_model we have to explicitly add
|
9
17
|
# the 'not deleted' scope, otherwise it will take all the rows
|
10
18
|
# from the join model
|
@@ -17,6 +25,10 @@ module Immortal
|
|
17
25
|
alias_method :has_many_immortal, :has_many
|
18
26
|
alias_method :has_many, :has_many_mortal
|
19
27
|
|
28
|
+
alias_method :belongs_to_immortal, :belongs_to
|
29
|
+
alias_method :belongs_to, :belongs_to_mortal
|
30
|
+
|
31
|
+
|
20
32
|
alias :mortal_delete_all :delete_all
|
21
33
|
alias :delete_all :immortal_delete_all
|
22
34
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'immortal/singular_association'
|
3
|
+
|
4
|
+
module Immortal
|
5
|
+
class BelongsToBuilder < ::ActiveRecord::Associations::Builder::BelongsTo
|
6
|
+
|
7
|
+
def define_accessors
|
8
|
+
super
|
9
|
+
define_deletables
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def define_deletables
|
15
|
+
define_with_deleted_reader
|
16
|
+
define_only_deleted_reader
|
17
|
+
end
|
18
|
+
|
19
|
+
def define_with_deleted_reader
|
20
|
+
name = self.name
|
21
|
+
|
22
|
+
model.redefine_method("#{name}_with_deleted") do |*params|
|
23
|
+
assoc = association(name)
|
24
|
+
assoc.send(:extend, SingularAssociation)
|
25
|
+
assoc.with_deleted_reader(*params)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def define_only_deleted_reader
|
30
|
+
name = self.name
|
31
|
+
|
32
|
+
model.redefine_method("#{name}_only_deleted") do |*params|
|
33
|
+
|
34
|
+
assoc = association(name)
|
35
|
+
assoc.send(:extend, SingularAssociation)
|
36
|
+
assoc.only_deleted_reader(*params)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module InstanceMethods
|
41
|
+
|
42
|
+
end #InstanceMethods
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Immortal
|
2
|
+
module SingularAssociation
|
3
|
+
attr_reader :deleted_target
|
4
|
+
|
5
|
+
def with_deleted_reader(force_reload = false)
|
6
|
+
deleted_reader('with', force_reload)
|
7
|
+
end
|
8
|
+
|
9
|
+
def only_deleted_reader(force_reload = false)
|
10
|
+
deleted_reader('only', force_reload)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def deleted_reader(how, force_reload = false)
|
16
|
+
klass.uncached do
|
17
|
+
send(:"reload_#{how}_deleted")
|
18
|
+
end
|
19
|
+
|
20
|
+
deleted_target
|
21
|
+
end
|
22
|
+
|
23
|
+
def reload_with_deleted
|
24
|
+
reset
|
25
|
+
reset_scope
|
26
|
+
load_deleted_target('with')
|
27
|
+
self unless deleted_target.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def reload_only_deleted
|
31
|
+
reset
|
32
|
+
reset_scope
|
33
|
+
load_deleted_target('only')
|
34
|
+
self unless deleted_target.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_with_deleted_target
|
38
|
+
klass.unscoped do
|
39
|
+
scoped.first.tap { |record| set_inverse_instance(record) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def find_only_deleted_target
|
44
|
+
klass.unscoped do
|
45
|
+
scoped.where(:deleted => true).first.tap { |record| set_inverse_instance(record) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def load_deleted_target(how)
|
50
|
+
@deleted_target ||= send(:"find_#{how}_deleted_target")
|
51
|
+
deleted_target
|
52
|
+
rescue ActiveRecord::RecordNotFound
|
53
|
+
reset
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
data/spec/immortal_spec.rb
CHANGED
@@ -198,4 +198,53 @@ describe Immortal do
|
|
198
198
|
generated_sql.should include(join_sql2)
|
199
199
|
end
|
200
200
|
|
201
|
+
it "should reload immortal polymorphic associations using default reader" do
|
202
|
+
node = ImmortalNode.create! :title => 'testing association 1'
|
203
|
+
target_1 = ImmortalSomeTarget.create! :title => 'target 1'
|
204
|
+
target_2 = ImmortalSomeOtherTarget.create! :title => 'target 2'
|
205
|
+
|
206
|
+
node.target.should be_nil
|
207
|
+
node.target = target_1
|
208
|
+
node.target.should == target_1
|
209
|
+
|
210
|
+
node.target_id = target_2.id
|
211
|
+
node.target_type = target_2.class.name
|
212
|
+
|
213
|
+
target_2.destroy
|
214
|
+
node.target.should be_nil
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should reload immortal polymorphic associations using deleted reader" do
|
218
|
+
#setup
|
219
|
+
node = ImmortalNode.create! :title => 'testing association 1'
|
220
|
+
target_1 = ImmortalSomeTarget.create! :title => 'target 1'
|
221
|
+
target_2 = ImmortalSomeOtherTarget.create! :title => 'target 2'
|
222
|
+
|
223
|
+
#confirm initial state
|
224
|
+
node.target.should be_nil
|
225
|
+
|
226
|
+
#load target & confirm
|
227
|
+
node.target = target_1
|
228
|
+
node.target.should == target_1
|
229
|
+
|
230
|
+
#switch target indirectly
|
231
|
+
node.target_id = target_2.id
|
232
|
+
node.target_type = target_2.class.name
|
233
|
+
|
234
|
+
#don't assign directly and destroy new target
|
235
|
+
target_2.destroy
|
236
|
+
|
237
|
+
#Respect what's expected
|
238
|
+
node.target.should be_nil
|
239
|
+
|
240
|
+
#Ask for deleted target (or not deleted). Will NOT cache
|
241
|
+
node.target_with_deleted.should == target_2
|
242
|
+
|
243
|
+
#Ask only for deleted target. Will NOT cache
|
244
|
+
node.target_only_deleted.should == target_2
|
245
|
+
|
246
|
+
#Confirm we haven't invaded the target namespace
|
247
|
+
node.target.should be_nil
|
248
|
+
end
|
249
|
+
|
201
250
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -36,11 +36,25 @@ begin
|
|
36
36
|
t.timestamps
|
37
37
|
end
|
38
38
|
create_table :immortal_nodes do |t|
|
39
|
+
t.integer :target_id
|
40
|
+
t.string :target_type
|
39
41
|
t.string :title
|
40
42
|
t.integer :value
|
41
43
|
t.boolean :deleted, :default => false
|
42
44
|
t.timestamps
|
43
45
|
end
|
46
|
+
|
47
|
+
create_table :immortal_some_targets do |t|
|
48
|
+
t.string :title
|
49
|
+
t.boolean :deleted, :default => false
|
50
|
+
t.timestamps
|
51
|
+
end
|
52
|
+
|
53
|
+
create_table :immortal_some_other_targets do |t|
|
54
|
+
t.string :title
|
55
|
+
t.boolean :deleted, :default => false
|
56
|
+
t.timestamps
|
57
|
+
end
|
44
58
|
end
|
45
59
|
ensure
|
46
60
|
$stdout = old_stdout
|
@@ -61,8 +75,23 @@ class ImmortalNode < ActiveRecord::Base
|
|
61
75
|
|
62
76
|
has_many :joins, :class_name => 'ImmortalJoin'
|
63
77
|
has_many :models, :through => :joins, :source => :immortal_model
|
78
|
+
|
79
|
+
belongs_to :target, :polymorphic => true
|
80
|
+
end
|
81
|
+
|
82
|
+
class ImmortalSomeTarget < ActiveRecord::Base
|
83
|
+
include Immortal
|
84
|
+
|
85
|
+
has_many :immortal_nodes, :as => :target
|
64
86
|
end
|
65
87
|
|
88
|
+
class ImmortalSomeOtherTarget < ActiveRecord::Base
|
89
|
+
include Immortal
|
90
|
+
|
91
|
+
has_many :immortal_nodes, :as => :target
|
92
|
+
end
|
93
|
+
|
94
|
+
|
66
95
|
class ImmortalModel < ActiveRecord::Base
|
67
96
|
include Immortal
|
68
97
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: immortal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -14,7 +14,7 @@ date: 2011-10-17 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
17
|
-
requirement: &
|
17
|
+
requirement: &70147088431320 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 3.1.1
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70147088431320
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rspec
|
28
|
-
requirement: &
|
28
|
+
requirement: &70147088430840 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ~>
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: 2.6.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70147088430840
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: sqlite3
|
39
|
-
requirement: &
|
39
|
+
requirement: &70147088430460 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70147088430460
|
48
48
|
description: Typical paranoid gem built for Rails 3 and with the minimum code needed
|
49
49
|
to satisfy acts_as_paranoid's API
|
50
50
|
email:
|
@@ -61,6 +61,8 @@ files:
|
|
61
61
|
- Rakefile
|
62
62
|
- immortal.gemspec
|
63
63
|
- lib/immortal.rb
|
64
|
+
- lib/immortal/belongs_to_builder.rb
|
65
|
+
- lib/immortal/singular_association.rb
|
64
66
|
- spec/immortal_spec.rb
|
65
67
|
- spec/spec_helper.rb
|
66
68
|
homepage: http://github.com/teambox/immortal
|