/
reputation_rule.rb
107 lines (89 loc) · 2.94 KB
/
reputation_rule.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
class ReputationRule < ActiveRecord::Base
has_many :intermediate_values, :class_name => 'ReputationIntermediateValue', :foreign_key => 'rule_id'
has_many :behaviours, :class_name => 'ReputationBehaviour', :foreign_key => 'rule_id'
serialize :constants, Hash
serialize :aggregate_constants, Hash
validates_presence_of :name
validates_uniqueness_of :name
validates_numericality_of :weight, :only_integer => true, :greater_than => 0
attr_accessible :name, :kind, :weight, :function, :constants, :aggregate_function, :aggregate_constants
attr_readonly :kind
def initialize(args = {})
options = {
:weight => 1,
:kind => 'singular',
:function => 'linear',
:constants => { :m => 1 },
:aggregate_function => 'linear',
:aggregate_constants => { :m => 1 }
}.merge(args)
super options
end
# Return the total score for a certain user
#
# @param [User]
def self.value_for(user)
all.inject(0){|total,r| total + r.value_for( user ) }
end
# Lookup the weighting relative to all other rules
#
def normalized_weighting
BigDecimal(weight.to_s) / ReputationRule.sum('weight')
end
# Calculate the score for a certain user
#
# @param [User]
def value_for(user)
behaviour = user.behaviours.find_by_rule_id id
if behaviour
case kind
when 'singular'
f(behaviour.metric) * normalized_weighting
when 'collection'
ivo = intermediate_values.find_by_user_id_and_name(user.id,kind)
iv = ivo ? ivo.value : 0
aggregate_f(
f(behaviour.metric) + iv
) * normalized_weighting
end
else
0
end
end
# Return the function object defined by :function and :constants
#
# @return [Reputation::Functions::Linear, Reputation::Functions::Step, Reputation::Functions::GeneralisedLogisticCurve]
def function
build_function(super, constants)
end
# Return the aggregate function object defined by :aggregate_function and :aggregate_constants
#
# @return [Reputation::Functions::Linear, Reputation::Functions::Step, Reputation::Functions::GeneralisedLogisticCurve]
def aggregate_function
build_function(super, aggregate_constants)
end
def recalculate_intermediate_values_for(user) # :nodoc:
behaviour = user.behaviours.find_by_rule_id(self.id)
if behaviour
case kind
when 'collection'
iv = intermediate_values.find_by_user_id_and_name(user.id,kind) || intermediate_values.build(:user => user, :name => kind)
iv.value += f(behaviour.metric)
iv.save!
end
end
end
private
# Delegate f to the function#f
def f(*args)
function.f(*args)
end
# Delegate aggregate_f to the aggregate_function#f
def aggregate_f(*args)
aggregate_function.f(*args)
end
def build_function(name, constants)
klass = "Reputation::Functions::#{name.to_s.camelcase}".constantize
klass.new(constants)
end
end