Proposals hot_score

This commit is contained in:
kikito
2015-09-14 20:37:32 +02:00
parent 47c95078f2
commit 8f8afdfd62
3 changed files with 107 additions and 7 deletions

View File

@@ -27,6 +27,8 @@ class Proposal < ActiveRecord::Base
before_validation :sanitize_tag_list
before_validation :set_responsible_name
before_save :calculate_hot_score, :calculate_confidence_score
scope :for_render, -> { includes(:tags) }
scope :sort_by_hot_score , -> { order(hot_score: :desc) }
scope :sort_by_confidence_score , -> { order(confidence_score: :desc) }
@@ -87,6 +89,22 @@ class Proposal < ActiveRecord::Base
"#{Setting.value_for("proposal_code_prefix")}-#{created_at.strftime('%Y-%M')}-#{id}"
end
def after_commented
save # updates the hot_score because there is a before_save
end
def calculate_hot_score
self.hot_score = ScoreCalculator.hot_score(created_at,
cached_votes_up,
cached_votes_up,
comments_count)
end
def calculate_confidence_score
self.confidence_score = ScoreCalculator.confidence_score(cached_votes_up,
cached_votes_up)
end
def self.title_max_length
@@title_max_length ||= self.columns.find { |c| c.name == 'title' }.limit || 80
end
@@ -126,6 +144,7 @@ class Proposal < ActiveRecord::Base
self.responsible_name = author.document_number
end
end
private
def validate_description_length

View File

@@ -4,16 +4,16 @@ module ScoreCalculator
COMMENT_WEIGHT = 1.0/20 # 1 positive vote / x comments
TIME_UNIT = 12.hours.to_f
def self.hot_score(date, votes_total, votes_up, comments_count)
total = votes_total + COMMENT_WEIGHT * comments_count
ups = votes_up + COMMENT_WEIGHT * comments_count
def self.hot_score(date, votes_total, votes_up, comments_count)
total = (votes_total + COMMENT_WEIGHT * comments_count).to_f
ups = (votes_up + COMMENT_WEIGHT * comments_count).to_f
downs = total - ups
score = ups - downs
order = Math.log([score.abs, 1].max, 10)
sign = (score <=> 0).to_f
offset = Math.log([score.abs, 1].max, 10) * (ups / [total, 1].max)
sign = score <=> 0
seconds = ((date || Time.now) - EPOC).to_f
(((order * sign) + (seconds/TIME_UNIT)) * 10000000).round
(((offset * sign) + (seconds/TIME_UNIT)) * 10000000).round
end
def self.confidence_score(votes_total, votes_up)

View File

@@ -142,4 +142,85 @@ describe Proposal do
end
end
end
end
describe '#hot_score' do
let(:now) { Time.now }
it "increases for newer proposals" do
old = create(:proposal, :with_hot_score, created_at: now - 1.day)
new = create(:proposal, :with_hot_score, created_at: now)
expect(new.hot_score).to be > old.hot_score
end
it "increases for proposals with more comments" do
more_comments = create(:proposal, :with_hot_score, created_at: now, comments_count: 25)
less_comments = create(:proposal, :with_hot_score, created_at: now, comments_count: 1)
expect(more_comments.hot_score).to be > less_comments.hot_score
end
it "increases for proposals with more positive votes" do
more_likes = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 5)
less_likes = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 1)
expect(more_likes.hot_score).to be > less_likes.hot_score
end
it "increases for proposals with more confidence" do
more_confidence = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 700)
less_confidence = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 9)
expect(more_confidence.hot_score).to be > less_confidence.hot_score
end
it "decays in older proposals, even if they have more votes" do
older_more_voted = create(:proposal, :with_hot_score, created_at: now - 2.days, cached_votes_up: 900)
new_less_voted = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 9)
expect(new_less_voted.hot_score).to be > older_more_voted.hot_score
end
describe 'actions which affect it' do
let(:proposal) { create(:proposal, :with_hot_score) }
it "increases with votes" do
previous = proposal.hot_score
5.times { proposal.register_vote(create(:user, verified_at: Time.now), true) }
expect(previous).to be < proposal.reload.hot_score
end
it "increases with comments" do
previous = proposal.hot_score
25.times{ Comment.create(user: create(:user), commentable: proposal, body: 'foobarbaz') }
expect(previous).to be < proposal.reload.hot_score
end
end
end
describe "#confidence_score" do
it "takes into account votes" do
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 100)
expect(proposal.confidence_score).to eq(10000)
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 0)
expect(proposal.confidence_score).to eq(0)
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 75)
expect(proposal.confidence_score).to eq(7500)
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 750)
expect(proposal.confidence_score).to eq(75000)
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 10)
expect(proposal.confidence_score).to eq(1000)
end
describe 'actions which affect it' do
let(:proposal) { create(:proposal, :with_confidence_score) }
it "increases with like" do
previous = proposal.confidence_score
5.times { proposal.register_vote(create(:user, verified_at: Time.now), true) }
expect(previous).to be < proposal.confidence_score
end
end
end
end