merit 0.10.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- merit (0.10.1)
4
+ merit (1.0.0)
5
5
  ambry (~> 0.3.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -23,7 +23,7 @@ NOTE: Mongoid support is experimental.
23
23
 
24
24
  You may give badges to any resource on your application if some condition
25
25
  holds. Badges may have levels, and may be temporary. Define rules on
26
- `app/models/merit_badge_rules.rb`:
26
+ `app/models/merit/badge_rules.rb`:
27
27
 
28
28
  `grant_on` accepts:
29
29
 
@@ -64,6 +64,12 @@ You may also grant badges "by hand" (optionally multiple times):
64
64
  Badge.find(3).grant_to(current_user, :allow_multiple => true)
65
65
  ```
66
66
 
67
+ Similarly you can take back badges that have been granted:
68
+
69
+ ```ruby
70
+ Badge.find(3).delete_from(current_user)
71
+ ```
72
+
67
73
  ---
68
74
 
69
75
  # Defining point rules
@@ -71,7 +77,7 @@ Badge.find(3).grant_to(current_user, :allow_multiple => true)
71
77
  Points are a simple integer value which are given to "meritable" resources.
72
78
  They are given on actions-triggered, either to the action user or to the
73
79
  method(s) defined in the `:to` option. Define rules on
74
- `app/models/merit_point_rules.rb`:
80
+ `app/models/merit/point_rules.rb`:
75
81
 
76
82
  ## Examples
77
83
 
@@ -99,7 +105,7 @@ score 15, :on => 'reviews#create', :to => [:reviewer, :reviewed]
99
105
  5 stars is a common ranking use case. They are not given at specified actions
100
106
  like badges, you should define a cron job to test if ranks are to be granted.
101
107
 
102
- Define rules on `app/models/merit_rank_rules.rb`:
108
+ Define rules on `app/models/merit/rank_rules.rb`:
103
109
 
104
110
  `set_rank` accepts:
105
111
 
@@ -134,20 +140,10 @@ end
134
140
 
135
141
  # To-do list
136
142
 
137
- * add an error handler for inexistent badges.
143
+ * target_object should be configurable (now it's singularized controller name)
144
+ * Translate comments from spanish in `rules_badge.rb`.
138
145
  * Should namespace app/models into Merit module.
139
- * rescue ActiveRecord::... should depend on ORM used
140
146
  * :value parameter (for star voting for example) should be configurable
141
147
  (depends on params[:value] on the controller).
142
148
  * Make fixtures for integration testing (now creating objects on test file!).
143
149
  * Rules should be cached? Calling *Rules.new more than once
144
- * Add badges_sashes timestamps
145
-
146
- ---
147
-
148
- # Contributors
149
-
150
- * [Tute Costa](https://github.com/tute)
151
- * [Juan Schwindt](https://github.com/jschwindt)
152
- * [Eric Knudtson](https://github.com/ek) ([Chef Surfing](https://chefsurfing.com/))
153
- * [A4bandas media](https://github.com/a4bandas)
@@ -12,5 +12,5 @@ rails server
12
12
 
13
13
  # or run tests
14
14
  cd ../..
15
- rake test
15
+ rake
16
16
  ORM=mongoid rake test
@@ -1,5 +1,49 @@
1
1
  # Upgrading
2
2
 
3
+ ## to 1.0.0
4
+
5
+ Points granting history is now logged.
6
+
7
+ * Attribute `points` and method `points=` don't exist anymore (method `points`
8
+ still works for querying number of points for a resource).
9
+ * There are new methods `add_points(num_points, log_message)` and
10
+ `remove_points(num_points, log_message)` in meritable resources to manually
11
+ change their amount of points, keeping a history log.
12
+
13
+ Run the following migration to have the new DB tables:
14
+
15
+ class UpgradeMerit < ActiveRecord::Migration
16
+ def self.up
17
+ create_table :merit_scores do |t|
18
+ t.references :sash
19
+ t.string :category, :default => 'default'
20
+ end
21
+
22
+ create_table :merit_score_points do |t|
23
+ t.references :score
24
+ t.integer :num_points, :default => 0
25
+ t.string :log
26
+ end
27
+ end
28
+
29
+ def self.down
30
+ drop_table :merit_scores
31
+ drop_table :merit_score_points
32
+ end
33
+ end
34
+
35
+ # This will create a single point entry log, with previous points granted
36
+ # to each meritable resource. Code example for a User class.
37
+ class UpgradeMeritableResources < ActiveRecord::Migration
38
+ def up
39
+ User.find_each do |user|
40
+ user.sash.scores << Merit::Score.create
41
+ user.add_points(user.points, 'Initial merit points import.')
42
+ end
43
+ remove_column :users, :points
44
+ end
45
+ end
46
+
3
47
  ## to 0.10.0
4
48
 
5
49
  `badges_sashes` table gets a primary key `id` column. Run the following migration:
@@ -26,29 +26,34 @@ class Badge
26
26
  # Grant badge to sash
27
27
  # Accepts :allow_multiple boolean option, defaults to false
28
28
  def grant_to(object_or_sash, *args)
29
- object_or_sash.create_sash_if_none unless object_or_sash.kind_of?(Sash)
30
- sash = object_or_sash.respond_to?(:sash) ? object_or_sash.sash : object_or_sash
31
-
32
29
  options = args.extract_options!
33
30
  options[:allow_multiple] ||= false
31
+ sash = sash_from(object_or_sash)
34
32
 
35
33
  if !sash.badge_ids.include?(id) || options[:allow_multiple]
36
34
  sash.add_badge(id)
37
- return true
35
+ true
38
36
  else
39
- return false
37
+ false
40
38
  end
41
39
  end
42
40
 
43
41
  # Take out badge from sash
44
42
  def delete_from(object_or_sash)
45
- object_or_sash.create_sash_if_none unless object_or_sash.kind_of?(Sash)
46
- sash = object_or_sash.respond_to?(:sash) ? object_or_sash.sash : object_or_sash
43
+ sash = sash_from(object_or_sash)
47
44
  if sash.badge_ids.include?(id)
48
45
  sash.rm_badge(id)
49
- return true
46
+ true
47
+ else
48
+ false
49
+ end
50
+ end
51
+
52
+ def sash_from(object_or_sash)
53
+ if object_or_sash.kind_of?(Sash)
54
+ object_or_sash
50
55
  else
51
- return false
56
+ object_or_sash.sash || object_or_sash.create_sash_and_scores
52
57
  end
53
58
  end
54
59
  end
@@ -1,7 +1,8 @@
1
1
  require "merit/models/#{Merit.orm}/merit_action"
2
2
 
3
3
  class MeritAction
4
- attr_accessible :user_id, :action_method, :action_value, :had_errors, :target_model, :target_id, :processed, :log
4
+ attr_accessible :user_id, :action_method, :action_value, :had_errors,
5
+ :target_model, :target_id, :processed, :log
5
6
 
6
7
  # Check rules defined for a merit_action
7
8
  def check_rules
@@ -13,38 +14,44 @@ class MeritAction
13
14
  end
14
15
 
15
16
  def check_badge_rules
16
- defined_rules = Merit::BadgeRules.new.defined_rules["#{target_model}\##{action_method}"]
17
- return if defined_rules.nil?
18
-
19
- defined_rules.each do |rule|
20
- rule.grant_or_delete_badge(self)
21
- end
17
+ return if badge_rules.nil?
18
+ badge_rules.each { |rule| rule.grant_or_delete_badge(self) }
22
19
  end
23
20
 
24
21
  def check_point_rules
25
- actions_to_point = Merit::PointRules.new.actions_to_point["#{target_model}\##{action_method}"]
26
- return if actions_to_point.nil?
22
+ return if point_rules.nil?
23
+ point_rules.each { |rule| rule.grant_points(self) }
24
+ end
25
+
26
+ def badge_rules
27
+ @badge_rules ||= Merit::BadgeRules.new.defined_rules[action_str] || []
28
+ end
29
+ def point_rules
30
+ @point_rules ||= Merit::PointRules.new.actions_to_point[action_str] || []
31
+ end
32
+ def action_str
33
+ "#{target_model}\##{action_method}"
34
+ end
35
+
36
+ def target(to)
37
+ @target ||= (to == :action_user) ? action_user : other_target(to)
38
+ end
39
+
40
+ def action_user
41
+ begin
42
+ Merit.user_model.find(user_id)
43
+ rescue ActiveRecord::RecordNotFound
44
+ Rails.logger.warn "[merit] no #{Merit.user_model} found with id #{user_id}"
45
+ return
46
+ end
47
+ end
27
48
 
28
- actions_to_point.each do |point_rule|
29
- point_rule[:to].each do |to|
30
- if to == :action_user
31
- target = Merit.user_model.find_by_id(user_id)
32
- if target.nil?
33
- Rails.logger.warn "[merit] no user found to grant points"
34
- return
35
- end
36
- else
37
- begin
38
- target = target_object.send(to)
39
- rescue NoMethodError
40
- Rails.logger.warn "[merit] No target_object found on check_rules."
41
- return
42
- end
43
- end
44
- target.points += point_rule[:score]
45
- target.save
46
- log!("points_granted:#{point_rule[:score]}")
47
- end
49
+ def other_target(to)
50
+ begin
51
+ target_object.send(to)
52
+ rescue NoMethodError
53
+ Rails.logger.warn "[merit] NoMethodError on '#{target_object.inspect}.#{to}' (called from MeritAction#other_target)"
54
+ return
48
55
  end
49
56
  end
50
57
 
@@ -20,6 +20,7 @@ module ActiveRecord
20
20
  migration_template 'create_merit_actions.rb', 'db/migrate/create_merit_actions.rb'
21
21
  migration_template 'create_sashes.rb', 'db/migrate/create_sashes.rb'
22
22
  migration_template 'create_badges_sashes.rb', 'db/migrate/create_badges_sashes.rb'
23
+ migration_template 'create_scores_and_points.rb', 'db/migrate/create_scores_and_points.rb'
23
24
  end
24
25
  end
25
26
  end
@@ -1,15 +1,12 @@
1
1
  class AddFieldsTo<%= table_name.camelize %> < ActiveRecord::Migration
2
2
  def self.up
3
3
  add_column :<%= table_name %>, :sash_id, :integer
4
- add_column :<%= table_name %>, :points, :integer, :default => 0
5
4
  add_column :<%= table_name %>, :level, :integer, :default => 0
6
5
  <%- resource = table_name.singularize -%>
7
- <%= resource.camelize %>.all.each{|<%= resource %>| <%= resource %>.update_attribute(:points, 0) } # Update existing entries
8
6
  end
9
7
 
10
8
  def self.down
11
9
  remove_column :<%= table_name %>, :sash_id
12
- remove_column :<%= table_name %>, :points
13
10
  remove_column :<%= table_name %>, :level
14
11
  end
15
- end
12
+ end
@@ -16,4 +16,4 @@ class CreateMeritActions < ActiveRecord::Migration
16
16
  def self.down
17
17
  drop_table :merit_actions
18
18
  end
19
- end
19
+ end
@@ -8,4 +8,4 @@ class CreateSashes < ActiveRecord::Migration
8
8
  def self.down
9
9
  drop_table :sashes
10
10
  end
11
- end
11
+ end
@@ -0,0 +1,19 @@
1
+ class CreateScoresAndPoints < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :merit_scores do |t|
4
+ t.references :sash
5
+ t.string :category, :default => 'default'
6
+ end
7
+
8
+ create_table :merit_score_points do |t|
9
+ t.references :score
10
+ t.integer :num_points, :default => 0
11
+ t.string :log
12
+ end
13
+ end
14
+
15
+ def self.down
16
+ drop_table :merit_scores
17
+ drop_table :merit_score_points
18
+ end
19
+ end
@@ -33,15 +33,18 @@ module Merit
33
33
  yield self
34
34
  end
35
35
 
36
+ class BadgeNotFound < Exception; end
37
+
36
38
  class Engine < Rails::Engine
37
39
  config.app_generators.orm Merit.orm
38
40
 
39
41
  initializer 'merit.controller' do |app|
40
42
  if Merit.orm == :active_record
41
- require "merit/models/#{Merit.orm}/sash"
42
- require "merit/models/#{Merit.orm}/badges_sash"
43
+ require 'merit/models/active_record/sash'
44
+ require 'merit/models/active_record/badges_sash'
45
+ require 'merit/models/active_record/merit/score'
43
46
  elsif Merit.orm == :mongoid
44
- require "merit/models/#{Merit.orm}/sash"
47
+ require "merit/models/mongoid/sash"
45
48
  end
46
49
 
47
50
  ActiveSupport.on_load(:action_controller) do
@@ -9,21 +9,11 @@ module Merit
9
9
  badge_rules = BadgeRules.new
10
10
  point_rules = PointRules.new
11
11
  if badge_rules.defined_rules[action].present? || point_rules.actions_to_point[action].present?
12
- # TODO: target_object should be configurable (now it's singularized controller name)
13
- target_object = instance_variable_get(:"@#{controller_name.singularize}")
14
- # Set target_id from params or from current instance variable
15
- target_id = params[:id] || target_object.try(:id)
16
- # id nil, or string (friendly_id); target_object found
17
- if target_object.present? && (target_id.nil? || !(target_id =~ /^[0-9]+$/))
18
- target_id = target_object.id
19
- end
20
-
21
- # TODO: value should be configurable (now it's params[:value] set in the controller)
22
12
  merit_action_id = MeritAction.create(
23
13
  :user_id => send(Merit.current_user_method).try(:id),
24
14
  :action_method => action_name,
25
15
  :action_value => params[:value],
26
- :had_errors => target_object.try(:errors).try(:present?),
16
+ :had_errors => target_object.try(:errors).try(:present?) || false,
27
17
  :target_model => controller_name,
28
18
  :target_id => target_id
29
19
  ).id
@@ -31,19 +21,26 @@ module Merit
31
21
  # Check rules in after_filter?
32
22
  if Merit.checks_on_each_request
33
23
  badge_rules.check_new_actions
34
-
35
- # Show flash msg?
36
- if (log = MeritAction.find(merit_action_id).log)
37
- # Badges granted to current_user
38
- granted = log.split('|').select{|log| log =~ /badge_granted_to_action_user/ }
39
- granted.each do |badge|
40
- badge_id = badge.split(':').last.to_i
41
- flash[:merit] = t('merit.flashs.badge_granted', :badge => t("badges.#{Badge.find(badge_id).name}.name"))
42
- end
43
- end
44
24
  end
45
25
  end
46
26
  end
47
27
  end
28
+
29
+ def target_object
30
+ target_obj = instance_variable_get(:"@#{controller_name.singularize}")
31
+ if target_obj.nil?
32
+ Rails.logger.warn("[merit] No object found, maybe you need a '@#{controller_name.singularize}' variable in '#{controller_name}_controller'?")
33
+ end
34
+ target_obj
35
+ end
36
+
37
+ def target_id
38
+ target_id = params[:id] || target_object.try(:id)
39
+ # using friendly_id if id nil or string (), and target_object found
40
+ if target_object.present? && (target_id.nil? || !(target_id =~ /^[0-9]+$/))
41
+ target_id = target_object.id
42
+ end
43
+ target_id
44
+ end
48
45
  end
49
46
  end
@@ -17,25 +17,38 @@ module Merit
17
17
  field :sash_id
18
18
  field :points, :type => Integer, :default => 0
19
19
  field :level, :type => Integer, :default => 0
20
+ def find_by_id(id)
21
+ where(:_id => id).first
22
+ end
20
23
  end
21
24
  end
25
+ end
22
26
 
23
- def find_by_id(id)
24
- Merit.orm == :mongoid ? where(:_id => id).first : super(id)
27
+ # Delegate relationship methods from meritable models to their sash
28
+ %w(badge_ids badges points).each do |method|
29
+ define_method(method) do
30
+ _sash = sash || create_sash_and_scores
31
+ _sash.send method
25
32
  end
26
33
  end
27
34
 
28
- def badges
29
- create_sash_if_none
30
- sash.badges
35
+ def add_points(num_points, log = 'Manually granted through `add_points`', category = 'default')
36
+ _sash = sash || create_sash_and_scores
37
+ _sash.add_points num_points, log, category
38
+ end
39
+ def substract_points(num_points, log = 'Manually granted through `add_points`', category = 'default')
40
+ _sash = sash || create_sash_and_scores
41
+ _sash.substract_points num_points, log, category
31
42
  end
32
43
 
33
44
  # Create sash if doesn't have
34
- def create_sash_if_none
45
+ def create_sash_and_scores
35
46
  if self.sash.blank?
36
47
  self.sash = Sash.create
48
+ self.sash.scores << Merit::Score.create
37
49
  self.save(:validate => false)
38
50
  end
51
+ self.sash
39
52
  end
40
53
  end
41
54
 
@@ -0,0 +1,16 @@
1
+ module Merit
2
+ class Score < ActiveRecord::Base
3
+ self.table_name = :merit_scores
4
+ belongs_to :sash
5
+ has_many :score_points, :dependent => :destroy, :class_name => 'Merit::Score::Point'
6
+
7
+ def points
8
+ score_points.group(:score_id).sum(:num_points).values.first || 0
9
+ end
10
+
11
+ class Point < ActiveRecord::Base
12
+ self.table_name = :merit_score_points
13
+ belongs_to :score, :class_name => 'Merit::Score'
14
+ end
15
+ end
16
+ end
@@ -1,21 +1,36 @@
1
1
  class Sash < ActiveRecord::Base
2
2
  has_many :badges_sashes, :dependent => :destroy
3
+ has_many :scores, :dependent => :destroy, :class_name => 'Merit::Score'
3
4
 
4
5
  def badges
5
6
  badge_ids.collect { |b_id| Badge.find(b_id) }
6
7
  end
7
8
 
8
9
  def badge_ids
9
- badges_sashes.collect(&:badge_id)
10
+ badges_sashes.map(&:badge_id)
10
11
  end
11
12
 
12
13
  def add_badge(badge_id)
13
14
  bs = BadgesSash.new
14
15
  bs.badge_id = badge_id
15
- badges_sashes << bs
16
+ self.badges_sashes << bs
16
17
  end
17
18
 
18
19
  def rm_badge(badge_id)
19
20
  badges_sashes.find_by_badge_id(badge_id).try(:destroy)
20
21
  end
22
+
23
+ def points(category = 'default')
24
+ scores.where(:category => category).first.points
25
+ end
26
+
27
+ def add_points(num_points, log = 'Manually granted through `add_points`', category = 'default')
28
+ point = Merit::Score::Point.new
29
+ point.log = log
30
+ point.num_points = num_points
31
+ self.scores.where(:category => category).first.score_points << point
32
+ end
33
+ def substract_points(num_points, log = 'Manually granted through `add_points`', category = 'default')
34
+ add_points -num_points, log, category
35
+ end
21
36
  end
@@ -3,7 +3,8 @@ module Merit
3
3
  # and a temporary option.
4
4
  # Could split this class between badges and rankings functionality
5
5
  class Rule
6
- attr_accessor :badge_name, :level, :to, :multiple, :temporary, :block, :model_name, :level_name
6
+ attr_accessor :badge_name, :level, :to, :model_name, :level_name,
7
+ :multiple, :temporary, :score, :block
7
8
 
8
9
  # Does this rule's condition block apply?
9
10
  def applies?(target_obj = nil)
@@ -12,13 +13,14 @@ module Merit
12
13
  case block.arity
13
14
  when 1 # Expects target object
14
15
  if target_obj.present?
15
- return block.call(target_obj)
16
+ block.call(target_obj)
16
17
  else
18
+ # TODO RAISE ERROR
17
19
  Rails.logger.warn "[merit] no target_obj found on Rule#applies?"
18
- return false
20
+ false
19
21
  end
20
22
  else # evaluates to boolean. block.arity returns 0 in Ruby 1.9.3 and -1 in Ruby 1.8.7
21
- return block.call
23
+ block.call
22
24
  end
23
25
  end
24
26
 
@@ -28,7 +30,7 @@ module Merit
28
30
  # then remove it.
29
31
  def grant_or_delete_badge(action)
30
32
  unless (sash = sash_to_badge(action))
31
- Rails.logger.warn "[merit] no sash found on Rule#grant_or_delete_badge"
33
+ Rails.logger.warn "[merit] no sash found on Rule#grant_or_delete_badge for action #{action.inspect}"
32
34
  return
33
35
  end
34
36
 
@@ -44,24 +46,30 @@ module Merit
44
46
  end
45
47
  end
46
48
 
49
+ def grant_points(action)
50
+ unless (sash = sash_to_badge(action))
51
+ Rails.logger.warn "[merit] no sash found on Rule#grant_points"
52
+ return
53
+ end
54
+
55
+ if applies? action.target_object(model_name)
56
+ sash.add_points self.score, action.inspect[0..240]
57
+ action.log!("points_granted:#{self.score}")
58
+ end
59
+ end
60
+
47
61
  # Subject to badge: source_user or target.user?
62
+ # Knows (law of demeter):
63
+ # * Rule#model_name & Rule#to
64
+ # * MeritAction#object & MeritAction#target_object
48
65
  def sash_to_badge(action)
49
- target = case to
50
- when :action_user
51
- Merit.user_model.find_by_id(action.user_id) # _by_id doens't raise ActiveRecord::RecordNotFound
52
- when :itself
53
- action.target_object(model_name)
54
- else
55
- begin
56
- action.target_object(model_name).send(to)
57
- rescue NoMethodError
58
- Rails.logger.warn "[merit] #{action.target_model.singularize.camelize}.find(#{action.target_id}) not found, no badges giving today"
59
- return
60
- end
61
- end
66
+ if to == :itself
67
+ target = action.target_object(model_name)
68
+ else
69
+ target = action.target(to)
70
+ end
62
71
  if target
63
- target.create_sash_if_none
64
- target.sash
72
+ target.sash || target.create_sash_and_scores
65
73
  end
66
74
  end
67
75
 
@@ -71,7 +79,7 @@ module Merit
71
79
  badges = Badge.by_name(badge_name)
72
80
  badges = badges.by_level(level) unless level.nil?
73
81
  if !(@badge = badges.first)
74
- raise "No badge '#{badge_name}'#{level.nil? ? '' : " with level #level"} found. Define it in 'config/initializers/merit.rb'."
82
+ raise BadgeNotFound, "No badge '#{badge_name}'#{level.nil? ? '' : " with level #level"} found. Define it in 'config/initializers/merit.rb'."
75
83
  end
76
84
  end
77
85
  @badge
@@ -9,12 +9,17 @@ module Merit
9
9
  options[:to] ||= [:action_user]
10
10
 
11
11
  actions = Array.wrap(options[:on])
12
- actions.each do |action|
13
- actions_to_point[action] ||= []
14
- actions_to_point[action] << {
15
- :score => points,
16
- :to => Array.wrap(options[:to])
17
- }
12
+
13
+ Array.wrap(options[:to]).each do |to|
14
+ rule = Rule.new
15
+ rule.score = points
16
+ rule.to = to
17
+ rule.block = block
18
+
19
+ actions.each do |action|
20
+ actions_to_point[action] ||= []
21
+ actions_to_point[action] << rule
22
+ end
18
23
  end
19
24
  end
20
25
 
@@ -4,7 +4,7 @@ Gem::Specification.new do |s|
4
4
  s.description = "Manage badges, points and rankings (reputation) of resources in a Rails application."
5
5
  s.homepage = "http://github.com/tute/merit"
6
6
  s.files = `git ls-files`.split("\n").reject{|f| f =~ /^\./ }
7
- s.version = '0.10.1'
7
+ s.version = '1.0.0'
8
8
  s.authors = ["Tute Costa"]
9
9
  s.email = 'tutecosta@gmail.com'
10
10
  s.add_dependency 'ambry', '~> 0.3.0'
@@ -11,8 +11,7 @@ class User
11
11
  attr_accessible :name
12
12
 
13
13
  def show_badges
14
- create_sash_if_none
15
- badges_uniq = Badge.find_by_id(sash.badge_ids)
14
+ badges_uniq = Badge.find_by_id(badge_ids)
16
15
  badges_uniq.collect{|b| "#{b.name.capitalize}#{badge_status(b)}" }.join(', ')
17
16
  end
18
17
 
@@ -15,7 +15,13 @@ module Merit
15
15
  score 20, :on => [
16
16
  'comments#create',
17
17
  'registrations#update'
18
- ]
18
+ ] do |object|
19
+ if object.class == Comment
20
+ object.name.length > 4
21
+ else
22
+ true
23
+ end
24
+ end
19
25
  end
20
26
  end
21
27
  end
@@ -6,8 +6,7 @@ class User < ActiveRecord::Base
6
6
  attr_accessible :name
7
7
 
8
8
  def show_badges
9
- create_sash_if_none
10
- badges_uniq = Badge.find_by_id(sash.badge_ids)
9
+ badges_uniq = Badge.find_by_id(badge_ids)
11
10
  badges_uniq.collect{|b| "#{b.name.capitalize}#{badge_status(b)}" }.join(', ')
12
11
  end
13
12
 
@@ -8,4 +8,4 @@ class CreateSashes < ActiveRecord::Migration
8
8
  def self.down
9
9
  drop_table :sashes
10
10
  end
11
- end
11
+ end
@@ -1,14 +1,11 @@
1
1
  class AddFieldsToUsers < ActiveRecord::Migration
2
2
  def self.up
3
3
  add_column :users, :sash_id, :integer
4
- add_column :users, :points, :integer, :default => 0
5
4
  add_column :users, :level, :integer, :default => 0
6
- User.all.each{|user| user.update_attribute(:points, 0) } # Update existing entries
7
5
  end
8
6
 
9
7
  def self.down
10
8
  remove_column :users, :sash_id
11
- remove_column :users, :points
12
9
  remove_column :users, :level
13
10
  end
14
- end
11
+ end
@@ -0,0 +1,19 @@
1
+ class CreateScoresAndPoints < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :merit_scores do |t|
4
+ t.references :sash
5
+ t.string :category, :default => 'default'
6
+ end
7
+
8
+ create_table :merit_score_points do |t|
9
+ t.references :score
10
+ t.integer :num_points, :default => 0
11
+ t.string :log
12
+ end
13
+ end
14
+
15
+ def self.down
16
+ drop_table :merit_scores
17
+ drop_table :merit_score_points
18
+ end
19
+ end
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # It's strongly recommended to check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(:version => 20120318022220) do
14
+ ActiveRecord::Schema.define(:version => 20121013174256) do
15
15
 
16
16
  create_table "badges_sashes", :force => true do |t|
17
17
  t.integer "badge_id"
@@ -46,6 +46,17 @@ ActiveRecord::Schema.define(:version => 20120318022220) do
46
46
  t.datetime "updated_at", :null => false
47
47
  end
48
48
 
49
+ create_table "merit_score_points", :force => true do |t|
50
+ t.integer "score_id"
51
+ t.integer "num_points", :default => 0
52
+ t.string "log"
53
+ end
54
+
55
+ create_table "merit_scores", :force => true do |t|
56
+ t.integer "sash_id"
57
+ t.string "category", :default => "default"
58
+ end
59
+
49
60
  create_table "sashes", :force => true do |t|
50
61
  t.datetime "created_at", :null => false
51
62
  t.datetime "updated_at", :null => false
@@ -56,7 +67,6 @@ ActiveRecord::Schema.define(:version => 20120318022220) do
56
67
  t.datetime "created_at", :null => false
57
68
  t.datetime "updated_at", :null => false
58
69
  t.integer "sash_id"
59
- t.integer "points", :default => 0
60
70
  t.integer "level", :default => 0
61
71
  end
62
72
 
@@ -32,6 +32,14 @@ class NavigationTest < ActiveSupport::IntegrationCase
32
32
  end
33
33
  assert user.badges.empty?, 'Should not have badges'
34
34
 
35
+ assert_equal 0, user.points
36
+ assert_equal 0, Merit::Score::Point.count
37
+ user.add_points 15
38
+ assert_equal 15, user.points
39
+ user.substract_points 15
40
+ assert_equal 0, user.points
41
+ assert_equal 2, Merit::Score::Point.count
42
+
35
43
  # Make tenth comment, assert 10-commenter badge granted
36
44
  visit '/comments/new'
37
45
  fill_in 'Name', :with => 'Hi!'
@@ -100,7 +108,16 @@ class NavigationTest < ActiveSupport::IntegrationCase
100
108
  click_button('Create Comment')
101
109
 
102
110
  user = User.where(:name => 'a').first
103
- assert_equal 40, user.points, 'Commenting should grant 20 points'
111
+ assert_equal 20, user.points, 'Commenting should not grant 20 points if name.length <= 4'
112
+
113
+ visit '/comments/new'
114
+ fill_in 'Name', :with => 'Hi there!'
115
+ fill_in 'Comment', :with => 'Hi bro!'
116
+ fill_in 'User', :with => user.id
117
+ click_button('Create Comment')
118
+
119
+ user = User.where(:name => 'a').first
120
+ assert_equal 40, user.points, 'Commenting should grant 20 points if name.length > 4'
104
121
 
105
122
  visit "/comments/#{Comment.last.id}/vote/4"
106
123
  user = User.first
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class MeritUnitTest < ActiveSupport::TestCase
4
- test "Rule applies?" do
4
+ test "Rule#applies? should depend on provided block" do
5
5
  rule = Merit::Rule.new
6
6
  assert rule.applies?, 'empty conditions should make rule apply'
7
7
 
@@ -11,27 +11,41 @@ class MeritUnitTest < ActiveSupport::TestCase
11
11
 
12
12
  rule.block = lambda{|obj| obj.length >= 4 }
13
13
  assert rule.applies?(str), 'block should make rule apply'
14
+
15
+ rule.block = lambda{|obj| true }
16
+ assert !rule.applies?, 'block which expects object should return false if no argument'
14
17
  end
15
18
 
16
- test "BadgeSash knows it's related badge" do
17
- # No BadgeSash model for Mongoid
18
- return if ENV["ORM"] == "mongoid"
19
+ test "Rule#badge should get related badge or raise Merit exception" do
20
+ rule = Merit::Rule.new
21
+ rule.badge_name = 'inexistent'
22
+ assert_raise Merit::BadgeNotFound do
23
+ rule.badge
24
+ end
19
25
 
20
- Badge.create(:id => 99, :name => 'test-badge')
21
- badge_sash = BadgesSash.new
22
- badge_sash.badge_id = 99
23
- assert_equal Badge.find(99), badge_sash.badge
26
+ badge = Badge.create(:id => 98, :name => 'test-badge-98')
27
+ rule.badge_name = badge.name
28
+ assert_equal Badge.find(98), rule.badge
24
29
  end
25
30
 
31
+ # TODO: Test and refactor:
32
+ # Rule: grant_or_delete_badge(action), sash_to_badge
33
+ # Badge: delete_from
34
+ # MeritAction: target(to), action_user, other_target(to), target_object(model_name = nil)
35
+
36
+
26
37
  test "Badge#grant_to allow_multiple option" do
27
38
  badge = Badge.create(:id => 99, :name => 'test-badge')
28
39
  sash = Sash.create(:id => 99)
40
+
29
41
  assert_equal 0, sash.badge_ids.count
30
- badge.grant_to sash
31
- assert_equal 1, sash.reload.badge_ids.count
32
- badge.grant_to sash
33
- assert_equal 1, sash.reload.badge_ids.count
34
- badge.grant_to sash, :allow_multiple => true
35
- assert_equal 2, sash.reload.badge_ids.count
42
+
43
+ assert badge.grant_to(sash)
44
+ assert_equal 1, sash.badge_ids.count
45
+ assert !badge.grant_to(sash)
46
+ assert_equal 1, sash.badge_ids.count
47
+
48
+ assert badge.grant_to(sash, :allow_multiple => true)
49
+ assert_equal 2, sash.badge_ids.count
36
50
  end
37
51
  end
@@ -31,7 +31,6 @@ Capybara.default_driver = :rack_test
31
31
  Capybara.default_selector = :css
32
32
 
33
33
  if ENV["ORM"] == "mongoid"
34
- puts 'Testing with ORM Mongoid'
35
34
  class ActiveSupport::TestCase
36
35
  def teardown
37
36
  Mongoid.database.collections.each do |collection|
@@ -39,8 +38,7 @@ if ENV["ORM"] == "mongoid"
39
38
  end
40
39
  end
41
40
  end
42
- else
43
- puts 'Testing with ORM ActiveRecord'
41
+ else # ActiveRecord
44
42
  # Run any available migration
45
43
  ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
46
44
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: merit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-07 00:00:00.000000000 Z
12
+ date: 2012-10-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ambry
@@ -155,13 +155,13 @@ files:
155
155
  - UPGRADING.md
156
156
  - app/models/badge.rb
157
157
  - app/models/merit_action.rb
158
- - config/locales/en.yml
159
158
  - lib/generators/active_record/install_generator.rb
160
159
  - lib/generators/active_record/merit_generator.rb
161
160
  - lib/generators/active_record/templates/add_fields_to_model.rb
162
161
  - lib/generators/active_record/templates/create_badges_sashes.rb
163
162
  - lib/generators/active_record/templates/create_merit_actions.rb
164
163
  - lib/generators/active_record/templates/create_sashes.rb
164
+ - lib/generators/active_record/templates/create_scores_and_points.rb
165
165
  - lib/generators/merit/install_generator.rb
166
166
  - lib/generators/merit/merit_generator.rb
167
167
  - lib/generators/merit/templates/merit.rb
@@ -172,6 +172,7 @@ files:
172
172
  - lib/merit/controller_extensions.rb
173
173
  - lib/merit/model_additions.rb
174
174
  - lib/merit/models/active_record/badges_sash.rb
175
+ - lib/merit/models/active_record/merit/score.rb
175
176
  - lib/merit/models/active_record/merit_action.rb
176
177
  - lib/merit/models/active_record/sash.rb
177
178
  - lib/merit/models/mongo_mapper/merit_action.rb
@@ -279,6 +280,7 @@ files:
279
280
  - test/dummy/db/migrate/20120318022218_create_sashes.rb
280
281
  - test/dummy/db/migrate/20120318022219_create_badges_sashes.rb
281
282
  - test/dummy/db/migrate/20120318022220_add_fields_to_users.rb
283
+ - test/dummy/db/migrate/20121013174256_create_scores_and_points.rb
282
284
  - test/dummy/db/schema.rb
283
285
  - test/dummy/db/seeds.rb
284
286
  - test/dummy/public/404.html
@@ -318,7 +320,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
318
320
  version: '0'
319
321
  requirements: []
320
322
  rubyforge_project:
321
- rubygems_version: 1.8.23
323
+ rubygems_version: 1.8.24
322
324
  signing_key:
323
325
  specification_version: 3
324
326
  summary: General reputation Rails engine.
@@ -1,4 +0,0 @@
1
- en:
2
- merit:
3
- flashs:
4
- badge_granted: "Congratulations! You've just earned '%{badge}' badge."