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.
Files changed (152) hide show
  1. data/.gitignore +32 -0
  2. data/Gemfile +10 -9
  3. data/Guardfile +15 -0
  4. data/Rakefile +11 -40
  5. data/lib/rails/generators/ripple/configuration/configuration_generator.rb +0 -13
  6. data/lib/rails/generators/ripple/configuration/templates/ripple.yml +4 -4
  7. data/lib/rails/generators/ripple/js/js_generator.rb +0 -13
  8. data/lib/rails/generators/ripple/js/templates/js/contrib.js +0 -17
  9. data/lib/rails/generators/ripple/js/templates/js/ripple.js +0 -13
  10. data/lib/rails/generators/ripple/model/model_generator.rb +0 -14
  11. data/lib/rails/generators/ripple/model/templates/model.rb +1 -1
  12. data/lib/rails/generators/ripple/observer/observer_generator.rb +0 -14
  13. data/lib/rails/generators/ripple/test/test_generator.rb +7 -19
  14. data/lib/rails/generators/ripple_generator.rb +1 -14
  15. data/lib/ripple.rb +7 -14
  16. data/lib/ripple/associations.rb +129 -26
  17. data/lib/ripple/associations/embedded.rb +1 -15
  18. data/lib/ripple/associations/instantiators.rb +0 -13
  19. data/lib/ripple/associations/linked.rb +41 -19
  20. data/lib/ripple/associations/many.rb +0 -14
  21. data/lib/ripple/associations/many_embedded_proxy.rb +0 -14
  22. data/lib/ripple/associations/many_linked_proxy.rb +39 -18
  23. data/lib/ripple/associations/many_reference_proxy.rb +93 -0
  24. data/lib/ripple/associations/many_stored_key_proxy.rb +76 -0
  25. data/lib/ripple/associations/one.rb +1 -15
  26. data/lib/ripple/associations/one_embedded_proxy.rb +0 -14
  27. data/lib/ripple/associations/one_key_proxy.rb +58 -0
  28. data/lib/ripple/associations/one_linked_proxy.rb +4 -14
  29. data/lib/ripple/associations/one_stored_key_proxy.rb +43 -0
  30. data/lib/ripple/associations/proxy.rb +8 -14
  31. data/lib/ripple/attribute_methods.rb +19 -17
  32. data/lib/ripple/attribute_methods/dirty.rb +19 -15
  33. data/lib/ripple/attribute_methods/query.rb +0 -14
  34. data/lib/ripple/attribute_methods/read.rb +0 -14
  35. data/lib/ripple/attribute_methods/write.rb +0 -14
  36. data/lib/ripple/callbacks.rb +10 -16
  37. data/lib/ripple/conflict/basic_resolver.rb +82 -0
  38. data/lib/ripple/conflict/document_hooks.rb +20 -0
  39. data/lib/ripple/conflict/resolver.rb +71 -0
  40. data/lib/ripple/conflict/test_helper.rb +33 -0
  41. data/lib/ripple/conversion.rb +0 -14
  42. data/lib/ripple/core_ext.rb +1 -14
  43. data/lib/ripple/core_ext/casting.rb +19 -19
  44. data/lib/ripple/core_ext/object.rb +8 -0
  45. data/lib/ripple/document.rb +21 -16
  46. data/lib/ripple/document/bucket_access.rb +0 -14
  47. data/lib/ripple/document/finders.rb +17 -23
  48. data/lib/ripple/document/key.rb +8 -28
  49. data/lib/ripple/document/link.rb +30 -0
  50. data/lib/ripple/document/persistence.rb +12 -20
  51. data/lib/ripple/embedded_document.rb +10 -15
  52. data/lib/ripple/embedded_document/around_callbacks.rb +18 -0
  53. data/lib/ripple/embedded_document/finders.rb +7 -18
  54. data/lib/ripple/embedded_document/persistence.rb +5 -17
  55. data/lib/ripple/i18n.rb +0 -14
  56. data/lib/ripple/inspection.rb +21 -15
  57. data/lib/ripple/locale/en.yml +9 -13
  58. data/lib/ripple/nested_attributes.rb +33 -39
  59. data/lib/ripple/observable.rb +0 -13
  60. data/lib/ripple/properties.rb +1 -14
  61. data/lib/ripple/property_type_mismatch.rb +0 -14
  62. data/lib/ripple/railtie.rb +4 -14
  63. data/lib/ripple/railties/ripple.rake +86 -0
  64. data/lib/ripple/serialization.rb +11 -11
  65. data/lib/ripple/test_server.rb +36 -0
  66. data/lib/ripple/timestamps.rb +0 -13
  67. data/lib/ripple/translation.rb +4 -14
  68. data/lib/ripple/validations.rb +1 -15
  69. data/lib/ripple/validations/associated_validator.rb +26 -17
  70. data/lib/ripple/version.rb +3 -0
  71. data/ripple.gemspec +24 -35
  72. data/spec/integration/ripple/associations_spec.rb +89 -58
  73. data/spec/integration/ripple/conflict_resolution_spec.rb +298 -0
  74. data/spec/integration/ripple/nested_attributes_spec.rb +19 -19
  75. data/spec/integration/ripple/persistence_spec.rb +15 -34
  76. data/spec/integration/ripple/search_associations_spec.rb +31 -0
  77. data/spec/ripple/associations/many_embedded_proxy_spec.rb +23 -36
  78. data/spec/ripple/associations/many_linked_proxy_spec.rb +133 -45
  79. data/spec/ripple/associations/many_reference_proxy_spec.rb +170 -0
  80. data/spec/ripple/associations/many_stored_key_proxy_spec.rb +158 -0
  81. data/spec/ripple/associations/one_embedded_proxy_spec.rb +24 -37
  82. data/spec/ripple/associations/one_key_proxy_spec.rb +82 -0
  83. data/spec/ripple/associations/one_linked_proxy_spec.rb +22 -23
  84. data/spec/ripple/associations/one_stored_key_proxy_spec.rb +72 -0
  85. data/spec/ripple/associations/proxy_spec.rb +21 -15
  86. data/spec/ripple/associations_spec.rb +54 -23
  87. data/spec/ripple/attribute_methods/dirty_spec.rb +56 -5
  88. data/spec/ripple/attribute_methods_spec.rb +47 -21
  89. data/spec/ripple/bucket_access_spec.rb +4 -17
  90. data/spec/ripple/callbacks_spec.rb +52 -15
  91. data/spec/ripple/conflict/resolver_spec.rb +42 -0
  92. data/spec/ripple/conversion_spec.rb +2 -15
  93. data/spec/ripple/core_ext_spec.rb +12 -15
  94. data/spec/ripple/document/link_spec.rb +67 -0
  95. data/spec/ripple/document_spec.rb +34 -19
  96. data/spec/ripple/embedded_document/finders_spec.rb +12 -19
  97. data/spec/ripple/embedded_document/persistence_spec.rb +20 -26
  98. data/spec/ripple/embedded_document_spec.rb +44 -34
  99. data/spec/ripple/finders_spec.rb +58 -29
  100. data/spec/ripple/inspection_spec.rb +40 -37
  101. data/spec/ripple/key_spec.rb +5 -17
  102. data/spec/ripple/observable_spec.rb +3 -16
  103. data/spec/ripple/persistence_spec.rb +134 -18
  104. data/spec/ripple/properties_spec.rb +21 -15
  105. data/spec/ripple/ripple_spec.rb +1 -14
  106. data/spec/ripple/serialization_spec.rb +16 -17
  107. data/spec/ripple/timestamps_spec.rb +73 -52
  108. data/spec/ripple/validations/associated_validator_spec.rb +69 -25
  109. data/spec/ripple/validations_spec.rb +3 -16
  110. data/spec/spec_helper.rb +17 -18
  111. data/spec/support/associations.rb +1 -1
  112. data/spec/support/associations/proxies.rb +0 -13
  113. data/spec/support/integration_setup.rb +11 -0
  114. data/spec/support/mocks.rb +0 -13
  115. data/spec/support/models.rb +33 -2
  116. data/spec/support/models/address.rb +1 -16
  117. data/spec/support/models/box.rb +7 -14
  118. data/spec/support/models/car.rb +27 -1
  119. data/spec/support/models/cardboard_box.rb +0 -14
  120. data/spec/support/models/clock.rb +6 -15
  121. data/spec/support/models/clock_observer.rb +0 -14
  122. data/spec/support/models/credit_card.rb +5 -0
  123. data/spec/support/models/customer.rb +0 -14
  124. data/spec/support/models/email.rb +0 -14
  125. data/spec/support/models/family.rb +1 -13
  126. data/spec/support/models/favorite.rb +0 -14
  127. data/spec/support/models/invoice.rb +0 -14
  128. data/spec/support/models/late_invoice.rb +0 -14
  129. data/spec/support/models/nested.rb +12 -0
  130. data/spec/support/models/ninja.rb +7 -0
  131. data/spec/support/models/note.rb +0 -14
  132. data/spec/support/models/page.rb +1 -15
  133. data/spec/support/models/paid_invoice.rb +0 -14
  134. data/spec/support/models/post.rb +12 -0
  135. data/spec/support/models/profile.rb +7 -0
  136. data/spec/support/models/subscription.rb +26 -0
  137. data/spec/support/models/tasks.rb +0 -18
  138. data/spec/support/models/team.rb +11 -0
  139. data/spec/support/models/transactions.rb +17 -0
  140. data/spec/support/models/tree.rb +2 -16
  141. data/spec/support/models/user.rb +14 -16
  142. data/spec/support/models/widget.rb +8 -14
  143. data/spec/support/search.rb +14 -0
  144. data/spec/support/test_server.rb +22 -12
  145. data/spec/support/test_server.yml.example +14 -2
  146. metadata +223 -59
  147. data/lib/rails/generators/ripple/test/templates/test_server.rb +0 -46
  148. data/spec/support/models/driver.rb +0 -5
  149. data/spec/support/models/engine.rb +0 -4
  150. data/spec/support/models/passenger.rb +0 -5
  151. data/spec/support/models/seat.rb +0 -4
  152. data/spec/support/models/wheel.rb +0 -5
@@ -0,0 +1,30 @@
1
+ require 'riak/link'
2
+
3
+ module Ripple
4
+ module Document
5
+ # A Link that is tied to a particular document and tag.
6
+ # The key is fetched from the document lazily when needed.
7
+ class Link < Riak::Link
8
+ attr_reader :document
9
+ private :document
10
+
11
+ def initialize(document, tag)
12
+ @document = document
13
+ super(document.class.bucket_name, nil, tag)
14
+ end
15
+
16
+ def key
17
+ document.key
18
+ end
19
+
20
+ def hash
21
+ document.hash
22
+ end
23
+ end
24
+
25
+ def to_link(tag)
26
+ Link.new(self, tag)
27
+ end
28
+ end
29
+ end
30
+
@@ -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
@@ -29,7 +15,7 @@ module Ripple
29
15
  # Destroys all records one at a time.
30
16
  # Place holder while :delete to bucket is being developed.
31
17
  def destroy_all
32
- all(&:destroy)
18
+ list(&:destroy)
33
19
  end
34
20
 
35
21
  attr_writer :quorums
@@ -74,8 +60,7 @@ module Ripple
74
60
  end
75
61
 
76
62
  def really_save(*args)
77
- robject.key = key if robject.key != key
78
- robject.data = attributes_for_persistence
63
+ update_robject
79
64
  robject.store(self.class.quorums.slice(:w,:dw))
80
65
  self.key = robject.key
81
66
  @new = false
@@ -86,8 +71,9 @@ module Ripple
86
71
  # @return self
87
72
  def reload
88
73
  return self if new?
89
- robject.reload(:force => true)
90
- self.__send__(:attributes=, @robject.data.except("_type"), false)
74
+ @robject = @robject.reload(:force => true)
75
+ self.__send__(:raw_attributes=, @robject.data.except("_type"))
76
+ reset_associations
91
77
  self
92
78
  end
93
79
 
@@ -113,9 +99,15 @@ module Ripple
113
99
  end
114
100
  end
115
101
 
102
+ def update_robject
103
+ robject.key = key if robject.key != key
104
+ robject.content_type = 'application/json'
105
+ robject.data = attributes_for_persistence
106
+ end
107
+
116
108
  private
117
109
  def attributes_for_persistence
118
- attributes.merge("_type" => self.class.name)
110
+ raw_attributes.merge("_type" => self.class.name)
119
111
  end
120
112
  end
121
113
  end
@@ -1,20 +1,7 @@
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_support/core_ext/hash/except'
17
3
  require 'ripple/translation'
4
+ require 'ripple/embedded_document/around_callbacks'
18
5
  require 'ripple/embedded_document/finders'
19
6
  require 'ripple/embedded_document/persistence'
20
7
  require 'ripple/properties'
@@ -45,6 +32,7 @@ module Ripple
45
32
  include Ripple::Validations
46
33
  include Ripple::Associations
47
34
  include Ripple::Callbacks
35
+ include Ripple::EmbeddedDocument::AroundCallbacks
48
36
  include Ripple::Conversion
49
37
  include Finders
50
38
  include Ripple::Inspection
@@ -62,7 +50,14 @@ module Ripple
62
50
  def ==(other)
63
51
  self.class == other.class &&
64
52
  _parent_document == other._parent_document &&
65
- attributes.except('_type') == other.attributes.except('_type')
53
+ serializable_hash == other.serializable_hash
54
+ end
55
+ alias eql? ==
56
+
57
+ def hash
58
+ parent = [_parent_document.class]
59
+ parent << [_parent_document.key] if _parent_document.respond_to?(:key)
60
+ [ self.class, parent, serializable_hash ].hash
66
61
  end
67
62
  end
68
63
  end
@@ -0,0 +1,18 @@
1
+ require 'ripple/callbacks'
2
+
3
+ module Ripple
4
+ module EmbeddedDocument
5
+ module AroundCallbacks
6
+ extend ActiveSupport::Concern
7
+ extend Translation
8
+
9
+ included do
10
+ Ripple::Callbacks::CALLBACK_TYPES.each do |type|
11
+ define_singleton_method "around_#{type}" do |*args|
12
+ raise NotImplementedError.new(t("around_callbacks_not_supported", :type => type))
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ 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 'active_support/concern'
16
2
  require 'active_support/inflector'
17
3
 
@@ -24,14 +10,17 @@ module Ripple
24
10
  module ClassMethods
25
11
  def instantiate(attrs)
26
12
  begin
27
- klass = attrs['_type'].present? ? attrs['_type'].constantize : self
28
- klass.new(attrs)
13
+ klass = attrs['_type'].present? ? attrs.delete('_type').constantize : self
29
14
  rescue NameError
30
- new(attrs)
15
+ klass = self
16
+ end
17
+ klass.new.tap do |object|
18
+ object.raw_attributes = attrs
19
+ object.changed_attributes.clear
31
20
  end
32
21
  end
33
22
  end
34
-
23
+
35
24
  end
36
25
  end
37
26
  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 'active_support/concern'
16
2
  require 'ripple/translation'
17
3
 
@@ -32,7 +18,7 @@ module Ripple
32
18
  extend ActiveSupport::Concern
33
19
 
34
20
  module ClassMethods
35
- # Creates a method that points to the parent document.
21
+ # Creates a method that points to the parent document.
36
22
  def embedded_in(parent)
37
23
  define_method(parent) { @_parent_document }
38
24
  end
@@ -68,7 +54,9 @@ module Ripple
68
54
  # Saves this embedded document by delegating to the root document.
69
55
  def save(*args)
70
56
  if _root_document
71
- _root_document.save(*args)
57
+ run_save_callbacks do
58
+ _root_document.save(*args)
59
+ end
72
60
  else
73
61
  raise NoRootDocument.new(self, :save)
74
62
  end
@@ -76,7 +64,7 @@ module Ripple
76
64
 
77
65
  # @private
78
66
  def attributes_for_persistence
79
- attributes.merge("_type" => self.class.name)
67
+ raw_attributes.merge("_type" => self.class.name)
80
68
  end
81
69
 
82
70
  # The root {Ripple::Document} to which this embedded document belongs.
@@ -1,16 +1,2 @@
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/i18n'
16
2
  I18n.load_path << File.expand_path("../locale/en.yml", __FILE__)
@@ -1,26 +1,32 @@
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
1
  require 'ripple'
15
2
 
16
3
  module Ripple
17
4
  # Makes IRB and other inspect output a bit friendlier
18
5
  module Inspection
6
+
19
7
  # A human-readable version of the {Ripple::Document} or {Ripple::EmbeddedDocument}
8
+ # plus attributes
20
9
  def inspect
21
10
  attribute_list = attributes_for_persistence.except("_type").map {|k,v| "#{k}=#{v.inspect}" }.join(' ')
22
- identifier = self.class.embeddable? ? "" : ":#{key || '[new]'}"
23
- "<#{self.class.name}#{identifier} #{attribute_list}>"
11
+ inspection_string(attribute_list)
12
+ end
13
+
14
+ # A string representation of the {Ripple::Document} or {Ripple::EmbeddedDocument}
15
+ def to_s
16
+ inspection_string
24
17
  end
18
+
19
+ private
20
+
21
+ def inspection_string(extra = nil)
22
+ body = self.class.name + persistance_identifier
23
+ body += " #{extra}" if extra
24
+ "<#{body}>"
25
+ end
26
+
27
+ def persistance_identifier
28
+ self.class.embeddable? ? "" : ":#{key || '[new]'}"
29
+ end
30
+
25
31
  end
26
32
  end
@@ -1,26 +1,22 @@
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
1
  en:
15
2
  ripple:
3
+ around_callbacks_not_supported: "around_%{type} callbacks are not supported on embedded documents. See https://github.com/seancribbs/ripple/issues/188 for more detail."
4
+ associated_document_error_summary: "for %{doc_type} %{doc_id}: %{errors}"
16
5
  attribute_hash: "value of attributes must be a Hash"
6
+ cluster_not_created: "The cluster for the current environment is not created yet. Run `rake riak:create` first."
7
+ conflict_handler_not_implemented: "No on_conflict handler has been implemented for %{document}"
17
8
  document_invalid: "Validation failed: %{errors}"
18
9
  document_not_found:
19
10
  no_key: "Couldn't find document without a key"
20
11
  one_key: "Couldn't find document with key: %{key}"
21
12
  many_keys: "Couldn't find documents with keys: %{keys}"
22
13
  invalid_association_value: "Invalid value %{value} for association %{name} of type %{klass} on %{owner}"
14
+ many_association_validation_error: "are invalid (%{association_errors})"
15
+ many_key_association: "You cannot use a many association using :key"
23
16
  missing_configuration: "You are missing your ripple configuration file that should be at %{file}"
24
17
  no_root_document: "You cannot call %{method} on %{doc} without a root document"
18
+ one_association_validation_error: "is invalid (%{association_errors})"
25
19
  property_type_mismatch: "Cannot cast %{value} into a %{class}"
20
+ undefined_property: "Undefined property :%{prop} for class '%{class}'"
21
+ unexpected_conflicts: "Conflict cannot be resolved for %{conflicts} (for %{document})"
26
22
 
@@ -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_support/core_ext/class/inheritable_attributes'
17
3
 
@@ -23,10 +9,14 @@ module Ripple
23
9
  TRUE_VALUES = [ true, "true", 1, "1", "yes", "ok", "y" ]
24
10
 
25
11
  included do
26
- class_inheritable_accessor :nested_attributes_options, :instance_writer => false
12
+ if respond_to?(:class_attribute) # ActiveSupport 3.1
13
+ class_attribute :nested_attributes_options, :instance_writer => false
14
+ else
15
+ class_inheritable_accessor :nested_attributes_options, :instance_writer => false
16
+ end
27
17
  self.nested_attributes_options = {}
28
18
  end
29
-
19
+
30
20
  # = Nested Attributes
31
21
  #
32
22
  # This is similar to the `accepts_nested_attributes` functionality
@@ -87,7 +77,7 @@ module Ripple
87
77
  # { :key => 'yyy', :reference => 'updated foo2' } ])
88
78
  # manifest.shipments.first.reference # => updated foo1
89
79
  # manifest.shipments.second.reference # => updated foo2
90
- #
80
+ #
91
81
  # NOTE: On many embedded, then entire collection of embedded documents is replaced, as there
92
82
  # is no key to specifically update.
93
83
  #
@@ -105,41 +95,45 @@ module Ripple
105
95
  # end
106
96
  #
107
97
  # The assigning of attributes replaces existing:
108
- #
98
+ #
109
99
  # manifest = Manifest.create(:signature_attributes => [ { :esig => 'a00001' }, { :esig => 'b00001' } ]
110
100
  # manifest.signatures # => [<Signature esig="a00001">, <Signature esig="b00001">]
111
101
  #
112
102
  # manifest.signature_attributes = [ { :esig => 'c00001' } ]
113
103
  # manifest.signatures # => [<Signature esig="c00001">]
114
- #
104
+ #
115
105
  module ClassMethods
116
-
106
+
117
107
  def accepts_nested_attributes_for(*attr_names)
118
108
  options = { :allow_destroy => false }
119
109
  options.update(attr_names.extract_options!)
120
-
110
+
121
111
  attr_names.each do |association_name|
122
112
  if association = self.associations[association_name]
123
113
  nested_attributes_options[association_name.to_sym] = options
124
-
125
- class_eval %{
126
- def #{association_name}_attributes=(attributes)
127
- assign_nested_attributes_for_#{association.type}_association(:#{association_name}, attributes)
128
- end
129
114
 
130
- before_save :autosave_nested_attributes_for_#{association_name}
131
- before_save :destroy_marked_for_destruction
115
+ define_method "#{association_name}_attributes=" do |attributes|
116
+ send("assign_nested_attributes_for_#{association.type}_association",
117
+ association_name, attributes
118
+ )
119
+ end
132
120
 
133
- private
121
+ before_save :"autosave_nested_attributes_for_#{association_name}"
122
+ before_save :destroy_marked_for_destruction
134
123
 
135
- def autosave_nested_attributes_for_#{association_name}
136
- save_nested_attributes_for_#{association.type}_association(:#{association_name}) if self.autosave[:#{association_name}]
124
+ define_method "autosave_nested_attributes_for_#{association_name}" do
125
+ if self.autosave[association_name]
126
+ send("save_nested_attributes_for_#{association.type}_association",
127
+ association_name
128
+ )
137
129
  end
138
- }, __FILE__, __LINE__
130
+ end
131
+ private :"autosave_nested_attributes_for_#{association_name}"
132
+
139
133
  else
140
134
  raise ArgumentError, "Association #{association_name} not found!"
141
135
  end
142
- end
136
+ end
143
137
  end
144
138
  end
145
139
 
@@ -156,7 +150,7 @@ module Ripple
156
150
  end
157
151
 
158
152
  private
159
-
153
+
160
154
  def save_nested_attributes_for_one_association(association_name)
161
155
  send(association_name).save
162
156
  end
@@ -178,14 +172,14 @@ module Ripple
178
172
 
179
173
  def assign_nested_attributes_for_one_association(association_name, attributes)
180
174
  association = self.class.associations[association_name]
181
- if association.embeddable?
175
+ if association.embedded?
182
176
  assign_nested_attributes_for_one_embedded_association(association_name, attributes)
183
177
  else
184
178
  self.autosave[association_name] = true
185
179
  assign_nested_attributes_for_one_linked_association(association_name, attributes)
186
180
  end
187
181
  end
188
-
182
+
189
183
  def assign_nested_attributes_for_one_embedded_association(association_name, attributes)
190
184
  send(association_name).build(attributes.except(*UNASSIGNABLE_KEYS))
191
185
  end
@@ -215,7 +209,7 @@ module Ripple
215
209
  end
216
210
 
217
211
  association = self.class.associations[association_name]
218
- if association.embeddable?
212
+ if association.embedded?
219
213
  assign_nested_attributes_for_many_embedded_association(association_name, attributes_collection)
220
214
  else
221
215
  self.autosave[association_name] = true
@@ -255,7 +249,7 @@ module Ripple
255
249
  record.attributes = attributes.except(*UNASSIGNABLE_KEYS)
256
250
  end
257
251
  end
258
-
252
+
259
253
  def has_destroy_flag?(hash)
260
254
  TRUE_VALUES.include?(hash.stringify_keys['_destroy'])
261
255
  end
@@ -275,5 +269,5 @@ module Ripple
275
269
  end
276
270
 
277
271
  end
278
-
272
+
279
273
  end