qfill 0.0.3 → 0.1.1

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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.github/dependabot.yml +8 -0
  3. data/.github/workflows/style.yml +37 -0
  4. data/.github/workflows/test.yml +55 -0
  5. data/.rspec +3 -2
  6. data/.rubocop.yml +26 -0
  7. data/.rubocop_todo.yml +163 -0
  8. data/.simplecov +6 -0
  9. data/CODE_OF_CONDUCT.md +133 -0
  10. data/Gemfile +31 -0
  11. data/Guardfile +12 -0
  12. data/{LICENSE.txt → LICENSE} +1 -1
  13. data/README.md +2 -2
  14. data/Rakefile +24 -1
  15. data/lib/qfill/errors/invalid_index.rb +8 -0
  16. data/lib/qfill/filter.rb +5 -3
  17. data/lib/qfill/list.rb +4 -2
  18. data/lib/qfill/list_set.rb +17 -7
  19. data/lib/qfill/manager.rb +90 -61
  20. data/lib/qfill/origin.rb +4 -3
  21. data/lib/qfill/popper.rb +31 -26
  22. data/lib/qfill/pusher.rb +34 -23
  23. data/lib/qfill/result.rb +78 -40
  24. data/lib/qfill/strategy/base.rb +65 -0
  25. data/lib/qfill/strategy/drain_to_empty.rb +73 -0
  26. data/lib/qfill/strategy/drain_to_limit.rb +46 -0
  27. data/lib/qfill/strategy/sample.rb +42 -0
  28. data/lib/qfill/strategy/time_slice.rb +105 -0
  29. data/lib/qfill/strategy.rb +13 -0
  30. data/lib/qfill/version.rb +3 -1
  31. data/lib/qfill.rb +13 -10
  32. data/maintenance-branch +1 -0
  33. data/qfill.gemspec +15 -13
  34. data/spec/qfill/filter_spec.rb +35 -26
  35. data/spec/qfill/list_set_spec.rb +28 -23
  36. data/spec/qfill/list_spec.rb +35 -27
  37. data/spec/qfill/manager_spec.rb +715 -284
  38. data/spec/qfill/origin_spec.rb +45 -35
  39. data/spec/qfill/popper_spec.rb +36 -30
  40. data/spec/qfill/pusher_spec.rb +32 -26
  41. data/spec/qfill/result_spec.rb +49 -38
  42. data/spec/qfill_spec.rb +6 -5
  43. data/spec/spec_helper.rb +11 -37
  44. data/spec/support/helper.rb +13 -0
  45. data/spec/support/random_object.rb +30 -0
  46. metadata +52 -23
@@ -1,416 +1,847 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
  describe Qfill::Manager do
3
- context "#new" do
4
- context "with no arguments" do
5
- it "should raise ArgumentError" do
6
- expect { Qfill::Manager.new() }.to raise_error(ArgumentError)
5
+ let(:manager) { described_class.new(arguments) }
6
+
7
+ describe '#new' do
8
+ context 'with no arguments' do
9
+ it 'raises ArgumentError' do
10
+ expect { described_class.new }.to raise_error(ArgumentError)
7
11
  end
8
12
  end
9
- context "with only popper" do
10
- it "should raise ArgumentError" do
11
- popper = Qfill::Popper.from_array_of_hashes(
12
- [{ :name => "High List",
13
- :elements => [1,2,3]}] )
14
- expect { Qfill::Manager.new(:popper => popper) }.to raise_error(ArgumentError)
13
+
14
+ context 'with only popper' do
15
+ let(:popper) do
16
+ Qfill::Popper.from_array_of_hashes(
17
+ [{ name: 'High List',
18
+ elements: [1, 2, 3] }]
19
+ )
20
+ end
21
+
22
+ it 'raises ArgumentError' do
23
+ expect { described_class.new(popper: popper) }.to raise_error(ArgumentError)
15
24
  end
16
25
  end
17
- context "with only pusher" do
18
- it "should raise ArgumentError" do
19
- pusher = Qfill::Pusher.from_array_of_hashes(
20
- [{ :name => "Some Result",
21
- :ratio => 0.25 }] )
22
- expect { Qfill::Manager.new(:pusher => pusher) }.to raise_error(ArgumentError)
26
+
27
+ context 'with only pusher' do
28
+ let(:pusher) do
29
+ Qfill::Pusher.from_array_of_hashes(
30
+ [{ name: 'Some Result',
31
+ ratio: 0.25 }]
32
+ )
33
+ end
34
+
35
+ it 'raises ArgumentError' do
36
+ expect { described_class.new(pusher: pusher) }.to raise_error(ArgumentError)
23
37
  end
24
38
  end
25
- context "with popper and pusher" do
26
- before :each do
27
- @popper = Qfill::Popper.from_array_of_hashes(
28
- [{ :name => "High List",
29
- :elements => [1,2,3]}] )
30
- @pusher = Qfill::Pusher.from_array_of_hashes(
31
- [{ :name => "Some Result",
32
- :ratio => 0.25 }] )
33
- @arguments = {
34
- :pusher => @pusher,
35
- :popper => @popper
39
+
40
+ context 'with popper and pusher' do
41
+ let(:popper) do
42
+ Qfill::Popper.from_array_of_hashes(
43
+ [{ name: 'High List',
44
+ elements: [1, 2, 3] }]
45
+ )
46
+ end
47
+ let(:pusher) do
48
+ Qfill::Pusher.from_array_of_hashes(
49
+ [{ name: 'Some Result',
50
+ ratio: 0.25 }]
51
+ )
52
+ end
53
+ let(:arguments) do
54
+ {
55
+ pusher: pusher,
56
+ popper: popper
36
57
  }
37
58
  end
38
- it "should not raise any errors" do
39
- expect { Qfill::Manager.new(@arguments) }.to_not raise_error
59
+
60
+ it 'does not raise any errors' do
61
+ expect { described_class.new(arguments) }.not_to raise_error
40
62
  end
41
- it "should instantiate with pusher" do
42
- Qfill::Manager.new(@arguments).pusher.should == @pusher
63
+
64
+ it 'instantiates with pusher' do
65
+ expect(described_class.new(arguments).pusher).to eq(pusher)
43
66
  end
44
- it "should instantiate with popper" do
45
- Qfill::Manager.new(@arguments).popper.should == @popper
67
+
68
+ it 'instantiates with popper' do
69
+ expect(described_class.new(arguments).popper).to eq(popper)
46
70
  end
47
71
  end
48
- context "with popper and pusher and all_list_max smaller than # total elements" do
49
- before :each do
50
- @popper = Qfill::Popper.from_array_of_hashes(
51
- [{ :name => "High List",
52
- :elements => [1,2,3]}] )
53
- @pusher = Qfill::Pusher.from_array_of_hashes(
54
- [{ :name => "Some Result",
55
- :ratio => 0.25 }] )
56
- @arguments = {
57
- :pusher => @pusher,
58
- :popper => @popper,
59
- :all_list_max => 2
72
+
73
+ context 'with popper and pusher and all_list_max smaller than # total elements' do
74
+ let(:popper) do
75
+ Qfill::Popper.from_array_of_hashes(
76
+ [{ name: 'High List',
77
+ elements: [1, 2, 3] }]
78
+ )
79
+ end
80
+ let(:pusher) do
81
+ Qfill::Pusher.from_array_of_hashes(
82
+ [{ name: 'Some Result',
83
+ ratio: 0.25 }]
84
+ )
85
+ end
86
+ let(:arguments) do
87
+ {
88
+ pusher: pusher,
89
+ popper: popper,
90
+ all_list_max: 2
60
91
  }
61
92
  end
62
- it "should not raise any errors" do
63
- expect { Qfill::Manager.new(@arguments) }.to_not raise_error
93
+
94
+ it 'does not raise any errors' do
95
+ expect { described_class.new(arguments) }.not_to raise_error
64
96
  end
65
- it "should instantiate with pusher" do
66
- Qfill::Manager.new(@arguments).pusher.should == @pusher
97
+
98
+ it 'instantiates with pusher' do
99
+ expect(described_class.new(arguments).pusher).to eq(pusher)
67
100
  end
68
- it "should instantiate with popper" do
69
- Qfill::Manager.new(@arguments).popper.should == @popper
101
+
102
+ it 'instantiates with popper' do
103
+ expect(described_class.new(arguments).popper).to eq(popper)
70
104
  end
71
- it "should instantiate with all_list_max" do
72
- Qfill::Manager.new(@arguments).all_list_max.should == 2
105
+
106
+ it 'retains specified all_list_max' do
107
+ expect(described_class.new(arguments).all_list_max).to eq(2)
73
108
  end
74
109
  end
75
- context "all_list_max greater than # total elements" do
76
- before :each do
77
- @popper = Qfill::Popper.from_array_of_hashes(
78
- [{ :name => "High List",
79
- :elements => [1,2,3]}] )
80
- @pusher = Qfill::Pusher.from_array_of_hashes(
81
- [{ :name => "Some Result",
82
- :ratio => 0.25 }] )
83
- @arguments = {
84
- :pusher => @pusher,
85
- :popper => @popper,
86
- :all_list_max => 666
110
+
111
+ context 'all_list_max greater than # total elements' do
112
+ let(:popper) do
113
+ Qfill::Popper.from_array_of_hashes(
114
+ [{ name: 'High List',
115
+ elements: [1, 2, 3] }]
116
+ )
117
+ end
118
+ let(:pusher) do
119
+ Qfill::Pusher.from_array_of_hashes(
120
+ [{ name: 'Some Result',
121
+ ratio: 0.25 }]
122
+ )
123
+ end
124
+ let(:arguments) do
125
+ {
126
+ pusher: pusher,
127
+ popper: popper,
128
+ all_list_max: 666
87
129
  }
88
130
  end
89
- it "should instantiate with all_list_max" do
90
- Qfill::Manager.new(@arguments).all_list_max.should == 3
131
+
132
+ it 'reduces all_list_max to number of elements' do
133
+ expect(described_class.new(arguments).all_list_max).to eq(3)
91
134
  end
92
135
  end
93
136
  end
94
- context "strategy => :sample" do
95
- context "backfill => false" do
96
- before :each do
97
- @popper = Qfill::Popper.from_array_of_hashes(
137
+
138
+ context 'when strategy => :sample' do
139
+ context 'when backfill => false' do
140
+ let(:popper) do
141
+ Qfill::Popper.from_array_of_hashes(
98
142
  # We will create 4 queues, high, medium, low, and none.
99
143
  # These might be queue of things that have ratings, and the none queue for things which have not yet been rated.
100
144
  # The backfill route of the queues then, assuming we want people to rate the things that are not yet rated,
101
145
  # but not at the expense of hte experience, would be:
102
146
  # high => medium => none => low
103
- [{:name => 'high',
104
- :elements => %w( h1 h2 h3 h4 h5 h6 h7 h8 h9 ),
105
- :backfill => 'medium'},
106
- {:name => "medium",
107
- :elements => %w( m1 m2 m3 m4 m5 m6 m7 m8 m9 ),
108
- :backfill => 'none'},
109
- {:name => 'low',
110
- :elements => %w( l1 l2 l3 l4 l5 l6 l7 l8 l9 ),
111
- :backfill => false},
112
- {:name => 'none',
113
- :elements => %w( n1 n2 n3 n4 n5 n6 n7 n8 n9 ),
114
- :backfill => 'low' }] )
115
- @pusher = Qfill::Pusher.from_array_of_hashes(
116
- [{ :name => "first",
117
- :list_ratios => {
147
+ [{ name: 'high',
148
+ elements: %w[h1 h2 h3 h4 h5 h6 h7 h8 h9],
149
+ backfill: 'medium' },
150
+ { name: 'medium',
151
+ elements: %w[m1 m2 m3 m4 m5 m6 m7 m8 m9],
152
+ backfill: 'none' },
153
+ { name: 'low',
154
+ elements: %w[l1 l2 l3 l4 l5 l6 l7 l8 l9],
155
+ backfill: false },
156
+ { name: 'none',
157
+ elements: %w[n1 n2 n3 n4 n5 n6 n7 n8 n9],
158
+ backfill: 'low' }]
159
+ )
160
+ end
161
+ let(:pusher) do
162
+ Qfill::Pusher.from_array_of_hashes(
163
+ [{ name: 'first',
164
+ list_ratios: {
118
165
  'high' => 0.5,
119
166
  'medium' => 0.1,
120
167
  'none' => 0.4
121
168
  },
122
- :ratio => 0.25 },
123
- { :name => "second",
124
- :ratio => 0.50 },
125
- { :name => "third",
126
- :ratio => 0.25 }] )
127
- @arguments = {
128
- :pusher => @pusher,
129
- :popper => @popper,
130
- :all_list_max => 40,
131
- :strategy => :sample
169
+ ratio: 0.25 },
170
+ { name: 'second',
171
+ ratio: 0.50 },
172
+ { name: 'third',
173
+ ratio: 0.25 }]
174
+ )
175
+ end
176
+ let(:arguments) do
177
+ {
178
+ pusher: pusher,
179
+ popper: popper,
180
+ all_list_max: 40,
181
+ strategy: :sample
132
182
  }
133
183
  end
134
- context "#new" do
135
- it "should not raise any errors" do
136
- expect { Qfill::Manager.new(@arguments) }.to_not raise_error
184
+
185
+ describe '#new' do
186
+ it 'does not raise any errors' do
187
+ expect { described_class.new(arguments) }.not_to raise_error
137
188
  end
138
189
  end
139
- context "#fill!" do
140
- it "should instantiate with pusher" do
141
- expect { Qfill::Manager.new(@arguments).fill! }.to_not raise_error
190
+
191
+ describe '#fill!' do
192
+ it 'instantiates with pusher' do
193
+ expect { described_class.new(arguments).fill! }.not_to raise_error
142
194
  end
143
195
  end
144
- context "results" do
145
- before(:each) do
146
- @manager = Qfill::Manager.new(@arguments)
147
- end
148
- context "before fill!" do
149
- it "should calculate the correct popper total elements" do
150
- @manager.popper.get_total_elements.should == 36
196
+
197
+ context 'results' do
198
+ context 'before fill!' do
199
+ it 'calculates the correct popper total elements' do
200
+ expect(manager.popper.count_all_elements).to eq(36)
151
201
  end
152
- it "should calculate the correct popper primary elements" do
153
- @manager.popper.get_primary_elements == 36
202
+
203
+ it 'calculates the correct popper primary elements' do
204
+ expect(manager.popper.count_primary_elements).to eq(36)
154
205
  end
155
- it "should calculate the correct pusher total elements" do
156
- @manager.pusher.get_total_elements.should == 0
206
+
207
+ it 'calculates the correct pusher total elements' do
208
+ expect(manager.pusher.count_all_elements).to eq(0)
157
209
  end
158
210
  end
159
- context "after fill!" do
160
- before(:each) do
161
- @manager.fill!
211
+
212
+ context 'after fill!' do
213
+ before do
214
+ manager.fill!
162
215
  end
163
- it "should calculate the correct popper total elements" do
164
- @manager.popper.get_total_elements.should == 0
216
+
217
+ it 'calculates the correct popper total elements' do
218
+ expect(manager.popper.count_all_elements).to eq(0)
165
219
  end
166
- it "should calculate the correct popper primary elements" do
167
- @manager.popper.get_primary_elements == 0
220
+
221
+ it 'calculates the correct popper primary elements' do
222
+ expect(manager.popper.count_primary_elements).to eq(0)
168
223
  end
169
- it "should calculate the correct pusher total elements" do
170
- @manager.pusher.get_total_elements.should == 36
224
+
225
+ it 'calculates the correct pusher total elements' do
226
+ expect(manager.pusher.count_all_elements).to eq(36)
171
227
  end
172
228
  end
173
229
  end
174
230
  end
175
- context "backfill => true" do
176
- before :each do
177
- @popper = Qfill::Popper.from_array_of_hashes(
231
+
232
+ context 'when backfill => true' do
233
+ let(:popper) do
234
+ Qfill::Popper.from_array_of_hashes(
178
235
  # We will create 4 queues, high, medium, low, and none.
179
236
  # These might be queue of things that have ratings, and the none queue for things which have not yet been rated.
180
237
  # The backfill route of the queues then, assuming we want people to rate the things that are not yet rated,
181
238
  # but not at the expense of hte experience, would be:
182
239
  # high => medium => none => low
183
- [{:name => 'high',
184
- :elements => %w( h1 h2 h3 h4 h5 h6 h7 h8 h9 ),
185
- :backfill => 'medium'},
186
- {:name => "medium",
187
- :elements => %w( m1 m2 m3 m4 m5 m6 m7 m8 m9 ),
188
- :backfill => 'none'},
189
- {:name => 'low',
190
- :elements => %w( l1 l2 l3 l4 l5 l6 l7 l8 l9 ),
191
- :backfill => true},
192
- {:name => 'none',
193
- :elements => %w( n1 n2 n3 n4 n5 n6 n7 n8 n9 ),
194
- :backfill => 'low' }] )
195
- @pusher = Qfill::Pusher.from_array_of_hashes(
196
- [{ :name => "first",
197
- :list_ratios => {
240
+ [{ name: 'high',
241
+ elements: %w[h1 h2 h3 h4 h5 h6 h7 h8 h9],
242
+ backfill: 'medium' },
243
+ { name: 'medium',
244
+ elements: %w[m1 m2 m3 m4 m5 m6 m7 m8 m9],
245
+ backfill: 'none' },
246
+ { name: 'low',
247
+ elements: %w[l1 l2 l3 l4 l5 l6 l7 l8 l9],
248
+ backfill: true },
249
+ { name: 'none',
250
+ elements: %w[n1 n2 n3 n4 n5 n6 n7 n8 n9],
251
+ backfill: 'low' }]
252
+ )
253
+ end
254
+ let(:pusher) do
255
+ Qfill::Pusher.from_array_of_hashes(
256
+ [{ name: 'first',
257
+ list_ratios: {
198
258
  'high' => 0.5,
199
259
  'medium' => 0.1,
200
260
  'none' => 0.4
201
261
  },
202
- :ratio => 0.25 },
203
- { :name => "second",
204
- :ratio => 0.50 },
205
- { :name => "third",
206
- :ratio => 0.25 }] )
207
- @arguments = {
208
- :pusher => @pusher,
209
- :popper => @popper,
210
- :all_list_max => 40,
211
- :strategy => :sample
262
+ ratio: 0.25 },
263
+ { name: 'second',
264
+ ratio: 0.50 },
265
+ { name: 'third',
266
+ ratio: 0.25 }]
267
+ )
268
+ end
269
+ let(:arguments) do
270
+ {
271
+ pusher: pusher,
272
+ popper: popper,
273
+ all_list_max: 28,
274
+ strategy: :sample
212
275
  }
213
276
  end
214
- context "#new" do
215
- it "should not raise any errors" do
216
- expect { Qfill::Manager.new(@arguments) }.to_not raise_error
277
+
278
+ describe '#new' do
279
+ it 'does not raise any errors' do
280
+ expect { described_class.new(arguments) }.not_to raise_error
217
281
  end
218
282
  end
219
- context "#fill!" do
220
- it "should instantiate with pusher" do
221
- expect { Qfill::Manager.new(@arguments).fill! }.to_not raise_error
283
+
284
+ describe '#fill!' do
285
+ it 'instantiates with pusher' do
286
+ expect { described_class.new(arguments).fill! }.not_to raise_error
222
287
  end
223
288
  end
224
- context "results" do
225
- before(:each) do
226
- @manager = Qfill::Manager.new(@arguments)
227
- end
228
- context "before fill!" do
229
- it "should calculate the correct popper total elements" do
230
- @manager.popper.get_total_elements.should == 36
289
+
290
+ context 'results' do
291
+ context 'before fill!' do
292
+ it 'calculates the correct popper total elements' do
293
+ expect(manager.popper.count_all_elements).to eq(36)
231
294
  end
232
- it "should calculate the correct popper primary elements" do
233
- @manager.popper.get_primary_elements == 27
295
+
296
+ it 'calculates the correct popper primary elements' do
297
+ expect(manager.popper.count_primary_elements).to eq(27)
234
298
  end
235
- it "should calculate the correct pusher total elements" do
236
- @manager.pusher.get_total_elements.should == 0
299
+
300
+ it 'calculates the correct pusher total elements' do
301
+ expect(manager.pusher.count_all_elements).to eq(0)
237
302
  end
238
303
  end
239
- context "after fill!" do
240
- before(:each) do
241
- @manager.fill!
304
+
305
+ context 'after fill!' do
306
+ before do
307
+ manager.fill!
242
308
  end
243
- it "should calculate the correct popper total elements" do
244
- @manager.popper.get_total_elements.should == 9
309
+
310
+ it 'calculates the correct popper total elements' do
311
+ expect(manager.popper.count_all_elements).to eq(8)
245
312
  end
246
- it "should calculate the correct popper primary elements" do
247
- @manager.popper.get_primary_elements == 0
313
+
314
+ it 'calculates the correct popper primary elements' do
315
+ expect(manager.popper.count_primary_elements).to eq(0)
248
316
  end
249
- it "should calculate the correct pusher total elements" do
250
- @manager.pusher.get_total_elements.should == 27
317
+
318
+ it 'calculates the correct pusher total elements' do
319
+ expect(manager.pusher.count_all_elements).to eq(28)
251
320
  end
252
321
  end
253
322
  end
254
323
  end
255
324
  end
256
- context "strategy :drain" do
257
- context "backfill => false" do
258
- before :each do
259
- @popper = Qfill::Popper.from_array_of_hashes(
325
+
326
+ context 'when strategy => :drain_to_limit' do
327
+ context 'when backfill => false' do
328
+ let(:popper) do
329
+ Qfill::Popper.from_array_of_hashes(
260
330
  # We will create 4 queues, high, medium, low, and none.
261
331
  # These might be queue of things that have ratings, and the none queue for things which have not yet been rated.
262
332
  # The backfill route of the queues then, assuming we want people to rate the things that are not yet rated,
263
333
  # but not at the expense of hte experience, would be:
264
334
  # high => medium => none => low
265
- [{:name => 'high',
266
- :elements => %w( h1 h2 h3 h4 h5 h6 h7 h8 h9 ),
267
- :backfill => 'medium'},
268
- {:name => "medium",
269
- :elements => %w( m1 m2 m3 m4 m5 m6 m7 m8 m9 ),
270
- :backfill => 'none'},
271
- {:name => 'low',
272
- :elements => %w( l1 l2 l3 l4 l5 l6 l7 l8 l9 ),
273
- :backfill => false},
274
- {:name => 'none',
275
- :elements => %w( n1 n2 n3 n4 n5 n6 n7 n8 n9 ),
276
- :backfill => 'low' }] )
277
- @pusher = Qfill::Pusher.from_array_of_hashes(
278
- [{ :name => "first",
279
- :list_ratios => {
335
+ [{ name: 'high',
336
+ elements: %w[h1 h2 h3 h4 h5 h6 h7 h8 h9 h10 h11 h12],
337
+ backfill: 'medium' },
338
+ { name: 'medium',
339
+ elements: %w[m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12],
340
+ backfill: 'none' },
341
+ { name: 'low',
342
+ elements: %w[l1 l2 l3 l4 l5 l6 l7 l8 l9 l10 l11 l12],
343
+ backfill: false },
344
+ { name: 'none',
345
+ elements: %w[n1 n2 n3 n4 n5 n6 n7 n8 n9 n10 n11 n12],
346
+ backfill: 'low' }]
347
+ )
348
+ end
349
+ let(:pusher) do
350
+ Qfill::Pusher.from_array_of_hashes(
351
+ [{ name: 'first',
352
+ list_ratios: {
280
353
  'high' => 0.5,
281
354
  'medium' => 0.1,
282
355
  'none' => 0.4
283
356
  },
284
- :ratio => 0.25 },
285
- { :name => "second",
286
- :ratio => 0.50 },
287
- { :name => "third",
288
- :ratio => 0.25 }] )
289
- @arguments = {
290
- :pusher => @pusher,
291
- :popper => @popper,
292
- :all_list_max => 40,
293
- :strategy => :drain
357
+ ratio: 0.25 },
358
+ { name: 'second',
359
+ ratio: 0.50 },
360
+ { name: 'third',
361
+ ratio: 0.25 }]
362
+ )
363
+ end
364
+ let(:arguments) do
365
+ {
366
+ pusher: pusher,
367
+ popper: popper,
368
+ all_list_max: 40,
369
+ strategy: :drain_to_limit
294
370
  }
295
371
  end
296
- context "#new" do
297
- it "should not raise any errors" do
298
- expect { Qfill::Manager.new(@arguments) }.to_not raise_error
372
+
373
+ describe '#new' do
374
+ it 'does not raise any errors' do
375
+ expect { described_class.new(arguments) }.not_to raise_error
299
376
  end
300
377
  end
301
- context "#fill!" do
302
- it "should instantiate with pusher" do
303
- expect { Qfill::Manager.new(@arguments).fill! }.to_not raise_error
378
+
379
+ describe '#fill!' do
380
+ it 'instantiates with pusher' do
381
+ expect { described_class.new(arguments).fill! }.not_to raise_error
304
382
  end
305
383
  end
306
- context "results" do
307
- before(:each) do
308
- @manager = Qfill::Manager.new(@arguments)
309
- end
310
- context "before fill!" do
311
- it "should calculate the correct popper total elements" do
312
- @manager.popper.get_total_elements.should == 36
384
+
385
+ context 'results' do
386
+ context 'before fill!' do
387
+ it 'calculates the correct popper total elements' do
388
+ expect(manager.popper.count_all_elements).to eq(48)
313
389
  end
314
- it "should calculate the correct popper primary elements" do
315
- @manager.popper.get_primary_elements == 36
390
+
391
+ it 'calculates the correct popper primary elements' do
392
+ expect(manager.popper.count_primary_elements).to eq(48)
316
393
  end
317
- it "should calculate the correct pusher total elements" do
318
- @manager.pusher.get_total_elements.should == 0
394
+
395
+ it 'calculates the correct pusher total elements' do
396
+ expect(manager.pusher.count_all_elements).to eq(0)
319
397
  end
320
398
  end
321
- context "after fill!" do
322
- before(:each) do
323
- @manager.fill!
399
+
400
+ context 'after fill!' do
401
+ before do
402
+ manager.fill!
324
403
  end
325
- it "should calculate the correct popper total elements" do
326
- @manager.popper.get_total_elements.should == 0 # With drain the results do not exactly match the requested ratios.
404
+
405
+ it 'calculates the correct popper total elements' do
406
+ expect(manager.popper.count_all_elements).to eq(8) # With drain_to_limit the results do not exactly match the requested ratios.
327
407
  end
328
- it "should calculate the correct popper primary elements" do
329
- @manager.popper.get_primary_elements == 0
408
+
409
+ it 'calculates the correct popper primary elements' do
410
+ expect(manager.popper.count_primary_elements).to eq(8)
330
411
  end
331
- it "should calculate the correct pusher total elements" do
332
- @manager.pusher.get_total_elements.should == 36
412
+
413
+ it 'calculates the correct pusher total elements' do
414
+ expect(manager.pusher.count_all_elements).to eq(40)
333
415
  end
334
416
  end
335
417
  end
336
418
  end
337
- context "backfill => true" do
338
- before :each do
339
- @popper = Qfill::Popper.from_array_of_hashes(
419
+
420
+ context 'when backfill => true' do
421
+ let(:popper) do
422
+ Qfill::Popper.from_array_of_hashes(
340
423
  # We will create 4 queues, high, medium, low, and none.
341
424
  # These might be queue of things that have ratings, and the none queue for things which have not yet been rated.
342
425
  # The backfill route of the queues then, assuming we want people to rate the things that are not yet rated,
343
426
  # but not at the expense of hte experience, would be:
344
427
  # high => medium => none => low
345
- [{:name => 'high',
346
- :elements => %w( h1 h2 h3 h4 h5 h6 h7 h8 h9 ),
347
- :backfill => 'medium'},
348
- {:name => "medium",
349
- :elements => %w( m1 m2 m3 m4 m5 m6 m7 m8 m9 ),
350
- :backfill => 'none'},
351
- {:name => 'low',
352
- :elements => %w( l1 l2 l3 l4 l5 l6 l7 l8 l9 ),
353
- :backfill => true},
354
- {:name => 'none',
355
- :elements => %w( n1 n2 n3 n4 n5 n6 n7 n8 n9 ),
356
- :backfill => 'low' }] )
357
- @pusher = Qfill::Pusher.from_array_of_hashes(
358
- [{ :name => "first",
359
- :list_ratios => {
428
+ [{ name: 'high',
429
+ elements: %w[h1 h2 h3 h4 h5 h6 h7 h8 h9],
430
+ backfill: 'medium' },
431
+ { name: 'medium',
432
+ elements: %w[m1 m2 m3 m4 m5 m6 m7 m8 m9],
433
+ backfill: 'none' },
434
+ { name: 'low',
435
+ elements: %w[l1 l2 l3 l4 l5 l6 l7 l8 l9],
436
+ backfill: true },
437
+ { name: 'none',
438
+ elements: %w[n1 n2 n3 n4 n5 n6 n7 n8 n9],
439
+ backfill: 'low' }]
440
+ )
441
+ end
442
+ let(:pusher) do
443
+ Qfill::Pusher.from_array_of_hashes(
444
+ [{ name: 'first',
445
+ list_ratios: {
360
446
  'high' => 0.5,
361
447
  'medium' => 0.1,
362
448
  'none' => 0.4
363
449
  },
364
- :ratio => 0.25 },
365
- { :name => "second",
366
- :ratio => 0.50 },
367
- { :name => "third",
368
- :ratio => 0.25 }] )
369
- @arguments = {
370
- :pusher => @pusher,
371
- :popper => @popper,
372
- :all_list_max => 40,
373
- :strategy => :drain
450
+ ratio: 0.25 },
451
+ { name: 'second',
452
+ ratio: 0.50 },
453
+ { name: 'third',
454
+ ratio: 0.25 }]
455
+ )
456
+ end
457
+ let(:arguments) do
458
+ {
459
+ pusher: pusher,
460
+ popper: popper,
461
+ all_list_max: 40,
462
+ strategy: :drain_to_limit
374
463
  }
375
464
  end
376
- context "#new" do
377
- it "should not raise any errors" do
378
- expect { Qfill::Manager.new(@arguments) }.to_not raise_error
465
+
466
+ describe '#new' do
467
+ it 'does not raise any errors' do
468
+ expect { described_class.new(arguments) }.not_to raise_error
469
+ end
470
+ end
471
+
472
+ describe '#fill!' do
473
+ it 'instantiates with pusher' do
474
+ expect { described_class.new(arguments).fill! }.not_to raise_error
475
+ end
476
+ end
477
+
478
+ context 'results' do
479
+ context 'before fill!' do
480
+ it 'calculates the correct popper total elements' do
481
+ expect(manager.popper.count_all_elements).to eq(36)
482
+ end
483
+
484
+ it 'calculates the correct popper primary elements' do
485
+ expect(manager.popper.count_primary_elements).to eq(27)
486
+ end
487
+
488
+ it 'calculates the correct pusher total elements' do
489
+ expect(manager.pusher.count_all_elements).to eq(0)
490
+ end
491
+ end
492
+
493
+ context 'after fill!' do
494
+ before do
495
+ manager.fill!
496
+ end
497
+
498
+ it 'calculates the correct popper total elements' do
499
+ expect(manager.popper.count_all_elements).to eq(7) # With drain_to_limit the results do not exactly match the requested ratios.
500
+ end
501
+
502
+ it 'calculates the correct popper primary elements' do
503
+ expect(manager.popper.count_primary_elements).to eq(0)
504
+ end
505
+
506
+ it 'calculates the correct pusher total elements' do
507
+ expect(manager.pusher.count_all_elements).to eq(29)
508
+ end
509
+ end
510
+ end
511
+ end
512
+ end
513
+
514
+ context 'when strategy => :drain_to_empty' do
515
+ context 'when backfill => false' do
516
+ let(:popper) do
517
+ Qfill::Popper.from_array_of_hashes(
518
+ # We will create 4 queues, higspec/qfill/manager_spec.rb:386h, medium, low, and none.
519
+ # These might be queue of things that have ratings, and the none queue for things which have not yet been rated.
520
+ # The backfill route of the queues then, assuming we want people to rate the things that are not yet rated,
521
+ # but not at the expense of the experience, would be:
522
+ # high => medium => none => low
523
+ [{ name: 'high',
524
+ elements: %w[h1 h2 h3 h4 h5 h6 h7 h8 h9],
525
+ backfill: 'medium' },
526
+ { name: 'medium',
527
+ elements: %w[m1 m2 m3 m4 m5 m6 m7 m8 m9],
528
+ backfill: 'none' },
529
+ { name: 'low',
530
+ elements: %w[l1 l2 l3 l4 l5 l6 l7 l8 l9],
531
+ backfill: false },
532
+ { name: 'none',
533
+ elements: %w[n1 n2 n3 n4 n5 n6 n7 n8 n9],
534
+ backfill: 'low' }]
535
+ )
536
+ end
537
+ let(:pusher) do
538
+ Qfill::Pusher.from_array_of_hashes(
539
+ [{ name: 'first',
540
+ list_ratios: {
541
+ 'high' => 0.5,
542
+ 'medium' => 0.1,
543
+ 'none' => 0.4
544
+ },
545
+ preferred: %w[high none] },
546
+ { name: 'second',
547
+ list_ratios: {
548
+ 'high' => 0.5,
549
+ 'medium' => 0.4,
550
+ 'none' => 0.1
551
+ },
552
+ preferred: %w[high medium] },
553
+ { name: 'third' }]
554
+ )
555
+ end
556
+ let(:arguments) do
557
+ {
558
+ pusher: pusher,
559
+ popper: popper,
560
+ all_list_max: 40,
561
+ strategy: :drain_to_empty
562
+ }
563
+ end
564
+
565
+ describe '#new' do
566
+ it 'does not raise any errors' do
567
+ expect { described_class.new(arguments) }.not_to raise_error
568
+ end
569
+ end
570
+
571
+ describe '#fill!' do
572
+ it 'instantiates with pusher' do
573
+ expect { described_class.new(arguments).fill! }.not_to raise_error
574
+ end
575
+ end
576
+
577
+ context 'results' do
578
+ end
579
+
580
+ context 'before fill!' do
581
+ it 'calculates the correct popper total elements' do
582
+ expect(manager.popper.count_all_elements).to eq(36)
583
+ end
584
+
585
+ it 'calculates the correct popper primary elements' do
586
+ expect(manager.popper.count_primary_elements).to eq(36)
587
+ end
588
+
589
+ it 'calculates the correct pusher total elements' do
590
+ expect(manager.pusher.count_all_elements).to eq(0)
591
+ end
592
+ end
593
+
594
+ context 'after fill!' do
595
+ before do
596
+ manager.fill!
597
+ end
598
+
599
+ it 'calculates the correct popper total elements' do
600
+ expect(manager.popper.count_all_elements).to eq(0) # With drain_to_limit the results do not exactly match the requested ratios.
379
601
  end
602
+
603
+ it 'calculates the correct popper primary elements' do
604
+ expect(manager.popper.count_primary_elements).to eq(0)
605
+ end
606
+
607
+ it 'calculates the correct pusher total elements' do
608
+ expect(manager.pusher.count_all_elements).to eq(36)
609
+ end
610
+ end
611
+ end
612
+
613
+ context 'when backfill => true' do
614
+ let(:popper) do
615
+ Qfill::Popper.from_array_of_hashes(
616
+ # We will create 4 queues, high, medium, low, and none.
617
+ # These might be queue of things that have ratings, and the none queue for things which have not yet been rated.
618
+ # The backfill route of the queues then, assuming we want people to rate the things that are not yet rated,
619
+ # but not at the expense of the experience, would be:
620
+ # high => medium => none => low
621
+ [{ name: 'high',
622
+ elements: build_elements('h', 20),
623
+ backfill: 'medium' },
624
+ { name: 'medium',
625
+ elements: build_elements('m', 20),
626
+ backfill: 'none' },
627
+ { name: 'low',
628
+ elements: build_elements('l', 20),
629
+ backfill: true },
630
+ { name: 'none',
631
+ elements: build_elements('n', 20),
632
+ backfill: 'low' }]
633
+ )
634
+ end
635
+ let(:pusher) do
636
+ Qfill::Pusher.from_array_of_hashes(
637
+ [{ name: 'first',
638
+ list_ratios: {
639
+ 'high' => 0.5,
640
+ 'medium' => 0.1,
641
+ 'none' => 0.4
642
+ },
643
+ ratio: 1,
644
+ preferred: %w[high none] },
645
+ { name: 'second',
646
+ ratio: 0.50 },
647
+ { name: 'third',
648
+ ratio: 0.25 }]
649
+ )
380
650
  end
381
- context "#fill!" do
382
- it "should instantiate with pusher" do
383
- expect { Qfill::Manager.new(@arguments).fill! }.to_not raise_error
651
+ let(:arguments) do
652
+ {
653
+ pusher: pusher,
654
+ popper: popper,
655
+ all_list_max: 100,
656
+ strategy: :drain_to_empty
657
+ }
658
+ end
659
+
660
+ describe '#new' do
661
+ it 'does not raise any errors' do
662
+ expect { described_class.new(arguments) }.not_to raise_error
384
663
  end
385
664
  end
386
- context "results" do
387
- before(:each) do
388
- @manager = Qfill::Manager.new(@arguments)
665
+
666
+ describe '#fill!' do
667
+ it 'instantiates with pusher' do
668
+ expect { described_class.new(arguments).fill! }.not_to raise_error
389
669
  end
390
- context "before fill!" do
391
- it "should calculate the correct popper total elements" do
392
- @manager.popper.get_total_elements.should == 36
670
+ end
671
+
672
+ context 'results' do
673
+ context 'before fill!' do
674
+ it 'calculates the correct popper total elements' do
675
+ expect(manager.popper.count_all_elements).to eq(80)
393
676
  end
394
- it "should calculate the correct popper primary elements" do
395
- @manager.popper.get_primary_elements == 27
677
+
678
+ it 'calculates the correct popper primary elements' do
679
+ expect(manager.popper.count_primary_elements).to eq(60)
396
680
  end
397
- it "should calculate the correct pusher total elements" do
398
- @manager.pusher.get_total_elements.should == 0
681
+
682
+ it 'calculates the correct pusher total elements' do
683
+ expect(manager.pusher.count_all_elements).to eq(0)
399
684
  end
400
685
  end
401
- context "after fill!" do
402
- before(:each) do
403
- @manager.fill!
686
+
687
+ context 'after fill!' do
688
+ before do
689
+ manager.fill!
404
690
  end
405
- it "should calculate the correct popper total elements" do
406
- @manager.popper.get_total_elements.should == 7 # With drain the results do not exactly match the requested ratios.
691
+
692
+ it 'calculates the correct leftover popper total elements' do
693
+ expect(manager.popper.count_all_elements).to eq(20) # TODO???: With drain_to_empty the results do not exactly match the requested ratios.
407
694
  end
408
- it "should calculate the correct popper primary elements" do
409
- @manager.popper.get_primary_elements == 0
695
+
696
+ it 'calculates the correct popper primary elements' do
697
+ expect(manager.popper.count_primary_elements).to eq(0)
410
698
  end
411
- it "should calculate the correct pusher total elements" do
412
- @manager.pusher.get_total_elements.should == 29
699
+
700
+ context 'when all_list_max is higher than count of all elements' do
701
+ it 'reduces all_list_max to original count of all elements' do
702
+ expect(manager.all_list_max).to eq(80)
703
+ end
704
+
705
+ it 'is greater than count of all elements in the results (pusher)' do
706
+ expect(manager.all_list_max > manager.pusher.count_all_elements).to eq(true)
707
+ end
413
708
  end
709
+
710
+ context 'when all_list_max is lower than count of all elements' do
711
+ let(:arguments) do
712
+ {
713
+ pusher: pusher,
714
+ popper: popper,
715
+ all_list_max: 4,
716
+ strategy: :drain_to_empty
717
+ }
718
+ end
719
+
720
+ it 'retains specified all_list_max' do
721
+ expect(manager.all_list_max).to eq(4)
722
+ end
723
+
724
+ it 'is equal to count of all elements in the results (pusher)' do
725
+ expect(manager.pusher.count_all_elements).to eq(manager.all_list_max)
726
+ end
727
+ end
728
+ end
729
+ end
730
+ end
731
+ end
732
+
733
+ context 'when strategy => :time_slice' do
734
+ let(:elements) { 2400 }
735
+ let(:window_size) { 20 }
736
+ let(:pane_size) { 2 }
737
+ let(:popper) do
738
+ Qfill::Popper.from_array_of_hashes(
739
+ [
740
+ {
741
+ name: 'data',
742
+ elements: build_elements('ef', elements)
743
+ }
744
+ ]
745
+ )
746
+ end
747
+ let(:arguments) do
748
+ {
749
+ popper: popper,
750
+ strategy: :time_slice,
751
+ strategy_options: {
752
+ window_size: window_size,
753
+ window_units: 'minutes',
754
+ pane_size: pane_size,
755
+ pane_units: 'seconds'
756
+ }
757
+ }
758
+ end
759
+
760
+ shared_examples_for "a good citizen" do
761
+ describe '#new' do
762
+ it 'does not raise any errors' do
763
+ expect { described_class.new(arguments) }.not_to raise_error
764
+ end
765
+ end
766
+
767
+ describe '#fill!' do
768
+ it 'instantiates with pusher' do
769
+ expect { described_class.new(arguments).fill! }.not_to raise_error
770
+ end
771
+ end
772
+ end
773
+
774
+ it_behaves_like "a good citizen"
775
+
776
+ context "other options" do
777
+ let(:elements) { 101 }
778
+
779
+ context "5 minutes by 3 seconds" do
780
+ let(:window_size) { 5 }
781
+ let(:pane_size) { 3 }
782
+
783
+ it_behaves_like "a good citizen"
784
+ end
785
+
786
+ context "7 minutes by 4 seconds" do
787
+ let(:window_size) { 7 }
788
+ let(:pane_size) { 4 }
789
+
790
+ it_behaves_like "a good citizen"
791
+ end
792
+ end
793
+
794
+ context 'results' do
795
+ context 'before fill!' do
796
+ it 'calculates the correct popper total elements' do
797
+ expect(manager.popper.count_all_elements).to eq(2400)
798
+ end
799
+
800
+ it 'calculates the correct popper primary elements' do
801
+ expect(manager.popper.count_primary_elements).to eq(2400)
802
+ end
803
+
804
+ it 'calculates the correct pusher total elements' do
805
+ expect(manager.pusher.count_all_elements).to eq(0)
806
+ end
807
+
808
+ it 'has pusher queues that are "full" (because max starts at 0)' do
809
+ expect(manager.pusher.queues.count(&:is_full?)).to eq(600)
810
+ end
811
+
812
+ it 'has pusher queues that are not really full' do
813
+ expect(manager.pusher.queues.count { |x| x.elements.empty? }).to eq(600)
814
+ end
815
+ end
816
+
817
+ context 'after fill!' do
818
+ before do
819
+ manager.fill!
820
+ end
821
+
822
+ it 'calculates the correct popper total elements' do
823
+ expect(manager.popper.count_all_elements).to eq(0)
824
+ end
825
+
826
+ it 'calculates the correct popper primary elements' do
827
+ expect(manager.popper.count_primary_elements).to eq(0)
828
+ end
829
+
830
+ it 'calculates the correct pusher total elements' do
831
+ expect(manager.pusher.count_all_elements).to eq(2400)
832
+ end
833
+
834
+ it 'has correct number of pusher queues' do
835
+ expect(manager.pusher.queues.length).to eq(600)
836
+ end
837
+
838
+ it 'has pusher queues that are full' do
839
+ expect(manager.pusher.queues.count(&:is_full?)).to eq(600)
840
+ end
841
+
842
+ it 'has pusher queues that are not too full' do
843
+ elements_per_queue = 2400 / 600
844
+ expect(manager.pusher.queues.count { |x| x.elements.length == elements_per_queue }).to eq(600)
414
845
  end
415
846
  end
416
847
  end