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,129 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::Associations do
4
+ require 'support/models/invoice'
5
+ require 'support/models/customer'
6
+ require 'support/models/note'
7
+
8
+ it "should provide access to the associations hash" do
9
+ Invoice.should respond_to(:associations)
10
+ Invoice.associations.should be_kind_of(Hash)
11
+ end
12
+
13
+ it "should collect the embedded associations" do
14
+ Invoice.embedded_associations.should == Array(Invoice.associations[:note])
15
+ end
16
+
17
+ it "should collect the linked associations" do
18
+ Invoice.linked_associations.should == Array(Invoice.associations[:customer])
19
+ end
20
+
21
+ it "should collect the stored_key associations" do
22
+ Account.stored_key_associations.should == Array(Account.associations[:transactions])
23
+ Transaction.stored_key_associations.should == Array(Transaction.associations[:account])
24
+ end
25
+
26
+ it "should copy associations to a subclass" do
27
+ Invoice.associations[:foo] = "bar"
28
+ class SubInvoice < Invoice; end
29
+ SubInvoice.associations[:foo].should == "bar"
30
+ end
31
+
32
+ describe "when adding a :many association" do
33
+ it "should add accessor and mutator methods" do
34
+ Invoice.many :items
35
+ Invoice.instance_methods.map(&:to_sym).should include(:items)
36
+ Invoice.instance_methods.map(&:to_sym).should include(:items=)
37
+ end
38
+ end
39
+
40
+ describe "when adding a :one association" do
41
+ it "should add accessor, mutator, and query methods" do
42
+ Invoice.one :payee
43
+ Invoice.instance_methods.map(&:to_sym).should include(:payee)
44
+ Invoice.instance_methods.map(&:to_sym).should include(:payee=)
45
+ Invoice.instance_methods.map(&:to_sym).should include(:payee?)
46
+ end
47
+ end
48
+
49
+ before(:all) do
50
+ @orig_invoice = Invoice
51
+ Object.send(:remove_const, :Invoice)
52
+ class Invoice < @orig_invoice; end
53
+ end
54
+
55
+ after(:all) do
56
+ Object.send(:remove_const, :SubInvoice) if defined?(SubInvoice)
57
+ Object.send(:remove_const, :Invoice)
58
+ Object.send(:const_set, :Invoice, @orig_invoice)
59
+ end
60
+ end
61
+
62
+ describe Ripple::Association do
63
+ it "should initialize with a type and name" do
64
+ lambda { Ripple::Association.new(:many, :pages) }.should_not raise_error
65
+ end
66
+
67
+ describe "determining the class name" do
68
+ it "should default to the camelized class name on :one relationships" do
69
+ @association = Ripple::Association.new(:one, :page)
70
+ @association.class_name.should == "Page"
71
+ end
72
+
73
+ it "should default to the singularized camelized class name on :many relationships" do
74
+ @association = Ripple::Association.new(:many, :pages)
75
+ @association.class_name.should == "Page"
76
+ end
77
+
78
+ it "should use the :class_name option when given" do
79
+ @association = Ripple::Association.new(:many, :pages, :class_name => "Note")
80
+ @association.class_name.should == "Note"
81
+ end
82
+ end
83
+
84
+ describe "determining the target class" do
85
+ require 'support/models/tree'
86
+
87
+ it "should default to the constantized class name" do
88
+ @association = Ripple::Association.new(:one, :t, :class_name => "Trunk")
89
+ @association.klass.should == Trunk
90
+ end
91
+
92
+ it "should be determined by the derived class name" do
93
+ @association = Ripple::Association.new(:many, :branches)
94
+ @association.klass.should == Branch
95
+ end
96
+
97
+ it "should use the :class option when given" do
98
+ @association = Ripple::Association.new(:many, :pages, :class => Leaf)
99
+ @association.klass.should == Leaf
100
+ end
101
+ end
102
+
103
+ it "should be many when type is :many" do
104
+ Ripple::Association.new(:many, :pages).should be_many
105
+ end
106
+
107
+ it "should be one when type is :one" do
108
+ Ripple::Association.new(:one, :pages).should be_one
109
+ end
110
+
111
+ it "should determine an instance variable based on the name" do
112
+ Ripple::Association.new(:many, :pages).ivar.should == "@_pages"
113
+ end
114
+
115
+ describe "key correspondence" do
116
+ require 'support/models/profile'
117
+ require 'support/models/user'
118
+
119
+ it "should raise an exception if trying to use a many association when :using => :key" do
120
+ expect { Profile.many :user, :using => :key }.to raise_error(ArgumentError, "You cannot use a many association using :key")
121
+ end
122
+
123
+ it "should add the key_delegate attr_accessor to the model declaring the association" do
124
+ Profile.one :user, :using => :key
125
+ Profile.new.should respond_to(:key_delegate)
126
+ Profile.new.should respond_to(:key_delegate=)
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::AttributeMethods::Dirty do
4
+ let(:company) { Company.new }
5
+ let(:ceo) { CEO.new(:name => 'John Doe') }
6
+ let(:department) { Department.new(:name => 'Marketing') }
7
+ let(:manager) { Manager.new(:name => 'Billy Willy') }
8
+ let(:invoice) { Invoice.new }
9
+
10
+ describe "previous_changes" do
11
+ before do
12
+ company.robject.stub!(:store).and_return(true)
13
+ company.name = 'Fizz Buzz, Inc.'
14
+ end
15
+
16
+ it "should capture previous changes when saving" do
17
+ company.save
18
+ company.previous_changes.should include('name')
19
+ end
20
+
21
+ it "should make previous changes available to after callbacks" do
22
+ my_class = Class.new(Company) do
23
+ after_save {|c| c['pc'] = previous_changes }
24
+ end
25
+ comp = my_class.new
26
+ comp.robject.stub!(:store).and_return(true)
27
+ comp.name = 'Fizz Buzz, Inc.'
28
+ comp.save
29
+ comp['pc'].should include('name')
30
+ end
31
+ end
32
+
33
+ describe "#changed?" do
34
+
35
+ it "returns true if the document's attributes have changed (regardless of whether or not it has any embedded associated documents)" do
36
+ company.name = 'Fizz Buzz, Inc'
37
+ company.should be_changed
38
+ end
39
+
40
+
41
+ context "when the document's attributes have not changed" do
42
+ it 'returns false if it has no embedded associated documents' do
43
+ company.should_not be_changed
44
+ end
45
+
46
+ context 'when the document has embedded associated documents' do
47
+ before(:each) do
48
+ company.ceo = ceo
49
+ company.invoices << invoice
50
+ company.departments << department
51
+ department.managers << manager
52
+ end
53
+
54
+ it 'returns false if all the embedded documents are not changed' do
55
+ company.should_not be_changed
56
+ end
57
+
58
+ it 'does not consider changes to linked associated documents' do
59
+ invoice.should_not_receive(:changed?)
60
+ company.changed?
61
+ end
62
+
63
+ it 'returns true if a one embedded association document is changed' do
64
+ ceo.should_receive(:changed?).and_return(true)
65
+ company.should be_changed
66
+ end
67
+
68
+ it 'returns true if a many embedded association document is changed' do
69
+ department.should_receive(:changed?).and_return(true)
70
+ company.should be_changed
71
+ end
72
+
73
+ it 'recurses through the whole embedded document structure to find changed grandchild documents' do
74
+ manager.should_receive(:changed?).and_return(true)
75
+ company.should be_changed
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,230 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::AttributeMethods do
4
+ require 'support/models/widget'
5
+
6
+ before :each do
7
+ @widget = Widget.new
8
+ end
9
+
10
+ describe "object key" do
11
+ it "should provide access to the key" do
12
+ @widget.should respond_to(:key)
13
+ @widget.key.should be_nil
14
+ end
15
+
16
+ it "should provide a mutator for the key" do
17
+ @widget.should respond_to(:key=)
18
+ @widget.key = "cog"
19
+ @widget.key.should == "cog"
20
+ end
21
+
22
+ it "should not set the key from mass assignment" do
23
+ @widget.key = 'widget-key'
24
+ @widget.attributes = {'key' => 'new-key'}
25
+ @widget.key.should == 'widget-key'
26
+ end
27
+
28
+ it "should typecast the key to a string" do
29
+ @widget.key = 10
30
+ @widget.key.should == "10"
31
+ end
32
+ end
33
+
34
+ describe "accessors" do
35
+ it "should be defined for defined properties" do
36
+ @widget.should respond_to(:size)
37
+ @widget.should respond_to(:name)
38
+ end
39
+
40
+ it "should return nil if no default is defined on the property" do
41
+ @widget.size.should be_nil
42
+ end
43
+
44
+ it "should return the property default if defined and not set" do
45
+ @widget.name.should == "widget"
46
+ @widget.manufactured.should == false
47
+ end
48
+
49
+ it "dups the default if it is duplicable so that two document do not share the same mutable value" do
50
+ widget2 = Widget.new
51
+ @widget.name.should_not be(widget2.name)
52
+ widget2.name.gsub!("w", "f")
53
+ @widget.name.should == "widget"
54
+ end
55
+
56
+ it "should allow raw attribute access when accessing the document with []" do
57
+ @widget['name'].should == 'widget'
58
+ end
59
+
60
+ it "should expose the property directly" do
61
+ @widget.name.gsub!("w","f")
62
+ @widget.name.should == "fidget"
63
+ end
64
+ end
65
+
66
+ describe "mutators" do
67
+ it "should have mutators for defined properties" do
68
+ @widget.should respond_to(:size=)
69
+ @widget.should respond_to(:name=)
70
+ end
71
+
72
+ it "should assign the value of the attribute" do
73
+ @widget.size = 10
74
+ @widget.size.should == 10
75
+ end
76
+
77
+ it "should allow assignment of undefined attributes when assigning to the document with []=" do
78
+ @widget.should_not respond_to(:shoe_size)
79
+ @widget['shoe_size'] = 8
80
+ @widget['shoe_size'].should == 8
81
+ end
82
+
83
+ it "should type cast assigned values automatically" do
84
+ @widget.name = :so_what
85
+ @widget.name.should == "so_what"
86
+ end
87
+
88
+ it "should raise an error when assigning a bad value" do
89
+ lambda { @widget.size = true }.should raise_error(Ripple::PropertyTypeMismatch)
90
+ end
91
+ end
92
+
93
+ describe "query methods" do
94
+ it "should be defined for defined properties" do
95
+ @widget.should respond_to(:size?)
96
+ @widget.should respond_to(:name?)
97
+ end
98
+
99
+ it "should be false when the attribute is nil" do
100
+ @widget.size.should be_nil
101
+ @widget.size?.should be_false
102
+ end
103
+
104
+ it "should be true when the attribute has a value present" do
105
+ @widget.size = 10
106
+ @widget.size?.should be_true
107
+ end
108
+
109
+ it "should be false for 0 values" do
110
+ @widget.size = 0
111
+ @widget.size?.should be_false
112
+ end
113
+
114
+ it "should be false for empty values" do
115
+ @widget.name = ""
116
+ @widget.name?.should be_false
117
+ end
118
+ end
119
+
120
+ it "should track changes to attributes" do
121
+ @widget.name = "foobar"
122
+ @widget.changed?.should be_true
123
+ @widget.name_changed?.should be_true
124
+ @widget.name_change.should == ["widget", "foobar"]
125
+ @widget.changes.should == {"name" => ["widget", "foobar"]}
126
+ end
127
+
128
+ it "should report that an attribute is changed only if its value actually changes" do
129
+ @widget.name = "widget"
130
+ @widget.changed?.should be_false
131
+ @widget.name_changed?.should be_false
132
+ @widget.changes.should be_blank
133
+ end
134
+
135
+ it "should refresh the attribute methods when adding a new property" do
136
+ Widget.should_receive(:undefine_attribute_methods)
137
+ Widget.property :start_date, Date
138
+ Widget.properties.delete(:start_date) # cleanup
139
+ end
140
+
141
+ describe "#attributes" do
142
+ it "it returns a hash representation of all of the attributes" do
143
+ @widget.attributes.should == {"name" => "widget", "size" => nil, "manufactured" => false, "shipped_at" => nil}
144
+ end
145
+
146
+ it "does not include ghost attributes (attributes that do not have a defined property)" do
147
+ @widget['some_undefined_prop'] = 3.14159
148
+ @widget.attributes.should_not include('some_undefined_prop')
149
+ end
150
+ end
151
+
152
+ describe "#raw_attributes" do
153
+ it "returns a hash representation, including attributes for undefined properties" do
154
+ @widget['some_undefined_prop'] = 17
155
+ @widget.raw_attributes.should == {
156
+ 'name' => 'widget',
157
+ 'size' => nil,
158
+ 'manufactured' => false,
159
+ 'shipped_at' => nil,
160
+ 'some_undefined_prop' => 17
161
+ }
162
+ end
163
+ end
164
+
165
+ it "should load attributes from mass assignment" do
166
+ @widget.attributes = {"name" => "Riak", "size" => 100000 }
167
+ @widget.name.should == "Riak"
168
+ @widget.size.should == 100000
169
+ end
170
+
171
+ it "should assign attributes on initialization" do
172
+ @widget = Widget.new(:name => "Riak")
173
+ @widget.name.should == "Riak"
174
+ end
175
+
176
+ it "should have no changed attributes after initialization" do
177
+ @widget = Widget.new(:name => "Riak")
178
+ @widget.changes.should be_blank
179
+ end
180
+
181
+ it "should allow adding to the @attributes hash for attributes that do not exist" do
182
+ @widget = Widget.new
183
+ @widget['foo'] = 'bar'
184
+ @widget.instance_eval { @attributes['foo'] }.should == 'bar'
185
+ end
186
+
187
+ it "should allow reading from the @attributes hash for attributes that do not exist" do
188
+ @widget = Widget.new
189
+ @widget['foo'] = 'bar'
190
+ @widget['foo'].should == 'bar'
191
+ end
192
+
193
+ it "should allow a block upon initialization to set attributes protected from mass assignment" do
194
+ @widget = Widget.new { |w| w.key = 'some-key' }
195
+ @widget.key.should == 'some-key'
196
+ end
197
+
198
+ it "should raise an argument error when assigning a non hash to attributes" do
199
+ @widget = Widget.new
200
+ lambda { @widget.attributes = nil }.should raise_error(ArgumentError)
201
+ end
202
+
203
+ it "should protect attributes from mass assignment when initialized" do
204
+ @widget = Widget.new(:manufactured => true)
205
+ @widget.manufactured.should be_false
206
+ end
207
+
208
+ it "should protect attributes from mass assignment by default" do
209
+ @widget = Widget.new
210
+ @widget.attributes = { :manufactured => true }
211
+ @widget.manufactured.should be_false
212
+ end
213
+
214
+ it "should allow protected attributes to be mass assigned via raw_attributes=" do
215
+ @widget = Widget.new
216
+ @widget.send(:raw_attributes=, { :manufactured => true })
217
+ @widget.manufactured.should be_true
218
+ end
219
+
220
+ it "should allow mass assigning arbitrary attributes via raw_attributes" do
221
+ @widget = Widget.new
222
+ @widget.__send__(:raw_attributes=, :explode => '?BOOM')
223
+ @widget[:explode].should eq('?BOOM')
224
+ end
225
+
226
+ it "should raise an ArgumentError with an undefined property message when mass assigning a property that doesn't exist" do
227
+ lambda { @widget = Widget.new(:explode => '?BOOM') }.should raise_error(ArgumentError, %q[Undefined property :explode for class 'Widget'])
228
+ end
229
+
230
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ripple::Document::BucketAccess do
4
+ require 'support/models/invoice'
5
+ require 'support/models/late_invoice'
6
+ require 'support/models/paid_invoice'
7
+
8
+ it "should use the plural model name as the bucket name" do
9
+ Invoice.bucket_name.should == "invoices"
10
+ end
11
+
12
+ it "should use the parent bucket name by default (SBI)" do
13
+ LateInvoice.bucket_name.should == "invoices"
14
+ end
15
+
16
+ it "should allow a class to set the bucket name" do
17
+ PaidInvoice.bucket_name.should == "paid"
18
+ end
19
+
20
+ it "should allow access to the bucket" do
21
+ Invoice.bucket.should be_kind_of(Riak::Bucket)
22
+ Invoice.bucket.client.should == Ripple.client
23
+ Invoice.bucket.name.should == "invoices"
24
+ end
25
+ end