mock_redis 0.5.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,6 @@
1
+ ### 0.6.0
2
+ * Support for `#sort` (ascending and descending only)
3
+
1
4
  ### 0.5.5
2
5
  * Support exclusive ranges in `zcount`
3
6
  * List methods (`lindex`, `lrange`, `lset`, and `ltrim`) can take string indexes
data/README.md CHANGED
@@ -51,6 +51,9 @@ necessary exceptions.
51
51
 
52
52
  * `#info` just returns canned values; they don't update over time.
53
53
 
54
+ * `#sort` supports ascending and descending sort. `ALPHA` sort is not yet
55
+ supported.
56
+
54
57
  ## Unsupported Commands
55
58
 
56
59
  Some stuff, we just can't do with a single Ruby object in a single
@@ -79,10 +82,6 @@ please submit a pull request with your (tested!) implementation.
79
82
  * `#config(:get|:set|:resetstat)` isn't done. They can just return
80
83
  canned values.
81
84
 
82
- * `#sort` isn't done. We just haven't gotten to it yet. The input
83
- validation will be a pain in the butt, but other than that, it
84
- shouldn't be too bad.
85
-
86
85
  ## Running the Tests
87
86
 
88
87
  If you want to work on this, you'll probably want to run the
@@ -5,6 +5,7 @@ require 'mock_redis/list_methods'
5
5
  require 'mock_redis/set_methods'
6
6
  require 'mock_redis/string_methods'
7
7
  require 'mock_redis/zset_methods'
8
+ require 'mock_redis/sort_method'
8
9
 
9
10
  class MockRedis
10
11
  class Database
@@ -13,6 +14,7 @@ class MockRedis
13
14
  include SetMethods
14
15
  include StringMethods
15
16
  include ZsetMethods
17
+ include SortMethod
16
18
 
17
19
  attr_reader :data, :expire_times
18
20
 
@@ -0,0 +1,82 @@
1
+ require 'mock_redis/assertions'
2
+
3
+ class MockRedis
4
+ module SortMethod
5
+ include Assertions
6
+
7
+ def sort(key, options={})
8
+ return [] if key.nil?
9
+
10
+ enumerable = data[key]
11
+
12
+ return [] if enumerable.nil?
13
+
14
+ by = options[:by]
15
+ limit = options[:limit] || []
16
+ store = options[:store]
17
+ get_patterns = Array(options[:get])
18
+ order = options[:order] || "ASC"
19
+ direction = order.split.first
20
+
21
+ projected = project(enumerable, by, get_patterns)
22
+ sorted = sort_by(projected, direction)
23
+ sliced = slice(sorted, limit)
24
+
25
+ store ? rpush(store, sliced) : sliced
26
+ end
27
+
28
+ private
29
+
30
+ ASCENDING_SORT = Proc.new { |a, b| a.first <=> b.first }
31
+ DESCENDING_SORT = Proc.new { |a, b| b.first <=> a.first }
32
+
33
+ def project(enumerable, by, get_patterns)
34
+ enumerable.map do |*elements|
35
+ element = elements.last
36
+ weight = by ? lookup_from_pattern(by, element) : element
37
+ value = element
38
+
39
+ if get_patterns.length > 0
40
+ value = get_patterns.map do |pattern|
41
+ pattern == "#" ? element : lookup_from_pattern(pattern, element)
42
+ end
43
+ value = value.first if value.length == 1
44
+ end
45
+
46
+ [weight, value]
47
+ end
48
+ end
49
+
50
+ def sort_by(projected, direction)
51
+ sorter =
52
+ case direction.upcase
53
+ when "DESC"
54
+ DESCENDING_SORT
55
+ when "ASC", "ALPHA"
56
+ ASCENDING_SORT
57
+ else
58
+ raise "Invalid direction '#{direction}'"
59
+ end
60
+
61
+ projected.sort(&sorter).map(&:last)
62
+ end
63
+
64
+ def slice(sorted, limit)
65
+ skip = limit.first || 0
66
+ take = limit.last || sorted.length
67
+
68
+ sorted[skip...(skip + take)] || sorted
69
+ end
70
+
71
+ def lookup_from_pattern(pattern, element)
72
+ key = pattern.sub('*', element)
73
+
74
+ if (hash_parts = key.split('->')).length > 1
75
+ hget hash_parts.first, hash_parts.last
76
+ else
77
+ get key
78
+ end
79
+ end
80
+
81
+ end
82
+ end
@@ -1,3 +1,3 @@
1
1
  class MockRedis
2
- VERSION = '0.5.5'
2
+ VERSION = '0.6.0'
3
3
  end
@@ -21,7 +21,7 @@ describe "#setbit(key, offset)" do
21
21
 
22
22
  it "does the right thing with multibyte characters" do
23
23
  @redises.set(@key, "€99.94") # the euro sign is 3 bytes wide in UTF-8
24
- # @redises.setbit(@key, 63, 1).should == 0
24
+ @redises.setbit(@key, 63, 1).should == 0
25
25
  @redises.get(@key).should == "€99.95"
26
26
  end
27
27
 
@@ -43,4 +43,4 @@ describe "#setbit(key, offset)" do
43
43
 
44
44
  it_should_behave_like "a string-only command"
45
45
  end
46
-
46
+
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#sort(key, options)' do
4
+ before do
5
+ @key = "mock-redis-test:list_sort"
6
+
7
+ @redises.rpush(@key, '1')
8
+ @redises.rpush(@key, '2')
9
+
10
+ @redises.set('mock-redis-test:values_1', 'a')
11
+ @redises.set('mock-redis-test:values_2', 'b')
12
+
13
+ @redises.set('mock-redis-test:weight_1', '2')
14
+ @redises.set('mock-redis-test:weight_2', '1')
15
+
16
+ @redises.hset('mock-redis-test:hash_1', 'key', 'x')
17
+ @redises.hset('mock-redis-test:hash_2', 'key', 'y')
18
+ end
19
+
20
+ it_should_behave_like "a sortable"
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#sort(key, options)' do
4
+ before do
5
+ @key = "mock-redis-test:set_sort"
6
+
7
+ @redises.sadd(@key, '1')
8
+ @redises.sadd(@key, '2')
9
+
10
+ @redises.set('mock-redis-test:values_1', 'a')
11
+ @redises.set('mock-redis-test:values_2', 'b')
12
+
13
+ @redises.set('mock-redis-test:weight_1', '2')
14
+ @redises.set('mock-redis-test:weight_2', '1')
15
+
16
+ @redises.hset('mock-redis-test:hash_1', 'key', 'x')
17
+ @redises.hset('mock-redis-test:hash_2', 'key', 'y')
18
+ end
19
+
20
+ it_should_behave_like "a sortable"
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#sort(key, options)' do
4
+ before do
5
+ @key = "mock-redis-test:zset_sort"
6
+
7
+ @redises.zadd(@key, 100, '1')
8
+ @redises.zadd(@key, 99, '2')
9
+
10
+ @redises.set('mock-redis-test:values_1', 'a')
11
+ @redises.set('mock-redis-test:values_2', 'b')
12
+
13
+ @redises.set('mock-redis-test:weight_1', '2')
14
+ @redises.set('mock-redis-test:weight_2', '1')
15
+
16
+ @redises.hset('mock-redis-test:hash_1', 'key', 'x')
17
+ @redises.hset('mock-redis-test:hash_2', 'key', 'y')
18
+ end
19
+
20
+ it_should_behave_like "a sortable"
21
+ end
@@ -0,0 +1,56 @@
1
+ shared_examples_for "a sortable" do
2
+ it 'returns empty array on nil' do
3
+ @redises.sort(nil).should == []
4
+ end
5
+
6
+ context 'ordering' do
7
+ it 'orders ascending by default' do
8
+ @redises.sort(@key).should == ['1', '2']
9
+ end
10
+
11
+ it 'orders by descending when specified' do
12
+ @redises.sort(@key, :order => "DESC").should == ['2', '1']
13
+ end
14
+ end
15
+
16
+ context 'projections' do
17
+ it 'projects element when :get is "#"' do
18
+ @redises.sort(@key, :get => '#').should == ['1', '2']
19
+ end
20
+
21
+ it 'projects through a key pattern' do
22
+ @redises.sort(@key, :get => 'mock-redis-test:values_*').should == ['a', 'b']
23
+ end
24
+
25
+ it 'projects through a key pattern and reflects element' do
26
+ @redises.sort(@key, :get => ['#', 'mock-redis-test:values_*']).should == [['1', 'a'], ['2', 'b']]
27
+ end
28
+
29
+ it 'projects through a hash key pattern' do
30
+ @redises.sort(@key, :get => 'mock-redis-test:hash_*->key').should == ['x', 'y']
31
+ end
32
+ end
33
+
34
+ context 'weights' do
35
+ it 'weights by projecting through a key pattern' do
36
+ @redises.sort(@key, :by => "mock-redis-test:weight_*").should == ['2', '1']
37
+ end
38
+
39
+ it 'weights by projecting through a key pattern and a specific order' do
40
+ @redises.sort(@key, :order => "DESC", :by => "mock-redis-test:weight_*").should == ['1', '2']
41
+ end
42
+ end
43
+
44
+ context 'limit' do
45
+ it 'only returns requested window in the enumerable' do
46
+ @redises.sort(@key, :limit => [0, 1]).should == ['1']
47
+ end
48
+ end
49
+
50
+ context 'store' do
51
+ it 'stores into another key' do
52
+ @redises.sort(@key, :store => "mock-redis-test:some_bucket").should == 2
53
+ @redises.lrange("mock-redis-test:some_bucket", 0, -1).should == ['1', '2']
54
+ end
55
+ end
56
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mock_redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.5
4
+ version: 0.6.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-10-28 00:00:00.000000000 Z
13
+ date: 2012-10-30 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rake
@@ -86,6 +86,7 @@ files:
86
86
  - lib/mock_redis/multi_db_wrapper.rb
87
87
  - lib/mock_redis/pipelined_wrapper.rb
88
88
  - lib/mock_redis/set_methods.rb
89
+ - lib/mock_redis/sort_method.rb
89
90
  - lib/mock_redis/string_methods.rb
90
91
  - lib/mock_redis/transaction_wrapper.rb
91
92
  - lib/mock_redis/undef_redis_methods.rb
@@ -178,6 +179,9 @@ files:
178
179
  - spec/commands/sismember_spec.rb
179
180
  - spec/commands/smembers_spec.rb
180
181
  - spec/commands/smove_spec.rb
182
+ - spec/commands/sort_list_spec.rb
183
+ - spec/commands/sort_set_spec.rb
184
+ - spec/commands/sort_zset_spec.rb
181
185
  - spec/commands/spop_spec.rb
182
186
  - spec/commands/srandmember_spec.rb
183
187
  - spec/commands/srem_spec.rb
@@ -212,6 +216,7 @@ files:
212
216
  - spec/support/shared_examples/only_operates_on_sets.rb
213
217
  - spec/support/shared_examples/only_operates_on_strings.rb
214
218
  - spec/support/shared_examples/only_operates_on_zsets.rb
219
+ - spec/support/shared_examples/sorts_enumerables.rb
215
220
  - spec/transactions_spec.rb
216
221
  homepage: https://github.com/causes/mock_redis
217
222
  licenses: []
@@ -322,6 +327,9 @@ test_files:
322
327
  - spec/commands/sismember_spec.rb
323
328
  - spec/commands/smembers_spec.rb
324
329
  - spec/commands/smove_spec.rb
330
+ - spec/commands/sort_list_spec.rb
331
+ - spec/commands/sort_set_spec.rb
332
+ - spec/commands/sort_zset_spec.rb
325
333
  - spec/commands/spop_spec.rb
326
334
  - spec/commands/srandmember_spec.rb
327
335
  - spec/commands/srem_spec.rb
@@ -356,5 +364,6 @@ test_files:
356
364
  - spec/support/shared_examples/only_operates_on_sets.rb
357
365
  - spec/support/shared_examples/only_operates_on_strings.rb
358
366
  - spec/support/shared_examples/only_operates_on_zsets.rb
367
+ - spec/support/shared_examples/sorts_enumerables.rb
359
368
  - spec/transactions_spec.rb
360
369
  has_rdoc: