merit 1.7.1 → 1.8.0

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 (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