dynamoid 0.2.0 → 0.3.0

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 (97) hide show
  1. data/Dynamoid.gemspec +65 -3
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +6 -0
  4. data/README.markdown +117 -22
  5. data/Rakefile +22 -9
  6. data/VERSION +1 -1
  7. data/doc/.nojekyll +0 -0
  8. data/doc/Dynamoid.html +300 -0
  9. data/doc/Dynamoid/Adapter.html +1387 -0
  10. data/doc/Dynamoid/Adapter/AwsSdk.html +1561 -0
  11. data/doc/Dynamoid/Adapter/Local.html +1487 -0
  12. data/doc/Dynamoid/Associations.html +131 -0
  13. data/doc/Dynamoid/Associations/Association.html +1706 -0
  14. data/doc/Dynamoid/Associations/BelongsTo.html +339 -0
  15. data/doc/Dynamoid/Associations/ClassMethods.html +723 -0
  16. data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +339 -0
  17. data/doc/Dynamoid/Associations/HasMany.html +339 -0
  18. data/doc/Dynamoid/Associations/HasOne.html +339 -0
  19. data/doc/Dynamoid/Components.html +202 -0
  20. data/doc/Dynamoid/Config.html +395 -0
  21. data/doc/Dynamoid/Config/Options.html +609 -0
  22. data/doc/Dynamoid/Criteria.html +131 -0
  23. data/doc/Dynamoid/Criteria/Chain.html +759 -0
  24. data/doc/Dynamoid/Criteria/ClassMethods.html +98 -0
  25. data/doc/Dynamoid/Document.html +512 -0
  26. data/doc/Dynamoid/Document/ClassMethods.html +581 -0
  27. data/doc/Dynamoid/Errors.html +118 -0
  28. data/doc/Dynamoid/Errors/DocumentNotValid.html +210 -0
  29. data/doc/Dynamoid/Errors/Error.html +130 -0
  30. data/doc/Dynamoid/Errors/InvalidField.html +133 -0
  31. data/doc/Dynamoid/Errors/MissingRangeKey.html +133 -0
  32. data/doc/Dynamoid/Fields.html +649 -0
  33. data/doc/Dynamoid/Fields/ClassMethods.html +264 -0
  34. data/doc/Dynamoid/Finders.html +128 -0
  35. data/doc/Dynamoid/Finders/ClassMethods.html +502 -0
  36. data/doc/Dynamoid/Indexes.html +308 -0
  37. data/doc/Dynamoid/Indexes/ClassMethods.html +351 -0
  38. data/doc/Dynamoid/Indexes/Index.html +1089 -0
  39. data/doc/Dynamoid/Persistence.html +653 -0
  40. data/doc/Dynamoid/Persistence/ClassMethods.html +568 -0
  41. data/doc/Dynamoid/Validations.html +399 -0
  42. data/doc/_index.html +439 -0
  43. data/doc/class_list.html +47 -0
  44. data/doc/css/common.css +1 -0
  45. data/doc/css/full_list.css +55 -0
  46. data/doc/css/style.css +322 -0
  47. data/doc/file.LICENSE.html +66 -0
  48. data/doc/file.README.html +279 -0
  49. data/doc/file_list.html +52 -0
  50. data/doc/frames.html +13 -0
  51. data/doc/index.html +279 -0
  52. data/doc/js/app.js +205 -0
  53. data/doc/js/full_list.js +173 -0
  54. data/doc/js/jquery.js +16 -0
  55. data/doc/method_list.html +1054 -0
  56. data/doc/top-level-namespace.html +105 -0
  57. data/lib/dynamoid.rb +2 -1
  58. data/lib/dynamoid/adapter.rb +77 -6
  59. data/lib/dynamoid/adapter/aws_sdk.rb +96 -16
  60. data/lib/dynamoid/adapter/local.rb +84 -15
  61. data/lib/dynamoid/associations.rb +53 -4
  62. data/lib/dynamoid/associations/association.rb +154 -26
  63. data/lib/dynamoid/associations/belongs_to.rb +32 -6
  64. data/lib/dynamoid/associations/has_and_belongs_to_many.rb +29 -3
  65. data/lib/dynamoid/associations/has_many.rb +30 -4
  66. data/lib/dynamoid/associations/has_one.rb +26 -3
  67. data/lib/dynamoid/components.rb +7 -5
  68. data/lib/dynamoid/config.rb +15 -2
  69. data/lib/dynamoid/config/options.rb +8 -0
  70. data/lib/dynamoid/criteria.rb +7 -2
  71. data/lib/dynamoid/criteria/chain.rb +55 -8
  72. data/lib/dynamoid/document.rb +68 -7
  73. data/lib/dynamoid/errors.rb +17 -2
  74. data/lib/dynamoid/fields.rb +44 -1
  75. data/lib/dynamoid/finders.rb +32 -6
  76. data/lib/dynamoid/indexes.rb +22 -2
  77. data/lib/dynamoid/indexes/index.rb +48 -7
  78. data/lib/dynamoid/persistence.rb +111 -51
  79. data/lib/dynamoid/validations.rb +36 -0
  80. data/spec/app/models/address.rb +2 -1
  81. data/spec/app/models/camel_case.rb +11 -0
  82. data/spec/app/models/magazine.rb +4 -1
  83. data/spec/app/models/sponsor.rb +3 -1
  84. data/spec/app/models/subscription.rb +5 -1
  85. data/spec/app/models/user.rb +10 -1
  86. data/spec/dynamoid/associations/association_spec.rb +67 -1
  87. data/spec/dynamoid/associations/belongs_to_spec.rb +16 -1
  88. data/spec/dynamoid/associations/has_and_belongs_to_many_spec.rb +7 -0
  89. data/spec/dynamoid/associations/has_many_spec.rb +14 -0
  90. data/spec/dynamoid/associations/has_one_spec.rb +10 -1
  91. data/spec/dynamoid/criteria_spec.rb +5 -1
  92. data/spec/dynamoid/document_spec.rb +23 -3
  93. data/spec/dynamoid/fields_spec.rb +10 -1
  94. data/spec/dynamoid/indexes/index_spec.rb +19 -0
  95. data/spec/dynamoid/persistence_spec.rb +24 -0
  96. data/spec/dynamoid/validations_spec.rb +36 -0
  97. metadata +105 -4
@@ -1,18 +1,37 @@
1
1
  module Dynamoid
2
2
  module Adapter
3
+
4
+ # This gimpy hash construct should be equivalent to Amazon's actual DynamoDB, for offline development.
5
+ # All tests pass with either this or connecting to the real DynamoDB, and that's good enough for me.
3
6
  module Local
4
7
  extend self
5
- # Gimpy hash that should be somewhat equivalent to what Amazon's actual DynamoDB, for offline development.
6
-
8
+
9
+ # The hash holding all of our data.
10
+ #
11
+ # @return [Hash] a hash of raw values
12
+ #
13
+ # @since 0.2.0
7
14
  def data
8
15
  @data ||= {}
9
16
  end
10
17
 
18
+ # A convenience method for testing that destroys all table data without destroying their structure.
19
+ #
20
+ # @since 0.2.0
11
21
  def reset_data
12
22
  self.data.each {|k, v| v[:data] = {}}
13
23
  end
14
24
 
15
- # BatchGetItem
25
+ # Get many items at once from the hash.
26
+ #
27
+ # @example Retrieve IDs 1 and 2 from the table testtable
28
+ # Dynamoid::Adapter::Local.batch_get_item('table1' => ['1', '2'])
29
+ #
30
+ # @param [Hash] options the hash of tables and IDs to retrieve
31
+ #
32
+ # @return [Hash] a hash where keys are the table names and the values are the retrieved items
33
+ #
34
+ # @since 0.2.0
16
35
  def batch_get_item(options)
17
36
  Hash.new { |h, k| h[k] = Array.new }.tap do |hash|
18
37
  options.each do |table_name, keys|
@@ -30,24 +49,48 @@ module Dynamoid
30
49
  end
31
50
  end
32
51
 
33
- # CreateTable
52
+ # Create a table.
53
+ #
54
+ # @param [String] table_name the name of the table to create
55
+ # @param [Symbol] key the table's primary key (defaults to :id)
56
+ # @param [Hash] options provide a range_key here if you want one for the table
57
+ #
58
+ # @since 0.2.0
34
59
  def create_table(table_name, key, options = {})
35
60
  data[table_name] = {:hash_key => key, :range_key => options[:range_key], :data => {}}
36
61
  end
37
62
 
38
- # DeleteItem
63
+ # Removes an item from the hash.
64
+ #
65
+ # @param [String] table_name the name of the table
66
+ # @param [String] key the hash key of the item to delete
67
+ # @param [Number] range_key the range key of the item to delete, required if the table has a composite key
68
+ #
69
+ # @since 0.2.0
39
70
  def delete_item(table_name, key, range_key = nil)
40
71
  data[table_name][:data].delete("#{key}.#{range_key}")
41
72
  end
42
73
 
43
- # DeleteTable
74
+ # Deletes an entire table from the hash.
75
+ #
76
+ # @param [String] table_name the name of the table to destroy
77
+ #
78
+ # @since 0.2.0
44
79
  def delete_table(table_name)
45
80
  data.delete(table_name)
46
81
  end
47
82
 
48
- # DescribeTable
83
+ # @todo Add a DescribeTable method.
49
84
 
50
- # GetItem
85
+ # Fetches an item from the hash.
86
+ #
87
+ # @param [String] table_name the name of the table
88
+ # @param [String] key the hash key of the item to find
89
+ # @param [Number] range_key the range key of the item to find, required if the table has a composite key
90
+ #
91
+ # @return [Hash] a hash representing the raw item
92
+ #
93
+ # @since 0.2.0
51
94
  def get_item(table_name, key, range_key = nil)
52
95
  if data[table_name][:data]
53
96
  data[table_name][:data]["#{key}.#{range_key}"]
@@ -56,19 +99,39 @@ module Dynamoid
56
99
  end
57
100
  end
58
101
 
59
- # ListTables
102
+ # List all tables on DynamoDB.
103
+ #
104
+ # @since 0.2.0
60
105
  def list_tables
61
106
  data.keys
62
107
  end
63
108
 
64
- # PutItem
109
+ # Persists an item in the hash.
110
+ #
111
+ # @param [String] table_name the name of the table
112
+ # @param [Object] object a hash or Dynamoid object to persist
113
+ #
114
+ # @since 0.2.0
65
115
  def put_item(table_name, object)
66
116
  table = data[table_name]
67
117
  table[:data][object[table[:hash_key]]]
68
118
  table[:data]["#{object[table[:hash_key]]}.#{object[table[:range_key]]}"] = object.delete_if{|k, v| v.nil? || (v.respond_to?(:empty?) && v.empty?)}
69
119
  end
70
120
 
71
- # Query
121
+ # Query the hash.
122
+ #
123
+ # @param [String] table_name the name of the table
124
+ # @param [Hash] opts the options to query the table with
125
+ # @option opts [String] :hash_value the value of the hash key to find
126
+ # @option opts [Range] :range_value find the range key within this range
127
+ # @option opts [Number] :range_greater_than find range keys greater than this
128
+ # @option opts [Number] :range_less_than find range keys less than this
129
+ # @option opts [Number] :range_gte find range keys greater than or equal to this
130
+ # @option opts [Number] :range_lte find range keys less than or equal to this
131
+ #
132
+ # @return [Array] an array of all matching items
133
+ #
134
+ # @since 0.2.0
72
135
  def query(table_name, opts = {})
73
136
  id = opts[:hash_value]
74
137
  range_key = data[table_name][:range_key]
@@ -87,16 +150,22 @@ module Dynamoid
87
150
  end
88
151
  end
89
152
 
90
- # Scan
153
+ # Scan the hash.
154
+ #
155
+ # @param [String] table_name the name of the table
156
+ # @param [Hash] scan_hash a hash of attributes: matching records will be returned by the scan
157
+ #
158
+ # @return [Array] an array of all matching items
159
+ #
160
+ # @since 0.2.0
91
161
  def scan(table_name, scan_hash)
92
162
  return [] if data[table_name].nil?
93
163
  data[table_name][:data].values.flatten.select{|d| scan_hash.all?{|k, v| !d[k].nil? && d[k] == v}}
94
164
  end
95
165
 
96
- # UpdateItem
97
-
98
- # UpdateTable
166
+ # @todo Add an UpdateItem method.
99
167
 
168
+ # @todo Add an UpdateTable method.
100
169
  end
101
170
  end
102
171
  end
@@ -1,16 +1,21 @@
1
+ # encoding: utf-8
1
2
  require 'dynamoid/associations/association'
2
3
  require 'dynamoid/associations/has_many'
3
4
  require 'dynamoid/associations/belongs_to'
4
5
  require 'dynamoid/associations/has_one'
5
6
  require 'dynamoid/associations/has_and_belongs_to_many'
6
7
 
7
- # encoding: utf-8
8
- module Dynamoid #:nodoc:
8
+ module Dynamoid
9
9
 
10
- # Connects models together through the magic of associations.
10
+ # Connects models together through the magic of associations. We enjoy four different kinds of associations presently:
11
+ # * belongs_to
12
+ # * has_and_belongs_to_many
13
+ # * has_many
14
+ # * has_one
11
15
  module Associations
12
16
  extend ActiveSupport::Concern
13
17
 
18
+ # Create the association tracking attribute and initialize it to an empty hash.
14
19
  included do
15
20
  class_attribute :associations
16
21
 
@@ -18,24 +23,68 @@ module Dynamoid #:nodoc:
18
23
  end
19
24
 
20
25
  module ClassMethods
26
+
27
+ # create a has_many association for this document.
28
+ #
29
+ # @param [Symbol] name the name of the association
30
+ # @param [Hash] options options to pass to the association constructor
31
+ # @option options [Class] :class the target class of the has_many association; that is, the belongs_to class
32
+ # @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the belongs_to class
33
+ # @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a belongs_to association, the name of that association
34
+ #
35
+ # @since 0.2.0
21
36
  def has_many(name, options = {})
22
37
  association(:has_many, name, options)
23
38
  end
24
39
 
40
+ # create a has_one association for this document.
41
+ #
42
+ # @param [Symbol] name the name of the association
43
+ # @param [Hash] options options to pass to the association constructor
44
+ # @option options [Class] :class the target class of the has_one association; that is, the belongs_to class
45
+ # @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the belongs_to class
46
+ # @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a belongs_to association, the name of that association
47
+ #
48
+ # @since 0.2.0
25
49
  def has_one(name, options = {})
26
50
  association(:has_one, name, options)
27
51
  end
28
52
 
53
+ # create a belongs_to association for this document.
54
+ #
55
+ # @param [Symbol] name the name of the association
56
+ # @param [Hash] options options to pass to the association constructor
57
+ # @option options [Class] :class the target class of the has_one association; that is, the has_many or has_one class
58
+ # @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the has_many or has_one class
59
+ # @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a has_many or has_one association, the name of that association
60
+ #
61
+ # @since 0.2.0
29
62
  def belongs_to(name, options = {})
30
63
  association(:belongs_to, name, options)
31
64
  end
32
65
 
66
+ # create a has_and_belongs_to_many association for this document.
67
+ #
68
+ # @param [Symbol] name the name of the association
69
+ # @param [Hash] options options to pass to the association constructor
70
+ # @option options [Class] :class the target class of the has_and_belongs_to_many association; that is, the belongs_to class
71
+ # @option options [Symbol] :class_name the name of the target class of the association; that is, the name of the belongs_to class
72
+ # @option options [Symbol] :inverse_of the name of the association on the target class; that is, if the class has a belongs_to association, the name of that association
73
+ #
74
+ # @since 0.2.0
33
75
  def has_and_belongs_to_many(name, options = {})
34
76
  association(:has_and_belongs_to_many, name, options)
35
77
  end
36
78
 
37
79
  private
38
-
80
+
81
+ # create getters and setters for an association.
82
+ #
83
+ # @param [Symbol] symbol the type (:has_one, :has_many, :has_and_belongs_to_many, :belongs_to) of the association
84
+ # @param [Symbol] name the name of the association
85
+ # @param [Hash] options options to pass to the association constructor; see above for all valid options
86
+ #
87
+ # @since 0.2.0
39
88
  def association(type, name, options = {})
40
89
  field "#{name}_ids".to_sym, :set
41
90
  self.associations[name] = options.merge(:type => type)
@@ -1,12 +1,29 @@
1
1
  # encoding: utf-8
2
2
  module Dynamoid #:nodoc:
3
3
 
4
- # The base association module.
4
+ # The base association module which all associations include. Every association has two very important components: the source and
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
+ # The target is the object which is referencing by this association.
5
7
  module Associations
6
8
  module Association
7
9
  attr_accessor :name, :options, :source, :query
8
10
  include Enumerable
9
11
 
12
+ # Delegate methods to the records the association represents.
13
+ delegate :first, :last, :empty?, :size, :to => :records
14
+
15
+ # Create a new association.
16
+ #
17
+ # @param [Class] source the source record of the association; that is, the record that you already have
18
+ # @param [Symbol] name the name of the association
19
+ # @param [Hash] options optional parameters for the association
20
+ # @option options [Class] :class the target class of the association; that is, the class to which the association objects belong
21
+ # @option options [Symbol] :class_name the name of the target class of the association; only this or Class is necessary
22
+ # @option options [Symbol] :inverse_of the name of the association on the target class
23
+ #
24
+ # @return [Dynamoid::Association] the actual association instance itself
25
+ #
26
+ # @since 0.2.0
10
27
  def initialize(source, name, options)
11
28
  @name = name
12
29
  @options = options
@@ -14,62 +31,148 @@ module Dynamoid #:nodoc:
14
31
  @query = {}
15
32
  end
16
33
 
17
- def records
18
- results = target_class.find(source_ids.to_a)
19
- results = results.nil? ? [] : Array(results)
20
- return results if query.empty?
21
- results_with_query(results)
22
- end
23
- alias :all :records
24
-
25
- def empty?
26
- records.empty?
27
- end
34
+ # Alias convenience methods for the associations.
28
35
  alias :nil? :empty?
36
+ alias :count :size
29
37
 
30
- def size
31
- records.count
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
32
51
  end
33
- alias :count :size
52
+ alias :all :records
34
53
 
54
+ # Delegate include? to the records.
35
55
  def include?(object)
36
56
  records.include?(object)
37
57
  end
38
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
39
69
  def delete(object)
40
70
  source.update_attribute(source_attribute, source_ids - Array(object).collect(&:id))
41
71
  Array(object).collect{|o| self.send(:disassociate_target, o)} if target_association
42
72
  object
43
73
  end
44
-
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
45
83
  def <<(object)
46
84
  source.update_attribute(source_attribute, source_ids.merge(Array(object).collect(&:id)))
47
85
  Array(object).collect{|o| self.send(:associate_target, o)} if target_association
48
86
  object
49
87
  end
50
-
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
51
97
  def setter(object)
52
- source.update_attribute(source_attribute, Array(object).collect(&:id))
53
- Array(object).collect{|o| self.send(:associate_target, o)} if target_association
98
+ records.each {|o| delete(o)}
99
+ self << (object)
54
100
  object
55
101
  end
56
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
57
110
  def create(attributes = {})
58
- object = target_class.create(attributes)
59
- self << object
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)
60
123
  end
61
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
62
133
  def where(args)
63
134
  args.each {|k, v| query[k] = v}
64
135
  self
65
136
  end
66
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
67
145
  def each(&block)
68
146
  records.each(&block)
69
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
+ end
157
+
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
70
166
 
71
167
  private
72
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
73
176
  def results_with_query(results)
74
177
  results.find_all do |result|
75
178
  query.all? do |attribute, value|
@@ -77,27 +180,52 @@ module Dynamoid #:nodoc:
77
180
  end
78
181
  end
79
182
  end
80
-
183
+
184
+ # The target class name, either inferred through the association's name or specified in options.
185
+ #
186
+ # @since 0.2.0
187
+ def target_class_name
188
+ options[:class_name] || name.to_s.classify
189
+ end
190
+
191
+ # The target class, either inferred through the association's name or specified in options.
192
+ #
193
+ # @since 0.2.0
81
194
  def target_class
82
- name.to_s.singularize.capitalize.constantize
195
+ options[:class] || target_class_name.constantize
83
196
  end
84
197
 
198
+ # The target attribute: that is, the attribute on each object of the association that should reference the source.
199
+ #
200
+ # @since 0.2.0
85
201
  def target_attribute
86
202
  "#{target_association}_ids".to_sym if target_association
87
203
  end
88
-
204
+
205
+ # The ids in the target association.
206
+ #
207
+ # @since 0.2.0
89
208
  def target_ids
90
209
  target.send(target_attribute) || Set.new
91
210
  end
92
-
211
+
212
+ # The ids in the target association.
213
+ #
214
+ # @since 0.2.0
93
215
  def source_class
94
216
  source.class
95
217
  end
96
218
 
219
+ # The source's association attribute: the name of the association with _ids afterwards, like "users_ids".
220
+ #
221
+ # @since 0.2.0
97
222
  def source_attribute
98
223
  "#{name}_ids".to_sym
99
224
  end
100
225
 
226
+ # The ids in the source association.
227
+ #
228
+ # @since 0.2.0
101
229
  def source_ids
102
230
  source.send(source_attribute) || Set.new
103
231
  end
@@ -105,4 +233,4 @@ module Dynamoid #:nodoc:
105
233
  end
106
234
  end
107
235
 
108
- end
236
+ end