activerecord-reputation-system 2.0.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 357cba79dc17693f888aa559b94301e9cc6a0c39
4
+ data.tar.gz: 86542de25746208e733f163c661ec9b7be90ba2c
5
+ SHA512:
6
+ metadata.gz: 9656e9ca24b2a70661ef53336b6c96af676c1aa5d2d556267d223caf57aae0ff49fd79aa5e9feacda5ec0f16a1f2d80d7f1fc20d3c3e167023263e385c33d0c5
7
+ data.tar.gz: acc3482e4ea8e3d485d605fd711eecd7f7a70920049cb638472f4a532acb11f183dce97e374e32ec8e4e3c3c24e08c311c113648eb7f112543209ec210a00234
data/README.md CHANGED
@@ -91,6 +91,38 @@ You can get target records that have been evaluated by a given source record:
91
91
  Question.evaluated_by(:votes, @user) #=> [@question]
92
92
  ```
93
93
 
94
+ You can use a custom aggregation function, which is a feature available on this fork, but not on the original implementation.
95
+ You just need to provide the name of the method on the :aggregated_by option, and implement this method on the model.
96
+ On the example below, our aggregation function sums all values and multiply by ten:
97
+ ```ruby
98
+ class Answer < ActiveRecord::Base
99
+ belongs_to :author, :class_name => 'User'
100
+ belongs_to :question
101
+
102
+ has_reputation :custom_rating,
103
+ :source => :user,
104
+ :aggregated_by => :custom_aggregation
105
+
106
+ def custom_aggregation(*args)
107
+ rep, source, weight = args[0..2]
108
+
109
+ # Ruby doesn't support method overloading, so let's handle parameters on a condition
110
+
111
+ # For a new source, these are the input parameters:
112
+ # rep, source, weight
113
+ if args.length === 3
114
+ rep.value + weight * source.value * 10
115
+
116
+ # For an updated source, these are the input parameters:
117
+ # rep, source, weight, oldValue, newSize
118
+ elsif args.length === 5
119
+ oldValue, newSize = args[3..4]
120
+ rep.value + (source.value - oldValue) * 10
121
+ end
122
+ end
123
+ end
124
+ ```
125
+
94
126
  ## Documentation
95
127
 
96
128
  Please refer [Wiki](https://github.com/twitter/activerecord-reputation-system/wiki) for available APIs and more information.
@@ -106,6 +138,7 @@ Katsuya Noguchi
106
138
  1. [NARKOZ (Nihad Abbasov)](https://github.com/NARKOZ) - 4 commits
107
139
  2. [elitheeli (Eli Fox-Epstein)](https://github.com/elitheeli) - 1 commit
108
140
  3. [amrnt (Amr Tamimi)](https://github.com/amrnt) - 1 commit
141
+ 4. [caiosba (Caio Almeida)](https://github.com/caiosba) - 1 commit
109
142
 
110
143
  ## Related Links
111
144
 
@@ -37,6 +37,8 @@ class ReputationSystemGenerator < Rails::Generators::Base
37
37
  create_migration_file_if_not_exist 'change_evaluations_index_to_unique'
38
38
  create_migration_file_if_not_exist 'change_reputation_messages_index_to_unique'
39
39
  create_migration_file_if_not_exist 'change_reputations_index_to_unique'
40
+ create_migration_file_if_not_exist 'add_data_to_reputations'
41
+ create_migration_file_if_not_exist 'add_data_to_evaluations'
40
42
  end
41
43
 
42
44
  private
@@ -0,0 +1,9 @@
1
+ class AddDataToEvaluations < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :rs_evaluations, :data, :text
4
+ end
5
+
6
+ def self.down
7
+ remove_column :rs_evaluations, :data
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class AddDataToReputations < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :rs_reputations, :data, :text
4
+ end
5
+
6
+ def self.down
7
+ remove_column :rs_reputations, :data
8
+ end
9
+ end
@@ -14,6 +14,7 @@
14
14
  # limitations under the License.
15
15
  ##
16
16
 
17
+ require 'protected_attributes'
17
18
  require 'reputation_system/base'
18
19
  require 'reputation_system/query_methods'
19
20
  require 'reputation_system/finder_methods'
@@ -22,7 +22,8 @@ module ReputationSystem
22
22
 
23
23
  def get_attributes_of(reputation)
24
24
  of = reputation[:of]
25
- attrs = reputation[:of] == :self ? self : self.instance_eval(of.to_s) if of.is_a?(String) || of.is_a?(Symbol)
25
+ attrs = (of == :self) ? self : self.instance_eval(of.to_s) if of.is_a?(String) || of.is_a?(Symbol)
26
+ attrs = attrs.to_a if attrs.is_a?(ActiveRecord::Associations::CollectionProxy)
26
27
  attrs = self.instance_exec(self, &of) if of.is_a?(Proc)
27
28
  attrs = [attrs] unless attrs.is_a? Array
28
29
  attrs.compact
@@ -25,7 +25,7 @@ module ReputationSystem
25
25
  options[:select] ||= sanitize_sql_array(["%s.*", self.table_name])
26
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
27
  options[:joins] = sanitize_sql_array([options[:joins], self.table_name])
28
- find(:all, options)
28
+ joins(options[:joins]).select(options[:select])
29
29
  end
30
30
  end
31
31
 
@@ -27,7 +27,7 @@ module FinderMethods
27
27
  options[:select] = build_select_statement(table_name, reputation_name, options[:select])
28
28
  options[:joins] = build_join_statement(table_name, name, srn, options[:joins])
29
29
  options[:conditions] = build_condition_statement(reputation_name, options[:conditions])
30
- find(find_scope, options)
30
+ joins(options[:joins]).select(options[:select]).where(options[:conditions]).send(find_scope)
31
31
  end
32
32
 
33
33
  def count_with_reputation(*args)
@@ -35,7 +35,7 @@ module FinderMethods
35
35
  options[:joins] = build_join_statement(table_name, name, srn, options[:joins])
36
36
  options[:conditions] = build_condition_statement(reputation_name, options[:conditions])
37
37
  options[:conditions][0].gsub!(reputation_name.to_s, "COALESCE(rs_reputations.value, 0)")
38
- count(find_scope, options)
38
+ joins(options[:joins]).select(options[:select]).where(options[:conditions]).send(find_scope).count
39
39
  end
40
40
 
41
41
  def find_with_normalized_reputation(*args)
@@ -43,7 +43,7 @@ module FinderMethods
43
43
  options[:select] = build_select_statement(table_name, reputation_name, options[:select], srn, true)
44
44
  options[:joins] = build_join_statement(table_name, name, srn, options[:joins])
45
45
  options[:conditions] = build_condition_statement(reputation_name, options[:conditions], srn, true)
46
- find(find_scope, options)
46
+ joins(options[:joins]).select(options[:select]).where(options[:conditions]).send(find_scope)
47
47
  end
48
48
 
49
49
  def find_with_reputation_sql(*args)
@@ -53,8 +53,10 @@ module FinderMethods
53
53
  options[:conditions] = build_condition_statement(reputation_name, options[:conditions])
54
54
  if respond_to?(:construct_finder_sql, true)
55
55
  construct_finder_sql(options)
56
- else
56
+ elsif respond_to?(:construct_finder_arel, true)
57
57
  construct_finder_arel(options).to_sql
58
+ else
59
+ joins(options[:joins]).select(options[:select]).where(options[:conditions]).send(find_scope).to_sql
58
60
  end
59
61
  end
60
62
 
@@ -31,15 +31,17 @@ module ReputationSystem
31
31
  validates_uniqueness_of :source_id, :scope => [:reputation_name, :source_type, :target_id, :target_type]
32
32
  validate :source_must_be_defined_for_reputation_in_network
33
33
 
34
+ serialize :data, Hash
35
+
34
36
  def self.find_by_reputation_name_and_source_and_target(reputation_name, source, target)
35
37
  source_type = get_source_type_for_sti(source.class.name, target.class.name, reputation_name)
36
- ReputationSystem::Evaluation.find(:first,
37
- :conditions => {:reputation_name => reputation_name.to_s,
38
- :source_id => source.id,
39
- :source_type => source_type,
40
- :target_id => target.id,
41
- :target_type => target.class.name
42
- })
38
+ ReputationSystem::Evaluation.where(
39
+ :reputation_name => reputation_name.to_s,
40
+ :source_id => source.id,
41
+ :source_type => source_type,
42
+ :target_id => target.id,
43
+ :target_type => target.class.name
44
+ ).first
43
45
  end
44
46
 
45
47
  def self.create_evaluation(reputation_name, value, source, target)
@@ -31,10 +31,10 @@ module ReputationSystem
31
31
  before_validation :set_target_type_for_sti
32
32
  before_save :change_zero_value_in_case_of_product_process
33
33
 
34
- VALID_PROCESSES = ['sum', 'average', 'product']
35
- validates_inclusion_of :aggregated_by, :in => VALID_PROCESSES, :message => "Value chosen for aggregated_by is not valid process"
36
34
  validates_uniqueness_of :reputation_name, :scope => [:target_id, :target_type]
37
35
 
36
+ serialize :data, Hash
37
+
38
38
  def self.find_by_reputation_name_and_target(reputation_name, target)
39
39
  target_type = get_target_type_for_sti(target, reputation_name)
40
40
  ReputationSystem::Reputation.find_by_reputation_name_and_target_id_and_target_type(reputation_name.to_s, target.id, target_type)
@@ -66,7 +66,11 @@ module ReputationSystem
66
66
  when :product
67
67
  rep.value *= (newValue * weight)
68
68
  else
69
- raise ArgumentError, "#{process} process is not supported yet"
69
+ if source.target.respond_to?(process)
70
+ rep.value = source.target.send(process, rep, source, weight)
71
+ else
72
+ raise ArgumentError, "#{process} process is not supported yet"
73
+ end
70
74
  end
71
75
  save_succeeded = rep.save
72
76
  ReputationSystem::ReputationMessage.add_reputation_message_if_not_exist(source, rep)
@@ -90,7 +94,11 @@ module ReputationSystem
90
94
  when :product
91
95
  rep.value = (rep.value * newValue) / oldValue
92
96
  else
93
- raise ArgumentError, "#{process} process is not supported yet"
97
+ if source.target.respond_to?(process)
98
+ rep.value = source.target.send(process, rep, source, weight, oldValue, newSize)
99
+ else
100
+ raise ArgumentError, "#{process} process is not supported yet"
101
+ end
94
102
  end
95
103
  end
96
104
  save_succeeded = rep.save
@@ -175,13 +183,11 @@ module ReputationSystem
175
183
  end
176
184
 
177
185
  def self.max(reputation_name, target_type)
178
- ReputationSystem::Reputation.maximum(:value,
179
- :conditions => {:reputation_name => reputation_name.to_s, :target_type => target_type, :active => true})
186
+ ReputationSystem::Reputation.where(:reputation_name => reputation_name.to_s, :target_type => target_type, :active => true).maximum(:value)
180
187
  end
181
188
 
182
189
  def self.min(reputation_name, target_type)
183
- ReputationSystem::Reputation.minimum(:value,
184
- :conditions => {:reputation_name => reputation_name.to_s, :target_type => target_type, :active => true})
190
+ ReputationSystem::Reputation.where(:reputation_name => reputation_name.to_s, :target_type => target_type, :active => true).minimum(:value)
185
191
  end
186
192
 
187
193
  def self.get_target_type_for_sti(target, reputation_name)
@@ -44,6 +44,6 @@ module ReputationSystem
44
44
  errors.add(:sender, "must be an evaluation or a reputation")
45
45
  end
46
46
  end
47
-
47
+
48
48
  end
49
49
  end
@@ -25,21 +25,21 @@ module ReputationSystem
25
25
  end
26
26
 
27
27
  def activate_all_reputations
28
- ReputationSystem::Reputation.find(:all, :conditions => {:target_id => self.id, :target_type => self.class.name, :active => false}).each do |r|
28
+ ReputationSystem::Reputation.where(:target_id => self.id, :target_type => self.class.name, :active => false).each do |r|
29
29
  r.active = true
30
30
  r.save!
31
31
  end
32
32
  end
33
33
 
34
34
  def deactivate_all_reputations
35
- ReputationSystem::Reputation.find(:all, :conditions => {:target_id => self.id, :target_type => self.class.name, :active => true}).each do |r|
35
+ ReputationSystem::Reputation.where(:target_id => self.id, :target_type => self.class.name, :active => true).each do |r|
36
36
  r.active = false
37
37
  r.save!
38
38
  end
39
39
  end
40
40
 
41
41
  def reputations_activated?(reputation_name)
42
- r = ReputationSystem::Reputation.find(:first, :conditions => {:reputation_name => reputation_name.to_s, :target_id => self.id, :target_type => self.class.name})
42
+ r = ReputationSystem::Reputation.where(:reputation_name => reputation_name.to_s, :target_id => self.id, :target_type => self.class.name).first
43
43
  r ? r.active : false
44
44
  end
45
45
 
@@ -15,5 +15,5 @@
15
15
  ##
16
16
 
17
17
  module ReputationSystem
18
- VERSION = "2.0.2"
18
+ VERSION = "3.0.0"
19
19
  end
@@ -30,20 +30,20 @@ describe ReputationSystem::EvaluationMethods do
30
30
  it "should return false if it has not already been evaluated by a given source" do
31
31
  user = User.create! :name => 'katsuya'
32
32
  @question.add_evaluation(:total_votes, 3, user)
33
- @question.has_evaluation?(:total_votes, @user).should be_false
33
+ @question.has_evaluation?(:total_votes, @user).should be false
34
34
  end
35
35
  it "should return true if it has been evaluated by a given source" do
36
36
  @question.add_evaluation(:total_votes, 3, @user)
37
- @question.has_evaluation?(:total_votes, @user).should be_true
37
+ @question.has_evaluation?(:total_votes, @user).should be true
38
38
  end
39
39
  context "With Scopes" do
40
40
  it "should return false if it has not already been evaluated by a given source" do
41
41
  @phrase.add_evaluation(:difficulty_with_scope, 3, @user, :s1)
42
- @phrase.has_evaluation?(:difficulty_with_scope, @user, :s2).should be_false
42
+ @phrase.has_evaluation?(:difficulty_with_scope, @user, :s2).should be false
43
43
  end
44
44
  it "should return true if it has been evaluated by a given source" do
45
45
  @phrase.add_evaluation(:difficulty_with_scope, 3, @user, :s1)
46
- @phrase.has_evaluation?(:difficulty_with_scope, @user, :s1).should be_true
46
+ @phrase.has_evaluation?(:difficulty_with_scope, @user, :s1).should be true
47
47
  end
48
48
  end
49
49
  end
@@ -57,9 +57,9 @@ describe ReputationSystem::EvaluationMethods do
57
57
  user2 = User.create!(:name => 'katsuya')
58
58
  question2 = Question.create!(:text => 'Question 2', :author_id => @user.id)
59
59
  question3 = Question.create!(:text => 'Question 3', :author_id => @user.id)
60
- @question.add_evaluation(:total_votes, 1, @user).should be_true
61
- question2.add_evaluation(:total_votes, 2, user2).should be_true
62
- question3.add_evaluation(:total_votes, 3, @user).should be_true
60
+ @question.add_evaluation(:total_votes, 1, @user).should be true
61
+ question2.add_evaluation(:total_votes, 2, user2).should be true
62
+ question3.add_evaluation(:total_votes, 3, @user).should be true
63
63
  Question.evaluated_by(:total_votes, @user).should == [@question, question3]
64
64
  Question.evaluated_by(:total_votes, user2).should == [question2]
65
65
  end
@@ -68,14 +68,14 @@ describe ReputationSystem::EvaluationMethods do
68
68
  it "should return an array of targets evaluated by a given source on appropriate scope" do
69
69
  user2 = User.create!(:name => 'katsuya')
70
70
  phrase2 = Phrase.create!(:text => "Two")
71
- @phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1).should be_true
72
- @phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be_true
73
- @phrase.add_evaluation(:difficulty_with_scope, 3, user2, :s2).should be_true
74
- @phrase.add_evaluation(:difficulty_with_scope, 4, user2, :s3).should be_true
75
- phrase2.add_evaluation(:difficulty_with_scope, 1, user2, :s1).should be_true
76
- phrase2.add_evaluation(:difficulty_with_scope, 2, user2, :s2).should be_true
77
- phrase2.add_evaluation(:difficulty_with_scope, 3, @user, :s2).should be_true
78
- phrase2.add_evaluation(:difficulty_with_scope, 4, @user, :s3).should be_true
71
+ @phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1).should be true
72
+ @phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be true
73
+ @phrase.add_evaluation(:difficulty_with_scope, 3, user2, :s2).should be true
74
+ @phrase.add_evaluation(:difficulty_with_scope, 4, user2, :s3).should be true
75
+ phrase2.add_evaluation(:difficulty_with_scope, 1, user2, :s1).should be true
76
+ phrase2.add_evaluation(:difficulty_with_scope, 2, user2, :s2).should be true
77
+ phrase2.add_evaluation(:difficulty_with_scope, 3, @user, :s2).should be true
78
+ phrase2.add_evaluation(:difficulty_with_scope, 4, @user, :s3).should be true
79
79
  Phrase.evaluated_by(:difficulty_with_scope, @user, :s1).should == [@phrase]
80
80
  Phrase.evaluated_by(:difficulty_with_scope, user2, :s1).should == [phrase2]
81
81
  Phrase.evaluated_by(:difficulty_with_scope, @user, :s2).should == [@phrase, phrase2]
@@ -94,9 +94,9 @@ describe ReputationSystem::EvaluationMethods do
94
94
  it "should return an array of sources evaluated the target" do
95
95
  user2 = User.create!(:name => 'katsuya')
96
96
  question2 = Question.create!(:text => 'Question 2', :author_id => @user.id)
97
- @question.add_evaluation(:total_votes, 1, @user).should be_true
98
- question2.add_evaluation(:total_votes, 1, @user).should be_true
99
- question2.add_evaluation(:total_votes, 2, user2).should be_true
97
+ @question.add_evaluation(:total_votes, 1, @user).should be true
98
+ question2.add_evaluation(:total_votes, 1, @user).should be true
99
+ question2.add_evaluation(:total_votes, 2, user2).should be true
100
100
  @question.evaluators_for(:total_votes).should == [@user]
101
101
  question2.evaluators_for(:total_votes).should == [@user, user2]
102
102
  end
@@ -104,10 +104,10 @@ describe ReputationSystem::EvaluationMethods do
104
104
  context "With Scopes" do
105
105
  it "should return an array of targets evaluated by a given source on appropriate scope" do
106
106
  user2 = User.create!(:name => 'katsuya')
107
- @phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1).should be_true
108
- @phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be_true
109
- @phrase.add_evaluation(:difficulty_with_scope, 3, user2, :s2).should be_true
110
- @phrase.add_evaluation(:difficulty_with_scope, 4, user2, :s3).should be_true
107
+ @phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1).should be true
108
+ @phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be true
109
+ @phrase.add_evaluation(:difficulty_with_scope, 3, user2, :s2).should be true
110
+ @phrase.add_evaluation(:difficulty_with_scope, 4, user2, :s3).should be true
111
111
  @phrase.evaluators_for(:difficulty_with_scope, :s1).should == [@user]
112
112
  @phrase.evaluators_for(:difficulty_with_scope, :s2).should == [@user, user2]
113
113
  @phrase.evaluators_for(:difficulty_with_scope, :s3).should == [user2]
@@ -117,7 +117,7 @@ describe ReputationSystem::EvaluationMethods do
117
117
 
118
118
  describe "#add_evaluation" do
119
119
  it "should create evaluation in case of valid input" do
120
- @question.add_evaluation(:total_votes, 1, @user).should be_true
120
+ @question.add_evaluation(:total_votes, 1, @user).should be true
121
121
  @question.reputation_for(:total_votes).should == 1
122
122
  end
123
123
 
@@ -142,8 +142,8 @@ describe ReputationSystem::EvaluationMethods do
142
142
 
143
143
  context "with scopes" do
144
144
  it "should add evaluation on appropriate scope" do
145
- @phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1).should be_true
146
- @phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be_true
145
+ @phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1).should be true
146
+ @phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be true
147
147
  @phrase.reputation_for(:difficulty_with_scope, :s1).should == 1
148
148
  @phrase.reputation_for(:difficulty_with_scope, :s2).should == 2
149
149
  @phrase.reputation_for(:difficulty_with_scope, :s3).should == 0
@@ -161,30 +161,30 @@ describe ReputationSystem::EvaluationMethods do
161
161
 
162
162
  describe "#add_or_update_evaluation" do
163
163
  it "should create evaluation if it does not exist" do
164
- @question.add_or_update_evaluation(:total_votes, 1, @user).should be_true
164
+ @question.add_or_update_evaluation(:total_votes, 1, @user).should be true
165
165
  @question.reputation_for(:total_votes).should == 1
166
166
  end
167
167
 
168
168
  it "should update evaluation if it exists already" do
169
169
  @question.add_evaluation(:total_votes, 1, @user)
170
- @question.add_or_update_evaluation(:total_votes, 2, @user).should be_true
170
+ @question.add_or_update_evaluation(:total_votes, 2, @user).should be true
171
171
  @question.reputation_for(:total_votes).should == 2
172
172
  end
173
173
 
174
174
  context "with scopes" do
175
175
  it "should add evaluation on appropriate scope if it does not exist" do
176
- @phrase.add_or_update_evaluation(:difficulty_with_scope, 1, @user, :s1).should be_true
177
- @phrase.add_or_update_evaluation(:difficulty_with_scope, 2, @user, :s2).should be_true
176
+ @phrase.add_or_update_evaluation(:difficulty_with_scope, 1, @user, :s1).should be true
177
+ @phrase.add_or_update_evaluation(:difficulty_with_scope, 2, @user, :s2).should be true
178
178
  @phrase.reputation_for(:difficulty_with_scope, :s1).should == 1
179
179
  @phrase.reputation_for(:difficulty_with_scope, :s2).should == 2
180
180
  @phrase.reputation_for(:difficulty_with_scope, :s3).should == 0
181
181
  end
182
182
 
183
183
  it "should update evaluation on appropriate scope if it exists already" do
184
- @phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1).should be_true
185
- @phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be_true
186
- @phrase.add_or_update_evaluation(:difficulty_with_scope, 3, @user, :s1).should be_true
187
- @phrase.add_or_update_evaluation(:difficulty_with_scope, 5, @user, :s2).should be_true
184
+ @phrase.add_evaluation(:difficulty_with_scope, 1, @user, :s1).should be true
185
+ @phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be true
186
+ @phrase.add_or_update_evaluation(:difficulty_with_scope, 3, @user, :s1).should be true
187
+ @phrase.add_or_update_evaluation(:difficulty_with_scope, 5, @user, :s2).should be true
188
188
  @phrase.reputation_for(:difficulty_with_scope, :s1).should == 3
189
189
  @phrase.reputation_for(:difficulty_with_scope, :s2).should == 5
190
190
  @phrase.reputation_for(:difficulty_with_scope, :s3).should == 0
@@ -208,7 +208,7 @@ describe ReputationSystem::EvaluationMethods do
208
208
  end
209
209
 
210
210
  it "should update evaluation in case of valid input" do
211
- @question.update_evaluation(:total_votes, 2, @user).should be_true
211
+ @question.update_evaluation(:total_votes, 2, @user).should be true
212
212
  @question.reputation_for(:total_votes).should == 2
213
213
  end
214
214
 
@@ -226,11 +226,11 @@ describe ReputationSystem::EvaluationMethods do
226
226
 
227
227
  context "With Scopes" do
228
228
  before :each do
229
- @phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be_true
229
+ @phrase.add_evaluation(:difficulty_with_scope, 2, @user, :s2).should be true
230
230
  end
231
231
 
232
232
  it "should update evaluation on appropriate scope" do
233
- @phrase.update_evaluation(:difficulty_with_scope, 5, @user, :s2).should be_true
233
+ @phrase.update_evaluation(:difficulty_with_scope, 5, @user, :s2).should be true
234
234
  @phrase.reputation_for(:difficulty_with_scope, :s1).should == 0
235
235
  @phrase.reputation_for(:difficulty_with_scope, :s2).should == 5
236
236
  @phrase.reputation_for(:difficulty_with_scope, :s3).should == 0
@@ -296,7 +296,7 @@ describe ReputationSystem::EvaluationMethods do
296
296
  end
297
297
 
298
298
  it "should delete evaluation in case of valid input" do
299
- @question.delete_evaluation(:total_votes, @user).should be_true
299
+ @question.delete_evaluation(:total_votes, @user).should be true
300
300
  @question.reputation_for(:total_votes).should == 0
301
301
  end
302
302
 
@@ -305,7 +305,7 @@ describe ReputationSystem::EvaluationMethods do
305
305
  end
306
306
 
307
307
  it "should return false if evaluation does not exist" do
308
- @answer.delete_evaluation(:avg_rating, @user).should be_false
308
+ @answer.delete_evaluation(:avg_rating, @user).should be false
309
309
  end
310
310
 
311
311
  context "With Scopes" do
@@ -314,7 +314,7 @@ describe ReputationSystem::EvaluationMethods do
314
314
  end
315
315
 
316
316
  it "should delete evaluation on appropriate scope" do
317
- @phrase.delete_evaluation(:difficulty_with_scope, @user, :s2).should be_true
317
+ @phrase.delete_evaluation(:difficulty_with_scope, @user, :s2).should be true
318
318
  @phrase.reputation_for(:difficulty_with_scope, :s1).should == 0
319
319
  @phrase.reputation_for(:difficulty_with_scope, :s2).should == 0
320
320
  @phrase.reputation_for(:difficulty_with_scope, :s3).should == 0
@@ -332,13 +332,13 @@ describe ReputationSystem::EvaluationMethods do
332
332
 
333
333
  describe "#increase_evaluation" do
334
334
  it "should add evaluation if it does not exist" do
335
- @question.increase_evaluation(:total_votes, 2, @user).should be_true
335
+ @question.increase_evaluation(:total_votes, 2, @user).should be true
336
336
  @question.reputation_for(:total_votes).should == 2
337
337
  end
338
338
 
339
339
  it "should increase evaluation if it exists already" do
340
340
  @question.add_evaluation(:total_votes, 1, @user)
341
- @question.increase_evaluation(:total_votes, 2, @user).should be_true
341
+ @question.increase_evaluation(:total_votes, 2, @user).should be true
342
342
  @question.reputation_for(:total_votes).should == 3
343
343
  end
344
344
 
@@ -348,7 +348,7 @@ describe ReputationSystem::EvaluationMethods do
348
348
  end
349
349
 
350
350
  it "should increase evaluation on appropriate scope" do
351
- @phrase.increase_evaluation(:difficulty_with_scope, 5, @user, :s2).should be_true
351
+ @phrase.increase_evaluation(:difficulty_with_scope, 5, @user, :s2).should be true
352
352
  @phrase.reputation_for(:difficulty_with_scope, :s1).should == 0
353
353
  @phrase.reputation_for(:difficulty_with_scope, :s2).should == 7
354
354
  @phrase.reputation_for(:difficulty_with_scope, :s3).should == 0
@@ -358,13 +358,13 @@ describe ReputationSystem::EvaluationMethods do
358
358
 
359
359
  describe "#decrease_evaluation" do
360
360
  it "should add evaluation if it does not exist" do
361
- @question.decrease_evaluation(:total_votes, 2, @user).should be_true
361
+ @question.decrease_evaluation(:total_votes, 2, @user).should be true
362
362
  @question.reputation_for(:total_votes).should == -2
363
363
  end
364
364
 
365
365
  it "should increase evaluation if it exists already" do
366
366
  @question.add_evaluation(:total_votes, 1, @user)
367
- @question.decrease_evaluation(:total_votes, 2, @user).should be_true
367
+ @question.decrease_evaluation(:total_votes, 2, @user).should be true
368
368
  @question.reputation_for(:total_votes).should == -1
369
369
  end
370
370
 
@@ -374,7 +374,7 @@ describe ReputationSystem::EvaluationMethods do
374
374
  end
375
375
 
376
376
  it "should decrease evaluation on appropriate scope" do
377
- @phrase.decrease_evaluation(:difficulty_with_scope, 5, @user, :s2).should be_true
377
+ @phrase.decrease_evaluation(:difficulty_with_scope, 5, @user, :s2).should be true
378
378
  @phrase.reputation_for(:difficulty_with_scope, :s1).should == 0
379
379
  @phrase.reputation_for(:difficulty_with_scope, :s2).should == -3
380
380
  @phrase.reputation_for(:difficulty_with_scope, :s3).should == 0
@@ -177,6 +177,7 @@ describe ReputationSystem::FinderMethods do
177
177
  "FROM \"questions\" JOIN users ON questions.author_id = users.id "\
178
178
  "LEFT JOIN rs_reputations ON questions.id = rs_reputations.target_id AND rs_reputations.target_type = 'Question' AND rs_reputations.reputation_name = 'total_votes' AND rs_reputations.active = 't' "\
179
179
  "WHERE (COALESCE(rs_reputations.value, 0) > 0.6) "\
180
+ " " if ActiveRecord::VERSION::STRING >= '4' \
180
181
  "ORDER BY total_votes"
181
182
  end
182
183
  end
@@ -59,4 +59,12 @@ describe ReputationSystem::Evaluation do
59
59
  ReputationSystem::ReputationMessage.find_by_sender_id_and_sender_type(evaluation.id, evaluation.class.name).should be_nil
60
60
  end
61
61
  end
62
+
63
+ context "Additional Data" do
64
+ it "should have data as a serialized field" do
65
+ @attributes = {:reputation_name => 'total_votes', :source => @user, :target => @question, :value => 1}
66
+ e = ReputationSystem::Evaluation.create!(@attributes)
67
+ e.data.should be_a(Hash)
68
+ end
69
+ end
62
70
  end
@@ -46,8 +46,12 @@ describe ReputationSystem::Reputation do
46
46
  ReputationSystem::Reputation.create(:reputation_name => "karma3", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'product').should be_valid
47
47
  end
48
48
 
49
- it "should not be able to create reputation with process other than 'sum', 'average' and 'product'" do
50
- ReputationSystem::Reputation.create(:reputation_name => "karma", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'invalid').should_not be_valid
49
+ it "should be able to create reputation with custom process" do
50
+ ReputationSystem::Reputation.create(:reputation_name => "karma", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'custom_process').should be_valid
51
+ end
52
+
53
+ it "should be able to create reputation with custom process from source" do
54
+ ReputationSystem::Reputation.create(:reputation_name => "custom_rating", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'custom_rating').should be_valid
51
55
  end
52
56
 
53
57
  it "should not be able to create reputation of the same name for the same target" do
@@ -133,4 +137,31 @@ describe ReputationSystem::Reputation do
133
137
  answer.reputation_for(:avg_rating).should be_within(DELTA).of(3)
134
138
  end
135
139
  end
140
+
141
+ describe "custom aggregation function" do
142
+ it "should calculate based on a custom function for new source" do
143
+ user1 = User.create! :name => 'dick'
144
+ user2 = User.create! :name => 'katsuya'
145
+ answer = Answer.create!
146
+ answer.add_or_update_evaluation(:custom_rating, 3, user1)
147
+ answer.add_or_update_evaluation(:custom_rating, 2, user2)
148
+ answer.reputation_for(:custom_rating).should be_within(DELTA).of(50)
149
+ end
150
+
151
+ it "should calculate based on a custom function for updated source" do
152
+ user1 = User.create! :name => 'dick'
153
+ user2 = User.create! :name => 'katsuya'
154
+ answer = Answer.create!
155
+ answer.add_or_update_evaluation(:custom_rating, 3, user1)
156
+ answer.add_or_update_evaluation(:custom_rating, 2, user1)
157
+ answer.reputation_for(:custom_rating).should be_within(DELTA).of(20)
158
+ end
159
+ end
160
+
161
+ describe "additional data" do
162
+ it "should have data as a serialized field" do
163
+ r = ReputationSystem::Reputation.create!(:reputation_name => "karma", :target_id => @user.id, :target_type => @user.class.to_s, :aggregated_by => 'sum')
164
+ r.data.should be_a(Hash)
165
+ end
166
+ end
136
167
  end
@@ -153,9 +153,9 @@ describe ReputationSystem::ReputationMethods do
153
153
  @question2.add_evaluation(:total_votes, 70, @user)
154
154
  @question.add_evaluation(:total_votes, 100, @user)
155
155
  @question.deactivate_all_reputations
156
- ReputationSystem::Reputation.maximum(:value, :conditions => {:reputation_name => 'total_votes', :active => true}).should == 70
156
+ ReputationSystem::Reputation.where(:reputation_name => 'total_votes', :active => true).maximum(:value).should == 70
157
157
  @question.activate_all_reputations
158
- ReputationSystem::Reputation.maximum(:value, :conditions => {:reputation_name => 'total_votes', :active => true}).should == 100
158
+ ReputationSystem::Reputation.where(:reputation_name => 'total_votes', :active => true).maximum(:value).should == 100
159
159
  end
160
160
  end
161
161
  end
data/spec/spec_helper.rb CHANGED
@@ -43,6 +43,7 @@ ActiveRecord::Schema.define do
43
43
  t.references :source, :polymorphic => true
44
44
  t.references :target, :polymorphic => true
45
45
  t.float :value, :default => 0
46
+ t.text :data
46
47
  t.timestamps
47
48
  end
48
49
 
@@ -56,6 +57,7 @@ ActiveRecord::Schema.define do
56
57
  t.string :aggregated_by
57
58
  t.references :target, :polymorphic => true
58
59
  t.boolean :active, :default => true
60
+ t.text :data
59
61
  t.timestamps
60
62
  end
61
63
 
@@ -132,6 +134,14 @@ class User < ActiveRecord::Base
132
134
  has_reputation :answer_karma,
133
135
  :source => { :reputation => :weighted_avg_rating, :of => :answers },
134
136
  :aggregated_by => :average
137
+
138
+ has_reputation :custom_rating,
139
+ :source => { :reputation => :custom_rating, :of => :answers },
140
+ :aggregated_by => :custom_rating
141
+
142
+ def custom_process
143
+ 123
144
+ end
135
145
  end
136
146
 
137
147
  class Question < ActiveRecord::Base
@@ -161,12 +171,29 @@ class Answer < ActiveRecord::Base
161
171
  has_reputation :avg_rating,
162
172
  :source => :user,
163
173
  :aggregated_by => :average
174
+
175
+ has_reputation :custom_rating,
176
+ :source => :user,
177
+ :aggregated_by => :custom_aggregation,
178
+ :source_of => { :reputation => :custom_rating, :of => :author }
179
+
180
+ def custom_aggregation(*args)
181
+ rep, source, weight = args[0..2]
182
+ # rep, source, weight
183
+ if args.length === 3
184
+ rep.value + weight * source.value * 10
185
+ # rep, source, weight, oldValue, newSize
186
+ elsif args.length === 5
187
+ oldValue, newSize = args[3..4]
188
+ rep.value + (source.value - oldValue) * 10
189
+ end
190
+ end
164
191
  end
165
192
 
166
193
  class Phrase < ActiveRecord::Base
167
194
  has_many :translations do
168
195
  def for(locale)
169
- self.find_all_by_locale(locale.to_s)
196
+ self.where(:locale => locale.to_s).to_a
170
197
  end
171
198
  end
172
199
 
metadata CHANGED
@@ -1,52 +1,60 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-reputation-system
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
5
- prerelease:
4
+ version: 3.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Katsuya Noguchi
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-12-01 00:00:00.000000000 Z
11
+ date: 2014-10-07 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: activerecord
14
+ name: protected_attributes
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
- type: :development
20
+ type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
30
41
  - !ruby/object:Gem::Dependency
31
42
  name: rake
32
43
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
44
  requirements:
35
- - - ! '>='
45
+ - - '>='
36
46
  - !ruby/object:Gem::Version
37
47
  version: 0.8.7
38
48
  type: :development
39
49
  prerelease: false
40
50
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
51
  requirements:
43
- - - ! '>='
52
+ - - '>='
44
53
  - !ruby/object:Gem::Version
45
54
  version: 0.8.7
46
55
  - !ruby/object:Gem::Dependency
47
56
  name: rspec
48
57
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
58
  requirements:
51
59
  - - ~>
52
60
  - !ruby/object:Gem::Version
@@ -54,7 +62,6 @@ dependencies:
54
62
  type: :development
55
63
  prerelease: false
56
64
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
65
  requirements:
59
66
  - - ~>
60
67
  - !ruby/object:Gem::Version
@@ -62,39 +69,34 @@ dependencies:
62
69
  - !ruby/object:Gem::Dependency
63
70
  name: rdoc
64
71
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
72
  requirements:
67
- - - ! '>='
73
+ - - '>='
68
74
  - !ruby/object:Gem::Version
69
75
  version: '0'
70
76
  type: :development
71
77
  prerelease: false
72
78
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
79
  requirements:
75
- - - ! '>='
80
+ - - '>='
76
81
  - !ruby/object:Gem::Version
77
82
  version: '0'
78
83
  - !ruby/object:Gem::Dependency
79
84
  name: database_cleaner
80
85
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
86
  requirements:
83
87
  - - ~>
84
88
  - !ruby/object:Gem::Version
85
- version: 0.7.1
89
+ version: 1.2.0
86
90
  type: :development
87
91
  prerelease: false
88
92
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
93
  requirements:
91
94
  - - ~>
92
95
  - !ruby/object:Gem::Version
93
- version: 0.7.1
96
+ version: 1.2.0
94
97
  - !ruby/object:Gem::Dependency
95
98
  name: sqlite3
96
99
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
100
  requirements:
99
101
  - - ~>
100
102
  - !ruby/object:Gem::Version
@@ -102,7 +104,6 @@ dependencies:
102
104
  type: :development
103
105
  prerelease: false
104
106
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
107
  requirements:
107
108
  - - ~>
108
109
  - !ruby/object:Gem::Version
@@ -120,6 +121,8 @@ files:
120
121
  - Rakefile
121
122
  - lib/activerecord-reputation-system.rb
122
123
  - lib/generators/reputation_system/reputation_system_generator.rb
124
+ - lib/generators/reputation_system/templates/add_data_to_evaluations.rb
125
+ - lib/generators/reputation_system/templates/add_data_to_reputations.rb
123
126
  - lib/generators/reputation_system/templates/add_evaluations_index.rb
124
127
  - lib/generators/reputation_system/templates/add_reputation_messages_index.rb
125
128
  - lib/generators/reputation_system/templates/add_reputations_index.rb
@@ -127,6 +130,7 @@ files:
127
130
  - lib/generators/reputation_system/templates/change_reputation_messages_index_to_unique.rb
128
131
  - lib/generators/reputation_system/templates/change_reputations_index_to_unique.rb
129
132
  - lib/generators/reputation_system/templates/create_reputation_system.rb
133
+ - lib/reputation_system.rb
130
134
  - lib/reputation_system/base.rb
131
135
  - lib/reputation_system/evaluation_methods.rb
132
136
  - lib/reputation_system/finder_methods.rb
@@ -139,7 +143,6 @@ files:
139
143
  - lib/reputation_system/reputation_methods.rb
140
144
  - lib/reputation_system/scope_methods.rb
141
145
  - lib/reputation_system/version.rb
142
- - lib/reputation_system.rb
143
146
  - spec/reputation_system/base_spec.rb
144
147
  - spec/reputation_system/evaluation_methods_spec.rb
145
148
  - spec/reputation_system/finder_methods_spec.rb
@@ -152,27 +155,26 @@ files:
152
155
  - spec/spec_helper.rb
153
156
  homepage: https://github.com/twitter/activerecord-reputation-system
154
157
  licenses: []
158
+ metadata: {}
155
159
  post_install_message:
156
160
  rdoc_options: []
157
161
  require_paths:
158
162
  - lib
159
163
  required_ruby_version: !ruby/object:Gem::Requirement
160
- none: false
161
164
  requirements:
162
- - - ! '>='
165
+ - - '>='
163
166
  - !ruby/object:Gem::Version
164
167
  version: '0'
165
168
  required_rubygems_version: !ruby/object:Gem::Requirement
166
- none: false
167
169
  requirements:
168
- - - ! '>='
170
+ - - '>='
169
171
  - !ruby/object:Gem::Version
170
172
  version: '0'
171
173
  requirements: []
172
174
  rubyforge_project:
173
- rubygems_version: 1.8.23
175
+ rubygems_version: 2.2.2
174
176
  signing_key:
175
- specification_version: 3
177
+ specification_version: 4
176
178
  summary: ActiveRecord Reputation System gem allows rails apps to compute and publish
177
179
  reputation scores for active record models
178
180
  test_files: []