activerecord-reputation-system 1.5.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +29 -198
- data/lib/activerecord-reputation-system.rb +1 -0
- data/lib/reputation_system.rb +6 -6
- data/lib/reputation_system/base.rb +16 -6
- data/lib/reputation_system/{evaluation.rb → evaluation_methods.rb} +32 -13
- data/lib/reputation_system/models/evaluation.rb +73 -0
- data/lib/reputation_system/models/reputation.rb +211 -0
- data/lib/reputation_system/models/reputation_message.rb +49 -0
- data/lib/reputation_system/network.rb +2 -0
- data/lib/reputation_system/query_builder.rb +4 -4
- data/lib/reputation_system/{reputation.rb → reputation_methods.rb} +5 -15
- data/lib/reputation_system/{scope.rb → scope_methods.rb} +2 -2
- data/lib/reputation_system/version.rb +1 -1
- data/spec/reputation_system/base_spec.rb +46 -6
- data/spec/reputation_system/{evaluation_spec.rb → evaluation_methods_spec.rb} +52 -9
- data/spec/{models/rs_evaluation_spec.rb → reputation_system/models/evaluation_spec.rb} +8 -8
- data/spec/{models/rs_reputation_message_spec.rb → reputation_system/models/reputation_message_spec.rb} +10 -10
- data/spec/reputation_system/models/reputation_spec.rb +136 -0
- data/spec/reputation_system/{reputation_spec.rb → reputation_methods_spec.rb} +2 -2
- data/spec/reputation_system/{scope_spec.rb → scope_methods_spec.rb} +0 -0
- data/spec/spec_helper.rb +2 -4
- metadata +15 -14
- data/lib/models/rs_evaluation.rb +0 -69
- data/lib/models/rs_reputation.rb +0 -204
- data/lib/models/rs_reputation_message.rb +0 -46
- data/spec/models/rs_reputation_spec.rb +0 -119
data/lib/models/rs_evaluation.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# Copyright 2012 Twitter, Inc
|
3
|
-
#
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
-
# you may not use this file except in compliance with the License.
|
6
|
-
# You may obtain a copy of the License at
|
7
|
-
#
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
-
#
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
-
# See the License for the specific language governing permissions and
|
14
|
-
# limitations under the License.
|
15
|
-
##
|
16
|
-
|
17
|
-
class RSEvaluation < ActiveRecord::Base
|
18
|
-
belongs_to :source, :polymorphic => true
|
19
|
-
belongs_to :target, :polymorphic => true
|
20
|
-
has_one :sent_messages, :as => :sender, :class_name => 'RSReputationMessage', :dependent => :destroy
|
21
|
-
|
22
|
-
attr_accessible :reputation_name, :value, :source, :source_id, :source_type, :target, :target_id, :target_type
|
23
|
-
|
24
|
-
# Sets an appropriate source type in case of Single Table Inheritance.
|
25
|
-
before_validation :set_source_type_for_sti
|
26
|
-
|
27
|
-
# the same source cannot evaluate the same target more than once.
|
28
|
-
validates_uniqueness_of :source_id, :scope => [:reputation_name, :source_type, :target_id, :target_type]
|
29
|
-
validate :source_must_be_defined_for_reputation_in_network
|
30
|
-
|
31
|
-
def self.find_by_reputation_name_and_source_and_target(reputation_name, source, target)
|
32
|
-
source_type = get_source_type_for_sti(source, target.class.name, reputation_name)
|
33
|
-
RSEvaluation.find(:first,
|
34
|
-
:conditions => {:reputation_name => reputation_name.to_s,
|
35
|
-
:source_id => source.id,
|
36
|
-
:source_type => source_type,
|
37
|
-
:target_id => target.id,
|
38
|
-
:target_type => target.class.name
|
39
|
-
})
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.create_evaluation(reputation_name, value, source, target)
|
43
|
-
RSEvaluation.create!(:reputation_name => reputation_name.to_s, :value => value,
|
44
|
-
:source_id => source.id, :source_type => source.class.name,
|
45
|
-
:target_id => target.id, :target_type => target.class.name)
|
46
|
-
end
|
47
|
-
|
48
|
-
protected
|
49
|
-
|
50
|
-
def self.get_source_type_for_sti(source, target_type, reputation_name)
|
51
|
-
valid_source_type = ReputationSystem::Network.get_reputation_def(target_type, reputation_name)[:source].to_s.camelize
|
52
|
-
temp = source.class
|
53
|
-
while temp && valid_source_type != temp.name && temp.name != "ActiveRecord::Base"
|
54
|
-
temp = temp.superclass
|
55
|
-
end
|
56
|
-
temp ? temp.name : nil
|
57
|
-
end
|
58
|
-
|
59
|
-
def set_source_type_for_sti
|
60
|
-
temp = self.class.get_source_type_for_sti(source, target_type, reputation_name)
|
61
|
-
self.source_type = temp if temp
|
62
|
-
end
|
63
|
-
|
64
|
-
def source_must_be_defined_for_reputation_in_network
|
65
|
-
unless source_type == ReputationSystem::Network.get_reputation_def(target_type, reputation_name)[:source].to_s.camelize
|
66
|
-
errors.add(:source_type, "#{source_type} is not source of #{reputation_name} reputation")
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
data/lib/models/rs_reputation.rb
DELETED
@@ -1,204 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# Copyright 2012 Twitter, Inc
|
3
|
-
#
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
-
# you may not use this file except in compliance with the License.
|
6
|
-
# You may obtain a copy of the License at
|
7
|
-
#
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
-
#
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
-
# See the License for the specific language governing permissions and
|
14
|
-
# limitations under the License.
|
15
|
-
##
|
16
|
-
|
17
|
-
class RSReputation < ActiveRecord::Base
|
18
|
-
belongs_to :target, :polymorphic => true
|
19
|
-
has_many :received_messages, :class_name => 'RSReputationMessage', :foreign_key => :receiver_id, :dependent => :destroy do
|
20
|
-
def from(sender)
|
21
|
-
self.find_by_sender_id_and_sender_type(sender.id, sender.class.to_s)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
has_many :sent_messages, :as => :sender, :class_name => 'RSReputationMessage', :dependent => :destroy
|
25
|
-
|
26
|
-
attr_accessible :reputation_name, :value, :aggregated_by, :active, :target, :target_id, :target_type, :received_messages
|
27
|
-
|
28
|
-
before_validation :set_target_type_for_sti
|
29
|
-
before_save :change_zero_value_in_case_of_product_process
|
30
|
-
|
31
|
-
VALID_PROCESSES = ['sum', 'average', 'product']
|
32
|
-
validates_inclusion_of :aggregated_by, :in => VALID_PROCESSES, :message => "Value chosen for aggregated_by is not valid process"
|
33
|
-
validates_uniqueness_of :reputation_name, :scope => [:target_id, :target_type]
|
34
|
-
|
35
|
-
def self.find_by_reputation_name_and_target(reputation_name, target)
|
36
|
-
target_type = get_target_type_for_sti(target, reputation_name)
|
37
|
-
RSReputation.find_by_reputation_name_and_target_id_and_target_type(reputation_name.to_s, target.id, target_type)
|
38
|
-
end
|
39
|
-
|
40
|
-
# All external access to reputation should use this since they are created lazily.
|
41
|
-
def self.find_or_create_reputation(reputation_name, target, process)
|
42
|
-
rep = find_by_reputation_name_and_target(reputation_name, target)
|
43
|
-
rep ? rep : create_reputation(reputation_name, target, process)
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.create_reputation(reputation_name, target, process)
|
47
|
-
create_options = {:reputation_name => reputation_name.to_s, :target_id => target.id,
|
48
|
-
:target_type => target.class.name, :aggregated_by => process.to_s}
|
49
|
-
default_value = ReputationSystem::Network.get_reputation_def(target.class.name, reputation_name)[:init_value]
|
50
|
-
create_options.merge!(:value => default_value) if default_value
|
51
|
-
rep = create(create_options)
|
52
|
-
initialize_reputation_value(rep, target, process)
|
53
|
-
end
|
54
|
-
|
55
|
-
def self.update_reputation_value_with_new_source(rep, source, weight, process)
|
56
|
-
weight ||= 1 # weight is 1 by default.
|
57
|
-
size = rep.received_messages.size
|
58
|
-
valueBeforeUpdate = size > 0 ? rep.value : nil
|
59
|
-
newValue = source.value
|
60
|
-
case process.to_sym
|
61
|
-
when :sum
|
62
|
-
rep.value += (newValue * weight)
|
63
|
-
when :average
|
64
|
-
rep.value = (rep.value * size + newValue * weight) / (size + 1)
|
65
|
-
when :product
|
66
|
-
rep.value *= (newValue * weight)
|
67
|
-
else
|
68
|
-
raise ArgumentError, "#{process} process is not supported yet"
|
69
|
-
end
|
70
|
-
save_succeeded = rep.save
|
71
|
-
RSReputationMessage.add_reputation_message_if_not_exist(source, rep)
|
72
|
-
propagate_updated_reputation_value(rep, valueBeforeUpdate) if rep.target
|
73
|
-
save_succeeded
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.update_reputation_value_with_updated_source(rep, source, oldValue, weight, process)
|
77
|
-
weight ||= 1 # weight is 1 by default.
|
78
|
-
size = rep.received_messages.size
|
79
|
-
valueBeforeUpdate = size > 0 ? rep.value : nil
|
80
|
-
newValue = source.value
|
81
|
-
case process.to_sym
|
82
|
-
when :sum
|
83
|
-
rep.value += (newValue - oldValue) * weight
|
84
|
-
when :average
|
85
|
-
rep.value += ((newValue - oldValue) * weight) / size
|
86
|
-
when :product
|
87
|
-
rep.value = (rep.value * newValue) / oldValue
|
88
|
-
else
|
89
|
-
raise ArgumentError, "#{process} process is not supported yet"
|
90
|
-
end
|
91
|
-
save_succeeded = rep.save
|
92
|
-
propagate_updated_reputation_value(rep, valueBeforeUpdate) if rep.target
|
93
|
-
save_succeeded
|
94
|
-
end
|
95
|
-
|
96
|
-
def normalized_value
|
97
|
-
if self.active == 1 || self.active == true
|
98
|
-
max = RSReputation.max(self.reputation_name, self.target_type)
|
99
|
-
min = RSReputation.min(self.reputation_name, self.target_type)
|
100
|
-
if max && min
|
101
|
-
range = max - min
|
102
|
-
range == 0 ? 0 : (self.value - min) / range
|
103
|
-
else
|
104
|
-
0
|
105
|
-
end
|
106
|
-
else
|
107
|
-
0
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
protected
|
112
|
-
|
113
|
-
# Updates reputation value for new reputation if its source already exist.
|
114
|
-
def self.initialize_reputation_value(receiver, target, process)
|
115
|
-
name = receiver.reputation_name
|
116
|
-
unless ReputationSystem::Network.is_primary_reputation?(target.class.name, name)
|
117
|
-
sender_defs = ReputationSystem::Network.get_reputation_def(target.class.name, name)[:source]
|
118
|
-
sender_defs.each do |sd|
|
119
|
-
sender_targets = target.get_attributes_of(sd)
|
120
|
-
sender_targets.each do |st|
|
121
|
-
update_reputation_if_source_exist(sd, st, receiver, process) if receiver.target
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
receiver
|
126
|
-
end
|
127
|
-
|
128
|
-
# Propagates updated reputation value to the reputations whose source is the updated reputation.
|
129
|
-
def self.propagate_updated_reputation_value(sender, oldValue)
|
130
|
-
receiver_defs = ReputationSystem::Network.get_reputation_def(sender.target.class.name, sender.reputation_name)[:source_of]
|
131
|
-
receiver_defs.each do |rd|
|
132
|
-
targets = sender.target.get_attributes_of(rd)
|
133
|
-
targets.each do |target|
|
134
|
-
scope = sender.target.evaluate_reputation_scope(rd[:scope])
|
135
|
-
send_reputation_message_to_receiver(rd[:reputation], sender, target, scope, oldValue)
|
136
|
-
end
|
137
|
-
end if receiver_defs
|
138
|
-
end
|
139
|
-
|
140
|
-
def self.send_reputation_message_to_receiver(reputation_name, sender, target, scope, oldValue)
|
141
|
-
srn = ReputationSystem::Network.get_scoped_reputation_name(target.class.name, reputation_name, scope)
|
142
|
-
process = ReputationSystem::Network.get_reputation_def(target.class.name, srn)[:aggregated_by]
|
143
|
-
receiver = find_by_reputation_name_and_target(srn, target)
|
144
|
-
if receiver
|
145
|
-
weight = ReputationSystem::Network.get_weight_of_source_from_reputation_name_of_target(target, sender.reputation_name, srn)
|
146
|
-
update_reputation_value(receiver, sender, weight, process, oldValue)
|
147
|
-
# If r is new then value update will be done when it is initialized.
|
148
|
-
else
|
149
|
-
create_reputation(srn, target, process)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def self.update_reputation_value(receiver, sender, weight, process, oldValue)
|
154
|
-
unless oldValue
|
155
|
-
update_reputation_value_with_new_source(receiver, sender, weight, process)
|
156
|
-
else
|
157
|
-
update_reputation_value_with_updated_source(receiver, sender, oldValue, weight, process)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
def self.update_reputation_if_source_exist(sd, st, receiver, process)
|
162
|
-
scope = receiver.target.evaluate_reputation_scope(sd[:scope])
|
163
|
-
srn = ReputationSystem::Network.get_scoped_reputation_name(st.class.name, sd[:reputation], scope)
|
164
|
-
source = find_by_reputation_name_and_target(srn, st)
|
165
|
-
if source
|
166
|
-
update_reputation_value_with_new_source(receiver, source, sd[:weight], process)
|
167
|
-
RSReputationMessage.add_reputation_message_if_not_exist(source, receiver)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
def self.max(reputation_name, target_type)
|
172
|
-
RSReputation.maximum(:value,
|
173
|
-
:conditions => {:reputation_name => reputation_name.to_s, :target_type => target_type, :active => true})
|
174
|
-
end
|
175
|
-
|
176
|
-
def self.min(reputation_name, target_type)
|
177
|
-
RSReputation.minimum(:value,
|
178
|
-
:conditions => {:reputation_name => reputation_name.to_s, :target_type => target_type, :active => true})
|
179
|
-
end
|
180
|
-
|
181
|
-
def self.get_target_type_for_sti(target, reputation_name)
|
182
|
-
temp = target.class
|
183
|
-
defs = ReputationSystem::Network.get_reputation_defs(temp.name)[reputation_name.to_sym]
|
184
|
-
while temp && temp.name != "ActiveRecord::Base" && defs && defs.empty?
|
185
|
-
temp = temp.superclass
|
186
|
-
defs = ReputationSystem::Network.get_reputation_defs(temp.name)[reputation_name.to_sym]
|
187
|
-
end
|
188
|
-
temp ? temp.name : nil
|
189
|
-
end
|
190
|
-
|
191
|
-
def set_target_type_for_sti
|
192
|
-
temp = self.class.get_target_type_for_sti(target, reputation_name)
|
193
|
-
self.target_type = temp if temp
|
194
|
-
end
|
195
|
-
|
196
|
-
def change_zero_value_in_case_of_product_process
|
197
|
-
self.value = 1 if self.value == 0 && self.aggregated_by == "product"
|
198
|
-
end
|
199
|
-
|
200
|
-
def remove_associated_messages
|
201
|
-
RSReputationMessage.delete_all(:sender_type => self.class.name, :sender_id => self.id)
|
202
|
-
RSReputationMessage.delete_all(:receiver_id => self.id)
|
203
|
-
end
|
204
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# Copyright 2012 Twitter, Inc
|
3
|
-
#
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
-
# you may not use this file except in compliance with the License.
|
6
|
-
# You may obtain a copy of the License at
|
7
|
-
#
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
-
#
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
-
# See the License for the specific language governing permissions and
|
14
|
-
# limitations under the License.
|
15
|
-
##
|
16
|
-
|
17
|
-
class RSReputationMessage < ActiveRecord::Base
|
18
|
-
belongs_to :sender, :polymorphic => true
|
19
|
-
belongs_to :receiver, :class_name => 'RSReputation'
|
20
|
-
|
21
|
-
attr_accessible :weight, :sender, :receiver
|
22
|
-
|
23
|
-
# The same sender cannot send massage to the same receiver more than once.
|
24
|
-
validates_uniqueness_of :receiver_id, :scope => [:sender_id, :sender_type]
|
25
|
-
validate :sender_must_be_evaluation_or_reputation
|
26
|
-
|
27
|
-
after_destroy :delete_sender_if_evaluation
|
28
|
-
|
29
|
-
def self.add_reputation_message_if_not_exist(sender, receiver)
|
30
|
-
rm = create(:sender => sender, :receiver => receiver)
|
31
|
-
receiver.received_messages.push rm if rm.valid?
|
32
|
-
end
|
33
|
-
|
34
|
-
protected
|
35
|
-
|
36
|
-
def delete_sender_if_evaluation
|
37
|
-
sender.destroy if sender.is_a?(RSEvaluation)
|
38
|
-
end
|
39
|
-
|
40
|
-
def sender_must_be_evaluation_or_reputation
|
41
|
-
unless sender.is_a?(RSEvaluation) || sender.is_a?(RSReputation)
|
42
|
-
errors.add(:sender, "must be an evaluation or a reputation")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
@@ -1,119 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# Copyright 2012 Twitter, Inc
|
3
|
-
#
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
-
# you may not use this file except in compliance with the License.
|
6
|
-
# You may obtain a copy of the License at
|
7
|
-
#
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
-
#
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
-
# See the License for the specific language governing permissions and
|
14
|
-
# limitations under the License.
|
15
|
-
##
|
16
|
-
|
17
|
-
require 'spec_helper'
|
18
|
-
|
19
|
-
describe RSReputation do
|
20
|
-
before(:each) do
|
21
|
-
@user = User.create!(:name => 'jack')
|
22
|
-
end
|
23
|
-
|
24
|
-
context "Validation" do
|
25
|
-
it "should have value 0 by default in case of non product process" do
|
26
|
-
r = RSReputation.create!(:reputation_name => "karma", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'sum')
|
27
|
-
r.value.should == 0
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should be able to change value to 0 if process is not product process" do
|
31
|
-
r = RSReputation.create!(:reputation_name => "karma", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'sum', :value => 10)
|
32
|
-
r.value = 0
|
33
|
-
r.save!
|
34
|
-
r.reload
|
35
|
-
r.value.should == 0
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should have value 1 by default in case of product process" do
|
39
|
-
r = RSReputation.create!(:reputation_name => "karma", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'product')
|
40
|
-
r.value.should == 1
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should be able to create reputation with process 'sum', 'average' and 'product'" do
|
44
|
-
RSReputation.create(:reputation_name => "karma1", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'sum').should be_valid
|
45
|
-
RSReputation.create(:reputation_name => "karma2", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'average').should be_valid
|
46
|
-
RSReputation.create(:reputation_name => "karma3", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'product').should be_valid
|
47
|
-
end
|
48
|
-
|
49
|
-
it "should not be able to create reputation with process other than 'sum', 'average' and 'product'" do
|
50
|
-
RSReputation.create(:reputation_name => "karma", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'invalid').should_not be_valid
|
51
|
-
end
|
52
|
-
|
53
|
-
it "should not be able to create reputation of the same name for the same target" do
|
54
|
-
RSReputation.create(:reputation_name => "karma", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'sum').should be_valid
|
55
|
-
RSReputation.create(:reputation_name => "karma", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'sum').should_not be_valid
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
context "Callback" do
|
60
|
-
describe "#set_target_type_for_sti" do
|
61
|
-
it "should assign target class name as target type if not STI" do
|
62
|
-
question = Question.create!(:text => 'Does this work?', :author_id => @user.id)
|
63
|
-
question.add_evaluation(:total_votes, 5, @user)
|
64
|
-
rep = RSReputation.find_by_reputation_name_and_target(:total_votes, question)
|
65
|
-
rep.target_type.should == question.class.name
|
66
|
-
end
|
67
|
-
it "should assign target's ancestors class name where reputation is declared if STI" do
|
68
|
-
designer = Designer.create! :name => 'hiro'
|
69
|
-
programmer = Programmer.create! :name => 'katsuya'
|
70
|
-
programmer.add_evaluation(:leadership, 1, designer)
|
71
|
-
rep = RSReputation.find_by_reputation_name_and_target(:leadership, programmer)
|
72
|
-
rep.target_type.should == Person.name
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
context "Association" do
|
78
|
-
before :each do
|
79
|
-
@question = Question.create!(:text => 'What is Twitter?', :author_id => @user.id)
|
80
|
-
@question.add_evaluation(:total_votes, 5, @user)
|
81
|
-
end
|
82
|
-
|
83
|
-
it "should delete associated received messages" do
|
84
|
-
rep = RSReputation.find_by_target_id_and_target_type(@question.id, 'Question')
|
85
|
-
RSReputationMessage.find_by_receiver_id(rep.id).should_not be_nil
|
86
|
-
rep.destroy
|
87
|
-
RSReputationMessage.find_by_receiver_id(rep.id).should be_nil
|
88
|
-
end
|
89
|
-
|
90
|
-
it "should delete associated sent messages" do
|
91
|
-
rep = RSReputation.find_by_target_id_and_target_type(@user.id, 'User')
|
92
|
-
RSReputationMessage.find_by_sender_id_and_sender_type(rep.id, rep.class.name).should_not be_nil
|
93
|
-
rep.destroy
|
94
|
-
RSReputationMessage.find_by_sender_id_and_sender_type(rep.id, rep.class.name).should be_nil
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
describe "#normalized_value" do
|
99
|
-
before :each do
|
100
|
-
@user2 = User.create!(:name => 'dick')
|
101
|
-
@user3 = User.create!(:name => 'foo')
|
102
|
-
question = Question.new(:text => "Does this work?", :author_id => @user.id)
|
103
|
-
@r1 = RSReputation.create!(:reputation_name => "karma", :value => 2, :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'sum')
|
104
|
-
@r2 = RSReputation.create!(:reputation_name => "karma", :value => 6, :target_id => @user2.id, :target_type => @user2.class.to_s, :aggregated_by => 'sum')
|
105
|
-
@r3 = RSReputation.create!(:reputation_name => "karma", :value => 10, :target_id => @user3.id, :target_type => @user3.class.to_s, :aggregated_by => 'sum')
|
106
|
-
@r4 = RSReputation.create!(:reputation_name => "karma", :value => 10, :target_id => question.id, :target_type => question.class.to_s, :aggregated_by => 'sum')
|
107
|
-
end
|
108
|
-
|
109
|
-
it "should return correct normalized value" do
|
110
|
-
@r1.normalized_value.should be_within(DELTA).of(0)
|
111
|
-
@r2.normalized_value.should be_within(DELTA).of(0.5)
|
112
|
-
@r3.normalized_value.should be_within(DELTA).of(1)
|
113
|
-
end
|
114
|
-
|
115
|
-
it "should return 0 if max and min are the same" do
|
116
|
-
@r4.normalized_value.should be_within(DELTA).of(0)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|