seomoz-ripple 1.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +20 -0
- data/Guardfile +15 -0
- data/Rakefile +88 -0
- data/lib/rails/generators/ripple/configuration/configuration_generator.rb +13 -0
- data/lib/rails/generators/ripple/configuration/templates/ripple.yml +24 -0
- data/lib/rails/generators/ripple/js/js_generator.rb +13 -0
- data/lib/rails/generators/ripple/js/templates/js/contrib.js +63 -0
- data/lib/rails/generators/ripple/js/templates/js/iso8601.js +76 -0
- data/lib/rails/generators/ripple/js/templates/js/ripple.js +132 -0
- data/lib/rails/generators/ripple/model/model_generator.rb +20 -0
- data/lib/rails/generators/ripple/model/templates/model.rb +10 -0
- data/lib/rails/generators/ripple/observer/observer_generator.rb +16 -0
- data/lib/rails/generators/ripple/observer/templates/observer.rb +4 -0
- data/lib/rails/generators/ripple/test/templates/test_server.rb +46 -0
- data/lib/rails/generators/ripple/test/test_generator.rb +39 -0
- data/lib/rails/generators/ripple_generator.rb +78 -0
- data/lib/ripple.rb +79 -0
- data/lib/ripple/associations.rb +356 -0
- data/lib/ripple/associations/embedded.rb +35 -0
- data/lib/ripple/associations/instantiators.rb +26 -0
- data/lib/ripple/associations/linked.rb +65 -0
- data/lib/ripple/associations/many.rb +38 -0
- data/lib/ripple/associations/many_embedded_proxy.rb +38 -0
- data/lib/ripple/associations/many_linked_proxy.rb +66 -0
- data/lib/ripple/associations/many_reference_proxy.rb +93 -0
- data/lib/ripple/associations/many_stored_key_proxy.rb +76 -0
- data/lib/ripple/associations/one.rb +20 -0
- data/lib/ripple/associations/one_embedded_proxy.rb +35 -0
- data/lib/ripple/associations/one_key_proxy.rb +58 -0
- data/lib/ripple/associations/one_linked_proxy.rb +22 -0
- data/lib/ripple/associations/one_stored_key_proxy.rb +43 -0
- data/lib/ripple/associations/proxy.rb +118 -0
- data/lib/ripple/attribute_methods.rb +118 -0
- data/lib/ripple/attribute_methods/dirty.rb +50 -0
- data/lib/ripple/attribute_methods/query.rb +34 -0
- data/lib/ripple/attribute_methods/read.rb +26 -0
- data/lib/ripple/attribute_methods/write.rb +25 -0
- data/lib/ripple/callbacks.rb +74 -0
- data/lib/ripple/conflict/basic_resolver.rb +82 -0
- data/lib/ripple/conflict/document_hooks.rb +20 -0
- data/lib/ripple/conflict/resolver.rb +71 -0
- data/lib/ripple/conflict/test_helper.rb +33 -0
- data/lib/ripple/conversion.rb +28 -0
- data/lib/ripple/core_ext.rb +2 -0
- data/lib/ripple/core_ext/casting.rb +148 -0
- data/lib/ripple/core_ext/object.rb +8 -0
- data/lib/ripple/document.rb +104 -0
- data/lib/ripple/document/bucket_access.rb +25 -0
- data/lib/ripple/document/finders.rb +131 -0
- data/lib/ripple/document/key.rb +43 -0
- data/lib/ripple/document/link.rb +30 -0
- data/lib/ripple/document/persistence.rb +115 -0
- data/lib/ripple/embedded_document.rb +64 -0
- data/lib/ripple/embedded_document/around_callbacks.rb +18 -0
- data/lib/ripple/embedded_document/finders.rb +26 -0
- data/lib/ripple/embedded_document/persistence.rb +77 -0
- data/lib/ripple/i18n.rb +2 -0
- data/lib/ripple/inspection.rb +32 -0
- data/lib/ripple/locale/en.yml +21 -0
- data/lib/ripple/nested_attributes.rb +265 -0
- data/lib/ripple/observable.rb +28 -0
- data/lib/ripple/properties.rb +73 -0
- data/lib/ripple/property_type_mismatch.rb +12 -0
- data/lib/ripple/railtie.rb +13 -0
- data/lib/ripple/serialization.rb +84 -0
- data/lib/ripple/timestamps.rb +27 -0
- data/lib/ripple/translation.rb +14 -0
- data/lib/ripple/validations.rb +67 -0
- data/lib/ripple/validations/associated_validator.rb +43 -0
- data/ripple.gemspec +46 -0
- data/seomoz-ripple.gemspec +46 -0
- data/spec/fixtures/config.yml +8 -0
- data/spec/integration/ripple/associations_spec.rb +220 -0
- data/spec/integration/ripple/conflict_resolution_spec.rb +293 -0
- data/spec/integration/ripple/nested_attributes_spec.rb +264 -0
- data/spec/integration/ripple/persistence_spec.rb +57 -0
- data/spec/integration/ripple/search_associations_spec.rb +42 -0
- data/spec/ripple/associations/many_embedded_proxy_spec.rb +122 -0
- data/spec/ripple/associations/many_linked_proxy_spec.rb +191 -0
- data/spec/ripple/associations/many_reference_proxy_spec.rb +170 -0
- data/spec/ripple/associations/many_stored_key_proxy_spec.rb +158 -0
- data/spec/ripple/associations/one_embedded_proxy_spec.rb +125 -0
- data/spec/ripple/associations/one_key_proxy_spec.rb +82 -0
- data/spec/ripple/associations/one_linked_proxy_spec.rb +91 -0
- data/spec/ripple/associations/one_stored_key_proxy_spec.rb +72 -0
- data/spec/ripple/associations/proxy_spec.rb +84 -0
- data/spec/ripple/associations_spec.rb +129 -0
- data/spec/ripple/attribute_methods/dirty_spec.rb +80 -0
- data/spec/ripple/attribute_methods_spec.rb +230 -0
- data/spec/ripple/bucket_access_spec.rb +25 -0
- data/spec/ripple/callbacks_spec.rb +176 -0
- data/spec/ripple/conflict/resolver_spec.rb +42 -0
- data/spec/ripple/conversion_spec.rb +22 -0
- data/spec/ripple/core_ext_spec.rb +103 -0
- data/spec/ripple/document/link_spec.rb +67 -0
- data/spec/ripple/document_spec.rb +96 -0
- data/spec/ripple/embedded_document/finders_spec.rb +29 -0
- data/spec/ripple/embedded_document/persistence_spec.rb +80 -0
- data/spec/ripple/embedded_document_spec.rb +84 -0
- data/spec/ripple/finders_spec.rb +217 -0
- data/spec/ripple/inspection_spec.rb +51 -0
- data/spec/ripple/key_spec.rb +30 -0
- data/spec/ripple/observable_spec.rb +121 -0
- data/spec/ripple/persistence_spec.rb +326 -0
- data/spec/ripple/properties_spec.rb +262 -0
- data/spec/ripple/ripple_spec.rb +71 -0
- data/spec/ripple/serialization_spec.rb +51 -0
- data/spec/ripple/timestamps_spec.rb +76 -0
- data/spec/ripple/validations/associated_validator_spec.rb +77 -0
- data/spec/ripple/validations_spec.rb +104 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/associations.rb +1 -0
- data/spec/support/associations/proxies.rb +17 -0
- data/spec/support/integration_setup.rb +11 -0
- data/spec/support/mocks.rb +4 -0
- data/spec/support/models.rb +4 -0
- data/spec/support/models/address.rb +12 -0
- data/spec/support/models/box.rb +13 -0
- data/spec/support/models/car.rb +16 -0
- data/spec/support/models/cardboard_box.rb +3 -0
- data/spec/support/models/clock.rb +12 -0
- data/spec/support/models/clock_observer.rb +3 -0
- data/spec/support/models/company.rb +23 -0
- data/spec/support/models/customer.rb +4 -0
- data/spec/support/models/driver.rb +6 -0
- data/spec/support/models/email.rb +4 -0
- data/spec/support/models/engine.rb +5 -0
- data/spec/support/models/family.rb +16 -0
- data/spec/support/models/favorite.rb +4 -0
- data/spec/support/models/invoice.rb +7 -0
- data/spec/support/models/late_invoice.rb +3 -0
- data/spec/support/models/ninja.rb +9 -0
- data/spec/support/models/note.rb +5 -0
- data/spec/support/models/page.rb +4 -0
- data/spec/support/models/paid_invoice.rb +4 -0
- data/spec/support/models/passenger.rb +6 -0
- data/spec/support/models/profile.rb +10 -0
- data/spec/support/models/seat.rb +5 -0
- data/spec/support/models/subscription.rb +27 -0
- data/spec/support/models/tasks.rb +14 -0
- data/spec/support/models/team.rb +11 -0
- data/spec/support/models/transactions.rb +17 -0
- data/spec/support/models/tree.rb +4 -0
- data/spec/support/models/user.rb +10 -0
- data/spec/support/models/wheel.rb +6 -0
- data/spec/support/models/widget.rb +22 -0
- data/spec/support/test_server.rb +18 -0
- data/spec/support/test_server.yml.example +2 -0
- 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
|