ohm 1.1.2 → 1.2.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/lib/ohm.rb +153 -134
- data/test/enumerable.rb +79 -0
- metadata +31 -11
data/lib/ohm.rb
CHANGED
@@ -140,8 +140,27 @@ module Ohm
|
|
140
140
|
redis.flushdb
|
141
141
|
end
|
142
142
|
|
143
|
-
|
144
|
-
|
143
|
+
module Collection
|
144
|
+
include Enumerable
|
145
|
+
|
146
|
+
def each
|
147
|
+
if block_given?
|
148
|
+
to_a.each { |element| yield element }
|
149
|
+
else
|
150
|
+
Enumerator.new(self, :each)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Fetch the data from Redis in one go.
|
155
|
+
def to_a
|
156
|
+
fetch(ids)
|
157
|
+
end
|
158
|
+
|
159
|
+
def empty?
|
160
|
+
size == 0
|
161
|
+
end
|
162
|
+
|
163
|
+
# Wraps the whole pipelining functionality.
|
145
164
|
def fetch(ids)
|
146
165
|
arr = db.pipelined do
|
147
166
|
ids.each { |id| db.hgetall(namespace[id]) }
|
@@ -159,24 +178,126 @@ module Ohm
|
|
159
178
|
end
|
160
179
|
end
|
161
180
|
|
162
|
-
|
163
|
-
|
164
|
-
include PipelinedFetch
|
165
|
-
include Enumerable
|
181
|
+
class List
|
182
|
+
include Collection
|
166
183
|
|
167
|
-
|
168
|
-
|
169
|
-
|
184
|
+
attr :key
|
185
|
+
attr :namespace
|
186
|
+
attr :model
|
187
|
+
|
188
|
+
def initialize(key, namespace, model)
|
189
|
+
@key = key
|
190
|
+
@namespace = namespace
|
191
|
+
@model = model
|
170
192
|
end
|
171
193
|
|
172
|
-
|
173
|
-
|
194
|
+
# Returns the total size of the list using LLEN.
|
195
|
+
def size
|
196
|
+
db.llen(key)
|
174
197
|
end
|
198
|
+
alias :count :size
|
175
199
|
|
176
|
-
|
177
|
-
|
200
|
+
# Returns the first element of the list using LINDEX.
|
201
|
+
def first
|
202
|
+
model[db.lindex(key, 0)]
|
203
|
+
end
|
204
|
+
|
205
|
+
# Returns the last element of the list using LINDEX.
|
206
|
+
def last
|
207
|
+
model[db.lindex(key, -1)]
|
208
|
+
end
|
209
|
+
|
210
|
+
# Checks if the model is part of this List.
|
211
|
+
#
|
212
|
+
# An important thing to note is that this method loads all of the
|
213
|
+
# elements of the List since there is no command in Redis that
|
214
|
+
# allows you to actually check the list contents efficiently.
|
215
|
+
#
|
216
|
+
# You may want to avoid doing this if your list has say, 10K entries.
|
217
|
+
def include?(model)
|
218
|
+
ids.include?(model.id.to_s)
|
219
|
+
end
|
220
|
+
|
221
|
+
# Replace all the existing elements of a list with a different
|
222
|
+
# collection of models. This happens atomically in a MULTI-EXEC
|
223
|
+
# block.
|
224
|
+
#
|
225
|
+
# Example:
|
226
|
+
#
|
227
|
+
# user = User.create
|
228
|
+
# p1 = Post.create
|
229
|
+
# user.posts.push(p1)
|
230
|
+
#
|
231
|
+
# p2, p3 = Post.create, Post.create
|
232
|
+
# user.posts.replace([p2, p3])
|
233
|
+
#
|
234
|
+
# user.posts.include?(p1)
|
235
|
+
# # => false
|
236
|
+
#
|
237
|
+
def replace(models)
|
238
|
+
ids = models.map { |model| model.id }
|
239
|
+
|
240
|
+
model.db.multi do
|
241
|
+
db.del(key)
|
242
|
+
ids.each { |id| db.rpush(key, id) }
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Pushes the model to the _end_ of the list using RPUSH.
|
247
|
+
def push(model)
|
248
|
+
db.rpush(key, model.id)
|
249
|
+
end
|
250
|
+
|
251
|
+
# Pushes the model to the _beginning_ of the list using LPUSH.
|
252
|
+
def unshift(model)
|
253
|
+
db.lpush(key, model.id)
|
254
|
+
end
|
255
|
+
|
256
|
+
# Delete a model from the list.
|
257
|
+
#
|
258
|
+
# Note: If your list contains the model multiple times, this method
|
259
|
+
# will delete all instances of that model in one go.
|
260
|
+
#
|
261
|
+
# Example:
|
262
|
+
#
|
263
|
+
# class Comment < Ohm::Model
|
264
|
+
# end
|
265
|
+
#
|
266
|
+
# class Post < Ohm::Model
|
267
|
+
# list :comments, Comment
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
# p = Post.create
|
271
|
+
# c = Comment.create
|
272
|
+
#
|
273
|
+
# p.comments.push(c)
|
274
|
+
# p.comments.push(c)
|
275
|
+
#
|
276
|
+
# p.comments.delete(c)
|
277
|
+
#
|
278
|
+
# p.comments.size == 0
|
279
|
+
# # => true
|
280
|
+
#
|
281
|
+
def delete(model)
|
282
|
+
# LREM key 0 <id> means remove all elements matching <id>
|
283
|
+
# @see http://redis.io/commands/lrem
|
284
|
+
db.lrem(key, 0, model.id)
|
178
285
|
end
|
179
286
|
|
287
|
+
private
|
288
|
+
def ids
|
289
|
+
db.lrange(key, 0, -1)
|
290
|
+
end
|
291
|
+
|
292
|
+
def db
|
293
|
+
model.db
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# Defines most of the methods used by `Set` and `MultiSet`.
|
298
|
+
class BasicSet
|
299
|
+
include Collection
|
300
|
+
|
180
301
|
# Allows you to sort by any field in your model.
|
181
302
|
#
|
182
303
|
# Example:
|
@@ -249,6 +370,7 @@ module Ohm
|
|
249
370
|
def size
|
250
371
|
execute { |key| db.scard(key) }
|
251
372
|
end
|
373
|
+
alias :count :size
|
252
374
|
|
253
375
|
# Syntactic sugar for `sort_by` or `sort` when you only need the
|
254
376
|
# first element.
|
@@ -305,128 +427,17 @@ module Ohm
|
|
305
427
|
end
|
306
428
|
end
|
307
429
|
|
308
|
-
class
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
# Returns the total size of the list using LLEN.
|
313
|
-
def size
|
314
|
-
db.llen(key)
|
315
|
-
end
|
316
|
-
|
317
|
-
# Returns the first element of the list using LINDEX.
|
318
|
-
def first
|
319
|
-
model[db.lindex(key, 0)]
|
320
|
-
end
|
321
|
-
|
322
|
-
# Returns the last element of the list using LINDEX.
|
323
|
-
def last
|
324
|
-
model[db.lindex(key, -1)]
|
325
|
-
end
|
326
|
-
|
327
|
-
# Checks if the model is part of this List.
|
328
|
-
#
|
329
|
-
# An important thing to note is that this method loads all of the
|
330
|
-
# elements of the List since there is no command in Redis that
|
331
|
-
# allows you to actually check the list contents efficiently.
|
332
|
-
#
|
333
|
-
# You may want to avoid doing this if your list has say, 10K entries.
|
334
|
-
def include?(model)
|
335
|
-
ids.include?(model.id.to_s)
|
336
|
-
end
|
337
|
-
|
338
|
-
# Replace all the existing elements of a list with a different
|
339
|
-
# collection of models. This happens atomically in a MULTI-EXEC
|
340
|
-
# block.
|
341
|
-
#
|
342
|
-
# Example:
|
343
|
-
#
|
344
|
-
# user = User.create
|
345
|
-
# p1 = Post.create
|
346
|
-
# user.posts.push(p1)
|
347
|
-
#
|
348
|
-
# p2, p3 = Post.create, Post.create
|
349
|
-
# user.posts.replace([p2, p3])
|
350
|
-
#
|
351
|
-
# user.posts.include?(p1)
|
352
|
-
# # => false
|
353
|
-
#
|
354
|
-
def replace(models)
|
355
|
-
ids = models.map { |model| model.id }
|
430
|
+
class Set < BasicSet
|
431
|
+
attr :key
|
432
|
+
attr :namespace
|
433
|
+
attr :model
|
356
434
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
435
|
+
def initialize(key, namespace, model)
|
436
|
+
@key = key
|
437
|
+
@namespace = namespace
|
438
|
+
@model = model
|
361
439
|
end
|
362
440
|
|
363
|
-
# Fetch the data from Redis in one go.
|
364
|
-
def to_a
|
365
|
-
fetch(ids)
|
366
|
-
end
|
367
|
-
|
368
|
-
def each
|
369
|
-
to_a.each { |element| yield element }
|
370
|
-
end
|
371
|
-
|
372
|
-
def empty?
|
373
|
-
size == 0
|
374
|
-
end
|
375
|
-
|
376
|
-
# Pushes the model to the _end_ of the list using RPUSH.
|
377
|
-
def push(model)
|
378
|
-
db.rpush(key, model.id)
|
379
|
-
end
|
380
|
-
|
381
|
-
# Pushes the model to the _beginning_ of the list using LPUSH.
|
382
|
-
def unshift(model)
|
383
|
-
db.lpush(key, model.id)
|
384
|
-
end
|
385
|
-
|
386
|
-
# Delete a model from the list.
|
387
|
-
#
|
388
|
-
# Note: If your list contains the model multiple times, this method
|
389
|
-
# will delete all instances of that model in one go.
|
390
|
-
#
|
391
|
-
# Example:
|
392
|
-
#
|
393
|
-
# class Comment < Ohm::Model
|
394
|
-
# end
|
395
|
-
#
|
396
|
-
# class Post < Ohm::Model
|
397
|
-
# list :comments, Comment
|
398
|
-
# end
|
399
|
-
#
|
400
|
-
# p = Post.create
|
401
|
-
# c = Comment.create
|
402
|
-
#
|
403
|
-
# p.comments.push(c)
|
404
|
-
# p.comments.push(c)
|
405
|
-
#
|
406
|
-
# p.comments.delete(c)
|
407
|
-
#
|
408
|
-
# p.comments.size == 0
|
409
|
-
# # => true
|
410
|
-
#
|
411
|
-
def delete(model)
|
412
|
-
# LREM key 0 <id> means remove all elements matching <id>
|
413
|
-
# @see http://redis.io/commands/lrem
|
414
|
-
db.lrem(key, 0, model.id)
|
415
|
-
end
|
416
|
-
|
417
|
-
private
|
418
|
-
def ids
|
419
|
-
db.lrange(key, 0, -1)
|
420
|
-
end
|
421
|
-
|
422
|
-
def db
|
423
|
-
model.db
|
424
|
-
end
|
425
|
-
end
|
426
|
-
|
427
|
-
class Set < Struct.new(:key, :namespace, :model)
|
428
|
-
include Collection
|
429
|
-
|
430
441
|
# Chain new fiters on an existing set.
|
431
442
|
#
|
432
443
|
# Example:
|
@@ -547,8 +558,16 @@ module Ohm
|
|
547
558
|
# User.find(:name => "John", :age => 30).kind_of?(Ohm::MultiSet)
|
548
559
|
# # => true
|
549
560
|
#
|
550
|
-
class MultiSet <
|
551
|
-
|
561
|
+
class MultiSet < BasicSet
|
562
|
+
attr :namespace
|
563
|
+
attr :model
|
564
|
+
attr :command
|
565
|
+
|
566
|
+
def initialize(namespace, model, command)
|
567
|
+
@namespace = namespace
|
568
|
+
@model = model
|
569
|
+
@command = command
|
570
|
+
end
|
552
571
|
|
553
572
|
# Chain new fiters on an existing set.
|
554
573
|
#
|
data/test/enumerable.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.expand_path("./helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
scope do
|
4
|
+
class Contact < Ohm::Model
|
5
|
+
attribute :name
|
6
|
+
end
|
7
|
+
|
8
|
+
setup do
|
9
|
+
john = Contact.create(name: "John Doe")
|
10
|
+
jane = Contact.create(name: "Jane Doe")
|
11
|
+
|
12
|
+
[john, jane]
|
13
|
+
end
|
14
|
+
|
15
|
+
test "Set#count doesn't do each" do
|
16
|
+
set = Contact.all
|
17
|
+
|
18
|
+
def set.each
|
19
|
+
raise "Failed"
|
20
|
+
end
|
21
|
+
|
22
|
+
assert_equal 2, set.count
|
23
|
+
end
|
24
|
+
|
25
|
+
test "Set#each as an Enumerator" do |john, jane|
|
26
|
+
enum = Contact.all.each
|
27
|
+
|
28
|
+
enum.each do |c|
|
29
|
+
assert c == john || c == jane
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
test "select" do |john, jane|
|
34
|
+
assert_equal 2, Contact.all.count
|
35
|
+
assert_equal [john], Contact.all.select { |c| c.id == john.id }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
scope do
|
40
|
+
class Comment < Ohm::Model
|
41
|
+
end
|
42
|
+
|
43
|
+
class Post < Ohm::Model
|
44
|
+
list :comments, :Comment
|
45
|
+
end
|
46
|
+
|
47
|
+
setup do
|
48
|
+
c1 = Comment.create
|
49
|
+
c2 = Comment.create
|
50
|
+
|
51
|
+
post = Post.create
|
52
|
+
post.comments.push(c1)
|
53
|
+
post.comments.push(c2)
|
54
|
+
|
55
|
+
[post, c1, c2]
|
56
|
+
end
|
57
|
+
|
58
|
+
test "List#select" do |post, c1, c2|
|
59
|
+
assert_equal [c1], post.comments.select { |comment| comment == c1 }
|
60
|
+
end
|
61
|
+
|
62
|
+
test "List#each as Enumerator" do |post, c1, c2|
|
63
|
+
enum = post.comments.each
|
64
|
+
|
65
|
+
enum.each do |comment|
|
66
|
+
assert comment == c1 || comment == c2
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
test "List#count doesn't do each" do |post, c1, c2|
|
71
|
+
list = post.comments
|
72
|
+
|
73
|
+
def list.each
|
74
|
+
raise "Failed"
|
75
|
+
end
|
76
|
+
|
77
|
+
assert_equal 2, list.count
|
78
|
+
end
|
79
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ohm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -15,7 +15,7 @@ date: 2012-08-29 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: redis
|
18
|
-
requirement:
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ! '>='
|
@@ -23,10 +23,15 @@ dependencies:
|
|
23
23
|
version: '0'
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
version_requirements:
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ! '>='
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '0'
|
27
32
|
- !ruby/object:Gem::Dependency
|
28
33
|
name: nest
|
29
|
-
requirement:
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
30
35
|
none: false
|
31
36
|
requirements:
|
32
37
|
- - ~>
|
@@ -34,10 +39,15 @@ dependencies:
|
|
34
39
|
version: '1.0'
|
35
40
|
type: :runtime
|
36
41
|
prerelease: false
|
37
|
-
version_requirements:
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
38
48
|
- !ruby/object:Gem::Dependency
|
39
49
|
name: scrivener
|
40
|
-
requirement:
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
41
51
|
none: false
|
42
52
|
requirements:
|
43
53
|
- - ~>
|
@@ -45,10 +55,15 @@ dependencies:
|
|
45
55
|
version: 0.0.3
|
46
56
|
type: :runtime
|
47
57
|
prerelease: false
|
48
|
-
version_requirements:
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ~>
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.0.3
|
49
64
|
- !ruby/object:Gem::Dependency
|
50
65
|
name: cutest
|
51
|
-
requirement:
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
52
67
|
none: false
|
53
68
|
requirements:
|
54
69
|
- - ~>
|
@@ -56,7 +71,12 @@ dependencies:
|
|
56
71
|
version: '1.1'
|
57
72
|
type: :development
|
58
73
|
prerelease: false
|
59
|
-
version_requirements:
|
74
|
+
version_requirements: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ~>
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '1.1'
|
60
80
|
description: Ohm is a library that allows to store an object in Redis, a persistent
|
61
81
|
key-value database. It includes an extensible list of validations and has very good
|
62
82
|
performance.
|
@@ -81,6 +101,7 @@ files:
|
|
81
101
|
- test/connection.rb
|
82
102
|
- test/core.rb
|
83
103
|
- test/counters.rb
|
104
|
+
- test/enumerable.rb
|
84
105
|
- test/extensibility.rb
|
85
106
|
- test/filtering.rb
|
86
107
|
- test/hash_key.rb
|
@@ -115,9 +136,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
136
|
version: '0'
|
116
137
|
requirements: []
|
117
138
|
rubyforge_project: ohm
|
118
|
-
rubygems_version: 1.8.
|
139
|
+
rubygems_version: 1.8.23
|
119
140
|
signing_key:
|
120
141
|
specification_version: 3
|
121
142
|
summary: Object-hash mapping library for Redis.
|
122
143
|
test_files: []
|
123
|
-
has_rdoc:
|