better-ripple 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +17 -0
- data/README.md +182 -0
- data/RELEASE_NOTES.md +284 -0
- data/better-ripple.gemspec +55 -0
- data/lib/rails/generators/ripple/configuration/configuration_generator.rb +13 -0
- data/lib/rails/generators/ripple/configuration/templates/ripple.yml +25 -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.erb +10 -0
- data/lib/rails/generators/ripple/observer/observer_generator.rb +16 -0
- data/lib/rails/generators/ripple/observer/templates/observer.rb.erb +2 -0
- data/lib/rails/generators/ripple/test/templates/cucumber.rb.erb +7 -0
- data/lib/rails/generators/ripple/test/test_generator.rb +44 -0
- data/lib/rails/generators/ripple_generator.rb +79 -0
- data/lib/ripple.rb +86 -0
- data/lib/ripple/associations.rb +380 -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 +39 -0
- data/lib/ripple/associations/many_linked_proxy.rb +66 -0
- data/lib/ripple/associations/many_reference_proxy.rb +95 -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 +26 -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 +132 -0
- data/lib/ripple/attribute_methods/dirty.rb +59 -0
- data/lib/ripple/attribute_methods/query.rb +34 -0
- data/lib/ripple/attribute_methods/read.rb +28 -0
- data/lib/ripple/attribute_methods/write.rb +25 -0
- data/lib/ripple/callbacks.rb +71 -0
- data/lib/ripple/conflict/basic_resolver.rb +86 -0
- data/lib/ripple/conflict/document_hooks.rb +46 -0
- data/lib/ripple/conflict/resolver.rb +79 -0
- data/lib/ripple/conflict/test_helper.rb +34 -0
- data/lib/ripple/conversion.rb +29 -0
- data/lib/ripple/core_ext.rb +3 -0
- data/lib/ripple/core_ext/casting.rb +151 -0
- data/lib/ripple/core_ext/indexes.rb +89 -0
- data/lib/ripple/core_ext/object.rb +8 -0
- data/lib/ripple/document.rb +105 -0
- data/lib/ripple/document/bucket_access.rb +25 -0
- data/lib/ripple/document/finders.rb +131 -0
- data/lib/ripple/document/key.rb +35 -0
- data/lib/ripple/document/link.rb +30 -0
- data/lib/ripple/document/persistence.rb +130 -0
- data/lib/ripple/embedded_document.rb +63 -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 +75 -0
- data/lib/ripple/i18n.rb +5 -0
- data/lib/ripple/indexes.rb +151 -0
- data/lib/ripple/inspection.rb +32 -0
- data/lib/ripple/locale/en.yml +26 -0
- data/lib/ripple/locale/fr.yml +24 -0
- data/lib/ripple/nested_attributes.rb +275 -0
- data/lib/ripple/observable.rb +28 -0
- data/lib/ripple/properties.rb +74 -0
- data/lib/ripple/property_type_mismatch.rb +12 -0
- data/lib/ripple/railtie.rb +26 -0
- data/lib/ripple/railties/ripple.rake +103 -0
- data/lib/ripple/serialization.rb +82 -0
- data/lib/ripple/test_server.rb +35 -0
- data/lib/ripple/timestamps.rb +25 -0
- data/lib/ripple/translation.rb +18 -0
- data/lib/ripple/validations.rb +65 -0
- data/lib/ripple/validations/associated_validator.rb +43 -0
- data/lib/ripple/version.rb +3 -0
- metadata +310 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'ripple/associations/proxy'
|
2
|
+
require 'ripple/validations/associated_validator'
|
3
|
+
|
4
|
+
module Ripple
|
5
|
+
module Associations
|
6
|
+
module Embedded
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
super
|
10
|
+
lazy_load_validates_associated
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def lazy_load_validates_associated
|
16
|
+
return if @owner.class.validators_on(@reflection.name).any? {|v| Ripple::Validations::AssociatedValidator === v}
|
17
|
+
@owner.class.validates @reflection.name, :associated => true
|
18
|
+
end
|
19
|
+
|
20
|
+
def assign_references(docs)
|
21
|
+
Array.wrap(docs).each do |doc|
|
22
|
+
next unless doc.respond_to?(:_parent_document=)
|
23
|
+
doc._parent_document = owner
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def instantiate_target(*args)
|
28
|
+
doc = super
|
29
|
+
assign_references(doc)
|
30
|
+
doc
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'ripple/associations'
|
2
|
+
|
3
|
+
module Ripple
|
4
|
+
module Associations
|
5
|
+
module Instantiators
|
6
|
+
|
7
|
+
def build(attrs={})
|
8
|
+
instantiate_target(:new, attrs)
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(attrs={})
|
12
|
+
instantiate_target(:create, attrs)
|
13
|
+
end
|
14
|
+
|
15
|
+
def create!(attrs={})
|
16
|
+
instantiate_target(:create!, attrs)
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
def instantiate_target
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'ripple/associations'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Ripple
|
5
|
+
module Associations
|
6
|
+
module Linked
|
7
|
+
def replace(value)
|
8
|
+
@reflection.verify_type!(value, @owner)
|
9
|
+
@owner.robject.links -= links
|
10
|
+
Array.wrap(value).compact.each do |doc|
|
11
|
+
@owner.robject.links << doc.to_link(@reflection.link_tag)
|
12
|
+
end
|
13
|
+
loaded
|
14
|
+
@keys = nil
|
15
|
+
@target = value
|
16
|
+
end
|
17
|
+
|
18
|
+
def replace_links(value)
|
19
|
+
@owner.robject.links -= links
|
20
|
+
Array(value).each do |link|
|
21
|
+
@owner.robject.links << link
|
22
|
+
end
|
23
|
+
reset
|
24
|
+
end
|
25
|
+
|
26
|
+
def keys
|
27
|
+
@keys ||= Set.new(links.map { |l| l.key })
|
28
|
+
end
|
29
|
+
|
30
|
+
def reset
|
31
|
+
super
|
32
|
+
@keys = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def include?(document)
|
36
|
+
return false unless document.respond_to?(:robject)
|
37
|
+
|
38
|
+
# TODO: when we allow polymorphic assocations, this will have to change
|
39
|
+
# since @reflection.bucket_name will be '_' in that case.
|
40
|
+
return false unless document.robject.bucket.name == @reflection.bucket_name
|
41
|
+
keys.include?(document.key)
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
def links
|
46
|
+
@owner.robject.links.select(&@reflection.link_filter)
|
47
|
+
end
|
48
|
+
|
49
|
+
def robjects
|
50
|
+
walk_result = begin
|
51
|
+
@owner.robject.walk(*Array(@reflection.link_spec)).first || []
|
52
|
+
rescue
|
53
|
+
[]
|
54
|
+
end
|
55
|
+
|
56
|
+
# We can get more robject results that we have links when there is conflict,
|
57
|
+
# since link-walking returns the robjects for the union of all sibling links.
|
58
|
+
# Here, we filter out robjects that should not be included.
|
59
|
+
walk_result.select do |robject|
|
60
|
+
links.include?(robject.to_link(@reflection.link_tag))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'ripple/associations'
|
2
|
+
|
3
|
+
module Ripple
|
4
|
+
module Associations
|
5
|
+
module Many
|
6
|
+
include Instantiators
|
7
|
+
|
8
|
+
def to_ary
|
9
|
+
load_target
|
10
|
+
Array === target ? target.to_ary : Array.wrap(target)
|
11
|
+
end
|
12
|
+
|
13
|
+
def count
|
14
|
+
load_target
|
15
|
+
target.size
|
16
|
+
end
|
17
|
+
|
18
|
+
def reset
|
19
|
+
super
|
20
|
+
@target = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def <<(value)
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
alias_method :push, :<<
|
28
|
+
alias_method :concat, :<<
|
29
|
+
|
30
|
+
protected
|
31
|
+
def instantiate_target(instantiator, attrs={})
|
32
|
+
doc = klass.send(instantiator, attrs)
|
33
|
+
self << doc
|
34
|
+
doc
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'ripple/associations/proxy'
|
2
|
+
require 'ripple/associations/many'
|
3
|
+
require 'ripple/associations/embedded'
|
4
|
+
|
5
|
+
module Ripple
|
6
|
+
module Associations
|
7
|
+
class ManyEmbeddedProxy < Proxy
|
8
|
+
include Many
|
9
|
+
include Embedded
|
10
|
+
|
11
|
+
def <<(docs)
|
12
|
+
load_target
|
13
|
+
docs = Array.wrap(docs)
|
14
|
+
@reflection.verify_type!(docs, @owner)
|
15
|
+
assign_references(docs)
|
16
|
+
@target += docs
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def replace(docs)
|
21
|
+
@reflection.verify_type!(docs, @owner)
|
22
|
+
@_docs = docs.map { |doc| attrs = doc.respond_to?(:attributes_for_persistence) ? doc.attributes_for_persistence : doc }
|
23
|
+
assign_references(docs)
|
24
|
+
reset
|
25
|
+
@_docs
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
def find_target
|
30
|
+
(@_docs || []).map do |attrs|
|
31
|
+
klass.instantiate(attrs).tap do |doc|
|
32
|
+
assign_references(doc)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'ripple/associations/proxy'
|
2
|
+
require 'ripple/associations/many'
|
3
|
+
require 'ripple/associations/linked'
|
4
|
+
|
5
|
+
module Ripple
|
6
|
+
module Associations
|
7
|
+
class ManyLinkedProxy < Proxy
|
8
|
+
include Many
|
9
|
+
include Linked
|
10
|
+
|
11
|
+
def count
|
12
|
+
# avoid having to load all documents by using our keys set instead
|
13
|
+
keys.size
|
14
|
+
end
|
15
|
+
|
16
|
+
def <<(value)
|
17
|
+
if loaded?
|
18
|
+
new_target = @target.concat(Array.wrap(value))
|
19
|
+
replace new_target
|
20
|
+
else
|
21
|
+
@reflection.verify_type!([value], @owner)
|
22
|
+
@owner.robject.links << value.to_link(@reflection.link_tag)
|
23
|
+
appended_documents << value
|
24
|
+
@keys = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete(value)
|
31
|
+
load_target
|
32
|
+
@target.delete(value)
|
33
|
+
replace @target
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def reset
|
38
|
+
@appended_documents = nil
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
def loaded_documents
|
43
|
+
(super + appended_documents).uniq
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def find_target
|
49
|
+
robjs = robjects
|
50
|
+
|
51
|
+
robjs.delete_if do |robj|
|
52
|
+
appended_documents.any? do |doc|
|
53
|
+
doc.key == robj.key &&
|
54
|
+
doc.class.bucket_name == robj.bucket.name
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
appended_documents + robjs.map {|robj| klass.send(:instantiate, robj) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def appended_documents
|
62
|
+
@appended_documents ||= []
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'ripple/associations/proxy'
|
2
|
+
require 'ripple/associations/many'
|
3
|
+
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
module Ripple
|
7
|
+
module Associations
|
8
|
+
class ManyReferenceProxy < Proxy
|
9
|
+
include Many
|
10
|
+
|
11
|
+
def <<(value)
|
12
|
+
values = Array.wrap(value)
|
13
|
+
@reflection.verify_type!(values, @owner)
|
14
|
+
|
15
|
+
values.each {|v| assign_key(v) }
|
16
|
+
load_target
|
17
|
+
@target.merge values
|
18
|
+
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def replace(value)
|
23
|
+
@reflection.verify_type!(value, @owner)
|
24
|
+
delete_all
|
25
|
+
Array.wrap(value).compact.each do |doc|
|
26
|
+
assign_key(doc)
|
27
|
+
end
|
28
|
+
loaded
|
29
|
+
@keys = nil
|
30
|
+
@target = Set.new(value)
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete_all
|
34
|
+
load_target
|
35
|
+
@target.each do |e|
|
36
|
+
delete(e)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete(value)
|
41
|
+
load_target
|
42
|
+
assign_key(value, nil)
|
43
|
+
@target.delete(value)
|
44
|
+
end
|
45
|
+
|
46
|
+
def target
|
47
|
+
load_target
|
48
|
+
@target.to_a
|
49
|
+
end
|
50
|
+
|
51
|
+
def keys
|
52
|
+
@keys ||= Ripple.client.search(klass.bucket_name, "#{key_name}: #{@owner.key}")["response"]["docs"].inject(Set.new) do |set, search_document|
|
53
|
+
set << search_document["id"]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def reset
|
58
|
+
@keys = nil
|
59
|
+
super
|
60
|
+
end
|
61
|
+
|
62
|
+
def include?(document)
|
63
|
+
return false unless document.class.respond_to?(:bucket_name)
|
64
|
+
|
65
|
+
return false unless document.class.bucket_name == @reflection.bucket_name
|
66
|
+
keys.include?(document.key)
|
67
|
+
end
|
68
|
+
|
69
|
+
def count
|
70
|
+
if loaded?
|
71
|
+
@target.count
|
72
|
+
else
|
73
|
+
keys.count
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
def find_target
|
79
|
+
Set.new(klass.find(keys.to_a))
|
80
|
+
end
|
81
|
+
|
82
|
+
def key_name
|
83
|
+
"#{@owner.class.name.underscore}_key"
|
84
|
+
end
|
85
|
+
|
86
|
+
def assign_key(target, key=@owner.key)
|
87
|
+
if target.new_record?
|
88
|
+
target.send("#{key_name}=", key)
|
89
|
+
else
|
90
|
+
target.update_attribute(key_name, key)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'ripple/associations/proxy'
|
2
|
+
require 'ripple/associations/many'
|
3
|
+
|
4
|
+
module Ripple
|
5
|
+
module Associations
|
6
|
+
class ManyStoredKeyProxy < Proxy
|
7
|
+
include Many
|
8
|
+
|
9
|
+
def count
|
10
|
+
keys.size
|
11
|
+
end
|
12
|
+
|
13
|
+
def <<(value)
|
14
|
+
@reflection.verify_type!([value], @owner)
|
15
|
+
|
16
|
+
raise "Unable to append if the document isn't first saved." if value.new_record?
|
17
|
+
load_target
|
18
|
+
@target << value
|
19
|
+
keys << value.key
|
20
|
+
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def replace(value)
|
25
|
+
@reflection.verify_type!(value, @owner)
|
26
|
+
|
27
|
+
reset_owner_keys
|
28
|
+
value.each { |doc| self << doc }
|
29
|
+
@target = value
|
30
|
+
loaded
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete(value)
|
34
|
+
keys.delete(value.key)
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def keys
|
39
|
+
if @owner.send(keys_name).nil?
|
40
|
+
reset_owner_keys
|
41
|
+
end
|
42
|
+
|
43
|
+
@owner.send(keys_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def reset
|
47
|
+
super
|
48
|
+
self.owner_keys = @owner.robject.data ? @owner.robject.data[keys_name] : []
|
49
|
+
end
|
50
|
+
|
51
|
+
def include?(document)
|
52
|
+
return false unless document.respond_to?(:robject)
|
53
|
+
return false unless document.robject.bucket.name == @reflection.bucket_name
|
54
|
+
keys.include?(document.key)
|
55
|
+
end
|
56
|
+
|
57
|
+
def reset_owner_keys
|
58
|
+
self.owner_keys = []
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
protected
|
63
|
+
def find_target
|
64
|
+
klass.find(keys.to_a)
|
65
|
+
end
|
66
|
+
|
67
|
+
def keys_name
|
68
|
+
"#{@reflection.name.to_s.singularize}_keys"
|
69
|
+
end
|
70
|
+
|
71
|
+
def owner_keys=(new_keys)
|
72
|
+
@owner.send("#{keys_name}=", @owner.class.properties[keys_name].type.new(new_keys))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|