reputation 0.0.2
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.
- data/.infinity_test +35 -0
- data/.rspec +2 -0
- data/app/models/reputation_behaviour.rb +38 -0
- data/app/models/reputation_intermediate_value.rb +22 -0
- data/app/models/reputation_rule.rb +107 -0
- data/generators/reputation/reputation_generator.rb +11 -0
- data/generators/reputation/templates/reputation_create_tables.rb +37 -0
- data/lib/reputation.rb +3 -0
- data/lib/reputation/engine.rb +8 -0
- data/lib/reputation/functions.rb +4 -0
- data/lib/reputation/functions/generalised_logistic_curve.rb +37 -0
- data/lib/reputation/functions/linear.rb +21 -0
- data/lib/reputation/functions/mixin.rb +44 -0
- data/lib/reputation/functions/step.rb +27 -0
- data/lib/reputation/user.rb +38 -0
- data/rails/init.rb +1 -0
- data/spec/functions/generalised_logistic_curve_spec.rb +50 -0
- data/spec/functions/linear_spec.rb +21 -0
- data/spec/functions/step_spec.rb +28 -0
- data/spec/helpers/functions.rb +13 -0
- data/spec/models/behaviour_spec.rb +31 -0
- data/spec/models/intermediate_value_spec.rb +29 -0
- data/spec/models/rule_spec.rb +233 -0
- data/spec/models/user_spec.rb +25 -0
- data/spec/rails_root/Rakefile +10 -0
- data/spec/rails_root/app/controllers/application_controller.rb +10 -0
- data/spec/rails_root/app/helpers/application_helper.rb +3 -0
- data/spec/rails_root/app/models/user.rb +3 -0
- data/spec/rails_root/config/boot.rb +114 -0
- data/spec/rails_root/config/database.yml +16 -0
- data/spec/rails_root/config/environment.rb +41 -0
- data/spec/rails_root/config/environments/development.rb +17 -0
- data/spec/rails_root/config/environments/test.rb +28 -0
- data/spec/rails_root/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_root/config/initializers/cookie_verification_secret.rb +7 -0
- data/spec/rails_root/config/initializers/inflections.rb +10 -0
- data/spec/rails_root/config/initializers/mime_types.rb +5 -0
- data/spec/rails_root/config/initializers/new_rails_defaults.rb +21 -0
- data/spec/rails_root/config/initializers/session_store.rb +15 -0
- data/spec/rails_root/config/routes.rb +43 -0
- data/spec/rails_root/db/development.sqlite3 +0 -0
- data/spec/rails_root/db/migrate/20110414125319_create_users.rb +11 -0
- data/spec/rails_root/db/migrate/20110812160932_reputation_create_tables.rb +37 -0
- data/spec/rails_root/db/schema.rb +48 -0
- data/spec/rails_root/db/test.sqlite3 +0 -0
- data/spec/rails_root/log/development.log +3471 -0
- data/spec/rails_root/log/test.log +27696 -0
- data/spec/rails_root/script/about +4 -0
- data/spec/rails_root/script/console +3 -0
- data/spec/rails_root/script/dbconsole +3 -0
- data/spec/rails_root/script/destroy +3 -0
- data/spec/rails_root/script/generate +3 -0
- data/spec/rails_root/script/performance/benchmarker +3 -0
- data/spec/rails_root/script/performance/profiler +3 -0
- data/spec/rails_root/script/plugin +3 -0
- data/spec/rails_root/script/runner +3 -0
- data/spec/rails_root/script/server +3 -0
- data/spec/scenarios/collection_spec.rb +118 -0
- data/spec/scenarios/singular_spec.rb +84 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +15 -0
- metadata +289 -0
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'reputation'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Reputation::Functions::GeneralisedLogisticCurve do
|
4
|
+
|
5
|
+
it_should_behave_like "any function"
|
6
|
+
|
7
|
+
describe "instance method" do
|
8
|
+
describe "'f'" do
|
9
|
+
it "should have an adjustable gradient" do
|
10
|
+
function_1 = Reputation::Functions::GeneralisedLogisticCurve.new(
|
11
|
+
:a => 0,
|
12
|
+
:k => 1,
|
13
|
+
:b => 1.5,
|
14
|
+
:v => 0.5,
|
15
|
+
:q => 0.5,
|
16
|
+
:m => 0.5
|
17
|
+
)
|
18
|
+
function_2 = Reputation::Functions::GeneralisedLogisticCurve.new(
|
19
|
+
:a => 0,
|
20
|
+
:k => 1,
|
21
|
+
:b => 0.5,
|
22
|
+
:v => 0.1,
|
23
|
+
:q => 0.5,
|
24
|
+
:m => 15
|
25
|
+
)
|
26
|
+
function_3 = Reputation::Functions::GeneralisedLogisticCurve.new(
|
27
|
+
:a => 0,
|
28
|
+
:k => 1,
|
29
|
+
:b => 0.5,
|
30
|
+
:v => 1.0,
|
31
|
+
:q => 0.5,
|
32
|
+
:m => 15
|
33
|
+
)
|
34
|
+
|
35
|
+
function_1.f(0).should be_close(0.23, 0.05)
|
36
|
+
function_2.f(0).should be_close(0, 0.05)
|
37
|
+
function_3.f(0).should be_close(0, 0.05)
|
38
|
+
|
39
|
+
function_1.f(5).should be_close(0.99, 0.05)
|
40
|
+
function_2.f(5).should be_close(0, 0.05)
|
41
|
+
function_3.f(5).should be_close(0, 0.05)
|
42
|
+
|
43
|
+
function_1.f(20).should be_close(1, 0.05)
|
44
|
+
function_2.f(20).should be_close(0.66, 0.05)
|
45
|
+
function_3.f(20).should be_close(0.96, 0.05)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Reputation::Functions::Linear do
|
4
|
+
|
5
|
+
it_should_behave_like "any function"
|
6
|
+
|
7
|
+
describe "instance method" do
|
8
|
+
describe "'f'" do
|
9
|
+
it "should have an adjustable gradient" do
|
10
|
+
function_1 = Reputation::Functions::Linear.new :m => 1
|
11
|
+
function_2 = Reputation::Functions::Linear.new :m => 2
|
12
|
+
function_3 = Reputation::Functions::Linear.new :m => 3
|
13
|
+
|
14
|
+
function_1.f(0.25).should eql 0.25
|
15
|
+
function_2.f(0.25).should eql 0.5
|
16
|
+
function_3.f(0.25).should eql 0.75
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Reputation::Functions::Step do
|
4
|
+
|
5
|
+
it_should_behave_like "any function"
|
6
|
+
|
7
|
+
describe "instance method" do
|
8
|
+
|
9
|
+
describe "'f'" do
|
10
|
+
it "should have an adjustable step" do
|
11
|
+
function_1 = Reputation::Functions::Step.new :c => 1
|
12
|
+
function_2 = Reputation::Functions::Step.new :c => 2
|
13
|
+
function_3 = Reputation::Functions::Step.new :c => 3
|
14
|
+
|
15
|
+
function_1.f(0.99).should eql -1
|
16
|
+
function_1.f(1).should eql 1
|
17
|
+
|
18
|
+
function_2.f(1.99).should eql -1
|
19
|
+
function_2.f(2).should eql 1
|
20
|
+
|
21
|
+
function_3.f(2.99).should eql -1
|
22
|
+
function_3.f(3).should eql 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
shared_examples_for "any function" do
|
2
|
+
describe "instance method" do
|
3
|
+
describe "'f'" do
|
4
|
+
it "should return 0 for a large negative number" do
|
5
|
+
subject.f(-10000).should == -1
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should return 1 for a large positivie number" do
|
9
|
+
subject.f(10000).should == 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReputationBehaviour do
|
4
|
+
|
5
|
+
before(:each) {
|
6
|
+
@rule = ReputationRule.create!(:name => "foo")
|
7
|
+
@user = User.create!(:name => "bob")
|
8
|
+
ReputationBehaviour.create!(:user => @user, :rule => @rule, :metric => 0)
|
9
|
+
}
|
10
|
+
|
11
|
+
it { should belong_to :user }
|
12
|
+
it { should belong_to :rule }
|
13
|
+
|
14
|
+
it { should validate_presence_of :user }
|
15
|
+
it { should validate_presence_of :rule }
|
16
|
+
it { should validate_numericality_of :metric }
|
17
|
+
|
18
|
+
it { should validate_uniqueness_of( :user_id ).scoped_to(:rule_id) }
|
19
|
+
|
20
|
+
it { should allow_mass_assignment_of :user }
|
21
|
+
it { should allow_mass_assignment_of :metric }
|
22
|
+
|
23
|
+
it "should allow the rule to be set via a name" do
|
24
|
+
ReputationBehaviour.create!(:user => User.create!, :rule => @rule.name, :metric => 0).rule.should eql @rule
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should allow the rule to be set using a Rule object" do
|
28
|
+
ReputationBehaviour.create!(:user => User.create!, :rule => @rule, :metric => 0).rule.should eql @rule
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReputationIntermediateValue do
|
4
|
+
|
5
|
+
before(:each) {
|
6
|
+
rule = ReputationRule.create!(:name => "foo")
|
7
|
+
user = User.create!(:name => "bob")
|
8
|
+
ReputationIntermediateValue.create!(:rule => rule, :user => user, :name => "foo")
|
9
|
+
}
|
10
|
+
|
11
|
+
it { should belong_to :user }
|
12
|
+
it { should belong_to :rule }
|
13
|
+
|
14
|
+
it { should validate_presence_of :user }
|
15
|
+
it { should validate_presence_of :rule }
|
16
|
+
it { should validate_numericality_of :value }
|
17
|
+
|
18
|
+
it { should validate_uniqueness_of( :name ).scoped_to(:user_id, :rule_id) }
|
19
|
+
|
20
|
+
it { should allow_mass_assignment_of :user }
|
21
|
+
it { should allow_mass_assignment_of :rule }
|
22
|
+
it { should allow_mass_assignment_of :name }
|
23
|
+
it { should allow_mass_assignment_of :value }
|
24
|
+
|
25
|
+
it "should set value to 0 by default" do
|
26
|
+
subject.value.should eql 0
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ReputationRule do
|
4
|
+
|
5
|
+
subject{ ReputationRule.create! :name => "test" }
|
6
|
+
|
7
|
+
it { should have_many :intermediate_values }
|
8
|
+
it { should have_many :behaviours }
|
9
|
+
|
10
|
+
it { should validate_presence_of :name }
|
11
|
+
it {
|
12
|
+
ReputationRule.create! :name => "wibble"
|
13
|
+
should validate_uniqueness_of :name
|
14
|
+
}
|
15
|
+
it { should validate_numericality_of :weight }
|
16
|
+
|
17
|
+
it { should allow_mass_assignment_of :name }
|
18
|
+
it { should allow_mass_assignment_of :kind }
|
19
|
+
it { should allow_mass_assignment_of :weight }
|
20
|
+
it { should allow_mass_assignment_of :function }
|
21
|
+
it { should allow_mass_assignment_of :constants }
|
22
|
+
it { should allow_mass_assignment_of :aggregate_function }
|
23
|
+
it { should allow_mass_assignment_of :aggregate_constants }
|
24
|
+
|
25
|
+
describe "initializing" do
|
26
|
+
it "should allow optional arguments" do
|
27
|
+
r = ReputationRule.create!(
|
28
|
+
:name => 'foo',
|
29
|
+
:weight => 4,
|
30
|
+
:function => 'generalised_logistic_curve',
|
31
|
+
:constants => {
|
32
|
+
:b => 2
|
33
|
+
},
|
34
|
+
:aggregate_function => 'step',
|
35
|
+
:aggregate_constants => {
|
36
|
+
:c => 20
|
37
|
+
}
|
38
|
+
)
|
39
|
+
|
40
|
+
r.weight.should == 4
|
41
|
+
r.function.should be_a Reputation::Functions::GeneralisedLogisticCurve
|
42
|
+
r.function.b.should == 2
|
43
|
+
r.aggregate_function.should be_a Reputation::Functions::Step
|
44
|
+
r.aggregate_function.c.should == 20
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "defaults" do
|
48
|
+
it { subject.weight.should eql 1 }
|
49
|
+
it { subject.function.should be_a Reputation::Functions::Linear }
|
50
|
+
it { subject.constants.should eql({ :m => 1 }) }
|
51
|
+
it { subject.aggregate_function.should be_a Reputation::Functions::Linear }
|
52
|
+
it { subject.aggregate_constants.should eql({ :m => 1 }) }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "instance method " do
|
57
|
+
|
58
|
+
describe "#function" do
|
59
|
+
|
60
|
+
it "should return a function object" do
|
61
|
+
subject.function.should be_a Reputation::Functions::Linear
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should depend on function attribute" do
|
65
|
+
subject.function = 'step'
|
66
|
+
subject.function.should be_a Reputation::Functions::Step
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should depend on constants attribute" do
|
70
|
+
subject.constants = {:m => 2.2}
|
71
|
+
subject.function.m.should eql 2.2
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#aggregate_function" do
|
77
|
+
|
78
|
+
it "should return a function object" do
|
79
|
+
subject.aggregate_function.should be_a Reputation::Functions::Linear
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should depend on function attribute" do
|
83
|
+
subject.aggregate_function = 'step'
|
84
|
+
subject.aggregate_function.should be_a Reputation::Functions::Step
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should depend on constants attribute" do
|
88
|
+
subject.aggregate_constants = {:m => 2.2}
|
89
|
+
subject.aggregate_function.m.should eql 2.2
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#normalized_weighting" do
|
95
|
+
it "should be 1 if there are no other rules" do
|
96
|
+
subject.update_attribute :weight, 200
|
97
|
+
|
98
|
+
subject.normalized_weighting.should eql 1
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should calculate the normalized weighting if there are other rules" do
|
102
|
+
ReputationRule.create :name => 'foo', :weight => 1
|
103
|
+
|
104
|
+
subject.normalized_weighting.should eql 1/2.0
|
105
|
+
|
106
|
+
ReputationRule.create :name => 'bar', :weight => 2
|
107
|
+
|
108
|
+
subject.normalized_weighting.should eql 1/4.0
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "#weight=" do
|
113
|
+
it "should alter the normalized_weight when saved" do
|
114
|
+
ReputationRule.create :name => :another_rule, :weight => 1
|
115
|
+
|
116
|
+
# Going from 1 part in 2, to 3 parts in 4
|
117
|
+
expect {
|
118
|
+
subject.weight = 3
|
119
|
+
subject.save
|
120
|
+
}.to change {
|
121
|
+
subject.normalized_weighting
|
122
|
+
}.from(0.5).to(0.75)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should alter the normalized_weight when a new rule is added" do
|
126
|
+
|
127
|
+
# Going from 1 part in 1, to 1 parts in 3
|
128
|
+
expect {
|
129
|
+
ReputationRule.create :name => :new_rule, :weight => 2
|
130
|
+
}.to change {
|
131
|
+
subject.normalized_weighting
|
132
|
+
}.from(1).to(1/3.0)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "#value_for" do
|
137
|
+
describe "when kind is singular" do
|
138
|
+
|
139
|
+
before(:each){
|
140
|
+
@rule = ReputationRule.create! :name => 'rule', :weight => 1, :kind => 'singular'
|
141
|
+
|
142
|
+
@user = User.create! :name => 'bob'
|
143
|
+
@user.behaviours.add 'rule', 0.5
|
144
|
+
}
|
145
|
+
|
146
|
+
it "should return the value based on the metric considering the normalised weighting" do
|
147
|
+
expect {
|
148
|
+
# Create another rule with equal weighting
|
149
|
+
ReputationRule.create! :name => 'other', :weight => 1
|
150
|
+
}.to change {
|
151
|
+
@rule.value_for @user
|
152
|
+
}.from(0.5).to(0.25)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should return the value based on the metric considering the squashing function" do
|
156
|
+
expect {
|
157
|
+
@rule.function = :linear
|
158
|
+
@rule.constants = { :m => 2 }
|
159
|
+
@rule.save
|
160
|
+
}.to change {
|
161
|
+
@rule.value_for @user
|
162
|
+
}.from(0.5).to(1.0)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "when kind is collection" do
|
167
|
+
before(:each){
|
168
|
+
@rule = ReputationRule.create! :name => 'rule',
|
169
|
+
:weight => 1,
|
170
|
+
:kind => 'collection',
|
171
|
+
:function => 'linear',
|
172
|
+
:constants => { :m => 1 },
|
173
|
+
:aggregate_function => 'linear',
|
174
|
+
:aggregate_constants => { :m => 0.1 }
|
175
|
+
|
176
|
+
@user = User.create! :name => 'bob'
|
177
|
+
@user.behaviours.add 'rule', 0.5
|
178
|
+
}
|
179
|
+
|
180
|
+
it "should return the value based on the metric considering the normalised weighting" do
|
181
|
+
expect {
|
182
|
+
ReputationRule.create :name => 'other', :weight => 1
|
183
|
+
}.to change {
|
184
|
+
@rule.value_for @user
|
185
|
+
}.from(1 * 0.5 * 1 * 0.1).to(0.5 * 0.5 * 1 * 0.1)
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should return the value based on the metric considering the squashing function" do
|
189
|
+
expect {
|
190
|
+
@rule.function = 'linear'
|
191
|
+
@rule.constants = { :m => 2 }
|
192
|
+
@rule.save
|
193
|
+
}.to change {
|
194
|
+
@rule.value_for @user
|
195
|
+
}.from(0.05).to(0.1)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should return the value based on previous metrics" do
|
199
|
+
expect {
|
200
|
+
@user.behaviours.add 'rule', 0.5
|
201
|
+
}.to change {
|
202
|
+
@rule.value_for @user
|
203
|
+
# Normalized weight, metric, gradient, aggregate_gradient + intermediate_value
|
204
|
+
}.from(1 * 0.5 * 1 * 0.1 + 0).to( 1 * 0.5 * 1 * 0.1 + (0.5 * 1 * 0.1))
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "class method " do
|
213
|
+
|
214
|
+
describe "#value_for" do
|
215
|
+
|
216
|
+
it "should sum all of the values for each rule for array of behaviors" do
|
217
|
+
ReputationRule.create! :name => 'rule 1', :weight => 1
|
218
|
+
ReputationRule.create! :name => 'rule 2', :weight => 1
|
219
|
+
ReputationRule.create! :name => 'rule 3', :weight => 1
|
220
|
+
|
221
|
+
@user = User.create! :name => 'bob'
|
222
|
+
|
223
|
+
@user.behaviours.add 'rule 1', 1.0
|
224
|
+
@user.behaviours.add 'rule 2', -0.25
|
225
|
+
|
226
|
+
ReputationRule.value_for( @user ).should == (1/3.0 - 0.25/3.0)
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe User do
|
4
|
+
|
5
|
+
it { should have_many :behaviours }
|
6
|
+
|
7
|
+
describe "instance method " do
|
8
|
+
describe "#reputation" do
|
9
|
+
before(:each){
|
10
|
+
@user = User.create! :name => "bob"
|
11
|
+
@rule_1 = ReputationRule.create! :name => '1', :weight => 1, :function => 'linear'
|
12
|
+
@rule_2 = ReputationRule.create! :name => '2', :weight => 1, :function => 'linear'
|
13
|
+
@user.behaviours.create!(:rule => '1', :metric => 1 )
|
14
|
+
@user.behaviours.create!(:rule => '2', :metric => 0.5 )
|
15
|
+
}
|
16
|
+
|
17
|
+
it "should call ReputationRule.value_for" do
|
18
|
+
ReputationRule.should_receive(:value_for).with(@user)
|
19
|
+
|
20
|
+
@user.reputation
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
3
|
+
|
4
|
+
require(File.join(File.dirname(__FILE__), 'config', 'boot'))
|
5
|
+
|
6
|
+
require 'rake'
|
7
|
+
require 'rake/testtask'
|
8
|
+
require 'rake/rdoctask'
|
9
|
+
|
10
|
+
require 'tasks/rails'
|