ripple 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. data/Rakefile +61 -48
  2. data/lib/ripple.rb +5 -1
  3. data/lib/ripple/core_ext/casting.rb +3 -0
  4. data/lib/ripple/document.rb +6 -2
  5. data/lib/ripple/document/associations.rb +154 -0
  6. data/lib/ripple/document/{persistence/callbacks.rb → associations/embedded.rb} +20 -24
  7. data/lib/ripple/document/associations/instantiators.rb +41 -0
  8. data/lib/{riak/util/translation.rb → ripple/document/associations/linked.rb} +14 -11
  9. data/lib/ripple/document/associations/many.rb +52 -0
  10. data/lib/ripple/document/associations/many_embedded_proxy.rb +49 -0
  11. data/lib/{riak/i18n.rb → ripple/document/associations/one.rb} +18 -2
  12. data/lib/ripple/document/associations/one_embedded_proxy.rb +41 -0
  13. data/lib/ripple/document/associations/proxy.rb +125 -0
  14. data/lib/ripple/document/attribute_methods.rb +8 -1
  15. data/lib/ripple/document/attribute_methods/read.rb +4 -0
  16. data/lib/ripple/document/attribute_methods/write.rb +4 -0
  17. data/lib/ripple/document/bucket_access.rb +1 -1
  18. data/lib/ripple/document/callbacks.rb +75 -0
  19. data/lib/ripple/document/finders.rb +50 -3
  20. data/lib/ripple/document/persistence.rb +14 -6
  21. data/lib/ripple/document/validations.rb +35 -7
  22. data/lib/ripple/document/validations/associated_validator.rb +37 -0
  23. data/lib/ripple/embedded_document.rb +8 -2
  24. data/lib/{riak/map_reduce_error.rb → ripple/embedded_document/conversion.rb} +19 -5
  25. data/lib/{riak/invalid_response.rb → ripple/embedded_document/finders.rb} +17 -8
  26. data/lib/ripple/embedded_document/persistence.rb +75 -13
  27. data/lib/ripple/locale/en.yml +7 -1
  28. data/{spec/riak/net_http_backend_spec.rb → lib/ripple/railtie.rb} +17 -13
  29. data/spec/fixtures/config.yml +3 -0
  30. data/spec/integration/ripple/associations_spec.rb +81 -0
  31. data/spec/integration/ripple/persistence_spec.rb +54 -0
  32. data/spec/ripple/associations/many_embedded_proxy_spec.rb +124 -0
  33. data/spec/ripple/associations/one_embedded_proxy_spec.rb +130 -0
  34. data/spec/ripple/associations/proxy_spec.rb +78 -0
  35. data/spec/ripple/associations_spec.rb +111 -0
  36. data/spec/ripple/attribute_methods_spec.rb +37 -16
  37. data/spec/ripple/bucket_access_spec.rb +3 -14
  38. data/spec/ripple/callbacks_spec.rb +53 -9
  39. data/spec/ripple/document_spec.rb +22 -6
  40. data/spec/ripple/embedded_document/conversion_spec.rb +35 -0
  41. data/spec/{riak/headers_spec.rb → ripple/embedded_document/finders_spec.rb} +17 -14
  42. data/spec/ripple/embedded_document/persistence_spec.rb +86 -0
  43. data/spec/ripple/embedded_document_spec.rb +1 -26
  44. data/spec/ripple/finders_spec.rb +66 -30
  45. data/spec/ripple/persistence_spec.rb +33 -21
  46. data/spec/ripple/properties_spec.rb +1 -7
  47. data/spec/ripple/ripple_spec.rb +10 -0
  48. data/spec/ripple/timestamps_spec.rb +12 -19
  49. data/spec/ripple/validations_spec.rb +48 -6
  50. data/spec/spec_helper.rb +4 -10
  51. data/spec/support/associations/proxies.rb +16 -0
  52. data/spec/support/integration.rb +4 -0
  53. data/spec/support/mocks.rb +3 -0
  54. data/spec/support/models/address.rb +8 -0
  55. data/spec/support/models/box.rb +6 -0
  56. data/spec/support/models/cardboard_box.rb +3 -0
  57. data/spec/support/models/clock.rb +6 -0
  58. data/spec/support/models/customer.rb +4 -0
  59. data/spec/support/models/email.rb +4 -0
  60. data/spec/support/models/family.rb +14 -0
  61. data/spec/support/models/favorite.rb +4 -0
  62. data/spec/support/models/invoice.rb +6 -0
  63. data/spec/support/models/late_invoice.rb +3 -0
  64. data/spec/support/models/note.rb +4 -0
  65. data/spec/support/models/page.rb +4 -0
  66. data/spec/support/models/paid_invoice.rb +4 -0
  67. data/spec/support/models/tree.rb +3 -0
  68. data/spec/support/models/user.rb +6 -0
  69. data/spec/support/models/widget.rb +6 -0
  70. metadata +111 -138
  71. data/.document +0 -5
  72. data/.gitignore +0 -26
  73. data/CONTRIBUTORS.textile +0 -5
  74. data/LICENSE +0 -13
  75. data/README.textile +0 -128
  76. data/RELEASE_NOTES.textile +0 -68
  77. data/VERSION +0 -1
  78. data/lib/riak.rb +0 -46
  79. data/lib/riak/bucket.rb +0 -157
  80. data/lib/riak/client.rb +0 -139
  81. data/lib/riak/client/curb_backend.rb +0 -82
  82. data/lib/riak/client/http_backend.rb +0 -209
  83. data/lib/riak/client/net_http_backend.rb +0 -49
  84. data/lib/riak/failed_request.rb +0 -37
  85. data/lib/riak/link.rb +0 -73
  86. data/lib/riak/locale/en.yml +0 -37
  87. data/lib/riak/map_reduce.rb +0 -248
  88. data/lib/riak/robject.rb +0 -258
  89. data/lib/riak/util/escape.rb +0 -12
  90. data/lib/riak/util/fiber1.8.rb +0 -48
  91. data/lib/riak/util/headers.rb +0 -44
  92. data/lib/riak/util/multipart.rb +0 -52
  93. data/lib/riak/walk_spec.rb +0 -117
  94. data/ripple.gemspec +0 -169
  95. data/spec/fixtures/cat.jpg +0 -0
  96. data/spec/fixtures/multipart-blank.txt +0 -7
  97. data/spec/fixtures/multipart-with-body.txt +0 -16
  98. data/spec/riak/bucket_spec.rb +0 -230
  99. data/spec/riak/client_spec.rb +0 -174
  100. data/spec/riak/curb_backend_spec.rb +0 -50
  101. data/spec/riak/escape_spec.rb +0 -17
  102. data/spec/riak/http_backend_spec.rb +0 -131
  103. data/spec/riak/link_spec.rb +0 -82
  104. data/spec/riak/map_reduce_spec.rb +0 -352
  105. data/spec/riak/multipart_spec.rb +0 -36
  106. data/spec/riak/object_spec.rb +0 -532
  107. data/spec/riak/walk_spec_spec.rb +0 -208
  108. data/spec/spec.opts +0 -1
  109. data/spec/support/http_backend_implementation_examples.rb +0 -215
  110. data/spec/support/mock_server.rb +0 -58
@@ -0,0 +1,111 @@
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::Associations do
17
+ require 'support/models/invoice'
18
+ require 'support/models/customer'
19
+ require 'support/models/note'
20
+
21
+ it "should provide access to the associations hash" do
22
+ Invoice.should respond_to(:associations)
23
+ Invoice.associations.should be_kind_of(Hash)
24
+ end
25
+
26
+ it "should add associations on the class instance" do
27
+ Invoice.new.should respond_to(:associations)
28
+ Invoice.new.associations.should be_kind_of(Hash)
29
+ end
30
+
31
+ it "should collect the embedded associations" do
32
+ Invoice.new.embedded_associations.should == Array(Invoice.associations[:note])
33
+ end
34
+
35
+ it "should copy associations to a subclass" do
36
+ Invoice.associations[:foo] = "bar"
37
+ class SubInvoice < Invoice; end
38
+ SubInvoice.associations[:foo].should == "bar"
39
+ end
40
+
41
+ describe "when adding a :many association" do
42
+ it "should add accessor and mutator methods" do
43
+ Invoice.many :items
44
+ Invoice.instance_methods.map(&:to_sym).should include(:items)
45
+ Invoice.instance_methods.map(&:to_sym).should include(:items=)
46
+ end
47
+ end
48
+
49
+ describe "when adding a :one association" do
50
+ it "should add accessor, mutator, and query methods" do
51
+ Invoice.one :payee
52
+ Invoice.instance_methods.map(&:to_sym).should include(:payee)
53
+ Invoice.instance_methods.map(&:to_sym).should include(:payee=)
54
+ Invoice.instance_methods.map(&:to_sym).should include(:payee?)
55
+ end
56
+ end
57
+ end
58
+
59
+ describe Ripple::Document::Association do
60
+ it "should initialize with a type and name" do
61
+ lambda { Ripple::Document::Association.new(:many, :pages) }.should_not raise_error
62
+ end
63
+
64
+ describe "determining the class name" do
65
+ it "should default to the camelized class name on :one relationships" do
66
+ @association = Ripple::Document::Association.new(:one, :page)
67
+ @association.class_name.should == "Page"
68
+ end
69
+
70
+ it "should default to the singularized camelized class name on :many relationships" do
71
+ @association = Ripple::Document::Association.new(:many, :pages)
72
+ @association.class_name.should == "Page"
73
+ end
74
+
75
+ it "should use the :class_name option when given" do
76
+ @association = Ripple::Document::Association.new(:many, :pages, :class_name => "Note")
77
+ @association.class_name.should == "Note"
78
+ end
79
+ end
80
+
81
+ describe "determining the target class" do
82
+ require 'support/models/tree'
83
+
84
+ it "should default to the constantized class name" do
85
+ @association = Ripple::Document::Association.new(:one, :t, :class_name => "Trunk")
86
+ @association.klass.should == Trunk
87
+ end
88
+
89
+ it "should be determined by the derived class name" do
90
+ @association = Ripple::Document::Association.new(:many, :branches)
91
+ @association.klass.should == Branch
92
+ end
93
+
94
+ it "should use the :class option when given" do
95
+ @association = Ripple::Document::Association.new(:many, :pages, :class => Leaf)
96
+ @association.klass.should == Leaf
97
+ end
98
+ end
99
+
100
+ it "should be many when type is :many" do
101
+ Ripple::Document::Association.new(:many, :pages).should be_many
102
+ end
103
+
104
+ it "should be one when type is :one" do
105
+ Ripple::Document::Association.new(:one, :pages).should be_one
106
+ end
107
+
108
+ it "should determine an instance variable based on the name" do
109
+ Ripple::Document::Association.new(:many, :pages).ivar.should == "@_pages"
110
+ end
111
+ end
@@ -14,16 +14,8 @@
14
14
  require File.expand_path("../../spec_helper", __FILE__)
15
15
 
16
16
  describe Ripple::Document::AttributeMethods do
17
- before :all do
18
- Object.module_eval do
19
- class Widget
20
- include Ripple::Document
21
- property :size, Integer
22
- property :name, String, :default => "widget"
23
- end
24
- end
25
- end
26
-
17
+ require 'support/models/widget'
18
+
27
19
  before :each do
28
20
  @widget = Widget.new
29
21
  end
@@ -40,9 +32,15 @@ describe Ripple::Document::AttributeMethods do
40
32
  @widget.key.should == "cog"
41
33
  end
42
34
 
43
- it "should accept the key in mass assignment" do
44
- @widget.attributes = {:key => "cog"}
45
- @widget.key.should == "cog"
35
+ it "should not set the key from mass assignment" do
36
+ @widget.key = 'widget-key'
37
+ @widget.attributes = {'key' => 'new-key'}
38
+ @widget.key.should == 'widget-key'
39
+ end
40
+
41
+ it "should typecast the key to a string" do
42
+ @widget.key = 10
43
+ @widget.key.should == "10"
46
44
  end
47
45
 
48
46
  end
@@ -60,6 +58,10 @@ describe Ripple::Document::AttributeMethods do
60
58
  it "should return the property default if defined and not set" do
61
59
  @widget.name.should == "widget"
62
60
  end
61
+
62
+ it "should allow raw attribute access when accessing the document with []" do
63
+ @widget['name'].should == 'widget'
64
+ end
63
65
 
64
66
  it "should expose the property directly" do
65
67
  @widget.name.gsub!("w","f")
@@ -77,6 +79,11 @@ describe Ripple::Document::AttributeMethods do
77
79
  @widget.size = 10
78
80
  @widget.size.should == 10
79
81
  end
82
+
83
+ it "should allow assignment of undefined attributes when assigning to the document with []=" do
84
+ @widget['name'] = 'sprocket'
85
+ @widget.name.should == 'sprocket'
86
+ end
80
87
 
81
88
  it "should type cast assigned values automatically" do
82
89
  @widget.name = :so_what
@@ -149,8 +156,22 @@ describe Ripple::Document::AttributeMethods do
149
156
  @widget = Widget.new(:name => "Riak")
150
157
  @widget.changes.should be_blank
151
158
  end
152
-
153
- after :all do
154
- Object.send(:remove_const, :Widget)
159
+
160
+ it "should allow adding to the @attributes hash for attributes that do no exist" do
161
+ @widget = Widget.new
162
+ @widget['foo'] = 'bar'
163
+ @widget.instance_eval { @attributes['foo'] }.should == 'bar'
164
+ end
165
+
166
+ it "should allow reading from the @attributes hash for attributes that do no exist" do
167
+ @widget = Widget.new
168
+ @widget['foo'] = 'bar'
169
+ @widget['foo'].should == 'bar'
170
+ end
171
+
172
+ it "should allow a block upon initialization to set attributes protected from mass assignment" do
173
+ @widget = Widget.new { |w| w.key = 'some-key' }
174
+ @widget.key.should == 'some-key'
155
175
  end
176
+
156
177
  end
@@ -14,13 +14,9 @@
14
14
  require File.expand_path("../spec_helper", File.dirname(__FILE__))
15
15
 
16
16
  describe Ripple::Document::BucketAccess do
17
- before :all do
18
- Object.module_eval do
19
- class Invoice; include Ripple::Document; end
20
- class LateInvoice < Invoice; end
21
- class PaidInvoice < Invoice; self.bucket_name = "paid"; end
22
- end
23
- end
17
+ require 'support/models/invoice'
18
+ require 'support/models/late_invoice'
19
+ require 'support/models/paid_invoice'
24
20
 
25
21
  it "should use the plural model name as the bucket name" do
26
22
  Invoice.bucket_name.should == "invoices"
@@ -40,11 +36,4 @@ describe Ripple::Document::BucketAccess do
40
36
  Invoice.bucket.should == bucket
41
37
  end
42
38
 
43
- after :all do
44
- Object.module_eval do
45
- remove_const(:PaidInvoice)
46
- remove_const(:LateInvoice)
47
- remove_const(:Invoice)
48
- end
49
- end
50
39
  end
@@ -13,10 +13,8 @@
13
13
  # limitations under the License.
14
14
  require File.expand_path("../../spec_helper", __FILE__)
15
15
 
16
- describe Ripple::Document::Persistence::Callbacks do
17
- before :all do
18
- Object.module_eval { class Box; include Ripple::Document; property :shape, String end }
19
- end
16
+ describe Ripple::Document::Callbacks do
17
+ require 'support/models/box'
20
18
 
21
19
  it "should add create, update, save, and destroy callback declarations" do
22
20
  [:save, :create, :update, :destroy].each do |event|
@@ -27,6 +25,12 @@ describe Ripple::Document::Persistence::Callbacks do
27
25
  end
28
26
  end
29
27
 
28
+ it "should validate callback declarations" do
29
+ Box.private_instance_methods.map(&:to_s).should include("_run_validation_callbacks")
30
+ Box.should respond_to("before_validation")
31
+ Box.should respond_to("after_validation")
32
+ end
33
+
30
34
  describe "invoking callbacks" do
31
35
  before :each do
32
36
  response = {:headers => {"content-type" => ["application/json"]}, :body => "{}"}
@@ -72,15 +76,55 @@ describe Ripple::Document::Persistence::Callbacks do
72
76
  @box = Box.new
73
77
  @box.destroy
74
78
  end
79
+
80
+ describe "validation callbacks" do
81
+ it "should call validation callbacks" do
82
+ Box.before_validation { $pinger.ping }
83
+ Box.after_validation { $pinger.ping }
84
+ $pinger.should_receive(:ping).twice
85
+ @box = Box.new
86
+ @box.valid?
87
+ end
88
+
89
+ it "should call validation callbacks only if the document is new" do
90
+ Box.before_validation(:on => :create) { $pinger.ping }
91
+ Box.after_validation(:on => :create) { $pinger.ping }
92
+ $pinger.should_receive(:ping).twice
93
+ @box = Box.new
94
+ @box.valid?
95
+ end
96
+
97
+ it "should not call validation callbacks only if the document is new" do
98
+ Box.before_validation(:on => :update) { $pinger.ping }
99
+ Box.after_validation(:on => :update) { $pinger.ping }
100
+ $pinger.should_not_receive(:ping)
101
+ @box = Box.new
102
+ @box.valid?
103
+ end
104
+
105
+ it "should call validation callbacks only if the document is not new" do
106
+ Box.before_validation(:on => :update) { $pinger.ping }
107
+ Box.after_validation(:on => :update) { $pinger.ping }
108
+ $pinger.should_receive(:ping).twice
109
+ @box = Box.new
110
+ @box.stub(:new?).and_return(false)
111
+ @box.valid?
112
+ end
113
+
114
+ it "should not call validation callbacks only if the document is not new" do
115
+ Box.before_validation(:on => :create) { $pinger.ping }
116
+ Box.after_validation(:on => :create) { $pinger.ping }
117
+ $pinger.should_not_receive(:ping)
118
+ @box = Box.new
119
+ @box.stub!(:new?).and_return(false)
120
+ @box.valid?
121
+ end
122
+ end
75
123
 
76
124
  after :each do
77
- [:save, :create, :update, :destroy].each do |type|
125
+ [:save, :create, :update, :destroy, :validation].each do |type|
78
126
  Box.reset_callbacks(type)
79
127
  end
80
128
  end
81
129
  end
82
-
83
- after :all do
84
- Object.send(:remove_const, :Box)
85
- end
86
130
  end
@@ -14,12 +14,10 @@
14
14
  require File.expand_path("../spec_helper", File.dirname(__FILE__))
15
15
 
16
16
  describe Ripple::Document do
17
- before :all do
18
- Object.module_eval { class Page; include Ripple::Document; end }
19
- end
17
+ require 'support/models/page'
20
18
 
21
19
  it "should add bucket access methods to classes when included" do
22
- Page.metaclass.included_modules.should include(Ripple::Document::BucketAccess)
20
+ (class << Page; self; end).included_modules.should include(Ripple::Document::BucketAccess)
23
21
  Page.should respond_to(:bucket_name)
24
22
  Page.should respond_to(:bucket)
25
23
  Page.should respond_to(:bucket_name=)
@@ -29,7 +27,25 @@ describe Ripple::Document do
29
27
  Page.should_not be_embeddable
30
28
  end
31
29
 
32
- after :all do
33
- Object.module_eval { remove_const(:Page) }
30
+ describe "ActiveModel compatibility" do
31
+ include ActiveModel::Lint::Tests
32
+
33
+ before :each do
34
+ @model = Page.new
35
+ end
36
+
37
+ def assert(value, message="")
38
+ value.should be
39
+ end
40
+
41
+ def assert_kind_of(klass, value)
42
+ value.should be_kind_of(klass)
43
+ end
44
+
45
+ ActiveModel::Lint::Tests.instance_methods.grep(/^test/).each do |m|
46
+ it "#{m}" do
47
+ send(m)
48
+ end
49
+ end
34
50
  end
35
51
  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__)
15
+
16
+ describe Ripple::EmbeddedDocument::Conversion do
17
+ require 'support/models/address'
18
+
19
+ before :each do
20
+ @addr = Address.new { |a| a.key = 'some-key' }
21
+ @addr.stub!(:new?).and_return(false)
22
+ end
23
+
24
+ it "should return the key as an array for to_key" do
25
+ @addr.to_key.should == ['some-key']
26
+ end
27
+
28
+ it "should be able to be converted to a param" do
29
+ @addr.to_param.should == 'some-key'
30
+ end
31
+
32
+ it "should be able to be converted to a model" do
33
+ @addr.to_model.should == @addr
34
+ end
35
+ end
@@ -11,24 +11,27 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- require File.expand_path("../spec_helper", File.dirname(__FILE__))
14
+ require File.expand_path("../../../spec_helper", __FILE__)
15
15
 
16
- describe Riak::Util::Headers do
17
- it "should include the Net::HTTPHeader module" do
18
- Riak::Util::Headers.included_modules.should include(Net::HTTPHeader)
19
- end
16
+ describe Ripple::EmbeddedDocument::Finders do
17
+ require 'support/models/address'
18
+ require 'support/models/favorite'
20
19
 
21
- it "should be initially empty" do
22
- Riak::Util::Headers.new.to_hash.should == {}
20
+ before :each do
21
+ @addr = Address.new
23
22
  end
24
23
 
25
- it "should parse a header line into the key and value" do
26
- Riak::Util::Headers.parse("Content-Type: text/plain\n").should == ["Content-Type", "text/plain"]
24
+ it "should instantiate a document" do
25
+ Address.stub!(:new).and_return(@address)
26
+ Address.instantiate('_type' => 'Address').should == @address
27
27
  end
28
-
29
- it "should parse a header line and add it to the collection" do
30
- h = Riak::Util::Headers.new
31
- h.parse("Content-Type: text/plain\n")
32
- h.to_hash.should == {"content-type" => ["text/plain"]}
28
+
29
+ it "should instantiate a class of _type if present in attrs" do
30
+ Favorite.instantiate('_type' => 'Address').class.should == Address
33
31
  end
32
+
33
+ it "should use self if being called from a class including Ripple::EmbeddedDocument and _type is not present" do
34
+ Address.instantiate({}).class.should == Address
35
+ end
36
+
34
37
  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::EmbeddedDocument::Persistence do
17
+ require 'support/models/user'
18
+ require 'support/models/address'
19
+
20
+ before :each do
21
+ @root = User.new
22
+ @addr = Address.new
23
+ @addr._parent_document = @root
24
+ end
25
+
26
+ it "should be embeddable if including Ripple::EmbeddedDocument" do
27
+ @addr.should be_embeddable
28
+ end
29
+
30
+ it "should not be a root document if including Ripple::EmbeddedDocument" do
31
+ @addr.should_not be__root_document
32
+ end
33
+
34
+ it "should be a root document if including Ripple::Document" do
35
+ @root.should be__root_document
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
+
48
+ it "should delegate save! to the root document" do
49
+ @root.should_receive(:save!).and_return(true)
50
+ @addr.save!.should be_true
51
+ end
52
+
53
+ it "should raise NoRootDocument when calling save without a root document" do
54
+ @addr = Address.new
55
+ lambda { @addr.save }.should raise_error(Ripple::NoRootDocument)
56
+ end
57
+
58
+ it "should raise NoRootDocument when calling save! without a root document" do
59
+ @addr = Address.new
60
+ lambda { @addr.save! }.should raise_error(Ripple::NoRootDocument)
61
+ end
62
+
63
+ it "should have a root document" do
64
+ @addr._root_document.should == @root
65
+ end
66
+
67
+ it "should have a parent document" do
68
+ @addr._parent_document.should == @root
69
+ end
70
+
71
+ it "should respond to new_record?" do
72
+ @addr.should respond_to(:new_record?)
73
+ @addr.should be_a_new_record
74
+ end
75
+
76
+ it "should respond to persisted" do
77
+ @addr.should respond_to(:persisted?)
78
+ @addr.should_not be_persisted
79
+ end
80
+
81
+ it "should properly create embedded attributes for persistence" do
82
+ @addr = Address.new
83
+ @root.addresses << @addr
84
+ @root.attributes_for_persistence.should == {'_type' => 'User', 'addresses' => [{'_type' => 'Address', 'street' => nil}]}
85
+ end
86
+ end