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
@@ -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
+