ripple 0.9.5 → 1.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +32 -0
- data/Gemfile +10 -9
- data/Guardfile +15 -0
- data/Rakefile +11 -40
- data/lib/rails/generators/ripple/configuration/configuration_generator.rb +0 -13
- data/lib/rails/generators/ripple/configuration/templates/ripple.yml +4 -4
- data/lib/rails/generators/ripple/js/js_generator.rb +0 -13
- data/lib/rails/generators/ripple/js/templates/js/contrib.js +0 -17
- data/lib/rails/generators/ripple/js/templates/js/ripple.js +0 -13
- data/lib/rails/generators/ripple/model/model_generator.rb +0 -14
- data/lib/rails/generators/ripple/model/templates/model.rb +1 -1
- data/lib/rails/generators/ripple/observer/observer_generator.rb +0 -14
- data/lib/rails/generators/ripple/test/test_generator.rb +7 -19
- data/lib/rails/generators/ripple_generator.rb +1 -14
- data/lib/ripple.rb +7 -14
- data/lib/ripple/associations.rb +129 -26
- data/lib/ripple/associations/embedded.rb +1 -15
- data/lib/ripple/associations/instantiators.rb +0 -13
- data/lib/ripple/associations/linked.rb +41 -19
- data/lib/ripple/associations/many.rb +0 -14
- data/lib/ripple/associations/many_embedded_proxy.rb +0 -14
- data/lib/ripple/associations/many_linked_proxy.rb +39 -18
- 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 +1 -15
- data/lib/ripple/associations/one_embedded_proxy.rb +0 -14
- data/lib/ripple/associations/one_key_proxy.rb +58 -0
- data/lib/ripple/associations/one_linked_proxy.rb +4 -14
- data/lib/ripple/associations/one_stored_key_proxy.rb +43 -0
- data/lib/ripple/associations/proxy.rb +8 -14
- data/lib/ripple/attribute_methods.rb +19 -17
- data/lib/ripple/attribute_methods/dirty.rb +19 -15
- data/lib/ripple/attribute_methods/query.rb +0 -14
- data/lib/ripple/attribute_methods/read.rb +0 -14
- data/lib/ripple/attribute_methods/write.rb +0 -14
- data/lib/ripple/callbacks.rb +10 -16
- 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 +0 -14
- data/lib/ripple/core_ext.rb +1 -14
- data/lib/ripple/core_ext/casting.rb +19 -19
- data/lib/ripple/core_ext/object.rb +8 -0
- data/lib/ripple/document.rb +21 -16
- data/lib/ripple/document/bucket_access.rb +0 -14
- data/lib/ripple/document/finders.rb +17 -23
- data/lib/ripple/document/key.rb +8 -28
- data/lib/ripple/document/link.rb +30 -0
- data/lib/ripple/document/persistence.rb +12 -20
- data/lib/ripple/embedded_document.rb +10 -15
- data/lib/ripple/embedded_document/around_callbacks.rb +18 -0
- data/lib/ripple/embedded_document/finders.rb +7 -18
- data/lib/ripple/embedded_document/persistence.rb +5 -17
- data/lib/ripple/i18n.rb +0 -14
- data/lib/ripple/inspection.rb +21 -15
- data/lib/ripple/locale/en.yml +9 -13
- data/lib/ripple/nested_attributes.rb +33 -39
- data/lib/ripple/observable.rb +0 -13
- data/lib/ripple/properties.rb +1 -14
- data/lib/ripple/property_type_mismatch.rb +0 -14
- data/lib/ripple/railtie.rb +4 -14
- data/lib/ripple/railties/ripple.rake +86 -0
- data/lib/ripple/serialization.rb +11 -11
- data/lib/ripple/test_server.rb +36 -0
- data/lib/ripple/timestamps.rb +0 -13
- data/lib/ripple/translation.rb +4 -14
- data/lib/ripple/validations.rb +1 -15
- data/lib/ripple/validations/associated_validator.rb +26 -17
- data/lib/ripple/version.rb +3 -0
- data/ripple.gemspec +24 -35
- data/spec/integration/ripple/associations_spec.rb +89 -58
- data/spec/integration/ripple/conflict_resolution_spec.rb +298 -0
- data/spec/integration/ripple/nested_attributes_spec.rb +19 -19
- data/spec/integration/ripple/persistence_spec.rb +15 -34
- data/spec/integration/ripple/search_associations_spec.rb +31 -0
- data/spec/ripple/associations/many_embedded_proxy_spec.rb +23 -36
- data/spec/ripple/associations/many_linked_proxy_spec.rb +133 -45
- 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 +24 -37
- data/spec/ripple/associations/one_key_proxy_spec.rb +82 -0
- data/spec/ripple/associations/one_linked_proxy_spec.rb +22 -23
- data/spec/ripple/associations/one_stored_key_proxy_spec.rb +72 -0
- data/spec/ripple/associations/proxy_spec.rb +21 -15
- data/spec/ripple/associations_spec.rb +54 -23
- data/spec/ripple/attribute_methods/dirty_spec.rb +56 -5
- data/spec/ripple/attribute_methods_spec.rb +47 -21
- data/spec/ripple/bucket_access_spec.rb +4 -17
- data/spec/ripple/callbacks_spec.rb +52 -15
- data/spec/ripple/conflict/resolver_spec.rb +42 -0
- data/spec/ripple/conversion_spec.rb +2 -15
- data/spec/ripple/core_ext_spec.rb +12 -15
- data/spec/ripple/document/link_spec.rb +67 -0
- data/spec/ripple/document_spec.rb +34 -19
- data/spec/ripple/embedded_document/finders_spec.rb +12 -19
- data/spec/ripple/embedded_document/persistence_spec.rb +20 -26
- data/spec/ripple/embedded_document_spec.rb +44 -34
- data/spec/ripple/finders_spec.rb +58 -29
- data/spec/ripple/inspection_spec.rb +40 -37
- data/spec/ripple/key_spec.rb +5 -17
- data/spec/ripple/observable_spec.rb +3 -16
- data/spec/ripple/persistence_spec.rb +134 -18
- data/spec/ripple/properties_spec.rb +21 -15
- data/spec/ripple/ripple_spec.rb +1 -14
- data/spec/ripple/serialization_spec.rb +16 -17
- data/spec/ripple/timestamps_spec.rb +73 -52
- data/spec/ripple/validations/associated_validator_spec.rb +69 -25
- data/spec/ripple/validations_spec.rb +3 -16
- data/spec/spec_helper.rb +17 -18
- data/spec/support/associations.rb +1 -1
- data/spec/support/associations/proxies.rb +0 -13
- data/spec/support/integration_setup.rb +11 -0
- data/spec/support/mocks.rb +0 -13
- data/spec/support/models.rb +33 -2
- data/spec/support/models/address.rb +1 -16
- data/spec/support/models/box.rb +7 -14
- data/spec/support/models/car.rb +27 -1
- data/spec/support/models/cardboard_box.rb +0 -14
- data/spec/support/models/clock.rb +6 -15
- data/spec/support/models/clock_observer.rb +0 -14
- data/spec/support/models/credit_card.rb +5 -0
- data/spec/support/models/customer.rb +0 -14
- data/spec/support/models/email.rb +0 -14
- data/spec/support/models/family.rb +1 -13
- data/spec/support/models/favorite.rb +0 -14
- data/spec/support/models/invoice.rb +0 -14
- data/spec/support/models/late_invoice.rb +0 -14
- data/spec/support/models/nested.rb +12 -0
- data/spec/support/models/ninja.rb +7 -0
- data/spec/support/models/note.rb +0 -14
- data/spec/support/models/page.rb +1 -15
- data/spec/support/models/paid_invoice.rb +0 -14
- data/spec/support/models/post.rb +12 -0
- data/spec/support/models/profile.rb +7 -0
- data/spec/support/models/subscription.rb +26 -0
- data/spec/support/models/tasks.rb +0 -18
- data/spec/support/models/team.rb +11 -0
- data/spec/support/models/transactions.rb +17 -0
- data/spec/support/models/tree.rb +2 -16
- data/spec/support/models/user.rb +14 -16
- data/spec/support/models/widget.rb +8 -14
- data/spec/support/search.rb +14 -0
- data/spec/support/test_server.rb +22 -12
- data/spec/support/test_server.yml.example +14 -2
- metadata +223 -59
- data/lib/rails/generators/ripple/test/templates/test_server.rb +0 -46
- data/spec/support/models/driver.rb +0 -5
- data/spec/support/models/engine.rb +0 -4
- data/spec/support/models/passenger.rb +0 -5
- data/spec/support/models/seat.rb +0 -4
- data/spec/support/models/wheel.rb +0 -5
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'ripple/associations/proxy'
|
2
|
+
require 'ripple/associations/one'
|
3
|
+
|
4
|
+
module Ripple
|
5
|
+
module Associations
|
6
|
+
class OneKeyProxy < Proxy
|
7
|
+
include One
|
8
|
+
|
9
|
+
def replace(doc)
|
10
|
+
@reflection.verify_type!(doc, owner)
|
11
|
+
|
12
|
+
reset_previous_target_key_delegate
|
13
|
+
assign_new_target_key_delegate(doc)
|
14
|
+
|
15
|
+
loaded
|
16
|
+
@target = doc
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_target
|
20
|
+
klass.find(owner.key)
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
def instantiate_target(instantiator, attrs={})
|
25
|
+
@target = super
|
26
|
+
@target.key = owner.key
|
27
|
+
@target
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def reset_previous_target_key_delegate
|
32
|
+
@target.key_delegate = @target if @target
|
33
|
+
end
|
34
|
+
|
35
|
+
def assign_new_target_key_delegate(doc)
|
36
|
+
doc.class.send(:include, Ripple::Associations::KeyDelegator) unless doc.class.include?(Ripple::Associations::KeyDelegator)
|
37
|
+
owner.key_delegate = doc.key_delegate = owner
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
module KeyDelegator
|
43
|
+
attr_accessor :key_delegate
|
44
|
+
|
45
|
+
def key_delegate
|
46
|
+
@key_delegate || self
|
47
|
+
end
|
48
|
+
|
49
|
+
def key
|
50
|
+
self === key_delegate ? super : key_delegate.key
|
51
|
+
end
|
52
|
+
|
53
|
+
def key=(value)
|
54
|
+
self === key_delegate ? super(value) : key_delegate.key = value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,17 +1,3 @@
|
|
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
|
-
|
15
1
|
require 'ripple/associations/proxy'
|
16
2
|
require 'ripple/associations/one'
|
17
3
|
require 'ripple/associations/linked'
|
@@ -22,6 +8,10 @@ module Ripple
|
|
22
8
|
include One
|
23
9
|
include Linked
|
24
10
|
|
11
|
+
def key
|
12
|
+
keys.first
|
13
|
+
end
|
14
|
+
|
25
15
|
protected
|
26
16
|
def find_target
|
27
17
|
return nil if links.blank?
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'ripple/associations/proxy'
|
2
|
+
require 'ripple/associations/one'
|
3
|
+
|
4
|
+
module Ripple
|
5
|
+
module Associations
|
6
|
+
class OneStoredKeyProxy < Proxy
|
7
|
+
include One
|
8
|
+
|
9
|
+
def replace(value)
|
10
|
+
@reflection.verify_type!(value, owner)
|
11
|
+
|
12
|
+
if value
|
13
|
+
assign_key(value.key)
|
14
|
+
else
|
15
|
+
assign_key(nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
@target = value
|
19
|
+
loaded
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def key
|
25
|
+
@owner.send(key_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
def assign_key(value)
|
29
|
+
@owner.send("#{key_name}=", value)
|
30
|
+
end
|
31
|
+
|
32
|
+
def key_name
|
33
|
+
"#{@reflection.name}_key"
|
34
|
+
end
|
35
|
+
|
36
|
+
def find_target
|
37
|
+
return nil if key.blank?
|
38
|
+
|
39
|
+
klass.find(key)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,17 +1,3 @@
|
|
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
|
-
|
15
1
|
require 'ripple/associations'
|
16
2
|
|
17
3
|
module Ripple
|
@@ -99,6 +85,14 @@ module Ripple
|
|
99
85
|
other === target
|
100
86
|
end
|
101
87
|
|
88
|
+
def loaded_documents
|
89
|
+
loaded? ? Array(target) : []
|
90
|
+
end
|
91
|
+
|
92
|
+
def has_changed_documents?
|
93
|
+
loaded_documents.any? { |doc| doc.changed? }
|
94
|
+
end
|
95
|
+
|
102
96
|
protected
|
103
97
|
def method_missing(method, *args, &block)
|
104
98
|
load_target
|
@@ -1,17 +1,3 @@
|
|
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
|
-
|
15
1
|
require 'ripple/translation'
|
16
2
|
require 'active_support/concern'
|
17
3
|
require 'active_model/attribute_methods'
|
@@ -35,7 +21,7 @@ module Ripple
|
|
35
21
|
include Query
|
36
22
|
include Dirty
|
37
23
|
include ActiveModel::MassAssignmentSecurity
|
38
|
-
|
24
|
+
|
39
25
|
attr_protected :key
|
40
26
|
end
|
41
27
|
|
@@ -59,6 +45,10 @@ module Ripple
|
|
59
45
|
# nor embedded documents.
|
60
46
|
# @return [Hash] all document attributes, by key
|
61
47
|
def attributes
|
48
|
+
raw_attributes.reject { |k, v| !respond_to?(k) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def raw_attributes
|
62
52
|
self.class.properties.values.inject(@attributes.with_indifferent_access) do |hash, prop|
|
63
53
|
hash[prop.key] = attribute(prop.key)
|
64
54
|
hash
|
@@ -67,9 +57,21 @@ module Ripple
|
|
67
57
|
|
68
58
|
# Mass assign the document's attributes.
|
69
59
|
# @param [Hash] attrs the attributes to assign
|
70
|
-
def attributes=(attrs
|
60
|
+
def attributes=(attrs)
|
61
|
+
raise ArgumentError, t('attribute_hash') unless Hash === attrs
|
62
|
+
sanitize_for_mass_assignment(attrs).each do |k,v|
|
63
|
+
if respond_to?("#{k}=")
|
64
|
+
__send__("#{k}=",v)
|
65
|
+
else
|
66
|
+
raise ArgumentError, t('undefined_property', :prop => k, :class => self.class.name)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# @private
|
72
|
+
def raw_attributes=(attrs)
|
71
73
|
raise ArgumentError, t('attribute_hash') unless Hash === attrs
|
72
|
-
|
74
|
+
attrs.each do |k,v|
|
73
75
|
next if k.to_sym == :key
|
74
76
|
if respond_to?("#{k}=")
|
75
77
|
__send__("#{k}=",v)
|
@@ -1,17 +1,3 @@
|
|
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
|
-
|
15
1
|
require 'active_support/concern'
|
16
2
|
require 'active_model/dirty'
|
17
3
|
|
@@ -21,6 +7,15 @@ module Ripple
|
|
21
7
|
extend ActiveSupport::Concern
|
22
8
|
include ActiveModel::Dirty
|
23
9
|
|
10
|
+
module ClassMethods
|
11
|
+
# @private
|
12
|
+
def instantiate(robject)
|
13
|
+
super(robject).tap do |o|
|
14
|
+
o.changed_attributes.clear
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
24
19
|
# @private
|
25
20
|
def really_save(*args)
|
26
21
|
if result = super
|
@@ -43,9 +38,18 @@ module Ripple
|
|
43
38
|
changed_attributes.clear
|
44
39
|
end
|
45
40
|
|
41
|
+
# Determines if the document has any chnages.
|
42
|
+
# @return [Boolean] true if this document, or any of its embedded
|
43
|
+
# documents at any level, have changed.
|
44
|
+
def changed?
|
45
|
+
super || self.class.embedded_associations.any? do |association|
|
46
|
+
send(association.name).has_changed_documents?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
46
50
|
private
|
47
51
|
def attribute=(attr_name, value)
|
48
|
-
if self.class.properties.include?(attr_name.
|
52
|
+
if self.class.properties.include?(attr_name.to_sym) && @attributes[attr_name] != value
|
49
53
|
attribute_will_change!(attr_name)
|
50
54
|
end
|
51
55
|
super
|
@@ -1,17 +1,3 @@
|
|
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
|
-
|
15
1
|
require 'active_support/concern'
|
16
2
|
|
17
3
|
module Ripple
|
@@ -1,17 +1,3 @@
|
|
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
|
-
|
15
1
|
require 'active_support/concern'
|
16
2
|
|
17
3
|
module Ripple
|
@@ -1,17 +1,3 @@
|
|
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
|
-
|
15
1
|
require 'active_support/concern'
|
16
2
|
|
17
3
|
module Ripple
|
data/lib/ripple/callbacks.rb
CHANGED
@@ -1,17 +1,3 @@
|
|
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
|
-
|
15
1
|
require 'active_support/concern'
|
16
2
|
require 'active_model/callbacks'
|
17
3
|
|
@@ -21,9 +7,11 @@ module Ripple
|
|
21
7
|
module Callbacks
|
22
8
|
extend ActiveSupport::Concern
|
23
9
|
|
10
|
+
CALLBACK_TYPES = [:create, :update, :save, :destroy, :validation]
|
11
|
+
|
24
12
|
included do
|
25
13
|
extend ActiveModel::Callbacks
|
26
|
-
define_model_callbacks
|
14
|
+
define_model_callbacks *(CALLBACK_TYPES - [:validation])
|
27
15
|
define_callbacks :validation, :terminator => "result == false", :scope => [:kind, :name]
|
28
16
|
end
|
29
17
|
|
@@ -53,10 +41,16 @@ module Ripple
|
|
53
41
|
module InstanceMethods
|
54
42
|
# @private
|
55
43
|
def really_save(*args, &block)
|
44
|
+
run_save_callbacks do
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def run_save_callbacks
|
56
50
|
state = new? ? :create : :update
|
57
51
|
run_callbacks(:save) do
|
58
52
|
run_callbacks(state) do
|
59
|
-
|
53
|
+
yield
|
60
54
|
end
|
61
55
|
end
|
62
56
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Ripple
|
2
|
+
module Conflict
|
3
|
+
class BasicResolver
|
4
|
+
delegate :model_class, :document, :siblings, :to => :@main_resolver
|
5
|
+
|
6
|
+
def initialize(main_resolver)
|
7
|
+
@main_resolver = main_resolver
|
8
|
+
end
|
9
|
+
|
10
|
+
def remaining_conflicts
|
11
|
+
@remaining_conflicts ||= []
|
12
|
+
end
|
13
|
+
|
14
|
+
def unexpected_conflicts
|
15
|
+
# if the user didn't specify the conflict they expect,
|
16
|
+
# then don't consider any conflicts unexpected
|
17
|
+
return [] if model_class.expected_conflicts.blank?
|
18
|
+
|
19
|
+
remaining_conflicts - model_class.expected_conflicts
|
20
|
+
end
|
21
|
+
|
22
|
+
def perform
|
23
|
+
process_properties
|
24
|
+
process_embedded_associations
|
25
|
+
process_linked_associations
|
26
|
+
process_stored_key_associations
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def process_properties
|
32
|
+
model_class.properties.each do |name, property|
|
33
|
+
document.send(:"#{name}=", resolved_property_value_for(property))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_embedded_associations
|
38
|
+
model_class.embedded_associations.each do |assoc|
|
39
|
+
document.send(:"#{assoc.name}=", resolved_association_value_for(assoc, :load_target))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def process_linked_associations
|
44
|
+
model_class.linked_associations.each do |assoc|
|
45
|
+
document.send(assoc.name).replace_links(resolved_association_value_for(assoc, :links))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def process_stored_key_associations
|
50
|
+
model_class.stored_key_associations.each do |assoc|
|
51
|
+
document.send(assoc.name).reset_owner_keys if (assoc.type == :many)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def resolved_property_value_for(property)
|
56
|
+
uniq_values = siblings.map(&property.key).uniq
|
57
|
+
|
58
|
+
value = if uniq_values.size == 1
|
59
|
+
uniq_values.first
|
60
|
+
elsif property.key == :updated_at
|
61
|
+
uniq_values.compact.max
|
62
|
+
elsif property.key == :created_at
|
63
|
+
uniq_values.compact.min
|
64
|
+
else
|
65
|
+
remaining_conflicts << property.key
|
66
|
+
property.default
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def resolved_association_value_for(association, proxy_value_method)
|
71
|
+
# the association proxy doesn't uniquify well, so we have to use the target or links directly
|
72
|
+
uniq_values = siblings.map { |s| s.send(association.name).__send__(proxy_value_method) }.uniq
|
73
|
+
|
74
|
+
return uniq_values.first if uniq_values.size == 1
|
75
|
+
remaining_conflicts << association.name
|
76
|
+
|
77
|
+
association.many? ? [] : nil # default value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|