voting 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3 -0
  3. data/LICENSE +21 -0
  4. data/README.md +229 -0
  5. data/lib/generators/voting/install_generator.rb +19 -0
  6. data/lib/generators/voting/templates/db/migrate/create_voting_tables.rb +35 -0
  7. data/lib/voting.rb +10 -0
  8. data/lib/voting/models/voting/extension.rb +85 -0
  9. data/lib/voting/models/voting/vote.rb +45 -0
  10. data/lib/voting/models/voting/voting.rb +73 -0
  11. data/lib/voting/version.rb +5 -0
  12. data/spec/factories/article.rb +5 -0
  13. data/spec/factories/author.rb +5 -0
  14. data/spec/factories/category.rb +5 -0
  15. data/spec/factories/comment.rb +5 -0
  16. data/spec/factories/voting/vote.rb +8 -0
  17. data/spec/factories/voting/voting.rb +9 -0
  18. data/spec/models/extension/after_save_spec.rb +37 -0
  19. data/spec/models/extension/as_spec.rb +26 -0
  20. data/spec/models/extension/down_spec.rb +26 -0
  21. data/spec/models/extension/order_by_voting_spec.rb +94 -0
  22. data/spec/models/extension/up_spec.rb +26 -0
  23. data/spec/models/extension/vote_for_spec.rb +26 -0
  24. data/spec/models/extension/vote_spec.rb +26 -0
  25. data/spec/models/extension/voted_question_spec.rb +38 -0
  26. data/spec/models/extension/voted_records_spec.rb +12 -0
  27. data/spec/models/extension/voted_spec.rb +40 -0
  28. data/spec/models/extension/votes_records_spec.rb +12 -0
  29. data/spec/models/extension/votes_spec.rb +40 -0
  30. data/spec/models/extension/voting_records_spec.rb +12 -0
  31. data/spec/models/extension/voting_spec.rb +40 -0
  32. data/spec/models/extension/voting_warm_up_spec.rb +115 -0
  33. data/spec/models/vote/create_spec.rb +273 -0
  34. data/spec/models/vote/vote_for_spec.rb +40 -0
  35. data/spec/models/vote_spec.rb +27 -0
  36. data/spec/models/voting/update_voting_spec.rb +28 -0
  37. data/spec/models/voting/values_data_spec.rb +24 -0
  38. data/spec/models/voting_spec.rb +26 -0
  39. data/spec/rails_helper.rb +11 -0
  40. data/spec/support/common.rb +22 -0
  41. data/spec/support/database_cleaner.rb +19 -0
  42. data/spec/support/db/migrate/create_articles_table.rb +7 -0
  43. data/spec/support/db/migrate/create_authors_table.rb +7 -0
  44. data/spec/support/db/migrate/create_categories_table.rb +9 -0
  45. data/spec/support/db/migrate/create_comments_table.rb +7 -0
  46. data/spec/support/factory_bot.rb +9 -0
  47. data/spec/support/migrate.rb +11 -0
  48. data/spec/support/models/article.rb +7 -0
  49. data/spec/support/models/author.rb +5 -0
  50. data/spec/support/models/category.rb +5 -0
  51. data/spec/support/models/comment.rb +5 -0
  52. data/spec/support/shared_context/with_database_records.rb +22 -0
  53. data/spec/support/shoulda.rb +10 -0
  54. metadata +257 -0
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+ require 'support/shared_context/with_database_records'
5
+
6
+ RSpec.describe Voting::Extension, ':voted' do
7
+ include_context 'with_database_records'
8
+
9
+ context 'with no scope' do
10
+ it 'returns votes made by this author' do
11
+ expect(author_1.voted).to match_array [vote_1, vote_4]
12
+ end
13
+ end
14
+
15
+ context 'with scope' do
16
+ it 'returns scoped votes made by this author' do
17
+ expect(author_1.voted(scope: category)).to eq [vote_7]
18
+ end
19
+ end
20
+
21
+ context 'when destroy author' do
22
+ it 'destroys votes of that author' do
23
+ expect(Voting::Vote.where(author: author_1).count).to eq 3
24
+
25
+ author_1.destroy!
26
+
27
+ expect(Voting::Vote.where(author: author_1).count).to eq 0
28
+ end
29
+ end
30
+
31
+ context 'when destroy resource voted by author' do
32
+ it 'destroys votes of that resource' do
33
+ expect(Voting::Vote.where(resource: comment_1).count).to eq 5
34
+
35
+ comment_1.destroy!
36
+
37
+ expect(Voting::Vote.where(resource: comment_1).count).to eq 0
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+ require 'support/shared_context/with_database_records'
5
+
6
+ RSpec.describe Voting::Extension, '.votes_records' do
7
+ include_context 'with_database_records'
8
+
9
+ it 'returns all votes that this resource received' do
10
+ expect(comment_1.votes_records).to match_array [vote_1, vote_2, vote_3, vote_7, vote_8]
11
+ end
12
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+ require 'support/shared_context/with_database_records'
5
+
6
+ RSpec.describe Voting::Extension, ':votes' do
7
+ include_context 'with_database_records'
8
+
9
+ context 'with no scope' do
10
+ it 'returns votes that this resource received' do
11
+ expect(comment_1.votes).to match_array [vote_1, vote_2, vote_3]
12
+ end
13
+ end
14
+
15
+ context 'with scope' do
16
+ it 'returns scoped votes that this resource received' do
17
+ expect(comment_1.votes(scope: category)).to match_array [vote_7, vote_8]
18
+ end
19
+ end
20
+
21
+ context 'when destroy author' do
22
+ it 'destroys votes of that author' do
23
+ expect(Voting::Vote.where(author: author_1).count).to eq 3
24
+
25
+ author_1.destroy!
26
+
27
+ expect(Voting::Vote.where(author: author_1).count).to eq 0
28
+ end
29
+ end
30
+
31
+ context 'when destroy resource' do
32
+ it 'destroys votes of that resource' do
33
+ expect(Voting::Vote.where(resource: comment_1).count).to eq 5
34
+
35
+ comment_1.destroy!
36
+
37
+ expect(Voting::Vote.where(resource: comment_1).count).to eq 0
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+ require 'support/shared_context/with_database_records'
5
+
6
+ RSpec.describe Voting::Extension, '.voting' do
7
+ include_context 'with_database_records'
8
+
9
+ it 'returns all voting of this resource' do
10
+ expect(comment_1.voting_records).to match_array Voting::Voting.where(resource: comment_1)
11
+ end
12
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+ require 'support/shared_context/with_database_records'
5
+
6
+ RSpec.describe Voting::Extension, '.voting' do
7
+ include_context 'with_database_records'
8
+
9
+ context 'with no scope' do
10
+ it 'returns voting record' do
11
+ expect(comment_1.voting).to eq Voting::Voting.find_by(resource: comment_1, scopeable: nil)
12
+ end
13
+ end
14
+
15
+ context 'with scope' do
16
+ it 'returns scoped voting record' do
17
+ expect(comment_1.voting(scope: category)).to eq Voting::Voting.find_by(resource: comment_1, scopeable: category)
18
+ end
19
+ end
20
+
21
+ context 'when destroy author' do
22
+ it 'does not destroy resource voting' do
23
+ expect(Voting::Voting.where(resource: comment_1).count).to eq 2
24
+
25
+ author_1.destroy!
26
+
27
+ expect(Voting::Voting.where(resource: comment_1).count).to eq 2
28
+ end
29
+ end
30
+
31
+ context 'when destroy resource' do
32
+ it 'destroys resource voting too' do
33
+ expect(Voting::Voting.where(resource: comment_1).count).to eq 2
34
+
35
+ comment_1.destroy!
36
+
37
+ expect(Voting::Voting.where(resource: comment_1).count).to eq 0
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe Voting::Extension, '.voting_warm_up' do
6
+ context 'when scoping is nil' do
7
+ context 'when update is made' do
8
+ let!(:record) { create :comment }
9
+ let!(:voting) { ::Voting::Voting.find_by resource: record }
10
+
11
+ it 'creates the cache' do
12
+ record.voting_warm_up scoping: nil
13
+
14
+ expect(::Voting::Voting.all).to eq [voting]
15
+ end
16
+
17
+ it 'returns the cached object' do
18
+ expect(record.voting_warm_up).to eq voting
19
+ end
20
+ end
21
+
22
+ context 'when record does not exist' do
23
+ let!(:record) { create :comment }
24
+
25
+ before { ::Voting::Voting.destroy_all }
26
+
27
+ it 'creates the cache' do
28
+ record.voting_warm_up scoping: nil
29
+
30
+ expect(::Voting::Voting.all.map(&:resource)).to eq [record]
31
+ end
32
+
33
+ it 'returns the cached object' do
34
+ expect(record.voting_warm_up).to eq ::Voting::Voting.last
35
+ end
36
+ end
37
+ end
38
+
39
+ context 'when scoping is not nil' do
40
+ context 'when update is made' do
41
+ let!(:category_1) { create :category }
42
+ let!(:category_2) { create :category }
43
+ let!(:record) { create :article, categories: [category_1, category_2] }
44
+
45
+ it 'creates the cache' do
46
+ record.voting_warm_up scoping: :categories
47
+
48
+ votings = ::Voting::Voting.all
49
+
50
+ expect(votings.map(&:scopeable)).to match_array [category_1, category_2]
51
+ expect(votings.map(&:resource)).to match_array [record, record]
52
+ end
53
+
54
+ it 'returns the cached objects' do
55
+ expect(record.voting_warm_up(scoping: :categories)).to eq ::Voting::Voting.all
56
+ end
57
+ end
58
+
59
+ context 'when record does not exist' do
60
+ let!(:category_1) { create :category }
61
+ let!(:category_2) { create :category }
62
+ let!(:record) { create :article, categories: [category_1, category_2] }
63
+
64
+ before { ::Voting::Voting.destroy_all }
65
+
66
+ it 'creates the cache' do
67
+ record.voting_warm_up scoping: :categories
68
+
69
+ votings = ::Voting::Voting.all
70
+
71
+ expect(votings.map(&:scopeable)).to match_array [category_1, category_2]
72
+ expect(votings.map(&:resource)).to match_array [record, record]
73
+ end
74
+
75
+ it 'returns the cached objects' do
76
+ expect(record.voting_warm_up(scoping: :categories)).to eq ::Voting::Voting.all
77
+ end
78
+ end
79
+
80
+ context 'when a non existent scoping is given' do
81
+ let!(:record) { create :article }
82
+
83
+ it 'returns an empty array' do
84
+ expect(record.voting_warm_up(scoping: :missing)).to eq []
85
+ end
86
+ end
87
+
88
+ context 'when scoping is given inside array' do
89
+ let!(:category) { create :category }
90
+ let!(:record) { create :article, categories: [category] }
91
+
92
+ it 'returns the cache' do
93
+ expect(record.voting_warm_up(scoping: [:categories])).to eq ::Voting::Voting.all
94
+ end
95
+ end
96
+
97
+ context 'when scoping is given inside multiple arrays' do
98
+ let!(:category) { create :category }
99
+ let!(:record) { create :article, categories: [category] }
100
+
101
+ it 'returns the cache' do
102
+ expect(record.voting_warm_up(scoping: [[:categories]])).to eq ::Voting::Voting.all
103
+ end
104
+ end
105
+
106
+ context 'when scoping is given with nil value together' do
107
+ let!(:category) { create :category }
108
+ let!(:record) { create :article, categories: [category] }
109
+
110
+ it 'returns the cache' do
111
+ expect(record.voting_warm_up(scoping: [[:categories, nil], nil])).to eq ::Voting::Voting.all
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,273 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe Voting::Vote, ':create' do
6
+ let!(:author) { create :author }
7
+
8
+ context 'with no scopeable' do
9
+ let!(:resource) { create :comment }
10
+
11
+ context 'when vote does not exist yet' do
12
+ it 'creates a vote entry' do
13
+ described_class.create author: author, resource: resource, value: 1
14
+
15
+ vote = described_class.last
16
+
17
+ expect(vote.author).to eq author
18
+ expect(vote.negative).to eq 0
19
+ expect(vote.positive).to eq 1
20
+ expect(vote.resource).to eq resource
21
+ end
22
+
23
+ it 'creates a voting entry' do
24
+ described_class.create author: author, resource: resource, value: 1
25
+
26
+ voting = Voting::Voting.last
27
+
28
+ expect(voting.estimate).to eq 0.2065432914738929
29
+ expect(voting.negative).to eq 0
30
+ expect(voting.positive).to eq 1
31
+ expect(voting.resource).to eq resource
32
+ end
33
+ end
34
+
35
+ context 'when vote already exists by other author' do
36
+ let!(:author_other) { create :author }
37
+
38
+ before { described_class.create author: author_other, resource: resource, value: -1 }
39
+
40
+ it 'creates one more vote entry' do
41
+ described_class.create author: author, resource: resource, value: 1
42
+
43
+ votes = described_class.all.order('created_at asc')
44
+
45
+ expect(votes.size).to eq 2
46
+
47
+ vote = votes[0]
48
+
49
+ expect(vote.author).to eq author_other
50
+ expect(vote.negative).to eq 1
51
+ expect(vote.positive).to eq 0
52
+ expect(vote.resource).to eq resource
53
+
54
+ vote = votes[1]
55
+
56
+ expect(vote.author).to eq author
57
+ expect(vote.negative).to eq 0
58
+ expect(vote.positive).to eq 1
59
+ expect(vote.resource).to eq resource
60
+ end
61
+
62
+ it 'updates the unique voting entry' do
63
+ described_class.create author: author, resource: resource, value: 1
64
+
65
+ voting = Voting::Voting.all
66
+
67
+ expect(voting.size).to eq 1
68
+
69
+ expect(voting[0].estimate).to eq 0.1711859764448097
70
+ expect(voting[0].negative).to eq 1
71
+ expect(voting[0].positive).to eq 1
72
+ expect(voting[0].resource).to eq resource
73
+ end
74
+ end
75
+
76
+ context 'when vote already exists by the same author' do
77
+ before { described_class.create author: author, resource: resource, value: -1 }
78
+
79
+ context 'when author vote with a different rate' do
80
+ it 'changes the actual vote' do
81
+ described_class.create author: author, resource: resource, value: 1
82
+
83
+ votes = described_class.all.order('created_at asc')
84
+
85
+ expect(votes.size).to eq 1
86
+
87
+ expect(votes[0].author).to eq author
88
+ expect(votes[0].negative).to eq 0
89
+ expect(votes[0].positive).to eq 1
90
+ expect(votes[0].resource).to eq resource
91
+ end
92
+
93
+ it 'updates the unique voting entry' do
94
+ described_class.create author: author, resource: resource, value: 1
95
+
96
+ voting = Voting::Voting.all
97
+
98
+ expect(voting.size).to eq 1
99
+
100
+ expect(voting[0].estimate).to eq 0.2065432914738929
101
+ expect(voting[0].negative).to eq 0
102
+ expect(voting[0].positive).to eq 1
103
+ expect(voting[0].resource).to eq resource
104
+ end
105
+ end
106
+
107
+ context 'when author vote with the same rate' do
108
+ it 'makes the vote be zero' do
109
+ described_class.create author: author, resource: resource, value: -1
110
+
111
+ votes = described_class.all.order('created_at asc')
112
+
113
+ expect(votes.size).to eq 1
114
+
115
+ expect(votes[0].author).to eq author
116
+ expect(votes[0].negative).to eq 0
117
+ expect(votes[0].positive).to eq 0
118
+ expect(votes[0].resource).to eq resource
119
+ end
120
+
121
+ it 'updates the unique voting entry' do
122
+ described_class.create author: author, resource: resource, value: -1
123
+
124
+ voting = Voting::Voting.all
125
+
126
+ expect(voting.size).to eq 1
127
+
128
+ expect(voting[0].estimate).to eq 0
129
+ expect(voting[0].negative).to eq 0
130
+ expect(voting[0].positive).to eq 0
131
+ expect(voting[0].resource).to eq resource
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ context 'with scopeable' do
138
+ let!(:scopeable) { create :category }
139
+ let!(:resource) { create :article }
140
+
141
+ context 'when vote does not exist yet' do
142
+ it 'creates a vote entry' do
143
+ described_class.create author: author, resource: resource, scopeable: scopeable, value: 1
144
+
145
+ vote = described_class.last
146
+
147
+ expect(vote.author).to eq author
148
+ expect(vote.negative).to eq 0
149
+ expect(vote.positive).to eq 1
150
+ expect(vote.resource).to eq resource
151
+ expect(vote.scopeable).to eq scopeable
152
+ end
153
+
154
+ it 'creates a voting entry' do
155
+ described_class.create author: author, resource: resource, scopeable: scopeable, value: 1
156
+
157
+ voting = Voting::Voting.last
158
+
159
+ expect(voting.estimate).to eq 0.2065432914738929
160
+ expect(voting.negative).to eq 0
161
+ expect(voting.positive).to eq 1
162
+ expect(voting.resource).to eq resource
163
+ expect(voting.scopeable).to eq scopeable
164
+ end
165
+ end
166
+
167
+ context 'when vote already exists by other author' do
168
+ let!(:author_other) { create :author }
169
+
170
+ before { described_class.create author: author_other, resource: resource, scopeable: scopeable, value: -1 }
171
+
172
+ it 'creates one more vote entry' do
173
+ described_class.create author: author, resource: resource, scopeable: scopeable, value: 1
174
+
175
+ votes = described_class.all.order('created_at asc')
176
+
177
+ expect(votes.size).to eq 2
178
+
179
+ vote = votes[0]
180
+
181
+ expect(vote.author).to eq author_other
182
+ expect(vote.negative).to eq 1
183
+ expect(vote.positive).to eq 0
184
+ expect(vote.resource).to eq resource
185
+ expect(vote.scopeable).to eq scopeable
186
+
187
+ vote = votes[1]
188
+
189
+ expect(vote.author).to eq author
190
+ expect(vote.negative).to eq 0
191
+ expect(vote.positive).to eq 1
192
+ expect(vote.resource).to eq resource
193
+ expect(vote.scopeable).to eq scopeable
194
+ end
195
+
196
+ it 'updates the unique voting entry' do
197
+ described_class.create author: author, resource: resource, scopeable: scopeable, value: 1
198
+
199
+ voting = Voting::Voting.all
200
+
201
+ expect(voting.size).to eq 1
202
+
203
+ expect(voting[0].estimate).to eq 0.1711859764448097
204
+ expect(voting[0].negative).to eq 1
205
+ expect(voting[0].positive).to eq 1
206
+ expect(voting[0].resource).to eq resource
207
+ expect(voting[0].scopeable).to eq scopeable
208
+ end
209
+ end
210
+
211
+ context 'when vote already exists by the same author' do
212
+ before { described_class.create author: author, resource: resource, scopeable: scopeable, value: -1 }
213
+
214
+ context 'when author vote with a different rate' do
215
+ it 'changes the actual vote' do
216
+ described_class.create author: author, resource: resource, scopeable: scopeable, value: 1
217
+
218
+ votes = described_class.all.order('created_at asc')
219
+
220
+ expect(votes.size).to eq 1
221
+
222
+ expect(votes[0].author).to eq author
223
+ expect(votes[0].negative).to eq 0
224
+ expect(votes[0].positive).to eq 1
225
+ expect(votes[0].resource).to eq resource
226
+ expect(votes[0].scopeable).to eq scopeable
227
+ end
228
+
229
+ it 'updates the unique voting entry' do
230
+ described_class.create author: author, resource: resource, scopeable: scopeable, value: 1
231
+
232
+ voting = Voting::Voting.all
233
+
234
+ expect(voting.size).to eq 1
235
+
236
+ expect(voting[0].estimate).to eq 0.2065432914738929
237
+ expect(voting[0].negative).to eq 0
238
+ expect(voting[0].positive).to eq 1
239
+ expect(voting[0].resource).to eq resource
240
+ expect(voting[0].scopeable).to eq scopeable
241
+ end
242
+ end
243
+
244
+ context 'when author vote with the same rate' do
245
+ it 'makes the vote be zero' do
246
+ described_class.create author: author, resource: resource, scopeable: scopeable, value: -1
247
+
248
+ votes = described_class.all.order('created_at asc')
249
+
250
+ expect(votes.size).to eq 1
251
+
252
+ expect(votes[0].author).to eq author
253
+ expect(votes[0].negative).to eq 0
254
+ expect(votes[0].positive).to eq 0
255
+ expect(votes[0].resource).to eq resource
256
+ end
257
+
258
+ it 'updates the unique voting entry' do
259
+ described_class.create author: author, resource: resource, scopeable: scopeable, value: -1
260
+
261
+ voting = Voting::Voting.all
262
+
263
+ expect(voting.size).to eq 1
264
+
265
+ expect(voting[0].estimate).to eq 0
266
+ expect(voting[0].negative).to eq 0
267
+ expect(voting[0].positive).to eq 0
268
+ expect(voting[0].resource).to eq resource
269
+ end
270
+ end
271
+ end
272
+ end
273
+ end