seomoz-ripple 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. data/Gemfile +20 -0
  2. data/Guardfile +15 -0
  3. data/Rakefile +88 -0
  4. data/lib/rails/generators/ripple/configuration/configuration_generator.rb +13 -0
  5. data/lib/rails/generators/ripple/configuration/templates/ripple.yml +24 -0
  6. data/lib/rails/generators/ripple/js/js_generator.rb +13 -0
  7. data/lib/rails/generators/ripple/js/templates/js/contrib.js +63 -0
  8. data/lib/rails/generators/ripple/js/templates/js/iso8601.js +76 -0
  9. data/lib/rails/generators/ripple/js/templates/js/ripple.js +132 -0
  10. data/lib/rails/generators/ripple/model/model_generator.rb +20 -0
  11. data/lib/rails/generators/ripple/model/templates/model.rb +10 -0
  12. data/lib/rails/generators/ripple/observer/observer_generator.rb +16 -0
  13. data/lib/rails/generators/ripple/observer/templates/observer.rb +4 -0
  14. data/lib/rails/generators/ripple/test/templates/test_server.rb +46 -0
  15. data/lib/rails/generators/ripple/test/test_generator.rb +39 -0
  16. data/lib/rails/generators/ripple_generator.rb +78 -0
  17. data/lib/ripple.rb +79 -0
  18. data/lib/ripple/associations.rb +356 -0
  19. data/lib/ripple/associations/embedded.rb +35 -0
  20. data/lib/ripple/associations/instantiators.rb +26 -0
  21. data/lib/ripple/associations/linked.rb +65 -0
  22. data/lib/ripple/associations/many.rb +38 -0
  23. data/lib/ripple/associations/many_embedded_proxy.rb +38 -0
  24. data/lib/ripple/associations/many_linked_proxy.rb +66 -0
  25. data/lib/ripple/associations/many_reference_proxy.rb +93 -0
  26. data/lib/ripple/associations/many_stored_key_proxy.rb +76 -0
  27. data/lib/ripple/associations/one.rb +20 -0
  28. data/lib/ripple/associations/one_embedded_proxy.rb +35 -0
  29. data/lib/ripple/associations/one_key_proxy.rb +58 -0
  30. data/lib/ripple/associations/one_linked_proxy.rb +22 -0
  31. data/lib/ripple/associations/one_stored_key_proxy.rb +43 -0
  32. data/lib/ripple/associations/proxy.rb +118 -0
  33. data/lib/ripple/attribute_methods.rb +118 -0
  34. data/lib/ripple/attribute_methods/dirty.rb +50 -0
  35. data/lib/ripple/attribute_methods/query.rb +34 -0
  36. data/lib/ripple/attribute_methods/read.rb +26 -0
  37. data/lib/ripple/attribute_methods/write.rb +25 -0
  38. data/lib/ripple/callbacks.rb +74 -0
  39. data/lib/ripple/conflict/basic_resolver.rb +82 -0
  40. data/lib/ripple/conflict/document_hooks.rb +20 -0
  41. data/lib/ripple/conflict/resolver.rb +71 -0
  42. data/lib/ripple/conflict/test_helper.rb +33 -0
  43. data/lib/ripple/conversion.rb +28 -0
  44. data/lib/ripple/core_ext.rb +2 -0
  45. data/lib/ripple/core_ext/casting.rb +148 -0
  46. data/lib/ripple/core_ext/object.rb +8 -0
  47. data/lib/ripple/document.rb +104 -0
  48. data/lib/ripple/document/bucket_access.rb +25 -0
  49. data/lib/ripple/document/finders.rb +131 -0
  50. data/lib/ripple/document/key.rb +43 -0
  51. data/lib/ripple/document/link.rb +30 -0
  52. data/lib/ripple/document/persistence.rb +115 -0
  53. data/lib/ripple/embedded_document.rb +64 -0
  54. data/lib/ripple/embedded_document/around_callbacks.rb +18 -0
  55. data/lib/ripple/embedded_document/finders.rb +26 -0
  56. data/lib/ripple/embedded_document/persistence.rb +77 -0
  57. data/lib/ripple/i18n.rb +2 -0
  58. data/lib/ripple/inspection.rb +32 -0
  59. data/lib/ripple/locale/en.yml +21 -0
  60. data/lib/ripple/nested_attributes.rb +265 -0
  61. data/lib/ripple/observable.rb +28 -0
  62. data/lib/ripple/properties.rb +73 -0
  63. data/lib/ripple/property_type_mismatch.rb +12 -0
  64. data/lib/ripple/railtie.rb +13 -0
  65. data/lib/ripple/serialization.rb +84 -0
  66. data/lib/ripple/timestamps.rb +27 -0
  67. data/lib/ripple/translation.rb +14 -0
  68. data/lib/ripple/validations.rb +67 -0
  69. data/lib/ripple/validations/associated_validator.rb +43 -0
  70. data/ripple.gemspec +46 -0
  71. data/seomoz-ripple.gemspec +46 -0
  72. data/spec/fixtures/config.yml +8 -0
  73. data/spec/integration/ripple/associations_spec.rb +220 -0
  74. data/spec/integration/ripple/conflict_resolution_spec.rb +293 -0
  75. data/spec/integration/ripple/nested_attributes_spec.rb +264 -0
  76. data/spec/integration/ripple/persistence_spec.rb +57 -0
  77. data/spec/integration/ripple/search_associations_spec.rb +42 -0
  78. data/spec/ripple/associations/many_embedded_proxy_spec.rb +122 -0
  79. data/spec/ripple/associations/many_linked_proxy_spec.rb +191 -0
  80. data/spec/ripple/associations/many_reference_proxy_spec.rb +170 -0
  81. data/spec/ripple/associations/many_stored_key_proxy_spec.rb +158 -0
  82. data/spec/ripple/associations/one_embedded_proxy_spec.rb +125 -0
  83. data/spec/ripple/associations/one_key_proxy_spec.rb +82 -0
  84. data/spec/ripple/associations/one_linked_proxy_spec.rb +91 -0
  85. data/spec/ripple/associations/one_stored_key_proxy_spec.rb +72 -0
  86. data/spec/ripple/associations/proxy_spec.rb +84 -0
  87. data/spec/ripple/associations_spec.rb +129 -0
  88. data/spec/ripple/attribute_methods/dirty_spec.rb +80 -0
  89. data/spec/ripple/attribute_methods_spec.rb +230 -0
  90. data/spec/ripple/bucket_access_spec.rb +25 -0
  91. data/spec/ripple/callbacks_spec.rb +176 -0
  92. data/spec/ripple/conflict/resolver_spec.rb +42 -0
  93. data/spec/ripple/conversion_spec.rb +22 -0
  94. data/spec/ripple/core_ext_spec.rb +103 -0
  95. data/spec/ripple/document/link_spec.rb +67 -0
  96. data/spec/ripple/document_spec.rb +96 -0
  97. data/spec/ripple/embedded_document/finders_spec.rb +29 -0
  98. data/spec/ripple/embedded_document/persistence_spec.rb +80 -0
  99. data/spec/ripple/embedded_document_spec.rb +84 -0
  100. data/spec/ripple/finders_spec.rb +217 -0
  101. data/spec/ripple/inspection_spec.rb +51 -0
  102. data/spec/ripple/key_spec.rb +30 -0
  103. data/spec/ripple/observable_spec.rb +121 -0
  104. data/spec/ripple/persistence_spec.rb +326 -0
  105. data/spec/ripple/properties_spec.rb +262 -0
  106. data/spec/ripple/ripple_spec.rb +71 -0
  107. data/spec/ripple/serialization_spec.rb +51 -0
  108. data/spec/ripple/timestamps_spec.rb +76 -0
  109. data/spec/ripple/validations/associated_validator_spec.rb +77 -0
  110. data/spec/ripple/validations_spec.rb +104 -0
  111. data/spec/spec_helper.rb +26 -0
  112. data/spec/support/associations.rb +1 -0
  113. data/spec/support/associations/proxies.rb +17 -0
  114. data/spec/support/integration_setup.rb +11 -0
  115. data/spec/support/mocks.rb +4 -0
  116. data/spec/support/models.rb +4 -0
  117. data/spec/support/models/address.rb +12 -0
  118. data/spec/support/models/box.rb +13 -0
  119. data/spec/support/models/car.rb +16 -0
  120. data/spec/support/models/cardboard_box.rb +3 -0
  121. data/spec/support/models/clock.rb +12 -0
  122. data/spec/support/models/clock_observer.rb +3 -0
  123. data/spec/support/models/company.rb +23 -0
  124. data/spec/support/models/customer.rb +4 -0
  125. data/spec/support/models/driver.rb +6 -0
  126. data/spec/support/models/email.rb +4 -0
  127. data/spec/support/models/engine.rb +5 -0
  128. data/spec/support/models/family.rb +16 -0
  129. data/spec/support/models/favorite.rb +4 -0
  130. data/spec/support/models/invoice.rb +7 -0
  131. data/spec/support/models/late_invoice.rb +3 -0
  132. data/spec/support/models/ninja.rb +9 -0
  133. data/spec/support/models/note.rb +5 -0
  134. data/spec/support/models/page.rb +4 -0
  135. data/spec/support/models/paid_invoice.rb +4 -0
  136. data/spec/support/models/passenger.rb +6 -0
  137. data/spec/support/models/profile.rb +10 -0
  138. data/spec/support/models/seat.rb +5 -0
  139. data/spec/support/models/subscription.rb +27 -0
  140. data/spec/support/models/tasks.rb +14 -0
  141. data/spec/support/models/team.rb +11 -0
  142. data/spec/support/models/transactions.rb +17 -0
  143. data/spec/support/models/tree.rb +4 -0
  144. data/spec/support/models/user.rb +10 -0
  145. data/spec/support/models/wheel.rb +6 -0
  146. data/spec/support/models/widget.rb +22 -0
  147. data/spec/support/test_server.rb +18 -0
  148. data/spec/support/test_server.yml.example +2 -0
  149. metadata +362 -0
@@ -0,0 +1,176 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::Callbacks do
4
+ require 'support/models/box'
5
+
6
+ it "should add create, update, save, and destroy callback declarations" do
7
+ [:save, :create, :update, :destroy].each do |event|
8
+ Box.private_instance_methods.map(&:to_s).should include("_run_#{event}_callbacks")
9
+ [:before, :after, :around].each do |time|
10
+ Box.should respond_to("#{time}_#{event}")
11
+ end
12
+ end
13
+ end
14
+
15
+ it "should validate callback declarations" do
16
+ Box.private_instance_methods.map(&:to_s).should include("_run_validation_callbacks")
17
+ Box.should respond_to("before_validation")
18
+ Box.should respond_to("after_validation")
19
+ end
20
+
21
+ describe "invoking callbacks" do
22
+ before :each do
23
+ response = {:headers => {"content-type" => ["application/json"]}, :body => "{}"}
24
+ @client = Ripple.client
25
+ @backend = mock("Backend", :store_object => true)
26
+ @client.stub!(:backend).and_return(@backend)
27
+ $pinger = mock("callback verifier")
28
+ end
29
+
30
+ it "should call save callbacks on save" do
31
+ Box.before_save { $pinger.ping }
32
+ Box.after_save { $pinger.ping }
33
+ Box.around_save(lambda { $pinger.ping })
34
+ $pinger.should_receive(:ping).exactly(3).times
35
+ @box = Box.new
36
+ @box.save
37
+ end
38
+
39
+ it "propagates callbacks to embedded associated documents" do
40
+ Box.before_save { $pinger.ping }
41
+ BoxSide.before_save { $pinger.ping }
42
+ $pinger.should_receive(:ping).exactly(2).times
43
+ @box = Box.new
44
+ @box.sides << BoxSide.new
45
+ @box.save
46
+ end
47
+
48
+ it 'does not persist the object to riak multiple times when propagating callbacks' do
49
+ Box.before_save { }
50
+ BoxSide.before_save { }
51
+ @box = Box.new
52
+ @box.sides << BoxSide.new << BoxSide.new
53
+
54
+ @box.robject.should_receive(:store).once
55
+ @box.save
56
+ end
57
+
58
+ it 'invokes the before/after callbacks in the correct order on embedded associated documents' do
59
+ callbacks = []
60
+ BoxSide.before_save { callbacks << :before_save }
61
+ BoxSide.after_save { callbacks << :after_save }
62
+
63
+ @box = Box.new
64
+ @box.sides << BoxSide.new
65
+ @box.robject.stub(:store) do
66
+ callbacks << :save
67
+ end
68
+ @box.save
69
+
70
+ callbacks.should == [:before_save, :save, :after_save]
71
+ end
72
+
73
+ it 'does not allow around callbacks on embedded associated documents' do
74
+ expect {
75
+ BoxSide.around_save { }
76
+ }.to raise_error(/around_save callbacks are not supported/)
77
+ end
78
+
79
+ it 'does not propagate validation callbacks multiple times' do
80
+ Box.before_validation { $pinger.ping }
81
+ BoxSide.before_validation { $pinger.ping }
82
+ $pinger.should_receive(:ping).exactly(2).times
83
+ @box = Box.new
84
+ @box.sides << BoxSide.new
85
+ @box.valid?
86
+ end
87
+
88
+ it "should call create callbacks on save when the document is new" do
89
+ Box.before_create { $pinger.ping }
90
+ Box.after_create { $pinger.ping }
91
+ Box.around_create(lambda { $pinger.ping })
92
+ $pinger.should_receive(:ping).exactly(3).times
93
+ @box = Box.new
94
+ @box.save
95
+ end
96
+
97
+ it "should call update callbacks on save when the document is not new" do
98
+ Box.before_update { $pinger.ping }
99
+ Box.after_update { $pinger.ping }
100
+ Box.around_update(lambda { $pinger.ping })
101
+ $pinger.should_receive(:ping).exactly(3).times
102
+ @box = Box.new
103
+ @box.stub!(:new?).and_return(false)
104
+ @box.save
105
+ end
106
+
107
+ it "should call destroy callbacks" do
108
+ Box.before_destroy { $pinger.ping }
109
+ Box.after_destroy { $pinger.ping }
110
+ Box.around_destroy(lambda { $pinger.ping })
111
+ $pinger.should_receive(:ping).exactly(3).times
112
+ @box = Box.new
113
+ @box.destroy
114
+ end
115
+
116
+ it "should call save and validate callbacks in the correct order" do
117
+ Box.before_validation { $pinger.ping(:v) }
118
+ Box.before_save { $pinger.ping(:s) }
119
+ $pinger.should_receive(:ping).with(:v).ordered
120
+ $pinger.should_receive(:ping).with(:s).ordered
121
+ @box = Box.new
122
+ @box.save
123
+ end
124
+
125
+ describe "validation callbacks" do
126
+ it "should call validation callbacks" do
127
+ Box.before_validation { $pinger.ping }
128
+ Box.after_validation { $pinger.ping }
129
+ $pinger.should_receive(:ping).twice
130
+ @box = Box.new
131
+ @box.valid?
132
+ end
133
+
134
+ it "should call validation callbacks only if the document is new" do
135
+ Box.before_validation(:on => :create) { $pinger.ping }
136
+ Box.after_validation(:on => :create) { $pinger.ping }
137
+ $pinger.should_receive(:ping).twice
138
+ @box = Box.new
139
+ @box.valid?
140
+ end
141
+
142
+ it "should not call validation callbacks only if the document is new" do
143
+ Box.before_validation(:on => :update) { $pinger.ping }
144
+ Box.after_validation(:on => :update) { $pinger.ping }
145
+ $pinger.should_not_receive(:ping)
146
+ @box = Box.new
147
+ @box.valid?
148
+ end
149
+
150
+ it "should call validation callbacks only if the document is not new" do
151
+ Box.before_validation(:on => :update) { $pinger.ping }
152
+ Box.after_validation(:on => :update) { $pinger.ping }
153
+ $pinger.should_receive(:ping).twice
154
+ @box = Box.new
155
+ @box.stub(:new?).and_return(false)
156
+ @box.valid?
157
+ end
158
+
159
+ it "should not call validation callbacks only if the document is not new" do
160
+ Box.before_validation(:on => :create) { $pinger.ping }
161
+ Box.after_validation(:on => :create) { $pinger.ping }
162
+ $pinger.should_not_receive(:ping)
163
+ @box = Box.new
164
+ @box.stub!(:new?).and_return(false)
165
+ @box.valid?
166
+ end
167
+ end
168
+
169
+ after :each do
170
+ [:save, :create, :update, :destroy, :validation].each do |type|
171
+ Box.reset_callbacks(type)
172
+ BoxSide.reset_callbacks(type)
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ module Ripple
4
+ module Conflict
5
+ describe Resolver do
6
+ it 'is registered as an on conflict hook with Riak::RObject' do
7
+ Riak::RObject.on_conflict_hooks.should include(described_class.to_proc)
8
+ end
9
+
10
+ describe 'calling the lambda returned by .to_proc' do
11
+ let(:sibling_1) { stub(:data => { '_type' => 'User' } ) }
12
+ let(:sibling_2) { stub(:data => { '_type' => 'User' } ) }
13
+ let(:user_siblings) { [sibling_1, sibling_2] }
14
+ let(:wheel_sibling) { stub(:data => { '_type' => 'Wheel' } ) }
15
+ let(:robject) { stub(:siblings => user_siblings) }
16
+ let(:resolved_robject) { stub("Resolved RObject") }
17
+ let(:resolved_document) { stub(:robject => resolved_robject) }
18
+
19
+ let!(:resolver) { described_class.new(robject, User) }
20
+
21
+ it 'creates a resolver for the appropriate model class, resolves the robject, and returns the resolved robject' do
22
+ described_class.
23
+ should_receive(:new).
24
+ with(robject, User).
25
+ and_return(resolver)
26
+
27
+ resolver.should_receive(:resolve)
28
+ resolver.stub(:document => resolved_document)
29
+
30
+ described_class.to_proc.call(robject).should be(resolved_robject)
31
+ end
32
+
33
+ it 'returns nil and does not attempt resolution when given an robject with siblings of different types' do
34
+ user_siblings << wheel_sibling
35
+ described_class.should_not_receive(:new)
36
+ described_class.to_proc.call(robject).should be_nil
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::Conversion do
4
+ require 'support/models/box'
5
+
6
+ before :each do
7
+ @box = Box.new { |a| a.key = 'some-key' }
8
+ @box.stub!(:new?).and_return(false)
9
+ end
10
+
11
+ it "should return the key as an array for to_key" do
12
+ @box.to_key.should == ['some-key']
13
+ end
14
+
15
+ it "should be able to be converted to a param" do
16
+ @box.to_param.should == 'some-key'
17
+ end
18
+
19
+ it "should be able to be converted to a model" do
20
+ @box.to_model.should == @box
21
+ end
22
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ describe Time do
4
+ before { @date_format = Ripple.date_format }
5
+ after { Ripple.date_format = @date_format }
6
+
7
+ it "serializes to JSON in UTC, ISO 8601 format by default" do
8
+ Time.utc(2010,3,16,12).as_json.should == "2010-03-16T12:00:00Z"
9
+ end
10
+
11
+ it "serializes to JSON in UTC, RFC822 format when specified" do
12
+ Ripple.date_format = :rfc822
13
+ Time.utc(2010,3,16,12).as_json.should == "Tue, 16 Mar 2010 12:00:00 -0000"
14
+ end
15
+ end
16
+
17
+ describe Date do
18
+ before { @date_format = Ripple.date_format }
19
+ after { Ripple.date_format = @date_format }
20
+
21
+ it "serializes to JSON ISO 8601 format by default" do
22
+ Date.civil(2010,3,16).as_json.should == "2010-03-16"
23
+ end
24
+
25
+ it "serializes to JSON in UTC, RFC822 format when specified" do
26
+ Ripple.date_format = :rfc822
27
+ Date.civil(2010,3,16).as_json.should == "16 Mar 2010"
28
+ end
29
+ end
30
+
31
+ describe DateTime do
32
+ before { @date_format = Ripple.date_format }
33
+ after { Ripple.date_format = @date_format }
34
+
35
+ before :each do
36
+ Time.zone = :utc
37
+ end
38
+
39
+ it "serializes to JSON in UTC, ISO 8601 format by default" do
40
+ DateTime.civil(2010,3,16,12).as_json.should == "2010-03-16T12:00:00+00:00"
41
+ end
42
+
43
+ it "serializes to JSON in UTC, RFC822 format when specified" do
44
+ Ripple.date_format = :rfc822
45
+ DateTime.civil(2010,3,16,12).as_json.should == "Tue, 16 Mar 2010 12:00:00 +0000"
46
+ end
47
+ end
48
+
49
+ describe ActiveSupport::TimeWithZone do
50
+ before { @date_format = Ripple.date_format }
51
+ after { Ripple.date_format = @date_format }
52
+
53
+ it "serializes to JSON in UTC, ISO 8601 format by default" do
54
+ time = Time.utc(2010,3,16,12)
55
+ zone = ActiveSupport::TimeZone['Alaska']
56
+ ActiveSupport::TimeWithZone.new(time, zone).as_json.should == "2010-03-16T12:00:00Z"
57
+ end
58
+
59
+ it "serializes to JSON in UTC, RFC822 format when specified" do
60
+ Ripple.date_format = :rfc822
61
+ time = Time.utc(2010,3,16,12)
62
+ zone = ActiveSupport::TimeZone['Alaska']
63
+ ActiveSupport::TimeWithZone.new(time, zone).as_json.should == "Tue, 16 Mar 2010 12:00:00 -0000"
64
+ end
65
+ end
66
+
67
+ describe String do
68
+ it "can parse RFC 822 and ISO 8601 times" do
69
+ 'Tue, 16 Mar 2010 12:00:00 -0000'.to_time.should == Time.utc(2010,3,16,12)
70
+ '2010-03-16T12:00:00Z'.to_time.should == Time.utc(2010,3,16,12)
71
+ end
72
+
73
+ it "can parse RFC 822 and ISO 8601 dates" do
74
+ '16 Mar 2010'.to_date.should == Date.civil(2010,3,16)
75
+ '2010-3-16'.to_date.should == Date.civil(2010,3,16)
76
+ end
77
+
78
+ it "can parse RFC 822 and ISO 8601 datetimes" do
79
+ 'Tue, 16 Mar 2010 12:00:00 +0000'.to_datetime.should == DateTime.civil(2010,3,16,12)
80
+ '2010-03-16T12:00:00+00:00'.to_datetime.should == DateTime.civil(2010,3,16,12)
81
+ end
82
+ end
83
+
84
+ describe "Boolean" do
85
+ it "should be available to properties on documents" do
86
+ lambda {
87
+ class BooleanTest
88
+ include Ripple::Document
89
+ property :foo, Boolean
90
+ end
91
+ }.should_not raise_error(NameError)
92
+ end
93
+ end
94
+
95
+ describe Set do
96
+ describe "#as_json" do
97
+ it 'returns an array of the #as_json result of each element' do
98
+ set = Set.new([stub(:as_json => 's1'), stub(:as_json => 's2')])
99
+ set.as_json.should =~ ['s1', 's2']
100
+ end
101
+ end
102
+ end
103
+
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ module Ripple
4
+ module Document
5
+ describe self do
6
+ describe "#to_link" do
7
+ let(:tag) { 'invoices' }
8
+ let(:document) { Invoice.new }
9
+ let(:to_link) { document.to_link(tag) }
10
+
11
+ it "returns a #{described_class}::Link" do
12
+ to_link.should be_a(Link)
13
+ end
14
+
15
+ it "sets the document to this document" do
16
+ to_link.send(:document).should equal(document)
17
+ end
18
+
19
+ it "sets the tag to the given tag" do
20
+ to_link.tag.should == tag
21
+ end
22
+ end
23
+ end
24
+
25
+ describe Link do
26
+ let(:key) { 'the-invoice-key' }
27
+ let(:tag) { 'invoices' }
28
+ let(:document) { Invoice.new { |i| i.key = key } }
29
+ let(:link) { described_class.new(document, tag) }
30
+
31
+ it 'does not fetch the key immediately' do
32
+ document.should_not_receive(:key)
33
+ link
34
+ end
35
+
36
+ describe '#key' do
37
+ it "returns the document's key" do
38
+ link.key.should == key
39
+ end
40
+ end
41
+
42
+ describe '#bucket' do
43
+ it "returns the bucket name from the document class" do
44
+ link.bucket.should == Invoice.bucket_name
45
+ end
46
+ end
47
+
48
+ describe '#tag' do
49
+ it 'returns the tag passed to the constructor' do
50
+ link.tag.should == tag
51
+ end
52
+ end
53
+
54
+ describe "#hash" do
55
+ it 'does not use the key' do
56
+ document.should_not_receive(:key)
57
+ link.hash
58
+ end
59
+
60
+ it "uses the document's #hash" do
61
+ document.should_receive(:hash).and_return(1234)
62
+ link.hash.should == 1234
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::Document do
4
+ require 'support/models/page'
5
+
6
+ it "should add bucket access methods to classes when included" do
7
+ (class << Page; self; end).included_modules.should include(Ripple::Document::BucketAccess)
8
+ Page.should respond_to(:bucket_name)
9
+ Page.should respond_to(:bucket)
10
+ Page.should respond_to(:bucket_name=)
11
+ end
12
+
13
+ it "should not be embeddable" do
14
+ Page.should_not be_embeddable
15
+ end
16
+
17
+ describe "equivalence" do
18
+ before do
19
+ class Homepage < Page; end
20
+ class ErrorPage; include Ripple::Document; self.bucket_name = "pages"; end
21
+ @doc = Page.new
22
+ @doc2 = Page.new
23
+ @sub = Homepage.new
24
+ @error = ErrorPage.new
25
+ [@doc,@doc2,@sub,@error].each {|d| d.key = "root"; d.stub!(:new?).and_return(false) }
26
+ end
27
+
28
+ it "should be == and eql? if the same object, and have the same hash key" do
29
+ @doc.should == @doc
30
+ @doc.should eql(@doc)
31
+ @doc.hash.should == @doc.hash
32
+ end
33
+
34
+ it "should be == and eql? and have the same hash key if instance of same class and key" do
35
+ @doc.should == @doc2
36
+ @doc2.should == @doc
37
+ @doc.should eql(@doc2)
38
+ @doc2.should eql(@doc)
39
+ @doc.hash.should == @doc2.hash
40
+ end
41
+
42
+ it "should be == but not eql? and have different hash keys if they have the same key but one is a subclass of the other" do
43
+ @doc.should == @sub
44
+ @sub.should == @doc
45
+
46
+ @doc.should_not eql(@sub)
47
+ @sub.should_not eql(@doc)
48
+
49
+ @doc.hash.should_not == @sub.hash
50
+ end
51
+
52
+ it "should be == but not eql? and have different hash keys if of the same bucket and key" do
53
+ @doc.should == @error
54
+ @error.should == @doc
55
+
56
+ @doc.should_not eql(@error)
57
+ @error.should_not eql(@doc)
58
+
59
+ @doc.hash.should_not == @error.hash
60
+ @error.hash.should_not == @doc.hash
61
+ end
62
+
63
+ it "should not be == or eql? or have the same hash key if new record" do
64
+ @doc2.stub!(:new?).and_return(true)
65
+ @doc.should_not == @doc2
66
+ @doc2.should_not == @doc
67
+
68
+ @doc.should_not eql(@doc2)
69
+ @doc2.should_not eql(@doc)
70
+
71
+ @doc.hash.should_not == @doc2.hash
72
+ end
73
+ end
74
+
75
+ describe "ActiveModel compatibility" do
76
+ include ActiveModel::Lint::Tests
77
+
78
+ before :each do
79
+ @model = Page.new
80
+ end
81
+
82
+ def assert(value, message="")
83
+ value.should be
84
+ end
85
+
86
+ def assert_kind_of(klass, value)
87
+ value.should be_kind_of(klass)
88
+ end
89
+
90
+ ActiveModel::Lint::Tests.instance_methods.grep(/^test/).each do |m|
91
+ it "#{m}" do
92
+ send(m)
93
+ end
94
+ end
95
+ end
96
+ end