ripple 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/lib/ripple.rb +17 -1
  2. data/lib/ripple/associations.rb +157 -0
  3. data/lib/ripple/associations/embedded.rb +42 -0
  4. data/lib/ripple/associations/instantiators.rb +39 -0
  5. data/lib/ripple/{document/associations → associations}/linked.rb +9 -11
  6. data/lib/ripple/{document/associations/one_embedded_proxy.rb → associations/many.rb} +30 -21
  7. data/lib/ripple/{document/associations/embedded.rb → associations/many_embedded_proxy.rb} +26 -23
  8. data/lib/ripple/{embedded_document/conversion.rb → associations/one.rb} +8 -13
  9. data/lib/ripple/{document/associations/instantiators.rb → associations/one_embedded_proxy.rb} +17 -19
  10. data/lib/ripple/associations/proxy.rb +123 -0
  11. data/lib/ripple/attribute_methods.rb +116 -0
  12. data/lib/ripple/{document/attribute_methods/write.rb → attribute_methods/dirty.rb} +26 -16
  13. data/lib/ripple/attribute_methods/query.rb +48 -0
  14. data/lib/ripple/{document/attribute_methods → attribute_methods}/read.rb +16 -18
  15. data/lib/ripple/attribute_methods/write.rb +38 -0
  16. data/lib/ripple/callbacks.rb +73 -0
  17. data/lib/ripple/{document/associations/one.rb → conversion.rb} +18 -13
  18. data/lib/ripple/document.rb +19 -9
  19. data/lib/ripple/embedded_document.rb +10 -10
  20. data/lib/ripple/embedded_document/persistence.rb +12 -53
  21. data/lib/ripple/properties.rb +83 -0
  22. data/lib/ripple/timestamps.rb +34 -0
  23. data/lib/ripple/{document/validations.rb → validations.rb} +31 -33
  24. data/lib/ripple/{document/validations → validations}/associated_validator.rb +9 -10
  25. data/spec/integration/ripple/associations_spec.rb +1 -2
  26. data/spec/integration/ripple/persistence_spec.rb +2 -3
  27. data/spec/ripple/associations/many_embedded_proxy_spec.rb +2 -2
  28. data/spec/ripple/associations/one_embedded_proxy_spec.rb +2 -2
  29. data/spec/ripple/associations/proxy_spec.rb +1 -1
  30. data/spec/ripple/associations_spec.rb +15 -20
  31. data/spec/ripple/attribute_methods_spec.rb +3 -6
  32. data/spec/ripple/callbacks_spec.rb +1 -1
  33. data/spec/ripple/{embedded_document/conversion_spec.rb → conversion_spec.rb} +4 -4
  34. data/spec/ripple/embedded_document/persistence_spec.rb +4 -16
  35. data/spec/ripple/properties_spec.rb +17 -18
  36. data/spec/ripple/timestamps_spec.rb +1 -1
  37. data/spec/ripple/validations_spec.rb +1 -1
  38. data/spec/spec_helper.rb +1 -1
  39. data/spec/support/associations/proxies.rb +4 -4
  40. metadata +27 -29
  41. data/lib/ripple/document/associations.rb +0 -154
  42. data/lib/ripple/document/associations/many.rb +0 -52
  43. data/lib/ripple/document/associations/many_embedded_proxy.rb +0 -49
  44. data/lib/ripple/document/associations/proxy.rb +0 -125
  45. data/lib/ripple/document/attribute_methods.rb +0 -118
  46. data/lib/ripple/document/attribute_methods/dirty.rb +0 -52
  47. data/lib/ripple/document/attribute_methods/query.rb +0 -49
  48. data/lib/ripple/document/callbacks.rb +0 -75
  49. data/lib/ripple/document/properties.rb +0 -85
  50. data/lib/ripple/document/timestamps.rb +0 -22
  51. data/spec/support/integration.rb +0 -4
data/lib/ripple.rb CHANGED
@@ -23,9 +23,25 @@ module Ripple
23
23
  extend ActiveSupport::Autoload
24
24
  include ActiveSupport::Configurable
25
25
 
26
+ # Primary models
26
27
  autoload :EmbeddedDocument
27
28
  autoload :Document
29
+
30
+ # Model mixins and support classes
31
+ autoload :Association, "ripple/associations"
32
+ autoload :Associations
33
+ autoload :AttributeMethods
34
+ autoload :Callbacks
35
+ autoload :Conversion
36
+ autoload :Properties
37
+ autoload :Property, "ripple/properties"
38
+ autoload :Timestamps
39
+ autoload :Validations
40
+
41
+ # Exceptions
28
42
  autoload :PropertyTypeMismatch
43
+
44
+ # Utilities
29
45
  autoload :Translation
30
46
 
31
47
  DEFAULT_CONFIG = {}
@@ -46,7 +62,7 @@ module Ripple
46
62
  self.client = nil
47
63
  super
48
64
  end
49
-
65
+
50
66
  def load_config(config_file)
51
67
  self.config = YAML.load_file(File.expand_path config_file).with_indifferent_access[:ripple]
52
68
  end
@@ -0,0 +1,157 @@
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
+ require 'ripple'
15
+
16
+ module Ripple
17
+ module Associations
18
+ extend ActiveSupport::Concern
19
+ extend ActiveSupport::Autoload
20
+
21
+ autoload :Proxy
22
+ autoload :One
23
+ autoload :Many
24
+ autoload :Embedded
25
+ autoload :Instantiators
26
+ autoload :OneEmbeddedProxy
27
+ autoload :ManyEmbeddedProxy
28
+
29
+ module ClassMethods
30
+ # @private
31
+ def inherited(subclass)
32
+ super
33
+ subclass.associations.merge!(associations)
34
+ end
35
+
36
+ # Associations defined on the document
37
+ def associations
38
+ @associations ||= {}.with_indifferent_access
39
+ end
40
+
41
+ # Associations of embedded documents
42
+ def embedded_associations
43
+ associations.values.select(&:embeddable?)
44
+ end
45
+
46
+ # Creates a singular association
47
+ def one(name, options={})
48
+ create_association(:one, name, options)
49
+ end
50
+
51
+ # Creates a plural association
52
+ def many(name, options={})
53
+ create_association(:many, name, options)
54
+ end
55
+
56
+ private
57
+ def create_association(type, name, options={})
58
+ association = associations[name] = Association.new(type, name, options)
59
+
60
+ define_method(name) do
61
+ get_proxy(association)
62
+ end
63
+
64
+ define_method("#{name}=") do |value|
65
+ get_proxy(association).replace(value)
66
+ value
67
+ end
68
+
69
+ if association.one?
70
+ define_method("#{name}?") do
71
+ get_proxy(association).present?
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ module InstanceMethods
78
+ # @private
79
+ def get_proxy(association)
80
+ unless proxy = instance_variable_get(association.ivar)
81
+ proxy = association.proxy_class.new(self, association)
82
+ instance_variable_set(association.ivar, proxy)
83
+ end
84
+ proxy
85
+ end
86
+
87
+ # Adds embedded documents to the attributes
88
+ # @private
89
+ def attributes_for_persistence
90
+ self.class.embedded_associations.inject(super) do |attrs, association|
91
+ if documents = instance_variable_get(association.ivar)
92
+ attrs[association.name] = documents.is_a?(Array) ? documents.map(&:attributes_for_persistence) : documents.attributes_for_persistence
93
+ end
94
+ attrs
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ class Association
101
+ attr_reader :type, :name, :options
102
+
103
+ # association options :using, :class_name, :class, :extend,
104
+ # options that may be added :validate
105
+
106
+ def initialize(type, name, options={})
107
+ @type, @name, @options = type, name, options.to_options
108
+ end
109
+
110
+ def class_name
111
+ @class_name ||= case
112
+ when @options[:class_name]
113
+ @options[:class_name]
114
+ when @options[:class]
115
+ @options[:class].to_s
116
+ when many?
117
+ @name.to_s.classify
118
+ else
119
+ @name.to_s.camelize
120
+ end
121
+ end
122
+
123
+ def klass
124
+ @klass ||= options[:class] || class_name.constantize
125
+ end
126
+
127
+ def many?
128
+ @type == :many
129
+ end
130
+
131
+ def one?
132
+ @type == :one
133
+ end
134
+
135
+ def embeddable?
136
+ klass.embeddable?
137
+ end
138
+
139
+ def polymorphic?
140
+ false
141
+ end
142
+
143
+ def ivar
144
+ "@_#{name}"
145
+ end
146
+
147
+ def proxy_class
148
+ @proxy_class ||= proxy_class_name.constantize
149
+ end
150
+
151
+ def proxy_class_name
152
+ @using ||= options[:using] || (embeddable? ? :embedded : :link)
153
+ klass_name = (many? ? 'Many' : 'One') + @using.to_s.camelize + ('Polymorphic' if polymorphic?).to_s + 'Proxy'
154
+ "Ripple::Associations::#{klass_name}"
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,42 @@
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
+ require 'ripple'
15
+
16
+ module Ripple
17
+ module Associations
18
+ module Embedded
19
+
20
+ def initialize(*args)
21
+ super
22
+ owner.class.validates reflection.name, :associated => true
23
+ end
24
+
25
+ protected
26
+
27
+ def assign_references(docs)
28
+ Array(docs).each do |doc|
29
+ next unless doc.respond_to?(:_parent_document=)
30
+ doc._parent_document = owner
31
+ end
32
+ end
33
+
34
+ def instantiate_target(*args)
35
+ doc = super
36
+ assign_references(doc)
37
+ doc
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,39 @@
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
+ require 'ripple'
15
+
16
+ module Ripple
17
+ module Associations
18
+ module Instantiators
19
+
20
+ def build(attrs={})
21
+ instantiate_target(:new, attrs)
22
+ end
23
+
24
+ def create(attrs={})
25
+ instantiate_target(:create, attrs)
26
+ end
27
+
28
+ def create!(attrs={})
29
+ instantiate_target(:create!, attrs)
30
+ end
31
+
32
+ protected
33
+ def instantiate_target
34
+ raise NotImplementedError
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -14,19 +14,17 @@
14
14
  require 'ripple'
15
15
 
16
16
  module Ripple
17
- module Document
18
- module Associations
19
- module Linked
17
+ module Associations
18
+ module Linked
20
19
 
21
- def create(attrs={})
22
- instantiate_target(:create, attrs)
23
- end
20
+ def create(attrs={})
21
+ instantiate_target(:create, attrs)
22
+ end
24
23
 
25
- def create!(attrs={})
26
- instantiate_target(:create!, attrs)
27
- end
28
-
24
+ def create!(attrs={})
25
+ instantiate_target(:create!, attrs)
29
26
  end
27
+
30
28
  end
31
29
  end
32
- end
30
+ end
@@ -14,28 +14,37 @@
14
14
  require 'ripple'
15
15
 
16
16
  module Ripple
17
- module Document
18
- module Associations
19
- class OneEmbeddedProxy < Proxy
20
- include One
21
- include Embedded
22
-
23
- def replace(doc)
24
- @_doc = doc.respond_to?(:attributes_for_persistence) ? doc.attributes_for_persistence : doc
25
- assign_references(doc)
26
- reset
27
- @_doc
28
- end
29
-
17
+ module Associations
18
+ module Many
19
+ include Instantiators
20
+
21
+ def to_ary
22
+ load_target
23
+ Array === target ? target.to_ary : Array(target)
24
+ end
25
+
26
+ def count
27
+ load_target
28
+ target.size
29
+ end
30
+
31
+ def reset
32
+ super
33
+ @target = []
34
+ end
35
+
36
+ def <<
37
+ raise NotImplementedError
38
+ end
39
+ alias_method :push, :<<
40
+ alias_method :concat, :<<
41
+
30
42
  protected
31
- def find_target
32
- return nil unless @_doc
33
- klass.instantiate(@_doc).tap do |doc|
34
- assign_references(doc)
35
- end
36
- end
37
-
43
+ def instantiate_target(instantiator, attrs={})
44
+ doc = klass.send(instantiator, attrs)
45
+ self << doc
46
+ doc
38
47
  end
39
48
  end
40
49
  end
41
- end
50
+ end
@@ -14,31 +14,34 @@
14
14
  require 'ripple'
15
15
 
16
16
  module Ripple
17
- module Document
18
- module Associations
19
- module Embedded
20
-
21
- def initialize(*args)
22
- super
23
- owner.class.validates reflection.name, :associated => true
24
- end
25
-
26
- protected
27
-
28
- def assign_references(docs)
29
- Array(docs).each do |doc|
30
- next unless doc.respond_to?(:_parent_document=)
31
- doc._parent_document = owner
32
- end
33
- end
34
-
35
- def instantiate_target(*args)
36
- doc = super
17
+ module Associations
18
+ class ManyEmbeddedProxy < Proxy
19
+ include Many
20
+ include Embedded
21
+
22
+ def <<(docs)
23
+ load_target
24
+ assign_references(docs)
25
+ @target += Array(docs)
26
+ self
27
+ end
28
+
29
+ def replace(docs)
30
+ @_docs = docs.map { |doc| attrs = doc.respond_to?(:attributes_for_persistence) ? doc.attributes_for_persistence : doc }
31
+ assign_references(docs)
32
+ reset
33
+ @_docs
34
+ end
35
+
36
+ protected
37
+ def find_target
38
+ (@_docs || []).map do |attrs|
39
+ klass.instantiate(attrs).tap do |doc|
37
40
  assign_references(doc)
38
- doc
39
41
  end
40
-
42
+ end
41
43
  end
44
+
42
45
  end
43
46
  end
44
- end
47
+ end
@@ -14,20 +14,15 @@
14
14
  require 'ripple'
15
15
 
16
16
  module Ripple
17
- module EmbeddedDocument
18
- module Conversion
19
- extend ActiveSupport::Concern
17
+ module Associations
18
+ module One
19
+ include Instantiators
20
20
 
21
- module InstanceMethods
22
- include ActiveModel::Conversion
23
-
24
- def to_key
25
- new? ? nil : [key]
26
- end
27
-
28
- def to_param
29
- key
30
- end
21
+ protected
22
+ def instantiate_target(instantiator, attrs={})
23
+ @target = klass.send(instantiator, attrs)
24
+ loaded
25
+ @target
31
26
  end
32
27
  end
33
28
  end