ohm-zset 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gems ADDED
@@ -0,0 +1,15 @@
1
+ # .gems generated gem export file. Note that any env variable settings will be missing. Append these after using a ';' field separator
2
+
3
+ file-tail -v1.0.10
4
+ minitest -v3.2.0
5
+ nest -v1.1.1
6
+ ohm -v1.0.2
7
+ redis -v3.0.1
8
+ redis -v2.2.2
9
+ ruby2ruby -v1.3.1
10
+ ruby_parser -v2.3.1
11
+ scrivener -v0.0.3
12
+ sexp_processor -v3.2.0
13
+ sourcify -v0.5.0
14
+ tins -v0.4.3
15
+ uuidtools -v2.1.3
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ ## MAC OS
2
+ .DS_Store
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create use 1.9.3@ohm-zset
data/CHANGELOG ADDED
@@ -0,0 +1,24 @@
1
+ v 0.2
2
+
3
+ - refactored code
4
+
5
+ v 0.1.4
6
+
7
+ - included option to intersect and union multiple sets with specified name
8
+
9
+ v 0.1.3
10
+
11
+ - included save_set, and load_set, and cleaned code
12
+
13
+ v 0.1.2
14
+
15
+ - included duplicate and ZSet.generate_uuid
16
+
17
+ v 0.1.1
18
+
19
+ - included UUID generation for keys of new ZSets for union and intersection
20
+
21
+ v 0.1.0
22
+
23
+ - stable
24
+ - Ohm basic support for Redis sorted sets
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Joshua Arvin Lat
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,172 @@
1
+ # ohm-zset
2
+
3
+ Ohm Sorted Set (ZSET) support for Redis.
4
+
5
+ ## Basic Usage
6
+
7
+ ```ruby
8
+ class Big < Ohm::Model
9
+ set :smalls, :Small
10
+ zset :zsmalls, :Small, :size
11
+ end
12
+
13
+ class Small < Ohm::Model
14
+ attribute :name
15
+ attribute :size
16
+ end
17
+
18
+ b = Big.create
19
+ s1 = Small.create(name: 'S1', size: 5)
20
+ s2 = Small.create(name: 'S2', size: 4)
21
+ s3 = Small.create(name: 'S3', size: 3)
22
+ s4 = Small.create(name: 'S4', size: 2)
23
+ s5 = Small.create(name: 'S5', size: 1)
24
+
25
+ b.zsmalls.add_list(s1, s2, s3, s4, s5)
26
+
27
+ b.zsmalls.size
28
+ # => 5
29
+
30
+ b.zsmalls.to_a.map(&:name)
31
+ # => ['S5', 'S4', 'S3', 'S2', 'S1']
32
+
33
+ b.zsmalls.to_a.map(&:size)
34
+ # => ['1', '2', '3', '4', '5']
35
+ ```
36
+
37
+ ## Interacting with the elements of the set
38
+ **Ohm-ZSET** includes *get*, *rank*, *revrank*, *score*, *range*, *revrange*, *rangebyscore*, *revrangebyscore*
39
+
40
+ ```ruby
41
+
42
+ b.zsmalls.get(0).name
43
+ # => 'S5'
44
+
45
+ b.zsmalls.range(0, 3).to_a.map(&:name)
46
+ # => ['S5', 'S4', 'S3', 'S2']
47
+
48
+ b.zsmalls.revrange(0, 3).each do |small|
49
+ puts "#{small.name} - #{small.size}"
50
+ end
51
+ # => S1 - 5
52
+ # => S2 - 4
53
+ # => S3 - 3
54
+ # => S4 - 2
55
+
56
+ s6 = Small.create(name:'S6', size:3.5)
57
+ b.zsmalls.add(s6)
58
+ b.zsmalls.to_a.map(&:name)
59
+ # => ['S5', 'S4', 'S3', 'S6', 'S2', 'S1']
60
+ ```
61
+
62
+ You can update the score of an element by using *update*. There is also a *count* function that returns the number of elements with scores inside a specified range.
63
+
64
+ ## Deleting Elements
65
+ **Ohm-ZSET** includes *delete* for deleting a single element, *clear* for deleting all elements, and *remrangebyrank* and *remrangebyscore* for deleting selected elements.
66
+
67
+ ```ruby
68
+ b.zsmalls.delete(s6)
69
+ b.zsmalls.to_a.map(&:name)
70
+ # => ['S5', 'S4', 'S3', 'S2', 'S1']
71
+
72
+ b.zsmalls.include? s6
73
+ # => false
74
+
75
+ b.zsmalls.clear
76
+ b.zsmalls.to_a.map(&:name)
77
+ # => []
78
+ ```
79
+
80
+ It also has *destroy!* to delete the key of the sorted set.
81
+
82
+ ## Set Intersection and Union
83
+ Set intersection between sorted sets and sets are allowed. You can use *intersect*, *intersect_multiple*, *union*, and *union_multiple* between sets and sorted sets.
84
+
85
+ ```ruby
86
+ b.smalls.add(s1)
87
+ b.smalls.add(s2)
88
+ b.smalls.add(s4)
89
+
90
+ # Intersect ['S5', 'S4', 'S3', 'S2', 'S1'] with ['S4', 'S2', 'S1']
91
+ b.zsmalls.intersect(b.smalls).to_a.map(&:name)
92
+ # => ['S4', 'S2', 'S1']
93
+ ```
94
+
95
+ The sorted set allows union and intersection of multiple sets and sorted sets with weights.
96
+ Result of intersection and union is another ZSET.
97
+
98
+ It also allows intersection and union to a new set with the specified name.
99
+
100
+ ```ruby
101
+ zunion = Ohm::ZSet.union_multiple('zunion', [zlittles, slittles, zlittles2, zlittles3])
102
+
103
+ zunion.key
104
+ # => 'zunion'
105
+ ```
106
+
107
+ ## Scoring Functions
108
+ **Ohm-ZSET** also supports custom scoring functions. The default scoring function is ZScore::Integer.
109
+ There are also available built-in scoring functions in the module.
110
+
111
+ ```ruby
112
+ class Bigger < Ohm::Model
113
+ include Ohm::ZScores
114
+
115
+ zset :zlittles, :Little, :score
116
+
117
+ # Custom scoring function
118
+ zset :zsmalls, :Small, :value, lambda{ |x| Integer(x) + 1 }
119
+
120
+ # Built-in scoring functions
121
+ zset :zlittles, :Little, :score, ZScore::Float
122
+ zset :zbools, :Bool, :is_valid, ZScore::Boolean
123
+ zset :zdts, :DT, :last_login, ZScore::DateTime
124
+
125
+ # Built-in string sorting functions
126
+ zset :zbools2, :Bool, :name, ZScore::String
127
+ zset :zbools3, :Bool, :name, ZScore::StringInsensitive
128
+ zset :zbools4, :Bool, :name, ZScore::StringInsensitiveHigh
129
+ end
130
+
131
+ class Bool < Ohm::Model
132
+ attribute :name
133
+ attribute :is_valid
134
+ end
135
+
136
+ class DT < Ohm::Model
137
+ attribute :name
138
+ attribute :last_login
139
+ end
140
+
141
+ class Small < Ohm::Model
142
+ attribute :name
143
+ attribute :value
144
+ end
145
+
146
+ class Little < Ohm::Model
147
+ attribute :name
148
+ attribute :score
149
+ end
150
+
151
+ ```
152
+
153
+ Redis allows only numerical scores so DateTime and strings objects are first converted to numbers and then stored as scores.
154
+
155
+ **Note**: The string scoring algorithm is limited only to the first 9 characters because of the floating point accuracy limit.
156
+ You can use the *starts_with* function when dealing with string sorted sets. It returns all the elements of the set with a score field value that starts with the specified string.
157
+
158
+ ## Saving and Loading ZSet instances by name / key
159
+
160
+ ```ruby
161
+
162
+ sorted_set = b.zlittles
163
+ sorted_set.save_set
164
+
165
+ sorted_set_2 = Ohm::ZSet.load_set(sorted_set.key)
166
+ sorted_set_2.add(Little.create(name: 'X1',score: 29))
167
+
168
+ # sorted_set and sorted_set_2 are pointing to same ZSet instance
169
+ ```
170
+
171
+ ## Copyright
172
+ Copyright (c) 2012 [Joshua Arvin Lat](http://www.joshualat.com). See LICENSE for more details.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/lib/ohm-zset.rb ADDED
@@ -0,0 +1,406 @@
1
+ require 'ohm'
2
+ require 'time'
3
+ require 'uuidtools'
4
+ require 'sourcify'
5
+
6
+ # http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
7
+ class Object
8
+ def meta_def(name, &blk)
9
+ (class << self; self; end).instance_eval { define_method(name, &blk) }
10
+ end
11
+ end
12
+
13
+ module Ohm
14
+ class Model
15
+ def self.zset(name, model, *score_field)
16
+
17
+ define_method name do
18
+ model = Utils.const(self.class, model)
19
+ Ohm::ZSet.new(key[name], model.key, model, score_field)
20
+ end
21
+
22
+ meta_def name do
23
+ model = Utils.const(self, model)
24
+ Ohm::ZSet.new(key[name], model.key, model, score_field)
25
+ end
26
+
27
+ end
28
+ end
29
+
30
+ module Utils
31
+ class << self
32
+ def proc_to_string(function)
33
+ function.to_source
34
+ end
35
+
36
+ def string_to_proc(function)
37
+ eval function
38
+ end
39
+
40
+ def score_field_to_string(score_field)
41
+ string_list = []
42
+
43
+ lambda_function = score_field.each do |field|
44
+ break field if field.is_a? Proc
45
+
46
+ string_list.push(field.to_s)
47
+
48
+ break lambda{ |x| x.to_i } if field == score_field.last
49
+ end
50
+
51
+ string_list.push Ohm::Utils.proc_to_string(lambda_function)
52
+ string_list.join(":")
53
+ end
54
+
55
+ def string_to_score_field(score_field)
56
+ string_list = score_field.split(":")
57
+ return_list = []
58
+
59
+ string_list.each do |field|
60
+ if field.include? 'proc'
61
+ return_list.push Ohm::Utils.string_to_proc field
62
+ else
63
+ return_list.push field.to_sym
64
+ end
65
+ end
66
+
67
+ return_list
68
+ end
69
+ end
70
+ end
71
+
72
+ module ZScores
73
+ module ZScore
74
+ Integer = lambda{ |x| Integer(x) }
75
+ Float = lambda{ |x| Float(x) }
76
+ Boolean = lambda{ |x| Ohm::ZScores.boolean(x) }
77
+ DateTime = lambda{ |x| Ohm::ZScores.datetime(x) }
78
+ String = lambda{ |x| Ohm::ZScores.string(x) }
79
+ StringInsensitive = lambda{ |x| Ohm::ZScores.string_insensitive(x) }
80
+ StringInsensitiveHigh = lambda{ |x| Ohm::ZScores.string_insensitive_high(x) }
81
+ end
82
+
83
+ class << self
84
+ def boolean(val)
85
+ case val
86
+ when "true", "1", true
87
+ 1
88
+ when "false", "0", false, nil
89
+ 0
90
+ else
91
+ 1
92
+ end
93
+ end
94
+
95
+ def datetime(val)
96
+ ::DateTime.parse(val.to_s).to_time.to_i
97
+ end
98
+
99
+ # scoring accurate until 9th character
100
+ def string(val)
101
+ total_score = 0
102
+
103
+ val.each_char.with_index do |c, i|
104
+ total_score += (c.ord-31) * ((126-32) ** (10 - i))
105
+ break if i == 9
106
+ end
107
+
108
+ total_score.to_f
109
+ end
110
+
111
+ # scoring accurate until 9th character
112
+ def string_insensitive(val)
113
+ total_score = 0
114
+
115
+ val.each_char.with_index do |c, i|
116
+ char_ord = c.ord-31
117
+ if ('a'..'z').include? c
118
+ char_ord -= 32
119
+ end
120
+ total_score += (char_ord) * ((126-32) ** (10 - i))
121
+ break if i == 9
122
+ end
123
+
124
+ total_score.to_f
125
+ end
126
+
127
+ # scoring accurate until 9th character
128
+ def string_insensitive_high(val)
129
+ total_score = 0
130
+
131
+ val.each_char.with_index do |c, i|
132
+ char_ord = c.ord-31
133
+ if ('a'..'z').include? c
134
+ char_ord -= 31.5
135
+ end
136
+ total_score += (char_ord) * ((126-32) ** (10 - i))
137
+ break if i == 9
138
+ end
139
+
140
+ total_score.to_f
141
+ end
142
+ end
143
+ end
144
+
145
+ class ZSet < Struct.new(:key, :namespace, :model, :score_field)
146
+ include PipelinedFetch
147
+ include Enumerable
148
+
149
+ class << self
150
+ def intersect_multiple(new_key, sets, weights = [])
151
+ base_set = sets[0]
152
+ weights = [1.0] * sets.length if weights = []
153
+
154
+ new_set = Ohm::ZSet.new(new_key, base_set.model.key, base_set.model, base_set.score_field)
155
+ sets = sets.map(&:key)
156
+
157
+ Ohm.redis.zinterstore(new_key, sets, :weights => weights)
158
+ new_set
159
+ end
160
+
161
+ def load_set(name)
162
+ new_model, new_score_field = Ohm.redis.hmget("ZSet:" + name, "model", "score_field")
163
+ return nil if new_model == nil && new_score_field == nil
164
+
165
+ new_model = Ohm::Utils.const(self.class, new_model.to_sym)
166
+ new_score_field = Ohm::Utils.string_to_score_field new_score_field
167
+ return_instance = Ohm::ZSet.new(name, new_model.key, new_model, new_score_field)
168
+ end
169
+
170
+ def union_multiple(new_key, sets, weights = [])
171
+ base_set = sets[0]
172
+ weights = [1.0] * sets.length if weights = []
173
+
174
+ new_set = Ohm::ZSet.new(new_key, base_set.model.key, base_set.model, base_set.score_field)
175
+ sets = sets.map(&:key)
176
+
177
+ Ohm.redis.zunionstore(new_key, sets, :weights => weights)
178
+
179
+ new_set
180
+ end
181
+
182
+ def generate_uuid
183
+ "ZSet:" + UUIDTools::UUID.random_create.to_s
184
+ end
185
+
186
+ def random_instance(model, score_field)
187
+ self.new_instance(Ohm::ZSet.generate_uuid, model, score_field)
188
+ end
189
+
190
+ def new_instance(name, model, score_field)
191
+ self.new(name, model.key, model, score_field)
192
+ end
193
+ end
194
+
195
+ def size
196
+ db.zcard(key)
197
+ end
198
+
199
+ def count(a = "-inf", b = "+inf")
200
+ return size if a == "-inf" && b == "+inf"
201
+
202
+ db.zcount(key, a, b)
203
+ end
204
+
205
+ def ids(a = 0, b = -1)
206
+ execute { |key| db.zrange(key, a, b) }
207
+ end
208
+
209
+ def range(a = 0, b = -1)
210
+ fetch(ids(a, b))
211
+ end
212
+
213
+ def revrange(a = 0, b = -1)
214
+ fetch(execute { |key| db.zrevrange(key, a, b) })
215
+ end
216
+
217
+ # Fetch data from Redis
218
+ def to_a
219
+ fetch(ids)
220
+ end
221
+
222
+ def include?(model)
223
+ !rank(model).nil?
224
+ end
225
+
226
+ def get(i)
227
+ range(i, i)[0] rescue nil
228
+ end
229
+
230
+ def each
231
+ to_a.each { |element| yield element }
232
+ end
233
+
234
+ def empty?
235
+ size == 0
236
+ end
237
+
238
+ def add(model)
239
+ score_value = model
240
+
241
+ lambda_function = score_field.each do |field|
242
+ break field if field.is_a? Proc
243
+
244
+ score_value = model.send(field)
245
+
246
+ break lambda{ |x| x.to_i } if field == score_field.last
247
+ end
248
+
249
+ db.zadd(key, lambda_function.call(score_value), model.id)
250
+ end
251
+
252
+ def add_list(*models)
253
+ models.each do |model|
254
+ add(model)
255
+ end
256
+ end
257
+
258
+ def update(model)
259
+ add (model)
260
+ end
261
+
262
+ def delete(model)
263
+ db.zrem(key, model.id)
264
+
265
+ model
266
+ end
267
+
268
+ def remrangebyrank(a, b)
269
+ db.zremrangebyrank(key, a, b)
270
+ end
271
+
272
+ def remrangebyscore(a, b)
273
+ db.zremrangebyscore(key, a, b)
274
+ end
275
+
276
+ def intersect(set, w1=1.0, w2=1.0)
277
+ new_key = generate_uuid
278
+ new_set = Ohm::ZSet.new(new_key, model.key, model, score_field)
279
+
280
+ db.zinterstore(new_set.key, [key, set.key], :weights => [w1, w2])
281
+ new_set
282
+ end
283
+
284
+ def intersect_multiple(sets, weights = [])
285
+ sets = sets.map(&:key)
286
+ sets.push(key)
287
+ weights = [1.0] * sets.length if weights = []
288
+
289
+ new_key = generate_uuid
290
+ new_set = Ohm::ZSet.new(new_key, model.key, model, score_field)
291
+
292
+ db.zinterstore(new_set.key, sets, :weights => weights)
293
+
294
+ new_set
295
+ end
296
+
297
+ def intersect_multiple!(sets, weights = [])
298
+ weights = [1.0] * sets.length if weights = []
299
+ db.zinterstore(key, sets.map(&:key), :weights => weights)
300
+ self
301
+ end
302
+
303
+ def union(set, w1=1.0, w2=1.0)
304
+ new_key = generate_uuid
305
+ new_set = Ohm::ZSet.new(new_key, model.key, model, score_field)
306
+
307
+ db.zunionstore(new_set.key, [key, set.key], :weights => [w1, w2])
308
+
309
+ new_set
310
+ end
311
+
312
+ def union_multiple(sets, weights = [])
313
+ sets = sets.map(&:key)
314
+ sets.push(key)
315
+
316
+ weights = [1.0] * sets.length if weights = []
317
+ new_key = generate_uuid
318
+ new_set = Ohm::ZSet.new(new_key, model.key, model, score_field)
319
+
320
+ db.zunionstore(new_set.key, sets, :weights => weights)
321
+
322
+ new_set
323
+ end
324
+
325
+ def rank(model)
326
+ db.zrank(key, model.id)
327
+ end
328
+
329
+ def revrank(model)
330
+ db.zrevrank(key, model.id)
331
+ end
332
+
333
+ def score(model)
334
+ db.zscore(key, model.id).to_i
335
+ end
336
+
337
+ def rangebyscore(a = "-inf", b = "+inf", limit = {})
338
+ limit[:offset] ||= 0
339
+ limit[:count] ||= -1
340
+
341
+ fetch(execute { |key| db.zrangebyscore(key, a, b, :limit => [limit[:offset], limit[:count]]) })
342
+ end
343
+
344
+ def revrangebyscore(a = "+inf", b = "-inf", limit = {})
345
+ limit[:offset] ||= 0
346
+ limit[:count] ||= -1
347
+
348
+ fetch(execute { |key| db.zrevrangebyscore(key, a, b, :limit => [limit[:offset], limit[:count]]) })
349
+ end
350
+
351
+ def starts_with(query, limit = {})
352
+ start_query = ZScores.string(query)
353
+ end_query = "(" + ZScores.string(query.succ).to_s
354
+
355
+ rangebyscore(start_query, end_query, limit)
356
+ end
357
+
358
+ def first
359
+ range(0, 1)[0] rescue nil
360
+ end
361
+
362
+ def last
363
+ revrange(0, 1)[0] rescue nil
364
+ end
365
+
366
+ def destroy!
367
+ db.del(key)
368
+ end
369
+
370
+ def clear
371
+ remrangebyrank(0, -1)
372
+ end
373
+
374
+ def generate_uuid
375
+ ZSet.generate_uuid
376
+ end
377
+
378
+ def save_set
379
+ db.hmset("ZSet:" + key, *get_hmset_attrs)
380
+ end
381
+
382
+ def duplicate
383
+ intersect(self, 1.0, 0.0)
384
+ end
385
+
386
+ def get_hmset_attrs
387
+ return_list = []
388
+ return_list << "model" << model.to_s
389
+ return_list << "score_field" << Utils.score_field_to_string(score_field)
390
+ return_list
391
+ end
392
+
393
+ def expire(seconds)
394
+ db.expire(self.key, seconds)
395
+ end
396
+
397
+ private
398
+ def db
399
+ model.db
400
+ end
401
+
402
+ def execute
403
+ yield key
404
+ end
405
+ end
406
+ end
@@ -0,0 +1,16 @@
1
+ module Kernel
2
+ def suppress_warnings
3
+ original_verbosity = $VERBOSE
4
+ $VERBOSE = nil
5
+ result = yield
6
+ $VERBOSE = original_verbosity
7
+ return result
8
+ end
9
+
10
+ def require_suppress(library)
11
+ suppress_warnings{
12
+ require library
13
+ }
14
+ end
15
+ end
16
+
data/test/helper.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "minitest/autorun"
2
+ require_relative "../lib/ohm-zset"
3
+
4
+
@@ -0,0 +1,663 @@
1
+ require_relative "../helper"
2
+
3
+ class Big < Ohm::Model
4
+ include Ohm::ZScores
5
+
6
+ collection :smalls, :Small
7
+ zset :zlittles, :Little, :score, ZScore::Float
8
+ zset :zsmalls, :Small, :value
9
+ zset :zlittles2, :Little, :score
10
+ zset :zlittles3, :Little, :score
11
+ zset :zbools, :Bool, :is_valid, ZScore::Boolean
12
+ set :slittles, :Little
13
+ zset :zdts, :DT, :last_login, ZScore::DateTime
14
+ zset :zbools2, :Bool, :name, ZScore::String
15
+ zset :zbools3, :Bool, :name, ZScore::StringInsensitive
16
+ zset :zbools4, :Bool, :name, ZScore::StringInsensitiveHigh
17
+ end
18
+
19
+ class Bool < Ohm::Model
20
+ attribute :name
21
+ attribute :is_valid
22
+ end
23
+
24
+ class DT < Ohm::Model
25
+ attribute :name
26
+ #attribute :date_updated
27
+ attribute :last_login
28
+ end
29
+
30
+ class Small < Ohm::Model
31
+ attribute :name
32
+ attribute :value
33
+ end
34
+
35
+ class Little < Ohm::Model
36
+ attribute :name
37
+ attribute :score
38
+ end
39
+
40
+ def add_to_zset(model, zset_name, items, item_class)
41
+ z = model.send(zset_name)
42
+
43
+ items.each do |i|
44
+ z.send(:add, item_class.create(i))
45
+ end
46
+ end
47
+
48
+ def setup_big_1
49
+ b = Big.create
50
+
51
+ l1 = Little.create(name: 'L1', score: 1)
52
+ l2 = Little.create(name: 'L2', score: 2)
53
+ l3 = Little.create(name: 'L3', score: 3)
54
+ l4 = Little.create(name: 'L4', score: 4)
55
+
56
+ Big.zlittles.clear
57
+ Big.zlittles.add(l1)
58
+ Big.zlittles.add(l2)
59
+ Big.zlittles.add(l3)
60
+ Big.zlittles.add(l4)
61
+
62
+ b.slittles.add(l1)
63
+ b.slittles.add(l2)
64
+ b.slittles.add(Little.create(name: 'E3', score: 24))
65
+ b.slittles.add(l4)
66
+
67
+ Big.zlittles2.clear
68
+ Big.zlittles2.add(l2)
69
+ Big.zlittles2.add(l3)
70
+ Big.zlittles2.add(l4)
71
+
72
+ Big.zlittles3.clear
73
+ Big.zlittles3.add(l1)
74
+ Big.zlittles3.add(l4)
75
+ Big.zlittles3.add(Little.create(name: 'E1', score: 21))
76
+ Big.zlittles3.add(Little.create(name: 'E2', score: 22))
77
+
78
+ Big.zsmalls.clear
79
+ Big.zsmalls.add(Small.create(name: 'S1', value: 8))
80
+ Big.zsmalls.add(Small.create(name: 'S2', value: 7))
81
+ Big.zsmalls.add(Small.create(name: 'S3', value: 6))
82
+ Big.zsmalls.add(Small.create(name: 'S4', value: 5))
83
+
84
+ b
85
+ end
86
+
87
+ def setup_1
88
+ b = Big.create
89
+
90
+ l1 = Little.create(name: 'L1', score: 1)
91
+ l2 = Little.create(name: 'L2', score: 2)
92
+ l3 = Little.create(name: 'L3', score: 3)
93
+ l4 = Little.create(name: 'L4', score: 4)
94
+
95
+ b.slittles.add(l1)
96
+ b.slittles.add(l2)
97
+ b.slittles.add(Little.create(name: 'E3',score: 24))
98
+ b.slittles.add(l4)
99
+
100
+ b.zlittles.add(l1)
101
+ b.zlittles.add(l2)
102
+ b.zlittles.add(l3)
103
+ b.zlittles.add(l4)
104
+
105
+ b.zlittles2.add(l2)
106
+ b.zlittles2.add(l3)
107
+ b.zlittles2.add(l4)
108
+
109
+ b.zlittles3.add(l1)
110
+ b.zlittles3.add(l4)
111
+ b.zlittles3.add(Little.create(name: 'E1', score: 21))
112
+ b.zlittles3.add(Little.create(name: 'E2', score: 22))
113
+
114
+ b.zsmalls.add(Small.create(name: 'S1', value: 8))
115
+ b.zsmalls.add(Small.create(name: 'S2', value: 7))
116
+ b.zsmalls.add(Small.create(name: 'S3', value: 6))
117
+ b.zsmalls.add(Small.create(name: 'S4', value: 5))
118
+
119
+
120
+ b.zlittles.add(l1)
121
+ b.zlittles.add(l2)
122
+ b.zlittles.add(l3)
123
+ b.zlittles.add(l4)
124
+
125
+ b
126
+ end
127
+
128
+ def setup_2
129
+ b = Big.create
130
+
131
+ l1 = Little.create(name: 'L1', score: 1)
132
+ l2 = Little.create(name: 'L2', score: 2)
133
+ l3 = Little.create(name: 'L3', score: 3)
134
+ l4 = Little.create(name: 'L4', score: 4)
135
+
136
+ b.zlittles.add(l1)
137
+ b.zlittles.add(l2)
138
+ b.zlittles.add(l3)
139
+ b.zlittles.add(l4)
140
+
141
+ [b, l1, l2, l3, l4]
142
+ end
143
+
144
+ def setup_3
145
+ b = Big.create
146
+
147
+ b1 = Bool.create(name: 'B1', is_valid: "false")
148
+ b2 = Bool.create(name: 'B2', is_valid: "true")
149
+ b3 = Bool.create(name: 'B3', is_valid: "false")
150
+ b4 = Bool.create(name: 'B4', is_valid: "true")
151
+
152
+ b.zbools.add(b1)
153
+ b.zbools.add(b2)
154
+ b.zbools.add(b3)
155
+ b.zbools.add(b4)
156
+
157
+ b
158
+ end
159
+
160
+ def setup_4
161
+ b = Big.create
162
+
163
+ d1 = DT.create(name: 'D1', last_login: "2012-07-29 06:24:20 +0800")
164
+ d2 = DT.create(name: 'D2', last_login: "2012-07-29 05:24:20 +0800")
165
+ d3 = DT.create(name: 'D3', last_login: "2012-07-29 04:24:20 +0800")
166
+ d4 = DT.create(name: 'D4', last_login: "2012-08-29")
167
+ b.zdts.add_list(d1, d2, d3, d4)
168
+ b
169
+ end
170
+
171
+ def setup_5
172
+ b = Big.create
173
+
174
+ items = [
175
+ {name: 'Apple', is_valid: 'false'},
176
+ {name: 'Coconut', is_valid: 'true'},
177
+ {name: 'Dragonfruit', is_valid: 'false'},
178
+ {name: 'Banana', is_valid: 'true'},
179
+ {name: 'apples', is_valid: 'true'},
180
+ {name: 'coconuts', is_valid: 'true'},
181
+ {name: 'durians', is_valid: 'false'},
182
+ {name: 'bananas', is_valid: 'true'},
183
+ {name: 'apple', is_valid: 'true'},
184
+ {name: 'coconut', is_valid: 'true'},
185
+ {name: 'banana', is_valid: 'false'},
186
+ {name: 'durian', is_valid: 'true'},
187
+ ]
188
+
189
+ add_to_zset(b, 'zbools2', items, Bool)
190
+
191
+ b
192
+ end
193
+
194
+ def setup_6
195
+ b = Big.create
196
+
197
+ items = [
198
+ {name: 'apple', is_valid: 'false'},
199
+ {name: 'Coconut', is_valid: 'true'},
200
+ {name: 'duria', is_valid: 'false'},
201
+ {name: 'Banana', is_valid: 'true'},
202
+ {name: 'Apples', is_valid: 'true'},
203
+ {name: 'coconuts', is_valid: 'true'},
204
+ {name: 'durians', is_valid: 'false'},
205
+ {name: 'bananas', is_valid: 'true'},
206
+ {name: 'Apple', is_valid: 'true'},
207
+ {name: 'coconut', is_valid: 'true'},
208
+ {name: 'banana', is_valid: 'false'},
209
+ {name: 'Durian', is_valid: 'true'},
210
+ ]
211
+
212
+ add_to_zset(b, 'zbools3', items, Bool)
213
+
214
+ b
215
+ end
216
+
217
+ def setup_7
218
+ b = Big.create
219
+
220
+ items = [
221
+ {name: 'apple', is_valid: 'false'},
222
+ {name: 'Coconut', is_valid: 'true'},
223
+ {name: 'duria', is_valid: 'false'},
224
+ {name: 'Banana', is_valid: 'true'},
225
+ {name: 'Apples', is_valid: 'true'},
226
+ {name: 'coconuts', is_valid: 'true'},
227
+ {name: 'durians', is_valid: 'false'},
228
+ {name: 'bananas', is_valid: 'true'},
229
+ {name: 'Apple', is_valid: 'true'},
230
+ {name: 'coconut', is_valid: 'true'},
231
+ {name: 'banana', is_valid: 'false'},
232
+ {name: 'Durian', is_valid: 'true'},
233
+ ]
234
+
235
+ add_to_zset(b, 'zbools4', items, Bool)
236
+
237
+ b
238
+ end
239
+
240
+ # Tests for the class methods
241
+ # TODO: figure out how to DRY up the class and instance method tests. Probably move the method body to a common method and test that common method instead
242
+ describe Ohm do
243
+ it "can add objects and get the size for the class" do
244
+ setup_big_1
245
+
246
+ assert_equal 4, Big.zlittles.size
247
+ end
248
+ end
249
+
250
+ # Tests for the instance methods
251
+ describe Ohm do
252
+ it "can add objects and get the size" do
253
+ b = setup_1
254
+
255
+ assert_equal 4, b.zlittles.size
256
+ end
257
+
258
+ it "can add objects with scores and automatically sorts them by score" do
259
+ b = setup_1
260
+
261
+ assert_equal ["L1", "L2", "L3", "L4"], b.zlittles.to_a.map(&:name)
262
+ end
263
+
264
+ it "can return a range of sorted elements" do
265
+ b = setup_1
266
+
267
+ assert_equal ["L2", "L3"], b.zlittles.range(1, 2).map(&:name)
268
+ assert_equal ["L1", "L2", "L3"], b.zlittles.range(0, 2).map(&:name)
269
+ end
270
+
271
+ it "can return a range of sorted elements in reverse" do
272
+ b = setup_1
273
+
274
+ assert_equal ["L3", "L2"], b.zlittles.revrange(1, 2).map(&:name)
275
+ assert_equal ["L4", "L3", "L2"], b.zlittles.revrange(0, 2).map(&:name)
276
+ end
277
+
278
+ it "can iterate over the elements of a specified range of the set" do
279
+ b = setup_1
280
+
281
+ expected_items = ["L2", "L3", "L4"]
282
+
283
+ b.zlittles.range(1, 3).each_with_index do |e, i|
284
+ assert_equal expected_items[i], e.name
285
+ end
286
+ end
287
+
288
+ it "can iterate over the elements of a specified range of the reverse sorted set" do
289
+ b = setup_1
290
+ expected_items = ["L3", "L2", "L1"]
291
+
292
+ b.zlittles.revrange(1, 3).each_with_index do |e, i|
293
+ assert_equal expected_items[i], e.name
294
+ end
295
+ end
296
+
297
+ it "can get an element with a specified index" do
298
+ b = setup_1
299
+
300
+ assert_equal "L3", b.zlittles.get(2).name
301
+ assert_nil b.zlittles.get(5)
302
+ end
303
+
304
+ it "can delete an element" do
305
+ b = setup_1
306
+
307
+ x = b.zlittles.get(2)
308
+ deleted_element = b.zlittles.delete(x)
309
+
310
+ assert_equal x, deleted_element
311
+ assert_equal 3, b.zlittles.size
312
+ end
313
+
314
+ it "knows if it includes a specified element" do
315
+ b, l1, l2, l3, l4 = setup_2
316
+
317
+ assert b.zlittles.include?(l1)
318
+
319
+ b.zlittles.delete(l2)
320
+
321
+ refute b.zlittles.include?(l2)
322
+ assert b.zlittles.include?(l3)
323
+ assert b.zlittles.include?(l4)
324
+ assert b.zlittles.include?(l1)
325
+
326
+ b.zlittles.add(l2)
327
+
328
+ assert b.zlittles.include?(l2)
329
+ end
330
+
331
+ it "can delete a range of elements by rank" do
332
+ b = setup_1
333
+ assert_equal ["L1", "L2", "L3", "L4"], b.zlittles.to_a.map(&:name)
334
+
335
+ b.zlittles.remrangebyrank(0, 1)
336
+ assert_equal ["L3", "L4"], b.zlittles.to_a.map(&:name)
337
+
338
+ b.zlittles.remrangebyrank(0, 0)
339
+ assert_equal ["L4"], b.zlittles.to_a.map(&:name)
340
+ end
341
+
342
+ it "can delete a range of elements by score" do
343
+ b = setup_1
344
+ assert_equal ["L1", "L2", "L3", "L4"], b.zlittles.to_a.map(&:name)
345
+
346
+ b.zlittles.remrangebyscore(2, 3)
347
+ assert_equal ["L1", "L4"], b.zlittles.to_a.map(&:name)
348
+ end
349
+
350
+ it "can allow intersection of 2 zsets" do
351
+ b = setup_1
352
+
353
+ zlittles = b.zlittles
354
+ zlittles2 = b.zlittles2
355
+ zintersection = b.zlittles.intersect(zlittles2)
356
+ zlittles3 = b.zlittles3
357
+ zintersection2 = b.zlittles.intersect(zlittles3)
358
+ zintersection3 = zintersection.intersect(zintersection2)
359
+ zintersection4 = zintersection.intersect(zintersection)
360
+
361
+ assert_equal ["L1", "L4"], zintersection2.to_a.map(&:name)
362
+ assert_equal ["L2", "L3", "L4"], zintersection.to_a.map(&:name)
363
+ assert_equal ["L4"], zintersection3.to_a.map(&:name)
364
+ assert_equal zintersection.to_a.map(&:name), zintersection4.to_a.map(&:name)
365
+ end
366
+
367
+ it "can allow intersection of a zset and a set" do
368
+ b = setup_1
369
+
370
+ zlittles = b.zlittles
371
+ zlittles2 = b.zlittles2
372
+ slittles = b.slittles
373
+
374
+ zintersection = b.zlittles.intersect(slittles)
375
+ zintersection2 = b.zlittles2.intersect(slittles)
376
+
377
+ assert_equal ["L1","L2","L4"], zintersection.to_a.map(&:name)
378
+ assert_equal ["L2","L4"], zintersection2.to_a.map(&:name)
379
+ end
380
+
381
+ it "can allow intersection of multiple zsets and sets" do
382
+ b = setup_1
383
+
384
+ zlittles = b.zlittles
385
+ zlittles2 = b.zlittles2
386
+ zlittles3 = b.zlittles3
387
+ slittles = b.slittles
388
+
389
+ zintersection = b.zlittles.intersect_multiple([zlittles2, zlittles3])
390
+
391
+ assert_equal ["L4"], zintersection.to_a.map(&:name)
392
+ end
393
+
394
+ it "can allow intersection of multiple zsets and sets to a new named set" do
395
+ b = setup_1
396
+
397
+ zlittles = b.zlittles
398
+ zlittles2 = b.zlittles2
399
+ zlittles3 = b.zlittles3
400
+ slittles = b.slittles
401
+ zintersection = Ohm::ZSet.intersect_multiple("zintersection", [zlittles, zlittles2, zlittles3])
402
+
403
+ assert_equal ["L4"], zintersection.to_a.map(&:name)
404
+ assert_equal "zintersection", zintersection.key
405
+ end
406
+
407
+ it "can allow union of 2 zsets" do
408
+ b = setup_1
409
+
410
+ zlittles = b.zlittles
411
+ zlittles2 = b.zlittles2
412
+ zunion = b.zlittles.union(zlittles2)
413
+
414
+ assert_equal ["L1","L2","L3","L4"], zunion.to_a.map(&:name)
415
+ end
416
+
417
+ it "can allow union of a zset and a set" do
418
+ b = setup_1
419
+
420
+ zlittles = b.zlittles
421
+ zlittles2 = b.zlittles2
422
+ slittles = b.slittles
423
+
424
+ zunion = b.zlittles.union(slittles)
425
+ zunion2 = b.zlittles2.union(slittles)
426
+
427
+ assert_equal ["E3","L1","L2","L3","L4"], zunion.to_a.map(&:name)
428
+ end
429
+
430
+ it "can allow union of multiple zsets and sets" do
431
+ b = setup_1
432
+
433
+ zlittles = b.zlittles
434
+ zlittles2 = b.zlittles2
435
+ zlittles3 = b.zlittles3
436
+ slittles = b.slittles
437
+
438
+ zunion = b.zlittles.union_multiple([slittles, zlittles2, zlittles3])
439
+
440
+ assert_equal ["E3","L1","L2","L3","L4","E1","E2"], zunion.to_a.map(&:name)
441
+ end
442
+
443
+ it "can allow union of multiple zsets and sets to a newly named set" do
444
+ b = setup_1
445
+
446
+ zlittles = b.zlittles
447
+ zlittles2 = b.zlittles2
448
+ zlittles3 = b.zlittles3
449
+ slittles = b.slittles
450
+
451
+ zunion = Ohm::ZSet.union_multiple("zunion", [zlittles, slittles, zlittles2, zlittles3])
452
+
453
+ assert_equal ["E3","L1","L2","L3","L4","E1","E2"], zunion.to_a.map(&:name)
454
+ assert_equal "zunion", zunion.key
455
+ end
456
+
457
+ it "can get the rank of an element" do
458
+ b, l1, l2, l3, l4 = setup_2
459
+
460
+ assert_equal 0, b.zlittles.rank(l1)
461
+ assert_equal 1, b.zlittles.rank(l2)
462
+ assert_equal 2, b.zlittles.rank(l3)
463
+ assert_equal 3, b.zlittles.rank(l4)
464
+ end
465
+
466
+ it "can get the rank of specified element from the reverse sorted list" do
467
+ b, l1, l2, l3, l4 = setup_2
468
+
469
+ assert_equal 3, b.zlittles.revrank(l1)
470
+ assert_equal 2, b.zlittles.revrank(l2)
471
+ assert_equal 1, b.zlittles.revrank(l3)
472
+ assert_equal 0, b.zlittles.revrank(l4)
473
+ end
474
+
475
+ it "can get the score of an element" do
476
+ b, l1, l2, l3, l4 = setup_2
477
+
478
+ assert_equal 1, b.zlittles.score(l1)
479
+ assert_equal 2, b.zlittles.score(l2)
480
+ assert_equal 3, b.zlittles.score(l3)
481
+ assert_equal 4, b.zlittles.score(l4)
482
+ end
483
+
484
+ it "can get a range of elements by score" do
485
+ b, = setup_2
486
+
487
+ assert_equal ["L1", "L2", "L3", "L4"], b.zlittles.rangebyscore(0, 4).to_a.map(&:name)
488
+ assert_equal ["L1", "L2"], b.zlittles.rangebyscore(1, 2).to_a.map(&:name)
489
+ assert_equal ["L3", "L4"], b.zlittles.rangebyscore(3, 4).to_a.map(&:name)
490
+ assert_equal ["L1", "L2", "L3"], b.zlittles.rangebyscore(1, 3).to_a.map(&:name)
491
+ assert_equal ["L1", "L2"], b.zlittles.rangebyscore(0, 4, offset: 0, count: 2).to_a.map(&:name)
492
+ assert_equal ["L3", "L4"], b.zlittles.rangebyscore(0, 4, offset: 2, count: 2).to_a.map(&:name)
493
+ assert_equal ["L2", "L3", "L4"], b.zlittles.rangebyscore(0, 4, offset: 1, count: 3).to_a.map(&:name)
494
+ assert_equal ["L3"], b.zlittles.rangebyscore(1, 3, offset: 2, count: 4).to_a.map(&:name)
495
+ assert_equal ["L1", "L2", "L3", "L4"], b.zlittles.rangebyscore(0, "+inf").to_a.map(&:name)
496
+ assert_equal ["L4"], b.zlittles.rangebyscore(2, "+inf", offset: 2).to_a.map(&:name)
497
+ assert_equal ["L1", "L2"], b.zlittles.rangebyscore("-inf", 2).to_a.map(&:name)
498
+ assert_equal ["L4"], b.zlittles.rangebyscore(2, "+inf", offset: 2, count: 2).to_a.map(&:name)
499
+ end
500
+
501
+ it "can get a range of elements by score in reverse" do
502
+ b, = setup_2
503
+
504
+ assert_equal ["L4", "L3", "L2", "L1"], b.zlittles.revrangebyscore(4, 0).to_a.map(&:name)
505
+ assert_equal ["L2", "L1"], b.zlittles.revrangebyscore(2, 1).to_a.map(&:name)
506
+ assert_equal ["L4", "L3"], b.zlittles.revrangebyscore(4, 3).to_a.map(&:name)
507
+ assert_equal ["L3", "L2", "L1"], b.zlittles.revrangebyscore(3, 1).to_a.map(&:name)
508
+ assert_equal ["L4", "L3"], b.zlittles.revrangebyscore(4, 0, offset: 0, count: 2).to_a.map(&:name)
509
+ assert_equal ["L2", "L1"], b.zlittles.revrangebyscore(4, 0, offset: 2, count: 2).to_a.map(&:name)
510
+ assert_equal ["L3", "L2", "L1"], b.zlittles.revrangebyscore(4, 0, offset: 1, count: 3).to_a.map(&:name)
511
+ assert_equal ["L1"], b.zlittles.revrangebyscore(3, 1, offset: 2, count: 4).to_a.map(&:name)
512
+ assert_equal ["L4", "L3", "L2", "L1"], b.zlittles.revrangebyscore("+inf", 0).to_a.map(&:name)
513
+ assert_equal ["L2"], b.zlittles.revrangebyscore("+inf", 2, offset: 2).to_a.map(&:name)
514
+ assert_equal ["L2", "L1"], b.zlittles.revrangebyscore(2, "-inf").to_a.map(&:name)
515
+ assert_equal ["L2"], b.zlittles.revrangebyscore("+inf", 2, offset: 2, count: 2).to_a.map(&:name)
516
+ end
517
+
518
+ it "can get the number of elements between 2 given scores" do
519
+ b, = setup_2
520
+
521
+ assert_equal 2, b.zlittles.count(1, 2)
522
+ assert_equal 2, b.zlittles.count(3, 4)
523
+ assert_equal 4, b.zlittles.count(1, 4)
524
+ assert_equal 3, b.zlittles.count(2, "+inf")
525
+ assert_equal 4, b.zlittles.count
526
+ assert_equal 4, b.zlittles.count("-inf", "+inf")
527
+ assert_equal 2, b.zlittles.count("-inf", 2)
528
+ end
529
+
530
+ it "can update the sorted set properly upon updating the score of an element" do
531
+ b, l1, l2, l3, l4 = setup_2
532
+ assert_equal ["L1", "L2", "L3", "L4"], b.zlittles.to_a.map(&:name)
533
+
534
+ l1.score = 5
535
+ l1.save
536
+ b.zlittles.update(l1)
537
+ assert_equal ["L2", "L3", "L4", "L1"], b.zlittles.to_a.map(&:name)
538
+
539
+ l3.score = -3
540
+ l3.save
541
+ b.zlittles.update(l3)
542
+ assert_equal ["L3", "L2", "L4", "L1"], b.zlittles.to_a.map(&:name)
543
+
544
+ end
545
+
546
+ it "can sort elements by date" do
547
+ b = setup_4
548
+
549
+ assert_equal ["D3", "D2", "D1", "D4"], b.zdts.to_a.map(&:name)
550
+ end
551
+
552
+ it "can sort elements by name" do
553
+ b = setup_5
554
+
555
+ assert_equal ["Apple", "Banana", "Coconut", "Dragonfruit",
556
+ "apple", "apples", "banana", "bananas",
557
+ "coconut", "coconuts", "durian", "durians"],
558
+ b.zbools2.to_a.map(&:name)
559
+ end
560
+
561
+ it "can sort elements by name (insensitive)" do
562
+ b = setup_6
563
+
564
+ assert_equal ["apple", "Apple", "Apples",
565
+ "Banana", "banana", "bananas",
566
+ "Coconut", "coconut", "coconuts",
567
+ "duria", "Durian", "durians"],
568
+ b.zbools3.to_a.map(&:name)
569
+ end
570
+
571
+ it "can sort elements by name (insensitive high)" do
572
+ b = setup_7
573
+
574
+ assert_equal ["Apple", "Apples", "apple",
575
+ "Banana", "banana", "bananas",
576
+ "Coconut", "coconut", "coconuts",
577
+ "Durian", "duria", "durians"],
578
+ b.zbools4.to_a.map(&:name)
579
+ end
580
+
581
+ it "can find elements that starts with specified string" do
582
+ b = setup_5
583
+
584
+ assert_equal ["durian", "durians"], b.zbools2.starts_with("du").map(&:name)
585
+ assert_equal ["durians"], b.zbools2.starts_with("d",offset:1,limit:1).map(&:name)
586
+ assert_equal ["bananas"], b.zbools2.starts_with("bananas").map(&:name)
587
+ end
588
+
589
+ it "can return the first and last elements" do
590
+ b = setup_1
591
+
592
+ assert_equal "L1", b.zlittles.first.name
593
+ assert_equal "L4", b.zlittles.last.name
594
+ end
595
+
596
+ it "can be deleted / destroyed" do
597
+ b = setup_1
598
+
599
+ b.zlittles.destroy!
600
+
601
+ assert_equal [], b.zlittles.to_a.map(&:name)
602
+ end
603
+
604
+ it "can delete all elements at once" do
605
+ b = setup_1
606
+
607
+ b.zlittles.clear
608
+
609
+ assert_equal [], b.zlittles.to_a.map(&:name)
610
+ end
611
+
612
+ it "can clone itself to another instance" do
613
+ b, l1, l2, l3, l4 = setup_2
614
+
615
+ clone = b.zlittles.duplicate
616
+
617
+ assert_equal ["L1", "L2", "L3", "L4"], clone.to_a.map(&:name)
618
+ assert_equal 1, clone.score(l1)
619
+ assert_equal 2, clone.score(l2)
620
+ assert_equal 3, clone.score(l3)
621
+ assert_equal 4, clone.score(l4)
622
+ end
623
+
624
+ it "can convert a procedure block to string and back" do
625
+ x = lambda { |x| x + 1 }
626
+ y = Ohm::Utils.proc_to_string x
627
+
628
+ assert_equal "proc { |x| (x + 1) }", y
629
+
630
+ z = Ohm::Utils.string_to_proc y
631
+
632
+ assert_equal 3, z.call(2)
633
+ end
634
+
635
+ it "can convert a score_field list to string and back" do
636
+ score_field = [:n1, :n2, :n3, lambda { |x| x + 1 }]
637
+ score_field_string = Ohm::Utils.score_field_to_string score_field
638
+
639
+ assert_equal "n1:n2:n3:proc { |x| (x + 1) }", score_field_string
640
+
641
+ score_field_list = Ohm::Utils.string_to_score_field score_field_string
642
+
643
+ assert_equal :n1, score_field_list[0]
644
+ assert_equal :n2, score_field_list[1]
645
+ assert_equal :n3, score_field_list[2]
646
+
647
+ assert_equal 3, score_field_list[3].call(2)
648
+ end
649
+
650
+ it "can save and load sets by name" do
651
+ b = setup_1
652
+
653
+ sorted_set = b.zlittles
654
+ sorted_set.save_set
655
+ sorted_set_2 = Ohm::ZSet.load_set(sorted_set.key)
656
+
657
+ assert_equal sorted_set_2.to_a.map(&:name), sorted_set.to_a.map(&:name)
658
+
659
+ sorted_set_2.add(Little.create(name:'X1',score:29))
660
+
661
+ assert_equal sorted_set_2.to_a.map(&:name), sorted_set.to_a.map(&:name)
662
+ end
663
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ohm-zset
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.2'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Josh
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ohm
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Adds ZSet support to Ohm
31
+ email:
32
+ - akosijoshualat@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gems
38
+ - .gitignore
39
+ - .rvmrc
40
+ - CHANGELOG
41
+ - LICENSE
42
+ - README.md
43
+ - Rakefile
44
+ - lib/.DS_Store
45
+ - lib/ohm-zset.rb
46
+ - lib/suppress-warnings.rb
47
+ - test/.DS_Store
48
+ - test/helper.rb
49
+ - test/unit/.DS_Store
50
+ - test/unit/ohm-zset.rb
51
+ homepage: ''
52
+ licenses: []
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubyforge_project:
71
+ rubygems_version: 1.8.24
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Adds ZSet support to Ohm
75
+ test_files:
76
+ - test/.DS_Store
77
+ - test/helper.rb
78
+ - test/unit/.DS_Store
79
+ - test/unit/ohm-zset.rb