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,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::EmbeddedDocument::Finders do
4
+ require 'support/models/address'
5
+ require 'support/models/favorite'
6
+
7
+ before :each do
8
+ @address = Address.new
9
+ end
10
+
11
+ it "should instantiate a document" do
12
+ Address.stub!(:new).and_return(@address)
13
+ Address.instantiate('_type' => 'Address').should == @address
14
+ end
15
+
16
+ it "should instantiate a class of _type if present in attrs" do
17
+ Favorite.instantiate('_type' => 'Address').class.should == Address
18
+ end
19
+
20
+ it "should use self if being called from a class including Ripple::EmbeddedDocument and _type is not present" do
21
+ Address.instantiate({}).class.should == Address
22
+ end
23
+
24
+ it 'initializes the document with no changes' do
25
+ a = Address.instantiate('_type' => 'Address', 'street' => 'Pine St')
26
+ a.should_not be_changed
27
+ a.changes.should be_empty
28
+ end
29
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::EmbeddedDocument::Persistence do
4
+ require 'support/models/user'
5
+ require 'support/models/address'
6
+
7
+ before :each do
8
+ @root = User.new
9
+ @addr = Address.new(:street => "196 Broadway")
10
+ @addr._parent_document = @root
11
+ end
12
+
13
+ it "should delegate new? to the root document" do
14
+ @root.should_receive(:new?).and_return(true)
15
+ @addr.should be_new
16
+ end
17
+
18
+ it "should delegate save to the root document" do
19
+ @root.should_receive(:save).and_return(true)
20
+ @addr.save.should be_true
21
+ end
22
+
23
+ it "should delegate save! to the root document" do
24
+ @root.should_receive(:save).and_return(true)
25
+ @addr.save!.should be_true
26
+ end
27
+
28
+ it "should raise NoRootDocument when calling save without a root document" do
29
+ @addr._parent_document = nil
30
+ lambda { @addr.save }.should raise_error(Ripple::NoRootDocument)
31
+ end
32
+
33
+ it "should raise NoRootDocument when calling save! without a root document" do
34
+ @addr._parent_document = nil
35
+ lambda { @addr.save! }.should raise_error(Ripple::NoRootDocument)
36
+ end
37
+
38
+ it "should have a root document" do
39
+ @addr._root_document.should == @root
40
+ end
41
+
42
+ it "should have a parent document" do
43
+ @addr._parent_document.should == @root
44
+ end
45
+
46
+ it "should respond to new_record?" do
47
+ @addr.should respond_to(:new_record?)
48
+ @addr.should be_a_new_record
49
+ end
50
+
51
+ it "should respond to persisted" do
52
+ @addr.should respond_to(:persisted?)
53
+ @addr.should_not be_persisted
54
+ end
55
+
56
+ it "should properly create embedded attributes for persistence" do
57
+ @addr = Address.new
58
+ @root.addresses << @addr
59
+ @root.attributes_for_persistence.should == {'_type' => 'User', 'addresses' => [{'_type' => 'Address', 'street' => nil}]}
60
+ end
61
+
62
+ it "includes undefined properties in the attributes for persistence" do
63
+ addr = Address.new
64
+ addr['some_undefined_prop'] = 17
65
+ @root.addresses << addr
66
+ @root.attributes_for_persistence['addresses'].first.should include('some_undefined_prop' => 17)
67
+ end
68
+
69
+ it "should modify its attributes and save" do
70
+ @addr.should_receive(:save).and_return(true)
71
+ @addr.update_attributes(:street => "4 Folsom Ave")
72
+ @addr.street.should == "4 Folsom Ave"
73
+ end
74
+
75
+ it "should update a single attribute and save without validations" do
76
+ @addr.should_receive(:save).with(:validate => false).and_return(true)
77
+ @addr.update_attribute(:street, "4 Folsom Ave")
78
+ @addr.street.should == "4 Folsom Ave"
79
+ end
80
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::EmbeddedDocument do
4
+ require 'support/models/address'
5
+ require 'support/models/user'
6
+
7
+ it "should have a model name when included" do
8
+ Address.should respond_to(:model_name)
9
+ Address.model_name.should be_kind_of(ActiveModel::Name)
10
+ end
11
+
12
+ it "should be embeddable" do
13
+ Address.should be_embeddable
14
+ end
15
+
16
+ describe "equality" do
17
+ let(:user_1) { User.new {|u| u.key = "u1"} }
18
+ let(:user_2) { User.new {|u| u.key = "u2"} }
19
+ let(:street_1) { '123 Somewhere St' }
20
+ let(:street_2) { '123 Somewhere Ave' }
21
+ let(:address_1) { Address.new(:street => street_1) }
22
+ let(:address_2) { Address.new(:street => street_1) }
23
+
24
+ before(:each) do
25
+ address_1._parent_document = user_1
26
+ address_2._parent_document = user_1
27
+ end
28
+
29
+ def should_be_equal
30
+ (address_1 == address_2).should be_true
31
+ address_1.eql?(address_2).should be_true
32
+
33
+ (address_2 == address_1).should be_true
34
+ address_2.eql?(address_1).should be_true
35
+
36
+ address_1.hash.should == address_2.hash
37
+ end
38
+
39
+ def should_not_be_equal(other_address = address_2)
40
+ (address_1 == other_address).should be_false
41
+ address_1.eql?(other_address).should be_false
42
+
43
+ (other_address == address_1).should be_false
44
+ address_1.eql?(other_address).should be_false
45
+
46
+ address_1.hash.should_not == other_address.hash
47
+ end
48
+
49
+ specify "two document are equal when they have the same classes, parents and attributes" do
50
+ should_be_equal
51
+ end
52
+
53
+ specify "two documents are not equal when the parents are different (even if the attributes and classes are the same)" do
54
+ address_2._parent_document = user_2
55
+ should_not_be_equal
56
+ end
57
+
58
+ specify "two documents are not equal when the attributes are different (even if the parents and classes are the same)" do
59
+ address_2.street = street_2
60
+ should_not_be_equal
61
+ end
62
+
63
+ specify "two documents are not equal when the classes are different (even if the parents and attributes are the same)" do
64
+ special_address = SpecialAddress.new(address_1.attributes)
65
+ special_address._parent_document = address_1._parent_document
66
+
67
+ should_not_be_equal(special_address)
68
+ end
69
+
70
+ specify "two documents are not equal when their embedded documents are not equal (even if they are identical otherwise)" do
71
+ address_1.notes << Note.new(:text => 'Bob lives here')
72
+ address_2.notes << Note.new(:text => 'Jill lives here')
73
+
74
+ should_not_be_equal
75
+ end
76
+
77
+ specify "two documents can be equal when their embedded doc objects are different instances but are equal" do
78
+ address_1.notes << Note.new(:text => 'Bob lives here')
79
+ address_2.notes << Note.new(:text => 'Bob lives here')
80
+
81
+ should_be_equal
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,217 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::Document::Finders do
4
+ require 'support/models/box'
5
+ require 'support/models/cardboard_box'
6
+
7
+ before :each do
8
+ @backend = mock("Backend")
9
+ @client = Ripple.client
10
+ @client.stub!(:backend).and_return(@backend)
11
+ @bucket = Ripple.client.bucket("boxes")
12
+ @plain = Riak::RObject.new(@bucket, "square"){|o| o.content_type = "application/json"; o.raw_data = '{"shape":"square"}'}
13
+ @cb = Riak::RObject.new(@bucket, "rectangle"){|o| o.content_type = "application/json"; o.raw_data = '{"shape":"rectangle"}'}
14
+ end
15
+
16
+ it "should return nil if no keys are passed to find" do
17
+ Box.find().should be_nil
18
+ end
19
+
20
+ it "should return nil if no valid keys are passed to find" do
21
+ Box.find(nil).should be_nil
22
+ Box.find("").should be_nil
23
+ end
24
+
25
+ it "should raise Ripple::DocumentNotFound if an empty array is passed to find!" do
26
+ lambda { Box.find!() }.should raise_error(Ripple::DocumentNotFound, "Couldn't find document without a key")
27
+ end
28
+
29
+ describe "finding single documents" do
30
+ before do
31
+ @bucket.stub!(:get).with("square", {}).and_return(@plain)
32
+ end
33
+
34
+ it "should find a single document by key and assign its attributes" do
35
+ @bucket.should_receive(:get).with("square", {}).and_return(@plain)
36
+ box = Box.find("square")
37
+ box.should be_kind_of(Box)
38
+ box.shape.should == "square"
39
+ box.key.should == "square"
40
+ box.instance_variable_get(:@robject).should_not be_nil
41
+ box.should_not be_new_record
42
+ end
43
+
44
+ it "should find the first document using the first key with the bucket's keys" do
45
+ box = Box.new
46
+ keys = ['some_boxes_key']
47
+ Box.stub!(:find).and_return(box)
48
+ @bucket.stub!(:keys).and_return(keys)
49
+ @bucket.should_receive(:keys)
50
+ keys.should_receive(:first)
51
+ Box.first.should == box
52
+ end
53
+
54
+ it "should use find! when using first!" do
55
+ box = Box.new
56
+ Box.stub!(:find!).and_return(box)
57
+ @bucket.stub!(:keys).and_return(['key'])
58
+ Box.first!.should == box
59
+ end
60
+
61
+ it "should not raise an exception when finding an existing document with find!" do
62
+ lambda { Box.find!("square") }.should_not raise_error(Ripple::DocumentNotFound)
63
+ end
64
+
65
+ it "should put properties we don't know about into the attributes" do
66
+ @plain.raw_data = '{"non_existent_property":"some_value"}'
67
+ box = Box.find("square")
68
+ box[:non_existent_property].should == "some_value"
69
+ box.should_not respond_to(:non_existent_property)
70
+ end
71
+
72
+ it "should return the document when calling find!" do
73
+ box = Box.find!("square")
74
+ box.should be_kind_of(Box)
75
+ end
76
+
77
+ it "should return nil when no object exists at that key" do
78
+ @bucket.should_receive(:get).with("square", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "404 not found"))
79
+ box = Box.find("square")
80
+ box.should be_nil
81
+ end
82
+
83
+ it "should raise DocumentNotFound when using find! if no object exists at that key" do
84
+ @bucket.should_receive(:get).with("square", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "404 not found"))
85
+ lambda { Box.find!("square") }.should raise_error(Ripple::DocumentNotFound, "Couldn't find document with key: square")
86
+ end
87
+
88
+ it "should re-raise the failed request exception if not a 404" do
89
+ @bucket.should_receive(:get).with("square", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 500, {}, "500 internal server error"))
90
+ lambda { Box.find("square") }.should raise_error(Riak::FailedRequest)
91
+ end
92
+
93
+ it "should handle a key with a nil value" do
94
+ @plain.raw_data = nil
95
+ @plain.data = nil
96
+ box = Box.find("square")
97
+ box.should be_kind_of(Box)
98
+ box.key.should == "square"
99
+ end
100
+
101
+ it 'initializes the document with no changed attributes' do
102
+ box = Box.find("square")
103
+ box.should_not be_changed
104
+ box.changes.should be_empty
105
+ end
106
+ end
107
+
108
+ describe "finding multiple documents when given a splat of keys" do
109
+ it "should find multiple documents by the keys" do
110
+ @bucket.should_receive(:get).with("square", {}).and_return(@plain)
111
+ @bucket.should_receive(:get).with("rectangle", {}).and_return(@cb)
112
+ boxes = Box.find("square", "rectangle")
113
+ boxes.should have(2).items
114
+ boxes.first.shape.should == "square"
115
+ boxes.last.shape.should == "rectangle"
116
+ end
117
+
118
+ describe "when using find with missing keys" do
119
+ before :each do
120
+ @bucket.should_receive(:get).with("square", {}).and_return(@plain)
121
+ @bucket.should_receive(:get).with("rectangle", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "404 not found"))
122
+ end
123
+
124
+ it "should return nil for documents that no longer exist" do
125
+ boxes = Box.find("square", "rectangle")
126
+ boxes.should have(2).items
127
+ boxes.first.shape.should == "square"
128
+ boxes.last.should be_nil
129
+ end
130
+
131
+ it "should raise Ripple::DocumentNotFound when calling find! if some of the documents do not exist" do
132
+ lambda { Box.find!("square", "rectangle") }.should raise_error(Ripple::DocumentNotFound, "Couldn't find documents with keys: rectangle")
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "finding multiple documents when given an array" do
138
+ it "should find multiple documents by the keys" do
139
+ @bucket.should_receive(:get).with("square", {}).and_return(@plain)
140
+ @bucket.should_receive(:get).with("rectangle", {}).and_return(@cb)
141
+ boxes = Box.find(["square", "rectangle"])
142
+ boxes.should have(2).items
143
+ boxes.first.shape.should == "square"
144
+ boxes.last.shape.should == "rectangle"
145
+ end
146
+
147
+ it "should return an array of docs when given an array of one key" do
148
+ @bucket.should_receive(:get).with("square", {}).and_return(@plain)
149
+ boxes = Box.find(["square"])
150
+ boxes.should have(1).items
151
+ boxes.first.shape.should == "square"
152
+ end
153
+
154
+ it "should return an empty array when given an empty array" do
155
+ Box.find([ ]).should == []
156
+ end
157
+
158
+ describe "when using find with missing keys" do
159
+ before :each do
160
+ @bucket.should_receive(:get).with("square", {}).and_return(@plain)
161
+ @bucket.should_receive(:get).with("rectangle", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "404 not found"))
162
+ end
163
+
164
+ it "should return nil for documents that no longer exist" do
165
+ boxes = Box.find(["square", "rectangle"])
166
+ boxes.should have(2).items
167
+ boxes.first.shape.should == "square"
168
+ boxes.last.should be_nil
169
+ end
170
+ end
171
+ end
172
+
173
+ describe "listings all documents in the bucket" do
174
+ it "should load all objects in the bucket" do
175
+ @bucket.should_receive(:keys).and_return(["square", "rectangle"])
176
+ @bucket.should_receive(:get).with("square", {}).and_return(@plain)
177
+ @bucket.should_receive(:get).with("rectangle", {}).and_return(@cb)
178
+ boxes = Box.list
179
+ boxes.should have(2).items
180
+ boxes.first.shape.should == "square"
181
+ boxes.last.shape.should == "rectangle"
182
+ end
183
+
184
+ it "should exclude objects that are not found" do
185
+ @bucket.should_receive(:keys).and_return(["square", "rectangle"])
186
+ @bucket.should_receive(:get).with("square", {}).and_return(@plain)
187
+ @bucket.should_receive(:get).with("rectangle", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "404 not found"))
188
+ boxes = Box.list
189
+ boxes.should have(1).item
190
+ boxes.first.shape.should == "square"
191
+ end
192
+
193
+ it "should yield found objects to the passed block, excluding missing objects, and return an empty array" do
194
+ @bucket.should_receive(:keys).and_yield(["square"]).and_yield(["rectangle"])
195
+ @bucket.should_receive(:get).with("square", {}).and_return(@plain)
196
+ @bucket.should_receive(:get).with("rectangle", {}).and_raise(Riak::HTTPFailedRequest.new(:get, 200, 404, {}, "404 not found"))
197
+ @block = mock()
198
+ @block.should_receive(:ping).once
199
+ Box.list do |box|
200
+ @block.ping
201
+ ["square", "rectangle"].should include(box.shape)
202
+ end.should == []
203
+ end
204
+ end
205
+
206
+ describe "single-bucket inheritance" do
207
+ it "should instantiate as the proper type if defined in the document" do
208
+ @cb.raw_data = '{"shape":"rectangle", "_type":"CardboardBox"}'
209
+ @bucket.should_receive(:get).with("square", {}).and_return(@plain)
210
+ @bucket.should_receive(:get).with("rectangle", {}).and_return(@cb)
211
+ boxes = Box.find("square", "rectangle")
212
+ boxes.should have(2).items
213
+ boxes.first.class.should == Box
214
+ boxes.last.should be_kind_of(CardboardBox)
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::Inspection do
4
+ require 'support/models/box'
5
+ require 'support/models/address'
6
+
7
+ shared_examples_for 'an inspected document' do |method|
8
+
9
+ it "should include the class name in the inspect string" do
10
+ @box.send(method).should be_starts_with("<Box")
11
+ end
12
+
13
+ it "should include the key in the #{method} string for documents" do
14
+ @box.key = "square"
15
+ @box.send(method).should be_starts_with("<Box:square")
16
+ end
17
+
18
+ it "should indicate a new document when no key is specified" do
19
+ @box.send(method).should be_starts_with("<Box:[new]")
20
+ end
21
+
22
+ it "should not display a key for embedded documents" do
23
+ @address.send(method).should_not include("[new]")
24
+ end
25
+
26
+ end
27
+
28
+ before :each do
29
+ @box = Box.new
30
+ @address = Address.new
31
+ end
32
+
33
+ describe '#inspect' do
34
+
35
+ it_should_behave_like 'an inspected document', :inspect
36
+
37
+ it "should enumerate the document's properties and their values" do
38
+ @box.shape = "square"
39
+ @box.inspect.should include("shape=\"square\"")
40
+ @box.inspect.should include("created_at=")
41
+ @box.inspect.should include("updated_at=")
42
+ end
43
+
44
+ end
45
+
46
+ describe '#to_s' do
47
+
48
+ it_should_behave_like 'an inspected document', :to_s
49
+
50
+ end
51
+ end