ripple 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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