ballot 1.0

Sign up to get free protection for your applications and to get access to all the features.
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,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest_config'
4
+
5
+ describe 'RailsGenerator' do
6
+ describe 'for Sequel' do
7
+ let(:orm_name) { 'sequel' }
8
+ let(:orm_version) { Sequel::VERSION }
9
+ let(:rails_version) { ActiveRecord::VERSION::STRING }
10
+
11
+ test_ballot_install(
12
+ generate: %r{create\s+db/migrate/\d+_install_ballot_vote_migration},
13
+ contents: /Sequel.migration.*create_table :ballot_votes do/m
14
+ )
15
+
16
+ test_ballot_summary_votable(
17
+ generate: %r{create\s+db/migrate/\d+_ballot_cache_for_votable},
18
+ contents: %r{
19
+ Sequel.migration.*
20
+ alter_table\s+:'votables'.*
21
+ add_column\s+:cached_ballot_summary,
22
+ }mx
23
+ )
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest_config'
4
+
5
+ describe SequelVotableVoter do
6
+ describe_ballot_voter do
7
+ let(:voter) { SequelVotableVoter.create(name: 'I can vote!') }
8
+ let(:voter2) { SequelVotableVoter.create(name: 'I, too, can vote!') }
9
+ let(:votable) { voter2 }
10
+ let(:votable2) { voter }
11
+ end
12
+
13
+ describe_ballot_votable do
14
+ let(:voter) { SequelVotableVoter.create(name: 'I can vote!') }
15
+ let(:voter2) { SequelVotableVoter.create(name: 'I, too, can vote!') }
16
+ let(:votable) { voter2 }
17
+ let(:votable2) { voter }
18
+ end
19
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest_config'
4
+
5
+ describe Ballot::Sequel::Vote do
6
+ before do
7
+ voter.cast_up_ballot_for votable
8
+ voter.cast_up_ballot_for votable2
9
+ voter.cast_up_ballot_for votable_cache
10
+ voter2.cast_down_ballot_for votable
11
+ voter2.cast_down_ballot_for votable2
12
+ voter2.cast_down_ballot_for votable_cache
13
+ expected_votes # Force the query now
14
+ end
15
+
16
+ let(:expected_votes) {
17
+ [
18
+ Ballot::Sequel::Vote[1],
19
+ Ballot::Sequel::Vote[2],
20
+ Ballot::Sequel::Vote[3],
21
+ Ballot::Sequel::Vote[4],
22
+ Ballot::Sequel::Vote[5],
23
+ Ballot::Sequel::Vote[6]
24
+ ]
25
+ }
26
+
27
+ describe 'dataset_module' do
28
+ it 'provides an up subset' do
29
+ assert_equal 3, Ballot::Sequel::Vote.dataset.up.count
30
+ assert_equal 3, Ballot::Sequel::Vote.up.count
31
+ end
32
+
33
+ it 'provides a down subset' do
34
+ assert_equal 3, Ballot::Sequel::Vote.dataset.down.count
35
+ assert_equal 3, Ballot::Sequel::Vote.down.count
36
+ end
37
+
38
+ it 'provides a for_type filter' do
39
+ assert_empty Ballot::Sequel::Vote.dataset.for_type('SequelNotVotable')
40
+ assert_empty Ballot::Sequel::Vote.for_type(SequelNotVotable)
41
+ refute_empty Ballot::Sequel::Vote.dataset.for_type('SequelVotable')
42
+ refute_empty Ballot::Sequel::Vote.for_type(SequelVotable)
43
+ end
44
+
45
+ it 'provides a by_type filter' do
46
+ assert_empty Ballot::Sequel::Vote.dataset.by_type('SequelNotVoter')
47
+ assert_empty Ballot::Sequel::Vote.by_type(SequelNotVoter)
48
+ refute_empty Ballot::Sequel::Vote.dataset.by_type('SequelVoter')
49
+ refute_empty Ballot::Sequel::Vote.by_type(SequelVoter)
50
+ end
51
+ end
52
+
53
+ describe 'votable association' do
54
+ it 'defines #votable= correctly' do
55
+ v = Ballot::Sequel::Vote.new
56
+ v.votable = votable
57
+ assert_equal votable.id, v.votable_id
58
+ assert_equal Ballot::Sequel.type_name(votable), v.votable_type
59
+ end
60
+
61
+ it 'defines votable_dataset correctly' do
62
+ assert_equal votable, voter.ballots_by.first.votable
63
+ end
64
+
65
+ it 'defines eager loading correctly' do
66
+ sqls = capture_sql {
67
+ actual = Ballot::Sequel::Vote.eager(:votable).all
68
+ assert_equal expected_votes, actual
69
+ assert_equal [ votable, votable2, votable_cache ], actual.shift(3).map(&:votable)
70
+ assert_equal [ votable, votable2, votable_cache ], actual.shift(3).map(&:votable)
71
+ }
72
+
73
+ assert_match(/SELECT \* FROM `ballot_votes`/, sqls.shift)
74
+ assert_match(/SELECT \* FROM `votables` WHERE \(`id` IN \(1, 2\)\)/, sqls.shift)
75
+ assert_match(/SELECT \* FROM `votable_caches` WHERE \(`id` IN \(1\)\)/, sqls.shift)
76
+ assert_empty sqls
77
+ end
78
+ end
79
+
80
+ describe 'voter association' do
81
+ it 'defines #voter= correctly' do
82
+ v = Ballot::Sequel::Vote.new
83
+ v.voter = voter
84
+ assert_equal voter.id, v.voter_id
85
+ assert_equal Ballot::Sequel.type_name(voter), v.voter_type
86
+ end
87
+
88
+ it 'defines voter_dataset correctly' do
89
+ assert_equal voter, votable.ballots_for_dataset.first.voter
90
+ end
91
+
92
+ it 'defines eager loading correctly' do
93
+ sqls = capture_sql {
94
+ actual = Ballot::Sequel::Vote.eager(:voter).all
95
+ assert_equal expected_votes, actual
96
+ assert_equal [ voter ] * 3, actual.shift(3).map(&:voter)
97
+ assert_equal [ voter2 ] * 3, actual.shift(3).map(&:voter)
98
+ }
99
+
100
+ assert_match(/SELECT \* FROM `ballot_votes`/, sqls.shift)
101
+ assert_match(/SELECT \* FROM `voters` WHERE \(`id` IN \(1, 2\)\)/, sqls.shift)
102
+ assert_empty sqls
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record'
4
+
5
+ if RUBY_ENGINE == 'jruby'
6
+ require 'activerecord-jdbcsqlite3-adapter'
7
+ else
8
+ require 'sqlite3'
9
+ end
10
+
11
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
12
+
13
+ ActiveRecord::Schema.verbose = false
14
+ ActiveRecord::Schema.define(version: 1) do
15
+ create_table :ballot_votes do |t|
16
+ t.references :votable, polymorphic: true
17
+ t.references :voter, polymorphic: true
18
+
19
+ t.boolean :vote
20
+ t.string :scope
21
+ t.integer :weight
22
+
23
+ t.timestamps null: false, default: 'now()'
24
+ end
25
+
26
+ add_index :ballot_votes, %i(voter_id voter_type scope)
27
+ add_index :ballot_votes, %i(votable_id votable_type scope)
28
+
29
+ %i(voters not_voters votables not_votables votable_voters).each do |table|
30
+ create_table table do |t|
31
+ t.string :name
32
+ end
33
+ end
34
+
35
+ %i(sti_votables sti_not_votables).each do |table|
36
+ create_table table do |t|
37
+ t.string :name
38
+ t.string :type
39
+ end
40
+ end
41
+
42
+ create_table :votable_caches do |t|
43
+ t.string :name
44
+
45
+ if t.respond_to?(:jsonb)
46
+ t.jsonb :cached_ballot_summary
47
+ else
48
+ t.string :cached_ballot_summary
49
+ end
50
+ end
51
+ end
52
+
53
+ require 'ballot/active_record'
54
+ Ballot::ActiveRecord.inject!
55
+
56
+ class ARVoter < ActiveRecord::Base
57
+ self.table_name = 'voters'
58
+ acts_as_ballot :voter
59
+ end
60
+
61
+ class ARNotVoter < ActiveRecord::Base
62
+ self.table_name = 'not_voters'
63
+ end
64
+
65
+ class ARVotable < ActiveRecord::Base
66
+ self.table_name = 'votables'
67
+ acts_as_ballot :votable
68
+ end
69
+
70
+ class ARNotVotable < ActiveRecord::Base
71
+ self.table_name = 'not_votables'
72
+ end
73
+
74
+ class ARVotableVoter < ActiveRecord::Base
75
+ self.table_name = 'votable_voters'
76
+ acts_as_ballot :voter
77
+ acts_as_ballot :votable
78
+ end
79
+
80
+ class ARStiVotable < ActiveRecord::Base
81
+ self.table_name = 'sti_votables'
82
+ acts_as_ballot :votable
83
+ end
84
+
85
+ class ARChildOfStiVotable < ARStiVotable
86
+ end
87
+
88
+ class ARStiNotVotable < ActiveRecord::Base
89
+ self.table_name = 'sti_not_votables'
90
+ end
91
+
92
+ class ARVotableChildOfStiNotVotable < ARStiNotVotable
93
+ acts_as_ballot :votable
94
+ end
95
+
96
+ class ARVotableCache < ActiveRecord::Base
97
+ self.table_name = 'votable_caches'
98
+ acts_as_ballot :votable
99
+ end
100
+
101
+ class ARABoringClass
102
+ end
103
+
104
+ class Minitest::ActiveRecordSpec < Minitest::HooksSpec
105
+ register_spec_type(/ActiveRecord|\AAR/, self)
106
+
107
+ AbortTransaction = Class.new(StandardError)
108
+
109
+ def around
110
+ ActiveRecord::Base.connection.transaction do
111
+ super
112
+ fail AbortTransaction
113
+ end
114
+ rescue AbortTransaction
115
+ true # This transaction has been deliberately aborted.
116
+ end
117
+
118
+ def votable_dataset(votable)
119
+ votable.ballots_for
120
+ end
121
+
122
+ def voter_dataset(voter)
123
+ voter.ballots_by
124
+ end
125
+
126
+ def ballot_type_name(item)
127
+ Ballot::ActiveRecord.type_name(item)
128
+ end
129
+
130
+ let(:voter) { ARVoter.create(name: 'I can vote!') }
131
+ let(:voter2) { ARVoter.create(name: 'I, too, can vote!') }
132
+ let(:not_voter) { ARNotVoter.create(name: 'I cannot vote!') }
133
+
134
+ let(:votable) { ARVotable.create(name: 'a votable model') }
135
+ let(:votable2) { ARVotable.create(name: 'a second votable model') }
136
+ let(:votable_cache) { ARVotableCache.create(name: 'a votable model with caching') }
137
+ let(:sti_votable) { ARStiVotable.create(name: 'a votable STI model') }
138
+ let(:child_of_sti_votable) {
139
+ ARChildOfStiVotable.create(name: 'a votable STI child model')
140
+ }
141
+ let(:votable_child_of_sti_not_votable) {
142
+ ARVotableChildOfStiNotVotable.create(name: 'a votable STI child of a non-votable')
143
+ }
144
+ let(:not_votable) { ARNotVotable.create(name: 'a non-votable model') }
145
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Minitest::RailsGeneratorSpec < Minitest::HooksSpec
4
+ register_spec_type(/RailsGenerator/, self)
5
+
6
+ let(:app_path) { "test/generators/rails-#{orm_name}" }
7
+
8
+ def around
9
+ ENV['RAILS_VERSION'] = rails_version
10
+ ENV['ORM_VERSION'] = orm_version
11
+ gemfile = File.join(File.expand_path(app_path), 'Gemfile')
12
+
13
+ Dir.chdir(app_path) do
14
+ without_current_bundler do
15
+ ENV['BUNDLE_GEMFILE'] = gemfile
16
+ system! 'git clean -fdx .'
17
+ system! 'gem install bundler'
18
+ if ENV['TRAVIS']
19
+ system! 'bundle --version'
20
+ system! 'bundle install'
21
+ end
22
+ system! 'bundle exec rake db:create'
23
+ system! 'bundle exec rails g model votable name'
24
+ run_migrations!
25
+
26
+ yield
27
+ end
28
+ end
29
+ ensure
30
+ ENV.delete('ORM_VERSION')
31
+ ENV.delete('RAILS_VERSION')
32
+ ENV.delete('BUNDLE_GEMFILE')
33
+ end
34
+
35
+ def without_current_bundler(&block)
36
+ if defined?(::Bundler)
37
+ Bundler.with_clean_env(&block)
38
+ else
39
+ yield
40
+ end
41
+ end
42
+
43
+ def assert_subprocess_output(stdout = nil, stderr = nil)
44
+ out, err = capture_subprocess_io { yield }
45
+
46
+ err_msg = stderr.kind_of?(Regexp) ? :assert_match : :assert_equal if stderr
47
+ out_msg = stdout.kind_of?(Regexp) ? :assert_match : :assert_equal if stdout
48
+
49
+ y = send err_msg, stderr, err, 'In stderr' if err_msg
50
+ x = send out_msg, stdout, out, 'In stdout' if out_msg
51
+
52
+ (!stdout || x) && (!stderr || y)
53
+ end
54
+
55
+ def assert_contents(contents, filename)
56
+ contents_msg = contents.kind_of?(Regexp) ? :assert_match : :assert_equal
57
+ send contents_msg, contents, File.read(filename), 'In contents'
58
+ end
59
+
60
+ def run_migrations
61
+ system 'bundle exec rake db:migrate'
62
+ end
63
+
64
+ def run_migrations!
65
+ system! 'bundle exec rake db:migrate'
66
+ end
67
+
68
+ def system!(command)
69
+ output = capture_subprocess_io { system command }
70
+ fail output.join("\n") unless $?.success?
71
+ end
72
+
73
+ def rails_generate(*args)
74
+ system "bundle exec rails g #{args.join(' ')}"
75
+ end
76
+
77
+ class << self
78
+ def focus!
79
+ @focussed = true
80
+ end
81
+
82
+ def focussed?
83
+ !!@focussed
84
+ end
85
+
86
+ def test_ballot_install(generate: nil, migrate: nil, contents: nil)
87
+ return unless ENV['CI'] || ENV['TEST_GENERATORS']
88
+
89
+ fail 'Contents must be provided' unless contents
90
+
91
+ focus if focussed?
92
+ it 'installs the ballot_votes table' do
93
+ assert_subprocess_output generate || '' do
94
+ rails_generate 'ballot:install'
95
+ end
96
+
97
+ assert_subprocess_output migrate || '' do
98
+ run_migrations
99
+ end
100
+
101
+ assert_contents contents,
102
+ Dir['db/migrate/*_install_ballot_vote_migration.rb'].first
103
+ end
104
+ end
105
+
106
+ def test_ballot_summary_votable(generate: nil, migrate: nil, contents: nil)
107
+ return unless ENV['CI'] || ENV['TEST_GENERATORS']
108
+
109
+ fail 'Contents must be provided' unless contents
110
+
111
+ focus if focussed?
112
+ it 'adds the summary column to the votable table' do
113
+ assert_nil File.read('db/schema.rb').match(/cached_ballot_summary/)
114
+
115
+ assert_subprocess_output generate || '' do
116
+ rails_generate 'ballot:summary', 'votable'
117
+ end
118
+
119
+ assert_subprocess_output migrate || '' do
120
+ run_migrations
121
+ end
122
+
123
+ assert_contents contents,
124
+ Dir['db/migrate/*_ballot_cache_for_votable.rb'].first
125
+ assert_contents(/cached_ballot_summary/, 'db/schema.rb')
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sequel'
4
+
5
+ DB = if RUBY_ENGINE == 'jruby'
6
+ Sequel.connect('jdbc:sqlite::memory:')
7
+ else
8
+ Sequel.sqlite
9
+ end
10
+
11
+ class SQLLogger
12
+ class << self
13
+ def sqls
14
+ Thread.current['sqls'] ||= []
15
+ end
16
+
17
+ def method_missing(_, msg)
18
+ sqls << msg
19
+ end
20
+
21
+ def clear
22
+ sqls.clear
23
+ end
24
+ end
25
+ end
26
+
27
+ DB.loggers << SQLLogger
28
+
29
+ DB.create_table? :ballot_votes do
30
+ primary_key :id
31
+ Integer :votable_id
32
+ String :votable_type
33
+
34
+ Integer :voter_id
35
+ String :voter_type
36
+
37
+ Boolean :vote
38
+ String :scope
39
+ Integer :weight
40
+
41
+ DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
42
+ DateTime :updated_at, null: false, default: Sequel::CURRENT_TIMESTAMP
43
+ end
44
+
45
+ %i(voters not_voters votables not_votables votable_voters).each do |table|
46
+ DB.create_table? table do
47
+ primary_key :id
48
+ String :name
49
+ end
50
+ end
51
+
52
+ %i(sti_votables sti_not_votables).each do |table|
53
+ DB.create_table? table do
54
+ primary_key :id
55
+ String :name
56
+ String :type
57
+ end
58
+ end
59
+
60
+ DB.create_table? :votable_caches do
61
+ primary_key :id
62
+
63
+ String :name
64
+
65
+ if Sequel.respond_to?(:pg_json)
66
+ if respond_to?(:jsonb)
67
+ jsonb :cached_ballot_summary
68
+ else
69
+ json :cached_ballot_summary
70
+ end
71
+ else
72
+ String :cached_ballot_summary
73
+ end
74
+ end
75
+
76
+ require 'ballot/sequel'
77
+
78
+ class SequelVoter < Sequel::Model(:voters)
79
+ plugin :ballot_voter
80
+ end
81
+
82
+ class SequelNotVoter < Sequel::Model(:not_voters)
83
+ end
84
+
85
+ class SequelVotable < Sequel::Model(:votables)
86
+ plugin :ballot_votable
87
+ end
88
+
89
+ class SequelNotVotable < Sequel::Model(:not_votables)
90
+ end
91
+
92
+ class SequelVotableVoter < Sequel::Model(:votable_voters)
93
+ plugin :ballot_voter
94
+ plugin :ballot_votable
95
+ end
96
+
97
+ class SequelStiVotable < Sequel::Model(:sti_votables)
98
+ plugin :single_table_inheritance, :type
99
+ plugin :ballot_votable
100
+ end
101
+
102
+ class SequelChildOfStiVotable < SequelStiVotable
103
+ end
104
+
105
+ class SequelStiNotVotable < Sequel::Model(:sti_not_votables)
106
+ plugin :single_table_inheritance, :type
107
+ end
108
+
109
+ class SequelVotableChildOfStiNotVotable < SequelStiNotVotable
110
+ plugin :ballot_votable
111
+ end
112
+
113
+ class SequelVotableCache < Sequel::Model(:votable_caches)
114
+ plugin :ballot_votable
115
+ end
116
+
117
+ class SequelABoringClass
118
+ end
119
+
120
+ class Minitest::SequelSpec < Minitest::HooksSpec
121
+ parallelize_me! unless RUBY_ENGINE == 'jruby'
122
+
123
+ register_spec_type(/Sequel/, self)
124
+
125
+ def around
126
+ Sequel::Model.db.transaction(rollback: :always, auto_savepoint: true) { super }
127
+ end
128
+
129
+ def capture_sql
130
+ SQLLogger.clear
131
+ yield
132
+ SQLLogger.sqls.dup
133
+ ensure
134
+ SQLLogger.clear
135
+ end
136
+
137
+ def votable_dataset(votable)
138
+ votable.ballots_for_dataset
139
+ end
140
+
141
+ def voter_dataset(voter)
142
+ voter.ballots_by_dataset
143
+ end
144
+
145
+ def ballot_type_name(item)
146
+ Ballot::Sequel.type_name(item)
147
+ end
148
+
149
+ let(:voter) { SequelVoter.create(name: 'I can vote!') }
150
+ let(:voter2) { SequelVoter.create(name: 'I, too, can vote!') }
151
+ let(:not_voter) { SequelNotVoter.create(name: 'I cannot vote!') }
152
+
153
+ let(:votable) { SequelVotable.create(name: 'a votable model') }
154
+ let(:votable2) { SequelVotable.create(name: 'a second votable model') }
155
+ let(:votable_cache) { SequelVotableCache.create(name: 'a votable model with caching') }
156
+ let(:sti_votable) { SequelStiVotable.create(name: 'a votable STI model') }
157
+ let(:child_of_sti_votable) {
158
+ SequelChildOfStiVotable.create(name: 'a votable STI child model')
159
+ }
160
+ let(:votable_child_of_sti_not_votable) {
161
+ SequelVotableChildOfStiNotVotable.create(name: 'a votable STI child of a non-votable')
162
+ }
163
+ let(:not_votable) { SequelNotVotable.create(name: 'a non-votable model') }
164
+ end