ampere 0.1.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|