ripple 0.9.5 → 1.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/.gitignore +32 -0
  2. data/Gemfile +10 -9
  3. data/Guardfile +15 -0
  4. data/Rakefile +11 -40
  5. data/lib/rails/generators/ripple/configuration/configuration_generator.rb +0 -13
  6. data/lib/rails/generators/ripple/configuration/templates/ripple.yml +4 -4
  7. data/lib/rails/generators/ripple/js/js_generator.rb +0 -13
  8. data/lib/rails/generators/ripple/js/templates/js/contrib.js +0 -17
  9. data/lib/rails/generators/ripple/js/templates/js/ripple.js +0 -13
  10. data/lib/rails/generators/ripple/model/model_generator.rb +0 -14
  11. data/lib/rails/generators/ripple/model/templates/model.rb +1 -1
  12. data/lib/rails/generators/ripple/observer/observer_generator.rb +0 -14
  13. data/lib/rails/generators/ripple/test/test_generator.rb +7 -19
  14. data/lib/rails/generators/ripple_generator.rb +1 -14
  15. data/lib/ripple.rb +7 -14
  16. data/lib/ripple/associations.rb +129 -26
  17. data/lib/ripple/associations/embedded.rb +1 -15
  18. data/lib/ripple/associations/instantiators.rb +0 -13
  19. data/lib/ripple/associations/linked.rb +41 -19
  20. data/lib/ripple/associations/many.rb +0 -14
  21. data/lib/ripple/associations/many_embedded_proxy.rb +0 -14
  22. data/lib/ripple/associations/many_linked_proxy.rb +39 -18
  23. data/lib/ripple/associations/many_reference_proxy.rb +93 -0
  24. data/lib/ripple/associations/many_stored_key_proxy.rb +76 -0
  25. data/lib/ripple/associations/one.rb +1 -15
  26. data/lib/ripple/associations/one_embedded_proxy.rb +0 -14
  27. data/lib/ripple/associations/one_key_proxy.rb +58 -0
  28. data/lib/ripple/associations/one_linked_proxy.rb +4 -14
  29. data/lib/ripple/associations/one_stored_key_proxy.rb +43 -0
  30. data/lib/ripple/associations/proxy.rb +8 -14
  31. data/lib/ripple/attribute_methods.rb +19 -17
  32. data/lib/ripple/attribute_methods/dirty.rb +19 -15
  33. data/lib/ripple/attribute_methods/query.rb +0 -14
  34. data/lib/ripple/attribute_methods/read.rb +0 -14
  35. data/lib/ripple/attribute_methods/write.rb +0 -14
  36. data/lib/ripple/callbacks.rb +10 -16
  37. data/lib/ripple/conflict/basic_resolver.rb +82 -0
  38. data/lib/ripple/conflict/document_hooks.rb +20 -0
  39. data/lib/ripple/conflict/resolver.rb +71 -0
  40. data/lib/ripple/conflict/test_helper.rb +33 -0
  41. data/lib/ripple/conversion.rb +0 -14
  42. data/lib/ripple/core_ext.rb +1 -14
  43. data/lib/ripple/core_ext/casting.rb +19 -19
  44. data/lib/ripple/core_ext/object.rb +8 -0
  45. data/lib/ripple/document.rb +21 -16
  46. data/lib/ripple/document/bucket_access.rb +0 -14
  47. data/lib/ripple/document/finders.rb +17 -23
  48. data/lib/ripple/document/key.rb +8 -28
  49. data/lib/ripple/document/link.rb +30 -0
  50. data/lib/ripple/document/persistence.rb +12 -20
  51. data/lib/ripple/embedded_document.rb +10 -15
  52. data/lib/ripple/embedded_document/around_callbacks.rb +18 -0
  53. data/lib/ripple/embedded_document/finders.rb +7 -18
  54. data/lib/ripple/embedded_document/persistence.rb +5 -17
  55. data/lib/ripple/i18n.rb +0 -14
  56. data/lib/ripple/inspection.rb +21 -15
  57. data/lib/ripple/locale/en.yml +9 -13
  58. data/lib/ripple/nested_attributes.rb +33 -39
  59. data/lib/ripple/observable.rb +0 -13
  60. data/lib/ripple/properties.rb +1 -14
  61. data/lib/ripple/property_type_mismatch.rb +0 -14
  62. data/lib/ripple/railtie.rb +4 -14
  63. data/lib/ripple/railties/ripple.rake +86 -0
  64. data/lib/ripple/serialization.rb +11 -11
  65. data/lib/ripple/test_server.rb +36 -0
  66. data/lib/ripple/timestamps.rb +0 -13
  67. data/lib/ripple/translation.rb +4 -14
  68. data/lib/ripple/validations.rb +1 -15
  69. data/lib/ripple/validations/associated_validator.rb +26 -17
  70. data/lib/ripple/version.rb +3 -0
  71. data/ripple.gemspec +24 -35
  72. data/spec/integration/ripple/associations_spec.rb +89 -58
  73. data/spec/integration/ripple/conflict_resolution_spec.rb +298 -0
  74. data/spec/integration/ripple/nested_attributes_spec.rb +19 -19
  75. data/spec/integration/ripple/persistence_spec.rb +15 -34
  76. data/spec/integration/ripple/search_associations_spec.rb +31 -0
  77. data/spec/ripple/associations/many_embedded_proxy_spec.rb +23 -36
  78. data/spec/ripple/associations/many_linked_proxy_spec.rb +133 -45
  79. data/spec/ripple/associations/many_reference_proxy_spec.rb +170 -0
  80. data/spec/ripple/associations/many_stored_key_proxy_spec.rb +158 -0
  81. data/spec/ripple/associations/one_embedded_proxy_spec.rb +24 -37
  82. data/spec/ripple/associations/one_key_proxy_spec.rb +82 -0
  83. data/spec/ripple/associations/one_linked_proxy_spec.rb +22 -23
  84. data/spec/ripple/associations/one_stored_key_proxy_spec.rb +72 -0
  85. data/spec/ripple/associations/proxy_spec.rb +21 -15
  86. data/spec/ripple/associations_spec.rb +54 -23
  87. data/spec/ripple/attribute_methods/dirty_spec.rb +56 -5
  88. data/spec/ripple/attribute_methods_spec.rb +47 -21
  89. data/spec/ripple/bucket_access_spec.rb +4 -17
  90. data/spec/ripple/callbacks_spec.rb +52 -15
  91. data/spec/ripple/conflict/resolver_spec.rb +42 -0
  92. data/spec/ripple/conversion_spec.rb +2 -15
  93. data/spec/ripple/core_ext_spec.rb +12 -15
  94. data/spec/ripple/document/link_spec.rb +67 -0
  95. data/spec/ripple/document_spec.rb +34 -19
  96. data/spec/ripple/embedded_document/finders_spec.rb +12 -19
  97. data/spec/ripple/embedded_document/persistence_spec.rb +20 -26
  98. data/spec/ripple/embedded_document_spec.rb +44 -34
  99. data/spec/ripple/finders_spec.rb +58 -29
  100. data/spec/ripple/inspection_spec.rb +40 -37
  101. data/spec/ripple/key_spec.rb +5 -17
  102. data/spec/ripple/observable_spec.rb +3 -16
  103. data/spec/ripple/persistence_spec.rb +134 -18
  104. data/spec/ripple/properties_spec.rb +21 -15
  105. data/spec/ripple/ripple_spec.rb +1 -14
  106. data/spec/ripple/serialization_spec.rb +16 -17
  107. data/spec/ripple/timestamps_spec.rb +73 -52
  108. data/spec/ripple/validations/associated_validator_spec.rb +69 -25
  109. data/spec/ripple/validations_spec.rb +3 -16
  110. data/spec/spec_helper.rb +17 -18
  111. data/spec/support/associations.rb +1 -1
  112. data/spec/support/associations/proxies.rb +0 -13
  113. data/spec/support/integration_setup.rb +11 -0
  114. data/spec/support/mocks.rb +0 -13
  115. data/spec/support/models.rb +33 -2
  116. data/spec/support/models/address.rb +1 -16
  117. data/spec/support/models/box.rb +7 -14
  118. data/spec/support/models/car.rb +27 -1
  119. data/spec/support/models/cardboard_box.rb +0 -14
  120. data/spec/support/models/clock.rb +6 -15
  121. data/spec/support/models/clock_observer.rb +0 -14
  122. data/spec/support/models/credit_card.rb +5 -0
  123. data/spec/support/models/customer.rb +0 -14
  124. data/spec/support/models/email.rb +0 -14
  125. data/spec/support/models/family.rb +1 -13
  126. data/spec/support/models/favorite.rb +0 -14
  127. data/spec/support/models/invoice.rb +0 -14
  128. data/spec/support/models/late_invoice.rb +0 -14
  129. data/spec/support/models/nested.rb +12 -0
  130. data/spec/support/models/ninja.rb +7 -0
  131. data/spec/support/models/note.rb +0 -14
  132. data/spec/support/models/page.rb +1 -15
  133. data/spec/support/models/paid_invoice.rb +0 -14
  134. data/spec/support/models/post.rb +12 -0
  135. data/spec/support/models/profile.rb +7 -0
  136. data/spec/support/models/subscription.rb +26 -0
  137. data/spec/support/models/tasks.rb +0 -18
  138. data/spec/support/models/team.rb +11 -0
  139. data/spec/support/models/transactions.rb +17 -0
  140. data/spec/support/models/tree.rb +2 -16
  141. data/spec/support/models/user.rb +14 -16
  142. data/spec/support/models/widget.rb +8 -14
  143. data/spec/support/search.rb +14 -0
  144. data/spec/support/test_server.rb +22 -12
  145. data/spec/support/test_server.yml.example +14 -2
  146. metadata +223 -59
  147. data/lib/rails/generators/ripple/test/templates/test_server.rb +0 -46
  148. data/spec/support/models/driver.rb +0 -5
  149. data/spec/support/models/engine.rb +0 -4
  150. data/spec/support/models/passenger.rb +0 -5
  151. data/spec/support/models/seat.rb +0 -4
  152. data/spec/support/models/wheel.rb +0 -5
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::Associations::OneKeyProxy do
4
+
5
+ before :each do
6
+ @user = User.new
7
+ @profile = Profile.new(:color => 'blue')
8
+ end
9
+
10
+ describe "User with a key corresponded profile" do
11
+ it "should not have a profile before it is set" do
12
+ @user.profile.should be_nil
13
+ end
14
+
15
+ it "should be able to get and set its profile" do
16
+ @user.profile = @profile
17
+ @user.profile.should eq(@profile)
18
+ end
19
+
20
+ it "should return the assignment when assigning" do
21
+ rtn = @user.profile = @profile
22
+ rtn.should eq(@profile)
23
+ end
24
+
25
+ it "should be able to replace its profile with a new one" do
26
+ @user.profile = @profile
27
+ @user.profile = Profile.new(:color => 'red')
28
+ @user.profile.color.should eq('red')
29
+ end
30
+
31
+ it "should be able to build a new profile" do
32
+ Profile.stub(:new).and_return(@profile)
33
+ @user.profile.build.should eq(@profile)
34
+ end
35
+
36
+ it "should assign its key to the associated profile when assigning" do
37
+ @user.key = "foo"
38
+ @user.profile = @profile
39
+ @profile.key.should eq("foo")
40
+ end
41
+
42
+ it "should assign its key to the built profile" do
43
+ @user.key = "foo"
44
+ @user.profile.build.key.should eq("foo")
45
+ end
46
+
47
+ it "should update the key on the profile when updating it on the user" do
48
+ @user.profile = @profile
49
+ @user.key = "foo"
50
+ @profile.key.should eq("foo")
51
+ end
52
+
53
+ it "should not update the key of a previous profile" do
54
+ @profile2 = Profile.new
55
+ @user.profile = @profile
56
+ @user.profile = @profile2
57
+ @user.key = "foo"
58
+ @profile.key.should_not eq("foo")
59
+ end
60
+
61
+ it "should not infinitely loop when assigning a user to the profile" do
62
+ @user2 = User.new
63
+ @user.profile = @profile
64
+ @profile.user = @user2
65
+ @profile.key = "foo"
66
+ @user2.key.should eq("foo")
67
+ end
68
+
69
+ it "should update the user's key when being updated on the profile" do
70
+ @user.profile = @profile
71
+ @profile.key = "foo"
72
+ @user.key.should eq("foo")
73
+ end
74
+
75
+ it "should work properly with custom key methods" do
76
+ @user = Ninja.new(:name => 'Naruto')
77
+ @user.profile = @profile
78
+ @profile.key.should eq("ninja-naruto")
79
+ end
80
+ end
81
+
82
+ end
@@ -1,21 +1,8 @@
1
- # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- require File.expand_path("../../../spec_helper", __FILE__)
1
+ require 'spec_helper'
15
2
 
16
3
  describe Ripple::Associations::OneLinkedProxy do
17
- require 'support/models/tasks'
18
- require 'support/models/family'
4
+ # require 'support/models/tasks'
5
+ # require 'support/models/family'
19
6
 
20
7
  before :each do
21
8
  @person = Person.new {|p| p.key = "riak-user" }
@@ -36,7 +23,7 @@ describe Ripple::Associations::OneLinkedProxy do
36
23
 
37
24
  it "should set the link on the RObject when assigning" do
38
25
  @person.profile = @profile
39
- @person.robject.links.should include(@profile.robject.to_link("profile"))
26
+ @person.robject.links.should include(@profile.to_link("profile"))
40
27
  end
41
28
 
42
29
  it "should return the assigned document when assigning" do
@@ -44,18 +31,30 @@ describe Ripple::Associations::OneLinkedProxy do
44
31
  ret.should == @profile
45
32
  end
46
33
 
47
- it "should save the new document when assigning" do
48
- @profile.should_receive(:new?).and_return(true)
49
- @profile.should_receive(:save).and_return(true)
50
- @person.profile = @profile
51
- end
52
-
53
34
  it "should link-walk to the associated document when accessing" do
54
35
  @person.robject.links << @profile.robject.to_link("profile")
55
36
  @person.robject.should_receive(:walk).with(Riak::WalkSpec.new(:bucket => "profiles", :tag => "profile")).and_return([[@profile.robject]])
56
37
  @person.profile.should be_present
57
38
  end
58
39
 
40
+ it "handles conflict appropriately by selecting the linked-walk robject that matches the link" do
41
+ @person.robject.links << @profile.robject.to_link("profile")
42
+ @person.robject.
43
+ should_receive(:walk).
44
+ with(Riak::WalkSpec.new(:bucket => "profiles", :tag => "profile")).
45
+ and_return([[@other_profile.robject, @profile.robject]])
46
+
47
+ @person.profile.should == @profile
48
+ end
49
+
50
+ it "allows the links to be replaced directly" do
51
+ @person.profile = @profile
52
+ @person.profile.__send__(:should_receive, :reset)
53
+ @person.profile.__send__(:links).should == [@profile.robject.to_link("profile")]
54
+ @person.profile.replace_links(@other_profile.robject.to_link("profile"))
55
+ @person.profile.__send__(:links).should == [@other_profile.robject.to_link("profile")]
56
+ end
57
+
59
58
  it "should return nil immediately if the association link is missing" do
60
59
  @person.robject.links.should be_empty
61
60
  @person.profile.should be_nil
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::Associations::OneStoredKeyProxy do
4
+ # require 'support/models/transactions'
5
+ # require 'support/models/family'
6
+
7
+ before :each do
8
+ @account = Account.new {|e| e.key = "accounty" }
9
+ @other_account = Account.new{|e| e.key = "ickycount" }
10
+ @transaction = Transaction.new{|e| e.key = "transacty" }
11
+ end
12
+
13
+ it "should be blank before the associated document is set" do
14
+ @transaction.account.should_not be_present
15
+ end
16
+
17
+ it "should accept a single document" do
18
+ lambda { @transaction.account = @account }.should_not raise_error
19
+ end
20
+
21
+ it "should set the key when assigning" do
22
+ @transaction.account = @account
23
+ @transaction.account_key.should == "accounty"
24
+ end
25
+
26
+ it "should return the assigned document when assigning" do
27
+ ret = (@transaction.account = @account)
28
+ ret.should == @account
29
+ end
30
+
31
+ it "should find the associated document when accessing" do
32
+ @transaction.account_key = "accounty"
33
+ Account.should_receive(:find).with("accounty").and_return(@account)
34
+ @transaction.account.should be_present
35
+ end
36
+
37
+ it "should return nil immediately if the association link is missing" do
38
+ @transaction.account_key.should be_nil
39
+ @transaction.account.should be_nil
40
+ end
41
+
42
+ it "should replace associated document with a new one" do
43
+ @transaction.account = @account
44
+ @transaction.account = @other_account
45
+ @transaction.account.should == @other_account
46
+ @transaction.account_key.should == "ickycount"
47
+ end
48
+
49
+ it "should replace the associated document with the target of the proxy" do
50
+ other_transaction = Transaction.new {|e| e.key = "ickytrans" }
51
+ other_transaction.account = @other_account
52
+
53
+ @transaction.account = other_transaction.account
54
+ @transaction.account.should == @other_account
55
+ end
56
+
57
+ it "refuses assigning a proxy if its target is the wrong type" do
58
+ parent = Parent.new{|e| e.child = Child.new}
59
+ lambda { @transaction.account = parent.child }.should raise_error
60
+ end
61
+
62
+ it "should refuse assigning a document of the wrong type" do
63
+ lambda { @transaction.account = @transaction }.should raise_error
64
+ end
65
+
66
+ it "should nil out the association if nil is assigned" do
67
+ @transaction.account = @account
68
+ @transaction.account = nil
69
+ @transaction.account.should be_nil
70
+ @transaction.account_key.should be_nil
71
+ end
72
+ end
@@ -1,17 +1,4 @@
1
- # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- require File.expand_path("../../../spec_helper", __FILE__)
1
+ require 'spec_helper'
15
2
 
16
3
  describe Ripple::Associations::Proxy do
17
4
  require 'support/associations/proxies'
@@ -75,4 +62,23 @@ describe Ripple::Associations::Proxy do
75
62
  it { should be_blank }
76
63
  it { should_not be_present }
77
64
  end
78
- end
65
+
66
+ describe "#has_changed_documents?" do
67
+ before(:each) { @proxy.respond_to?(:loaded_documents).should be_true }
68
+
69
+ it "returns true if any of the loaded documents return true from #changed?" do
70
+ @proxy.stub(:loaded_documents => [stub(:changed? => false), stub(:changed? => true)])
71
+ @proxy.has_changed_documents?.should be_true
72
+ end
73
+
74
+ it "returns false if none of the loaded documents return true from #changed?" do
75
+ @proxy.stub(:loaded_documents => [stub(:changed? => false), stub(:changed? => false)])
76
+ @proxy.has_changed_documents?.should be_false
77
+ end
78
+
79
+ it "returns false if it has no loaded documents" do
80
+ @proxy.stub(:loaded_documents => [])
81
+ @proxy.has_changed_documents?.should be_false
82
+ end
83
+ end
84
+ end
@@ -1,22 +1,9 @@
1
- # Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- require File.expand_path("../../spec_helper", __FILE__)
1
+ require 'spec_helper'
15
2
 
16
3
  describe Ripple::Associations do
17
- require 'support/models/invoice'
18
- require 'support/models/customer'
19
- require 'support/models/note'
4
+ # require 'support/models/invoice'
5
+ # require 'support/models/customer'
6
+ # require 'support/models/note'
20
7
 
21
8
  it "should provide access to the associations hash" do
22
9
  Invoice.should respond_to(:associations)
@@ -27,6 +14,15 @@ describe Ripple::Associations do
27
14
  Invoice.embedded_associations.should == Array(Invoice.associations[:note])
28
15
  end
29
16
 
17
+ it "should collect the linked associations" do
18
+ Invoice.linked_associations.should == Array(Invoice.associations[:customer])
19
+ end
20
+
21
+ it "should collect the stored_key associations" do
22
+ Account.stored_key_associations.should == Array(Account.associations[:transactions])
23
+ Transaction.stored_key_associations.should == Array(Transaction.associations[:account])
24
+ end
25
+
30
26
  it "should copy associations to a subclass" do
31
27
  Invoice.associations[:foo] = "bar"
32
28
  class SubInvoice < Invoice; end
@@ -50,11 +46,16 @@ describe Ripple::Associations do
50
46
  end
51
47
  end
52
48
 
53
- after do
54
- Invoice.associations.delete(:foo)
55
- Invoice.associations.delete(:items)
56
- SubInvoice.associations.delete(:foo) if defined?(SubInvoice)
57
- Invoice.associations.delete(:payee)
49
+ before(:all) do
50
+ @orig_invoice = Invoice
51
+ Object.send(:remove_const, :Invoice)
52
+ class Invoice < @orig_invoice; end
53
+ end
54
+
55
+ after(:all) do
56
+ Object.send(:remove_const, :SubInvoice) if defined?(SubInvoice)
57
+ Object.send(:remove_const, :Invoice)
58
+ Object.send(:const_set, :Invoice, @orig_invoice)
58
59
  end
59
60
  end
60
61
 
@@ -81,7 +82,22 @@ describe Ripple::Association do
81
82
  end
82
83
 
83
84
  describe "determining the target class" do
84
- require 'support/models/tree'
85
+ context "when in a nested module scope" do
86
+ it "should find the target via the owner's module scope" do
87
+ @association = Ripple::Association.new(:many, :children)
88
+ @association.setup_on(Nested::Scope::Parent)
89
+ @association.klass.should == Nested::Scope::Child
90
+ end
91
+
92
+ it "should not try to find the target in the owner's scope when the class name is fully qualified" do
93
+ @association = Ripple::Association.new(:many, :children, :class_name => "Nested::Scope::Child")
94
+ @association.setup_on(Nested::Scope::Parent)
95
+ expect {
96
+ @association.klass
97
+ }.should_not raise_error
98
+ @association.klass.should == Nested::Scope::Child
99
+ end
100
+ end
85
101
 
86
102
  it "should default to the constantized class name" do
87
103
  @association = Ripple::Association.new(:one, :t, :class_name => "Trunk")
@@ -110,4 +126,19 @@ describe Ripple::Association do
110
126
  it "should determine an instance variable based on the name" do
111
127
  Ripple::Association.new(:many, :pages).ivar.should == "@_pages"
112
128
  end
129
+
130
+ describe "key correspondence" do
131
+ require 'support/models/profile'
132
+ require 'support/models/user'
133
+
134
+ it "should raise an exception if trying to use a many association when :using => :key" do
135
+ expect { Profile.many :user, :using => :key }.to raise_error(ArgumentError, "You cannot use a many association using :key")
136
+ end
137
+
138
+ it "should add the key_delegate attr_accessor to the model declaring the association" do
139
+ Profile.one :user, :using => :key
140
+ Profile.new.should respond_to(:key_delegate)
141
+ Profile.new.should respond_to(:key_delegate=)
142
+ end
143
+ end
113
144
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path("../../../spec_helper", __FILE__)
1
+ require 'spec_helper'
2
2
 
3
3
  describe Ripple::AttributeMethods::Dirty do
4
4
  let(:company) { Company.new }
@@ -12,18 +12,69 @@ describe Ripple::AttributeMethods::Dirty do
12
12
  company.robject.stub!(:store).and_return(true)
13
13
  company.name = 'Fizz Buzz, Inc.'
14
14
  end
15
-
15
+
16
16
  it "should capture previous changes when saving" do
17
17
  company.save
18
18
  company.previous_changes.should include('name')
19
19
  end
20
20
 
21
21
  it "should make previous changes available to after callbacks" do
22
- class << company
22
+ my_class = Class.new(Company) do
23
23
  after_save {|c| c['pc'] = previous_changes }
24
24
  end
25
- company.save
26
- company['pc'].should include('name')
25
+ comp = my_class.new
26
+ comp.robject.stub!(:store).and_return(true)
27
+ comp.name = 'Fizz Buzz, Inc.'
28
+ comp.save
29
+ comp['pc'].should include('name')
30
+ end
31
+ end
32
+
33
+ describe "#changed?" do
34
+
35
+ it "returns true if the document's attributes have changed (regardless of whether or not it has any embedded associated documents)" do
36
+ company.name = 'Fizz Buzz, Inc'
37
+ company.should be_changed
38
+ end
39
+
40
+
41
+ context "when the document's attributes have not changed" do
42
+ it 'returns false if it has no embedded associated documents' do
43
+ company.should_not be_changed
44
+ end
45
+
46
+ context 'when the document has embedded associated documents' do
47
+ before(:each) do
48
+ company.ceo = ceo
49
+ company.invoices << invoice
50
+ company.departments << department
51
+ department.managers << manager
52
+ end
53
+
54
+ it 'returns false if all the embedded documents are not changed' do
55
+ company.should_not be_changed
56
+ end
57
+
58
+ it 'does not consider changes to linked associated documents' do
59
+ invoice.should_not_receive(:changed?)
60
+ company.changed?
61
+ end
62
+
63
+ it 'returns true if a one embedded association document is changed' do
64
+ ceo.should_receive(:changed?).and_return(true)
65
+ company.should be_changed
66
+ end
67
+
68
+ it 'returns true if a many embedded association document is changed' do
69
+ department.should_receive(:changed?).and_return(true)
70
+ company.should be_changed
71
+ end
72
+
73
+ it 'recurses through the whole embedded document structure to find changed grandchild documents' do
74
+ manager.should_receive(:changed?).and_return(true)
75
+ company.should be_changed
76
+ end
77
+ end
27
78
  end
28
79
  end
29
80
  end