synamoid 1.2.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.
@@ -0,0 +1,16 @@
1
+ module Dynamoid
2
+ module Middleware
3
+ class IdentityMap
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ Dynamoid::IdentityMap.clear
10
+ @app.call(env)
11
+ ensure
12
+ Dynamoid::IdentityMap.clear
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,359 @@
1
+ require 'bigdecimal'
2
+ require 'securerandom'
3
+ require 'yaml'
4
+
5
+ # encoding: utf-8
6
+ module Dynamoid
7
+
8
+ # Persistence is responsible for dumping objects to and marshalling objects from the datastore. It tries to reserialize
9
+ # values to be of the same type as when they were passed in, based on the fields in the class.
10
+ module Persistence
11
+ extend ActiveSupport::Concern
12
+
13
+ attr_accessor :new_record
14
+ alias :new_record? :new_record
15
+
16
+ module ClassMethods
17
+
18
+ def table_name
19
+ table_base_name = options[:name] || base_class.name.split('::').last
20
+ .downcase.pluralize
21
+
22
+ @table_name ||= [Dynamoid::Config.namespace.to_s,table_base_name].reject(&:empty?).join("_")
23
+ end
24
+
25
+ # Creates a table.
26
+ #
27
+ # @param [Hash] options options to pass for table creation
28
+ # @option options [Symbol] :id the id field for the table
29
+ # @option options [Symbol] :table_name the actual name for the table
30
+ # @option options [Integer] :read_capacity set the read capacity for the table; does not work on existing tables
31
+ # @option options [Integer] :write_capacity set the write capacity for the table; does not work on existing tables
32
+ # @option options [Hash] {range_key => :type} a hash of the name of the range key and a symbol of its type
33
+ # @option options [Symbol] :hash_key_type the dynamo type of the hash key (:string or :number)
34
+ # @since 0.4.0
35
+ def create_table(options = {})
36
+ if self.range_key
37
+ range_key_hash = { range_key => dynamo_type(attributes[range_key][:type]) }
38
+ else
39
+ range_key_hash = nil
40
+ end
41
+ options = {
42
+ :id => self.hash_key,
43
+ :table_name => self.table_name,
44
+ :write_capacity => self.write_capacity,
45
+ :read_capacity => self.read_capacity,
46
+ :range_key => range_key_hash,
47
+ :hash_key_type => dynamo_type(attributes[self.hash_key][:type]),
48
+ :local_secondary_indexes => self.local_secondary_indexes.values,
49
+ :global_secondary_indexes => self.global_secondary_indexes.values
50
+ }.merge(options)
51
+
52
+ Dynamoid.adapter.create_table(options[:table_name], options[:id], options)
53
+ end
54
+
55
+ def from_database(attrs = {})
56
+ clazz = attrs[:type] ? obj = attrs[:type].constantize : self
57
+ clazz.new(attrs).tap { |r| r.new_record = false }
58
+ end
59
+
60
+ # Undump an object into a hash, converting each type from a string representation of itself into the type specified by the field.
61
+ #
62
+ # @since 0.2.0
63
+ def undump(incoming = nil)
64
+ incoming = (incoming || {}).symbolize_keys
65
+ Hash.new.tap do |hash|
66
+ self.attributes.each do |attribute, options|
67
+ hash[attribute] = undump_field(incoming[attribute], options)
68
+ end
69
+ incoming.each {|attribute, value| hash[attribute] = value unless hash.has_key? attribute }
70
+ end
71
+ end
72
+
73
+ # Undump a string value for a given type.
74
+ #
75
+ # @since 0.2.0
76
+ def undump_field(value, options)
77
+ if (field_class = options[:type]).is_a?(Class)
78
+ raise 'Dynamoid class-type fields do not support default values' if options[:default]
79
+
80
+ if field_class.respond_to?(:dynamoid_load)
81
+ field_class.dynamoid_load(value)
82
+ end
83
+ elsif options[:type] == :serialized
84
+ if value.is_a?(String)
85
+ options[:serializer] ? options[:serializer].load(value) : YAML.load(value)
86
+ else
87
+ value
88
+ end
89
+ else
90
+ if value.nil? && (default_value = options[:default])
91
+ value = default_value.respond_to?(:call) ? default_value.call : default_value
92
+ end
93
+
94
+ unless value.nil?
95
+ case options[:type]
96
+ when :string
97
+ value.to_s
98
+ when :integer
99
+ Integer(value)
100
+ when :number
101
+ BigDecimal.new(value.to_s)
102
+ when :array
103
+ value.to_a
104
+ when :raw
105
+ if value.is_a?(Hash)
106
+ undump_hash(value)
107
+ else
108
+ value
109
+ end
110
+ when :set
111
+ Set.new(value)
112
+ when :datetime
113
+ if value.is_a?(Date) || value.is_a?(DateTime) || value.is_a?(Time)
114
+ value
115
+ else
116
+ Time.at(value).to_datetime
117
+ end
118
+ when :boolean
119
+ # persisted as 't', but because undump is called during initialize it can come in as true
120
+ if value == 't' || value == true
121
+ true
122
+ elsif value == 'f' || value == false
123
+ false
124
+ else
125
+ raise ArgumentError, "Boolean column neither true nor false"
126
+ end
127
+ else
128
+ raise ArgumentError, "Unknown type #{options[:type]}"
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ def dynamo_type(type)
135
+ if type.is_a?(Class)
136
+ type.respond_to?(:dynamoid_field_type) ? type.dynamoid_field_type : :string
137
+ else
138
+ case type
139
+ when :integer, :number, :datetime
140
+ :number
141
+ when :string, :serialized
142
+ :string
143
+ else
144
+ raise 'unknown type'
145
+ end
146
+ end
147
+ end
148
+
149
+ private
150
+
151
+ def undump_hash(hash)
152
+ {}.tap do |h|
153
+ hash.each { |key, value| h[key.to_sym] = undump_hash_value(value) }
154
+ end
155
+ end
156
+
157
+ def undump_hash_value(val)
158
+ case val
159
+ when BigDecimal
160
+ if Dynamoid::Config.convert_big_decimal
161
+ val.to_f
162
+ else
163
+ val
164
+ end
165
+ when Hash
166
+ undump_hash(val)
167
+ when Array
168
+ val.map { |v| undump_hash_value(v) }
169
+ else
170
+ val
171
+ end
172
+ end
173
+ end
174
+
175
+ # Set updated_at and any passed in field to current DateTime. Useful for things like last_login_at, etc.
176
+ #
177
+ def touch(name = nil)
178
+ now = DateTime.now
179
+ self.updated_at = now
180
+ attributes[name] = now if name
181
+ save
182
+ end
183
+
184
+ # Is this object persisted in the datastore? Required for some ActiveModel integration stuff.
185
+ #
186
+ # @since 0.2.0
187
+ def persisted?
188
+ !new_record?
189
+ end
190
+
191
+ # Run the callbacks and then persist this object in the datastore.
192
+ #
193
+ # @since 0.2.0
194
+ def save(options = {})
195
+ self.class.create_table
196
+
197
+ if new_record?
198
+ conditions = { :unless_exists => [self.class.hash_key]}
199
+ conditions[:unless_exists] << range_key if(range_key)
200
+
201
+ run_callbacks(:create) { persist(conditions) }
202
+ else
203
+ persist
204
+ end
205
+
206
+ self
207
+ end
208
+
209
+ #
210
+ # update!() will increment the lock_version if the table has the column, but will not check it. Thus, a concurrent save will
211
+ # never cause an update! to fail, but an update! may cause a concurrent save to fail.
212
+ #
213
+ #
214
+ def update!(conditions = {}, &block)
215
+ run_callbacks(:update) do
216
+ options = range_key ? {:range_key => dump_field(self.read_attribute(range_key), self.class.attributes[range_key])} : {}
217
+
218
+ begin
219
+ new_attrs = Dynamoid.adapter.update_item(self.class.table_name, self.hash_key, options.merge(:conditions => conditions)) do |t|
220
+ if(self.class.attributes[:lock_version])
221
+ t.add(lock_version: 1)
222
+ end
223
+
224
+ yield t
225
+ end
226
+ load(new_attrs)
227
+ rescue Dynamoid::Errors::ConditionalCheckFailedException
228
+ raise Dynamoid::Errors::StaleObjectError.new(self, 'update')
229
+ end
230
+ end
231
+ end
232
+
233
+ def update(conditions = {}, &block)
234
+ update!(conditions, &block)
235
+ true
236
+ rescue Dynamoid::Errors::StaleObjectError
237
+ false
238
+ end
239
+
240
+ # Delete this object, but only after running callbacks for it.
241
+ #
242
+ # @since 0.2.0
243
+ def destroy
244
+ run_callbacks(:destroy) do
245
+ self.delete
246
+ end
247
+ self
248
+ end
249
+
250
+ # Delete this object from the datastore.
251
+ #
252
+ # @since 0.2.0
253
+ def delete
254
+ options = range_key ? {:range_key => dump_field(self.read_attribute(range_key), self.class.attributes[range_key])} : {}
255
+
256
+ # Add an optimistic locking check if the lock_version column exists
257
+ if(self.class.attributes[:lock_version])
258
+ conditions = {:if => {}}
259
+ conditions[:if][:lock_version] =
260
+ if changes[:lock_version].nil?
261
+ self.lock_version
262
+ else
263
+ changes[:lock_version][0]
264
+ end
265
+ options[:conditions] = conditions
266
+ end
267
+ Dynamoid.adapter.delete(self.class.table_name, self.hash_key, options)
268
+ rescue Dynamoid::Errors::ConditionalCheckFailedException
269
+ raise Dynamoid::Errors::StaleObjectError.new(self, 'delete')
270
+ end
271
+
272
+ # Dump this object's attributes into hash form, fit to be persisted into the datastore.
273
+ #
274
+ # @since 0.2.0
275
+ def dump
276
+ Hash.new.tap do |hash|
277
+ self.class.attributes.each do |attribute, options|
278
+ hash[attribute] = dump_field(self.read_attribute(attribute), options)
279
+ end
280
+ end
281
+ end
282
+
283
+ private
284
+
285
+ # Determine how to dump this field. Given a value, it'll determine how to turn it into a value that can be
286
+ # persisted into the datastore.
287
+ #
288
+ # @since 0.2.0
289
+ def dump_field(value, options)
290
+ if (field_class = options[:type]).is_a?(Class)
291
+ if value.respond_to?(:dynamoid_dump)
292
+ value.dynamoid_dump
293
+ elsif field_class.respond_to?(:dynamoid_dump)
294
+ field_class.dynamoid_dump(value)
295
+ else
296
+ raise ArgumentError, "Neither #{field_class} nor #{value} support serialization for Dynamoid."
297
+ end
298
+ else
299
+ case options[:type]
300
+ when :string
301
+ !value.nil? ? value.to_s : nil
302
+ when :integer
303
+ !value.nil? ? Integer(value) : nil
304
+ when :number
305
+ !value.nil? ? value : nil
306
+ when :set
307
+ !value.nil? ? Set.new(value) : nil
308
+ when :array
309
+ !value.nil? ? value : nil
310
+ when :datetime
311
+ !value.nil? ? value.to_time.to_f : nil
312
+ when :serialized
313
+ options[:serializer] ? options[:serializer].dump(value) : value.to_yaml
314
+ when :raw
315
+ !value.nil? ? value : nil
316
+ when :boolean
317
+ !value.nil? ? value.to_s[0] : nil
318
+ else
319
+ raise ArgumentError, "Unknown type #{options[:type]}"
320
+ end
321
+ end
322
+ end
323
+
324
+ # Persist the object into the datastore. Assign it an id first if it doesn't have one.
325
+ #
326
+ # @since 0.2.0
327
+ def persist(conditions = nil)
328
+ run_callbacks(:save) do
329
+ self.hash_key = SecureRandom.uuid if self.hash_key.nil? || self.hash_key.blank?
330
+
331
+ # Add an exists check to prevent overwriting existing records with new ones
332
+ if(new_record?)
333
+ conditions ||= {}
334
+ (conditions[:unless_exists] ||= []) << self.class.hash_key
335
+ end
336
+
337
+ # Add an optimistic locking check if the lock_version column exists
338
+ if(self.class.attributes[:lock_version])
339
+ conditions ||= {}
340
+ self.lock_version = (lock_version || 0) + 1
341
+ #Uses the original lock_version value from ActiveModel::Dirty in case user changed lock_version manually
342
+ (conditions[:if] ||= {})[:lock_version] = changes[:lock_version][0] if(changes[:lock_version][0])
343
+ end
344
+
345
+ begin
346
+ Dynamoid.adapter.write(self.class.table_name, self.dump, conditions)
347
+ @new_record = false
348
+ true
349
+ rescue Dynamoid::Errors::ConditionalCheckFailedException => e
350
+ if new_record?
351
+ raise Dynamoid::Errors::RecordNotUnique.new(e, self)
352
+ else
353
+ raise Dynamoid::Errors::StaleObjectError.new(self, 'persist')
354
+ end
355
+ end
356
+ end
357
+ end
358
+ end
359
+ end
@@ -0,0 +1,63 @@
1
+ # encoding: utf-8
2
+ module Dynamoid
3
+
4
+ # Provide ActiveModel validations to Dynamoid documents.
5
+ module Validations
6
+ extend ActiveSupport::Concern
7
+
8
+ include ActiveModel::Validations
9
+ include ActiveModel::Validations::Callbacks
10
+
11
+ # Override save to provide validation support.
12
+ #
13
+ # @since 0.2.0
14
+ def save(options = {})
15
+ options.reverse_merge!(:validate => true)
16
+ return false if options[:validate] and (not valid?)
17
+ super
18
+ end
19
+
20
+ # Is this object valid?
21
+ #
22
+ # @since 0.2.0
23
+ def valid?(context = nil)
24
+ context ||= (new_record? ? :create : :update)
25
+ super(context)
26
+ end
27
+
28
+ # Raise an error unless this object is valid.
29
+ #
30
+ # @since 0.2.0
31
+ def save!
32
+ raise Dynamoid::Errors::DocumentNotValid.new(self) unless valid?
33
+ save(:validate => false)
34
+ end
35
+
36
+ module ClassMethods
37
+
38
+ # Override validates_presence_of to handle false values as present.
39
+ #
40
+ # @since 1.1.1
41
+ def validates_presence_of(*attr_names)
42
+ validates_with PresenceValidator, _merge_attributes(attr_names)
43
+ end
44
+
45
+ private
46
+
47
+ # Validates that the specified attributes are present (false or not blank).
48
+ class PresenceValidator < ActiveModel::EachValidator
49
+ # Validate the record for the record and value.
50
+ def validate_each(record, attr_name, value)
51
+ record.errors.add(attr_name, :blank, options) if not_present?(value)
52
+ end
53
+
54
+ private
55
+
56
+ # Check whether a value is not present.
57
+ def not_present?(value)
58
+ value.blank? && value != false
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module Dynamoid
2
+ VERSION = "1.2.1"
3
+ end
metadata ADDED
@@ -0,0 +1,266 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: synamoid
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Josh Symonds
8
+ - Logan Bowers
9
+ - Craig Heneveld
10
+ - Anatha Kumaran
11
+ - Jason Dew
12
+ - Luis Arias
13
+ - Stefan Neculai
14
+ - Philip White
15
+ - Peeyush Kumar
16
+ - Sumanth Ravipati
17
+ - Pascal Corpet
18
+ - Brian Glusman
19
+ - Peter Boling
20
+ autorequire:
21
+ bindir: exe
22
+ cert_chain: []
23
+ date: 2016-09-26 00:00:00.000000000 Z
24
+ dependencies:
25
+ - !ruby/object:Gem::Dependency
26
+ name: activemodel
27
+ requirement: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - "~>"
30
+ - !ruby/object:Gem::Version
31
+ version: '5'
32
+ type: :runtime
33
+ prerelease: false
34
+ version_requirements: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '5'
39
+ - !ruby/object:Gem::Dependency
40
+ name: activemodel-serializers-xml
41
+ requirement: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '1'
46
+ type: :runtime
47
+ prerelease: false
48
+ version_requirements: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: '1'
53
+ - !ruby/object:Gem::Dependency
54
+ name: aws-sdk-resources
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '2'
60
+ type: :runtime
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '2'
67
+ - !ruby/object:Gem::Dependency
68
+ name: concurrent-ruby
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '1.0'
74
+ type: :runtime
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '1.0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: rake
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '10'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '10'
95
+ - !ruby/object:Gem::Dependency
96
+ name: bundler
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '1.12'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '1.12'
109
+ - !ruby/object:Gem::Dependency
110
+ name: rspec
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '3'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '3'
123
+ - !ruby/object:Gem::Dependency
124
+ name: yard
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ - !ruby/object:Gem::Dependency
138
+ name: github-markup
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ - !ruby/object:Gem::Dependency
152
+ name: pry
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ type: :development
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ - !ruby/object:Gem::Dependency
166
+ name: coveralls
167
+ requirement: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ type: :development
173
+ prerelease: false
174
+ version_requirements: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ - !ruby/object:Gem::Dependency
180
+ name: rspec-retry
181
+ requirement: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: '0'
186
+ type: :development
187
+ prerelease: false
188
+ version_requirements: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: '0'
193
+ description: Dynamoid is an ORM for Amazon's DynamoDB that supports offline development,
194
+ associations, querying, and everything else you'd expect from an ActiveRecord-style
195
+ replacement.
196
+ email:
197
+ - peter.boling@gmail.com
198
+ - brian@stellaservice.com
199
+ executables: []
200
+ extensions: []
201
+ extra_rdoc_files:
202
+ - LICENSE.txt
203
+ - README.md
204
+ files:
205
+ - ".document"
206
+ - ".gitignore"
207
+ - ".rspec"
208
+ - ".travis.yml"
209
+ - CHANGELOG.md
210
+ - Gemfile
211
+ - LICENSE.txt
212
+ - README.md
213
+ - Rakefile
214
+ - dynamoid.gemspec
215
+ - lib/dynamoid.rb
216
+ - lib/dynamoid/adapter.rb
217
+ - lib/dynamoid/adapter_plugin/aws_sdk_v2.rb
218
+ - lib/dynamoid/associations.rb
219
+ - lib/dynamoid/associations/association.rb
220
+ - lib/dynamoid/associations/belongs_to.rb
221
+ - lib/dynamoid/associations/has_and_belongs_to_many.rb
222
+ - lib/dynamoid/associations/has_many.rb
223
+ - lib/dynamoid/associations/has_one.rb
224
+ - lib/dynamoid/associations/many_association.rb
225
+ - lib/dynamoid/associations/single_association.rb
226
+ - lib/dynamoid/components.rb
227
+ - lib/dynamoid/config.rb
228
+ - lib/dynamoid/config/options.rb
229
+ - lib/dynamoid/criteria.rb
230
+ - lib/dynamoid/criteria/chain.rb
231
+ - lib/dynamoid/dirty.rb
232
+ - lib/dynamoid/document.rb
233
+ - lib/dynamoid/errors.rb
234
+ - lib/dynamoid/fields.rb
235
+ - lib/dynamoid/finders.rb
236
+ - lib/dynamoid/identity_map.rb
237
+ - lib/dynamoid/indexes.rb
238
+ - lib/dynamoid/middleware/identity_map.rb
239
+ - lib/dynamoid/persistence.rb
240
+ - lib/dynamoid/validations.rb
241
+ - lib/dynamoid/version.rb
242
+ homepage: http://github.com/Dynamoid/Dynamoid
243
+ licenses:
244
+ - MIT
245
+ metadata: {}
246
+ post_install_message:
247
+ rdoc_options: []
248
+ require_paths:
249
+ - lib
250
+ required_ruby_version: !ruby/object:Gem::Requirement
251
+ requirements:
252
+ - - ">="
253
+ - !ruby/object:Gem::Version
254
+ version: '0'
255
+ required_rubygems_version: !ruby/object:Gem::Requirement
256
+ requirements:
257
+ - - ">="
258
+ - !ruby/object:Gem::Version
259
+ version: '0'
260
+ requirements: []
261
+ rubyforge_project:
262
+ rubygems_version: 2.5.1
263
+ signing_key:
264
+ specification_version: 4
265
+ summary: Dynamoid is an ORM for Amazon's DynamoDB
266
+ test_files: []