ripple 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +26 -0
- data/LICENSE +13 -0
- data/README.textile +126 -0
- data/RELEASE_NOTES.textile +24 -0
- data/Rakefile +61 -0
- data/VERSION +1 -0
- data/lib/riak.rb +45 -0
- data/lib/riak/bucket.rb +105 -0
- data/lib/riak/client.rb +138 -0
- data/lib/riak/client/curb_backend.rb +63 -0
- data/lib/riak/client/http_backend.rb +209 -0
- data/lib/riak/client/net_http_backend.rb +49 -0
- data/lib/riak/failed_request.rb +37 -0
- data/lib/riak/i18n.rb +15 -0
- data/lib/riak/invalid_response.rb +25 -0
- data/lib/riak/link.rb +54 -0
- data/lib/riak/locale/en.yml +37 -0
- data/lib/riak/map_reduce.rb +240 -0
- data/lib/riak/map_reduce_error.rb +20 -0
- data/lib/riak/robject.rb +234 -0
- data/lib/riak/util/headers.rb +44 -0
- data/lib/riak/util/multipart.rb +52 -0
- data/lib/riak/util/translation.rb +29 -0
- data/lib/riak/walk_spec.rb +113 -0
- data/lib/ripple.rb +48 -0
- data/lib/ripple/core_ext/casting.rb +96 -0
- data/lib/ripple/document.rb +60 -0
- data/lib/ripple/document/attribute_methods.rb +111 -0
- data/lib/ripple/document/attribute_methods/dirty.rb +52 -0
- data/lib/ripple/document/attribute_methods/query.rb +49 -0
- data/lib/ripple/document/attribute_methods/read.rb +38 -0
- data/lib/ripple/document/attribute_methods/write.rb +36 -0
- data/lib/ripple/document/bucket_access.rb +38 -0
- data/lib/ripple/document/finders.rb +84 -0
- data/lib/ripple/document/persistence.rb +93 -0
- data/lib/ripple/document/persistence/callbacks.rb +48 -0
- data/lib/ripple/document/properties.rb +85 -0
- data/lib/ripple/document/validations.rb +44 -0
- data/lib/ripple/embedded_document.rb +38 -0
- data/lib/ripple/embedded_document/persistence.rb +46 -0
- data/lib/ripple/i18n.rb +15 -0
- data/lib/ripple/locale/en.yml +16 -0
- data/lib/ripple/property_type_mismatch.rb +23 -0
- data/lib/ripple/translation.rb +24 -0
- data/ripple.gemspec +159 -0
- data/spec/fixtures/cat.jpg +0 -0
- data/spec/fixtures/multipart-blank.txt +7 -0
- data/spec/fixtures/multipart-with-body.txt +16 -0
- data/spec/riak/bucket_spec.rb +141 -0
- data/spec/riak/client_spec.rb +169 -0
- data/spec/riak/curb_backend_spec.rb +50 -0
- data/spec/riak/headers_spec.rb +34 -0
- data/spec/riak/http_backend_spec.rb +136 -0
- data/spec/riak/link_spec.rb +50 -0
- data/spec/riak/map_reduce_spec.rb +347 -0
- data/spec/riak/multipart_spec.rb +36 -0
- data/spec/riak/net_http_backend_spec.rb +28 -0
- data/spec/riak/object_spec.rb +444 -0
- data/spec/riak/walk_spec_spec.rb +208 -0
- data/spec/ripple/attribute_methods_spec.rb +149 -0
- data/spec/ripple/bucket_access_spec.rb +48 -0
- data/spec/ripple/callbacks_spec.rb +86 -0
- data/spec/ripple/document_spec.rb +35 -0
- data/spec/ripple/embedded_document_spec.rb +52 -0
- data/spec/ripple/finders_spec.rb +146 -0
- data/spec/ripple/persistence_spec.rb +89 -0
- data/spec/ripple/properties_spec.rb +195 -0
- data/spec/ripple/ripple_spec.rb +43 -0
- data/spec/ripple/validations_spec.rb +64 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/http_backend_implementation_examples.rb +215 -0
- data/spec/support/mock_server.rb +58 -0
- metadata +221 -0
@@ -0,0 +1,149 @@
|
|
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__)
|
15
|
+
|
16
|
+
describe Ripple::Document::AttributeMethods do
|
17
|
+
before :all do
|
18
|
+
class Widget
|
19
|
+
include Ripple::Document
|
20
|
+
property :size, Integer
|
21
|
+
property :name, String, :default => "widget"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
before :each do
|
26
|
+
@widget = Widget.new
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "object key" do
|
30
|
+
it "should provide access to the key" do
|
31
|
+
@widget.should respond_to(:key)
|
32
|
+
@widget.key.should be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should provide a mutator for the key" do
|
36
|
+
@widget.should respond_to(:key=)
|
37
|
+
@widget.key = "cog"
|
38
|
+
@widget.key.should == "cog"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should accept the key in mass assignment" do
|
42
|
+
@widget.attributes = {:key => "cog"}
|
43
|
+
@widget.key.should == "cog"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "accessors" do
|
49
|
+
it "should be defined for defined properties" do
|
50
|
+
@widget.should respond_to(:size)
|
51
|
+
@widget.should respond_to(:name)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should return nil if no default is defined on the property" do
|
55
|
+
@widget.size.should be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should return the property default if defined and not set" do
|
59
|
+
@widget.name.should == "widget"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "mutators" do
|
64
|
+
it "should have mutators for defined properties" do
|
65
|
+
@widget.should respond_to(:size=)
|
66
|
+
@widget.should respond_to(:name=)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should assign the value of the attribute" do
|
70
|
+
@widget.size = 10
|
71
|
+
@widget.size.should == 10
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should type cast assigned values automatically" do
|
75
|
+
@widget.name = :so_what
|
76
|
+
@widget.name.should == "so_what"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should raise an error when assigning a bad value" do
|
80
|
+
lambda { @widget.size = true }.should raise_error(Ripple::PropertyTypeMismatch)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "query methods" do
|
85
|
+
it "should be defined for defined properties" do
|
86
|
+
@widget.should respond_to(:size?)
|
87
|
+
@widget.should respond_to(:name?)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should be false when the attribute is nil" do
|
91
|
+
@widget.size.should be_nil
|
92
|
+
@widget.size?.should be_false
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should be true when the attribute has a value present" do
|
96
|
+
@widget.size = 10
|
97
|
+
@widget.size?.should be_true
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should be false for 0 values" do
|
101
|
+
@widget.size = 0
|
102
|
+
@widget.size?.should be_false
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should be false for empty values" do
|
106
|
+
@widget.name = ""
|
107
|
+
@widget.name?.should be_false
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should track changes to attributes" do
|
112
|
+
@widget.name = "foobar"
|
113
|
+
@widget.changed?.should be_true
|
114
|
+
@widget.name_changed?.should be_true
|
115
|
+
@widget.name_change.should == ["widget", "foobar"]
|
116
|
+
@widget.changes.should == {"name" => ["widget", "foobar"]}
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
it "should refresh the attribute methods when adding a new property" do
|
121
|
+
Widget.should_receive(:undefine_attribute_methods)
|
122
|
+
Widget.property :start_date, Date
|
123
|
+
Widget.properties.delete(:start_date) # cleanup
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should provide a hash representation of all of the attributes" do
|
127
|
+
@widget.attributes.should == {"name" => "widget", "size" => nil}
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should load attributes from mass assignment" do
|
131
|
+
@widget.attributes = {"name" => "Riak", "size" => 100000 }
|
132
|
+
@widget.name.should == "Riak"
|
133
|
+
@widget.size.should == 100000
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should assign attributes on initialization" do
|
137
|
+
@widget = Widget.new(:name => "Riak")
|
138
|
+
@widget.name.should == "Riak"
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should have no changed attributes after initialization" do
|
142
|
+
@widget = Widget.new(:name => "Riak")
|
143
|
+
@widget.changes.should be_blank
|
144
|
+
end
|
145
|
+
|
146
|
+
after :all do
|
147
|
+
Object.send(:remove_const, :Widget)
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,48 @@
|
|
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.dirname(__FILE__))
|
15
|
+
|
16
|
+
describe Ripple::Document::BucketAccess do
|
17
|
+
before :all do
|
18
|
+
class Invoice; include Ripple::Document; end
|
19
|
+
class LateInvoice < Invoice; end
|
20
|
+
class PaidInvoice < Invoice; self.bucket_name = "paid"; end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should use the plural model name as the bucket name" do
|
24
|
+
Invoice.bucket_name.should == "invoices"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should use the parent bucket name by default (SBI)" do
|
28
|
+
LateInvoice.bucket_name.should == "invoices"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should allow a class to set the bucket name" do
|
32
|
+
PaidInvoice.bucket_name.should == "paid"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should allow access to the bucket" do
|
36
|
+
bucket = Riak::Bucket.new(Ripple.client, "invoices")
|
37
|
+
Ripple.client.should_receive(:[]).with("invoices", {:keys => false}).and_return(bucket)
|
38
|
+
Invoice.bucket.should == bucket
|
39
|
+
end
|
40
|
+
|
41
|
+
after :all do
|
42
|
+
Object.module_eval do
|
43
|
+
remove_const(:PaidInvoice)
|
44
|
+
remove_const(:LateInvoice)
|
45
|
+
remove_const(:Invoice)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,86 @@
|
|
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__)
|
15
|
+
|
16
|
+
describe Ripple::Document::Persistence::Callbacks do
|
17
|
+
before :all do
|
18
|
+
class Box; include Ripple::Document; property :shape, String end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should add create, update, save, and destroy callback declarations" do
|
22
|
+
[:save, :create, :update, :destroy].each do |event|
|
23
|
+
Box.private_instance_methods.should include("_run_#{event}_callbacks")
|
24
|
+
[:before, :after, :around].each do |time|
|
25
|
+
Box.should respond_to("#{time}_#{event}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "invoking callbacks" do
|
31
|
+
before :each do
|
32
|
+
response = {:headers => {"content-type" => ["application/json"]}, :body => "{}"}
|
33
|
+
@client = Ripple.client
|
34
|
+
@http = mock("HTTP Backend", :get => response, :put => response, :post => response, :delete => response)
|
35
|
+
@client.stub!(:http).and_return(@http)
|
36
|
+
$pinger = mock("callback verifier")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should call save callbacks on save" do
|
40
|
+
Box.before_save { $pinger.ping }
|
41
|
+
Box.after_save { $pinger.ping }
|
42
|
+
Box.around_save(lambda { $pinger.ping })
|
43
|
+
$pinger.should_receive(:ping).exactly(3).times
|
44
|
+
@box = Box.new
|
45
|
+
@box.save
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should call create callbacks on save when the document is new" do
|
49
|
+
Box.before_create { $pinger.ping }
|
50
|
+
Box.after_create { $pinger.ping }
|
51
|
+
Box.around_create(lambda { $pinger.ping })
|
52
|
+
$pinger.should_receive(:ping).exactly(3).times
|
53
|
+
@box = Box.new
|
54
|
+
@box.save
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should call update callbacks on save when the document is not new" do
|
58
|
+
Box.before_update { $pinger.ping }
|
59
|
+
Box.after_update { $pinger.ping }
|
60
|
+
Box.around_update(lambda { $pinger.ping })
|
61
|
+
$pinger.should_receive(:ping).exactly(3).times
|
62
|
+
@box = Box.new
|
63
|
+
@box.stub!(:new?).and_return(false)
|
64
|
+
@box.save
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should call destroy callbacks" do
|
68
|
+
Box.before_destroy { $pinger.ping }
|
69
|
+
Box.after_destroy { $pinger.ping }
|
70
|
+
Box.around_destroy(lambda { $pinger.ping })
|
71
|
+
$pinger.should_receive(:ping).exactly(3).times
|
72
|
+
@box = Box.new
|
73
|
+
@box.destroy
|
74
|
+
end
|
75
|
+
|
76
|
+
after :each do
|
77
|
+
[:save, :create, :update, :destroy].each do |type|
|
78
|
+
Box.reset_callbacks(type)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
after :all do
|
84
|
+
Object.send(:remove_const, :Box)
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,35 @@
|
|
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.dirname(__FILE__))
|
15
|
+
|
16
|
+
describe Ripple::Document do
|
17
|
+
before :all do
|
18
|
+
class Page; include Ripple::Document; end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should add bucket access methods to classes when included" do
|
22
|
+
Page.metaclass.included_modules.should include(Ripple::Document::BucketAccess)
|
23
|
+
Page.should respond_to(:bucket_name)
|
24
|
+
Page.should respond_to(:bucket)
|
25
|
+
Page.should respond_to(:bucket_name=)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not be embeddable" do
|
29
|
+
Page.should_not be_embeddable
|
30
|
+
end
|
31
|
+
|
32
|
+
after :all do
|
33
|
+
Object.module_eval { remove_const(:Page) }
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,52 @@
|
|
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__)
|
15
|
+
|
16
|
+
describe Ripple::EmbeddedDocument do
|
17
|
+
before :all do
|
18
|
+
class Address; include Ripple::EmbeddedDocument; end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should have a model name when included" do
|
22
|
+
Address.should respond_to(:model_name)
|
23
|
+
Address.model_name.should be_kind_of(ActiveModel::Name)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should be embeddable" do
|
27
|
+
Address.should be_embeddable
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "persistence" do
|
31
|
+
before :each do
|
32
|
+
@root = mock("root document")
|
33
|
+
@root.stub!(:new?).and_return(true)
|
34
|
+
@addr = Address.new
|
35
|
+
@addr._root_document = @root
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should delegate new? to the root document" do
|
39
|
+
@root.should_receive(:new?).and_return(true)
|
40
|
+
@addr.should be_new
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should delegate save to the root document" do
|
44
|
+
@root.should_receive(:save).and_return(true)
|
45
|
+
@addr.save.should be_true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
after :all do
|
50
|
+
Object.send(:remove_const, :Address)
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,146 @@
|
|
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__)
|
15
|
+
|
16
|
+
describe Ripple::Document::Finders do
|
17
|
+
before :all do
|
18
|
+
class Box
|
19
|
+
include Ripple::Document
|
20
|
+
property :shape, String
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
before :each do
|
25
|
+
@http = mock("HTTP Backend")
|
26
|
+
@client = Ripple.client
|
27
|
+
@client.stub!(:http).and_return(@http)
|
28
|
+
@bucket = Riak::Bucket.new(@client, "boxes")
|
29
|
+
@client.stub!(:[]).and_return(@bucket)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return an empty array if no keys are passed to find" do
|
33
|
+
Box.find().should == []
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "finding single documents" do
|
37
|
+
it "should find a single document by key and assign its attributes" do
|
38
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "square", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"square"}'})
|
39
|
+
box = Box.find("square")
|
40
|
+
box.should be_kind_of(Box)
|
41
|
+
box.shape.should == "square"
|
42
|
+
box.key.should == "square"
|
43
|
+
box.instance_variable_get(:@robject).should_not be_nil
|
44
|
+
box.should_not be_new_record
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should return nil when no object exists at that key" do
|
48
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "square", {}, {}).and_raise(Riak::FailedRequest.new(:get, 200, 404, {}, "404 not found"))
|
49
|
+
box = Box.find("square")
|
50
|
+
box.should be_nil
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should re-raise the failed request exception if not a 404" do
|
54
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "square", {}, {}).and_raise(Riak::FailedRequest.new(:get, 200, 500, {}, "500 internal server error"))
|
55
|
+
lambda { Box.find("square") }.should raise_error(Riak::FailedRequest)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "finding multiple documents" do
|
60
|
+
it "should find multiple documents by the keys" do
|
61
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "square", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"square"}'})
|
62
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "rectangle", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"rectangle"}'})
|
63
|
+
boxes = Box.find("square", "rectangle")
|
64
|
+
boxes.should have(2).items
|
65
|
+
boxes.first.shape.should == "square"
|
66
|
+
boxes.last.shape.should == "rectangle"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should return nil for documents that no longer exist" do
|
70
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "square", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"square"}'})
|
71
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "rectangle", {}, {}).and_raise(Riak::FailedRequest.new(:get, 200, 404, {}, "404 not found"))
|
72
|
+
boxes = Box.find("square", "rectangle")
|
73
|
+
boxes.should have(2).items
|
74
|
+
boxes.first.shape.should == "square"
|
75
|
+
boxes.last.should be_nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "finding all documents in the bucket" do
|
80
|
+
it "should load all objects in the bucket" do
|
81
|
+
@bucket.should_receive(:keys).and_return(["square", "rectangle"])
|
82
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "square", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"square"}'})
|
83
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "rectangle", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"rectangle"}'})
|
84
|
+
boxes = Box.all
|
85
|
+
boxes.should have(2).items
|
86
|
+
boxes.first.shape.should == "square"
|
87
|
+
boxes.last.shape.should == "rectangle"
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should exclude objects that are not found" do
|
91
|
+
@bucket.should_receive(:keys).and_return(["square", "rectangle"])
|
92
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "square", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"square"}'})
|
93
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "rectangle", {}, {}).and_raise(Riak::FailedRequest.new(:get, 200, 404, {}, "404 not found"))
|
94
|
+
boxes = Box.all
|
95
|
+
boxes.should have(1).item
|
96
|
+
boxes.first.shape.should == "square"
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should yield found objects to the passed block and return an empty array" do
|
100
|
+
@bucket.should_receive(:keys).and_yield("square").and_yield("rectangle")
|
101
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "square", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"square"}'})
|
102
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "rectangle", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"rectangle"}'})
|
103
|
+
@block = mock()
|
104
|
+
@block.should_receive(:ping).twice
|
105
|
+
Box.all do |box|
|
106
|
+
@block.ping
|
107
|
+
["square", "rectangle"].should include(box.shape)
|
108
|
+
end.should == []
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should yield found objects to the passed block, excluding missing objects, and return an empty array" do
|
112
|
+
@bucket.should_receive(:keys).and_yield("square").and_yield("rectangle")
|
113
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "square", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"square"}'})
|
114
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "rectangle", {}, {}).and_raise(Riak::FailedRequest.new(:get, 200, 404, {}, "404 not found"))
|
115
|
+
@block = mock()
|
116
|
+
@block.should_receive(:ping).once
|
117
|
+
Box.all do |box|
|
118
|
+
@block.ping
|
119
|
+
["square", "rectangle"].should include(box.shape)
|
120
|
+
end.should == []
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "single-bucket inheritance" do
|
125
|
+
before :all do
|
126
|
+
class CardboardBox < Box; end
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should instantiate as the proper type if defined in the document" do
|
130
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "square", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"square"}'})
|
131
|
+
@http.should_receive(:get).with(200, "/raw/", "boxes", "rectangle", {}, {}).and_return({:code => 200, :headers => {"content-type" => ["application/json"]}, :body => '{"shape":"rectangle", "_type":"CardboardBox"}'})
|
132
|
+
boxes = Box.find("square", "rectangle")
|
133
|
+
boxes.should have(2).items
|
134
|
+
boxes.first.should_not be_kind_of(CardboardBox)
|
135
|
+
boxes.last.should be_kind_of(CardboardBox)
|
136
|
+
end
|
137
|
+
|
138
|
+
after :all do
|
139
|
+
Object.send(:remove_const, :CardboardBox)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
after :all do
|
144
|
+
Object.send(:remove_const, :Box)
|
145
|
+
end
|
146
|
+
end
|