ampere 0.1.3 → 1.0.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.
- data/.rvmrc +1 -1
- data/README.md +26 -6
- data/VERSION +1 -1
- data/ampere.gemspec +3 -3
- data/lib/ampere/model.rb +189 -176
- data/spec/models/indices_spec.rb +17 -7
- data/spec/models/model_spec.rb +9 -3
- data/spec/models/queries_spec.rb +3 -1
- data/spec/models/relationships/belongs_to_spec.rb +9 -3
- data/spec/models/relationships/has_many_spec.rb +6 -2
- data/spec/models/relationships/has_one_spec.rb +6 -2
- data/spec/models/updates_spec.rb +3 -1
- data/spec/module/collections_spec.rb +3 -1
- metadata +20 -20
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm use 1.9.
|
1
|
+
rvm use 1.9.3@ampere
|
data/README.md
CHANGED
@@ -5,12 +5,24 @@ Ampere is an ActiveRecord-style ORM for the Redis key/value data store.
|
|
5
5
|
This is under active development right now and not very far along. Stay
|
6
6
|
tuned for further developments.
|
7
7
|
|
8
|
+
## A note about version 1.0 (IMPORTANT!!!)
|
9
|
+
|
10
|
+
For the 1.0 release I changed Ampere's API so that instead of subclassing
|
11
|
+
`Ampere::Model` to use Ampere's methods, you include it as a mixin. This
|
12
|
+
change has been reflected in the examples below.
|
13
|
+
|
14
|
+
This change was to unify the usage of Ampere a little more with usage of
|
15
|
+
Mongoid, and also so that users of Ampere can use their own class hierarchies,
|
16
|
+
which at some later date might have significance with how Ampere works.
|
17
|
+
|
8
18
|
## Usage
|
9
19
|
|
10
20
|
Write a model class and make it inherit from the `Ampere::Model` class.
|
11
21
|
These work pretty similarly to how they do in ActiveRecord or Mongoid.
|
12
22
|
|
13
|
-
class Car
|
23
|
+
class Car
|
24
|
+
include Ampere::Model
|
25
|
+
|
14
26
|
field :make
|
15
27
|
field :model
|
16
28
|
field :year
|
@@ -19,7 +31,9 @@ These work pretty similarly to how they do in ActiveRecord or Mongoid.
|
|
19
31
|
has_many :passengers
|
20
32
|
end
|
21
33
|
|
22
|
-
class Engine
|
34
|
+
class Engine
|
35
|
+
include Ampere::Model
|
36
|
+
|
23
37
|
field :displacement
|
24
38
|
field :cylinders
|
25
39
|
field :configuration
|
@@ -27,7 +41,9 @@ These work pretty similarly to how they do in ActiveRecord or Mongoid.
|
|
27
41
|
belongs_to :car
|
28
42
|
end
|
29
43
|
|
30
|
-
class Passenger
|
44
|
+
class Passenger
|
45
|
+
include Ampere::Model
|
46
|
+
|
31
47
|
field :name
|
32
48
|
field :seat
|
33
49
|
|
@@ -46,9 +62,11 @@ be slower if one of the keys you are searching by isn't indexed).
|
|
46
62
|
|
47
63
|
### Indexes
|
48
64
|
|
49
|
-
Indexes work similar to Mongoid. They are non-unique.
|
65
|
+
Indexes work similar to Mongoid. They are non-unique by default.
|
50
66
|
|
51
|
-
class Student
|
67
|
+
class Student
|
68
|
+
include Ampere::Model
|
69
|
+
|
52
70
|
field :last_name
|
53
71
|
field :first_name
|
54
72
|
|
@@ -60,7 +78,9 @@ last_name will happen faster.
|
|
60
78
|
|
61
79
|
You can also define indices on multiple fields.
|
62
80
|
|
63
|
-
class Student
|
81
|
+
class Student
|
82
|
+
include Ampere::Model
|
83
|
+
|
64
84
|
field :last_name
|
65
85
|
field :first_name
|
66
86
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
data/ampere.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "ampere"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "1.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Max Thom Stahl"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-04-20"
|
13
13
|
s.description = "An ActiveRecord/Mongoid-esque object model for the Redis key/value data store."
|
14
14
|
s.email = "max@villainousindustri.es"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -49,7 +49,7 @@ Gem::Specification.new do |s|
|
|
49
49
|
s.homepage = "http://github.com/mstahl/ampere"
|
50
50
|
s.licenses = ["EPL"]
|
51
51
|
s.require_paths = ["lib"]
|
52
|
-
s.rubygems_version = "1.8.
|
52
|
+
s.rubygems_version = "1.8.17"
|
53
53
|
s.summary = "A pure Ruby ORM for Redis."
|
54
54
|
|
55
55
|
if s.respond_to? :specification_version then
|
data/lib/ampere/model.rb
CHANGED
@@ -1,11 +1,23 @@
|
|
1
1
|
module Ampere
|
2
|
-
|
3
|
-
attr_reader :id
|
2
|
+
module Model
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
|
7
|
+
base.class_eval do
|
8
|
+
attr_reader :id
|
9
|
+
|
10
|
+
attr_accessor :fields
|
11
|
+
attr_accessor :field_defaults
|
12
|
+
attr_accessor :indices
|
13
|
+
attr_accessor :field_types
|
14
|
+
|
15
|
+
@fields = []
|
16
|
+
@field_defaults = {}
|
17
|
+
@indices = []
|
18
|
+
@field_types = {}
|
19
|
+
end
|
20
|
+
end
|
9
21
|
|
10
22
|
### Instance methods
|
11
23
|
|
@@ -138,225 +150,226 @@ module Ampere
|
|
138
150
|
|
139
151
|
### Class methods
|
140
152
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
153
|
+
module ClassMethods
|
154
|
+
# Returns an array of all the records that have been stored.
|
155
|
+
def all
|
156
|
+
Ampere.connection.keys("#{to_s.downcase}.*").map{|m| find m}
|
157
|
+
end
|
145
158
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
159
|
+
# Declares a belongs_to relationship to another model.
|
160
|
+
def belongs_to(field_name, options = {})
|
161
|
+
has_one field_name, options
|
162
|
+
end
|
150
163
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
164
|
+
# Like @indices, but only returns the compound indices this class defines.
|
165
|
+
def compound_indices
|
166
|
+
@indices.select{|i| i.class == Array}
|
167
|
+
end
|
155
168
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
169
|
+
# Returns the number of instances of this record that have been stored.
|
170
|
+
def count
|
171
|
+
Ampere.connection.keys("#{to_s.downcase}.*").length
|
172
|
+
end
|
160
173
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
174
|
+
# Instantiates and saves a new record.
|
175
|
+
def create(hash = {})
|
176
|
+
new(hash).save
|
177
|
+
end
|
165
178
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
179
|
+
# Deletes the record with the given ID.
|
180
|
+
def delete(id)
|
181
|
+
Ampere.connection.del(id)
|
182
|
+
end
|
170
183
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
184
|
+
# Declares a field. See the README for more details.
|
185
|
+
def field(name, options = {})
|
186
|
+
@fields ||= []
|
187
|
+
@field_defaults ||= {}
|
188
|
+
@indices ||= []
|
189
|
+
@unique_indices ||= []
|
190
|
+
@field_types ||= {}
|
178
191
|
|
179
|
-
|
192
|
+
@fields << name
|
180
193
|
|
181
|
-
|
194
|
+
# attr_accessor :"#{name}"
|
182
195
|
|
183
|
-
|
184
|
-
|
196
|
+
# Handle default value
|
197
|
+
@field_defaults[name] = options[:default]
|
185
198
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
199
|
+
# Handle type, if any
|
200
|
+
if options[:type] then
|
201
|
+
@field_types[:"#{name}"] = options[:type].to_s
|
202
|
+
end
|
190
203
|
|
191
|
-
|
192
|
-
|
193
|
-
|
204
|
+
define_method :"#{name}" do
|
205
|
+
instance_variable_get("@#{name}") or self.class.field_defaults[name]
|
206
|
+
end
|
194
207
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
208
|
+
define_method :"#{name}=" do |val|
|
209
|
+
if not self.class.field_types[:"#{name}"] or val.is_a?(eval(self.class.field_types[:"#{name}"])) then
|
210
|
+
instance_variable_set("@#{name}", val)
|
211
|
+
else
|
212
|
+
raise "Cannot set field of type #{self.class.field_types[name.to_sym]} with #{val.class} value"
|
213
|
+
end
|
200
214
|
end
|
201
215
|
end
|
202
|
-
end
|
203
216
|
|
204
|
-
|
205
|
-
|
206
|
-
|
217
|
+
def fields
|
218
|
+
@fields
|
219
|
+
end
|
207
220
|
|
208
|
-
|
209
|
-
|
210
|
-
|
221
|
+
def field_defaults
|
222
|
+
@field_defaults
|
223
|
+
end
|
211
224
|
|
212
|
-
|
213
|
-
|
214
|
-
|
225
|
+
def field_types
|
226
|
+
@field_types
|
227
|
+
end
|
215
228
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
229
|
+
# Finds the record with the given ID, or the first that matches the given conditions
|
230
|
+
def find(options = {})
|
231
|
+
if options.class == String then
|
232
|
+
if Ampere.connection.exists(options) then
|
233
|
+
new(Ampere.connection.hgetall(options), true)
|
234
|
+
else
|
235
|
+
nil
|
236
|
+
end
|
221
237
|
else
|
222
|
-
|
238
|
+
# TODO Write a handler for this case, even if it's an exception
|
239
|
+
raise "Cannot find by #{options.class} yet"
|
223
240
|
end
|
224
|
-
else
|
225
|
-
# TODO Write a handler for this case, even if it's an exception
|
226
|
-
raise "Cannot find by #{options.class} yet"
|
227
241
|
end
|
228
|
-
end
|
229
242
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
243
|
+
# Defines a has_one relationship with another model. See the README for more details.
|
244
|
+
def has_one(field_name, options = {})
|
245
|
+
referred_klass_name = (options[:class] or options['class'] or field_name)
|
246
|
+
my_klass_name = to_s.downcase
|
234
247
|
|
235
|
-
|
248
|
+
field :"#{field_name}_id"
|
236
249
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
250
|
+
define_method(field_name.to_sym) do
|
251
|
+
return if self.send("#{field_name}_id").nil?
|
252
|
+
eval(referred_klass_name.to_s.capitalize).find(self.send("#{field_name}_id"))
|
253
|
+
end
|
241
254
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
255
|
+
define_method(:"#{field_name}=") do |val|
|
256
|
+
return nil if val.nil?
|
257
|
+
# Set attr with key where referred model is stored
|
258
|
+
self.send("#{field_name}_id=", val.id)
|
259
|
+
# Also update that model's hash with a pointer back to here
|
260
|
+
val.send("#{my_klass_name}_id=", self.send("id"))
|
261
|
+
end
|
248
262
|
end
|
249
|
-
end
|
250
263
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
264
|
+
# Defines a has_many relationship with another model. See the README for more details.
|
265
|
+
def has_many(field_name, options = {})
|
266
|
+
klass_name = (options[:class] or options['class'] or field_name.to_s.gsub(/s$/, ''))
|
267
|
+
my_klass_name = to_s.downcase
|
255
268
|
|
256
|
-
|
257
|
-
|
258
|
-
|
269
|
+
define_method(:"#{field_name}") do
|
270
|
+
(Ampere.connection.smembers("#{to_s.downcase}.#{self.id}.has_many.#{field_name}")).map do |id|
|
271
|
+
eval(klass_name.to_s.capitalize).find(id)
|
272
|
+
end
|
259
273
|
end
|
260
|
-
end
|
261
274
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
275
|
+
define_method(:"#{field_name}=") do |val|
|
276
|
+
val.each do |v|
|
277
|
+
Ampere.connection.sadd("#{to_s.downcase}.#{self.id}.has_many.#{field_name}", v.id)
|
278
|
+
# Set pointer for belongs_to
|
279
|
+
Ampere.connection.hset(v.id, "#{my_klass_name}_id", self.send("id"))
|
280
|
+
end
|
267
281
|
end
|
268
282
|
end
|
269
|
-
end
|
270
283
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
284
|
+
# Defines an index. See the README for more details.
|
285
|
+
def index(field_name, options = {})
|
286
|
+
# TODO There has just got to be a better way to handle this.
|
287
|
+
@fields ||= []
|
288
|
+
@field_defaults ||= {}
|
289
|
+
@indices ||= []
|
290
|
+
@unique_indices ||= []
|
291
|
+
@field_types ||= {}
|
279
292
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
293
|
+
if field_name.class == String or field_name.class == Symbol then
|
294
|
+
# Singular index
|
295
|
+
raise "Can't index a nonexistent field!" unless @fields.include?(field_name)
|
296
|
+
elsif field_name.class == Array then
|
297
|
+
# Compound index
|
298
|
+
field_name.each{|f| raise "Can't index a nonexistent field!" unless @fields.include?(f)}
|
299
|
+
field_name.sort!
|
300
|
+
else
|
301
|
+
raise "Can't index a #{field_name.class}"
|
302
|
+
end
|
290
303
|
|
291
|
-
|
292
|
-
|
293
|
-
|
304
|
+
@indices << field_name
|
305
|
+
@unique_indices << field_name if options[:unique]
|
306
|
+
end
|
294
307
|
|
295
|
-
|
296
|
-
|
297
|
-
|
308
|
+
def indices
|
309
|
+
@indices
|
310
|
+
end
|
298
311
|
|
299
|
-
|
300
|
-
|
301
|
-
|
312
|
+
def unique_indices
|
313
|
+
@unique_indices
|
314
|
+
end
|
302
315
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
316
|
+
# Finds an array of records which match the given conditions. This method is
|
317
|
+
# much faster when all the fields given are indexed.
|
318
|
+
def where(options = {})
|
319
|
+
if options.empty? then
|
320
|
+
Ampere::Collection.new(eval(to_s), [])
|
321
|
+
else
|
322
|
+
indexed_fields = (options.keys & @indices) + compound_indices_for(options)
|
323
|
+
nonindexed_fields = (options.keys - @indices) - compound_indices_for(options).flatten
|
311
324
|
|
312
|
-
|
325
|
+
results = nil
|
313
326
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
+
unless indexed_fields.empty?
|
328
|
+
indexed_fields.map {|key|
|
329
|
+
if key.class == String or key.class == Symbol then
|
330
|
+
Ampere.connection.hget("ampere.index.#{to_s.downcase}.#{key}", options[key]).split(/:/) #.map {|id| find(id)}
|
331
|
+
else
|
332
|
+
# Compound index
|
333
|
+
Ampere.connection.hget(
|
334
|
+
"ampere.index.#{to_s.downcase}.#{key.join(':')}",
|
335
|
+
key.map{|k| options[k]}.join(':')
|
336
|
+
).split(/:/) #.map {|id| find(id)}
|
337
|
+
end
|
338
|
+
}.each {|s|
|
339
|
+
return s if s.empty?
|
327
340
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
}
|
334
|
-
end
|
335
|
-
|
336
|
-
unless nonindexed_fields.empty?
|
337
|
-
results = all if results.nil?
|
338
|
-
results = results.to_a.map{|r| r.class == String ? find(r) : r}
|
339
|
-
nonindexed_fields.each do |key|
|
340
|
-
results.select!{|r|
|
341
|
-
r.send(key) == options[key]
|
341
|
+
if results.nil? then
|
342
|
+
results = s
|
343
|
+
else
|
344
|
+
results &= s
|
345
|
+
end
|
342
346
|
}
|
343
347
|
end
|
344
|
-
|
348
|
+
|
349
|
+
unless nonindexed_fields.empty?
|
350
|
+
results = all if results.nil?
|
351
|
+
results = results.to_a.map{|r| r.class == String ? find(r) : r}
|
352
|
+
nonindexed_fields.each do |key|
|
353
|
+
results.select!{|r|
|
354
|
+
r.send(key) == options[key]
|
355
|
+
}
|
356
|
+
end
|
357
|
+
end
|
345
358
|
|
346
|
-
|
347
|
-
|
359
|
+
# TODO The eval(to_s) trick seems a little... ghetto.
|
360
|
+
Ampere::Collection.new(eval(to_s), results.reverse)
|
361
|
+
end
|
348
362
|
end
|
349
|
-
end
|
350
363
|
|
351
|
-
|
364
|
+
private
|
352
365
|
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
366
|
+
def compound_indices_for(query)
|
367
|
+
compound_indices.select{|ci|
|
368
|
+
(query.keys - ci).empty?
|
369
|
+
}
|
370
|
+
end
|
357
371
|
end
|
358
372
|
|
359
|
-
|
360
373
|
end
|
361
374
|
|
362
375
|
end
|
data/spec/models/indices_spec.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), "..", "spec_helper.rb")
|
2
2
|
|
3
3
|
describe "Model indices", :indices => true do
|
4
|
-
before :
|
4
|
+
before :each do
|
5
5
|
Redis.new.flushall
|
6
6
|
Ampere.connect
|
7
7
|
|
8
|
-
class Student
|
8
|
+
class Student
|
9
|
+
include Ampere::Model
|
10
|
+
|
9
11
|
field :first_name
|
10
12
|
field :last_name
|
11
13
|
field :student_id_num
|
@@ -48,19 +50,25 @@ describe "Model indices", :indices => true do
|
|
48
50
|
|
49
51
|
it 'should refuse to create an index on a field that does not exist' do
|
50
52
|
(->{
|
51
|
-
class Student
|
53
|
+
class Student
|
54
|
+
include Ampere::Model
|
55
|
+
|
52
56
|
field :this_field_exists
|
53
57
|
|
54
58
|
index :this_field_exists
|
55
59
|
end
|
56
60
|
}).should_not raise_error
|
57
61
|
(->{
|
58
|
-
class Student
|
62
|
+
class Student
|
63
|
+
include Ampere::Model
|
64
|
+
|
59
65
|
index :this_field_does_not_exist
|
60
66
|
end
|
61
67
|
}).should raise_error
|
62
68
|
(->{
|
63
|
-
class Student
|
69
|
+
class Student
|
70
|
+
include Ampere::Model
|
71
|
+
|
64
72
|
field :this_field_exists
|
65
73
|
|
66
74
|
index [:this_field_exists, :but_this_one_does_not]
|
@@ -68,7 +76,7 @@ describe "Model indices", :indices => true do
|
|
68
76
|
}).should raise_error
|
69
77
|
end
|
70
78
|
|
71
|
-
it 'should enforce the uniqueness of unique single-field indices'
|
79
|
+
it 'should enforce the uniqueness of unique single-field indices' do
|
72
80
|
# The student_id_num field of Student is unique. If two Students
|
73
81
|
# with the same student_id_num are stored, the second should not
|
74
82
|
# save successfully, throwing an exception instead.
|
@@ -87,7 +95,9 @@ describe "Model indices", :indices => true do
|
|
87
95
|
|
88
96
|
context 'compound indices' do
|
89
97
|
before :all do
|
90
|
-
class Professor
|
98
|
+
class Professor
|
99
|
+
include Ampere::Model
|
100
|
+
|
91
101
|
field :first_name
|
92
102
|
field :last_name
|
93
103
|
field :employee_id_number
|
data/spec/models/model_spec.rb
CHANGED
@@ -9,7 +9,9 @@ describe "Base models", :model => true do
|
|
9
9
|
Redis.new.flushall
|
10
10
|
|
11
11
|
# Define a model class here.
|
12
|
-
class Post
|
12
|
+
class Post
|
13
|
+
include Ampere::Model
|
14
|
+
|
13
15
|
field :title
|
14
16
|
field :byline
|
15
17
|
field :content
|
@@ -37,7 +39,9 @@ describe "Base models", :model => true do
|
|
37
39
|
end
|
38
40
|
|
39
41
|
it "should have default values definable" do
|
40
|
-
class Comment
|
42
|
+
class Comment
|
43
|
+
include Ampere::Model
|
44
|
+
|
41
45
|
field :subject, :default => "No subject"
|
42
46
|
field :content
|
43
47
|
end
|
@@ -54,7 +58,9 @@ describe "Base models", :model => true do
|
|
54
58
|
context 'types', :types => true do
|
55
59
|
before :all do
|
56
60
|
# Just adding a field with a type to Post
|
57
|
-
class Post
|
61
|
+
class Post
|
62
|
+
include Ampere::Model
|
63
|
+
|
58
64
|
field :pageviews, :type => Integer, :default => 0
|
59
65
|
end
|
60
66
|
end
|
data/spec/models/queries_spec.rb
CHANGED
@@ -6,7 +6,9 @@ describe 'belongs_to relationships', :belongs_to => true do
|
|
6
6
|
Ampere.connect
|
7
7
|
|
8
8
|
# These are used by the has_one/belongs_to example below
|
9
|
-
class Car
|
9
|
+
class Car
|
10
|
+
include Ampere::Model
|
11
|
+
|
10
12
|
field :make
|
11
13
|
field :model
|
12
14
|
field :year
|
@@ -15,7 +17,9 @@ describe 'belongs_to relationships', :belongs_to => true do
|
|
15
17
|
has_many :passengers
|
16
18
|
end
|
17
19
|
|
18
|
-
class Engine
|
20
|
+
class Engine
|
21
|
+
include Ampere::Model
|
22
|
+
|
19
23
|
field :displacement
|
20
24
|
field :cylinders
|
21
25
|
field :configuration
|
@@ -23,7 +27,9 @@ describe 'belongs_to relationships', :belongs_to => true do
|
|
23
27
|
belongs_to :car
|
24
28
|
end
|
25
29
|
|
26
|
-
class Passenger
|
30
|
+
class Passenger
|
31
|
+
include Ampere::Model
|
32
|
+
|
27
33
|
field :name
|
28
34
|
field :seat
|
29
35
|
|
@@ -6,7 +6,9 @@ describe 'has_many relationships', :has_many => true do
|
|
6
6
|
Ampere.connect
|
7
7
|
|
8
8
|
# These are used by the has_one/belongs_to example below
|
9
|
-
class Car
|
9
|
+
class Car
|
10
|
+
include Ampere::Model
|
11
|
+
|
10
12
|
field :make
|
11
13
|
field :model
|
12
14
|
field :year
|
@@ -14,7 +16,9 @@ describe 'has_many relationships', :has_many => true do
|
|
14
16
|
has_many :passengers
|
15
17
|
end
|
16
18
|
|
17
|
-
class Passenger
|
19
|
+
class Passenger
|
20
|
+
include Ampere::Model
|
21
|
+
|
18
22
|
field :name
|
19
23
|
field :seat
|
20
24
|
|
@@ -6,7 +6,9 @@ describe 'has_one relationships', has_one:true do
|
|
6
6
|
Ampere.connect
|
7
7
|
|
8
8
|
# These are used by the has_one/belongs_to example below
|
9
|
-
class Car
|
9
|
+
class Car
|
10
|
+
include Ampere::Model
|
11
|
+
|
10
12
|
field :make
|
11
13
|
field :model
|
12
14
|
field :year
|
@@ -14,7 +16,9 @@ describe 'has_one relationships', has_one:true do
|
|
14
16
|
has_one :engine
|
15
17
|
end
|
16
18
|
|
17
|
-
class Engine
|
19
|
+
class Engine
|
20
|
+
include Ampere::Model
|
21
|
+
|
18
22
|
field :displacement
|
19
23
|
field :cylinders
|
20
24
|
field :configuration
|
data/spec/models/updates_spec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ampere
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-04-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
16
|
-
requirement: &
|
16
|
+
requirement: &70280166250520 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70280166250520
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: shoulda
|
27
|
-
requirement: &
|
27
|
+
requirement: &70280166249600 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70280166249600
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: cucumber
|
38
|
-
requirement: &
|
38
|
+
requirement: &70280166263980 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70280166263980
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: bundler
|
49
|
-
requirement: &
|
49
|
+
requirement: &70280166262680 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.0.0
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70280166262680
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: jeweler
|
60
|
-
requirement: &
|
60
|
+
requirement: &70280166261440 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 1.6.4
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70280166261440
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: simplecov
|
71
|
-
requirement: &
|
71
|
+
requirement: &70280166260320 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70280166260320
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rspec
|
82
|
-
requirement: &
|
82
|
+
requirement: &70280166259660 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70280166259660
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rdoc
|
93
|
-
requirement: &
|
93
|
+
requirement: &70280166257860 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,7 +98,7 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70280166257860
|
102
102
|
description: An ActiveRecord/Mongoid-esque object model for the Redis key/value data
|
103
103
|
store.
|
104
104
|
email: max@villainousindustri.es
|
@@ -151,7 +151,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
151
151
|
version: '0'
|
152
152
|
segments:
|
153
153
|
- 0
|
154
|
-
hash:
|
154
|
+
hash: 719359362580818516
|
155
155
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
156
|
none: false
|
157
157
|
requirements:
|
@@ -160,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
160
|
version: '0'
|
161
161
|
requirements: []
|
162
162
|
rubyforge_project:
|
163
|
-
rubygems_version: 1.8.
|
163
|
+
rubygems_version: 1.8.17
|
164
164
|
signing_key:
|
165
165
|
specification_version: 3
|
166
166
|
summary: A pure Ruby ORM for Redis.
|