Permalink
Browse files

Feature: Switched to rails engine and using ActiveRecord as storage

  • Loading branch information...
1 parent 3235a21 commit 6b75e221c8d6405bbac0b043e9759396d3c4b6c6 Theo Cushion committed Apr 15, 2011
Showing with 1,083 additions and 632 deletions.
  1. +7 −1 .gitignore
  2. +1 −1 .rvmrc
  3. +22 −3 Rakefile
  4. +38 −0 app/models/reputation_behaviour.rb
  5. +22 −0 app/models/reputation_intermediate_value.rb
  6. +107 −0 app/models/reputation_rule.rb
  7. +11 −0 generators/reputation/reputation_generator.rb
  8. +37 −0 generators/reputation/templates/reputation_create_tables.rb
  9. +1 −4 lib/reputation.rb
  10. +0 −37 lib/reputation/behaviours.rb
  11. +4 −0 lib/reputation/functions/mixin.rb
  12. +0 −11 lib/reputation/reputation.rb
  13. +0 −126 lib/reputation/rules.rb
  14. +38 −0 lib/reputation/user.rb
  15. +0 −46 lib/reputation/users.rb
  16. +1 −0 rails/init.rb
  17. +7 −3 reputation.gemspec
  18. +0 −10 script/console
  19. +9 −9 spec/functions/generalised_logistic_curve_spec.rb
  20. +0 −16 spec/helpers/methods.rb
  21. +31 −0 spec/models/behaviour_spec.rb
  22. +29 −0 spec/models/intermediate_value_spec.rb
  23. +233 −0 spec/models/rule_spec.rb
  24. +25 −0 spec/models/user_spec.rb
  25. +10 −0 spec/rails_root/Rakefile
  26. +10 −0 spec/rails_root/app/controllers/application_controller.rb
  27. +3 −0 spec/rails_root/app/helpers/application_helper.rb
  28. +3 −0 spec/rails_root/app/models/user.rb
  29. +114 −0 spec/rails_root/config/boot.rb
  30. +16 −0 spec/rails_root/config/database.yml
  31. +41 −0 spec/rails_root/config/environment.rb
  32. +17 −0 spec/rails_root/config/environments/development.rb
  33. +28 −0 spec/rails_root/config/environments/test.rb
  34. +7 −0 spec/rails_root/config/initializers/backtrace_silencers.rb
  35. +7 −0 spec/rails_root/config/initializers/cookie_verification_secret.rb
  36. +10 −0 spec/rails_root/config/initializers/inflections.rb
  37. +5 −0 spec/rails_root/config/initializers/mime_types.rb
  38. +21 −0 spec/rails_root/config/initializers/new_rails_defaults.rb
  39. +15 −0 spec/rails_root/config/initializers/session_store.rb
  40. +43 −0 spec/rails_root/config/routes.rb
  41. +11 −0 spec/rails_root/db/migrate/20110414125319_create_users.rb
  42. +4 −0 spec/rails_root/script/about
  43. +3 −0 spec/rails_root/script/console
  44. +3 −0 spec/rails_root/script/dbconsole
  45. +3 −0 spec/rails_root/script/destroy
  46. +3 −0 spec/rails_root/script/generate
  47. +3 −0 spec/rails_root/script/performance/benchmarker
  48. +3 −0 spec/rails_root/script/performance/profiler
  49. +3 −0 spec/rails_root/script/plugin
  50. +3 −0 spec/rails_root/script/runner
  51. +3 −0 spec/rails_root/script/server
  52. +0 −83 spec/rules/rule_set_spec.rb
  53. +0 −222 spec/rules/rule_spec.rb
  54. +36 −34 spec/scenarios/collection_spec.rb
  55. +21 −21 spec/scenarios/singular_spec.rb
  56. +3 −0 spec/spec.opts
  57. +8 −5 spec/spec_helper.rb
View
@@ -1,2 +1,8 @@
Gemfile.lock
-pkg
+*.gem
+*.log
+*.sqlite3
+*.DS_Store
+spec/rails_root/db/schema.rb
+spec/rails_root/db/migrate/*_reputation_create_tables.rb
+spec/rails_root/vendor/plugins
View
2 .rvmrc
@@ -1 +1 @@
-rvm use ree
+rvm use ree@reputation
View
@@ -1,8 +1,27 @@
require 'rubygems'
require 'bundler/setup'
-require 'rspec/core/rake_task'
+require 'spec/rake/spectask'
-RSpec::Core::RakeTask.new(:spec)
+Spec::Rake::SpecTask.new(:spec => ["generator:cleanup", "generator:reputation"])
Bundler::GemHelper.install_tasks
-task :default => :spec
+task :default => :spec
+
+namespace :generator do
+ desc "Cleans up the test app before running the generator"
+ task :cleanup do
+ FileList["spec/rails_root/db/migrate/*_reputation_create_tables.rb","spec/rails_root/db/*.sqlite3"].each do |each|
+ FileUtils.rm_rf(each)
+ end
+
+ FileUtils.rm_rf("spec/rails_root/vendor/plugins/reputation")
+ FileUtils.mkdir_p("spec/rails_root/vendor/plugins")
+ reputation_root = File.expand_path(File.dirname(__FILE__))
+ system("ln -s #{reputation_root} spec/rails_root/vendor/plugins/reputation")
+ end
+
+ desc "Run the reputation generator"
+ task :reputation do
+ system "cd spec/rails_root && ./script/generate reputation && rake db:migrate db:test:prepare"
+ end
+end
@@ -0,0 +1,38 @@
+class ReputationBehaviour < ActiveRecord::Base
+
+ belongs_to :user
+ belongs_to :rule, :class_name => 'ReputationRule'
+
+ before_save :recalculate_rule
+
+ attr_accessible :user, :rule, :metric
+
+ validates_presence_of :user
+ validates_presence_of :rule
+ validates_numericality_of :metric
+
+ validates_uniqueness_of :user_id, :scope => :rule_id
+
+ # Set the rule, can either be a ReputationRule or the name of the rule
+ #
+ # @example
+ # behaviour.rule = 'rule_1'
+ # # or
+ # behaviour.rule = ReputationRule.find(:first)
+
+ def rule=(rule)
+ write_attribute :rule_id, case rule
+ when ReputationRule
+ rule.id
+ else
+ ReputationRule.find_by_name( rule ).try(:id)
+ end
+ end
+
+private
+
+ def recalculate_rule
+ rule.recalculate_intermediate_values_for user
+ end
+
+end
@@ -0,0 +1,22 @@
+class ReputationIntermediateValue < ActiveRecord::Base
+
+ belongs_to :user
+ belongs_to :rule, :class_name => 'ReputationRule'
+
+ validates_presence_of :user
+ validates_presence_of :rule
+ validates_numericality_of :value
+
+ validates_uniqueness_of :name, :scope => [:user_id, :rule_id]
+
+ attr_accessible :user, :rule, :name, :value
+
+ def initialize(args = {})
+ options = {
+ :value => 0
+ }.merge(args)
+
+ super options
+ end
+
+end
@@ -0,0 +1,107 @@
+class ReputationRule < ActiveRecord::Base
+
+ has_many :intermediate_values, :class_name => 'ReputationIntermediateValue', :foreign_key => 'rule_id'
+ has_many :behaviours, :class_name => 'ReputationBehaviour', :foreign_key => 'rule_id'
+
+ serialize :constants, Hash
+ serialize :aggregate_constants, Hash
+
+ validates_presence_of :name
+ validates_uniqueness_of :name
+ validates_numericality_of :weight, :only_integer => true, :greater_than => 0
+
+ attr_accessible :name, :kind, :weight, :function, :constants, :aggregate_function, :aggregate_constants
+
+ attr_readonly :kind
+
+ def initialize(args = {})
+ options = {
+ :weight => 1,
+ :kind => 'singular',
+ :function => 'linear',
+ :constants => { :m => 1 },
+ :aggregate_function => 'linear',
+ :aggregate_constants => { :m => 1 }
+ }.merge(args)
+
+ super options
+ end
+
+ # Return the total score for a certain user
+ #
+ # @param [User]
+ def self.value_for(user)
+ all.inject(0){|total,r| total + r.value_for( user ) }
+ end
+
+ # Lookup the weighting relative to all other rules
+ #
+ def normalized_weighting
+ BigDecimal(weight.to_s) / ReputationRule.sum('weight')
+ end
+
+ # Calculate the score for a certain user
+ #
+ # @param [User]
+ def value_for(user)
+ behaviour = user.behaviours.find_by_rule_id id
+ if behaviour
+ case kind
+ when 'singular'
+ f(behaviour.metric) * normalized_weighting
+ when 'collection'
+ ivo = intermediate_values.find_by_user_id_and_name(user.id,kind)
+ iv = ivo ? ivo.value : 0
+ aggregate_f(
+ f(behaviour.metric) + iv
+ ) * normalized_weighting
+ end
+ else
+ 0
+ end
+ end
+
+ # Return the function object defined by :function and :constants
+ #
+ # @return [Reputation::Functions::Linear, Reputation::Functions::Step, Reputation::Functions::GeneralisedLogisticCurve]
+ def function
+ build_function(super, constants)
+ end
+
+ # Return the aggregate function object defined by :aggregate_function and :aggregate_constants
+ #
+ # @return [Reputation::Functions::Linear, Reputation::Functions::Step, Reputation::Functions::GeneralisedLogisticCurve]
+ def aggregate_function
+ build_function(super, aggregate_constants)
+ end
+
+ def recalculate_intermediate_values_for(user) # :nodoc:
+ behaviour = user.behaviours.find_by_rule_id(self.id)
+ if behaviour
+ case kind
+ when 'collection'
+ iv = intermediate_values.find_by_user_id_and_name(user.id,kind) || intermediate_values.build(:user => user, :name => kind)
+ iv.value += f(behaviour.metric)
+ iv.save!
+ end
+ end
+ end
+
+private
+
+ # Delegate f to the function#f
+ def f(*args)
+ function.f(*args)
+ end
+
+ # Delegate aggregate_f to the aggregate_function#f
+ def aggregate_f(*args)
+ aggregate_function.f(*args)
+ end
+
+ def build_function(name, constants)
+ klass = "Reputation::Functions::#{name.to_s.camelcase}".constantize
+ klass.new(constants)
+ end
+
+end
@@ -0,0 +1,11 @@
+class ReputationGenerator < Rails::Generator::Base
+
+ def manifest
+
+ record do |m|
+ m.migration_template "reputation_create_tables.rb", "db/migrate", :migration_file_name => "reputation_create_tables"
+ end
+
+ end
+
+end
@@ -0,0 +1,37 @@
+class ReputationCreateTables < ActiveRecord::Migration
+ def self.up
+ create_table :reputation_rules do |t|
+ t.string :name
+ t.integer :weight
+ t.string :kind
+ t.string :function
+ t.string :constants
+ t.string :aggregate_function
+ t.string :aggregate_constants
+ end
+
+ create_table :reputation_intermediate_values do |t|
+ t.references :user
+ t.references :rule
+ t.string :name
+ t.decimal :value
+ end
+ add_index :reputation_intermediate_values, :user_id
+ add_index :reputation_intermediate_values, :rule_id
+ add_index :reputation_intermediate_values, :name
+
+ create_table :reputation_behaviours do |t|
+ t.references :user
+ t.references :rule
+ t.decimal :metric
+ end
+ add_index :reputation_behaviours, :user_id
+ add_index :reputation_behaviours, :rule_id
+ end
+
+ def self.down
+ drop_table :reputation_rules
+ drop_table :reputation_user_rule
+ drop_table :reputation_behaviours
+ end
+end
View
@@ -1,5 +1,2 @@
-require 'reputation/reputation'
-require 'reputation/users'
-require 'reputation/rules'
-require 'reputation/behaviours'
+require 'reputation/user'
require 'reputation/functions'
@@ -1,37 +0,0 @@
-class Reputation
- class BehaviourSet
-
- def initialize(user, engine)
- @user = user
- @engine = engine
- end
-
- def [](name)
- behaviours[name]
- end
-
- def add(name, metric)
- behaviours[name] = Behaviour.new(name, @user, metric, @engine)
- end
-
- private
-
- def behaviours
- @behaviours ||= {}
- end
-
- end
-
- class Behaviour
- attr_accessor :name, :user, :metric
-
- def initialize(name, user, metric, engine)
- @name = name
- @user = user
- @metric = metric
- @engine = engine
-
- @engine.rules[@name].before_new_behaviour_for(@user)
- end
- end
-end
@@ -5,6 +5,8 @@ class Reputation
class Functions
module Mixin
+ # Produces the URL for a google chart of the function
+ #
def google_chart_url
points = 1000
range = Array.new(points){|i| (i-points/2) * 0.01 }
@@ -18,6 +20,8 @@ def google_chart_url
)
end
+ # Opens the google chart for the function in the browser
+ #
def google_chart
Launchy::Browser.run google_chart_url
end
@@ -1,11 +0,0 @@
-class Reputation
-
- def rules
- @rules ||= RuleSet.new(self)
- end
-
- def users
- @users ||= UserSet.new(self)
- end
-
-end
Oops, something went wrong.

0 comments on commit 6b75e22

Please sign in to comment.