ballot 1.0

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 (70) hide show
  1. checksums.yaml +7 -0
  2. data/Contributing.md +68 -0
  3. data/History.md +5 -0
  4. data/Licence.md +27 -0
  5. data/Manifest.txt +68 -0
  6. data/README.rdoc +264 -0
  7. data/Rakefile +71 -0
  8. data/bin/ballot_generator +9 -0
  9. data/lib/ballot.rb +25 -0
  10. data/lib/ballot/action_controller.rb +32 -0
  11. data/lib/ballot/active_record.rb +152 -0
  12. data/lib/ballot/active_record/votable.rb +145 -0
  13. data/lib/ballot/active_record/vote.rb +35 -0
  14. data/lib/ballot/active_record/voter.rb +99 -0
  15. data/lib/ballot/railtie.rb +19 -0
  16. data/lib/ballot/sequel.rb +170 -0
  17. data/lib/ballot/sequel/vote.rb +99 -0
  18. data/lib/ballot/votable.rb +445 -0
  19. data/lib/ballot/vote.rb +129 -0
  20. data/lib/ballot/voter.rb +320 -0
  21. data/lib/ballot/words.rb +32 -0
  22. data/lib/generators/ballot.rb +40 -0
  23. data/lib/generators/ballot/install/install_generator.rb +27 -0
  24. data/lib/generators/ballot/install/templates/active_record/migration.rb +19 -0
  25. data/lib/generators/ballot/install/templates/sequel/migration.rb +25 -0
  26. data/lib/generators/ballot/standalone.rb +89 -0
  27. data/lib/generators/ballot/standalone/support.rb +70 -0
  28. data/lib/generators/ballot/summary/summary_generator.rb +27 -0
  29. data/lib/generators/ballot/summary/templates/active_record/migration.rb +15 -0
  30. data/lib/generators/ballot/summary/templates/sequel/migration.rb +20 -0
  31. data/lib/sequel/plugins/ballot_votable.rb +180 -0
  32. data/lib/sequel/plugins/ballot_voter.rb +125 -0
  33. data/test/active_record/ballot_votable_test.rb +16 -0
  34. data/test/active_record/ballot_voter_test.rb +13 -0
  35. data/test/active_record/rails_generator_test.rb +28 -0
  36. data/test/active_record/votable_voter_test.rb +19 -0
  37. data/test/generators/rails-activerecord/Rakefile +2 -0
  38. data/test/generators/rails-activerecord/app/.keep +0 -0
  39. data/test/generators/rails-activerecord/bin/rails +5 -0
  40. data/test/generators/rails-activerecord/config/application.rb +17 -0
  41. data/test/generators/rails-activerecord/config/boot.rb +3 -0
  42. data/test/generators/rails-activerecord/config/database.yml +12 -0
  43. data/test/generators/rails-activerecord/config/environment.rb +3 -0
  44. data/test/generators/rails-activerecord/config/routes.rb +3 -0
  45. data/test/generators/rails-activerecord/config/secrets.yml +5 -0
  46. data/test/generators/rails-activerecord/db/seeds.rb +1 -0
  47. data/test/generators/rails-activerecord/log/.keep +0 -0
  48. data/test/generators/rails-sequel/Rakefile +2 -0
  49. data/test/generators/rails-sequel/app/.keep +0 -0
  50. data/test/generators/rails-sequel/bin/rails +5 -0
  51. data/test/generators/rails-sequel/config/application.rb +14 -0
  52. data/test/generators/rails-sequel/config/boot.rb +3 -0
  53. data/test/generators/rails-sequel/config/database.yml +12 -0
  54. data/test/generators/rails-sequel/config/environment.rb +3 -0
  55. data/test/generators/rails-sequel/config/routes.rb +3 -0
  56. data/test/generators/rails-sequel/config/secrets.yml +5 -0
  57. data/test/generators/rails-sequel/db/seeds.rb +1 -0
  58. data/test/generators/rails-sequel/log/.keep +0 -0
  59. data/test/minitest_config.rb +14 -0
  60. data/test/sequel/ballot_votable_test.rb +45 -0
  61. data/test/sequel/ballot_voter_test.rb +42 -0
  62. data/test/sequel/rails_generator_test.rb +25 -0
  63. data/test/sequel/votable_voter_test.rb +19 -0
  64. data/test/sequel/vote_test.rb +105 -0
  65. data/test/support/active_record_setup.rb +145 -0
  66. data/test/support/generators_setup.rb +129 -0
  67. data/test/support/sequel_setup.rb +164 -0
  68. data/test/support/shared_examples/votable_examples.rb +630 -0
  69. data/test/support/shared_examples/voter_examples.rb +600 -0
  70. metadata +333 -0
@@ -0,0 +1,600 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VoterExamples
4
+ def describe_voter_models(models, focus: false)
5
+ describe '.ballot_voter?' do
6
+ models.each do |model|
7
+ self.focus if focus && respond_to?(:focus)
8
+ it "#{model}.ballot_voter? is true" do
9
+ assert_true model.ballot_voter?
10
+ end
11
+
12
+ self.focus if focus && respond_to?(:focus)
13
+ it "#{model}#ballot_voter? is true" do
14
+ assert_true model.new.ballot_voter?
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ def describe_non_voter_models(models, focus: false)
21
+ describe '.ballot_voter?' do
22
+ models.each do |model|
23
+ self.focus if focus && respond_to?(:focus)
24
+ it "#{model}.ballot_voter? is false" do
25
+ assert_false model.ballot_voter?
26
+ end
27
+
28
+ self.focus if focus && respond_to?(:focus)
29
+ it "#{model}.ballot_voter? is false" do
30
+ assert_false model.new.ballot_voter?
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def describe_ballot_voter(klass = nil, focus: false, &block)
37
+ msg = 'a voter model'
38
+ klass && msg = "#{klass} is #{msg}"
39
+
40
+ describe msg do
41
+ instance_exec(&block) if block
42
+
43
+ describe '#cast_ballot_for' do
44
+ self.focus if focus
45
+ it 'is false when no votable is provided' do
46
+ assert_false voter.cast_ballot_for
47
+ end
48
+
49
+ self.focus if focus
50
+ it 'is false when the votable is not a model' do
51
+ assert_false voter.cast_ballot_for Class.new
52
+ end
53
+
54
+ self.focus if focus
55
+ it 'is false when the votable is not a votable' do
56
+ assert_false voter.cast_ballot_for not_votable
57
+ end
58
+
59
+ self.focus if focus
60
+ it 'is true when a vote succeeds' do
61
+ assert_true voter.cast_ballot_for votable
62
+ end
63
+
64
+ self.focus if focus
65
+ it 'adds a vote' do
66
+ assert_true voter.cast_ballot_for votable
67
+ assert_true voter_dataset(voter).any?
68
+ assert_equal 1, voter_dataset(voter).count
69
+ end
70
+
71
+ self.focus if focus
72
+ it 'creates only one vote per item' do
73
+ voter.cast_ballot_for votable: votable
74
+
75
+ assert_true(
76
+ voter.cast_ballot_for(
77
+ votable_id: votable.id,
78
+ votable_type: ballot_type_name(votable),
79
+ vote: 'no'
80
+ )
81
+ )
82
+
83
+ assert_equal 1, votable_dataset(votable).count
84
+ end
85
+
86
+ self.focus if focus
87
+ it 'creates only one vote per item, unless duplicates are allowed' do
88
+ voter.cast_ballot_for votable: votable
89
+ assert_true voter.cast_ballot_for votable: votable, duplicate: true
90
+ assert_equal 2, votable_dataset(votable).count
91
+ end
92
+
93
+ self.focus if focus
94
+ it 'creates a scoped vote' do
95
+ voter.cast_ballot_for votable: votable, scope: 'rank'
96
+ assert_true votable_dataset(votable).where(scope: 'rank').any?
97
+ end
98
+
99
+ self.focus if focus
100
+ it 'creates only one scoped vote per person' do
101
+ voter.cast_ballot_for votable: votable, scope: 'rank'
102
+ voter.cast_ballot_for votable: votable, scope: 'rank', vote: 'no'
103
+ assert_equal 1, votable_dataset(votable).where(scope: 'rank').count
104
+ end
105
+
106
+ self.focus if focus
107
+ it 'creates only one scoped vote per person, unless duplicates are allowed' do
108
+ voter.cast_ballot_for votable: votable, scope: 'rank'
109
+ assert_true(
110
+ voter.cast_ballot_for(
111
+ votable: votable, scope: 'rank', vote: 'no', duplicate: true
112
+ )
113
+ )
114
+ assert_equal 2, votable_dataset(votable).where(scope: 'rank').count
115
+ end
116
+
117
+ self.focus if focus
118
+ it 'creates multiple votes with different scopes' do
119
+ assert_true voter.cast_ballot_for votable: votable, scope: 'weekly_rank'
120
+ assert_true voter.cast_ballot_for votable: votable, scope: 'monthly_rank'
121
+ assert_equal 2, votable_dataset(votable).count
122
+ end
123
+
124
+ self.focus if focus
125
+ it 'records separate votes for separate voters' do
126
+ assert_true voter.cast_ballot_for votable: votable
127
+ assert_true voter2.cast_ballot_for votable: votable
128
+ assert_equal 2, votable_dataset(votable).count
129
+ end
130
+
131
+ self.focus if focus
132
+ it 'uses a default vote weight of 1' do
133
+ voter.cast_ballot_for votable
134
+ assert_equal 1, votable_dataset(votable).first.weight
135
+ end
136
+ end
137
+
138
+ describe '#cast_up_ballot_for' do
139
+ self.focus if focus
140
+ it 'is false when the votable is not a model' do
141
+ assert_false voter.cast_up_ballot_for Class.new
142
+ end
143
+
144
+ self.focus if focus
145
+ it 'is false when the votable is not a votable' do
146
+ assert_false voter.cast_up_ballot_for not_votable
147
+ end
148
+
149
+ self.focus if focus
150
+ it 'is true when a vote succeeds' do
151
+ assert_true voter.cast_up_ballot_for votable
152
+ end
153
+
154
+ self.focus if focus
155
+ it 'adds a vote' do
156
+ assert_true voter.cast_up_ballot_for votable
157
+ assert_true voter_dataset(voter).any?
158
+ assert_equal 1, votable_dataset(votable).count
159
+ end
160
+
161
+ self.focus if focus
162
+ it 'creates only one vote per item' do
163
+ voter.cast_up_ballot_for votable
164
+ assert_false voter.cast_up_ballot_for votable, vote: 'no'
165
+ assert_equal 1, votable_dataset(votable).count
166
+ end
167
+
168
+ self.focus if focus
169
+ it 'creates only one vote per item, unless duplicates are allowed' do
170
+ voter.cast_up_ballot_for votable
171
+ assert_true voter.cast_up_ballot_for votable, duplicate: true
172
+ assert_equal 2, votable_dataset(votable).count
173
+ end
174
+
175
+ self.focus if focus
176
+ it 'creates a scoped vote' do
177
+ voter.cast_up_ballot_for votable, scope: 'rank'
178
+ assert_true votable_dataset(votable).where(scope: 'rank').any?
179
+ end
180
+
181
+ self.focus if focus
182
+ it 'creates only one scoped vote per person' do
183
+ voter.cast_up_ballot_for votable, scope: 'rank'
184
+ voter.cast_up_ballot_for votable, scope: 'rank', vote: 'no'
185
+ assert_equal 1, votable_dataset(votable).where(scope: 'rank').count
186
+ end
187
+
188
+ self.focus if focus
189
+ it 'creates only one scoped vote per person, unless duplicates are allowed' do
190
+ voter.cast_up_ballot_for votable, scope: 'rank'
191
+ assert_true(
192
+ voter.cast_up_ballot_for(votable, scope: 'rank', vote: 'no', duplicate: true)
193
+ )
194
+ assert_equal 2, votable_dataset(votable).where(scope: 'rank').count
195
+ end
196
+
197
+ self.focus if focus
198
+ it 'creates multiple votes with different scopes' do
199
+ assert_true voter.cast_up_ballot_for votable, scope: 'weekly_rank'
200
+ assert_true voter.cast_up_ballot_for votable, scope: 'monthly_rank'
201
+ assert_equal 2, votable_dataset(votable).count
202
+ end
203
+
204
+ self.focus if focus
205
+ it 'records separate votes for separate voters' do
206
+ assert_true voter.cast_up_ballot_for votable
207
+ assert_true voter2.cast_up_ballot_for votable
208
+ assert_equal 2, votable_dataset(votable).count
209
+ end
210
+
211
+ self.focus if focus
212
+ it 'uses a default vote weight of 1' do
213
+ voter.cast_up_ballot_for votable
214
+ assert_equal 1, votable_dataset(votable).first.weight
215
+ end
216
+ end
217
+
218
+ describe '#cast_down_ballot_for' do
219
+ self.focus if focus
220
+ it 'is false when the votable is not a model' do
221
+ assert_false voter.cast_down_ballot_for Class.new
222
+ end
223
+
224
+ self.focus if focus
225
+ it 'is false when the votable is not a votable' do
226
+ assert_false voter.cast_down_ballot_for not_votable
227
+ end
228
+
229
+ self.focus if focus
230
+ it 'is true when a vote succeeds' do
231
+ assert_true voter.cast_down_ballot_for votable
232
+ end
233
+
234
+ self.focus if focus
235
+ it 'adds a vote' do
236
+ assert_true voter.cast_down_ballot_for votable
237
+ assert_true voter_dataset(voter).any?
238
+ assert_equal 1, votable_dataset(votable).count
239
+ end
240
+
241
+ self.focus if focus
242
+ it 'creates only one vote per item' do
243
+ voter.cast_down_ballot_for votable
244
+ assert_false voter.cast_down_ballot_for votable, vote: 'no'
245
+ assert_equal 1, votable_dataset(votable).count
246
+ end
247
+
248
+ self.focus if focus
249
+ it 'creates only one vote per item, unless duplicates are allowed' do
250
+ voter.cast_down_ballot_for votable
251
+ assert_true voter.cast_down_ballot_for votable, duplicate: true
252
+ assert_equal 2, votable_dataset(votable).count
253
+ end
254
+
255
+ self.focus if focus
256
+ it 'creates a scoped vote' do
257
+ voter.cast_down_ballot_for votable, scope: 'rank'
258
+ assert_true votable_dataset(votable).where(scope: 'rank').any?
259
+ end
260
+
261
+ self.focus if focus
262
+ it 'creates only one scoped vote per person' do
263
+ voter.cast_down_ballot_for votable, scope: 'rank'
264
+ voter.cast_down_ballot_for votable, scope: 'rank', vote: 'no'
265
+ assert_equal 1, votable_dataset(votable).where(scope: 'rank').count
266
+ end
267
+
268
+ self.focus if focus
269
+ it 'creates only one scoped vote per person, unless duplicates are allowed' do
270
+ voter.cast_down_ballot_for votable, scope: 'rank'
271
+ assert_true(
272
+ voter.cast_down_ballot_for(votable, scope: 'rank', vote: 'no', duplicate: true)
273
+ )
274
+ assert_equal 2, votable_dataset(votable).where(scope: 'rank').count
275
+ end
276
+
277
+ self.focus if focus
278
+ it 'creates multiple votes with different scopes' do
279
+ assert_true voter.cast_down_ballot_for votable, scope: 'weekly_rank'
280
+ assert_true voter.cast_down_ballot_for votable, scope: 'monthly_rank'
281
+ assert_equal 2, votable_dataset(votable).count
282
+ end
283
+
284
+ self.focus if focus
285
+ it 'records separate votes for separate voters' do
286
+ assert_true voter.cast_down_ballot_for votable
287
+ assert_true voter2.cast_down_ballot_for votable
288
+ assert_equal 2, votable_dataset(votable).count
289
+ end
290
+
291
+ self.focus if focus
292
+ it 'uses a default vote weight of 1' do
293
+ voter.cast_down_ballot_for votable
294
+ assert_equal 1, votable_dataset(votable).first.weight
295
+ end
296
+ end
297
+
298
+ describe '#remove_ballot_for' do
299
+ self.focus if focus
300
+ it 'removes an up vote' do
301
+ voter.cast_up_ballot_for votable
302
+ assert_true voter.remove_ballot_for votable
303
+ assert_true votable_dataset(votable).none?
304
+ end
305
+
306
+ self.focus if focus
307
+ it 'removes a down vote' do
308
+ voter.cast_down_ballot_for votable
309
+ assert_true voter.remove_ballot_for votable
310
+ assert_true votable_dataset(votable).none?
311
+ end
312
+
313
+ self.focus if focus
314
+ it 'sets ballot_registered? to false' do
315
+ voter.cast_ballot_for votable
316
+ assert_true voter.remove_ballot_for votable
317
+ assert_false votable.ballot_registered?
318
+ end
319
+
320
+ self.focus if focus
321
+ it 'removes only a single vote' do
322
+ voter.cast_up_ballot_for votable
323
+ voter2.cast_up_ballot_for votable
324
+ voter.remove_ballot_for votable
325
+ assert_true votable_dataset(votable).any?
326
+ assert_true votable_dataset(votable).where(
327
+ voter_id: voter.id,
328
+ voter_type: voter.class.name
329
+ ).none?
330
+ assert_true votable_dataset(votable).where(
331
+ voter_id: voter2.id,
332
+ voter_type: voter2.class.name
333
+ ).any?
334
+ end
335
+ end
336
+
337
+ describe '#cast_ballot_for?' do
338
+ self.focus if focus
339
+ it 'is true if the user voted up' do
340
+ voter.cast_up_ballot_for votable
341
+ assert_true voter.cast_ballot_for?(votable)
342
+ end
343
+
344
+ self.focus if focus
345
+ it 'is true if the user voted down' do
346
+ voter.cast_down_ballot_for votable
347
+ assert_true voter.cast_ballot_for?(votable)
348
+ end
349
+
350
+ self.focus if focus
351
+ it 'is false if the user has not voted' do
352
+ assert_false voter.cast_ballot_for?(votable)
353
+ end
354
+
355
+ self.focus if focus
356
+ it 'is true if the user voted in scope' do
357
+ voter.cast_up_ballot_for votable, scope: 'rank'
358
+ assert_false voter.cast_ballot_for?(votable)
359
+ assert_true voter.cast_ballot_for?(votable, scope: 'rank')
360
+ end
361
+ end
362
+
363
+ describe '#cast_up_ballot_for?, #cast_down_ballot_for?' do
364
+ self.focus if focus
365
+ it 'is up if the user voted up' do
366
+ voter.cast_up_ballot_for votable
367
+ assert_true voter.cast_up_ballot_for?(votable)
368
+ assert_false voter.cast_down_ballot_for?(votable)
369
+ end
370
+
371
+ self.focus if focus
372
+ it 'is true if the user voted down' do
373
+ voter.cast_down_ballot_for votable
374
+ assert_false voter.cast_up_ballot_for?(votable)
375
+ assert_true voter.cast_down_ballot_for?(votable)
376
+ end
377
+
378
+ self.focus if focus
379
+ it 'is false if the user has not voted' do
380
+ assert_false voter.cast_up_ballot_for?(votable)
381
+ assert_false voter.cast_down_ballot_for?(votable)
382
+ end
383
+
384
+ self.focus if focus
385
+ it 'is true if the user voted in scope' do
386
+ voter.cast_up_ballot_for votable, scope: 'rank'
387
+ assert_false voter.cast_up_ballot_for?(votable)
388
+ assert_false voter.cast_down_ballot_for?(votable)
389
+ assert_true voter.cast_up_ballot_for?(votable, scope: 'rank')
390
+ assert_false voter.cast_down_ballot_for?(votable, scope: 'rank')
391
+ end
392
+ end
393
+
394
+ describe '#ballot_as_cast_for' do
395
+ self.focus if focus
396
+ it 'is true when voted up' do
397
+ voter.cast_up_ballot_for votable
398
+ assert_true voter.ballot_as_cast_for(votable)
399
+ end
400
+
401
+ self.focus if focus
402
+ it 'is false when voted down' do
403
+ voter.cast_down_ballot_for votable
404
+ assert_false voter.ballot_as_cast_for(votable)
405
+ end
406
+
407
+ self.focus if focus
408
+ it 'is nil when not voted' do
409
+ assert_nil voter.ballot_as_cast_for(votable)
410
+ end
411
+
412
+ self.focus if focus
413
+ it 'is true when voted up with a scope' do
414
+ voter.cast_up_ballot_for votable, scope: 'rank'
415
+ assert_true voter.ballot_as_cast_for(votable, scope: 'rank')
416
+ assert_nil voter.ballot_as_cast_for(votable)
417
+ end
418
+
419
+ self.focus if focus
420
+ it 'is false when voted down' do
421
+ voter.cast_down_ballot_for votable, scope: 'rank'
422
+ assert_false voter.ballot_as_cast_for(votable, scope: 'rank')
423
+ assert_nil voter.ballot_as_cast_for(votable)
424
+ end
425
+
426
+ self.focus if focus
427
+ it 'is nil when not voted' do
428
+ assert_nil voter.ballot_as_cast_for(votable, scope: 'rank')
429
+ end
430
+
431
+ self.focus if focus
432
+ it 'applies only to the voter' do
433
+ voter.cast_down_ballot_for votable
434
+ voter2.cast_up_ballot_for votable
435
+ assert_false voter.ballot_as_cast_for(votable)
436
+ end
437
+ end
438
+
439
+ describe '#up_ballots_by' do
440
+ self.focus if focus
441
+ it 'returns the set of up votes' do
442
+ voter.cast_up_ballot_for votable
443
+ voter.cast_up_ballot_for sti_votable
444
+ voter.cast_down_ballot_for child_of_sti_votable
445
+ voter.cast_down_ballot_for votable_child_of_sti_not_votable
446
+
447
+ assert_equal [
448
+ votable_dataset(votable).first,
449
+ votable_dataset(sti_votable).first
450
+ ], voter.up_ballots_by.all
451
+ end
452
+ end
453
+
454
+ describe '#down_ballots_by' do
455
+ self.focus if focus
456
+ it 'returns the set of down votes' do
457
+ voter.cast_up_ballot_for votable
458
+ voter.cast_up_ballot_for sti_votable
459
+ voter.cast_down_ballot_for child_of_sti_votable
460
+ voter.cast_down_ballot_for votable_child_of_sti_not_votable
461
+
462
+ assert_equal [
463
+ votable_dataset(child_of_sti_votable).first,
464
+ votable_dataset(votable_child_of_sti_not_votable).first
465
+ ], voter.down_ballots_by.all
466
+ end
467
+ end
468
+
469
+ describe '#ballots_for_class' do
470
+ self.focus if focus
471
+ it 'returns the set of votes for this class' do
472
+ voter.cast_up_ballot_for votable
473
+ voter.cast_down_ballot_for votable2
474
+
475
+ assert_equal [ votable_dataset(votable).first, votable_dataset(votable2).first ],
476
+ voter.ballots_for_class(votable.class).all
477
+ end
478
+ end
479
+
480
+ describe '#up_ballots_for_class' do
481
+ self.focus if focus
482
+ it 'returns the set of up votes for this class' do
483
+ voter.cast_up_ballot_for votable
484
+ voter.cast_down_ballot_for votable2
485
+
486
+ assert_equal [ votable_dataset(votable).first ],
487
+ voter.up_ballots_for_class(votable.class).all
488
+ end
489
+ end
490
+
491
+ describe '#down_ballots_for_class' do
492
+ self.focus if focus
493
+ it 'returns the set of down votes for this class' do
494
+ voter.cast_up_ballot_for votable
495
+ voter.cast_down_ballot_for votable2
496
+
497
+ assert_equal [ votable_dataset(votable2).first ],
498
+ voter.down_ballots_for_class(votable.class).all
499
+ end
500
+ end
501
+
502
+ describe '#ballot_votables' do
503
+ self.focus if focus
504
+ it 'returns the set of items voted on' do
505
+ voter.cast_up_ballot_for votable
506
+ voter.cast_down_ballot_for votable2
507
+
508
+ assert_equal [ votable, votable2 ], voter.ballot_votables
509
+ end
510
+ end
511
+
512
+ describe '#ballot_up_votables' do
513
+ self.focus if focus
514
+ it 'returns the set of items up voted' do
515
+ voter.cast_up_ballot_for votable
516
+ voter.cast_down_ballot_for votable2
517
+
518
+ assert_equal [ votable ], voter.ballot_up_votables
519
+ end
520
+ end
521
+
522
+ describe '#ballot_down_votables' do
523
+ self.focus if focus
524
+ it 'returns the set of items down voted' do
525
+ voter.cast_up_ballot_for votable
526
+ voter.cast_down_ballot_for votable2
527
+
528
+ assert_equal [ votable2 ], voter.ballot_down_votables
529
+ end
530
+ end
531
+ end
532
+ end
533
+
534
+ def describe_ballot_voter_sti_votable_support(focus: false)
535
+ describe 'with STI' do
536
+ describe '#vote' do
537
+ self.focus if focus && respond_to?(:focus)
538
+ it 'works with STI models' do
539
+ voter.cast_ballot_for sti_votable
540
+ assert_true votable_dataset(sti_votable).any?
541
+ end
542
+
543
+ self.focus if focus && respond_to?(:focus)
544
+ it 'works with Child STI models' do
545
+ voter.cast_ballot_for child_of_sti_votable
546
+ assert_true votable_dataset(child_of_sti_votable).any?
547
+ end
548
+
549
+ self.focus if focus && respond_to?(:focus)
550
+ it 'works with votable children of non-votable STI models' do
551
+ voter.cast_ballot_for votable_child_of_sti_not_votable
552
+ assert_true votable_dataset(votable_child_of_sti_not_votable).any?
553
+ end
554
+ end
555
+
556
+ describe '#cast_up_ballot_for' do
557
+ self.focus if focus && respond_to?(:focus)
558
+ it 'works with STI models' do
559
+ voter.cast_up_ballot_for sti_votable
560
+ assert_true votable_dataset(sti_votable).any?
561
+ end
562
+
563
+ self.focus if focus && respond_to?(:focus)
564
+ it 'works with Child STI models' do
565
+ voter.cast_up_ballot_for child_of_sti_votable
566
+ assert_true votable_dataset(child_of_sti_votable).any?
567
+ end
568
+
569
+ self.focus if focus && respond_to?(:focus)
570
+ it 'works with votable children of non-votable STI models' do
571
+ voter.cast_up_ballot_for votable_child_of_sti_not_votable
572
+ assert_true votable_dataset(votable_child_of_sti_not_votable).any?
573
+ end
574
+ end
575
+
576
+ describe '#cast_down_ballot_for' do
577
+ self.focus if focus && respond_to?(:focus)
578
+ it 'works with STI models' do
579
+ voter.cast_down_ballot_for sti_votable
580
+ assert_true votable_dataset(sti_votable).any?
581
+ end
582
+
583
+ self.focus if focus && respond_to?(:focus)
584
+ it 'works with Child STI models' do
585
+ voter.cast_down_ballot_for child_of_sti_votable
586
+ assert_true votable_dataset(child_of_sti_votable).any?
587
+ end
588
+
589
+ self.focus if focus && respond_to?(:focus)
590
+ it 'works with votable children of non-votable STI models' do
591
+ voter.cast_down_ballot_for votable_child_of_sti_not_votable
592
+ assert_true votable_dataset(votable_child_of_sti_not_votable).any?
593
+ end
594
+ end
595
+ end
596
+ end
597
+
598
+ ::Minitest::SequelSpec.extend self
599
+ ::Minitest::ActiveRecordSpec.extend self
600
+ end