merit 1.9.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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