ohm-zset 0.2

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/.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