# Merit Gem: Reputation rules (badges, points and rankings) for Rails applications

![Merit](http://i567.photobucket.com/albums/ss118/DeuceBigglebags/th_nspot26_300.jpg)

[![Build Status](https://travis-ci.org/tute/merit.png?branch=master)](http://travis-ci.org/tute/merit)

# Installation

1. Add `gem 'merit'` to your `Gemfile`
2. Run `rails g merit:install`
3. Run `rails g merit MODEL_NAME` (e.g. `user`)
4. Run `rake db:migrate`
5. Define badges you will use in `config/initializers/merit.rb`
6. Configure reputation rules for your application in `app/models/merit/*`

---

# Defining badge rules

You may give badges to any resource on your application if some condition
holds. Badges may have levels, and may be temporary. Define rules on
`app/models/merit/badge_rules.rb`:

`grant_on` accepts:

* `'controller#action'` string (similar to Rails routes)
* `:badge` for badge name
* `:level` for badge level
* `:to` method name over target_object which obtains object to badge
* `:model_name` (string) define controller's name if it differs from
  the model (like `RegistrationsController` for `User` model).
* `:multiple` (boolean) badge may be granted multiple times
* `:temporary` (boolean) if the receiver had the badge but the condition
  doesn't hold anymore, remove it. `false` by default (badges are kept
  forever).
* `&block`
  * empty (always grants)
  * a block which evaluates to boolean (recieves target object as parameter)
  * a block with a hash composed of methods to run on the target object with
    expected values

## Examples

```ruby
# app/models/merit/badge_rules.rb
grant_on 'comments#vote', :badge => 'relevant-commenter', :to => :user do |comment|
  comment.votes.count == 5
end

grant_on ['users#create', 'users#update'], :badge => 'autobiographer', :temporary => true do |user|
  user.name.present? && user.address.present?
end
```

```ruby
# Check granted badges
current_user.badges # Returns an array of badges

# Grant or remove manually
current_user.add_badge(badge.id)
current_user.rm_badge(badge.id)
```

---

# Defining point rules

Points are given to "meritable" resources on actions-triggered, either to the
action user or to the method(s) defined in the `:to` option. Define rules on
`app/models/merit/point_rules.rb`:

`score` accepts:

* `:on` action as string or array of strings (similar to Rails routes)
* `:to` method(s) to send to the target_object (who should be scored?)
* `&block`
  * empty (always scores)
  * a block which evaluates to boolean (recieves target object as parameter)

## Examples

```ruby
# app/models/merit/point_rules.rb
score 10, :to => :post_creator, :on => 'comments#create' do |comment|
  comment.title.present?
end

score 20, :on => [
  'comments#create',
  'photos#create'
]

score 15, :on => 'reviews#create', :to => [:reviewer, :reviewed]
```

```ruby
# Check awarded points
current_user.points # Returns an integer

# Score manually
current_user.add_points(20, 'Optional log message')
current_user.substract_points(10)
```

---

# Defining rank rules

5 stars is a common ranking use case. They are not given at specified actions
like badges, you should define a cron job to test if ranks are to be granted.

Define rules on `app/models/merit/rank_rules.rb`:

`set_rank` accepts:

* `:level` ranking level (greater is better)
* `:to` model or scope to check if new rankings apply
* `:level_name` attribute name (default is empty and results in
  '`level`' attribute, if set it's appended like
  '`level_#{level_name}`')

Check for rules on a rake task executed in background like:

```ruby
task :cron => :environment do
  Merit::RankRules.new.check_rank_rules
end
```


## Examples

```ruby
set_rank :level => 2, :to => Commiter.active do |commiter|
  commiter.branches > 1 && commiter.followers >= 10
end

set_rank :level => 3, :to => Commiter.active do |commiter|
  commiter.branches > 2 && commiter.followers >= 20
end
```


# To-do list

* Improve model_additions with http://blog.8thlight.com/josh-cheek/2012/02/03/modules-called-they-want-their-integrity-back.html
* Should namespace Badge, BadgesSash and Sash into Merit module.