merit 1.9.0 → 2.0.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +11 -13
  4. data/UPGRADING.md +8 -1
  5. data/lib/generators/active_record/install_generator.rb +14 -5
  6. data/lib/generators/active_record/merit_generator.rb +2 -1
  7. data/lib/generators/active_record/remove_generator.rb +5 -2
  8. data/lib/generators/merit/merit_generator.rb +3 -1
  9. data/lib/generators/merit/templates/merit_badge_rules.rb +9 -5
  10. data/lib/merit.rb +3 -10
  11. data/lib/merit/judge.rb +5 -1
  12. data/lib/merit/model_additions.rb +14 -13
  13. data/lib/merit/models/active_record/merit/action.rb +2 -2
  14. data/lib/merit/models/active_record/merit/activity_log.rb +2 -2
  15. data/lib/merit/models/active_record/merit/badges_sash.rb +2 -15
  16. data/lib/merit/models/active_record/merit/score.rb +1 -36
  17. data/lib/merit/models/base/{merit/badges_sash.rb → badges_sash.rb} +0 -0
  18. data/lib/merit/models/base/sash.rb +59 -0
  19. data/lib/merit/models/mongoid/merit/badges_sash.rb +3 -1
  20. data/lib/merit/rule.rb +1 -1
  21. data/lib/merit/rules_points_methods.rb +3 -2
  22. data/merit.gemspec +1 -1
  23. data/test/dummy/app/models/comment.rb +1 -1
  24. data/test/dummy/app/models/merit/point_rules.rb +1 -1
  25. data/test/dummy/app/models/user.rb +1 -1
  26. data/test/dummy/app/views/users/index.html.erb +1 -0
  27. data/test/integration/navigation_test.rb +1 -0
  28. data/test/test_helper.rb +5 -0
  29. data/test/unit/base_target_finder_test.rb +0 -3
  30. data/test/unit/merit_unit_test.rb +4 -40
  31. data/test/unit/rule_unit_test.rb +1 -1
  32. data/test/unit/rules_matcher_test.rb +6 -6
  33. data/test/unit/sash_finder_test.rb +1 -4
  34. data/test/unit/sash_test.rb +104 -0
  35. data/test/unit/target_finder_test.rb +4 -5
  36. metadata +5 -4
  37. data/lib/merit/models/base/merit/sash.rb +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: debce052338bde9db1f6ad4a50b88cbad2cdd466
4
- data.tar.gz: 3c41c3c3ce1df213836fdb4f708425cc83fb9ec6
3
+ metadata.gz: c0822239c7421032c0da3487684baadd738b4805
4
+ data.tar.gz: 44eb5162425fc37edb09615e7f95f112d6b8cf04
5
5
  SHA512:
6
- metadata.gz: ccb24cf9023b3aa519e9e265379a57864176019a63cfde2253fc145b82a58fe402fc0ffe2963b7f43ec9ab5242d26819d10e7814743c62e2aa435e2a91b427d3
7
- data.tar.gz: e77bf853ca0b6ca140f57a04fe32d3e0c6499cc13027e4a413514967afabb3544d6dc7bb9babd5fe84b5cf382bfe242a0bff222a2121be543ae13fdb08af27cd
6
+ metadata.gz: 5379050b40dd4b93083443c349cf0726ee7fa436708cb2d8a4456f86b1a2b6de5c0b2dae51205613bca4b39fb5ea6bd9afded0d45d07fbfa962654284b31c08c
7
+ data.tar.gz: 346cf4cd10a20c4bfb07b1579cf16291ec77b6906b1f22999444bc7950b797d3fc372dfc4a63e8e393c56117b211e33ca571d8bacd1a8c7c3de5209c4130f8d9
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0
4
+
5
+ - [#146] Fixes loading paths
6
+ - [#140] Points Categories feature
7
+ - Removes deprecated methods
8
+
9
+ ## 1.9.0
10
+
11
+ - [#134] Bug fix: find sashes only when rules apply.
12
+ - Adds deprecation warnings.
13
+
3
14
  ## 1.8.0
4
15
 
5
16
  - [#128] Finishes Observer implementation so client applications can be
data/README.md CHANGED
@@ -28,7 +28,6 @@ and Rankings.
28
28
  - [Displaying Rankings](#displaying-rankings)
29
29
  - [Getting Notifications](#getting-notifications)
30
30
  - [Uninstalling Merit](#uninstalling-merit)
31
- - [To-do List](#to-do-list)
32
31
 
33
32
 
34
33
  # Installation
@@ -159,6 +158,7 @@ action user or to the method(s) defined in the `:to` option. Define rules on
159
158
  * `:model_name` (optional) to specify the model name if it cannot be guessed
160
159
  from the controller. (e.g. `model_name: 'User'` for `RegistrationsController`,
161
160
  or `model_name: 'Comment'` for `Api::CommentsController`)
161
+ * `:category` (optional) to categorize earned points. `default` is used by default.
162
162
  * `&block`
163
163
  * empty (always scores)
164
164
  * a block which evaluates to boolean (recieves target object as parameter)
@@ -167,7 +167,7 @@ action user or to the method(s) defined in the `:to` option. Define rules on
167
167
 
168
168
  ```ruby
169
169
  # app/models/merit/point_rules.rb
170
- score 10, to: :post_creator, on: 'comments#create' do |comment|
170
+ score 10, to: :post_creator, on: 'comments#create', category: 'comment_activity' do |comment|
171
171
  comment.title.present?
172
172
  end
173
173
 
@@ -186,13 +186,13 @@ score proc, on: 'photos#create'
186
186
 
187
187
  ```ruby
188
188
  # Score manually
189
- current_user.add_points(20)
190
- current_user.subtract_points(10)
189
+ current_user.add_points(20, category: 'Optional category')
190
+ current_user.subtract_points(10, category: 'Optional category')
191
191
  ```
192
192
 
193
193
  ```ruby
194
194
  # Query awarded points since a given date
195
- score_points = current_user.sash.scores.first.score_points
195
+ score_points = current_user.score_points(category: 'Optional category')
196
196
  score_points.where("created_at > '#{1.month.ago}'").sum(:num_points)
197
197
  ```
198
198
 
@@ -201,9 +201,14 @@ score_points.where("created_at > '#{1.month.ago}'").sum(:num_points)
201
201
  Meritable models have a `points` method which returns an integer:
202
202
 
203
203
  ```erb
204
- <%= current_user.points %>
204
+ <%= current_user.points(category: 'Optional category') %>
205
205
  ```
206
206
 
207
+ If `category` left empty, it will return the sum of points for every category.
208
+
209
+ ```erb
210
+ <%= current_user.points %>
211
+ ```
207
212
 
208
213
  # Rankings
209
214
 
@@ -287,10 +292,3 @@ config.add_observer 'ReputationChangeObserver'
287
292
  3. Run `rails g merit:remove MODEL_NAME` (e.g. `user`)
288
293
  4. Run `rake db:migrate`
289
294
  5. Remove `merit` from your Gemfile
290
-
291
-
292
- # To-do List
293
-
294
- ## Pre 2.0.0
295
-
296
- * Move level from meritable model into Sash
@@ -1,6 +1,13 @@
1
1
  # Main Changes / Upgrading Notes
2
2
 
3
- ## 1.9.0 (not released yet)
3
+ ## 2.0.0
4
+
5
+ * Removes deprecated methods: `Merit::Badge.last_granted` and
6
+ `Merit::Score.top_scored`.
7
+ * Removes `add_points` `log` parameter.
8
+ * Adds points category option.
9
+
10
+ ## 1.9.0
4
11
 
5
12
  * Deprecates `Merit::Badge.last_granted` and `Merit::Score.top_scored`.
6
13
  Code can be readded to client applications following instructions in:
@@ -13,11 +13,20 @@ module ActiveRecord
13
13
  end
14
14
 
15
15
  def copy_migrations_and_model
16
- migration_template 'create_merit_actions.rb', 'db/migrate/create_merit_actions.rb'
17
- migration_template 'create_merit_activity_logs.rb', 'db/migrate/create_merit_activity_logs.rb'
18
- migration_template 'create_sashes.rb', 'db/migrate/create_sashes.rb'
19
- migration_template 'create_badges_sashes.rb', 'db/migrate/create_badges_sashes.rb'
20
- migration_template 'create_scores_and_points.rb', 'db/migrate/create_scores_and_points.rb'
16
+ migration_template 'create_merit_actions.rb',
17
+ 'db/migrate/create_merit_actions.rb'
18
+
19
+ migration_template 'create_merit_activity_logs.rb',
20
+ 'db/migrate/create_merit_activity_logs.rb'
21
+
22
+ migration_template 'create_sashes.rb',
23
+ 'db/migrate/create_sashes.rb'
24
+
25
+ migration_template 'create_badges_sashes.rb',
26
+ 'db/migrate/create_badges_sashes.rb'
27
+
28
+ migration_template 'create_scores_and_points.rb',
29
+ 'db/migrate/create_scores_and_points.rb'
21
30
  end
22
31
  end
23
32
  end
@@ -13,7 +13,8 @@ module ActiveRecord
13
13
  end
14
14
 
15
15
  def copy_migrations_and_model
16
- migration_template 'add_fields_to_model.rb', "db/migrate/add_fields_to_#{table_name}"
16
+ migration_template 'add_fields_to_model.rb',
17
+ "db/migrate/add_fields_to_#{table_name}"
17
18
  end
18
19
  end
19
20
  end
@@ -13,8 +13,11 @@ module ActiveRecord
13
13
  end
14
14
 
15
15
  def copy_migrations_and_model
16
- migration_template 'remove_merit_tables.rb', 'db/migrate/remove_merit_tables.rb'
17
- migration_template 'remove_fields_from_model.rb', "db/migrate/remove_fields_from_#{table_name}"
16
+ migration_template 'remove_merit_tables.rb',
17
+ 'db/migrate/remove_merit_tables.rb'
18
+
19
+ migration_template 'remove_fields_from_model.rb',
20
+ "db/migrate/remove_fields_from_#{table_name}"
18
21
  end
19
22
  end
20
23
  end
@@ -5,7 +5,9 @@ module Merit
5
5
  hook_for :orm
6
6
 
7
7
  def inject_merit_content
8
- inject_into_class(model_path, class_name, " has_merit\n\n") if model_exists?
8
+ if model_exists?
9
+ inject_into_class(model_path, class_name, " has_merit\n\n")
10
+ end
9
11
  end
10
12
 
11
13
  private
@@ -4,7 +4,7 @@
4
4
  # * Nothing (always grants)
5
5
  # * A block which evaluates to boolean (recieves the object as parameter)
6
6
  # * A block with a hash composed of methods to run on the target object with
7
- # expected values (+:votes => 5+ for instance).
7
+ # expected values (+votes: 5+ for instance).
8
8
  #
9
9
  # +grant_on+ can have a +:to+ method name, which called over the target object
10
10
  # should retrieve the object to badge (could be +:user+, +:self+, +:follower+,
@@ -23,20 +23,24 @@ module Merit
23
23
  def initialize
24
24
  # If it creates user, grant badge
25
25
  # Should be "current_user" after registration for badge to be granted.
26
- # grant_on 'users#create', :badge => 'just-registered', :to => :itself
26
+ # grant_on 'users#create', badge: 'just-registered', to: :itself
27
27
 
28
28
  # If it has 10 comments, grant commenter-10 badge
29
- # grant_on 'comments#create', :badge => 'commenter', :level => 10 do |comment|
29
+ # grant_on 'comments#create', badge: 'commenter', level: 10 do |comment|
30
30
  # comment.user.comments.count == 10
31
31
  # end
32
32
 
33
33
  # If it has 5 votes, grant relevant-commenter badge
34
- # grant_on 'comments#vote', :badge => 'relevant-commenter', :to => :user do |comment|
34
+ # grant_on 'comments#vote', badge: 'relevant-commenter',
35
+ # to: :user do |comment|
36
+ #
35
37
  # comment.votes.count == 5
36
38
  # end
37
39
 
38
40
  # Changes his name by one wider than 4 chars (arbitrary ruby code case)
39
- # grant_on 'registrations#update', :badge => 'autobiographer', :temporary => true, :model_name => 'User' do |user|
41
+ # grant_on 'registrations#update', badge: 'autobiographer',
42
+ # temporary: true, model_name: 'User' do |user|
43
+ #
40
44
  # user.name.length > 4
41
45
  # end
42
46
  end
@@ -10,6 +10,8 @@ require 'merit/reputation_change_observer'
10
10
  require 'merit/sash_finder'
11
11
  require 'merit/base_target_finder'
12
12
  require 'merit/target_finder'
13
+ require 'merit/models/base/sash'
14
+ require 'merit/models/base/badges_sash'
13
15
 
14
16
  module Merit
15
17
  def self.setup
@@ -70,9 +72,9 @@ module Merit
70
72
 
71
73
  class Engine < Rails::Engine
72
74
  config.app_generators.orm Merit.orm
75
+ config.eager_load_paths << File.expand_path("../merit/models/#{Merit.orm}", __FILE__)
73
76
 
74
77
  initializer 'merit.controller' do |app|
75
- require_models
76
78
  extend_orm_with_has_merit
77
79
  ActiveSupport.on_load(:action_controller) do
78
80
  begin
@@ -87,15 +89,6 @@ module Merit
87
89
  end
88
90
  end
89
91
 
90
- def require_models
91
- require 'merit/models/base/merit/sash'
92
- require 'merit/models/base/merit/badges_sash'
93
- require "merit/models/#{Merit.orm}/merit/activity_log"
94
- require "merit/models/#{Merit.orm}/merit/badges_sash"
95
- require "merit/models/#{Merit.orm}/merit/sash"
96
- require "merit/models/#{Merit.orm}/merit/score"
97
- end
98
-
99
92
  def extend_orm_with_has_merit
100
93
  if Object.const_defined?('ActiveRecord')
101
94
  ActiveRecord::Base.send :include, Merit
@@ -25,7 +25,7 @@ module Merit
25
25
  def apply_points
26
26
  return unless rule_applies?
27
27
  sashes.each do |sash|
28
- point = sash.add_points points
28
+ point = sash.add_points points, category: category
29
29
  notify_observers(
30
30
  description: "granted #{points} points",
31
31
  merit_object: point,
@@ -79,6 +79,10 @@ module Merit
79
79
  end
80
80
  end
81
81
 
82
+ def category
83
+ @rule.category
84
+ end
85
+
82
86
  def sashes
83
87
  @sashes ||= SashFinder.find @rule, @action
84
88
  end
@@ -9,7 +9,7 @@ module Merit
9
9
  # https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1079-belongs_to-dependent-destroy-should-destroy-self-before-assocation
10
10
  belongs_to :sash, class_name: 'Merit::Sash'
11
11
 
12
- _merit_orm_specific_config
12
+ send :"_merit_#{Merit.orm}_specific_config"
13
13
  _merit_delegate_methods_to_sash
14
14
  _merit_define_badge_related_entries_method
15
15
  _merit_sash_initializer
@@ -18,21 +18,17 @@ module Merit
18
18
  # Delegate methods from meritable models to their sash
19
19
  def _merit_delegate_methods_to_sash
20
20
  methods = %w(badge_ids badges points add_badge rm_badge
21
- add_points substract_points subtract_points)
21
+ add_points subtract_points score_points)
22
22
  methods.each { |method| delegate method, to: :_sash }
23
23
  end
24
24
 
25
- def _merit_orm_specific_config
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
32
- field :level, type: Integer, default: 0
33
- def find_by_id(id)
34
- where(_id: id).first
35
- end
25
+ def _merit_active_record_specific_config
26
+ end
27
+
28
+ def _merit_mongoid_specific_config
29
+ field :level, type: Integer, default: 0
30
+ def find_by_id(id)
31
+ where(_id: id).first
36
32
  end
37
33
  end
38
34
 
@@ -41,6 +37,11 @@ module Merit
41
37
  Badge._define_related_entries_method(meritable_class_name)
42
38
  end
43
39
 
40
+ def show_attr_accessible?
41
+ defined?(ProtectedAttributes) ||
42
+ !defined?(ActionController::StrongParameters)
43
+ end
44
+
44
45
  # _sash initializes a sash if doesn't have one yet.
45
46
  # From Rails 3.2 we can override association methods to do so
46
47
  # transparently, but merit supports Rails ~> 3.0.0. See:
@@ -2,9 +2,9 @@ module Merit
2
2
  class Action < ActiveRecord::Base
3
3
  self.table_name = :merit_actions
4
4
 
5
- has_many :activity_logs, class_name: Merit::ActivityLog
5
+ has_many :activity_logs, class_name: 'Merit::ActivityLog'
6
6
 
7
- if defined?(ProtectedAttributes) || !defined?(ActionController::StrongParameters)
7
+ if show_attr_accessible?
8
8
  attr_accessible :user_id, :action_method, :action_value, :had_errors,
9
9
  :target_model, :target_id, :processed, :log
10
10
  end
@@ -2,11 +2,11 @@ module Merit
2
2
  class ActivityLog < ActiveRecord::Base
3
3
  self.table_name = :merit_activity_logs
4
4
 
5
- belongs_to :action, class_name: Merit::Action
5
+ belongs_to :action, class_name: 'Merit::Action'
6
6
  belongs_to :related_change, polymorphic: true
7
7
  has_one :sash, through: :related_change
8
8
 
9
- if defined?(ProtectedAttributes) || !defined?(ActionController::StrongParameters)
9
+ if show_attr_accessible?
10
10
  attr_accessible :action_id, :related_change, :description, :created_at
11
11
  end
12
12
  end
@@ -2,22 +2,9 @@ module Merit
2
2
  class BadgesSash < ActiveRecord::Base
3
3
  include Base::BadgesSash
4
4
  has_many :activity_logs,
5
- class_name: Merit::ActivityLog,
5
+ class_name: 'Merit::ActivityLog',
6
6
  as: :related_change
7
7
 
8
- if defined?(ProtectedAttributes) || !defined?(ActionController::StrongParameters)
9
- attr_accessible :badge_id
10
- end
11
-
12
- # DEPRECATED: `last_granted` will be removed from merit, please refer to:
13
- # https://github.com/tute/merit/wiki/How-to-show-last-granted-badges
14
- def self.last_granted(options = {})
15
- warn '[merit] [DEPRECATION] `last_granted` will be removed from merit, please refer to: https://github.com/tute/merit/wiki/How-to-show-last-granted-badges'
16
- options[:since_date] ||= 1.month.ago
17
- options[:limit] ||= 10
18
- where("created_at > '#{options[:since_date]}'")
19
- .limit(options[:limit])
20
- .map(&:badge)
21
- end
8
+ attr_accessible :badge_id if show_attr_accessible?
22
9
  end
23
10
  end
@@ -6,41 +6,6 @@ module Merit
6
6
  dependent: :destroy,
7
7
  class_name: 'Merit::Score::Point'
8
8
 
9
- # DEPRECATED: `top_scored` will be removed from merit, please refer to:
10
- # https://github.com/tute/merit/wiki/How-to-show-a-points-leaderboard
11
- def self.top_scored(options = {})
12
- warn '[merit] [DEPRECATION] `top_scored` will be removed from merit, please refer to: https://github.com/tute/merit/wiki/How-to-show-a-points-leaderboard'
13
- options[:table_name] ||= :users
14
- options[:since_date] ||= 1.month.ago
15
- options[:limit] ||= 10
16
-
17
- alias_id_column = "#{options[:table_name].to_s.singularize}_id"
18
- if options[:table_name] == :sashes
19
- sash_id_column = "#{options[:table_name]}.id"
20
- else
21
- sash_id_column = "#{options[:table_name]}.sash_id"
22
- end
23
-
24
- # MeritableModel - Sash -< Scores -< ScorePoints
25
- sql_query = <<SQL
26
- SELECT
27
- #{options[:table_name]}.id AS #{alias_id_column},
28
- SUM(num_points) as sum_points
29
- FROM #{options[:table_name]}
30
- LEFT JOIN merit_scores ON merit_scores.sash_id = #{sash_id_column}
31
- LEFT JOIN merit_score_points ON merit_score_points.score_id = merit_scores.id
32
- WHERE merit_score_points.created_at > '#{options[:since_date]}'
33
- GROUP BY #{options[:table_name]}.id, merit_scores.sash_id
34
- ORDER BY sum_points DESC
35
- LIMIT #{options[:limit]}
36
- SQL
37
- results = ActiveRecord::Base.connection.execute(sql_query)
38
- results.map do |h|
39
- h.keep_if { |k, v| (k == alias_id_column) || (k == 'sum_points') }
40
- end
41
- results
42
- end
43
-
44
9
  def points
45
10
  score_points.group(:score_id).sum(:num_points).values.first || 0
46
11
  end
@@ -49,7 +14,7 @@ SQL
49
14
  belongs_to :score, class_name: 'Merit::Score'
50
15
  has_one :sash, through: :score
51
16
  has_many :activity_logs,
52
- class_name: Merit::ActivityLog,
17
+ class_name: 'Merit::ActivityLog',
53
18
  as: :related_change
54
19
  end
55
20
  end
@@ -0,0 +1,59 @@
1
+ module Merit
2
+ module Base
3
+ module Sash
4
+ def badges
5
+ badge_ids.map { |id| Merit::Badge.find id }
6
+ end
7
+
8
+ def badge_ids
9
+ badges_sashes.map(&:badge_id)
10
+ end
11
+
12
+ # Retrieve the number of points from a category
13
+ # By default all points are summed up
14
+ # @param category [String] The category
15
+ # @return [Integer] The number of points
16
+ def points(options = {})
17
+ if (category = options[:category])
18
+ scores.where(category: category).first.try(:points) || 0
19
+ else
20
+ scores.reduce(0) { |sum, score| sum + score.points }
21
+ end
22
+ end
23
+
24
+ # Retrieve all points from a category or none if category doesn't exist
25
+ # By default retrieve all Points
26
+ # @param category [String] The category
27
+ # @return [ActiveRecord::Relation] containing the points
28
+ def score_points(options = {})
29
+ scope = Merit::Score::Point
30
+ .includes(:score)
31
+ .where('merit_scores.sash_id = ?', id)
32
+ if (category = options[:category])
33
+ scope = scope.where('merit_scores.category = ?', category)
34
+ end
35
+ scope
36
+ end
37
+
38
+ def add_points(num_points, options = {})
39
+ point = Merit::Score::Point.new
40
+ point.num_points = num_points
41
+ scores
42
+ .where(category: options[:category] || 'default')
43
+ .first_or_create
44
+ .score_points << point
45
+ point
46
+ end
47
+
48
+ def subtract_points(num_points, options = {})
49
+ add_points(-num_points, options)
50
+ end
51
+
52
+ private
53
+
54
+ def create_scores
55
+ scores << Merit::Score.create
56
+ end
57
+ end
58
+ end
59
+ end
@@ -5,7 +5,9 @@ module Merit
5
5
  include Base::BadgesSash
6
6
 
7
7
  field :badge_id, type: Integer
8
- attr_accessible :badge_id
8
+
9
+ attr_accessible :badge_id if show_attr_accessible?
10
+
9
11
  has_many :activity_logs, class_name: 'Merit::ActivityLog', as: :related_change
10
12
 
11
13
  def self.last_granted(options = {})
@@ -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, :category
8
8
 
9
9
  # Does this rule's condition block apply?
10
10
  def applies?(target_obj = nil)
@@ -6,15 +6,16 @@ module Merit
6
6
  # Define rules on certaing actions for giving points
7
7
  def score(points, *args, &block)
8
8
  options = args.extract_options!
9
- options[:to] ||= :action_user
9
+ options_to = options.fetch(:to) { :action_user }
10
10
 
11
11
  actions = Array.wrap(options[:on])
12
12
 
13
- Array.wrap(options[:to]).each do |to|
13
+ Array.wrap(options_to).each do |to|
14
14
  rule = Rule.new
15
15
  rule.score = points
16
16
  rule.to = to
17
17
  rule.block = block
18
+ rule.category = options.fetch(:category) { :default }
18
19
  rule.model_name = options[:model_name] if options[:model_name]
19
20
 
20
21
  actions.each do |action|
@@ -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.9.0'
8
+ s.version = '2.0.0'
9
9
  s.authors = ["Tute Costa"]
10
10
  s.email = 'tutecosta@gmail.com'
11
11
 
@@ -18,7 +18,7 @@ class Comment
18
18
 
19
19
  belongs_to :user
20
20
 
21
- if defined?(ProtectedAttributes) || !defined?(ActionController::StrongParameters)
21
+ if show_attr_accessible?
22
22
  attr_accessible :name, :comment, :user_id, :votes
23
23
  end
24
24
 
@@ -14,7 +14,7 @@ module Merit
14
14
  score 2, to: :user_comments, on: 'comments#vote'
15
15
 
16
16
  # Points to voted user
17
- score 5, to: :user, on: 'comments#vote'
17
+ score 5, to: :user, on: 'comments#vote', category: 'vote'
18
18
 
19
19
  # Example rule for using model_name in the case of namespaced controllers
20
20
  score 1, to: :user, model_name: 'Comment', on: 'api/comments#show'
@@ -17,7 +17,7 @@ class User
17
17
  has_many :addresses
18
18
  has_many :comments
19
19
 
20
- if defined?(ProtectedAttributes) || !defined?(ActionController::StrongParameters)
20
+ if show_attr_accessible?
21
21
  attr_accessible :name
22
22
  end
23
23
 
@@ -14,6 +14,7 @@
14
14
  <td><%= user.comments.count %></td>
15
15
  <td><%= user.show_badges %></td>
16
16
  <td><%= user.points %></td>
17
+ <td><%= user.points(category: 'vote') %></td>
17
18
  <td><%= link_to 'Show', user %>
18
19
  - <%= link_to 'Edit', edit_user_path(user) %>
19
20
  - <%= link_to 'Destroy', user, data: { :confirm => 'Are you sure?' }, :method => :delete %></td>
@@ -186,6 +186,7 @@ class NavigationTest < ActiveSupport::IntegrationCase
186
186
  visit "/comments/#{Comment.last.id}/vote/4"
187
187
  user = User.first
188
188
  assert_equal 46, user.points, 'Voting comments should grant 5 points for voted, and 1 point for voting'
189
+ assert_equal 5, user.points(category: 'vote'), 'Voting comments should grant 5 points for voted in vote category'
189
190
 
190
191
  visit '/comments/new'
191
192
  fill_in 'Name', with: 'Hi'
@@ -28,5 +28,10 @@ Capybara.default_selector = :css
28
28
 
29
29
  ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
30
30
 
31
+ require "merit/models/#{Merit.orm}/merit/activity_log"
32
+ require "merit/models/#{Merit.orm}/merit/badges_sash"
33
+ require "merit/models/#{Merit.orm}/merit/sash"
34
+ require "merit/models/#{Merit.orm}/merit/score"
35
+
31
36
  # Load support files
32
37
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
@@ -1,7 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
3
  describe Merit::BaseTargetFinder do
4
-
5
4
  describe '#find' do
6
5
  describe 'rule has a model_name' do
7
6
  it "should prioritize the rule's model name" do
@@ -39,7 +38,6 @@ describe Merit::BaseTargetFinder do
39
38
  rule.to = :itself
40
39
  rule.model_name = 'registrations'
41
40
  action = Merit::Action.new(target_model: 'users', target_id: 220)
42
- comment = Comment.new
43
41
 
44
42
  finder = Merit::BaseTargetFinder.new(rule, action)
45
43
  Rails.logger.expects(:warn)
@@ -47,5 +45,4 @@ describe Merit::BaseTargetFinder do
47
45
  end
48
46
  end
49
47
  end
50
-
51
48
  end
@@ -4,11 +4,9 @@ require 'test_helper'
4
4
  class MeritUnitTest < ActiveSupport::TestCase
5
5
  test 'extends only meritable ActiveRecord models' do
6
6
  class User < ActiveRecord::Base
7
- def self.columns; @columns ||= []; end
8
7
  has_merit
9
8
  end
10
9
  class Fruit < ActiveRecord::Base
11
- def self.columns; @columns ||= []; end
12
10
  end
13
11
 
14
12
  assert User.method_defined?(:points), 'has_merit adds methods'
@@ -17,50 +15,15 @@ class MeritUnitTest < ActiveSupport::TestCase
17
15
 
18
16
  test 'Badges get "related_models" methods' do
19
17
  class Soldier < ActiveRecord::Base
20
- def self.columns; @columns ||= []; end
21
18
  has_merit
22
19
  end
23
20
  class Player < ActiveRecord::Base
24
- def self.columns; @columns ||= []; end
25
21
  has_merit
26
22
  end
27
23
  assert Merit::Badge.method_defined?(:soldiers), 'Badge#soldiers should be defined'
28
24
  assert Merit::Badge.method_defined?(:players), 'Badge#players should be defined'
29
25
  end
30
26
 
31
- test 'Badge#last_granted returns recently granted badges' do
32
- # Create sashes, badges and badges_sashes
33
- sash = Merit::Sash.create
34
- badge = Merit::Badge.create(id: 20, name: 'test-badge-21')
35
- sash.add_badge badge.id
36
- Merit::BadgesSash.last.update_attribute :created_at, 1.day.ago
37
- sash.add_badge badge.id
38
- Merit::BadgesSash.last.update_attribute :created_at, 8.days.ago
39
- sash.add_badge badge.id
40
- Merit::BadgesSash.last.update_attribute :created_at, 15.days.ago
41
-
42
- # Test method options
43
- assert_equal Merit::Badge.last_granted(since_date: Time.now), []
44
- assert_equal Merit::Badge.last_granted(since_date: 1.week.ago), [badge]
45
- assert_equal Merit::Badge.last_granted(since_date: 2.weeks.ago).count, 2
46
- assert_equal Merit::Badge.last_granted(since_date: 2.weeks.ago, limit: 1), [badge]
47
- end
48
-
49
- test 'Merit::Score.top_scored returns scores leaderboard' do
50
- # Create sashes and add points
51
- sash_1 = Merit::Sash.create
52
- sash_1.add_points(10); sash_1.add_points(10)
53
- sash_2 = Merit::Sash.create
54
- sash_2.add_points(5); sash_2.add_points(5)
55
-
56
- # Test method options
57
- assert_equal [{'sash_id'=>sash_1.id, 'sum_points'=>20},
58
- {'sash_id'=>sash_2.id, 'sum_points'=>10}],
59
- Merit::Score.top_scored(table_name: :sashes)
60
- assert_equal [{'sash_id'=>sash_1.id, 'sum_points'=>20}],
61
- Merit::Score.top_scored(table_name: :sashes, limit: 1)
62
- end
63
-
64
27
  test 'unknown ranking raises exception' do
65
28
  class WeirdRankRules
66
29
  include Merit::RankRulesMethods
@@ -74,8 +37,9 @@ class MeritUnitTest < ActiveSupport::TestCase
74
37
  end
75
38
 
76
39
  test 'Badge#custom_fields_hash saves correctly' do
77
- Merit::Badge.create(id: 99, name: 'test-badge',
78
- custom_fields: { key_1: 'value1' })
40
+ Merit::Badge.create(id: 99,
41
+ name: 'test-badge',
42
+ custom_fields: { key_1: 'value1' })
79
43
  assert_equal 'value1', Merit::Badge.find(99).custom_fields[:key_1]
80
44
  end
81
- end
45
+ end
@@ -32,7 +32,7 @@ describe Merit::Rule do
32
32
  describe '#badge' do
33
33
  it 'raises exception on inexistent badge' do
34
34
  @rule.badge_name = 'inexistent'
35
- ->{ @rule.badge }.must_raise Merit::BadgeNotFound
35
+ -> { @rule.badge }.must_raise Merit::BadgeNotFound
36
36
  end
37
37
 
38
38
  it 'finds related badge' do
@@ -5,29 +5,29 @@ describe Merit::RulesMatcher do
5
5
  describe 'rules actions are treated as a regexp' do
6
6
  it 'selects matching rules (suffix)' do
7
7
  matcher = Merit::RulesMatcher.new('comments', 'update')
8
- matcher.select_from({
8
+ matcher.select_from(
9
9
  'comments#update' => 'comments#update',
10
10
  'comments#up' => 'comments#up',
11
11
  'comments#up$' => 'comments#up$',
12
12
  'comments#up.+$' => 'comments#up.+$',
13
- }).must_be :==, ['comments#update', 'comments#up.+$']
13
+ ).must_be :==, ['comments#update', 'comments#up.+$']
14
14
 
15
15
  matcher = Merit::RulesMatcher.new('comments', 'up')
16
- matcher.select_from({
16
+ matcher.select_from(
17
17
  'comments#update' => 'comments#update',
18
18
  'comments#up' => 'comments#up',
19
19
  'comments#up$' => 'comments#up$',
20
20
  'comments#up.+$' => 'comments#up.+$',
21
- }).must_be :==, ['comments#up', 'comments#up$']
21
+ ).must_be :==, ['comments#up', 'comments#up$']
22
22
  end
23
23
 
24
24
  it 'selects matching rules (prefix)' do
25
25
  matcher = Merit::RulesMatcher.new('/posts/1/comments', 'create')
26
- matcher.select_from({
26
+ matcher.select_from(
27
27
  'comments#create' => 'comments#create',
28
28
  '^comments#create' => '^comments#create',
29
29
  '^.*/comments#create' => '^.*/comments#create',
30
- }).must_be :==, ['^.*/comments#create']
30
+ ).must_be :==, ['^.*/comments#create']
31
31
  end
32
32
  end
33
33
 
@@ -1,7 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
3
  describe Merit::SashFinder do
4
-
5
4
  it 'should return an array of sashes of the target objects' do
6
5
  sash_1 = Merit::Sash.new
7
6
  user_1 = User.new
@@ -11,9 +10,8 @@ describe Merit::SashFinder do
11
10
  user_2 = User.new
12
11
  user_2.stubs(:_sash).returns(sash_2)
13
12
 
14
- object_without_sash = OpenStruct.new
15
-
16
13
  # TODO: With stub we are not exercising compact
14
+ # object_without_sash = OpenStruct.new
17
15
  # users = [user_1, user_2, object_without_sash]
18
16
  users = [user_1, user_2]
19
17
 
@@ -26,5 +24,4 @@ describe Merit::SashFinder do
26
24
  sashes.must_include sash_1
27
25
  sashes.must_include sash_2
28
26
  end
29
-
30
27
  end
@@ -0,0 +1,104 @@
1
+ require 'test_helper'
2
+
3
+ class SashTest < ActiveSupport::TestCase
4
+ before do
5
+ @custom_category = 'custom_category'
6
+ @sash = Merit::Sash.create
7
+ end
8
+
9
+ describe "#add_points" do
10
+ describe "when category specified" do
11
+ it "should create a new Point with specified category" do
12
+ @sash.add_points 5, category: @custom_category
13
+ score = Merit::Score.last
14
+ point = score.score_points.last
15
+
16
+ assert_equal point.num_points, 5
17
+ assert_equal score.category, @custom_category
18
+ end
19
+ end
20
+
21
+ it "should create a new Point in category default with specified number of points" do
22
+ assert_difference("Merit::Score::Point.count", 1) do
23
+ @sash.add_points 5
24
+ end
25
+ score = Merit::Score.last
26
+ point = score.score_points.last
27
+
28
+ assert_equal point.num_points, 5
29
+ assert_equal score.category, 'default'
30
+ end
31
+ end
32
+
33
+ describe "#subtract_points" do
34
+ describe "when category specified" do
35
+ it "should create a new Point with specified category" do
36
+ @sash.subtract_points 5, category: @custom_category
37
+ score = Merit::Score.last
38
+ point = score.score_points.last
39
+
40
+ assert_equal point.num_points, -5
41
+ assert_equal score.category, @custom_category
42
+ end
43
+ end
44
+
45
+ it "should create a new Point in category default with inverse of specified number of points" do
46
+ assert_difference("Merit::Score::Point.count", 1) do
47
+ @sash.subtract_points 5
48
+ end
49
+ score = Merit::Score.last
50
+ point = score.score_points.last
51
+
52
+ assert_equal point.num_points, -5
53
+ assert_equal score.category, 'default'
54
+ end
55
+ end
56
+
57
+ describe "#points" do
58
+ before do
59
+ @sash.add_points 5, category: @custom_category
60
+ @sash.add_points 7
61
+ end
62
+
63
+ describe "when category specified" do
64
+ it "should retrieve the number of points of the category" do
65
+ assert_equal 5, @sash.points(category: @custom_category)
66
+ end
67
+ end
68
+
69
+ it "should retrieve the sum of points of all categories" do
70
+ assert_equal 12, @sash.points
71
+ end
72
+ end
73
+
74
+ describe "#score_points" do
75
+ before do
76
+ @point1 = @sash.add_points 5, category: @custom_category
77
+ @point2 = @sash.add_points 7
78
+ end
79
+
80
+ describe "when category specified" do
81
+ it "should return the points of the category" do
82
+ assert_equal 1, @sash.score_points(category: @custom_category).size
83
+ scores = @sash.score_points(category: @custom_category)
84
+ assert scores.include? @point1
85
+ assert !scores.include?(@point2)
86
+ end
87
+
88
+ it "should return no Points if category doesn't exist" do
89
+ assert_equal 0, @sash.score_points(category: 'non-existing').size
90
+ end
91
+ end
92
+
93
+ it "should return all points" do
94
+ assert_equal 2, @sash.score_points.size
95
+ assert @sash.score_points.include? @point1
96
+ assert @sash.score_points.include? @point2
97
+ end
98
+
99
+ it "should return no Points if no points found" do
100
+ @sash1 = Merit::Sash.create
101
+ assert_equal 0, @sash1.score_points.size
102
+ end
103
+ end
104
+ end
@@ -1,7 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
3
  describe Merit::TargetFinder do
4
-
5
4
  describe '#find' do
6
5
  describe 'rule#to is :itself' do
7
6
  it 'should return the base target' do
@@ -11,9 +10,10 @@ describe Merit::TargetFinder do
11
10
 
12
11
  comment = Comment.new
13
12
 
14
- Merit::BaseTargetFinder.
15
- stubs(:find).with(rule, action).
16
- returns(comment)
13
+ Merit::BaseTargetFinder
14
+ .stubs(:find)
15
+ .with(rule, action)
16
+ .returns(comment)
17
17
 
18
18
  finder = Merit::TargetFinder.new(rule, action)
19
19
  collection = finder.find
@@ -94,5 +94,4 @@ describe Merit::TargetFinder do
94
94
  end
95
95
  end
96
96
  end
97
-
98
97
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: merit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tute Costa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-17 00:00:00.000000000 Z
11
+ date: 2014-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ambry
@@ -152,8 +152,8 @@ files:
152
152
  - lib/merit/models/active_record/merit/badges_sash.rb
153
153
  - lib/merit/models/active_record/merit/sash.rb
154
154
  - lib/merit/models/active_record/merit/score.rb
155
- - lib/merit/models/base/merit/badges_sash.rb
156
- - lib/merit/models/base/merit/sash.rb
155
+ - lib/merit/models/base/badges_sash.rb
156
+ - lib/merit/models/base/sash.rb
157
157
  - lib/merit/models/mongoid/merit/action.rb
158
158
  - lib/merit/models/mongoid/merit/activity_log.rb
159
159
  - lib/merit/models/mongoid/merit/badges_sash.rb
@@ -246,6 +246,7 @@ files:
246
246
  - test/unit/rule_unit_test.rb
247
247
  - test/unit/rules_matcher_test.rb
248
248
  - test/unit/sash_finder_test.rb
249
+ - test/unit/sash_test.rb
249
250
  - test/unit/target_finder_test.rb
250
251
  homepage: http://github.com/tute/merit
251
252
  licenses:
@@ -1,45 +0,0 @@
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
- if log != 'Manually granted'
19
- warn '[merit] [DEPRECATION] `add_points` `log` parameter is deprecated'
20
- end
21
- point = Merit::Score::Point.new
22
- point.log = log
23
- point.num_points = num_points
24
- scores.where(category: category).first.score_points << point
25
- point
26
- end
27
-
28
- # DEPRECATED: Please use <tt>subtract_points</tt> instead.
29
- def substract_points(num_points, log = 'Manually granted', category = 'default')
30
- warn '[merit] [DEPRECATION] `substract_points` is deprecated. Please use `subtract_points` instead.'
31
- subtract_points num_points, log, category
32
- end
33
-
34
- def subtract_points(num_points, log = 'Manually granted', category = 'default')
35
- add_points(-num_points, log, category)
36
- end
37
-
38
- private
39
-
40
- def create_scores
41
- scores << Merit::Score.create
42
- end
43
- end
44
- end
45
- end