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.
- data/lib/ripple.rb +17 -1
- data/lib/ripple/associations.rb +157 -0
- data/lib/ripple/associations/embedded.rb +42 -0
- data/lib/ripple/associations/instantiators.rb +39 -0
- data/lib/ripple/{document/associations → associations}/linked.rb +9 -11
- data/lib/ripple/{document/associations/one_embedded_proxy.rb → associations/many.rb} +30 -21
- data/lib/ripple/{document/associations/embedded.rb → associations/many_embedded_proxy.rb} +26 -23
- data/lib/ripple/{embedded_document/conversion.rb → associations/one.rb} +8 -13
- data/lib/ripple/{document/associations/instantiators.rb → associations/one_embedded_proxy.rb} +17 -19
- data/lib/ripple/associations/proxy.rb +123 -0
- data/lib/ripple/attribute_methods.rb +116 -0
- data/lib/ripple/{document/attribute_methods/write.rb → attribute_methods/dirty.rb} +26 -16
- data/lib/ripple/attribute_methods/query.rb +48 -0
- data/lib/ripple/{document/attribute_methods → attribute_methods}/read.rb +16 -18
- data/lib/ripple/attribute_methods/write.rb +38 -0
- data/lib/ripple/callbacks.rb +73 -0
- data/lib/ripple/{document/associations/one.rb → conversion.rb} +18 -13
- data/lib/ripple/document.rb +19 -9
- data/lib/ripple/embedded_document.rb +10 -10
- data/lib/ripple/embedded_document/persistence.rb +12 -53
- data/lib/ripple/properties.rb +83 -0
- data/lib/ripple/timestamps.rb +34 -0
- data/lib/ripple/{document/validations.rb → validations.rb} +31 -33
- data/lib/ripple/{document/validations → validations}/associated_validator.rb +9 -10
- data/spec/integration/ripple/associations_spec.rb +1 -2
- data/spec/integration/ripple/persistence_spec.rb +2 -3
- data/spec/ripple/associations/many_embedded_proxy_spec.rb +2 -2
- data/spec/ripple/associations/one_embedded_proxy_spec.rb +2 -2
- data/spec/ripple/associations/proxy_spec.rb +1 -1
- data/spec/ripple/associations_spec.rb +15 -20
- data/spec/ripple/attribute_methods_spec.rb +3 -6
- data/spec/ripple/callbacks_spec.rb +1 -1
- data/spec/ripple/{embedded_document/conversion_spec.rb → conversion_spec.rb} +4 -4
- data/spec/ripple/embedded_document/persistence_spec.rb +4 -16
- data/spec/ripple/properties_spec.rb +17 -18
- data/spec/ripple/timestamps_spec.rb +1 -1
- data/spec/ripple/validations_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/support/associations/proxies.rb +4 -4
- metadata +27 -29
- data/lib/ripple/document/associations.rb +0 -154
- data/lib/ripple/document/associations/many.rb +0 -52
- data/lib/ripple/document/associations/many_embedded_proxy.rb +0 -49
- data/lib/ripple/document/associations/proxy.rb +0 -125
- data/lib/ripple/document/attribute_methods.rb +0 -118
- data/lib/ripple/document/attribute_methods/dirty.rb +0 -52
- data/lib/ripple/document/attribute_methods/query.rb +0 -49
- data/lib/ripple/document/callbacks.rb +0 -75
- data/lib/ripple/document/properties.rb +0 -85
- data/lib/ripple/document/timestamps.rb +0 -22
- 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
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
data/lib/ripple/document.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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)
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
+
|