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,176 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ripple::Callbacks do
|
4
|
+
require 'support/models/box'
|
5
|
+
|
6
|
+
it "should add create, update, save, and destroy callback declarations" do
|
7
|
+
[:save, :create, :update, :destroy].each do |event|
|
8
|
+
Box.private_instance_methods.map(&:to_s).should include("_run_#{event}_callbacks")
|
9
|
+
[:before, :after, :around].each do |time|
|
10
|
+
Box.should respond_to("#{time}_#{event}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should validate callback declarations" do
|
16
|
+
Box.private_instance_methods.map(&:to_s).should include("_run_validation_callbacks")
|
17
|
+
Box.should respond_to("before_validation")
|
18
|
+
Box.should respond_to("after_validation")
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "invoking callbacks" do
|
22
|
+
before :each do
|
23
|
+
response = {:headers => {"content-type" => ["application/json"]}, :body => "{}"}
|
24
|
+
@client = Ripple.client
|
25
|
+
@backend = mock("Backend", :store_object => true)
|
26
|
+
@client.stub!(:backend).and_return(@backend)
|
27
|
+
$pinger = mock("callback verifier")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should call save callbacks on save" do
|
31
|
+
Box.before_save { $pinger.ping }
|
32
|
+
Box.after_save { $pinger.ping }
|
33
|
+
Box.around_save(lambda { $pinger.ping })
|
34
|
+
$pinger.should_receive(:ping).exactly(3).times
|
35
|
+
@box = Box.new
|
36
|
+
@box.save
|
37
|
+
end
|
38
|
+
|
39
|
+
it "propagates callbacks to embedded associated documents" do
|
40
|
+
Box.before_save { $pinger.ping }
|
41
|
+
BoxSide.before_save { $pinger.ping }
|
42
|
+
$pinger.should_receive(:ping).exactly(2).times
|
43
|
+
@box = Box.new
|
44
|
+
@box.sides << BoxSide.new
|
45
|
+
@box.save
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'does not persist the object to riak multiple times when propagating callbacks' do
|
49
|
+
Box.before_save { }
|
50
|
+
BoxSide.before_save { }
|
51
|
+
@box = Box.new
|
52
|
+
@box.sides << BoxSide.new << BoxSide.new
|
53
|
+
|
54
|
+
@box.robject.should_receive(:store).once
|
55
|
+
@box.save
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'invokes the before/after callbacks in the correct order on embedded associated documents' do
|
59
|
+
callbacks = []
|
60
|
+
BoxSide.before_save { callbacks << :before_save }
|
61
|
+
BoxSide.after_save { callbacks << :after_save }
|
62
|
+
|
63
|
+
@box = Box.new
|
64
|
+
@box.sides << BoxSide.new
|
65
|
+
@box.robject.stub(:store) do
|
66
|
+
callbacks << :save
|
67
|
+
end
|
68
|
+
@box.save
|
69
|
+
|
70
|
+
callbacks.should == [:before_save, :save, :after_save]
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'does not allow around callbacks on embedded associated documents' do
|
74
|
+
expect {
|
75
|
+
BoxSide.around_save { }
|
76
|
+
}.to raise_error(/around_save callbacks are not supported/)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'does not propagate validation callbacks multiple times' do
|
80
|
+
Box.before_validation { $pinger.ping }
|
81
|
+
BoxSide.before_validation { $pinger.ping }
|
82
|
+
$pinger.should_receive(:ping).exactly(2).times
|
83
|
+
@box = Box.new
|
84
|
+
@box.sides << BoxSide.new
|
85
|
+
@box.valid?
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should call create callbacks on save when the document is new" do
|
89
|
+
Box.before_create { $pinger.ping }
|
90
|
+
Box.after_create { $pinger.ping }
|
91
|
+
Box.around_create(lambda { $pinger.ping })
|
92
|
+
$pinger.should_receive(:ping).exactly(3).times
|
93
|
+
@box = Box.new
|
94
|
+
@box.save
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should call update callbacks on save when the document is not new" do
|
98
|
+
Box.before_update { $pinger.ping }
|
99
|
+
Box.after_update { $pinger.ping }
|
100
|
+
Box.around_update(lambda { $pinger.ping })
|
101
|
+
$pinger.should_receive(:ping).exactly(3).times
|
102
|
+
@box = Box.new
|
103
|
+
@box.stub!(:new?).and_return(false)
|
104
|
+
@box.save
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should call destroy callbacks" do
|
108
|
+
Box.before_destroy { $pinger.ping }
|
109
|
+
Box.after_destroy { $pinger.ping }
|
110
|
+
Box.around_destroy(lambda { $pinger.ping })
|
111
|
+
$pinger.should_receive(:ping).exactly(3).times
|
112
|
+
@box = Box.new
|
113
|
+
@box.destroy
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should call save and validate callbacks in the correct order" do
|
117
|
+
Box.before_validation { $pinger.ping(:v) }
|
118
|
+
Box.before_save { $pinger.ping(:s) }
|
119
|
+
$pinger.should_receive(:ping).with(:v).ordered
|
120
|
+
$pinger.should_receive(:ping).with(:s).ordered
|
121
|
+
@box = Box.new
|
122
|
+
@box.save
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "validation callbacks" do
|
126
|
+
it "should call validation callbacks" do
|
127
|
+
Box.before_validation { $pinger.ping }
|
128
|
+
Box.after_validation { $pinger.ping }
|
129
|
+
$pinger.should_receive(:ping).twice
|
130
|
+
@box = Box.new
|
131
|
+
@box.valid?
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should call validation callbacks only if the document is new" do
|
135
|
+
Box.before_validation(:on => :create) { $pinger.ping }
|
136
|
+
Box.after_validation(:on => :create) { $pinger.ping }
|
137
|
+
$pinger.should_receive(:ping).twice
|
138
|
+
@box = Box.new
|
139
|
+
@box.valid?
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should not call validation callbacks only if the document is new" do
|
143
|
+
Box.before_validation(:on => :update) { $pinger.ping }
|
144
|
+
Box.after_validation(:on => :update) { $pinger.ping }
|
145
|
+
$pinger.should_not_receive(:ping)
|
146
|
+
@box = Box.new
|
147
|
+
@box.valid?
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should call validation callbacks only if the document is not new" do
|
151
|
+
Box.before_validation(:on => :update) { $pinger.ping }
|
152
|
+
Box.after_validation(:on => :update) { $pinger.ping }
|
153
|
+
$pinger.should_receive(:ping).twice
|
154
|
+
@box = Box.new
|
155
|
+
@box.stub(:new?).and_return(false)
|
156
|
+
@box.valid?
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should not call validation callbacks only if the document is not new" do
|
160
|
+
Box.before_validation(:on => :create) { $pinger.ping }
|
161
|
+
Box.after_validation(:on => :create) { $pinger.ping }
|
162
|
+
$pinger.should_not_receive(:ping)
|
163
|
+
@box = Box.new
|
164
|
+
@box.stub!(:new?).and_return(false)
|
165
|
+
@box.valid?
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
after :each do
|
170
|
+
[:save, :create, :update, :destroy, :validation].each do |type|
|
171
|
+
Box.reset_callbacks(type)
|
172
|
+
BoxSide.reset_callbacks(type)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Ripple
|
4
|
+
module Conflict
|
5
|
+
describe Resolver do
|
6
|
+
it 'is registered as an on conflict hook with Riak::RObject' do
|
7
|
+
Riak::RObject.on_conflict_hooks.should include(described_class.to_proc)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'calling the lambda returned by .to_proc' do
|
11
|
+
let(:sibling_1) { stub(:data => { '_type' => 'User' } ) }
|
12
|
+
let(:sibling_2) { stub(:data => { '_type' => 'User' } ) }
|
13
|
+
let(:user_siblings) { [sibling_1, sibling_2] }
|
14
|
+
let(:wheel_sibling) { stub(:data => { '_type' => 'Wheel' } ) }
|
15
|
+
let(:robject) { stub(:siblings => user_siblings) }
|
16
|
+
let(:resolved_robject) { stub("Resolved RObject") }
|
17
|
+
let(:resolved_document) { stub(:robject => resolved_robject) }
|
18
|
+
|
19
|
+
let!(:resolver) { described_class.new(robject, User) }
|
20
|
+
|
21
|
+
it 'creates a resolver for the appropriate model class, resolves the robject, and returns the resolved robject' do
|
22
|
+
described_class.
|
23
|
+
should_receive(:new).
|
24
|
+
with(robject, User).
|
25
|
+
and_return(resolver)
|
26
|
+
|
27
|
+
resolver.should_receive(:resolve)
|
28
|
+
resolver.stub(:document => resolved_document)
|
29
|
+
|
30
|
+
described_class.to_proc.call(robject).should be(resolved_robject)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns nil and does not attempt resolution when given an robject with siblings of different types' do
|
34
|
+
user_siblings << wheel_sibling
|
35
|
+
described_class.should_not_receive(:new)
|
36
|
+
described_class.to_proc.call(robject).should be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ripple::Conversion do
|
4
|
+
require 'support/models/box'
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
@box = Box.new { |a| a.key = 'some-key' }
|
8
|
+
@box.stub!(:new?).and_return(false)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return the key as an array for to_key" do
|
12
|
+
@box.to_key.should == ['some-key']
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be able to be converted to a param" do
|
16
|
+
@box.to_param.should == 'some-key'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should be able to be converted to a model" do
|
20
|
+
@box.to_model.should == @box
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Time do
|
4
|
+
before { @date_format = Ripple.date_format }
|
5
|
+
after { Ripple.date_format = @date_format }
|
6
|
+
|
7
|
+
it "serializes to JSON in UTC, ISO 8601 format by default" do
|
8
|
+
Time.utc(2010,3,16,12).as_json.should == "2010-03-16T12:00:00Z"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "serializes to JSON in UTC, RFC822 format when specified" do
|
12
|
+
Ripple.date_format = :rfc822
|
13
|
+
Time.utc(2010,3,16,12).as_json.should == "Tue, 16 Mar 2010 12:00:00 -0000"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe Date do
|
18
|
+
before { @date_format = Ripple.date_format }
|
19
|
+
after { Ripple.date_format = @date_format }
|
20
|
+
|
21
|
+
it "serializes to JSON ISO 8601 format by default" do
|
22
|
+
Date.civil(2010,3,16).as_json.should == "2010-03-16"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "serializes to JSON in UTC, RFC822 format when specified" do
|
26
|
+
Ripple.date_format = :rfc822
|
27
|
+
Date.civil(2010,3,16).as_json.should == "16 Mar 2010"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe DateTime do
|
32
|
+
before { @date_format = Ripple.date_format }
|
33
|
+
after { Ripple.date_format = @date_format }
|
34
|
+
|
35
|
+
before :each do
|
36
|
+
Time.zone = :utc
|
37
|
+
end
|
38
|
+
|
39
|
+
it "serializes to JSON in UTC, ISO 8601 format by default" do
|
40
|
+
DateTime.civil(2010,3,16,12).as_json.should == "2010-03-16T12:00:00+00:00"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "serializes to JSON in UTC, RFC822 format when specified" do
|
44
|
+
Ripple.date_format = :rfc822
|
45
|
+
DateTime.civil(2010,3,16,12).as_json.should == "Tue, 16 Mar 2010 12:00:00 +0000"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe ActiveSupport::TimeWithZone do
|
50
|
+
before { @date_format = Ripple.date_format }
|
51
|
+
after { Ripple.date_format = @date_format }
|
52
|
+
|
53
|
+
it "serializes to JSON in UTC, ISO 8601 format by default" do
|
54
|
+
time = Time.utc(2010,3,16,12)
|
55
|
+
zone = ActiveSupport::TimeZone['Alaska']
|
56
|
+
ActiveSupport::TimeWithZone.new(time, zone).as_json.should == "2010-03-16T12:00:00Z"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "serializes to JSON in UTC, RFC822 format when specified" do
|
60
|
+
Ripple.date_format = :rfc822
|
61
|
+
time = Time.utc(2010,3,16,12)
|
62
|
+
zone = ActiveSupport::TimeZone['Alaska']
|
63
|
+
ActiveSupport::TimeWithZone.new(time, zone).as_json.should == "Tue, 16 Mar 2010 12:00:00 -0000"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe String do
|
68
|
+
it "can parse RFC 822 and ISO 8601 times" do
|
69
|
+
'Tue, 16 Mar 2010 12:00:00 -0000'.to_time.should == Time.utc(2010,3,16,12)
|
70
|
+
'2010-03-16T12:00:00Z'.to_time.should == Time.utc(2010,3,16,12)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "can parse RFC 822 and ISO 8601 dates" do
|
74
|
+
'16 Mar 2010'.to_date.should == Date.civil(2010,3,16)
|
75
|
+
'2010-3-16'.to_date.should == Date.civil(2010,3,16)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "can parse RFC 822 and ISO 8601 datetimes" do
|
79
|
+
'Tue, 16 Mar 2010 12:00:00 +0000'.to_datetime.should == DateTime.civil(2010,3,16,12)
|
80
|
+
'2010-03-16T12:00:00+00:00'.to_datetime.should == DateTime.civil(2010,3,16,12)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "Boolean" do
|
85
|
+
it "should be available to properties on documents" do
|
86
|
+
lambda {
|
87
|
+
class BooleanTest
|
88
|
+
include Ripple::Document
|
89
|
+
property :foo, Boolean
|
90
|
+
end
|
91
|
+
}.should_not raise_error(NameError)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe Set do
|
96
|
+
describe "#as_json" do
|
97
|
+
it 'returns an array of the #as_json result of each element' do
|
98
|
+
set = Set.new([stub(:as_json => 's1'), stub(:as_json => 's2')])
|
99
|
+
set.as_json.should =~ ['s1', 's2']
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Ripple
|
4
|
+
module Document
|
5
|
+
describe self do
|
6
|
+
describe "#to_link" do
|
7
|
+
let(:tag) { 'invoices' }
|
8
|
+
let(:document) { Invoice.new }
|
9
|
+
let(:to_link) { document.to_link(tag) }
|
10
|
+
|
11
|
+
it "returns a #{described_class}::Link" do
|
12
|
+
to_link.should be_a(Link)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "sets the document to this document" do
|
16
|
+
to_link.send(:document).should equal(document)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "sets the tag to the given tag" do
|
20
|
+
to_link.tag.should == tag
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe Link do
|
26
|
+
let(:key) { 'the-invoice-key' }
|
27
|
+
let(:tag) { 'invoices' }
|
28
|
+
let(:document) { Invoice.new { |i| i.key = key } }
|
29
|
+
let(:link) { described_class.new(document, tag) }
|
30
|
+
|
31
|
+
it 'does not fetch the key immediately' do
|
32
|
+
document.should_not_receive(:key)
|
33
|
+
link
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#key' do
|
37
|
+
it "returns the document's key" do
|
38
|
+
link.key.should == key
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#bucket' do
|
43
|
+
it "returns the bucket name from the document class" do
|
44
|
+
link.bucket.should == Invoice.bucket_name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#tag' do
|
49
|
+
it 'returns the tag passed to the constructor' do
|
50
|
+
link.tag.should == tag
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#hash" do
|
55
|
+
it 'does not use the key' do
|
56
|
+
document.should_not_receive(:key)
|
57
|
+
link.hash
|
58
|
+
end
|
59
|
+
|
60
|
+
it "uses the document's #hash" do
|
61
|
+
document.should_receive(:hash).and_return(1234)
|
62
|
+
link.hash.should == 1234
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ripple::Document do
|
4
|
+
require 'support/models/page'
|
5
|
+
|
6
|
+
it "should add bucket access methods to classes when included" do
|
7
|
+
(class << Page; self; end).included_modules.should include(Ripple::Document::BucketAccess)
|
8
|
+
Page.should respond_to(:bucket_name)
|
9
|
+
Page.should respond_to(:bucket)
|
10
|
+
Page.should respond_to(:bucket_name=)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should not be embeddable" do
|
14
|
+
Page.should_not be_embeddable
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "equivalence" do
|
18
|
+
before do
|
19
|
+
class Homepage < Page; end
|
20
|
+
class ErrorPage; include Ripple::Document; self.bucket_name = "pages"; end
|
21
|
+
@doc = Page.new
|
22
|
+
@doc2 = Page.new
|
23
|
+
@sub = Homepage.new
|
24
|
+
@error = ErrorPage.new
|
25
|
+
[@doc,@doc2,@sub,@error].each {|d| d.key = "root"; d.stub!(:new?).and_return(false) }
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be == and eql? if the same object, and have the same hash key" do
|
29
|
+
@doc.should == @doc
|
30
|
+
@doc.should eql(@doc)
|
31
|
+
@doc.hash.should == @doc.hash
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should be == and eql? and have the same hash key if instance of same class and key" do
|
35
|
+
@doc.should == @doc2
|
36
|
+
@doc2.should == @doc
|
37
|
+
@doc.should eql(@doc2)
|
38
|
+
@doc2.should eql(@doc)
|
39
|
+
@doc.hash.should == @doc2.hash
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should be == but not eql? and have different hash keys if they have the same key but one is a subclass of the other" do
|
43
|
+
@doc.should == @sub
|
44
|
+
@sub.should == @doc
|
45
|
+
|
46
|
+
@doc.should_not eql(@sub)
|
47
|
+
@sub.should_not eql(@doc)
|
48
|
+
|
49
|
+
@doc.hash.should_not == @sub.hash
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should be == but not eql? and have different hash keys if of the same bucket and key" do
|
53
|
+
@doc.should == @error
|
54
|
+
@error.should == @doc
|
55
|
+
|
56
|
+
@doc.should_not eql(@error)
|
57
|
+
@error.should_not eql(@doc)
|
58
|
+
|
59
|
+
@doc.hash.should_not == @error.hash
|
60
|
+
@error.hash.should_not == @doc.hash
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should not be == or eql? or have the same hash key if new record" do
|
64
|
+
@doc2.stub!(:new?).and_return(true)
|
65
|
+
@doc.should_not == @doc2
|
66
|
+
@doc2.should_not == @doc
|
67
|
+
|
68
|
+
@doc.should_not eql(@doc2)
|
69
|
+
@doc2.should_not eql(@doc)
|
70
|
+
|
71
|
+
@doc.hash.should_not == @doc2.hash
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "ActiveModel compatibility" do
|
76
|
+
include ActiveModel::Lint::Tests
|
77
|
+
|
78
|
+
before :each do
|
79
|
+
@model = Page.new
|
80
|
+
end
|
81
|
+
|
82
|
+
def assert(value, message="")
|
83
|
+
value.should be
|
84
|
+
end
|
85
|
+
|
86
|
+
def assert_kind_of(klass, value)
|
87
|
+
value.should be_kind_of(klass)
|
88
|
+
end
|
89
|
+
|
90
|
+
ActiveModel::Lint::Tests.instance_methods.grep(/^test/).each do |m|
|
91
|
+
it "#{m}" do
|
92
|
+
send(m)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|