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.
Files changed (62) hide show
  1. data/.infinity_test +35 -0
  2. data/.rspec +2 -0
  3. data/app/models/reputation_behaviour.rb +38 -0
  4. data/app/models/reputation_intermediate_value.rb +22 -0
  5. data/app/models/reputation_rule.rb +107 -0
  6. data/generators/reputation/reputation_generator.rb +11 -0
  7. data/generators/reputation/templates/reputation_create_tables.rb +37 -0
  8. data/lib/reputation.rb +3 -0
  9. data/lib/reputation/engine.rb +8 -0
  10. data/lib/reputation/functions.rb +4 -0
  11. data/lib/reputation/functions/generalised_logistic_curve.rb +37 -0
  12. data/lib/reputation/functions/linear.rb +21 -0
  13. data/lib/reputation/functions/mixin.rb +44 -0
  14. data/lib/reputation/functions/step.rb +27 -0
  15. data/lib/reputation/user.rb +38 -0
  16. data/rails/init.rb +1 -0
  17. data/spec/functions/generalised_logistic_curve_spec.rb +50 -0
  18. data/spec/functions/linear_spec.rb +21 -0
  19. data/spec/functions/step_spec.rb +28 -0
  20. data/spec/helpers/functions.rb +13 -0
  21. data/spec/models/behaviour_spec.rb +31 -0
  22. data/spec/models/intermediate_value_spec.rb +29 -0
  23. data/spec/models/rule_spec.rb +233 -0
  24. data/spec/models/user_spec.rb +25 -0
  25. data/spec/rails_root/Rakefile +10 -0
  26. data/spec/rails_root/app/controllers/application_controller.rb +10 -0
  27. data/spec/rails_root/app/helpers/application_helper.rb +3 -0
  28. data/spec/rails_root/app/models/user.rb +3 -0
  29. data/spec/rails_root/config/boot.rb +114 -0
  30. data/spec/rails_root/config/database.yml +16 -0
  31. data/spec/rails_root/config/environment.rb +41 -0
  32. data/spec/rails_root/config/environments/development.rb +17 -0
  33. data/spec/rails_root/config/environments/test.rb +28 -0
  34. data/spec/rails_root/config/initializers/backtrace_silencers.rb +7 -0
  35. data/spec/rails_root/config/initializers/cookie_verification_secret.rb +7 -0
  36. data/spec/rails_root/config/initializers/inflections.rb +10 -0
  37. data/spec/rails_root/config/initializers/mime_types.rb +5 -0
  38. data/spec/rails_root/config/initializers/new_rails_defaults.rb +21 -0
  39. data/spec/rails_root/config/initializers/session_store.rb +15 -0
  40. data/spec/rails_root/config/routes.rb +43 -0
  41. data/spec/rails_root/db/development.sqlite3 +0 -0
  42. data/spec/rails_root/db/migrate/20110414125319_create_users.rb +11 -0
  43. data/spec/rails_root/db/migrate/20110812160932_reputation_create_tables.rb +37 -0
  44. data/spec/rails_root/db/schema.rb +48 -0
  45. data/spec/rails_root/db/test.sqlite3 +0 -0
  46. data/spec/rails_root/log/development.log +3471 -0
  47. data/spec/rails_root/log/test.log +27696 -0
  48. data/spec/rails_root/script/about +4 -0
  49. data/spec/rails_root/script/console +3 -0
  50. data/spec/rails_root/script/dbconsole +3 -0
  51. data/spec/rails_root/script/destroy +3 -0
  52. data/spec/rails_root/script/generate +3 -0
  53. data/spec/rails_root/script/performance/benchmarker +3 -0
  54. data/spec/rails_root/script/performance/profiler +3 -0
  55. data/spec/rails_root/script/plugin +3 -0
  56. data/spec/rails_root/script/runner +3 -0
  57. data/spec/rails_root/script/server +3 -0
  58. data/spec/scenarios/collection_spec.rb +118 -0
  59. data/spec/scenarios/singular_spec.rb +84 -0
  60. data/spec/spec.opts +3 -0
  61. data/spec/spec_helper.rb +15 -0
  62. 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'