merit 1.7.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -1
  3. data/Gemfile +7 -0
  4. data/README.md +31 -4
  5. data/app/models/merit/action.rb +2 -3
  6. data/app/models/merit/badge.rb +2 -2
  7. data/lib/generators/active_record/install_generator.rb +1 -1
  8. data/lib/generators/active_record/merit_generator.rb +2 -2
  9. data/lib/generators/active_record/remove_generator.rb +2 -2
  10. data/lib/generators/active_record/templates/create_badges_sashes.rb +1 -1
  11. data/lib/generators/active_record/templates/create_merit_actions.rb +3 -3
  12. data/lib/generators/active_record/templates/create_scores_and_points.rb +2 -2
  13. data/lib/generators/active_record/templates/remove_merit_tables.rb +1 -1
  14. data/lib/generators/merit/install_generator.rb +1 -1
  15. data/lib/generators/merit/merit_generator.rb +2 -3
  16. data/lib/generators/merit/remove_generator.rb +3 -3
  17. data/lib/generators/merit/templates/merit.rb +10 -4
  18. data/lib/merit.rb +43 -15
  19. data/lib/merit/base_target_finder.rb +1 -3
  20. data/lib/merit/judge.rb +26 -6
  21. data/lib/merit/model_additions.rb +10 -17
  22. data/lib/merit/models/active_record/merit/action.rb +1 -1
  23. data/lib/merit/models/active_record/merit/activity_log.rb +1 -0
  24. data/lib/merit/models/active_record/merit/badges_sash.rb +6 -10
  25. data/lib/merit/models/active_record/merit/sash.rb +2 -38
  26. data/lib/merit/models/active_record/merit/score.rb +6 -5
  27. data/lib/merit/models/base/merit/badges_sash.rb +15 -0
  28. data/lib/merit/models/base/merit/sash.rb +42 -0
  29. data/lib/merit/models/mongoid/merit/action.rb +8 -6
  30. data/lib/merit/models/mongoid/merit/activity_log.rb +11 -0
  31. data/lib/merit/models/mongoid/merit/badges_sash.rb +19 -0
  32. data/lib/merit/models/mongoid/merit/sash.rb +28 -0
  33. data/lib/merit/models/mongoid/merit/score.rb +41 -0
  34. data/lib/merit/reputation_change_observer.rb +11 -0
  35. data/lib/merit/rule.rb +1 -1
  36. data/lib/merit/rules_matcher.rb +0 -2
  37. data/lib/merit/rules_rank_methods.rb +1 -1
  38. data/lib/merit/target_finder.rb +1 -2
  39. data/merit.gemspec +2 -1
  40. data/test/dummy/app/models/comment.rb +16 -1
  41. data/test/dummy/app/models/dummy_observer.rb +3 -0
  42. data/test/dummy/app/models/user.rb +14 -1
  43. data/test/dummy/config/initializers/merit.rb +3 -4
  44. data/test/dummy/config/mongoid.yml +13 -0
  45. data/test/integration/navigation_test.rb +19 -2
  46. data/test/unit/merit_unit_test.rb +1 -1
  47. metadata +25 -56
  48. data/lib/merit/models/mongoid/sash.rb +0 -14
  49. data/lib/merit/observer.rb +0 -13
  50. data/test/dummy-mongoid/Rakefile +0 -7
  51. data/test/dummy-mongoid/app/controllers/application_controller.rb +0 -7
  52. data/test/dummy-mongoid/app/controllers/comments_controller.rb +0 -90
  53. data/test/dummy-mongoid/app/controllers/registrations_controller.rb +0 -15
  54. data/test/dummy-mongoid/app/controllers/users_controller.rb +0 -67
  55. data/test/dummy-mongoid/app/helpers/application_helper.rb +0 -2
  56. data/test/dummy-mongoid/app/models/comment.rb +0 -13
  57. data/test/dummy-mongoid/app/models/merit/badge_rules.rb +0 -49
  58. data/test/dummy-mongoid/app/models/merit/point_rules.rb +0 -20
  59. data/test/dummy-mongoid/app/models/merit/rank_rules.rb +0 -24
  60. data/test/dummy-mongoid/app/models/user.rb +0 -25
  61. data/test/dummy-mongoid/app/views/comments/_form.html.erb +0 -29
  62. data/test/dummy-mongoid/app/views/comments/edit.html.erb +0 -6
  63. data/test/dummy-mongoid/app/views/comments/index.html.erb +0 -35
  64. data/test/dummy-mongoid/app/views/comments/new.html.erb +0 -5
  65. data/test/dummy-mongoid/app/views/comments/show.html.erb +0 -23
  66. data/test/dummy-mongoid/app/views/layouts/application.html.erb +0 -24
  67. data/test/dummy-mongoid/app/views/users/_form.html.erb +0 -22
  68. data/test/dummy-mongoid/app/views/users/edit.html.erb +0 -6
  69. data/test/dummy-mongoid/app/views/users/index.html.erb +0 -26
  70. data/test/dummy-mongoid/app/views/users/new.html.erb +0 -5
  71. data/test/dummy-mongoid/app/views/users/show.html.erb +0 -18
  72. data/test/dummy-mongoid/config.ru +0 -4
  73. data/test/dummy-mongoid/config/application.rb +0 -22
  74. data/test/dummy-mongoid/config/boot.rb +0 -10
  75. data/test/dummy-mongoid/config/environment.rb +0 -5
  76. data/test/dummy-mongoid/config/environments/development.rb +0 -25
  77. data/test/dummy-mongoid/config/environments/production.rb +0 -49
  78. data/test/dummy-mongoid/config/environments/test.rb +0 -35
  79. data/test/dummy-mongoid/config/initializers/backtrace_silencers.rb +0 -7
  80. data/test/dummy-mongoid/config/initializers/inflections.rb +0 -10
  81. data/test/dummy-mongoid/config/initializers/merit.rb +0 -37
  82. data/test/dummy-mongoid/config/initializers/mime_types.rb +0 -5
  83. data/test/dummy-mongoid/config/initializers/secret_token.rb +0 -7
  84. data/test/dummy-mongoid/config/initializers/session_store.rb +0 -8
  85. data/test/dummy-mongoid/config/locales/en.yml +0 -5
  86. data/test/dummy-mongoid/config/mongoid.yml +0 -14
  87. data/test/dummy-mongoid/config/routes.rb +0 -9
  88. data/test/dummy-mongoid/db/seeds.rb +0 -17
  89. data/test/dummy-mongoid/public/404.html +0 -26
  90. data/test/dummy-mongoid/public/422.html +0 -26
  91. data/test/dummy-mongoid/public/500.html +0 -26
  92. data/test/dummy-mongoid/public/favicon.ico +0 -0
  93. data/test/dummy-mongoid/public/javascripts/application.js +0 -2
  94. data/test/dummy-mongoid/public/javascripts/controls.js +0 -965
  95. data/test/dummy-mongoid/public/javascripts/dragdrop.js +0 -974
  96. data/test/dummy-mongoid/public/javascripts/effects.js +0 -1123
  97. data/test/dummy-mongoid/public/javascripts/prototype.js +0 -6001
  98. data/test/dummy-mongoid/public/javascripts/rails.js +0 -191
  99. data/test/dummy-mongoid/public/stylesheets/.gitkeep +0 -0
  100. data/test/dummy-mongoid/public/stylesheets/scaffold.css +0 -56
  101. data/test/dummy-mongoid/script/rails +0 -6
@@ -17,16 +17,18 @@ module Merit
17
17
 
18
18
  # Delegate methods from meritable models to their sash
19
19
  def _merit_delegate_methods_to_sash
20
- methods = %w(badge_ids badges points
21
- add_badge rm_badge
22
- add_points substract_points subtract_points)
20
+ methods = %w(badge_ids badges points add_badge rm_badge
21
+ add_points substract_points subtract_points)
23
22
  methods.each { |method| delegate method, to: :_sash }
24
23
  end
25
24
 
26
25
  def _merit_orm_specific_config
27
- if Merit.orm == :mongoid
28
- field :sash_id
29
- field :points, type: Integer, default: 0
26
+ if Merit.orm == :mongo_mapper
27
+ plugin Merit
28
+ key :sash_id, String
29
+ key :points, Integer, default: 0
30
+ key :level, Integer, default: 0
31
+ elsif Merit.orm == :mongoid
30
32
  field :level, type: Integer, default: 0
31
33
  def find_by_id(id)
32
34
  where(_id: id).first
@@ -45,18 +47,9 @@ module Merit
45
47
  # http://blog.hasmanythrough.com/2012/1/20/modularized-association-methods-in-rails-3-2
46
48
  def _merit_sash_initializer
47
49
  define_method(:_sash) do
48
- if sash.nil?
49
- self.update_attribute :sash_id, Sash.create.id
50
- end
51
- self.sash
50
+ sash || update_attribute(:sash_id, Sash.create.id)
51
+ sash
52
52
  end
53
53
  end
54
54
  end
55
55
  end
56
-
57
- if Object.const_defined?('ActiveRecord')
58
- ActiveRecord::Base.send :include, Merit
59
- end
60
- if Object.const_defined?('Mongoid')
61
- Mongoid::Document.send :include, Merit
62
- end
@@ -6,7 +6,7 @@ module Merit
6
6
 
7
7
  if defined?(ProtectedAttributes) || !defined?(ActionController::StrongParameters)
8
8
  attr_accessible :user_id, :action_method, :action_value, :had_errors,
9
- :target_model, :target_id, :processed, :log
9
+ :target_model, :target_id, :processed, :log
10
10
  end
11
11
  end
12
12
  end
@@ -4,6 +4,7 @@ module Merit
4
4
 
5
5
  belongs_to :action, class_name: Merit::Action
6
6
  belongs_to :related_change, polymorphic: true
7
+ has_one :sash, through: :related_change
7
8
 
8
9
  if defined?(ProtectedAttributes) || !defined?(ActionController::StrongParameters)
9
10
  attr_accessible :action_id, :related_change, :description, :created_at
@@ -1,9 +1,9 @@
1
1
  module Merit
2
2
  class BadgesSash < ActiveRecord::Base
3
- belongs_to :sash
3
+ include Base::BadgesSash
4
4
  has_many :activity_logs,
5
- class_name: Merit::ActivityLog,
6
- as: :related_change
5
+ class_name: Merit::ActivityLog,
6
+ as: :related_change
7
7
 
8
8
  if defined?(ProtectedAttributes) || !defined?(ActionController::StrongParameters)
9
9
  attr_accessible :badge_id
@@ -12,13 +12,9 @@ module Merit
12
12
  def self.last_granted(options = {})
13
13
  options[:since_date] ||= 1.month.ago
14
14
  options[:limit] ||= 10
15
- where("created_at > '#{options[:since_date]}'").
16
- limit(options[:limit]).
17
- map(&:badge)
18
- end
19
-
20
- def badge
21
- Badge.find(badge_id)
15
+ where("created_at > '#{options[:since_date]}'")
16
+ .limit(options[:limit])
17
+ .map(&:badge)
22
18
  end
23
19
  end
24
20
  end
@@ -6,56 +6,20 @@ module Merit
6
6
  # It's existence make join models like badges_users and scores_users
7
7
  # unnecessary. It should be transparent at the application.
8
8
  class Sash < ActiveRecord::Base
9
+ include Base::Sash
9
10
  has_many :badges_sashes, dependent: :destroy
10
11
  has_many :scores, dependent: :destroy, class_name: 'Merit::Score'
11
12
 
12
13
  after_create :create_scores
13
14
 
14
- def badges
15
- badge_ids.map { |id| Badge.find id }
16
- end
17
-
18
- def badge_ids
19
- badges_sashes.map(&:badge_id)
20
- end
21
-
22
15
  def add_badge(badge_id)
23
16
  bs = BadgesSash.new(badge_id: badge_id)
24
- self.badges_sashes << bs
17
+ badges_sashes << bs
25
18
  bs
26
19
  end
27
20
 
28
21
  def rm_badge(badge_id)
29
22
  badges_sashes.find_by_badge_id(badge_id).try(:destroy)
30
23
  end
31
-
32
-
33
- def points(category = 'default')
34
- scores.where(category: category).first.points
35
- end
36
-
37
- def add_points(num_points, log = 'Manually granted', category = 'default')
38
- point = Merit::Score::Point.new
39
- point.log = log
40
- point.num_points = num_points
41
- self.scores.where(category: category).first.score_points << point
42
- point
43
- end
44
-
45
- # DEPRECATED: Please use <tt>subtract_points</tt> instead.
46
- def substract_points(num_points, log = 'Manually granted', category = 'default')
47
- warn "[DEPRECATION] `substract_points` is deprecated. Please use `subtract_points` instead."
48
- subtract_points num_points, log, category
49
- end
50
-
51
- def subtract_points(num_points, log = 'Manually granted', category = 'default')
52
- add_points -num_points, log, category
53
- end
54
-
55
- private
56
-
57
- def create_scores
58
- self.scores << Merit::Score.create
59
- end
60
24
  end
61
25
  end
@@ -3,8 +3,8 @@ module Merit
3
3
  self.table_name = :merit_scores
4
4
  belongs_to :sash
5
5
  has_many :score_points,
6
- dependent: :destroy,
7
- class_name: 'Merit::Score::Point'
6
+ dependent: :destroy,
7
+ class_name: 'Merit::Score::Point'
8
8
 
9
9
  # Meant to display a leaderboard. Accepts options :table_name (users by
10
10
  # default), :since_date (1.month.ago by default) and :limit (10 by
@@ -24,7 +24,7 @@ module Merit
24
24
  sash_id_column = "#{options[:table_name]}.sash_id"
25
25
  end
26
26
 
27
- # MeritableModel Sash –< Scores –< ScorePoints
27
+ # MeritableModel - Sash -< Scores -< ScorePoints
28
28
  sql_query = <<SQL
29
29
  SELECT
30
30
  #{options[:table_name]}.id AS #{alias_id_column},
@@ -50,9 +50,10 @@ SQL
50
50
 
51
51
  class Point < ActiveRecord::Base
52
52
  belongs_to :score, class_name: 'Merit::Score'
53
+ has_one :sash, through: :score
53
54
  has_many :activity_logs,
54
- class_name: Merit::ActivityLog,
55
- as: :related_change
55
+ class_name: Merit::ActivityLog,
56
+ as: :related_change
56
57
  end
57
58
  end
58
59
  end
@@ -0,0 +1,15 @@
1
+ module Merit
2
+ module Base
3
+ module BadgesSash
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ belongs_to :sash
8
+ end
9
+
10
+ def badge
11
+ Badge.find(badge_id)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,42 @@
1
+ module Merit
2
+ module Base
3
+ module Sash
4
+ # Methods that are common between both the active_record and mongoid sash model
5
+ def badges
6
+ badge_ids.map { |id| Merit::Badge.find id }
7
+ end
8
+
9
+ def badge_ids
10
+ badges_sashes.map(&:badge_id)
11
+ end
12
+
13
+ def points(category = 'default')
14
+ scores.where(category: category).first.points
15
+ end
16
+
17
+ def add_points(num_points, log = 'Manually granted', category = 'default')
18
+ point = Merit::Score::Point.new
19
+ point.log = log
20
+ point.num_points = num_points
21
+ scores.where(category: category).first.score_points << point
22
+ point
23
+ end
24
+
25
+ # DEPRECATED: Please use <tt>subtract_points</tt> instead.
26
+ def substract_points(num_points, log = 'Manually granted', category = 'default')
27
+ warn '[DEPRECATION] `substract_points` is deprecated. Please use `subtract_points` instead.'
28
+ subtract_points num_points, log, category
29
+ end
30
+
31
+ def subtract_points(num_points, log = 'Manually granted', category = 'default')
32
+ add_points(-num_points, log, category)
33
+ end
34
+
35
+ private
36
+
37
+ def create_scores
38
+ scores << Merit::Score.create
39
+ end
40
+ end
41
+ end
42
+ end
@@ -3,13 +3,15 @@ module Merit
3
3
  include Mongoid::Document
4
4
  include Mongoid::Timestamps
5
5
 
6
- belongs_to :user
7
- field :action_method
8
- field :action_value, type: Integer
9
- field :had_errors, type: Boolean
6
+ has_many :activity_logs, class_name: 'Merit::ActivityLog', as: :related_change
10
7
 
11
- belongs_to :target, polymorphic: true
12
- field :processed, type: Boolean, default: false
8
+ field :user_id
9
+ field :action_method
10
+ field :action_value, type: Integer
11
+ field :had_errors, type: Boolean
12
+ field :target_model
13
+ field :target_id
14
+ field :processed, type: Boolean, default: false
13
15
  field :log
14
16
  end
15
17
  end
@@ -0,0 +1,11 @@
1
+ module Merit
2
+ class ActivityLog
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+
6
+ field :description
7
+
8
+ belongs_to :action, class_name: 'Merit::Action'
9
+ belongs_to :related_change, polymorphic: true
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ module Merit
2
+ class BadgesSash
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ include Base::BadgesSash
6
+
7
+ field :badge_id, type: Integer
8
+ attr_accessible :badge_id
9
+ has_many :activity_logs, class_name: 'Merit::ActivityLog', as: :related_change
10
+
11
+ def self.last_granted(options = {})
12
+ options[:since_date] ||= 1.month.ago
13
+ options[:limit] ||= 10
14
+ where(:created_at.lte => options[:since_date])
15
+ .limit(options[:limit])
16
+ .map(&:badge)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ module Merit
2
+ # Sash is a container for reputation data for meritable models. It's an
3
+ # indirection between meritable models and badges and scores (one to one
4
+ # relationship).
5
+ #
6
+ # It's existence make join models like badges_users and scores_users
7
+ # unnecessary. It should be transparent at the application.
8
+ class Sash
9
+ include Mongoid::Document
10
+ include Mongoid::Timestamps
11
+ include Base::Sash
12
+
13
+ has_many :badges_sashes, class_name: 'Merit::BadgesSash', dependent: :destroy
14
+ has_many :scores, class_name: 'Merit::Score', dependent: :destroy
15
+
16
+ after_create :create_scores
17
+
18
+ def add_badge(badge_id)
19
+ bs = Merit::BadgesSash.new(badge_id: badge_id)
20
+ badges_sashes.push(bs)
21
+ end
22
+
23
+ def rm_badge(badge_id)
24
+ bs = badges_sashes.where(badge_id: badge_id).first
25
+ badges_sashes.delete(bs)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,41 @@
1
+ module Merit
2
+ class Score
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+
6
+ field :category, type: String, default: 'default'
7
+
8
+ belongs_to :sash
9
+ has_many :score_points, class_name: 'Merit::Score::Point', dependent: :destroy
10
+
11
+ # Meant to display a leaderboard. Accepts options :table_name (users by
12
+ # default), :since_date (1.month.ago by default) and :limit (10 by
13
+ # default).
14
+ #
15
+ # It lists top 10 scored objects in the last month, unless you change
16
+ # query parameters.
17
+ def self.top_scored(options = {})
18
+ options[:since_date] ||= 1.month.ago
19
+ options[:limit] ||= 10
20
+ Score.where(created_at: (options[:since_date]..Time.now))
21
+ .desc(:points)
22
+ .limit(options[:limit])
23
+ .flatten.map { |score| score.sash.user }
24
+ end
25
+
26
+ def points
27
+ score_points.sum(:num_points) || 0
28
+ end
29
+
30
+ class Point
31
+ include Mongoid::Document
32
+ include Mongoid::Timestamps
33
+
34
+ field :num_points, type: Integer, default: 0
35
+ field :log, type: String
36
+
37
+ belongs_to :score, class_name: 'Merit::Score'
38
+ has_many :activity_logs, class_name: 'Merit::ActivityLog', as: :related_change
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,11 @@
1
+ module Merit
2
+ class ReputationChangeObserver
3
+ def update(changed_data)
4
+ ActivityLog.create(
5
+ description: changed_data[:description],
6
+ related_change: changed_data[:merit_object],
7
+ action_id: changed_data[:merit_action_id]
8
+ )
9
+ end
10
+ end
11
+ end
data/lib/merit/rule.rb CHANGED
@@ -4,7 +4,7 @@ module Merit
4
4
  # Could split this class between badges and rankings functionality
5
5
  class Rule
6
6
  attr_accessor :badge_name, :level, :to, :model_name, :level_name,
7
- :multiple, :temporary, :score, :block
7
+ :multiple, :temporary, :score, :block
8
8
 
9
9
  # Does this rule's condition block apply?
10
10
  def applies?(target_obj = nil)
@@ -1,6 +1,5 @@
1
1
  module Merit
2
2
  class RulesMatcher
3
-
4
3
  def initialize(path, action_name)
5
4
  @path = path
6
5
  @action_name = action_name
@@ -21,6 +20,5 @@ module Merit
21
20
  def entire_path
22
21
  @entire_path ||= [@path, @action_name].join('#')
23
22
  end
24
-
25
23
  end
26
24
  end
@@ -23,7 +23,7 @@ module Merit
23
23
  end
24
24
 
25
25
  defined_rules[options[:to]] ||= {}
26
- defined_rules[options[:to]].merge!({ options[:level] => rule })
26
+ defined_rules[options[:to]].merge!(options[:level] => rule)
27
27
  end
28
28
 
29
29
  # Not part of merit after_filter. To be called asynchronously:
@@ -1,7 +1,7 @@
1
1
  module Merit
2
2
  class TargetFinder < Struct.new(:rule, :action)
3
3
  def self.find(*args)
4
- self.new(*args).find
4
+ new(*args).find
5
5
  end
6
6
 
7
7
  def find
@@ -40,6 +40,5 @@ module Merit
40
40
  str << ' (called from Merit::TargetFinder#other_target)'
41
41
  Rails.logger.warn str
42
42
  end
43
-
44
43
  end
45
44
  end
data/merit.gemspec CHANGED
@@ -5,7 +5,7 @@ Gem::Specification.new do |s|
5
5
  s.homepage = "http://github.com/tute/merit"
6
6
  s.files = `git ls-files`.split("\n").reject{|f| f =~ /^\./ }
7
7
  s.license = 'MIT'
8
- s.version = '1.7.1'
8
+ s.version = '1.8.0'
9
9
  s.authors = ["Tute Costa"]
10
10
  s.email = 'tutecosta@gmail.com'
11
11
 
@@ -15,6 +15,7 @@ Gem::Specification.new do |s|
15
15
  s.add_development_dependency 'rails', '>= 3.2.0'
16
16
  s.add_development_dependency 'capybara'
17
17
  s.add_development_dependency 'simplecov'
18
+ s.add_development_dependency 'rubocop'
18
19
  s.add_development_dependency 'minitest-rails'
19
20
  s.add_development_dependency 'mocha', '0.13.3'
20
21
  end