immortal 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -41,6 +41,7 @@ If you want to improve immortal
41
41
 
42
42
  ## CHANGELOG
43
43
 
44
+ - 1.0.2 Added with/only_deleted singular association readers (see specs)
44
45
  - 1.0.1 Made compatible with Rails 3.1.X
45
46
  - 1.0.0 Changed the API, made it compatible with Rails 3.1, removed
46
47
  functionality
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.1'
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
@@ -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.1
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: &70094483448900 !ruby/object:Gem::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: *70094483448900
25
+ version_requirements: *70147088431320
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rspec
28
- requirement: &70094483448420 !ruby/object:Gem::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: *70094483448420
36
+ version_requirements: *70147088430840
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: sqlite3
39
- requirement: &70094483448040 !ruby/object:Gem::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: *70094483448040
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