ripple 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -0,0 +1,73 @@
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 Callbacks
18
+ extend ActiveSupport::Concern
19
+
20
+ included do
21
+ extend ActiveModel::Callbacks
22
+ define_model_callbacks :create, :update, :save, :destroy
23
+ define_callbacks :validation, :terminator => "result == false", :scope => [:kind, :name]
24
+ end
25
+
26
+ module ClassMethods
27
+ def before_validation(*args, &block)
28
+ options = args.last
29
+ if options.is_a?(Hash) && options[:on]
30
+ options[:if] = Array(options[:if])
31
+ options[:if] << "@_on_validate == :#{options[:on]}"
32
+ end
33
+ set_callback(:validation, :before, *args, &block)
34
+ end
35
+
36
+ def after_validation(*args, &block)
37
+ options = args.extract_options!
38
+ options[:prepend] = true
39
+ options[:if] = Array(options[:if])
40
+ options[:if] << "!halted && value != false"
41
+ options[:if] << "@_on_validate == :#{options[:on]}" if options[:on]
42
+ set_callback(:validation, :after, *(args << options), &block)
43
+ end
44
+ end
45
+
46
+ module InstanceMethods
47
+ # @private
48
+ def save(*args, &block)
49
+ state = new? ? :create : :update
50
+ run_callbacks(:save) do
51
+ run_callbacks(state) do
52
+ super
53
+ end
54
+ end
55
+ end
56
+
57
+ # @private
58
+ def destroy(*args, &block)
59
+ run_callbacks(:destroy) do
60
+ super
61
+ end
62
+ end
63
+
64
+ # @private
65
+ def valid?(*args, &block)
66
+ @_on_validate = new? ? :create : :update
67
+ run_callbacks(:validation) do
68
+ super
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -14,18 +14,23 @@
14
14
  require 'ripple'
15
15
 
16
16
  module Ripple
17
- module Document
18
- module Associations
19
- module One
20
- include Instantiators
21
-
22
- protected
23
- def instantiate_target(instantiator, attrs={})
24
- @target = klass.send(instantiator, attrs)
25
- loaded
26
- @target
27
- end
28
- end
17
+ module Conversion
18
+ include ActiveModel::Conversion
19
+
20
+ def new_record?
21
+ new?
22
+ end
23
+
24
+ def persisted?
25
+ !new?
26
+ end
27
+
28
+ def to_key
29
+ new? ? nil : [key]
30
+ end
31
+
32
+ def to_param
33
+ key
29
34
  end
30
35
  end
31
- end
36
+ end
@@ -42,24 +42,34 @@ module Ripple
42
42
  extend ActiveSupport::Concern
43
43
  extend ActiveSupport::Autoload
44
44
 
45
- autoload :Association, "ripple/document/associations"
46
- autoload :Associations
47
- autoload :AttributeMethods
48
45
  autoload :BucketAccess
49
- autoload :Callbacks
50
46
  autoload :Finders
51
47
  autoload :Persistence
52
- autoload :Properties
53
- autoload :Property, "ripple/document/properties"
54
- autoload :Timestamps
55
- autoload :Validations
56
48
 
57
49
  included do
50
+ extend ActiveModel::Naming
58
51
  extend BucketAccess
59
52
  include Ripple::Document::Persistence
60
- include Ripple::EmbeddedDocument
53
+ extend Ripple::Properties
54
+ include Ripple::AttributeMethods
55
+ include Ripple::Timestamps
56
+ include Ripple::Validations
57
+ include Ripple::Associations
58
+ include Ripple::Callbacks
59
+ include Ripple::Conversion
61
60
  include Ripple::Document::Finders
62
61
  end
63
62
 
63
+ module ClassMethods
64
+ def embeddable?
65
+ false
66
+ end
67
+ end
68
+
69
+ module InstanceMethods
70
+ def _root_document
71
+ self
72
+ end
73
+ end
64
74
  end
65
75
  end
@@ -25,21 +25,21 @@ module Ripple
25
25
 
26
26
  included do
27
27
  extend ActiveModel::Naming
28
- extend Ripple::Document::Properties
29
- include Ripple::Document::AttributeMethods
30
- include Ripple::Document::Timestamps
31
- include Ripple::Document::Validations
32
- include Ripple::Document::Associations
33
- include Ripple::Document::Callbacks
34
- include Conversion
35
- include Finders
36
28
  include Persistence
29
+ extend Ripple::Properties
30
+ include Ripple::AttributeMethods
31
+ include Ripple::Timestamps
32
+ include Ripple::Validations
33
+ include Ripple::Associations
34
+ include Ripple::Callbacks
35
+ include Ripple::Conversion
36
+ include Finders
37
37
  end
38
38
 
39
39
  module ClassMethods
40
40
  def embeddable?
41
- !included_modules.include?(Document)
41
+ true
42
42
  end
43
43
  end
44
44
  end
45
- end
45
+ end
@@ -20,88 +20,47 @@ module Ripple
20
20
  super(t("no_root_document", :doc => doc.inspect, :method => method))
21
21
  end
22
22
  end
23
-
23
+
24
24
  module EmbeddedDocument
25
25
  module Persistence
26
26
  extend ActiveSupport::Concern
27
-
27
+
28
28
  module ClassMethods
29
29
  def embedded_in(parent)
30
30
  define_method(parent) { @_parent_document }
31
31
  end
32
32
  end
33
-
33
+
34
34
  module InstanceMethods
35
-
36
35
  attr_reader :_parent_document
37
-
38
- def embeddable?
39
- self.class.embeddable?
40
- end
41
-
36
+
42
37
  def new?
43
- if _root_document?
44
- super
45
- elsif @_root_document
38
+ if _root_document
46
39
  _root_document.new?
47
40
  else
48
41
  true
49
42
  end
50
43
  end
51
-
52
- # because alias_method doesn't like super
53
- def new_record?; new?; end
54
-
55
- # for ActiveModel::Conversion
56
- def persisted?; !new?; end
57
-
44
+
58
45
  def save(*args)
59
- if _root_document?
60
- super
61
- elsif @_root_document
46
+ if _root_document
62
47
  _root_document.save(*args)
63
48
  else
64
49
  raise NoRootDocument.new(self, :save)
65
50
  end
66
51
  end
67
-
68
- def save!(*args)
69
- if _root_document?
70
- super
71
- elsif @_root_document
72
- _root_document.save!(*args)
73
- else
74
- raise NoRootDocument.new(self, :save!)
75
- end
76
- end
77
-
78
- def _root_document
79
- embeddable? ? @_root_document : self
80
- end
81
-
82
- def _root_document?
83
- _root_document === self
84
- end
85
52
 
86
53
  def attributes_for_persistence
87
- attributes.merge("_type" => self.class.name).merge(embedded_attributes_for_persistence)
54
+ attributes.merge("_type" => self.class.name)
55
+ end
56
+
57
+ def _root_document
58
+ @_parent_document.try(:_root_document)
88
59
  end
89
60
 
90
61
  def _parent_document=(value)
91
- @_root_document = value._root_document
92
62
  @_parent_document = value
93
63
  end
94
-
95
- protected
96
-
97
- def embedded_attributes_for_persistence
98
- embedded_associations.inject({}) do |attrs, association|
99
- if documents = instance_variable_get(association.ivar)
100
- attrs[association.name] = documents.is_a?(Array) ? documents.map(&:attributes_for_persistence) : documents.attributes_for_persistence
101
- end
102
- attrs
103
- end
104
- end
105
64
  end
106
65
  end
107
66
  end
@@ -0,0 +1,83 @@
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
+ require 'ripple/core_ext/casting'
16
+
17
+ module Ripple
18
+ # Adds the ability to declare properties on your Ripple::Document class.
19
+ # Properties will automatically generate accessor (get/set/query) methods and
20
+ # handle type-casting between your Ruby type and JSON-compatible types.
21
+ module Properties
22
+ # @private
23
+ def inherited(subclass)
24
+ super
25
+ subclass.properties.merge!(properties)
26
+ end
27
+
28
+ # @return [Hash] the properties defined on the document
29
+ def properties
30
+ @properties ||= {}.with_indifferent_access
31
+ end
32
+
33
+ def property(key, type, options={})
34
+ prop = Property.new(key, type, options)
35
+ properties[prop.key] = prop
36
+ end
37
+ end
38
+
39
+ # Encapsulates a single property on your Ripple::Document class.
40
+ class Property
41
+ # @return [Symbol] the key of this property in the Document
42
+ attr_reader :key
43
+ # @return [Class] the Ruby type of property.
44
+ attr_reader :type
45
+ # @return [Hash] configuration options
46
+ attr_reader :options
47
+
48
+ # Create a new document property.
49
+ # @param [String, Symbol] key the key of the property
50
+ # @param [Class] type the Ruby type of the property. Use {Boolean} for true or false types.
51
+ # @param [Hash] options configuration options
52
+ # @option options [Object, Proc] :default (nil) a default value for the property, or a lambda to evaluate when providing the default.
53
+ def initialize(key, type, options={})
54
+ @options = options.to_options
55
+ @key = key.to_sym
56
+ @type = type
57
+ end
58
+
59
+ # @return [Object] The default value for this property if defined, or nil.
60
+ def default
61
+ if default = options[:default]
62
+ type_cast(default.respond_to?(:call) ? default.call : default)
63
+ end
64
+ end
65
+
66
+ # @return [Hash] options appropriate for the validates class method
67
+ def validation_options
68
+ @options.dup.except(:default)
69
+ end
70
+
71
+ # Attempt to coerce the passed value into this property's type
72
+ # @param [Object] value the value to coerce
73
+ # @return [Object] the value coerced into this property's type
74
+ # @raise [PropertyTypeMismatch] if the value cannot be coerced into the property's type
75
+ def type_cast(value)
76
+ if @type.respond_to?(:ripple_cast)
77
+ @type.ripple_cast(value)
78
+ else
79
+ value
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,34 @@
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 Timestamps
18
+ extend ActiveSupport::Concern
19
+
20
+ module ClassMethods
21
+ def timestamps!
22
+ property :created_at, Time, :default => proc { Time.now.utc }
23
+ property :updated_at, Time
24
+ before_save :touch
25
+ end
26
+ end
27
+
28
+ module InstanceMethods
29
+ def touch
30
+ self.updated_at = Time.now.utc
31
+ end
32
+ end
33
+ end
34
+ end
@@ -14,7 +14,7 @@
14
14
  require 'ripple'
15
15
 
16
16
  module Ripple
17
-
17
+
18
18
  # Raised by <tt>save!</tt> when the document is invalid. Use the
19
19
  # +document+ method to retrieve the document which did not validate.
20
20
  # begin
@@ -31,42 +31,40 @@ module Ripple
31
31
  super(t("document_invalid", :errors => errors))
32
32
  end
33
33
  end
34
-
35
- module Document
36
- module Validations
37
- extend ActiveSupport::Concern
38
- extend ActiveSupport::Autoload
39
- include ActiveModel::Validations
40
-
41
- autoload :AssociatedValidator
42
34
 
43
- module ClassMethods
44
- # @private
45
- def property(key, type, options={})
46
- prop = super
47
- validates key, prop.validation_options unless prop.validation_options.blank?
48
- end
49
-
50
- # Instantiates a new record, applies attributes from a block, and saves it
51
- # Raises Ripple::DocumentInvalid if the record did not save
52
- def create!(attrs={}, &block)
53
- obj = create(attrs, &block)
54
- (raise Ripple::DocumentInvalid.new(obj) if obj.new?) || obj
55
- end
35
+ module Validations
36
+ extend ActiveSupport::Concern
37
+ extend ActiveSupport::Autoload
38
+ include ActiveModel::Validations
39
+
40
+ autoload :AssociatedValidator
41
+
42
+ module ClassMethods
43
+ # @private
44
+ def property(key, type, options={})
45
+ prop = super
46
+ validates key, prop.validation_options unless prop.validation_options.blank?
47
+ end
48
+
49
+ # Instantiates a new document, applies attributes from a block, and saves it
50
+ # Raises Ripple::DocumentInvalid if the record did not save
51
+ def create!(attrs={}, &block)
52
+ obj = create(attrs, &block)
53
+ (raise Ripple::DocumentInvalid.new(obj) if obj.new?) || obj
56
54
  end
55
+ end
57
56
 
58
- module InstanceMethods
59
- # @private
60
- def save(options={:validate => true})
61
- return false if options[:validate] && !valid?
62
- super()
63
- end
64
-
65
- def save!
66
- (raise Ripple::DocumentInvalid.new(self) unless save) || true
67
- end
68
-
57
+ module InstanceMethods
58
+ # @private
59
+ def save(options={:validate => true})
60
+ return false if options[:validate] && !valid?
61
+ super()
62
+ end
63
+
64
+ def save!
65
+ (raise Ripple::DocumentInvalid.new(self) unless save) || true
69
66
  end
70
67
  end
71
68
  end
72
69
  end
70
+