commendo 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f4d4570da8f16342e587461c8731982f4a82c8ba
4
- data.tar.gz: bdde9ae21c9bb35c7c9b6073a82e651086132617
3
+ metadata.gz: 9504182a72226de650736e2b987eda2734a5f3bf
4
+ data.tar.gz: ff9fb6d451b160f8f2ac4da2d4cb2688621ad7ff
5
5
  SHA512:
6
- metadata.gz: 31406c7ee3846a6046e8e149ca8ada66eaed799977ee615e778a5fb3a2c353165e246deb87b422bef7d5a544a4dddbac3788a4ed879a77a04b13b0f3ed9d7dbc
7
- data.tar.gz: 15e58e641bd237466b80713c64d893ebd66877aa4c4a28241b584875d5e476fc28c45d68194eacd9b74cfef5a4e144c011e892185bd1ee9d27f38fc346c11032
6
+ metadata.gz: 7669f08e1c313865623360a14f72d7686da669c36c7a096485f9da9d9552f904b7cf808bbdaf2379af32d681939a6ab5d587759cbead1fb8037d6869ef91e048
7
+ data.tar.gz: e8a729ece664f9167e0f2efd8212f5d1ac87ab5edd5dc443ff561ae047d81a97ab6d1d5dafccf7b2c8aac209bc38bc34cdd456e01816bba050ad03cd32a8c8b8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ # 1.1.0 / 2015-04-01
2
+ * [FEATURE] Add ability to remove a resource from a group and recalculate similarity
3
+
1
4
  # 1.0.0 / 2014-04-22
2
5
  * [FEATURE] Add limits to similarity requests and bump to production release 1.0.0 :)
3
6
 
@@ -38,6 +38,10 @@ module Commendo
38
38
  calculate_similarity_for_resource(resource, 0)
39
39
  end
40
40
 
41
+ def groups(resource)
42
+ redis.zrange(resource_key(resource), 0, -1)
43
+ end
44
+
41
45
  def delete(resource)
42
46
  similar = similar_to(resource)
43
47
  similar.each do |other_resource|
@@ -54,18 +58,17 @@ module Commendo
54
58
  #TODO make this use scan for scaling
55
59
  keys = redis.keys("#{resource_key_base}:*")
56
60
  keys.each_with_index do |key, i|
61
+ resource = key.gsub(/^#{resource_key_base}:/, '')
62
+ similarity_key = similarity_key(resource)
63
+ redis.del(similarity_key)
57
64
  yield(key, i, keys.length) if block_given?
58
65
  completed = redis.eval(similarity_lua, keys: [key], argv: [tmp_key_base, resource_key_base, similar_key_base, group_key_base, threshold])
59
66
  if completed == SET_TOO_LARGE_FOR_LUA
60
- calculate_similarity_for_key(key, threshold)
67
+ calculate_similarity_for_key_resource(key, resource, threshold)
61
68
  end
62
69
  end
63
70
  end
64
71
 
65
- def calculate_similarity_for_key(key, threshold)
66
- resource = key.gsub(/^#{resource_key_base}:/, '')
67
- calculate_similarity_for_key_resource(key, resource, threshold)
68
- end
69
72
 
70
73
  def calculate_similarity_for_resource(resource, threshold)
71
74
  key = resource_key(resource)
@@ -73,12 +76,14 @@ module Commendo
73
76
  end
74
77
 
75
78
  def calculate_similarity_for_key_resource(key, resource, threshold)
76
- groups = redis.zrange(resource_key(resource), 0, -1)
79
+ groups = groups(resource)
77
80
  group_keys = groups.map { |group| group_key(group) }
78
81
  tmp_key = "#{tmp_key_base}:#{SecureRandom.uuid}"
79
82
  redis.zunionstore(tmp_key, group_keys)
80
83
  resources = redis.zrange(tmp_key, 0, -1)
81
84
  redis.del(tmp_key)
85
+ similarity_key = similarity_key(resource)
86
+ redis.del(similarity_key)
82
87
  resources.each do |to_compare|
83
88
  next if resource == to_compare
84
89
  redis.eval(pair_comparison_lua, keys: [key, resource_key(to_compare), similarity_key(resource), similarity_key(to_compare)], argv: [tmp_key_base, resource, to_compare, threshold])
@@ -104,7 +109,7 @@ module Commendo
104
109
  end
105
110
 
106
111
  def filtered_similar_to(resource, options = {})
107
- if @tag_set.nil? || (options[:include].nil? && options[:exclude].nil?)
112
+ if @tag_set.nil? || (options[:include].nil? && options[:exclude].nil?) || @tag_set.empty?
108
113
  return similar_to(resource, options[:limit] || 0)
109
114
  else
110
115
  similar = similar_to(resource)
@@ -122,6 +127,20 @@ module Commendo
122
127
  "#{similar_key_base}:#{resource}"
123
128
  end
124
129
 
130
+ def remove_from_groups(resource, *groups)
131
+ resource_key = resource_key(resource)
132
+ redis.zrem(resource_key, groups)
133
+ groups.each do |group|
134
+ group_key = group_key(group)
135
+ redis.zrem(group_key, resource)
136
+ end
137
+ end
138
+
139
+ def remove_from_groups_and_calculate(resource, *groups)
140
+ remove_from_groups(resource, *groups)
141
+ calculate_similarity_for_resource(resource, 0)
142
+ end
143
+
125
144
  private
126
145
 
127
146
  def similarity_lua
@@ -26,20 +26,21 @@ for _,group in ipairs(groups) do
26
26
  end
27
27
  --redis.log(redis.LOG_NOTICE, 'Found ' .. table.getn(group_keys) .. ' group keys')
28
28
 
29
- --TODO change foo
29
+ --TODO change unionfoo to a random slug
30
30
  local tmp_groups_union_key = tmp_key_base .. 'unionfoo'
31
31
  redis.call('ZUNIONSTORE', tmp_groups_union_key, table.getn(group_keys), unpack(group_keys))
32
32
  local resources = redis.call('ZRANGE', tmp_groups_union_key, 0, -1)
33
33
 
34
+ --TODO change 'foo' to something much more unlikely
34
35
  local previous = 'foo'
35
36
  for _,to_compare in ipairs(resources) do
36
37
  --redis.log(redis.LOG_NOTICE, 'Comparing ' .. resource .. ' and ' .. to_compare)
37
38
  if to_compare ~= previous then
38
39
  previous = to_compare
39
- if resource > to_compare then
40
+ if resource ~= to_compare then
40
41
  --redis.log(redis.LOG_NOTICE, 'Calculating similarity for ' .. resource .. ' and ' .. to_compare)
41
42
 
42
- --TODO change bar
43
+ --TODO change bar to a random slug
43
44
  local tmp_pair_intersect_key = tmp_key_base .. 'bar'
44
45
  redis.call('ZINTERSTORE', tmp_pair_intersect_key, 2, resource_key, resource_key_base .. ':' .. to_compare)
45
46
  local intersect = redis.call('ZRANGE', tmp_pair_intersect_key, 0, -1, 'WITHSCORES')
@@ -51,7 +52,7 @@ for _,to_compare in ipairs(resources) do
51
52
  intersect_score = intersect_score + intersect[i+1]
52
53
  end
53
54
 
54
- --TODO change baz
55
+ --TODO change baz to a random slug
55
56
  local tmp_pair_union_key = tmp_key_base .. 'baz'
56
57
  redis.call('ZUNIONSTORE', tmp_pair_union_key, 2, resource_key, resource_key_base .. ':' .. to_compare)
57
58
 
@@ -66,7 +67,7 @@ for _,to_compare in ipairs(resources) do
66
67
  if similarity > threshold then
67
68
  --redis.log(redis.LOG_NOTICE, resource .. ' and ' .. to_compare .. ' scored ' .. similarity)
68
69
  redis.call('ZADD', sim_key_base .. ':' .. resource, similarity, to_compare)
69
- redis.call('ZADD', sim_key_base .. ':' .. to_compare, similarity, resource)
70
+ --redis.call('ZADD', sim_key_base .. ':' .. to_compare, similarity, resource)
70
71
  end
71
72
  end
72
73
  end
@@ -8,6 +8,11 @@ module Commendo
8
8
  @redis, @key_base = redis, key_base
9
9
  end
10
10
 
11
+ def empty?
12
+ cursor, keys = redis.scan(0, match: "#{key_base}:*", count: 1)
13
+ cursor.to_i == 0
14
+ end
15
+
11
16
  def get(resource)
12
17
  redis.smembers(resource_key(resource)).sort
13
18
  end
@@ -1,3 +1,3 @@
1
1
  module Commendo
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -9,134 +9,113 @@ module Commendo
9
9
 
10
10
  class ContentSetTest < Minitest::Test
11
11
 
12
+ def setup
13
+ @redis = Redis.new(db: 15)
14
+ @redis.flushdb
15
+ @key_base = 'CommendoTests'
16
+ @cs = ContentSet.new(@redis, @key_base)
17
+ end
18
+
12
19
  def test_gives_similarity_key_for_resource
13
- redis = Redis.new(db: 15)
14
- key_base = 'CommendoTests'
15
- cs = ContentSet.new(redis, key_base)
16
- assert_equal 'CommendoTests:similar:resource-1', cs.similarity_key('resource-1')
20
+ key_base = 'CommendoTestsFooBarBaz'
21
+ cs = ContentSet.new(@redis, key_base)
22
+ assert_equal 'CommendoTestsFooBarBaz:similar:resource-1', cs.similarity_key('resource-1')
17
23
  end
18
24
 
19
25
  def test_recommends_when_added
20
- redis = Redis.new(db: 15)
21
- redis.flushdb
22
- key_base = 'CommendoTests'
23
- cs = ContentSet.new(redis, key_base)
24
- cs.add('resource-1', 'group-1', 'group-2')
25
- cs.add('resource-2', 'group-1')
26
- cs.add('resource-3', 'group-1', 'group-2')
27
- cs.add('resource-4', 'group-2')
28
- cs.calculate_similarity
26
+ @cs.add('resource-1', 'group-1', 'group-2')
27
+ @cs.add('resource-2', 'group-1')
28
+ @cs.add('resource-3', 'group-1', 'group-2')
29
+ @cs.add('resource-4', 'group-2')
30
+ @cs.calculate_similarity
29
31
  expected = [
30
32
  {resource: 'resource-3', similarity: 1.0},
31
33
  {resource: 'resource-4', similarity: 0.667},
32
34
  {resource: 'resource-2', similarity: 0.667}
33
35
  ]
34
- assert_equal expected, cs.similar_to('resource-1')
36
+ assert_equal expected, @cs.similar_to('resource-1')
35
37
  end
36
38
 
37
39
  def test_recommends_limited_by_number
38
- redis = Redis.new(db: 15)
39
- redis.flushdb
40
- key_base = 'CommendoTests'
41
- cs = ContentSet.new(redis, key_base)
42
- cs.add('resource-1', 'group-1', 'group-2')
43
- cs.add('resource-2', 'group-1')
44
- cs.add('resource-3', 'group-1', 'group-2')
45
- cs.add('resource-4', 'group-2')
46
- cs.calculate_similarity
40
+ @cs.add('resource-1', 'group-1', 'group-2')
41
+ @cs.add('resource-2', 'group-1')
42
+ @cs.add('resource-3', 'group-1', 'group-2')
43
+ @cs.add('resource-4', 'group-2')
44
+ @cs.calculate_similarity
47
45
  expected = [
48
46
  {resource: 'resource-3', similarity: 1.0},
49
47
  {resource: 'resource-4', similarity: 0.667},
50
48
  {resource: 'resource-2', similarity: 0.667}
51
49
  ]
52
- assert_equal expected[0..0], cs.similar_to('resource-1', 1)
53
- assert_equal expected[0..1], cs.similar_to('resource-1', 2)
54
- assert_equal expected, cs.similar_to('resource-1', 3)
55
- assert_equal expected, cs.similar_to('resource-1', 99)
50
+ assert_equal expected[0..0], @cs.similar_to('resource-1', 1)
51
+ assert_equal expected[0..1], @cs.similar_to('resource-1', 2)
52
+ assert_equal expected, @cs.similar_to('resource-1', 3)
53
+ assert_equal expected, @cs.similar_to('resource-1', 99)
56
54
  end
57
55
 
58
56
  def test_recommends_when_added_with_scores
59
- redis = Redis.new(db: 15)
60
- redis.flushdb
61
- key_base = 'CommendoTests'
62
- cs = ContentSet.new(redis, key_base)
63
- cs.add('resource-1', ['group-1', 2], ['group-2', 2])
64
- cs.add('resource-2', ['group-1', 7])
65
- cs.add('resource-3', ['group-1', 2], ['group-2', 2])
66
- cs.add('resource-4', ['group-2', 3])
67
- cs.calculate_similarity
57
+ @cs.add('resource-1', ['group-1', 2], ['group-2', 2])
58
+ @cs.add('resource-2', ['group-1', 7])
59
+ @cs.add('resource-3', ['group-1', 2], ['group-2', 2])
60
+ @cs.add('resource-4', ['group-2', 3])
61
+ @cs.calculate_similarity
68
62
  expected = [
69
63
  {resource: 'resource-3', similarity: 1.0},
70
64
  {resource: 'resource-2', similarity: 0.818},
71
65
  {resource: 'resource-4', similarity: 0.714}
72
66
  ]
73
- assert_equal expected, cs.similar_to('resource-1')
67
+ assert_equal expected, @cs.similar_to('resource-1')
74
68
  end
75
69
 
76
70
  def test_recommends_with_large_number_of_groups
77
- redis = Redis.new(db: 15)
78
- redis.flushdb
79
- key_base = 'CommendoTests'
80
- cs = ContentSet.new(redis, key_base)
81
71
  (0..3000).each do |i|
82
- cs.add('resource-1', ["group-#{i}", i/100.0], ["group-#{i+1}", i/20.0])
83
- cs.add('resource-9', ["group-#{i}", i/100.0], ["group-#{i+1}", i/20.0])
72
+ @cs.add('resource-1', ["group-#{i}", i/100.0], ["group-#{i+1}", i/20.0])
73
+ @cs.add('resource-9', ["group-#{i}", i/100.0], ["group-#{i+1}", i/20.0])
84
74
  end
85
- cs.calculate_similarity
75
+ @cs.calculate_similarity
86
76
  expected = [
87
77
  {resource: 'resource-9', similarity: 1.0}
88
78
  ]
89
- assert_equal expected, cs.similar_to('resource-1')
79
+ assert_equal expected, @cs.similar_to('resource-1')
90
80
  end
91
81
 
92
82
  def test_recommends_when_extra_scores_added
93
- test_recommends_when_added_with_scores
94
- redis = Redis.new(db: 15)
95
- key_base = 'CommendoTests'
96
- cs = ContentSet.new(redis, key_base)
97
- cs.add('resource-3', ['group-1', 1], ['group-3', 2])
98
- cs.add('resource-4', ['group-2', 1])
99
- cs.add_by_group('group-1', ['newource-9', 100], 'resource-2', 'resource-3')
100
- cs.add_by_group('group-2', 'resource-1', 'resource-3', 'resource-4')
101
- cs.calculate_similarity
83
+ test_recommends_when_added_with_scores #sets up the content set
84
+ @cs.add('resource-3', ['group-1', 1], ['group-3', 2])
85
+ @cs.add('resource-4', ['group-2', 1])
86
+ @cs.add_by_group('group-1', ['newource-9', 100], 'resource-2', 'resource-3')
87
+ @cs.add_by_group('group-2', 'resource-1', 'resource-3', 'resource-4')
88
+ @cs.calculate_similarity
102
89
  expected = [
103
90
  {resource: 'newource-9', similarity: 1.0},
104
91
  {resource: 'resource-1', similarity: 0.769},
105
92
  {resource: 'resource-3', similarity: 0.706}
106
93
  ]
107
- assert_equal expected, cs.similar_to('resource-2')
94
+ assert_equal expected, @cs.similar_to('resource-2')
108
95
  end
109
96
 
110
97
  def test_recommends_when_added_by_group
111
- redis = Redis.new(db: 15)
112
- redis.flushdb
113
- key_base = 'CommendoTests'
114
- cs = ContentSet.new(redis, key_base)
115
- cs.add_by_group('group-1', 'resource-1', 'resource-2', 'resource-3')
116
- cs.add_by_group('group-2', 'resource-1', 'resource-3', 'resource-4')
117
- cs.calculate_similarity
98
+ @cs.add_by_group('group-1', 'resource-1', 'resource-2', 'resource-3')
99
+ @cs.add_by_group('group-2', 'resource-1', 'resource-3', 'resource-4')
100
+ @cs.calculate_similarity
118
101
  expected = [
119
102
  {resource: 'resource-3', similarity: 1.0},
120
103
  {resource: 'resource-4', similarity: 0.667},
121
104
  {resource: 'resource-2', similarity: 0.667}
122
105
  ]
123
- assert_equal expected, cs.similar_to('resource-1')
106
+ assert_equal expected, @cs.similar_to('resource-1')
124
107
  end
125
108
 
126
109
  def test_recommends_when_added_by_group_with_scores
127
- redis = Redis.new(db: 15)
128
- redis.flushdb
129
- key_base = 'CommendoTests'
130
- cs = ContentSet.new(redis, key_base)
131
- cs.add_by_group('group-1', ['resource-1', 2], ['resource-2', 3], ['resource-3', 7])
132
- cs.add_by_group('group-2', ['resource-1', 2], ['resource-3', 3], ['resource-4', 5])
133
- cs.calculate_similarity
110
+ @cs.add_by_group('group-1', ['resource-1', 2], ['resource-2', 3], ['resource-3', 7])
111
+ @cs.add_by_group('group-2', ['resource-1', 2], ['resource-3', 3], ['resource-4', 5])
112
+ @cs.calculate_similarity
134
113
  expected = [
135
114
  {resource: 'resource-3', similarity: 1.0},
136
115
  {resource: 'resource-4', similarity: 0.778},
137
116
  {resource: 'resource-2', similarity: 0.714}
138
117
  ]
139
- assert_equal expected, cs.similar_to('resource-1')
118
+ assert_equal expected, @cs.similar_to('resource-1')
140
119
  end
141
120
 
142
121
  def test_recommendations_are_isolated_by_key_base
@@ -148,16 +127,12 @@ module Commendo
148
127
  end
149
128
 
150
129
  def test_calculates_similarity_scores
151
- redis = Redis.new(db: 15)
152
- redis.flushdb
153
- key_base = 'CommendoTests'
154
- cs = ContentSet.new(redis, key_base)
155
130
  (3..23).each do |group|
156
131
  (3..23).each do |res|
157
- cs.add_by_group(group, res) if res % group == 0
132
+ @cs.add_by_group(group, res) if res % group == 0
158
133
  end
159
134
  end
160
- cs.calculate_similarity
135
+ @cs.calculate_similarity
161
136
  expected = [
162
137
  {resource: '9', similarity: 0.667},
163
138
  {resource: '6', similarity: 0.667},
@@ -166,108 +141,124 @@ module Commendo
166
141
  {resource: '21', similarity: 0.286},
167
142
  {resource: '15', similarity: 0.286}
168
143
  ]
169
- assert_equal expected, cs.similar_to(18)
144
+ assert_equal expected, @cs.similar_to(18)
170
145
  end
171
146
 
172
147
  def test_calculates_with_threshold
173
- redis = Redis.new(db: 15)
174
- redis.flushdb
175
- key_base = 'CommendoTests'
176
- cs = ContentSet.new(redis, key_base)
177
148
  (3..23).each do |group|
178
149
  (3..23).each do |res|
179
- cs.add_by_group(group, res) if res % group == 0
150
+ @cs.add_by_group(group, res) if res % group == 0
180
151
  end
181
152
  end
182
- cs.calculate_similarity(0.4)
153
+ @cs.calculate_similarity(0.4)
183
154
  expected = [
184
155
  {resource: '9', similarity: 0.667},
185
156
  {resource: '6', similarity: 0.667},
186
157
  {resource: '12', similarity: 0.5}
187
158
  ]
188
- assert_equal expected, cs.similar_to(18)
159
+ assert_equal expected, @cs.similar_to(18)
189
160
  end
190
161
 
191
162
  def test_calculate_yields_after_each
192
- redis = Redis.new(db: 15)
193
- redis.flushdb
194
- key_base = 'CommendoTests'
195
- cs = ContentSet.new(redis, key_base)
196
163
  (3..23).each do |group|
197
164
  (3..23).each do |res|
198
- cs.add_by_group(group, res) if res % group == 0
165
+ @cs.add_by_group(group, res) if res % group == 0
199
166
  end
200
167
  end
201
168
  expected_keys = ['CommendoTests:resources:3', 'CommendoTests:resources:4', 'CommendoTests:resources:5', 'CommendoTests:resources:6', 'CommendoTests:resources:7', 'CommendoTests:resources:8', 'CommendoTests:resources:9', 'CommendoTests:resources:10', 'CommendoTests:resources:11', 'CommendoTests:resources:12', 'CommendoTests:resources:13', 'CommendoTests:resources:14', 'CommendoTests:resources:15', 'CommendoTests:resources:16', 'CommendoTests:resources:17', 'CommendoTests:resources:18', 'CommendoTests:resources:19', 'CommendoTests:resources:20', 'CommendoTests:resources:21', 'CommendoTests:resources:22', 'CommendoTests:resources:23']
202
169
  actual_keys = []
203
- cs.calculate_similarity { |key, index, total|
170
+ @cs.calculate_similarity { |key, index, total|
204
171
  actual_keys << key
205
172
  }
206
173
  assert_equal expected_keys.sort, actual_keys.sort
207
174
  end
208
175
 
209
- def test_calculate_deletes_old_values_first
210
- skip
211
- end
212
-
213
176
  def test_deletes_resource_from_everywhere
214
- redis = Redis.new(db: 15)
215
- redis.flushdb
216
- key_base = 'CommendoTests'
217
- cs = ContentSet.new(redis, key_base)
218
177
  (3..23).each do |group|
219
178
  (3..23).each do |res|
220
- cs.add_by_group(group, res) if res % group == 0
179
+ @cs.add_by_group(group, res) if res % group == 0
221
180
  end
222
181
  end
223
- cs.calculate_similarity
224
- assert similar_to(cs, 18, 12)
182
+ @cs.calculate_similarity
183
+ assert similar_to(@cs, 18, 12)
184
+
185
+ @cs.delete(12)
186
+ assert_equal [], @cs.similar_to(12)
187
+ refute similar_to(@cs, 18, 12)
225
188
 
226
- cs.delete(12)
227
- assert_equal [], cs.similar_to(12)
228
- refute similar_to(cs, 18, 12)
189
+ @cs.calculate_similarity
190
+ assert_equal [], @cs.similar_to(12)
191
+ refute similar_to(@cs, 18, 12)
192
+ end
229
193
 
230
- cs.calculate_similarity
231
- assert_equal [], cs.similar_to(12)
232
- refute similar_to(cs, 18, 12)
194
+ def test_remove_from_groups
195
+ (3..23).each do |group|
196
+ (3..23).each do |res|
197
+ @cs.add(res, group) if res % group == 0
198
+ end
199
+ end
200
+ resource = 20
201
+ assert_equal ['4','5','10','20'].sort!, @cs.groups(resource).sort!
202
+ @cs.remove_from_groups(resource, 10)
203
+ assert_equal ['4','5','20'].sort!, @cs.groups(resource).sort!
204
+ @cs.remove_from_groups(resource, 4)
205
+ assert_equal ['5','20'].sort!, @cs.groups(resource).sort!
206
+ end
233
207
 
208
+ def test_remove_causes_similarity_to_change_when_recalculated
209
+ (3..23).each do |group|
210
+ (3..23).each do |res|
211
+ @cs.add(res, group) if res % group == 0
212
+ end
213
+ end
214
+ @cs.calculate_similarity
215
+ assert similar_to(@cs, 18, 12)
216
+ @cs.remove_from_groups(18, 6, 3)
217
+ @cs.calculate_similarity
218
+ refute similar_to(@cs, 18, 12)
234
219
  end
235
220
 
236
221
  def test_accepts_incremental_updates
237
- redis = Redis.new(db: 15)
238
- redis.flushdb
239
- key_base = 'CommendoTests'
240
- cs = ContentSet.new(redis, key_base)
241
222
  (3..23).each do |group|
242
223
  (3..23).each do |res|
243
- cs.add(res, group) if res % group == 0
224
+ @cs.add(res, group) if res % group == 0
244
225
  end
245
226
  end
246
- cs.calculate_similarity
247
- assert similar_to(cs, 18, 12)
248
- refute similar_to(cs, 10, 12)
227
+ @cs.calculate_similarity
228
+ assert similar_to(@cs, 18, 12)
229
+ refute similar_to(@cs, 10, 12)
230
+
231
+ @cs.add_and_calculate(12, 'foo', true)
232
+ @cs.add_and_calculate(10, 'foo', true)
233
+ assert similar_to(@cs, 10, 12)
234
+ end
249
235
 
250
- cs.add_and_calculate(12, 'foo', true)
251
- cs.add_and_calculate(10, 'foo', true)
252
- assert similar_to(cs, 10, 12)
236
+ def test_remove_and_calculate
237
+ (3..23).each do |group|
238
+ (3..23).each do |res|
239
+ @cs.add(res, group) if res % group == 0
240
+ end
241
+ end
242
+ @cs.calculate_similarity
243
+ assert similar_to(@cs, 18, 12)
244
+ @cs.remove_from_groups_and_calculate(18, 6, 3)
245
+ refute similar_to(@cs, 18, 12)
253
246
  end
254
247
 
255
248
  def test_filters_include_by_tag_collection
256
- redis = Redis.new(db: 15)
257
- redis.flushdb
258
- ts = TagSet.new(redis, 'CommendoTests:tags')
259
- cs = ContentSet.new(redis, 'CommendoTests', ts)
249
+ ts = TagSet.new(@redis, "#{@key_base}:tags")
250
+ @cs = ContentSet.new(@redis, @key_base, ts)
260
251
  (3..23).each do |group|
261
252
  (3..23).each do |res|
262
- cs.add(res, group) if res % group == 0
253
+ @cs.add(res, group) if res % group == 0
263
254
  ts.add(res, 'mod3') if res.modulo(3).zero?
264
255
  ts.add(res, 'mod4') if res.modulo(4).zero?
265
256
  ts.add(res, 'mod5') if res.modulo(5).zero?
266
257
  end
267
258
  end
268
- cs.calculate_similarity
259
+ @cs.calculate_similarity
269
260
 
270
- actual = cs.filtered_similar_to(10, include: ['mod5'])
261
+ actual = @cs.filtered_similar_to(10, include: ['mod5'])
271
262
  assert_equal 3, actual.length
272
263
  assert contains_resource('5', actual)
273
264
  assert contains_resource('15', actual)
@@ -276,21 +267,19 @@ module Commendo
276
267
  end
277
268
 
278
269
  def test_filters_include_by_tag_collection_and_limit
279
- redis = Redis.new(db: 15)
280
- redis.flushdb
281
- ts = TagSet.new(redis, 'CommendoTests:tags')
282
- cs = ContentSet.new(redis, 'CommendoTests', ts)
270
+ ts = TagSet.new(@redis, "#{@key_base}:tags")
271
+ @cs = ContentSet.new(@redis, @key_base, ts)
283
272
  (3..23).each do |group|
284
273
  (3..23).each do |res|
285
- cs.add(res, group) if res % group == 0
274
+ @cs.add(res, group) if res % group == 0
286
275
  ts.add(res, 'mod3') if res.modulo(3).zero?
287
276
  ts.add(res, 'mod4') if res.modulo(4).zero?
288
277
  ts.add(res, 'mod5') if res.modulo(5).zero?
289
278
  end
290
279
  end
291
- cs.calculate_similarity
280
+ @cs.calculate_similarity
292
281
 
293
- actual = cs.filtered_similar_to(10, include: ['mod5'], limit: 2)
282
+ actual = @cs.filtered_similar_to(10, include: ['mod5'], limit: 2)
294
283
  assert_equal 2, actual.length
295
284
  assert contains_resource('5', actual)
296
285
  #assert contains_resource('15', actual)
@@ -299,44 +288,40 @@ module Commendo
299
288
  end
300
289
 
301
290
  def test_filters_exclude_by_tag_collection
302
- redis = Redis.new(db: 15)
303
- redis.flushdb
304
- ts = TagSet.new(redis, 'CommendoTests:tags')
305
- cs = ContentSet.new(redis, 'CommendoTests', ts)
291
+ ts = TagSet.new(@redis, "#{@key_base}:tags")
292
+ @cs = ContentSet.new(@redis, @key_base, ts)
306
293
  (3..23).each do |group|
307
294
  (3..23).each do |res|
308
- cs.add(res, group) if res % group == 0
295
+ @cs.add(res, group) if res % group == 0
309
296
  ts.add(res, 'mod3') if res.modulo(3).zero?
310
297
  ts.add(res, 'mod4') if res.modulo(4).zero?
311
298
  ts.add(res, 'mod5') if res.modulo(5).zero?
312
299
  end
313
300
  end
314
- cs.calculate_similarity
301
+ @cs.calculate_similarity
315
302
 
316
- actual = cs.filtered_similar_to(10, exclude: ['mod3'])
303
+ actual = @cs.filtered_similar_to(10, exclude: ['mod3'])
317
304
  assert_equal 2, actual.length
318
305
  assert contains_resource('5', actual)
319
306
  assert contains_resource('20', actual)
320
307
  refute contains_resource('15', actual)
321
-
322
308
  end
323
309
 
324
310
  def test_filters_includes_and_exclude_by_tag_collection
325
- redis = Redis.new(db: 15)
326
- redis.flushdb
327
- ts = TagSet.new(redis, 'CommendoTests:tags')
328
- cs = ContentSet.new(redis, 'CommendoTests', ts)
311
+ ts = TagSet.new(@redis, "#{@key_base}:tags")
312
+ @cs = ContentSet.new(@redis, @key_base, ts)
313
+ #Build some test data
329
314
  (3..23).each do |group|
330
315
  (3..23).each do |res|
331
- cs.add(res, group) if res % group == 0
316
+ @cs.add(res, group) if res % group == 0
332
317
  ts.add(res, 'mod3') if res.modulo(3).zero?
333
318
  ts.add(res, 'mod4') if res.modulo(4).zero?
334
319
  ts.add(res, 'mod5') if res.modulo(5).zero?
335
320
  end
336
321
  end
337
- cs.calculate_similarity
322
+ @cs.calculate_similarity
338
323
 
339
- actual = cs.filtered_similar_to(12, include: ['mod4'], exclude: ['mod3', 'mod5'])
324
+ actual = @cs.filtered_similar_to(12, include: ['mod4'], exclude: ['mod3', 'mod5'])
340
325
  assert_equal 3, actual.length
341
326
 
342
327
  refute contains_resource('6', actual)
@@ -349,23 +334,20 @@ module Commendo
349
334
  assert contains_resource('16', actual)
350
335
  refute contains_resource('15', actual)
351
336
  refute contains_resource('20', actual)
352
-
353
337
  end
354
338
 
355
339
  def test_recommends_for_many
356
- redis = Redis.new(db: 15)
357
- redis.flushdb
358
- ts = TagSet.new(redis, 'CommendoTests:tags')
359
- cs = ContentSet.new(redis, 'CommendoTests', ts)
340
+ ts = TagSet.new(@redis, "#{@key_base}:tags")
341
+ @cs = ContentSet.new(@redis, @key_base, ts)
360
342
  (3..23).each do |group|
361
343
  (3..23).each do |res|
362
- cs.add(res, group) if res % group == 0
344
+ @cs.add(res, group) if res % group == 0
363
345
  ts.add(res, 'mod3') if res.modulo(3).zero?
364
346
  ts.add(res, 'mod4') if res.modulo(4).zero?
365
347
  ts.add(res, 'mod5') if res.modulo(5).zero?
366
348
  end
367
349
  end
368
- cs.calculate_similarity
350
+ @cs.calculate_similarity
369
351
  expected = [
370
352
  {resource: '18', similarity: 1.834},
371
353
  {resource: '3', similarity: 1.734},
@@ -379,26 +361,24 @@ module Commendo
379
361
  {resource: '16', similarity: 0.286},
380
362
  {resource: '20', similarity: 0.25}
381
363
  ]
382
- actual = cs.similar_to([12, 6, 9])
364
+ actual = @cs.similar_to([12, 6, 9])
383
365
  assert_equal expected, actual
384
366
  #, include: ['mod4'], exclude: ['mod3', 'mod5']
385
367
  end
386
368
 
387
369
  def test_recommends_for_many_applies_filters
388
- redis = Redis.new(db: 15)
389
- redis.flushdb
390
- ts = TagSet.new(redis, 'CommendoTests:tags')
391
- cs = ContentSet.new(redis, 'CommendoTests', ts)
370
+ ts = TagSet.new(@redis, "#{@key_base}:tags")
371
+ @cs = ContentSet.new(@redis, @key_base, ts)
392
372
  (3..23).each do |group|
393
373
  (3..23).each do |res|
394
- cs.add(res, group) if res % group == 0
374
+ @cs.add(res, group) if res % group == 0
395
375
  ts.add(res, 'mod3') if res.modulo(3).zero?
396
376
  ts.add(res, 'mod4') if res.modulo(4).zero?
397
377
  ts.add(res, 'mod5') if res.modulo(5).zero?
398
378
  end
399
379
  end
400
- cs.calculate_similarity
401
- actual = cs.filtered_similar_to([12, 6, 9], include: ['mod4'], exclude: ['mod3', 'mod5'])
380
+ @cs.calculate_similarity
381
+ actual = @cs.filtered_similar_to([12, 6, 9], include: ['mod4'], exclude: ['mod3', 'mod5'])
402
382
  refute contains_resource('6', actual)
403
383
  refute contains_resource('18', actual)
404
384
  assert contains_resource('4', actual)
@@ -416,7 +396,7 @@ module Commendo
416
396
  end
417
397
 
418
398
  def contains_resource(resource, similarities)
419
- similarities.select { |sim| sim[:resource] == "#{resource}" }.length > 0
399
+ !similarities.select { |sim| sim[:resource] == "#{resource}" }.empty?
420
400
  end
421
401
 
422
402
  end
data/test/tag_set_test.rb CHANGED
@@ -9,118 +9,112 @@ module Commendo
9
9
 
10
10
  class TagSetTest < Minitest::Test
11
11
 
12
+ def setup
13
+ @redis = Redis.new(db: 15)
14
+ @redis.flushdb
15
+ @ts = TagSet.new(@redis, 'TagSetTest')
16
+ end
17
+
12
18
  def test_adds_tags_for_resource
13
- redis = Redis.new(db: 15)
14
- redis.flushdb
15
- ts = TagSet.new(redis, 'TagSetTest')
16
- assert_equal [], ts.get(1)
17
- ts.add(1, 'foo', 'bar', 'baz')
18
- assert_equal ['bar', 'baz','foo'], ts.get(1)
19
- ts.add(1, 'qux', 'qip')
20
- assert_equal ['bar', 'baz', 'foo', 'qip', 'qux'], ts.get(1)
19
+ assert_equal [], @ts.get(1)
20
+ @ts.add(1, 'foo', 'bar', 'baz')
21
+ assert_equal ['bar', 'baz','foo'], @ts.get(1)
22
+ @ts.add(1, 'qux', 'qip')
23
+ assert_equal ['bar', 'baz', 'foo', 'qip', 'qux'], @ts.get(1)
24
+ end
25
+
26
+ def test_empty?
27
+ assert @ts.respond_to? :empty?
28
+ assert @ts.empty?
29
+ @ts.add(1, 'qux', 'qip')
30
+ refute @ts.empty?
31
+ @ts.delete(1)
32
+ assert @ts.empty?
21
33
  end
22
34
 
23
35
  def test_sets_tags_for_resource
24
- redis = Redis.new(db: 15)
25
- redis.flushdb
26
- ts = TagSet.new(redis, 'TagSetTest')
27
- assert_equal [], ts.get(1)
28
- ts.set(1, 'foo', 'bar', 'baz')
29
- assert_equal ['bar', 'baz', 'foo'], ts.get(1)
30
- ts.set(1, 'qux', 'qip')
31
- assert_equal ['qip', 'qux'], ts.get(1)
36
+ assert_equal [], @ts.get(1)
37
+ @ts.set(1, 'foo', 'bar', 'baz')
38
+ assert_equal ['bar', 'baz', 'foo'], @ts.get(1)
39
+ @ts.set(1, 'qux', 'qip')
40
+ assert_equal ['qip', 'qux'], @ts.get(1)
32
41
  end
33
42
 
34
43
  def test_sets_tags_when_empty
35
- redis = Redis.new(db: 15)
36
- redis.flushdb
37
- ts = TagSet.new(redis, 'TagSetTest')
38
- ts.set(1, 'foo', 'bar', 'baz')
39
- ts.set(2, 'qux', 'qip')
40
- assert_equal ['bar', 'baz', 'foo'], ts.get(1)
41
- assert_equal ['qip', 'qux'], ts.get(2)
42
- ts.set(1, *[])
43
- assert_equal [], ts.get(1)
44
- assert_equal ['qip', 'qux'], ts.get(2)
44
+ @ts.set(1, 'foo', 'bar', 'baz')
45
+ @ts.set(2, 'qux', 'qip')
46
+ assert_equal ['bar', 'baz', 'foo'], @ts.get(1)
47
+ assert_equal ['qip', 'qux'], @ts.get(2)
48
+ @ts.set(1, *[])
49
+ assert_equal [], @ts.get(1)
50
+ assert_equal ['qip', 'qux'], @ts.get(2)
45
51
  end
46
52
 
47
53
  def test_deletes_tags_for_resource
48
- redis = Redis.new(db: 15)
49
- redis.flushdb
50
- ts = TagSet.new(redis, 'TagSetTest')
51
- ts.set(1, 'foo', 'bar', 'baz')
52
- ts.set(2, 'qux', 'qip')
53
- assert_equal ['bar', 'baz', 'foo'], ts.get(1)
54
- assert_equal ['qip', 'qux'], ts.get(2)
55
- ts.delete(1)
56
- assert_equal [], ts.get(1)
57
- assert_equal ['qip', 'qux'], ts.get(2)
54
+ @ts.set(1, 'foo', 'bar', 'baz')
55
+ @ts.set(2, 'qux', 'qip')
56
+ assert_equal ['bar', 'baz', 'foo'], @ts.get(1)
57
+ assert_equal ['qip', 'qux'], @ts.get(2)
58
+ @ts.delete(1)
59
+ assert_equal [], @ts.get(1)
60
+ assert_equal ['qip', 'qux'], @ts.get(2)
58
61
  end
59
62
 
60
63
  def test_matches_tags
61
- redis = Redis.new(db: 15)
62
- redis.flushdb
63
- ts = TagSet.new(redis, 'TagSetTest')
64
- ts.set(1, 'foo', 'bar', 'baz')
65
- ts.set(2, 'qux', 'qip')
66
-
67
- assert ts.matches(1, ['foo'])
68
- assert ts.matches(1, ['bar', 'baz'])
69
- assert ts.matches(1, ['bar', 'baz', 'foo'])
70
- refute ts.matches(1, ['qux'])
71
- refute ts.matches(1, ['qip'])
72
-
73
- refute ts.matches(2, ['foo'])
74
- refute ts.matches(2, ['bar', 'baz'])
75
- refute ts.matches(2, ['bar', 'baz', 'foo'])
76
- assert ts.matches(2, ['qux', 'qip'])
77
- assert ts.matches(2, ['qux'])
78
- assert ts.matches(2, ['qip'])
64
+ @ts.set(1, 'foo', 'bar', 'baz')
65
+ @ts.set(2, 'qux', 'qip')
66
+
67
+ assert @ts.matches(1, ['foo'])
68
+ assert @ts.matches(1, ['bar', 'baz'])
69
+ assert @ts.matches(1, ['bar', 'baz', 'foo'])
70
+ refute @ts.matches(1, ['qux'])
71
+ refute @ts.matches(1, ['qip'])
72
+
73
+ refute @ts.matches(2, ['foo'])
74
+ refute @ts.matches(2, ['bar', 'baz'])
75
+ refute @ts.matches(2, ['bar', 'baz', 'foo'])
76
+ assert @ts.matches(2, ['qux', 'qip'])
77
+ assert @ts.matches(2, ['qux'])
78
+ assert @ts.matches(2, ['qip'])
79
79
  end
80
80
 
81
81
  def test_matches_exclude_tags
82
- redis = Redis.new(db: 15)
83
- redis.flushdb
84
- ts = TagSet.new(redis, 'TagSetTest')
85
- ts.set(1, 'foo', 'bar', 'baz')
86
- ts.set(2, 'qux', 'qip')
87
-
88
- refute ts.matches(1, nil, ['foo'])
89
- refute ts.matches(1, [], ['foo'])
90
- refute ts.matches(1, [], ['bar', 'baz'])
91
- refute ts.matches(1, [], ['bar', 'baz', 'foo'])
92
- assert ts.matches(1, [], ['qux'])
93
- assert ts.matches(1, [], ['qip'])
94
-
95
- assert ts.matches(2, nil, ['foo'])
96
- assert ts.matches(2, [], ['foo'])
97
- assert ts.matches(2, [], ['bar', 'baz'])
98
- assert ts.matches(2, [], ['bar', 'baz', 'foo'])
99
- refute ts.matches(2, [], ['qux', 'qip'])
100
- refute ts.matches(2, [], ['qux'])
101
- refute ts.matches(2, [], ['qip'])
82
+ @ts.set(1, 'foo', 'bar', 'baz')
83
+ @ts.set(2, 'qux', 'qip')
84
+
85
+ refute @ts.matches(1, nil, ['foo'])
86
+ refute @ts.matches(1, [], ['foo'])
87
+ refute @ts.matches(1, [], ['bar', 'baz'])
88
+ refute @ts.matches(1, [], ['bar', 'baz', 'foo'])
89
+ assert @ts.matches(1, [], ['qux'])
90
+ assert @ts.matches(1, [], ['qip'])
91
+
92
+ assert @ts.matches(2, nil, ['foo'])
93
+ assert @ts.matches(2, [], ['foo'])
94
+ assert @ts.matches(2, [], ['bar', 'baz'])
95
+ assert @ts.matches(2, [], ['bar', 'baz', 'foo'])
96
+ refute @ts.matches(2, [], ['qux', 'qip'])
97
+ refute @ts.matches(2, [], ['qux'])
98
+ refute @ts.matches(2, [], ['qip'])
102
99
  end
103
100
 
104
101
  def test_matches_include_and_exclude_tags
105
- redis = Redis.new(db: 15)
106
- redis.flushdb
107
- ts = TagSet.new(redis, 'TagSetTest')
108
- ts.set(1, 'foo', 'bar', 'baz')
109
- ts.set(2, 'qux', 'qip')
110
-
111
- refute ts.matches(1, ['foo'], ['bar'])
112
- refute ts.matches(1, ['bar'], ['foo'])
113
-
114
- assert ts.matches(1, ['foo'], [])
115
- assert ts.matches(1, ['foo'], nil)
116
- assert ts.matches(1, ['foo'], ['qux'])
117
-
118
- assert ts.matches(2, ['qip'], ['foo'])
119
- assert ts.matches(2, ['qux'], ['bar', 'baz'])
120
- assert ts.matches(2, ['qip'], ['bar', 'baz', 'foo'])
121
- refute ts.matches(2, ['qip'], ['qux', 'qip'])
122
- refute ts.matches(2, ['qip'], ['qux'])
123
- refute ts.matches(2, ['qux'], ['qip'])
102
+ @ts.set(1, 'foo', 'bar', 'baz')
103
+ @ts.set(2, 'qux', 'qip')
104
+
105
+ refute @ts.matches(1, ['foo'], ['bar'])
106
+ refute @ts.matches(1, ['bar'], ['foo'])
107
+
108
+ assert @ts.matches(1, ['foo'], [])
109
+ assert @ts.matches(1, ['foo'], nil)
110
+ assert @ts.matches(1, ['foo'], ['qux'])
111
+
112
+ assert @ts.matches(2, ['qip'], ['foo'])
113
+ assert @ts.matches(2, ['qux'], ['bar', 'baz'])
114
+ assert @ts.matches(2, ['qip'], ['bar', 'baz', 'foo'])
115
+ refute @ts.matches(2, ['qip'], ['qux', 'qip'])
116
+ refute @ts.matches(2, ['qip'], ['qux'])
117
+ refute @ts.matches(2, ['qux'], ['qip'])
124
118
  end
125
119
 
126
120
  end
metadata CHANGED
@@ -1,111 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: commendo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Styles
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-22 00:00:00.000000000 Z
11
+ date: 2015-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: progressbar
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.5'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.5'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: mocha
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: yard
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: minitest
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ~>
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
103
  version: 5.0.8
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ~>
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: 5.0.8
111
111
  description: A Jaccard-similarity recommender using Redis sets
@@ -119,7 +119,7 @@ executables:
119
119
  extensions: []
120
120
  extra_rdoc_files: []
121
121
  files:
122
- - .gitignore
122
+ - ".gitignore"
123
123
  - CHANGELOG.md
124
124
  - Gemfile
125
125
  - LICENSE.txt
@@ -150,17 +150,17 @@ require_paths:
150
150
  - lib
151
151
  required_ruby_version: !ruby/object:Gem::Requirement
152
152
  requirements:
153
- - - '>='
153
+ - - ">="
154
154
  - !ruby/object:Gem::Version
155
155
  version: '0'
156
156
  required_rubygems_version: !ruby/object:Gem::Requirement
157
157
  requirements:
158
- - - '>='
158
+ - - ">="
159
159
  - !ruby/object:Gem::Version
160
160
  version: '0'
161
161
  requirements: []
162
162
  rubyforge_project:
163
- rubygems_version: 2.2.0
163
+ rubygems_version: 2.2.2
164
164
  signing_key:
165
165
  specification_version: 4
166
166
  summary: A Jaccard-similarity recommender using Redis sets