activerecord-reputation-system 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +20 -3
- data/lib/models/rs_reputation.rb +31 -24
- data/lib/reputation_system.rb +1 -2
- data/lib/reputation_system/base.rb +0 -1
- data/lib/reputation_system/evaluation.rb +59 -47
- data/lib/reputation_system/network.rb +57 -31
- data/lib/reputation_system/reputation.rb +32 -9
- data/lib/reputation_system/version.rb +1 -1
- data/spec/reputation_system/evaluation_spec.rb +69 -23
- data/spec/reputation_system/reputation_spec.rb +43 -0
- metadata +51 -17
- data/lib/reputation_system/normalization.rb +0 -50
- data/spec/reputation_system/normalization_spec.rb +0 -68
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
## Active Record Reputation System [![Build Status](https://secure.travis-ci.org/twitter/activerecord-reputation-system.png)](http://travis-ci.org/twitter/activerecord-reputation-system)
|
1
|
+
## Active Record Reputation System [![Build Status](https://secure.travis-ci.org/twitter/activerecord-reputation-system.png)](http://travis-ci.org/twitter/activerecord-reputation-system) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/twitter/activerecord-reputation-system)
|
2
2
|
|
3
3
|
The Active Record Reputation System helps you discover more about your application and make better decisions. The Reputation System gem makes it easy to integrate reputation systems into Rails applications, decouple the system from the main application and provide guidelines for good design of reputation systems.
|
4
4
|
|
@@ -165,12 +165,12 @@ reputations_activated?(reputation_name)
|
|
165
165
|
# Includes the specified reputation value for the given name via a normal Active Record find query.
|
166
166
|
ActiveRecord::Base.find_with_reputation(reputation_name, find_scope, options)
|
167
167
|
# For example:
|
168
|
-
|
168
|
+
User.find_with_reputation(:karma, :all, {:select => "id", :conditions => ["karma > ?", 3], :order => "karma"})
|
169
169
|
|
170
170
|
# Includes the specified normalized reputation value for the given name via a normal Active Record find query.
|
171
171
|
ActiveRecord::Base.find_with_normalized_reputation(reputation_name, find_options)
|
172
172
|
# For example:
|
173
|
-
|
173
|
+
User.find_with_normalized_reputation(:karma, :all, {:select => "id", :conditions => ["karma > ?", 0.5], :order => "karma"})
|
174
174
|
|
175
175
|
# Includes the specified reputation value for the given name via a normal Active Record count query.
|
176
176
|
ActiveRecord::Base.count_with_reputation(reputation_name, find_options)
|
@@ -179,6 +179,15 @@ ActiveRecord::Base.count_with_reputation(reputation_name, find_options)
|
|
179
179
|
ActiveRecord::Base.find_with_reputation_sql(reputation_name, find_options)
|
180
180
|
```
|
181
181
|
|
182
|
+
## Querying for Evaluated ActiveRecord
|
183
|
+
```ruby
|
184
|
+
# Returns all active record instances evaluated by a given source for a given reputation name.
|
185
|
+
ActiveRecord::Base.evaluated_by(reputation_name, source)
|
186
|
+
# For example:
|
187
|
+
Question.evaluated_by(:votes, @user)
|
188
|
+
#
|
189
|
+
```
|
190
|
+
|
182
191
|
## Advanced Topics
|
183
192
|
### Scope
|
184
193
|
Reputations can have different scopes to provide additional context.
|
@@ -213,6 +222,10 @@ To execute an Active Record query using a scoped reputation, try this:
|
|
213
222
|
```ruby
|
214
223
|
ActiveRecord::Base.find_with_reputation(:reputation_name, :scope, :find_options)
|
215
224
|
```
|
225
|
+
To find active records evaluated by a given source for a scoped reputation, try this:
|
226
|
+
```ruby
|
227
|
+
ActiveRecord::Base.evaluated_by(:reputation_name, source, :scope)
|
228
|
+
```
|
216
229
|
There are a few more helper methods available for scopes:
|
217
230
|
```ruby
|
218
231
|
# Allows you to add a scope dynamically.
|
@@ -268,6 +281,10 @@ For more information on semantic versioning, please visit http://semver.org/.
|
|
268
281
|
* Katsuya Noguchi: http://github.com/katsuyan
|
269
282
|
* Inspired by ["Building Web Reputation Systems" by Randy Farmer and Bryce Glass](http://shop.oreilly.com/product/9780596159801.do)
|
270
283
|
|
284
|
+
## Related Links
|
285
|
+
|
286
|
+
* RailsCasts: http://railscasts.com/episodes/364-active-record-reputation-system
|
287
|
+
|
271
288
|
## License
|
272
289
|
|
273
290
|
Copyright 2012 Twitter, Inc.
|
data/lib/models/rs_reputation.rb
CHANGED
@@ -65,9 +65,10 @@ class RSReputation < ActiveRecord::Base
|
|
65
65
|
else
|
66
66
|
raise ArgumentError, "#{process} process is not supported yet"
|
67
67
|
end
|
68
|
-
rep.save
|
68
|
+
save_succeeded = rep.save
|
69
69
|
RSReputationMessage.add_reputation_message_if_not_exist(source, rep)
|
70
70
|
propagate_updated_reputation_value(rep, valueBeforeUpdate) if rep.target
|
71
|
+
save_succeeded
|
71
72
|
end
|
72
73
|
|
73
74
|
def self.update_reputation_value_with_updated_source(rep, source, oldValue, weight, process)
|
@@ -85,8 +86,9 @@ class RSReputation < ActiveRecord::Base
|
|
85
86
|
else
|
86
87
|
raise ArgumentError, "#{process} process is not supported yet"
|
87
88
|
end
|
88
|
-
rep.save
|
89
|
+
save_succeeded = rep.save
|
89
90
|
propagate_updated_reputation_value(rep, valueBeforeUpdate) if rep.target
|
91
|
+
save_succeeded
|
90
92
|
end
|
91
93
|
|
92
94
|
def normalized_value
|
@@ -123,29 +125,34 @@ class RSReputation < ActiveRecord::Base
|
|
123
125
|
|
124
126
|
# Propagates updated reputation value to the reputations whose source is the updated reputation.
|
125
127
|
def self.propagate_updated_reputation_value(sender, oldValue)
|
126
|
-
|
127
|
-
receiver_defs
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
scope = sender.target.evaluate_reputation_scope(rd[:scope])
|
133
|
-
srn = ReputationSystem::Network.get_scoped_reputation_name(rt.class.name, rd[:reputation], scope)
|
134
|
-
process = ReputationSystem::Network.get_reputation_def(rt.class.name, srn)[:aggregated_by]
|
135
|
-
rep = find_by_reputation_name_and_target(srn, rt)
|
136
|
-
if rep
|
137
|
-
weight = ReputationSystem::Network.get_weight_of_source_from_reputation_name_of_target(rt, sender_name, srn)
|
138
|
-
unless oldValue
|
139
|
-
update_reputation_value_with_new_source(rep, sender, weight, process)
|
140
|
-
else
|
141
|
-
update_reputation_value_with_updated_source(rep, sender, oldValue, weight, process)
|
142
|
-
end
|
143
|
-
# If r is new then value update will be done when it is initialized.
|
144
|
-
else
|
145
|
-
create_reputation(srn, rt, process)
|
146
|
-
end
|
147
|
-
end
|
128
|
+
receiver_defs = ReputationSystem::Network.get_reputation_def(sender.target.class.name, sender.reputation_name)[:source_of]
|
129
|
+
receiver_defs.each do |rd|
|
130
|
+
targets = sender.target.get_attributes_of(rd)
|
131
|
+
targets.each do |target|
|
132
|
+
scope = sender.target.evaluate_reputation_scope(rd[:scope])
|
133
|
+
send_reputation_message_to_receiver(rd[:reputation], sender, target, scope, oldValue)
|
148
134
|
end
|
135
|
+
end if receiver_defs
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.send_reputation_message_to_receiver(reputation_name, sender, target, scope, oldValue)
|
139
|
+
srn = ReputationSystem::Network.get_scoped_reputation_name(target.class.name, reputation_name, scope)
|
140
|
+
process = ReputationSystem::Network.get_reputation_def(target.class.name, srn)[:aggregated_by]
|
141
|
+
receiver = find_by_reputation_name_and_target(srn, target)
|
142
|
+
if receiver
|
143
|
+
weight = ReputationSystem::Network.get_weight_of_source_from_reputation_name_of_target(target, sender.reputation_name, srn)
|
144
|
+
update_reputation_value(receiver, sender, weight, process, oldValue)
|
145
|
+
# If r is new then value update will be done when it is initialized.
|
146
|
+
else
|
147
|
+
create_reputation(srn, target, process)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.update_reputation_value(receiver, sender, weight, process, oldValue)
|
152
|
+
unless oldValue
|
153
|
+
update_reputation_value_with_new_source(receiver, sender, weight, process)
|
154
|
+
else
|
155
|
+
update_reputation_value_with_updated_source(receiver, sender, oldValue, weight, process)
|
149
156
|
end
|
150
157
|
end
|
151
158
|
|
data/lib/reputation_system.rb
CHANGED
@@ -16,7 +16,6 @@
|
|
16
16
|
|
17
17
|
require 'reputation_system/base'
|
18
18
|
require 'reputation_system/query'
|
19
|
-
require 'reputation_system/normalization'
|
20
19
|
require 'reputation_system/evaluation'
|
21
20
|
require 'reputation_system/network'
|
22
21
|
require 'reputation_system/reputation'
|
@@ -25,4 +24,4 @@ require 'models/rs_evaluation'
|
|
25
24
|
require 'models/rs_reputation'
|
26
25
|
require 'models/rs_reputation_message'
|
27
26
|
|
28
|
-
ActiveRecord::Base.send(:include, ReputationSystem::Base)
|
27
|
+
ActiveRecord::Base.send(:include, ReputationSystem::Base)
|
@@ -51,7 +51,6 @@ module ReputationSystem
|
|
51
51
|
unless ancestors.include?(ReputationSystem::Reputation)
|
52
52
|
has_many :reputations, :as => :target, :class_name => "RSReputation", :dependent => :destroy
|
53
53
|
include ReputationSystem::Query
|
54
|
-
include ReputationSystem::Normalization
|
55
54
|
include ReputationSystem::Reputation
|
56
55
|
include ReputationSystem::Scope
|
57
56
|
end
|
@@ -16,8 +16,24 @@
|
|
16
16
|
|
17
17
|
module ReputationSystem
|
18
18
|
module Evaluation
|
19
|
+
module ClassMethods
|
20
|
+
def evaluated_by(reputation_name, source, *args)
|
21
|
+
scope = args.first
|
22
|
+
srn = ReputationSystem::Network.get_scoped_reputation_name(self.name, reputation_name, scope)
|
23
|
+
source_type = source.class.name
|
24
|
+
options = {}
|
25
|
+
options[:select] ||= sanitize_sql_array(["%s.*", self.table_name])
|
26
|
+
options[:joins] = sanitize_sql_array(["JOIN rs_evaluations ON %s.id = rs_evaluations.target_id AND rs_evaluations.target_type = ? AND rs_evaluations.reputation_name = ? AND rs_evaluations.source_id = ? AND rs_evaluations.source_type = ?", self.name, srn.to_s, source.id, source_type])
|
27
|
+
options[:joins] = sanitize_sql_array([options[:joins], self.table_name])
|
28
|
+
find(:all, options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.included(klass)
|
33
|
+
klass.extend ClassMethods
|
34
|
+
end
|
35
|
+
|
19
36
|
def add_evaluation(reputation_name, value, source, *args)
|
20
|
-
raise ArgumentError, "#{reputation_name.to_s} is not defined for #{self.class.name}" unless ReputationSystem::Network.has_reputation_for?(self.class.name, reputation_name)
|
21
37
|
scope = args.first
|
22
38
|
srn = ReputationSystem::Network.get_scoped_reputation_name(self.class.name, reputation_name, scope)
|
23
39
|
process = ReputationSystem::Network.get_reputation_def(self.class.name, srn)[:aggregated_by]
|
@@ -27,63 +43,32 @@ module ReputationSystem
|
|
27
43
|
end
|
28
44
|
|
29
45
|
def update_evaluation(reputation_name, value, source, *args)
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
evaluation
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
oldValue = evaluation.value
|
38
|
-
evaluation.value = value
|
39
|
-
evaluation.save!
|
40
|
-
process = ReputationSystem::Network.get_reputation_def(self.class.name, srn)[:aggregated_by]
|
41
|
-
rep = RSReputation.find_by_reputation_name_and_target(srn, self)
|
42
|
-
RSReputation.update_reputation_value_with_updated_source(rep, evaluation, oldValue, 1, process)
|
43
|
-
end
|
46
|
+
srn, evaluation = find_srn_and_evaluation!(reputation_name, source, args.first)
|
47
|
+
oldValue = evaluation.value
|
48
|
+
evaluation.value = value
|
49
|
+
evaluation.save!
|
50
|
+
process = ReputationSystem::Network.get_reputation_def(self.class.name, srn)[:aggregated_by]
|
51
|
+
rep = RSReputation.find_by_reputation_name_and_target(srn, self)
|
52
|
+
RSReputation.update_reputation_value_with_updated_source(rep, evaluation, oldValue, 1, process)
|
44
53
|
end
|
45
54
|
|
46
55
|
def add_or_update_evaluation(reputation_name, value, source, *args)
|
47
|
-
|
48
|
-
srn
|
49
|
-
|
50
|
-
if evaluation.nil?
|
51
|
-
self.add_evaluation(reputation_name, value, source, scope)
|
56
|
+
srn, evaluation = find_srn_and_evaluation(reputation_name, source, args.first)
|
57
|
+
if RSEvaluation.exists? :reputation_name => srn, :source_id => source.id, :source_type => source.class.name, :target_id => self.id, :target_type => self.class.name
|
58
|
+
self.update_evaluation(reputation_name, value, source, *args)
|
52
59
|
else
|
53
|
-
self.
|
60
|
+
self.add_evaluation(reputation_name, value, source, *args)
|
54
61
|
end
|
55
62
|
end
|
56
63
|
|
57
64
|
def delete_evaluation(reputation_name, source, *args)
|
58
|
-
|
59
|
-
|
60
|
-
srn = ReputationSystem::Network.get_scoped_reputation_name(self.class.name, reputation_name, scope)
|
61
|
-
evaluation = RSEvaluation.find_by_reputation_name_and_source_and_target(srn, source, self)
|
62
|
-
unless evaluation.nil?
|
63
|
-
process = ReputationSystem::Network.get_reputation_def(self.class.name, srn)[:aggregated_by]
|
64
|
-
oldValue = evaluation.value
|
65
|
-
evaluation.value = process == :product ? 1 : 0
|
66
|
-
rep = RSReputation.find_by_reputation_name_and_target(srn, self)
|
67
|
-
RSReputation.update_reputation_value_with_updated_source(rep, evaluation, oldValue, 1, process)
|
68
|
-
evaluation.destroy
|
69
|
-
end
|
65
|
+
srn, evaluation = find_srn_and_evaluation(reputation_name, source, args.first)
|
66
|
+
delete_evaluation_without_validation(srn, evaluation) if evaluation
|
70
67
|
end
|
71
68
|
|
72
69
|
def delete_evaluation!(reputation_name, source, *args)
|
73
|
-
|
74
|
-
|
75
|
-
srn = ReputationSystem::Network.get_scoped_reputation_name(self.class.name, reputation_name, scope)
|
76
|
-
evaluation = RSEvaluation.find_by_reputation_name_and_source_and_target(srn, source, self)
|
77
|
-
if evaluation.nil?
|
78
|
-
raise ArgumentError, "Given instance of #{source.class.name} has not evaluated #{reputation_name} of the instance of #{self.class.name} yet."
|
79
|
-
else
|
80
|
-
process = ReputationSystem::Network.get_reputation_def(self.class.name, srn)[:aggregated_by]
|
81
|
-
oldValue = evaluation.value
|
82
|
-
evaluation.value = process == :product ? 1 : 0
|
83
|
-
rep = RSReputation.find_by_reputation_name_and_target(srn, self)
|
84
|
-
RSReputation.update_reputation_value_with_updated_source(rep, evaluation, oldValue, 1, process)
|
85
|
-
evaluation.destroy
|
86
|
-
end
|
70
|
+
srn, evaluation = find_srn_and_evaluation!(reputation_name, source, args.first)
|
71
|
+
delete_evaluation_without_validation(srn, evaluation)
|
87
72
|
end
|
88
73
|
|
89
74
|
def increase_evaluation(reputation_name, value, source, *args)
|
@@ -95,6 +80,33 @@ module ReputationSystem
|
|
95
80
|
end
|
96
81
|
|
97
82
|
protected
|
83
|
+
def find_srn_and_evaluation(reputation_name, source, scope)
|
84
|
+
srn = ReputationSystem::Network.get_scoped_reputation_name(self.class.name, reputation_name, scope)
|
85
|
+
evaluation = RSEvaluation.find_by_reputation_name_and_source_and_target(srn, source, self)
|
86
|
+
return srn, evaluation
|
87
|
+
end
|
88
|
+
|
89
|
+
def find_srn_and_evaluation!(reputation_name, source, scope)
|
90
|
+
srn = ReputationSystem::Network.get_scoped_reputation_name(self.class.name, reputation_name, scope)
|
91
|
+
evaluation = find_evaluation!(reputation_name, srn, source)
|
92
|
+
return srn, evaluation
|
93
|
+
end
|
94
|
+
|
95
|
+
def find_evaluation!(reputation_name, srn, source)
|
96
|
+
evaluation = RSEvaluation.find_by_reputation_name_and_source_and_target(srn, source, self)
|
97
|
+
raise ArgumentError, "Given instance of #{source.class.name} has not evaluated #{reputation_name} of the instance of #{self.class.name} yet." unless evaluation
|
98
|
+
evaluation
|
99
|
+
end
|
100
|
+
|
101
|
+
def delete_evaluation_without_validation(srn, evaluation)
|
102
|
+
process = ReputationSystem::Network.get_reputation_def(self.class.name, srn)[:aggregated_by]
|
103
|
+
oldValue = evaluation.value
|
104
|
+
evaluation.value = process == :product ? 1 : 0
|
105
|
+
rep = RSReputation.find_by_reputation_name_and_target(srn, self)
|
106
|
+
RSReputation.update_reputation_value_with_updated_source(rep, evaluation, oldValue, 1, process)
|
107
|
+
evaluation.destroy
|
108
|
+
end
|
109
|
+
|
98
110
|
def change_evaluation_value_by(reputation_name, value, source, *args)
|
99
111
|
scope = args.first
|
100
112
|
srn = ReputationSystem::Network.get_scoped_reputation_name(self.class.name, reputation_name, scope)
|
@@ -82,6 +82,7 @@ module ReputationSystem
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def get_scoped_reputation_name(class_name, reputation_name, scope)
|
85
|
+
raise ArgumentError, "#{reputation_name.to_s} is not defined for #{class_name}" unless has_reputation_for?(class_name, reputation_name)
|
85
86
|
scope = scope.to_sym if scope
|
86
87
|
validate_scope_necessity(class_name, reputation_name, scope)
|
87
88
|
validate_scope_existence(class_name, reputation_name, scope)
|
@@ -92,13 +93,12 @@ module ReputationSystem
|
|
92
93
|
source = get_reputation_def(target.class.name, reputation_name)[:source]
|
93
94
|
if source.is_a?(Array)
|
94
95
|
source.each do |s|
|
95
|
-
|
96
|
-
|
97
|
-
srn = get_scoped_reputation_name((of.is_a?(Array) ? of[0] : of ).class.name, s[:reputation], scope)
|
98
|
-
source = s if srn.to_sym == source_name.to_sym
|
96
|
+
srn = get_scoped_reputation_name_from_source_def_and_target(s, target)
|
97
|
+
return s[:weight] if srn.to_sym == source_name.to_sym
|
99
98
|
end
|
99
|
+
else
|
100
|
+
source[:weight]
|
100
101
|
end
|
101
|
-
source[:weight]
|
102
102
|
end
|
103
103
|
|
104
104
|
protected
|
@@ -113,34 +113,44 @@ module ReputationSystem
|
|
113
113
|
|
114
114
|
def create_scoped_reputation_def(class_name, reputation_name, scope, options)
|
115
115
|
raise ArgumentError, "#{reputation_name} does not have scope." unless has_scopes?(class_name, reputation_name)
|
116
|
-
scope_options = {}
|
116
|
+
scope_options = options.reject { |k, v| ![:source, :aggregated_by].include? k }
|
117
117
|
reputation_def = get_reputation_def(class_name, reputation_name)
|
118
|
-
|
119
|
-
scope_options[:source] = options[:source]
|
120
|
-
else
|
118
|
+
unless is_primary_reputation?(class_name, reputation_name)
|
121
119
|
scope_options[:source] = []
|
122
|
-
reputation_def[:source].each
|
123
|
-
rep = {}
|
124
|
-
rep[:reputation] = s[:reputation]
|
125
|
-
# Passing "this" is not pretty but in some case "instance_exec" method
|
126
|
-
# does not give right context for some reason.
|
127
|
-
# This could be ruby bug. Needs further investigation.
|
128
|
-
rep[:of] = lambda { |this| instance_exec(this, scope.to_s, &s[:of]) } if s[:of].is_a? Proc
|
129
|
-
scope_options[:source].push rep
|
130
|
-
end
|
120
|
+
reputation_def[:source].each { |sd| scope_options[:source].push create_source_reputation_def(sd, scope) }
|
131
121
|
end
|
132
|
-
|
133
|
-
|
134
|
-
if so[:defined_for_scope].nil? || (so[:defined_for_scope] && so[:defined_for_scope].include?(scope.to_sym))
|
122
|
+
(reputation_def[:source_of] || []).each do |so|
|
123
|
+
if source_of_defined_for_scope?(so, scope)
|
135
124
|
scope_options[:source_of] ||= []
|
136
125
|
scope_options[:source_of].push so
|
137
126
|
end
|
138
|
-
end
|
139
|
-
scope_options[:aggregated_by] = options[:aggregated_by]
|
127
|
+
end
|
140
128
|
srn = get_scoped_reputation_name(class_name, reputation_name, scope)
|
141
129
|
network[class_name.to_sym][srn.to_sym] = scope_options
|
142
130
|
end
|
143
131
|
|
132
|
+
def create_source_reputation_def(source_def, scope)
|
133
|
+
rep = {}
|
134
|
+
rep[:reputation] = source_def[:reputation]
|
135
|
+
# Passing "this" is not pretty but in some case "instance_exec" method
|
136
|
+
# does not give right context for some reason.
|
137
|
+
# This could be ruby bug. Needs further investigation.
|
138
|
+
rep[:of] = lambda { |this| instance_exec(this, scope.to_s, &source_def[:of]) } if source_def[:of].is_a? Proc
|
139
|
+
rep
|
140
|
+
end
|
141
|
+
|
142
|
+
def get_scoped_reputation_name_from_source_def_and_target(source_def, target)
|
143
|
+
scope = target.evaluate_reputation_scope(source_def[:scope]) if source_def[:scope]
|
144
|
+
of = target.get_attributes_of(source_def)
|
145
|
+
class_name = (of.is_a?(Array) ? of[0] : of).class.name
|
146
|
+
get_scoped_reputation_name(class_name, source_def[:reputation], scope)
|
147
|
+
end
|
148
|
+
|
149
|
+
def source_of_defined_for_scope?(source_of_def, scope)
|
150
|
+
defined_for_scope = source_of_def[:defined_for_scope]
|
151
|
+
defined_for_scope.nil? || (defined_for_scope && defined_for_scope.include?(scope.to_sym))
|
152
|
+
end
|
153
|
+
|
144
154
|
def construct_scoped_reputation_options(class_name, reputation_name, options)
|
145
155
|
scopes = get_reputation_def(class_name, reputation_name)[:scopes]
|
146
156
|
scopes.each do |scope|
|
@@ -149,20 +159,36 @@ module ReputationSystem
|
|
149
159
|
end
|
150
160
|
|
151
161
|
def derive_source_of_from_source(class_name, reputation_name, source, src_class_name)
|
152
|
-
|
153
|
-
klass = src_class_name.to_s.constantize
|
154
|
-
of_value = class_name.tableize
|
155
|
-
of_value = of_value.chomp('s') unless klass.instance_methods.include?(of_value.to_s) || klass.instance_methods.include?(of_value.to_sym)
|
156
|
-
else
|
157
|
-
of_value = "self"
|
158
|
-
end
|
162
|
+
of_value = derive_of_value(class_name, source[:of], src_class_name)
|
159
163
|
reputation_def = get_reputation_def(src_class_name, source[:reputation])
|
160
164
|
reputation_def[:source_of] ||= []
|
161
|
-
unless reputation_def[:source_of]
|
165
|
+
unless source_of_include_reputation?(reputation_def[:source_of], reputation_name)
|
162
166
|
reputation_def[:source_of] << {:reputation => reputation_name.to_sym, :of => of_value.to_sym}
|
163
167
|
end
|
164
168
|
end
|
165
169
|
|
170
|
+
def derive_of_value(class_name, source_of, src_class_name)
|
171
|
+
if not_source_of_self?(source_of)
|
172
|
+
attr = class_name.tableize
|
173
|
+
class_has_attribute?(src_class_name, attr) ? attr : attr.chomp('s')
|
174
|
+
else
|
175
|
+
"self"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def not_source_of_self?(source_of)
|
180
|
+
source_of && source_of.is_a?(Symbol) && source_of != :self
|
181
|
+
end
|
182
|
+
|
183
|
+
def class_has_attribute?(class_name, attribute)
|
184
|
+
klass = class_name.to_s.constantize
|
185
|
+
klass.instance_methods.include?(attribute.to_s) || klass.instance_methods.include?(attribute.to_sym)
|
186
|
+
end
|
187
|
+
|
188
|
+
def source_of_include_reputation?(source_of, reputation_name)
|
189
|
+
source_of.map { |rep| rep[:reputation] }.include?(reputation_name.to_sym)
|
190
|
+
end
|
191
|
+
|
166
192
|
def derive_source_of_from_source_later(class_name, reputation_name, source, src_class_name)
|
167
193
|
reputation = source[:reputation].to_sym
|
168
194
|
src_class_name = src_class_name.to_sym
|
@@ -17,17 +17,32 @@
|
|
17
17
|
module ReputationSystem
|
18
18
|
module Reputation
|
19
19
|
def reputation_value_for(reputation_name, *args)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
20
|
+
find_reputation(reputation_name, args.first).value
|
21
|
+
end
|
22
|
+
|
23
|
+
def normalized_reputation_value_for(reputation_name, *args)
|
24
|
+
find_reputation(reputation_name, args.first).normalized_value
|
25
|
+
end
|
26
|
+
|
27
|
+
def activate_all_reputations
|
28
|
+
RSReputation.find(:all, :conditions => {:target_id => self.id, :target_type => self.class.name, :active => false}).each do |r|
|
29
|
+
r.active = true
|
30
|
+
r.save!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def deactivate_all_reputations
|
35
|
+
RSReputation.find(:all, :conditions => {:target_id => self.id, :target_type => self.class.name, :active => true}).each do |r|
|
36
|
+
r.active = false
|
37
|
+
r.save!
|
28
38
|
end
|
29
39
|
end
|
30
40
|
|
41
|
+
def reputations_activated?(reputation_name)
|
42
|
+
r = RSReputation.find(:first, :conditions => {:reputation_name => reputation_name.to_s, :target_id => self.id, :target_type => self.class.name})
|
43
|
+
r ? r.active : false
|
44
|
+
end
|
45
|
+
|
31
46
|
def rank_for(reputation_name, *args)
|
32
47
|
scope = args.first
|
33
48
|
my_value = self.reputation_value_for(reputation_name, scope)
|
@@ -35,5 +50,13 @@ module ReputationSystem
|
|
35
50
|
:conditions => ["rs_reputations.value > ?", my_value]
|
36
51
|
) + 1
|
37
52
|
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
def find_reputation(reputation_name, scope)
|
56
|
+
raise ArgumentError, "#{reputation_name} is not valid" if !self.class.has_reputation_for?(reputation_name)
|
57
|
+
srn = ReputationSystem::Network.get_scoped_reputation_name(self.class.name, reputation_name, scope)
|
58
|
+
process = ReputationSystem::Network.get_reputation_def(self.class.name, srn)[:aggregated_by]
|
59
|
+
RSReputation.find_or_create_reputation(srn, self, process)
|
60
|
+
end
|
38
61
|
end
|
39
|
-
end
|
62
|
+
end
|
@@ -26,9 +26,55 @@ describe ActiveRecord::Base do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
context "Primary Reputation" do
|
29
|
+
describe "#evaluated_by" do
|
30
|
+
it "should return an empty array if it is not evaluaated by a given source" do
|
31
|
+
Question.evaluated_by(:total_votes, @user).should == []
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should return an array of targets evaluated by a given source" do
|
35
|
+
user2 = User.create!(:name => 'katsuya')
|
36
|
+
question2 = Question.create!(:text => 'Question 2', :author_id => @user.id)
|
37
|
+
question3 = Question.create!(:text => 'Question 3', :author_id => @user.id)
|
38
|
+
@question.add_evaluation(:total_votes, 1, @user).should be_true
|
39
|
+
question2.add_evaluation(:total_votes, 2, user2).should be_true
|
40
|
+
question3.add_evaluation(:total_votes, 3, @user).should be_true
|
41
|
+
Question.evaluated_by(:total_votes, @user).should == [@question, question3]
|
42
|
+
Question.evaluated_by(:total_votes, user2).should == [question2]
|
43
|
+
end
|
44
|
+
|
45
|
+
context "With Scopes" do
|
46
|
+
it "should return an array of targets evaluated by a given source on appropriate scope" do
|
47
|
+
user2 = User.create!(:name => 'katsuya')
|
48
|
+
phrase2 = Phrase.create!(:text => "Two")
|
49
|
+
@phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1).should be_true
|
50
|
+
@phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be_true
|
51
|
+
@phrase.add_evaluation(:difficulty_with_scope, 3, user2, :s2).should be_true
|
52
|
+
@phrase.add_evaluation(:difficulty_with_scope, 4, user2, :s3).should be_true
|
53
|
+
phrase2.add_evaluation(:difficulty_with_scope, 1, user2, :s1).should be_true
|
54
|
+
phrase2.add_evaluation(:difficulty_with_scope, 2, user2, :s2).should be_true
|
55
|
+
phrase2.add_evaluation(:difficulty_with_scope, 3, @user, :s2).should be_true
|
56
|
+
phrase2.add_evaluation(:difficulty_with_scope, 4, @user, :s3).should be_true
|
57
|
+
Phrase.evaluated_by(:difficulty_with_scope, @user, :s1).should == [@phrase]
|
58
|
+
Phrase.evaluated_by(:difficulty_with_scope, user2, :s1).should == [phrase2]
|
59
|
+
Phrase.evaluated_by(:difficulty_with_scope, @user, :s2).should == [@phrase, phrase2]
|
60
|
+
Phrase.evaluated_by(:difficulty_with_scope, user2, :s2).should == [@phrase, phrase2]
|
61
|
+
Phrase.evaluated_by(:difficulty_with_scope, @user, :s3).should == [phrase2]
|
62
|
+
Phrase.evaluated_by(:difficulty_with_scope, user2, :s3).should == [@phrase]
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should raise exception if invalid scope is given" do
|
66
|
+
lambda{@phrase.add_evaluation(:difficulty_with_scope, 1, :invalid_scope)}.should raise_error(ArgumentError)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should raise exception if scope is not given" do
|
70
|
+
lambda{@phrase.add_evaluation(:difficulty_with_scope, 1)}.should raise_error(ArgumentError)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
29
75
|
describe "#add_evaluation" do
|
30
76
|
it "should create evaluation in case of valid input" do
|
31
|
-
@question.add_evaluation(:total_votes, 1, @user)
|
77
|
+
@question.add_evaluation(:total_votes, 1, @user).should be_true
|
32
78
|
@question.reputation_value_for(:total_votes).should == 1
|
33
79
|
end
|
34
80
|
|
@@ -48,8 +94,8 @@ describe ActiveRecord::Base do
|
|
48
94
|
|
49
95
|
context "With Scopes" do
|
50
96
|
it "should add evaluation on appropriate scope" do
|
51
|
-
@phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1)
|
52
|
-
@phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2)
|
97
|
+
@phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1).should be_true
|
98
|
+
@phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be_true
|
53
99
|
@phrase.reputation_value_for(:difficulty_with_scope, :s1).should == 1
|
54
100
|
@phrase.reputation_value_for(:difficulty_with_scope, :s2).should == 2
|
55
101
|
@phrase.reputation_value_for(:difficulty_with_scope, :s3).should == 0
|
@@ -67,30 +113,30 @@ describe ActiveRecord::Base do
|
|
67
113
|
|
68
114
|
describe "#add_or_update_evaluation" do
|
69
115
|
it "should create evaluation if it does not exist" do
|
70
|
-
@question.add_or_update_evaluation(:total_votes, 1, @user)
|
116
|
+
@question.add_or_update_evaluation(:total_votes, 1, @user).should be_true
|
71
117
|
@question.reputation_value_for(:total_votes).should == 1
|
72
118
|
end
|
73
119
|
|
74
120
|
it "should update evaluation if it exists already" do
|
75
121
|
@question.add_evaluation(:total_votes, 1, @user)
|
76
|
-
@question.add_or_update_evaluation(:total_votes, 2, @user)
|
122
|
+
@question.add_or_update_evaluation(:total_votes, 2, @user).should be_true
|
77
123
|
@question.reputation_value_for(:total_votes).should == 2
|
78
124
|
end
|
79
125
|
|
80
126
|
context "With Scopes" do
|
81
127
|
it "should add evaluation on appropriate scope if it does not exist" do
|
82
|
-
@phrase.add_or_update_evaluation(:difficulty_with_scope, 1, @user, :s1)
|
83
|
-
@phrase.add_or_update_evaluation(:difficulty_with_scope, 2, @user, :s2)
|
128
|
+
@phrase.add_or_update_evaluation(:difficulty_with_scope, 1, @user, :s1).should be_true
|
129
|
+
@phrase.add_or_update_evaluation(:difficulty_with_scope, 2, @user, :s2).should be_true
|
84
130
|
@phrase.reputation_value_for(:difficulty_with_scope, :s1).should == 1
|
85
131
|
@phrase.reputation_value_for(:difficulty_with_scope, :s2).should == 2
|
86
132
|
@phrase.reputation_value_for(:difficulty_with_scope, :s3).should == 0
|
87
133
|
end
|
88
134
|
|
89
135
|
it "should update evaluation on appropriate scope if it exists already" do
|
90
|
-
@phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1)
|
91
|
-
@phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2)
|
92
|
-
@phrase.add_or_update_evaluation(:difficulty_with_scope, 3, @user, :s1)
|
93
|
-
@phrase.add_or_update_evaluation(:difficulty_with_scope, 5, @user, :s2)
|
136
|
+
@phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1).should be_true
|
137
|
+
@phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be_true
|
138
|
+
@phrase.add_or_update_evaluation(:difficulty_with_scope, 3, @user, :s1).should be_true
|
139
|
+
@phrase.add_or_update_evaluation(:difficulty_with_scope, 5, @user, :s2).should be_true
|
94
140
|
@phrase.reputation_value_for(:difficulty_with_scope, :s1).should == 3
|
95
141
|
@phrase.reputation_value_for(:difficulty_with_scope, :s2).should == 5
|
96
142
|
@phrase.reputation_value_for(:difficulty_with_scope, :s3).should == 0
|
@@ -104,7 +150,7 @@ describe ActiveRecord::Base do
|
|
104
150
|
end
|
105
151
|
|
106
152
|
it "should update evaluation in case of valid input" do
|
107
|
-
@question.update_evaluation(:total_votes, 2, @user)
|
153
|
+
@question.update_evaluation(:total_votes, 2, @user).should be_true
|
108
154
|
@question.reputation_value_for(:total_votes).should == 2
|
109
155
|
end
|
110
156
|
|
@@ -122,11 +168,11 @@ describe ActiveRecord::Base do
|
|
122
168
|
|
123
169
|
context "With Scopes" do
|
124
170
|
before :each do
|
125
|
-
@phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2)
|
171
|
+
@phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be_true
|
126
172
|
end
|
127
173
|
|
128
174
|
it "should update evaluation on appropriate scope" do
|
129
|
-
@phrase.update_evaluation(:difficulty_with_scope, 5, @user, :s2)
|
175
|
+
@phrase.update_evaluation(:difficulty_with_scope, 5, @user, :s2).should be_true
|
130
176
|
@phrase.reputation_value_for(:difficulty_with_scope, :s1).should == 0
|
131
177
|
@phrase.reputation_value_for(:difficulty_with_scope, :s2).should == 5
|
132
178
|
@phrase.reputation_value_for(:difficulty_with_scope, :s3).should == 0
|
@@ -192,7 +238,7 @@ describe ActiveRecord::Base do
|
|
192
238
|
end
|
193
239
|
|
194
240
|
it "should delete evaluation in case of valid input" do
|
195
|
-
@question.delete_evaluation(:total_votes, @user)
|
241
|
+
@question.delete_evaluation(:total_votes, @user).should be_true
|
196
242
|
@question.reputation_value_for(:total_votes).should == 0
|
197
243
|
end
|
198
244
|
|
@@ -210,7 +256,7 @@ describe ActiveRecord::Base do
|
|
210
256
|
end
|
211
257
|
|
212
258
|
it "should delete evaluation on appropriate scope" do
|
213
|
-
@phrase.delete_evaluation(:difficulty_with_scope, @user, :s2)
|
259
|
+
@phrase.delete_evaluation(:difficulty_with_scope, @user, :s2).should be_true
|
214
260
|
@phrase.reputation_value_for(:difficulty_with_scope, :s1).should == 0
|
215
261
|
@phrase.reputation_value_for(:difficulty_with_scope, :s2).should == 0
|
216
262
|
@phrase.reputation_value_for(:difficulty_with_scope, :s3).should == 0
|
@@ -228,13 +274,13 @@ describe ActiveRecord::Base do
|
|
228
274
|
|
229
275
|
describe "#increase_evaluation" do
|
230
276
|
it "should add evaluation if it does not exist" do
|
231
|
-
@question.increase_evaluation(:total_votes, 2, @user)
|
277
|
+
@question.increase_evaluation(:total_votes, 2, @user).should be_true
|
232
278
|
@question.reputation_value_for(:total_votes).should == 2
|
233
279
|
end
|
234
280
|
|
235
281
|
it "should increase evaluation if it exists already" do
|
236
282
|
@question.add_evaluation(:total_votes, 1, @user)
|
237
|
-
@question.increase_evaluation(:total_votes, 2, @user)
|
283
|
+
@question.increase_evaluation(:total_votes, 2, @user).should be_true
|
238
284
|
@question.reputation_value_for(:total_votes).should == 3
|
239
285
|
end
|
240
286
|
|
@@ -244,7 +290,7 @@ describe ActiveRecord::Base do
|
|
244
290
|
end
|
245
291
|
|
246
292
|
it "should increase evaluation on appropriate scope" do
|
247
|
-
@phrase.increase_evaluation(:difficulty_with_scope, 5, @user, :s2)
|
293
|
+
@phrase.increase_evaluation(:difficulty_with_scope, 5, @user, :s2).should be_true
|
248
294
|
@phrase.reputation_value_for(:difficulty_with_scope, :s1).should == 0
|
249
295
|
@phrase.reputation_value_for(:difficulty_with_scope, :s2).should == 7
|
250
296
|
@phrase.reputation_value_for(:difficulty_with_scope, :s3).should == 0
|
@@ -254,13 +300,13 @@ describe ActiveRecord::Base do
|
|
254
300
|
|
255
301
|
describe "#decrease_evaluation" do
|
256
302
|
it "should add evaluation if it does not exist" do
|
257
|
-
@question.decrease_evaluation(:total_votes, 2, @user)
|
303
|
+
@question.decrease_evaluation(:total_votes, 2, @user).should be_true
|
258
304
|
@question.reputation_value_for(:total_votes).should == -2
|
259
305
|
end
|
260
306
|
|
261
307
|
it "should increase evaluation if it exists already" do
|
262
308
|
@question.add_evaluation(:total_votes, 1, @user)
|
263
|
-
@question.decrease_evaluation(:total_votes, 2, @user)
|
309
|
+
@question.decrease_evaluation(:total_votes, 2, @user).should be_true
|
264
310
|
@question.reputation_value_for(:total_votes).should == -1
|
265
311
|
end
|
266
312
|
|
@@ -269,8 +315,8 @@ describe ActiveRecord::Base do
|
|
269
315
|
@phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2)
|
270
316
|
end
|
271
317
|
|
272
|
-
it "should
|
273
|
-
@phrase.decrease_evaluation(:difficulty_with_scope, 5, @user, :s2)
|
318
|
+
it "should decrease evaluation on appropriate scope" do
|
319
|
+
@phrase.decrease_evaluation(:difficulty_with_scope, 5, @user, :s2).should be_true
|
274
320
|
@phrase.reputation_value_for(:difficulty_with_scope, :s1).should == 0
|
275
321
|
@phrase.reputation_value_for(:difficulty_with_scope, :s2).should == -3
|
276
322
|
@phrase.reputation_value_for(:difficulty_with_scope, :s3).should == 0
|
@@ -116,4 +116,47 @@ describe ActiveRecord::Base do
|
|
116
116
|
end
|
117
117
|
end
|
118
118
|
end
|
119
|
+
|
120
|
+
context "Normalization" do
|
121
|
+
describe "#normalized_reputation_value_for" do
|
122
|
+
it "should return 0 as if there is no data" do
|
123
|
+
@question.normalized_reputation_value_for(:total_votes).should == 0
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should return appropriate value in case of valid input" do
|
127
|
+
question2 = Question.create!(:text => 'Does this work too?', :author_id => @user.id)
|
128
|
+
question3 = Question.create!(:text => 'Does this work too?', :author_id => @user.id)
|
129
|
+
@question.add_evaluation(:total_votes, 1, @user)
|
130
|
+
question2.add_evaluation(:total_votes, 2, @user)
|
131
|
+
question3.add_evaluation(:total_votes, 3, @user)
|
132
|
+
@question.normalized_reputation_value_for(:total_votes).should == 0
|
133
|
+
question2.normalized_reputation_value_for(:total_votes).should == 0.5
|
134
|
+
question3.normalized_reputation_value_for(:total_votes).should == 1
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should raise exception if invalid reputation name is given" do
|
138
|
+
lambda {@question.normalized_reputation_value_for(:invalid)}.should raise_error(ArgumentError)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should raise exception if scope is given for reputation with no scopes" do
|
142
|
+
lambda {@question.normalized_reputation_value_for(:difficulty, :s1)}.should raise_error(ArgumentError)
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should raise exception if scope is not given for reputation with scopes" do
|
146
|
+
lambda {@phrase.normalized_reputation_value_for(:difficulty_with_scope)}.should raise_error(ArgumentError)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "#exclude_all_reputations_for_normalization" do
|
151
|
+
it "should activate all reputation" do
|
152
|
+
@question2 = Question.create!(:text => 'Does this work??', :author_id => @user.id)
|
153
|
+
@question2.add_evaluation(:total_votes, 70, @user)
|
154
|
+
@question.add_evaluation(:total_votes, 100, @user)
|
155
|
+
@question.deactivate_all_reputations
|
156
|
+
RSReputation.maximum(:value, :conditions => {:reputation_name => 'total_votes', :active => true}).should == 70
|
157
|
+
@question.activate_all_reputations
|
158
|
+
RSReputation.maximum(:value, :conditions => {:reputation_name => 'total_votes', :active => true}).should == 100
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
119
162
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-reputation-system
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: rake
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: 0.8.7
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.8.7
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: rspec
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ~>
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: '2.8'
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.8'
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: rdoc
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
@@ -54,10 +69,15 @@ dependencies:
|
|
54
69
|
version: '0'
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: database_cleaner
|
60
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
61
81
|
none: false
|
62
82
|
requirements:
|
63
83
|
- - ~>
|
@@ -65,10 +85,15 @@ dependencies:
|
|
65
85
|
version: 0.7.1
|
66
86
|
type: :development
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.7.1
|
69
94
|
- !ruby/object:Gem::Dependency
|
70
95
|
name: sqlite3
|
71
|
-
requirement:
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
72
97
|
none: false
|
73
98
|
requirements:
|
74
99
|
- - ~>
|
@@ -76,7 +101,12 @@ dependencies:
|
|
76
101
|
version: 1.3.5
|
77
102
|
type: :development
|
78
103
|
prerelease: false
|
79
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.3.5
|
80
110
|
description: ActiveRecord Reputation System gem allows rails apps to compute and publish
|
81
111
|
reputation scores for active record models.
|
82
112
|
email:
|
@@ -99,7 +129,6 @@ files:
|
|
99
129
|
- lib/reputation_system/base.rb
|
100
130
|
- lib/reputation_system/evaluation.rb
|
101
131
|
- lib/reputation_system/network.rb
|
102
|
-
- lib/reputation_system/normalization.rb
|
103
132
|
- lib/reputation_system/query.rb
|
104
133
|
- lib/reputation_system/reputation.rb
|
105
134
|
- lib/reputation_system/scope.rb
|
@@ -111,7 +140,6 @@ files:
|
|
111
140
|
- spec/reputation_system/base_spec.rb
|
112
141
|
- spec/reputation_system/evaluation_spec.rb
|
113
142
|
- spec/reputation_system/network_spec.rb
|
114
|
-
- spec/reputation_system/normalization_spec.rb
|
115
143
|
- spec/reputation_system/query_spec.rb
|
116
144
|
- spec/reputation_system/reputation_spec.rb
|
117
145
|
- spec/reputation_system/scope_spec.rb
|
@@ -128,15 +156,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
128
156
|
- - ! '>='
|
129
157
|
- !ruby/object:Gem::Version
|
130
158
|
version: '0'
|
159
|
+
segments:
|
160
|
+
- 0
|
161
|
+
hash: 1595828597124955977
|
131
162
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
163
|
none: false
|
133
164
|
requirements:
|
134
165
|
- - ! '>='
|
135
166
|
- !ruby/object:Gem::Version
|
136
167
|
version: '0'
|
168
|
+
segments:
|
169
|
+
- 0
|
170
|
+
hash: 1595828597124955977
|
137
171
|
requirements: []
|
138
172
|
rubyforge_project:
|
139
|
-
rubygems_version: 1.8.
|
173
|
+
rubygems_version: 1.8.24
|
140
174
|
signing_key:
|
141
175
|
specification_version: 3
|
142
176
|
summary: ActiveRecord Reputation System gem allows rails apps to compute and publish
|
@@ -1,50 +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
|
-
module ReputationSystem
|
18
|
-
module Normalization
|
19
|
-
def normalized_reputation_value_for(reputation_name, *args)
|
20
|
-
scope = args.first
|
21
|
-
if !self.class.has_reputation_for?(reputation_name)
|
22
|
-
raise ArgumentError, "#{reputation_name} is not valid"
|
23
|
-
else
|
24
|
-
reputation_name = ReputationSystem::Network.get_scoped_reputation_name(self.class.name, reputation_name, scope)
|
25
|
-
process = ReputationSystem::Network.get_reputation_def(self.class.name, reputation_name)[:aggregated_by]
|
26
|
-
reputation = RSReputation.find_or_create_reputation(reputation_name, self, process)
|
27
|
-
reputation.normalized_value
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def activate_all_reputations
|
32
|
-
RSReputation.find(:all, :conditions => {:target_id => self.id, :target_type => self.class.name, :active => false}).each do |r|
|
33
|
-
r.active = true
|
34
|
-
r.save!
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def deactivate_all_reputations
|
39
|
-
RSReputation.find(:all, :conditions => {:target_id => self.id, :target_type => self.class.name, :active => true}).each do |r|
|
40
|
-
r.active = false
|
41
|
-
r.save!
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def reputations_activated?(reputation_name)
|
46
|
-
r = RSReputation.find(:first, :conditions => {:reputation_name => reputation_name.to_s, :target_id => self.id, :target_type => self.class.name})
|
47
|
-
r ? r.active : false
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,68 +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 ActiveRecord::Base do
|
20
|
-
|
21
|
-
before(:each) do
|
22
|
-
@user = User.create!(:name => 'jack')
|
23
|
-
@question = Question.create!(:text => 'Does this work?', :author_id => @user.id)
|
24
|
-
@answer = Answer.create!(:text => 'Yes!', :author_id => @user.id, :question_id => @question.id)
|
25
|
-
@phrase = Phrase.create!(:text => "One")
|
26
|
-
end
|
27
|
-
|
28
|
-
describe "#normalized_reputation_value_for" do
|
29
|
-
it "should return 0 as if there is no data" do
|
30
|
-
@question.normalized_reputation_value_for(:total_votes).should == 0
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should return appropriate value in case of valid input" do
|
34
|
-
question2 = Question.create!(:text => 'Does this work too?', :author_id => @user.id)
|
35
|
-
question3 = Question.create!(:text => 'Does this work too?', :author_id => @user.id)
|
36
|
-
@question.add_evaluation(:total_votes, 1, @user)
|
37
|
-
question2.add_evaluation(:total_votes, 2, @user)
|
38
|
-
question3.add_evaluation(:total_votes, 3, @user)
|
39
|
-
@question.normalized_reputation_value_for(:total_votes).should == 0
|
40
|
-
question2.normalized_reputation_value_for(:total_votes).should == 0.5
|
41
|
-
question3.normalized_reputation_value_for(:total_votes).should == 1
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should raise exception if invalid reputation name is given" do
|
45
|
-
lambda {@question.normalized_reputation_value_for(:invalid)}.should raise_error(ArgumentError)
|
46
|
-
end
|
47
|
-
|
48
|
-
it "should raise exception if scope is given for reputation with no scopes" do
|
49
|
-
lambda {@question.normalized_reputation_value_for(:difficulty, :s1)}.should raise_error(ArgumentError)
|
50
|
-
end
|
51
|
-
|
52
|
-
it "should raise exception if scope is not given for reputation with scopes" do
|
53
|
-
lambda {@phrase.normalized_reputation_value_for(:difficulty_with_scope)}.should raise_error(ArgumentError)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe "#exclude_all_reputations_for_normalization" do
|
58
|
-
it "should activate all reputation" do
|
59
|
-
@question2 = Question.create!(:text => 'Does this work??', :author_id => @user.id)
|
60
|
-
@question2.add_evaluation(:total_votes, 70, @user)
|
61
|
-
@question.add_evaluation(:total_votes, 100, @user)
|
62
|
-
@question.deactivate_all_reputations
|
63
|
-
RSReputation.maximum(:value, :conditions => {:reputation_name => 'total_votes', :active => true}).should == 70
|
64
|
-
@question.activate_all_reputations
|
65
|
-
RSReputation.maximum(:value, :conditions => {:reputation_name => 'total_votes', :active => true}).should == 100
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|