reputation 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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/.infinity_test
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
infinity_test do
|
2
|
+
|
3
|
+
notifications :growl do
|
4
|
+
show_images :mode => :mario_bros
|
5
|
+
end
|
6
|
+
|
7
|
+
use :rubies => %w(1.9.2 1.9.1 1.8.7 ree jruby macruby rbx), :test_framework => :rspec
|
8
|
+
|
9
|
+
# use :specific_options => {'jruby' => 'J-cp bar/whisky-in-the.jar:.'}
|
10
|
+
|
11
|
+
before(:each_ruby) do |environment|
|
12
|
+
# ...
|
13
|
+
end
|
14
|
+
|
15
|
+
after(:each_ruby) do |environment|
|
16
|
+
# ...
|
17
|
+
end
|
18
|
+
|
19
|
+
before_run do
|
20
|
+
clear :terminal
|
21
|
+
end
|
22
|
+
|
23
|
+
after_run do
|
24
|
+
# ...
|
25
|
+
end
|
26
|
+
|
27
|
+
#heuristics('my_pattern') do |file|
|
28
|
+
# ...
|
29
|
+
#end
|
30
|
+
|
31
|
+
replace_patterns do |application|
|
32
|
+
# ...
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/.rspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
class ReputationBehaviour < ActiveRecord::Base
|
2
|
+
|
3
|
+
belongs_to :user
|
4
|
+
belongs_to :rule, :class_name => 'ReputationRule'
|
5
|
+
|
6
|
+
before_save :recalculate_rule
|
7
|
+
|
8
|
+
attr_accessible :user, :rule, :metric
|
9
|
+
|
10
|
+
validates_presence_of :user
|
11
|
+
validates_presence_of :rule
|
12
|
+
validates_numericality_of :metric
|
13
|
+
|
14
|
+
validates_uniqueness_of :user_id, :scope => :rule_id
|
15
|
+
|
16
|
+
# Set the rule, can either be a ReputationRule or the name of the rule
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# behaviour.rule = 'rule_1'
|
20
|
+
# # or
|
21
|
+
# behaviour.rule = ReputationRule.find(:first)
|
22
|
+
|
23
|
+
def rule=(rule)
|
24
|
+
write_attribute :rule_id, case rule
|
25
|
+
when ReputationRule
|
26
|
+
rule.id
|
27
|
+
else
|
28
|
+
ReputationRule.find_by_name( rule ).try(:id)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def recalculate_rule
|
35
|
+
rule.recalculate_intermediate_values_for user
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class ReputationIntermediateValue < ActiveRecord::Base
|
2
|
+
|
3
|
+
belongs_to :user
|
4
|
+
belongs_to :rule, :class_name => 'ReputationRule'
|
5
|
+
|
6
|
+
validates_presence_of :user
|
7
|
+
validates_presence_of :rule
|
8
|
+
validates_numericality_of :value
|
9
|
+
|
10
|
+
validates_uniqueness_of :name, :scope => [:user_id, :rule_id]
|
11
|
+
|
12
|
+
attr_accessible :user, :rule, :name, :value
|
13
|
+
|
14
|
+
def initialize(args = {})
|
15
|
+
options = {
|
16
|
+
:value => 0
|
17
|
+
}.merge(args)
|
18
|
+
|
19
|
+
super options
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
class ReputationRule < ActiveRecord::Base
|
2
|
+
|
3
|
+
has_many :intermediate_values, :class_name => 'ReputationIntermediateValue', :foreign_key => 'rule_id'
|
4
|
+
has_many :behaviours, :class_name => 'ReputationBehaviour', :foreign_key => 'rule_id'
|
5
|
+
|
6
|
+
serialize :constants, Hash
|
7
|
+
serialize :aggregate_constants, Hash
|
8
|
+
|
9
|
+
validates_presence_of :name
|
10
|
+
validates_uniqueness_of :name
|
11
|
+
validates_numericality_of :weight, :only_integer => true, :greater_than => 0
|
12
|
+
|
13
|
+
attr_accessible :name, :kind, :weight, :function, :constants, :aggregate_function, :aggregate_constants
|
14
|
+
|
15
|
+
attr_readonly :kind
|
16
|
+
|
17
|
+
def initialize(*args)
|
18
|
+
args[0] = {
|
19
|
+
:weight => 1,
|
20
|
+
:kind => 'singular',
|
21
|
+
:function => 'linear',
|
22
|
+
:constants => { :m => 1 },
|
23
|
+
:aggregate_function => 'linear',
|
24
|
+
:aggregate_constants => { :m => 1 }
|
25
|
+
}.merge(args.first||{})
|
26
|
+
|
27
|
+
super *args
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return the total score for a certain user
|
31
|
+
#
|
32
|
+
# @param [User]
|
33
|
+
def self.value_for(user)
|
34
|
+
all.inject(0){|total,r| total + r.value_for( user ) }
|
35
|
+
end
|
36
|
+
|
37
|
+
# Lookup the weighting relative to all other rules
|
38
|
+
#
|
39
|
+
def normalized_weighting
|
40
|
+
BigDecimal(weight.to_s) / ReputationRule.sum('weight')
|
41
|
+
end
|
42
|
+
|
43
|
+
# Calculate the score for a certain user
|
44
|
+
#
|
45
|
+
# @param [User]
|
46
|
+
def value_for(user)
|
47
|
+
behaviour = user.behaviours.find_by_rule_id id
|
48
|
+
if behaviour
|
49
|
+
case kind
|
50
|
+
when 'singular'
|
51
|
+
f(behaviour.metric) * normalized_weighting
|
52
|
+
when 'collection'
|
53
|
+
ivo = intermediate_values.find_by_user_id_and_name(user.id,kind)
|
54
|
+
iv = ivo ? ivo.value : 0
|
55
|
+
aggregate_f(
|
56
|
+
f(behaviour.metric) + iv
|
57
|
+
) * normalized_weighting
|
58
|
+
end
|
59
|
+
else
|
60
|
+
0
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return the function object defined by :function and :constants
|
65
|
+
#
|
66
|
+
# @return [Reputation::Functions::Linear, Reputation::Functions::Step, Reputation::Functions::GeneralisedLogisticCurve]
|
67
|
+
def function
|
68
|
+
build_function(super, constants)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return the aggregate function object defined by :aggregate_function and :aggregate_constants
|
72
|
+
#
|
73
|
+
# @return [Reputation::Functions::Linear, Reputation::Functions::Step, Reputation::Functions::GeneralisedLogisticCurve]
|
74
|
+
def aggregate_function
|
75
|
+
build_function(super, aggregate_constants)
|
76
|
+
end
|
77
|
+
|
78
|
+
def recalculate_intermediate_values_for(user) # :nodoc:
|
79
|
+
behaviour = user.behaviours.find_by_rule_id(self.id)
|
80
|
+
if behaviour
|
81
|
+
case kind
|
82
|
+
when 'collection'
|
83
|
+
iv = intermediate_values.find_by_user_id_and_name(user.id,kind) || intermediate_values.build(:user => user, :name => kind)
|
84
|
+
iv.value += f(behaviour.metric)
|
85
|
+
iv.save!
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# Delegate f to the function#f
|
93
|
+
def f(*args)
|
94
|
+
function.f(*args)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Delegate aggregate_f to the aggregate_function#f
|
98
|
+
def aggregate_f(*args)
|
99
|
+
aggregate_function.f(*args)
|
100
|
+
end
|
101
|
+
|
102
|
+
def build_function(name, constants)
|
103
|
+
klass = "Reputation::Functions::#{name.to_s.camelcase}".constantize
|
104
|
+
klass.new(constants)
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class ReputationCreateTables < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :reputation_rules do |t|
|
4
|
+
t.string :name
|
5
|
+
t.integer :weight
|
6
|
+
t.string :kind
|
7
|
+
t.string :function
|
8
|
+
t.string :constants
|
9
|
+
t.string :aggregate_function
|
10
|
+
t.string :aggregate_constants
|
11
|
+
end
|
12
|
+
|
13
|
+
create_table :reputation_intermediate_values do |t|
|
14
|
+
t.references :user
|
15
|
+
t.references :rule
|
16
|
+
t.string :name
|
17
|
+
t.decimal :value
|
18
|
+
end
|
19
|
+
add_index :reputation_intermediate_values, :user_id
|
20
|
+
add_index :reputation_intermediate_values, :rule_id
|
21
|
+
add_index :reputation_intermediate_values, :name
|
22
|
+
|
23
|
+
create_table :reputation_behaviours do |t|
|
24
|
+
t.references :user
|
25
|
+
t.references :rule
|
26
|
+
t.decimal :metric
|
27
|
+
end
|
28
|
+
add_index :reputation_behaviours, :user_id
|
29
|
+
add_index :reputation_behaviours, :rule_id
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.down
|
33
|
+
drop_table :reputation_rules
|
34
|
+
drop_table :reputation_user_rule
|
35
|
+
drop_table :reputation_behaviours
|
36
|
+
end
|
37
|
+
end
|
data/lib/reputation.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
class Reputation
|
2
|
+
class Functions
|
3
|
+
class GeneralisedLogisticCurve
|
4
|
+
|
5
|
+
include Mixin
|
6
|
+
|
7
|
+
attr_accessor :a, :k, :b, :v, :q, :m
|
8
|
+
|
9
|
+
def initialize(args = {})
|
10
|
+
constants = {
|
11
|
+
:a => -1, # lower asymptote
|
12
|
+
:k => 1, # upper asymptote
|
13
|
+
:b => 10, # growth rate
|
14
|
+
:v => 0.5, # affects near which asymptote maximum growth occurs
|
15
|
+
:q => 0.5, # depends on the value Y(0)
|
16
|
+
:m => 0, # the time of maximum growth if Q=v
|
17
|
+
}.merge( args )
|
18
|
+
@a = constants[:a]
|
19
|
+
@k = constants[:k]
|
20
|
+
@b = constants[:b]
|
21
|
+
@v = constants[:v]
|
22
|
+
@q = constants[:q]
|
23
|
+
@m = constants[:m]
|
24
|
+
end
|
25
|
+
|
26
|
+
def f(t)
|
27
|
+
limit(
|
28
|
+
a.to_f + (
|
29
|
+
(k.to_f - a.to_f) /
|
30
|
+
(1 + q.to_f * Math.exp(-1 * b.to_f*(t.to_f-m.to_f)) )**(1.to_f/v.to_f)
|
31
|
+
)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Reputation
|
2
|
+
class Functions
|
3
|
+
class Linear
|
4
|
+
|
5
|
+
include Mixin
|
6
|
+
|
7
|
+
attr_accessor :m
|
8
|
+
|
9
|
+
def initialize(args = {})
|
10
|
+
constants = { :m => 1 }.merge( args )
|
11
|
+
@m = constants[:m]
|
12
|
+
end
|
13
|
+
|
14
|
+
def f(x)
|
15
|
+
limit x * m
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "googlecharts"
|
2
|
+
require "launchy"
|
3
|
+
|
4
|
+
class Reputation
|
5
|
+
class Functions
|
6
|
+
module Mixin
|
7
|
+
|
8
|
+
# Produces the URL for a google chart of the function
|
9
|
+
#
|
10
|
+
def google_chart_url
|
11
|
+
points = 1000
|
12
|
+
range = Array.new(points){|i| (i-points/2) * 0.01 }
|
13
|
+
y = range.map{|x| f(x) }
|
14
|
+
c = Googlecharts.line(
|
15
|
+
:size => '800x200',
|
16
|
+
:axis_with_labels => 'x,y',
|
17
|
+
:title => self.class.name,
|
18
|
+
:data => y,
|
19
|
+
:axis_range => [[range.first,range.last],[y.min,y.max]]
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Opens the google chart for the function in the browser
|
24
|
+
#
|
25
|
+
def google_chart
|
26
|
+
Launchy::Browser.run google_chart_url
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def limit(r)
|
32
|
+
if r > 1
|
33
|
+
1
|
34
|
+
elsif r < -1
|
35
|
+
-1
|
36
|
+
else
|
37
|
+
r
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Reputation
|
2
|
+
class Functions
|
3
|
+
class Step
|
4
|
+
|
5
|
+
include Mixin
|
6
|
+
|
7
|
+
attr_accessor :a, :k, :c
|
8
|
+
|
9
|
+
def initialize(args = {})
|
10
|
+
constants = {
|
11
|
+
:a => -1, # lower asymptote
|
12
|
+
:k => 1, # upper asymptote
|
13
|
+
:c => 0.5 # point of switch
|
14
|
+
}.merge( args )
|
15
|
+
@c = constants[:c]
|
16
|
+
@k = constants[:k]
|
17
|
+
@a = constants[:a]
|
18
|
+
end
|
19
|
+
|
20
|
+
def f(x)
|
21
|
+
limit( x.to_f >= c.to_f ? k : a )
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Reputation
|
2
|
+
module User
|
3
|
+
|
4
|
+
def self.included(model)
|
5
|
+
model.send(:include, InstanceMethods)
|
6
|
+
model.send(:include, Relations)
|
7
|
+
end
|
8
|
+
|
9
|
+
module Relations
|
10
|
+
def self.included(model)
|
11
|
+
model.class_eval do
|
12
|
+
|
13
|
+
has_many :behaviours, :class_name => "ReputationBehaviour" do
|
14
|
+
def add(rule, metric)
|
15
|
+
rule = ReputationRule.find_by_name rule unless rule.is_a? ReputationRule
|
16
|
+
b = proxy_reflection.klass.find_by_user_id_and_rule_id proxy_owner.id, rule.id
|
17
|
+
b ||= proxy_reflection.klass.new :rule => rule, :user => proxy_owner
|
18
|
+
b.update_attribute :metric, metric
|
19
|
+
proxy_owner.behaviours(true)
|
20
|
+
b
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module InstanceMethods
|
29
|
+
|
30
|
+
# Returns the reputation value for the user
|
31
|
+
#
|
32
|
+
def reputation
|
33
|
+
ReputationRule.value_for(self)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|