dynamoid 0.3.0 → 0.3.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.
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "dynamoid"
8
- s.version = "0.3.0"
8
+ s.version = "0.3.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Josh Symonds"]
@@ -86,6 +86,8 @@ Gem::Specification.new do |s|
86
86
  "lib/dynamoid/associations/has_and_belongs_to_many.rb",
87
87
  "lib/dynamoid/associations/has_many.rb",
88
88
  "lib/dynamoid/associations/has_one.rb",
89
+ "lib/dynamoid/associations/many_association.rb",
90
+ "lib/dynamoid/associations/single_association.rb",
89
91
  "lib/dynamoid/components.rb",
90
92
  "lib/dynamoid/config.rb",
91
93
  "lib/dynamoid/config/options.rb",
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.3.1
@@ -1,5 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require 'dynamoid/associations/association'
3
+ require 'dynamoid/associations/single_association'
4
+ require 'dynamoid/associations/many_association'
3
5
  require 'dynamoid/associations/has_many'
4
6
  require 'dynamoid/associations/belongs_to'
5
7
  require 'dynamoid/associations/has_one'
@@ -1,19 +1,15 @@
1
1
  # encoding: utf-8
2
2
  module Dynamoid #:nodoc:
3
3
 
4
- # The base association module which all associations include. Every association has two very important components: the source and
4
+ # The base association module which all associations include. Every association has two very important components: the source and
5
5
  # the target. The source is the object which is calling the association information. It always has the target_ids inside of an attribute on itself.
6
6
  # The target is the object which is referencing by this association.
7
7
  module Associations
8
8
  module Association
9
- attr_accessor :name, :options, :source, :query
10
- include Enumerable
11
-
12
- # Delegate methods to the records the association represents.
13
- delegate :first, :last, :empty?, :size, :to => :records
9
+ attr_accessor :name, :options, :source
14
10
 
15
11
  # Create a new association.
16
- #
12
+ #
17
13
  # @param [Class] source the source record of the association; that is, the record that you already have
18
14
  # @param [Symbol] name the name of the association
19
15
  # @param [Hash] options optional parameters for the association
@@ -28,158 +24,9 @@ module Dynamoid #:nodoc:
28
24
  @name = name
29
25
  @options = options
30
26
  @source = source
31
- @query = {}
32
- end
33
-
34
- # Alias convenience methods for the associations.
35
- alias :nil? :empty?
36
- alias :count :size
37
-
38
- # The records associated to the source.
39
- #
40
- # @return the association records; depending on which association this is, either a single instance or an array
41
- #
42
- # @since 0.2.0
43
- def records
44
- results = Array(target_class.find(source_ids.to_a))
45
-
46
- if query.empty?
47
- results
48
- else
49
- results_with_query(results)
50
- end
51
- end
52
- alias :all :records
53
-
54
- # Delegate include? to the records.
55
- def include?(object)
56
- records.include?(object)
57
- end
58
-
59
- # @todo Improve the two methods below to not have quite so much duplicated code.
60
-
61
- # Deletes an object or array of objects from the association. This removes their records from the association field on the source,
62
- # and attempts to remove the source from the target association if it is detected to exist.
63
- #
64
- # @param [Dynamoid::Document] object the object (or array of objects) to remove from the association
65
- #
66
- # @return [Dynamoid::Document] the deleted object
67
- #
68
- # @since 0.2.0
69
- def delete(object)
70
- source.update_attribute(source_attribute, source_ids - Array(object).collect(&:id))
71
- Array(object).collect{|o| self.send(:disassociate_target, o)} if target_association
72
- object
73
- end
74
-
75
- # Add an object or array of objects to an association. This preserves the current records in the association (if any)
76
- # and adds the object to the target association if it is detected to exist.
77
- #
78
- # @param [Dynamoid::Document] object the object (or array of objects) to add to the association
79
- #
80
- # @return [Dynamoid::Document] the added object
81
- #
82
- # @since 0.2.0
83
- def <<(object)
84
- source.update_attribute(source_attribute, source_ids.merge(Array(object).collect(&:id)))
85
- Array(object).collect{|o| self.send(:associate_target, o)} if target_association
86
- object
87
- end
88
-
89
- # Replace an association with object or array of objects. This removes all of the existing associated records and replaces them with
90
- # the passed object(s), and associates the target association if it is detected to exist.
91
- #
92
- # @param [Dynamoid::Document] object the object (or array of objects) to add to the association
93
- #
94
- # @return [Dynamoid::Document] the added object
95
- #
96
- # @since 0.2.0
97
- def setter(object)
98
- records.each {|o| delete(o)}
99
- self << (object)
100
- object
101
- end
102
-
103
- # Create a new instance of the target class and add it directly to the association.
104
- #
105
- # @param [Hash] attribute hash for the new object
106
- #
107
- # @return [Dynamoid::Document] the newly-created object
108
- #
109
- # @since 0.2.0
110
- def create(attributes = {})
111
- self << target_class.create(attributes)
112
- end
113
-
114
- # Create a new instance of the target class and add it directly to the association. If the create fails an exception will be raised.
115
- #
116
- # @param [Hash] attribute hash for the new object
117
- #
118
- # @return [Dynamoid::Document] the newly-created object
119
- #
120
- # @since 0.2.0
121
- def create!(attributes = {})
122
- self << target_class.create!(attributes)
123
- end
124
-
125
-
126
- # Naive association filtering.
127
- #
128
- # @param [Hash] A hash of attributes; each must match every returned object's attribute exactly.
129
- #
130
- # @return [Dynamoid::Association] the association this method was called on (for chaining purposes)
131
- #
132
- # @since 0.2.0
133
- def where(args)
134
- args.each {|k, v| query[k] = v}
135
- self
136
- end
137
-
138
- # Create a new instance of the target class and add it directly to the association. If the create fails an exception will be raised.
139
- #
140
- # @param [Hash] attribute hash for the new object
141
- #
142
- # @return [Dynamoid::Document] the newly-created object
143
- #
144
- # @since 0.2.0
145
- def each(&block)
146
- records.each(&block)
147
- end
148
-
149
- # Destroys all members of the association and removes them from the association.
150
- #
151
- # @since 0.2.0
152
- def destroy_all
153
- objs = records
154
- source.update_attribute(source_attribute, nil)
155
- objs.each(&:destroy)
156
27
  end
157
28
 
158
- # Deletes all members of the association and removes them from the association.
159
- #
160
- # @since 0.2.0
161
- def delete_all
162
- objs = records
163
- source.update_attribute(source_attribute, nil)
164
- objs.each(&:delete)
165
- end
166
-
167
29
  private
168
-
169
- # If a query exists, filter all existing results based on that query.
170
- #
171
- # @param [Array] results the raw results for the association
172
- #
173
- # @return [Array] the filtered results for the query
174
- #
175
- # @since 0.2.0
176
- def results_with_query(results)
177
- results.find_all do |result|
178
- query.all? do |attribute, value|
179
- result.send(attribute) == value
180
- end
181
- end
182
- end
183
30
 
184
31
  # The target class name, either inferred through the association's name or specified in options.
185
32
  #
@@ -194,7 +41,7 @@ module Dynamoid #:nodoc:
194
41
  def target_class
195
42
  options[:class] || target_class_name.constantize
196
43
  end
197
-
44
+
198
45
  # The target attribute: that is, the attribute on each object of the association that should reference the source.
199
46
  #
200
47
  # @since 0.2.0
@@ -204,25 +51,25 @@ module Dynamoid #:nodoc:
204
51
 
205
52
  # The ids in the target association.
206
53
  #
207
- # @since 0.2.0
54
+ # @since 0.2.0
208
55
  def target_ids
209
56
  target.send(target_attribute) || Set.new
210
57
  end
211
58
 
212
59
  # The ids in the target association.
213
60
  #
214
- # @since 0.2.0
61
+ # @since 0.2.0
215
62
  def source_class
216
63
  source.class
217
64
  end
218
-
65
+
219
66
  # The source's association attribute: the name of the association with _ids afterwards, like "users_ids".
220
67
  #
221
68
  # @since 0.2.0
222
69
  def source_attribute
223
70
  "#{name}_ids".to_sym
224
71
  end
225
-
72
+
226
73
  # The ids in the source association.
227
74
  #
228
75
  # @since 0.2.0
@@ -232,5 +79,5 @@ module Dynamoid #:nodoc:
232
79
 
233
80
  end
234
81
  end
235
-
82
+
236
83
  end
@@ -5,39 +5,11 @@ module Dynamoid #:nodoc:
5
5
  # object to which the association object is associated.
6
6
  module Associations
7
7
  class BelongsTo
8
- include Dynamoid::Associations::Association
9
-
10
- # Is this object equal to the association's target?
11
- #
12
- # @return [Boolean] true/false
13
- #
14
- # @since 0.2.0
15
- def ==(other)
16
- target == other
17
- end
18
-
19
- # Delegate methods we don't find directly to the target.
20
- #
21
- # @since 0.2.0
22
- def method_missing(method, *args)
23
- if target.respond_to?(method)
24
- target.send(method, *args)
25
- else
26
- super
27
- end
28
- end
29
-
8
+ include Association
9
+ include SingleAssociation
10
+
30
11
  private
31
-
32
- # Find the target of the belongs_to association.
33
- #
34
- # @return [Dynamoid::Document] the found target (or nil if nothing)
35
- #
36
- # @since 0.2.0
37
- def target
38
- records.first
39
- end
40
-
12
+
41
13
  # Find the target association, either has_many or has_one. Uses either options[:inverse_of] or the source class name and default parsing to
42
14
  # return the most likely name for the target association.
43
15
  #
@@ -4,31 +4,12 @@ module Dynamoid #:nodoc:
4
4
  # The has and belongs to many association.
5
5
  module Associations
6
6
  class HasAndBelongsToMany
7
- include Dynamoid::Associations::Association
8
-
9
- # Is this array equal to the association's records?
10
- #
11
- # @return [Boolean] true/false
12
- #
13
- # @since 0.2.0
14
- def ==(other)
15
- records == Array(other)
16
- end
17
-
18
- # Delegate methods we don't find directly to the records array.
19
- #
20
- # @since 0.2.0
21
- def method_missing(method, *args)
22
- if records.respond_to?(method)
23
- records.send(method, *args)
24
- else
25
- super
26
- end
27
- end
28
-
7
+ include Association
8
+ include ManyAssociation
9
+
29
10
  private
30
-
31
- # Find the target association, always another :has_and_belongs_to_many association. Uses either options[:inverse_of] or the source class name
11
+
12
+ # Find the target association, always another :has_and_belongs_to_many association. Uses either options[:inverse_of] or the source class name
32
13
  # and default parsing to return the most likely name for the target association.
33
14
  #
34
15
  # @since 0.2.0
@@ -38,15 +19,15 @@ module Dynamoid #:nodoc:
38
19
  return nil if guess.nil? || guess[:type] != :has_and_belongs_to_many
39
20
  key_name
40
21
  end
41
-
22
+
42
23
  # Associate a source object to this association.
43
24
  #
44
- # @since 0.2.0
25
+ # @since 0.2.0
45
26
  def associate_target(object)
46
27
  ids = object.send(target_attribute) || Set.new
47
28
  object.update_attribute(target_attribute, ids.merge(Array(source.id)))
48
29
  end
49
-
30
+
50
31
  # Disassociate a source object from this association.
51
32
  #
52
33
  # @since 0.2.0
@@ -56,5 +37,5 @@ module Dynamoid #:nodoc:
56
37
  end
57
38
  end
58
39
  end
59
-
40
+
60
41
  end
@@ -4,27 +4,8 @@ module Dynamoid #:nodoc:
4
4
  # The has_many association.
5
5
  module Associations
6
6
  class HasMany
7
- include Dynamoid::Associations::Association
8
-
9
- # Is this array equal to the association's records?
10
- #
11
- # @return [Boolean] true/false
12
- #
13
- # @since 0.2.0
14
- def ==(other)
15
- records == Array(other)
16
- end
17
-
18
- # Delegate methods we don't find directly to the records array.
19
- #
20
- # @since 0.2.0
21
- def method_missing(method, *args)
22
- if records.respond_to?(method)
23
- records.send(method, *args)
24
- else
25
- super
26
- end
27
- end
7
+ include Association
8
+ include ManyAssociation
28
9
 
29
10
  private
30
11
 
@@ -4,64 +4,36 @@ module Dynamoid #:nodoc:
4
4
  # The HasOne association.
5
5
  module Associations
6
6
  class HasOne
7
- include Dynamoid::Associations::Association
8
-
9
- # Is this object equal to the association's target?
10
- #
11
- # @return [Boolean] true/false
12
- #
13
- # @since 0.2.0
14
- def ==(other)
15
- target == other
16
- end
7
+ include Association
8
+ include SingleAssociation
17
9
 
18
- # Delegate methods we don't find directly to the target.
19
- #
20
- # @since 0.2.0
21
- def method_missing(method, *args)
22
- if target.respond_to?(method)
23
- target.send(method, *args)
24
- else
25
- super
26
- end
27
- end
28
-
29
10
  private
30
-
31
- # Find the target of the has_one association.
32
- #
33
- # @return [Dynamoid::Document] the found target (or nil if nothing)
34
- #
35
- # @since 0.2.0
36
- def target
37
- records.first
38
- end
39
11
 
40
- # Find the target association, always a :belongs_to association. Uses either options[:inverse_of] or the source class name
12
+ # Find the target association, always a :belongs_to association. Uses either options[:inverse_of] or the source class name
41
13
  # and default parsing to return the most likely name for the target association.
42
14
  #
43
- # @since 0.2.0
15
+ # @since 0.2.0
44
16
  def target_association
45
17
  key_name = options[:inverse_of] || source.class.to_s.singularize.underscore.to_sym
46
18
  guess = target_class.associations[key_name]
47
19
  return nil if guess.nil? || guess[:type] != :belongs_to
48
20
  key_name
49
21
  end
50
-
22
+
51
23
  # Associate a source object to this association.
52
24
  #
53
- # @since 0.2.0
25
+ # @since 0.2.0
54
26
  def associate_target(object)
55
27
  object.update_attribute(target_attribute, Set[source.id])
56
28
  end
57
-
29
+
58
30
  # Disassociate a source object from this association.
59
31
  #
60
- # @since 0.2.0
32
+ # @since 0.2.0
61
33
  def disassociate_target(object)
62
34
  source.update_attribute(source_attribute, nil)
63
35
  end
64
36
  end
65
37
  end
66
-
38
+
67
39
  end
@@ -0,0 +1,188 @@
1
+ # encoding: utf-8
2
+ module Dynamoid #:nodoc:
3
+
4
+ module Associations
5
+ module ManyAssociation
6
+
7
+ attr_accessor :query
8
+
9
+ def initialize(*args)
10
+ @query = {}
11
+ super
12
+ end
13
+
14
+ include Enumerable
15
+ # Delegate methods to the records the association represents.
16
+ delegate :first, :last, :empty?, :size, :to => :records
17
+
18
+ # The records associated to the source.
19
+ #
20
+ # @return the association records; depending on which association this is, either a single instance or an array
21
+ #
22
+ # @since 0.2.0
23
+ def records
24
+ results = Array(target_class.find(source_ids.to_a))
25
+
26
+ if query.empty?
27
+ results
28
+ else
29
+ results_with_query(results)
30
+ end
31
+ end
32
+
33
+ # Alias convenience methods for the associations.
34
+ alias :all :records
35
+ alias :count :size
36
+ alias :nil? :empty?
37
+
38
+ # Delegate include? to the records.
39
+ def include?(object)
40
+ records.include?(object)
41
+ end
42
+
43
+ # Deletes an object or array of objects from the association. This removes their records from the association field on the source,
44
+ # and attempts to remove the source from the target association if it is detected to exist.
45
+ #
46
+ # @param [Dynamoid::Document] object the object (or array of objects) to remove from the association
47
+ #
48
+ # @return [Dynamoid::Document] the deleted object
49
+ #
50
+ # @since 0.2.0
51
+ def delete(object)
52
+ source.update_attribute(source_attribute, source_ids - Array(object).collect(&:id))
53
+ Array(object).each {|o| self.send(:disassociate_target, o)} if target_association
54
+ object
55
+ end
56
+
57
+
58
+ # Add an object or array of objects to an association. This preserves the current records in the association (if any)
59
+ # and adds the object to the target association if it is detected to exist.
60
+ #
61
+ # @param [Dynamoid::Document] object the object (or array of objects) to add to the association
62
+ #
63
+ # @return [Dynamoid::Document] the added object
64
+ #
65
+ # @since 0.2.0
66
+ def <<(object)
67
+ source.update_attribute(source_attribute, source_ids.merge(Array(object).collect(&:id)))
68
+ Array(object).each {|o| self.send(:associate_target, o)} if target_association
69
+ object
70
+ end
71
+
72
+ # Replace an association with object or array of objects. This removes all of the existing associated records and replaces them with
73
+ # the passed object(s), and associates the target association if it is detected to exist.
74
+ #
75
+ # @param [Dynamoid::Document] object the object (or array of objects) to add to the association
76
+ #
77
+ # @return [Dynamoid::Document] the added object
78
+ #
79
+ # @since 0.2.0
80
+ def setter(object)
81
+ records.each {|o| delete(o)}
82
+ self << (object)
83
+ object
84
+ end
85
+
86
+ # Create a new instance of the target class and add it directly to the association. If the create fails an exception will be raised.
87
+ #
88
+ # @param [Hash] attribute hash for the new object
89
+ #
90
+ # @return [Dynamoid::Document] the newly-created object
91
+ #
92
+ # @since 0.2.0
93
+ def create!(attributes = {})
94
+ self << target_class.create!(attributes)
95
+ end
96
+
97
+ # Create a new instance of the target class and add it directly to the association.
98
+ #
99
+ # @param [Hash] attribute hash for the new object
100
+ #
101
+ # @return [Dynamoid::Document] the newly-created object
102
+ #
103
+ # @since 0.2.0
104
+ def create(attributes = {})
105
+ self << target_class.create(attributes)
106
+ end
107
+
108
+ # Create a new instance of the target class and add it directly to the association. If the create fails an exception will be raised.
109
+ #
110
+ # @param [Hash] attribute hash for the new object
111
+ #
112
+ # @return [Dynamoid::Document] the newly-created object
113
+ #
114
+ # @since 0.2.0
115
+ def each(&block)
116
+ records.each(&block)
117
+ end
118
+
119
+ # Destroys all members of the association and removes them from the association.
120
+ #
121
+ # @since 0.2.0
122
+ def destroy_all
123
+ objs = records
124
+ source.update_attribute(source_attribute, nil)
125
+ objs.each(&:destroy)
126
+ end
127
+
128
+ # Deletes all members of the association and removes them from the association.
129
+ #
130
+ # @since 0.2.0
131
+ def delete_all
132
+ objs = records
133
+ source.update_attribute(source_attribute, nil)
134
+ objs.each(&:delete)
135
+ end
136
+
137
+ # Naive association filtering.
138
+ #
139
+ # @param [Hash] A hash of attributes; each must match every returned object's attribute exactly.
140
+ #
141
+ # @return [Dynamoid::Association] the association this method was called on (for chaining purposes)
142
+ #
143
+ # @since 0.2.0
144
+ def where(args)
145
+ args.each {|k, v| query[k] = v}
146
+ self
147
+ end
148
+
149
+ # Is this array equal to the association's records?
150
+ #
151
+ # @return [Boolean] true/false
152
+ #
153
+ # @since 0.2.0
154
+ def ==(other)
155
+ records == Array(other)
156
+ end
157
+
158
+ # Delegate methods we don't find directly to the records array.
159
+ #
160
+ # @since 0.2.0
161
+ def method_missing(method, *args)
162
+ if records.respond_to?(method)
163
+ records.send(method, *args)
164
+ else
165
+ super
166
+ end
167
+ end
168
+
169
+ private
170
+
171
+ # If a query exists, filter all existing results based on that query.
172
+ #
173
+ # @param [Array] results the raw results for the association
174
+ #
175
+ # @return [Array] the filtered results for the query
176
+ #
177
+ # @since 0.2.0
178
+ def results_with_query(results)
179
+ results.find_all do |result|
180
+ query.all? do |attribute, value|
181
+ result.send(attribute) == value
182
+ end
183
+ end
184
+ end
185
+
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ module Dynamoid #:nodoc:
3
+
4
+ module Associations
5
+ module SingleAssociation
6
+
7
+
8
+ def setter(object)
9
+ delete
10
+ source.update_attribute(source_attribute, Set[object.id])
11
+ self.send(:associate_target, object) if target_association
12
+ object
13
+ end
14
+
15
+ def delete
16
+ source.update_attribute(source_attribute, nil)
17
+ self.send(:disassociate_target, target) if target && target_association
18
+ target
19
+ end
20
+
21
+ def create!(attributes = {})
22
+ setter(target_class.create!(attributes))
23
+ end
24
+
25
+ def create(attributes = {})
26
+ setter(target_class.create!(attributes))
27
+ end
28
+
29
+
30
+ # Is this object equal to the association's target?
31
+ #
32
+ # @return [Boolean] true/false
33
+ #
34
+ # @since 0.2.0
35
+ def ==(other)
36
+ target == other
37
+ end
38
+
39
+ # Delegate methods we don't find directly to the target.
40
+ #
41
+ # @since 0.2.0
42
+ def method_missing(method, *args)
43
+ if target.respond_to?(method)
44
+ target.send(method, *args)
45
+ else
46
+ super
47
+ end
48
+ end
49
+
50
+ def nil?
51
+ target.nil?
52
+ end
53
+
54
+ private
55
+
56
+ # Find the target of the has_one association.
57
+ #
58
+ # @return [Dynamoid::Document] the found target (or nil if nothing)
59
+ #
60
+ # @since 0.2.0
61
+ def target
62
+ target_class.find(source_ids.first)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -21,11 +21,7 @@ module Dynamoid #:nodoc:
21
21
  #
22
22
  # @since 0.2.0
23
23
  def create(attrs = {})
24
- obj = self.new(attrs)
25
- obj.run_callbacks(:create) do
26
- obj.save
27
- end
28
- obj
24
+ new(attrs).tap(&:save)
29
25
  end
30
26
 
31
27
  # Initialize a new object and immediately save it to the database. Raise an exception if persistence failed.
@@ -36,11 +32,7 @@ module Dynamoid #:nodoc:
36
32
  #
37
33
  # @since 0.2.0
38
34
  def create!(attrs = {})
39
- obj = self.new(attrs)
40
- obj.run_callbacks(:create) do
41
- obj.save!
42
- end
43
- obj
35
+ new(attrs).tap(&:save!)
44
36
  end
45
37
 
46
38
  # Initialize a new object.
@@ -51,7 +43,7 @@ module Dynamoid #:nodoc:
51
43
  #
52
44
  # @since 0.2.0
53
45
  def build(attrs = {})
54
- self.new(attrs)
46
+ new(attrs)
55
47
  end
56
48
 
57
49
  # Does this object exist?
@@ -29,16 +29,12 @@ module Dynamoid #:nodoc:
29
29
  def field(name, type = :string, options = {})
30
30
  named = name.to_s
31
31
  self.attributes[name] = {:type => type}.merge(options)
32
- define_method(named) do
33
- read_attribute(named)
34
- end
35
- define_method("#{named}=") do |value|
36
- write_attribute(named, value)
37
- end
38
- define_method("#{named}?") do
39
- !read_attribute(named).nil?
40
- end
41
- define_attribute_methods(self.attributes.keys)
32
+
33
+ define_method(named) { read_attribute(named) }
34
+ define_method("#{named}?") { !read_attribute(named).nil? }
35
+ define_method("#{named}=") {|value| write_attribute(named, value) }
36
+
37
+ define_attribute_method(name)
42
38
  end
43
39
  end
44
40
 
@@ -53,7 +49,7 @@ module Dynamoid #:nodoc:
53
49
  #
54
50
  # @since 0.2.0
55
51
  def write_attribute(name, value)
56
- self.send("#{name}_will_change!".to_sym) unless self.read_attribute(name) == value
52
+ attribute_will_change!(name) unless self.read_attribute(name) == value
57
53
  attributes[name.to_sym] = value
58
54
  end
59
55
  alias :[]= :write_attribute
@@ -107,4 +103,4 @@ module Dynamoid #:nodoc:
107
103
 
108
104
  end
109
105
 
110
- end
106
+ end
@@ -100,17 +100,13 @@ module Dynamoid
100
100
  # @since 0.2.0
101
101
  def save(options = {})
102
102
  @previously_changed = changes
103
- if self.new_record?
104
- run_callbacks(:create) do
105
- run_callbacks(:save) do
106
- persist
107
- end
108
- end
103
+
104
+ if new_record?
105
+ run_callbacks(:create) { persist }
109
106
  else
110
- run_callbacks(:save) do
111
- persist
112
- end
107
+ persist
113
108
  end
109
+
114
110
  self
115
111
  end
116
112
 
@@ -177,10 +173,12 @@ module Dynamoid
177
173
  #
178
174
  # @since 0.2.0
179
175
  def persist
180
- self.id = SecureRandom.uuid if self.id.nil? || self.id.blank?
181
- Dynamoid::Adapter.write(self.class.table_name, self.dump)
182
- save_indexes
183
- @new_record = false
176
+ run_callbacks(:save) do
177
+ self.id = SecureRandom.uuid if self.id.nil? || self.id.blank?
178
+ Dynamoid::Adapter.write(self.class.table_name, self.dump)
179
+ save_indexes
180
+ !(@new_record = false)
181
+ end
184
182
  end
185
183
 
186
184
  end
@@ -19,14 +19,13 @@ describe "Dynamoid::Associations::BelongsTo" do
19
19
 
20
20
  it 'delegates equality to its source record' do
21
21
  @magazine = @subscription.magazine.create
22
-
22
+
23
23
  @subscription.magazine.should == @magazine
24
24
  end
25
25
 
26
26
  it 'associates has_many automatically' do
27
27
  @magazine = @subscription.magazine.create
28
28
 
29
- @magazine.subscriptions.size.should == 1
30
29
  @magazine.subscriptions.should include @subscription
31
30
 
32
31
  @magazine = Magazine.create
@@ -63,7 +62,6 @@ describe "Dynamoid::Associations::BelongsTo" do
63
62
  it 'associates has_one automatically' do
64
63
  @magazine = @sponsor.magazine.create
65
64
 
66
- @magazine.sponsor.size.should == 1
67
65
  @magazine.sponsor.should == @sponsor
68
66
 
69
67
  @user = @subscription.customer.create
@@ -37,7 +37,6 @@ describe "Dynamoid::Associations::HasOne" do
37
37
  it 'associates belongs_to automatically' do
38
38
  @sponsor = @magazine.sponsor.create
39
39
  @sponsor.magazine.should == @magazine
40
- @magazine.sponsor.size.should == 1
41
40
  @magazine.sponsor.should == @sponsor
42
41
 
43
42
  @subscription = @user.monthly.create
@@ -8,6 +8,14 @@ describe "Dynamoid::Document" do
8
8
  @address.new_record.should be_true
9
9
  @address.attributes.should == {:id=>nil, :created_at=>nil, :updated_at=>nil, :city=>nil, :options=>nil}
10
10
  end
11
+
12
+ it 'responds to will_change! methods for all fields' do
13
+ @address = Address.new
14
+ @address.should respond_to(:id_will_change!)
15
+ @address.should respond_to(:options_will_change!)
16
+ @address.should respond_to(:created_at_will_change!)
17
+ @address.should respond_to(:updated_at_will_change!)
18
+ end
11
19
 
12
20
  it 'initializes a new document with attributes' do
13
21
  @address = Address.new(:city => 'Chicago')
@@ -1,12 +1,14 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
3
  describe "Dynamoid::Persistence" do
4
-
4
+
5
+ let(:document_class) { Class.new.send :include, Dynamoid::Document }
6
+
5
7
  before do
6
8
  Random.stubs(:rand).with(Dynamoid::Config.partition_size).returns(0)
7
9
  @address = Address.new
8
10
  end
9
-
11
+
10
12
  context 'without AWS keys' do
11
13
  unless ENV['ACCESS_KEY'] && ENV['SECRET_KEY']
12
14
  before do
@@ -102,6 +104,30 @@ describe "Dynamoid::Persistence" do
102
104
  User.undump(@hash)[:name].should == 'Josh'
103
105
  User.undump(@hash)[:created_at].to_f == @time.to_f
104
106
  end
107
+
108
+ it 'runs the before_create callback only once' do
109
+ document_class.before_create { doing_before_create }
110
+
111
+ document_class.any_instance.expects(:doing_before_create)
112
+
113
+ document_class.create
114
+ end
115
+
116
+ it 'runs after save callbacks when doing #create' do
117
+ document_class.after_create { doing_after_create }
118
+
119
+ document_class.any_instance.expects(:doing_after_create)
120
+
121
+ document_class.create
122
+ end
123
+
124
+ it 'runs after save callbacks when doing #save' do
125
+ document_class.after_create { doing_after_create }
126
+
127
+ document_class.any_instance.expects(:doing_after_create)
128
+
129
+ document_class.new.save
130
+ end
105
131
 
106
132
  it 'tracks previous changes on save or update' do
107
133
  @address.city = 'Chicago'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynamoid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -282,6 +282,8 @@ files:
282
282
  - lib/dynamoid/associations/has_and_belongs_to_many.rb
283
283
  - lib/dynamoid/associations/has_many.rb
284
284
  - lib/dynamoid/associations/has_one.rb
285
+ - lib/dynamoid/associations/many_association.rb
286
+ - lib/dynamoid/associations/single_association.rb
285
287
  - lib/dynamoid/components.rb
286
288
  - lib/dynamoid/config.rb
287
289
  - lib/dynamoid/config/options.rb
@@ -337,7 +339,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
337
339
  version: '0'
338
340
  segments:
339
341
  - 0
340
- hash: 1952467845042018091
342
+ hash: 3564635141636457738
341
343
  required_rubygems_version: !ruby/object:Gem::Requirement
342
344
  none: false
343
345
  requirements: