merit 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +5 -0
- data/Gemfile.lock +13 -2
- data/README.md +72 -53
- data/TESTING.txt +7 -2
- data/lib/generators/merit/templates/merit.rb +1 -1
- data/lib/merit.rb +2 -1
- data/lib/merit/controller_extensions.rb +2 -2
- data/lib/merit/model_additions.rb +9 -2
- data/lib/merit/models/mongo_mapper/merit_action.rb +1 -0
- data/lib/merit/models/mongoid/merit_action.rb +13 -0
- data/lib/merit/models/mongoid/sash.rb +14 -0
- data/lib/merit/rule.rb +4 -2
- data/lib/merit/rules_rank.rb +7 -2
- data/merit.gemspec +5 -2
- data/test/dummy-mongoid/Rakefile +7 -0
- data/test/dummy-mongoid/app/controllers/application_controller.rb +7 -0
- data/test/dummy-mongoid/app/controllers/comments_controller.rb +90 -0
- data/test/dummy-mongoid/app/controllers/registrations_controller.rb +15 -0
- data/test/dummy-mongoid/app/controllers/users_controller.rb +67 -0
- data/test/dummy-mongoid/app/helpers/application_helper.rb +2 -0
- data/test/dummy-mongoid/app/models/comment.rb +17 -0
- data/test/dummy-mongoid/app/models/merit/badge_rules.rb +49 -0
- data/test/dummy-mongoid/app/models/merit/point_rules.rb +20 -0
- data/test/dummy-mongoid/app/models/merit/rank_rules.rb +24 -0
- data/test/dummy-mongoid/app/models/user.rb +30 -0
- data/test/dummy-mongoid/app/views/comments/_form.html.erb +29 -0
- data/test/dummy-mongoid/app/views/comments/edit.html.erb +6 -0
- data/test/dummy-mongoid/app/views/comments/index.html.erb +35 -0
- data/test/dummy-mongoid/app/views/comments/new.html.erb +5 -0
- data/test/dummy-mongoid/app/views/comments/show.html.erb +23 -0
- data/test/dummy-mongoid/app/views/layouts/application.html.erb +24 -0
- data/test/dummy-mongoid/app/views/users/_form.html.erb +22 -0
- data/test/dummy-mongoid/app/views/users/edit.html.erb +6 -0
- data/test/dummy-mongoid/app/views/users/index.html.erb +26 -0
- data/test/dummy-mongoid/app/views/users/new.html.erb +5 -0
- data/test/dummy-mongoid/app/views/users/show.html.erb +18 -0
- data/test/dummy-mongoid/config.ru +4 -0
- data/test/dummy-mongoid/config/application.rb +22 -0
- data/test/dummy-mongoid/config/boot.rb +10 -0
- data/test/dummy-mongoid/config/environment.rb +5 -0
- data/test/dummy-mongoid/config/environments/development.rb +25 -0
- data/test/dummy-mongoid/config/environments/production.rb +49 -0
- data/test/dummy-mongoid/config/environments/test.rb +35 -0
- data/test/dummy-mongoid/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy-mongoid/config/initializers/inflections.rb +10 -0
- data/test/dummy-mongoid/config/initializers/merit.rb +37 -0
- data/test/dummy-mongoid/config/initializers/mime_types.rb +5 -0
- data/test/dummy-mongoid/config/initializers/secret_token.rb +7 -0
- data/test/dummy-mongoid/config/initializers/session_store.rb +8 -0
- data/test/dummy-mongoid/config/locales/en.yml +5 -0
- data/test/dummy-mongoid/config/mongoid.yml +14 -0
- data/test/dummy-mongoid/config/routes.rb +9 -0
- data/test/dummy-mongoid/db/seeds.rb +17 -0
- data/test/dummy-mongoid/public/404.html +26 -0
- data/test/dummy-mongoid/public/422.html +26 -0
- data/test/dummy-mongoid/public/500.html +26 -0
- data/test/dummy-mongoid/public/favicon.ico +0 -0
- data/test/dummy-mongoid/public/javascripts/application.js +2 -0
- data/test/dummy-mongoid/public/javascripts/controls.js +965 -0
- data/test/dummy-mongoid/public/javascripts/dragdrop.js +974 -0
- data/test/dummy-mongoid/public/javascripts/effects.js +1123 -0
- data/test/dummy-mongoid/public/javascripts/prototype.js +6001 -0
- data/test/dummy-mongoid/public/javascripts/rails.js +191 -0
- data/test/dummy-mongoid/public/stylesheets/.gitkeep +0 -0
- data/test/dummy-mongoid/public/stylesheets/scaffold.css +56 -0
- data/test/dummy-mongoid/script/rails +6 -0
- data/test/dummy/config/initializers/merit.rb +1 -1
- data/test/integration/navigation_test.rb +1 -1
- data/test/merit_unit_test.rb +3 -0
- data/test/test_helper.rb +20 -3
- metadata +92 -16
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
merit (0.
|
5
|
-
ambry
|
4
|
+
merit (0.8.0)
|
5
|
+
ambry (~> 0.3.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
@@ -37,6 +37,9 @@ GEM
|
|
37
37
|
addressable (2.2.7)
|
38
38
|
ambry (0.3.0)
|
39
39
|
arel (3.0.2)
|
40
|
+
bson (1.6.2)
|
41
|
+
bson_ext (1.6.2)
|
42
|
+
bson (~> 1.6.2)
|
40
43
|
builder (3.0.0)
|
41
44
|
capybara (1.1.2)
|
42
45
|
mime-types (>= 1.16)
|
@@ -61,6 +64,12 @@ GEM
|
|
61
64
|
mime-types (~> 1.16)
|
62
65
|
treetop (~> 1.4.8)
|
63
66
|
mime-types (1.18)
|
67
|
+
mongo (1.6.2)
|
68
|
+
bson (~> 1.6.2)
|
69
|
+
mongoid (2.4.8)
|
70
|
+
activemodel (~> 3.1)
|
71
|
+
mongo (~> 1.3)
|
72
|
+
tzinfo (~> 0.3.22)
|
64
73
|
multi_json (1.3.2)
|
65
74
|
nokogiri (1.5.2)
|
66
75
|
polyglot (0.3.3)
|
@@ -118,9 +127,11 @@ PLATFORMS
|
|
118
127
|
ruby
|
119
128
|
|
120
129
|
DEPENDENCIES
|
130
|
+
bson_ext
|
121
131
|
capybara
|
122
132
|
haml
|
123
133
|
merit!
|
134
|
+
mongoid (= 2.4.8)
|
124
135
|
rails (~> 3.2.3)
|
125
136
|
simplecov
|
126
137
|
sqlite3
|
data/README.md
CHANGED
@@ -5,12 +5,18 @@
|
|
5
5
|
[](http://travis-ci.org/tute/merit)
|
6
6
|
|
7
7
|
|
8
|
+
# Requirements
|
9
|
+
|
10
|
+
* ActiveRecord or Mongoid
|
11
|
+
|
8
12
|
# Installation
|
9
13
|
|
10
|
-
1. Add
|
11
|
-
2. Run
|
12
|
-
3. Run
|
13
|
-
4.
|
14
|
+
1. Add `gem 'merit'` to your `Gemfile`
|
15
|
+
2. Run `rails g merit:install`
|
16
|
+
3. Run `rails g merit MODEL_NAME`
|
17
|
+
4.
|
18
|
+
* ActiveRecord: Run `rake db:migrate`
|
19
|
+
* Mongoid: Set `config.orm = :mongoid` in `config/initializers/merit.rb`
|
14
20
|
5. Configure reputation rules for your application
|
15
21
|
|
16
22
|
---
|
@@ -19,21 +25,21 @@
|
|
19
25
|
|
20
26
|
You may give badges to any resource on your application if some condition
|
21
27
|
holds. Badges may have levels, and may be temporary. Define rules on
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
*
|
27
|
-
*
|
28
|
-
*
|
29
|
-
*
|
30
|
-
*
|
31
|
-
the model (like
|
32
|
-
*
|
33
|
-
*
|
34
|
-
|
35
|
-
|
36
|
-
*
|
28
|
+
`app/models/merit_badge_rules.rb`:
|
29
|
+
|
30
|
+
`grant_on` accepts:
|
31
|
+
|
32
|
+
* `'controller#action'` string (similar to Rails routes)
|
33
|
+
* `:badge` for badge name
|
34
|
+
* `:level` for badge level
|
35
|
+
* `:to` method name over target_object which obtains object to badge
|
36
|
+
* `:model_name` (string) define controller's name if it differs from
|
37
|
+
the model (like `RegistrationsController` for `User` model).
|
38
|
+
* `:multiple` (boolean) badge may be granted multiple times
|
39
|
+
* `:temporary` (boolean) if the receiver had the badge but the condition
|
40
|
+
doesn't hold anymore, remove it. `false` by default (badges are kept
|
41
|
+
forever).
|
42
|
+
* `&block`
|
37
43
|
* empty (always grants)
|
38
44
|
* a block which evaluates to boolean (recieves target object as parameter)
|
39
45
|
* a block with a hash composed of methods to run on the target object with
|
@@ -41,19 +47,24 @@ holds. Badges may have levels, and may be temporary. Define rules on
|
|
41
47
|
|
42
48
|
## Examples
|
43
49
|
|
44
|
-
grant_on 'comments#vote', :badge => 'relevant-commenter', :to => :user do |comment|
|
45
|
-
comment.votes.count == 5
|
46
|
-
end
|
47
50
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
+
```ruby
|
52
|
+
grant_on 'comments#vote', :badge => 'relevant-commenter', :to => :user do |comment|
|
53
|
+
comment.votes.count == 5
|
54
|
+
end
|
55
|
+
|
56
|
+
grant_on ['users#create', 'users#update'], :badge => 'autobiographer', :temporary => true do |user|
|
57
|
+
user.name.present? && user.address.present?
|
58
|
+
end
|
59
|
+
```
|
51
60
|
|
52
61
|
## Grant manually
|
53
62
|
|
54
63
|
You may also grant badges "by hand":
|
55
64
|
|
56
|
-
|
65
|
+
```ruby
|
66
|
+
Badge.find(3).grant_to(current_user)
|
67
|
+
```
|
57
68
|
|
58
69
|
---
|
59
70
|
|
@@ -61,21 +72,23 @@ You may also grant badges "by hand":
|
|
61
72
|
|
62
73
|
Points are a simple integer value which are given to "meritable" resources.
|
63
74
|
They are given on actions-triggered, either to the action user or to the
|
64
|
-
method(s) defined in the
|
65
|
-
|
75
|
+
method(s) defined in the `:to` option. Define rules on
|
76
|
+
`app/models/merit_point_rules.rb`:
|
66
77
|
|
67
78
|
## Examples
|
68
79
|
|
69
|
-
|
70
|
-
|
71
|
-
|
80
|
+
```ruby
|
81
|
+
score 10, :on => [
|
82
|
+
'users#update'
|
83
|
+
]
|
72
84
|
|
73
|
-
|
85
|
+
score 15, :on => 'reviews#create', :to => [:reviewer, :reviewed]
|
74
86
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
87
|
+
score 20, :on => [
|
88
|
+
'comments#create',
|
89
|
+
'photos#create'
|
90
|
+
]
|
91
|
+
```
|
79
92
|
|
80
93
|
---
|
81
94
|
|
@@ -84,42 +97,48 @@ method(s) defined in the <tt>:to</tt> option. Define rules on
|
|
84
97
|
5 stars is a common ranking use case. They are not given at specified actions
|
85
98
|
like badges, you should define a cron job to test if ranks are to be granted.
|
86
99
|
|
87
|
-
Define rules on
|
100
|
+
Define rules on `app/models/merit_rank_rules.rb`:
|
88
101
|
|
89
|
-
|
102
|
+
`set_rank` accepts:
|
90
103
|
|
91
|
-
*
|
92
|
-
*
|
93
|
-
*
|
94
|
-
'
|
95
|
-
'
|
104
|
+
* `:level` ranking level (greater is better)
|
105
|
+
* `:to` model or scope to check if new rankings apply
|
106
|
+
* `:level_name` attribute name (default is empty and results in
|
107
|
+
'`level`' attribute, if set it's appended like
|
108
|
+
'`level_#{level_name}`')
|
96
109
|
|
97
110
|
Check for rules on a rake task executed in background like:
|
98
111
|
|
99
|
-
|
100
|
-
|
101
|
-
|
112
|
+
```ruby
|
113
|
+
task :cron => :environment do
|
114
|
+
Merit::RankRules.new.check_rank_rules
|
115
|
+
end
|
116
|
+
```
|
102
117
|
|
103
118
|
|
104
119
|
## Examples
|
105
120
|
|
106
|
-
|
107
|
-
|
108
|
-
|
121
|
+
```ruby
|
122
|
+
set_rank :level => 2, :to => Commiter.active do |commiter|
|
123
|
+
commiter.branches > 1 && commiter.followers >= 10
|
124
|
+
end
|
109
125
|
|
110
|
-
|
111
|
-
|
112
|
-
|
126
|
+
set_rank :level => 3, :to => Commiter.active do |commiter|
|
127
|
+
commiter.branches > 2 && commiter.followers >= 20
|
128
|
+
end
|
129
|
+
```
|
113
130
|
|
114
131
|
---
|
115
132
|
|
116
133
|
# To-do list
|
117
134
|
|
135
|
+
* Can infer params[:id] = instance_variable.id in create actions, for having
|
136
|
+
the object in the rule method parameter, so we don't need it in controllers.
|
118
137
|
* add an error handler for inexistent badges.
|
119
138
|
* rails g merit MODEL_NAME shouldn't create general migrations again.
|
120
139
|
* Abstract User (rule.rb#51 for instance) into a Merit option.
|
121
140
|
* Should namespace app/models into Merit module.
|
122
|
-
* rescue ActiveRecord::... should depend on ORM used
|
141
|
+
* rescue ActiveRecord::... should depend on ORM used
|
123
142
|
* Why 1.8.7 tests are not passing?
|
124
143
|
* :value parameter (for star voting for example) should be configurable
|
125
144
|
(depends on params[:value] on the controller).
|
data/TESTING.txt
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
cd test/dummy
|
2
|
-
rails g merit:install #
|
2
|
+
rails g merit:install # n's for not overriding already defined badges & rules
|
3
|
+
n
|
3
4
|
n
|
4
5
|
n
|
5
6
|
n
|
6
7
|
rails g merit user
|
7
8
|
rake db:migrate ; rake db:seed
|
9
|
+
|
8
10
|
# see it in the browser
|
9
11
|
rails server
|
12
|
+
|
10
13
|
# or run tests
|
11
|
-
cd ../..
|
14
|
+
cd ../..
|
15
|
+
rake test
|
16
|
+
ORM=mongoid rake test
|
@@ -3,7 +3,7 @@ Merit.setup do |config|
|
|
3
3
|
# Check rules on each request or in background
|
4
4
|
# config.checks_on_each_request = true
|
5
5
|
|
6
|
-
# Define ORM. Could be :active_record (default) and :mongo_mapper
|
6
|
+
# Define ORM. Could be :active_record (default) and :mongo_mapper and :mongoid
|
7
7
|
# config.orm = :active_record
|
8
8
|
end
|
9
9
|
|
data/lib/merit.rb
CHANGED
@@ -21,9 +21,10 @@ module Merit
|
|
21
21
|
|
22
22
|
class Engine < Rails::Engine
|
23
23
|
initializer 'merit.controller' do |app|
|
24
|
-
# Merit.orm now set
|
25
24
|
if Merit.orm == :active_record
|
25
|
+
require "merit/models/#{Merit.orm}/sash"
|
26
26
|
require "merit/models/#{Merit.orm}/badges_sash"
|
27
|
+
elsif Merit.orm == :mongoid
|
27
28
|
require "merit/models/#{Merit.orm}/sash"
|
28
29
|
end
|
29
30
|
|
@@ -25,7 +25,7 @@ module Merit
|
|
25
25
|
:had_errors => target_object.try(:errors).try(:present?),
|
26
26
|
:target_model => controller_name,
|
27
27
|
:target_id => target_id
|
28
|
-
)
|
28
|
+
).id
|
29
29
|
|
30
30
|
# Check rules in after_filter?
|
31
31
|
if Merit.checks_on_each_request
|
@@ -37,7 +37,7 @@ module Merit
|
|
37
37
|
granted = log.split('|').select{|log| log =~ /badge_granted_to_action_user/ }
|
38
38
|
granted.each do |badge|
|
39
39
|
badge_id = badge.split(':').last.to_i
|
40
|
-
flash[:merit] = t('merit.flashs.badge_granted', badge
|
40
|
+
flash[:merit] = t('merit.flashs.badge_granted', :badge => Badge.find(badge_id).name)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -10,6 +10,10 @@ module Merit
|
|
10
10
|
key :sash_id, String
|
11
11
|
key :points, Integer, :default => 0
|
12
12
|
key :level, Integer, :default => 0
|
13
|
+
elsif Merit.orm == :mongoid
|
14
|
+
field :sash_id
|
15
|
+
field :points, :type => Integer, :default => 0
|
16
|
+
field :level, :type => Integer, :default => 0
|
13
17
|
end
|
14
18
|
end
|
15
19
|
end
|
@@ -21,8 +25,8 @@ module Merit
|
|
21
25
|
|
22
26
|
# Create sash if doesn't have
|
23
27
|
def create_sash_if_none
|
24
|
-
if sash.
|
25
|
-
self.sash = Sash.
|
28
|
+
if self.sash.blank?
|
29
|
+
self.sash = Sash.create
|
26
30
|
self.save(:validate => false)
|
27
31
|
end
|
28
32
|
end
|
@@ -34,3 +38,6 @@ end
|
|
34
38
|
if Object.const_defined?('MongoMapper')
|
35
39
|
MongoMapper::Document.plugin Merit
|
36
40
|
end
|
41
|
+
if Object.const_defined?('Mongoid')
|
42
|
+
Mongoid::Document.send :include, Merit
|
43
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class MeritAction
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Timestamps
|
4
|
+
|
5
|
+
belongs_to :user
|
6
|
+
field :action_method
|
7
|
+
field :action_value, :type => Integer
|
8
|
+
field :had_errors, :type => Boolean
|
9
|
+
|
10
|
+
belongs_to :target, :polymorphic => true
|
11
|
+
field :processed, :type => Boolean, :default => false
|
12
|
+
field :log
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Sash
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Timestamps
|
4
|
+
|
5
|
+
field :badge_ids, :type => Array, :default => []
|
6
|
+
|
7
|
+
def add_badge(badge_id)
|
8
|
+
self.push(:badge_ids, badge_id)
|
9
|
+
end
|
10
|
+
|
11
|
+
def rm_badge(badge_id)
|
12
|
+
self.pull(:badge_ids, badge_id)
|
13
|
+
end
|
14
|
+
end
|
data/lib/merit/rule.rb
CHANGED
@@ -9,7 +9,7 @@ module Merit
|
|
9
9
|
def applies?(target_obj = nil)
|
10
10
|
return true if block.nil? # no block given: always true
|
11
11
|
|
12
|
-
case block.
|
12
|
+
case block.arity
|
13
13
|
when 1 # Expects target object
|
14
14
|
if target_obj.present?
|
15
15
|
return block.call(target_obj)
|
@@ -72,7 +72,9 @@ module Merit
|
|
72
72
|
if @badge.nil?
|
73
73
|
badges = Badge.by_name(badge_name)
|
74
74
|
badges = badges.by_level(level) unless level.nil?
|
75
|
-
@badge = badges.first
|
75
|
+
if !(@badge = badges.first)
|
76
|
+
raise "No badge '#{badge_name}'#{level.nil? ? '' : " with level #level"} found. Define it in 'config/initializers/merit.rb'."
|
77
|
+
end
|
76
78
|
end
|
77
79
|
@badge
|
78
80
|
end
|
data/lib/merit/rules_rank.rb
CHANGED
@@ -28,7 +28,12 @@ module Merit
|
|
28
28
|
level_and_rules = level_and_rules.sort
|
29
29
|
level_and_rules.each do |level, rule|
|
30
30
|
begin
|
31
|
-
|
31
|
+
if Merit.orm == :mongoid
|
32
|
+
items = scoped_model.where(:"#{rule.level_name}".lt => level)
|
33
|
+
else
|
34
|
+
items = scoped_model.where("#{rule.level_name} < #{level}")
|
35
|
+
end
|
36
|
+
items.each do |obj|
|
32
37
|
if rule.applies?(obj)
|
33
38
|
obj.update_attribute rule.level_name, level
|
34
39
|
end
|
@@ -45,4 +50,4 @@ module Merit
|
|
45
50
|
@defined_rules ||= {}
|
46
51
|
end
|
47
52
|
end
|
48
|
-
end
|
53
|
+
end
|
data/merit.gemspec
CHANGED
@@ -4,13 +4,16 @@ 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.
|
7
|
+
s.version = "0.8.0"
|
8
8
|
s.authors = ["Tute Costa"]
|
9
9
|
s.email = 'tutecosta@gmail.com'
|
10
|
-
s.add_dependency 'ambry'
|
10
|
+
s.add_dependency 'ambry', '~> 0.3.0'
|
11
11
|
s.add_development_dependency 'rails', '~> 3.2.3'
|
12
12
|
s.add_development_dependency 'sqlite3'
|
13
13
|
s.add_development_dependency 'haml'
|
14
14
|
s.add_development_dependency 'capybara'
|
15
15
|
s.add_development_dependency 'simplecov'
|
16
|
+
# Testing with Mongoid
|
17
|
+
s.add_development_dependency 'bson_ext'
|
18
|
+
s.add_development_dependency 'mongoid', '~> 2.0.0'
|
16
19
|
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
3
|
+
|
4
|
+
require File.expand_path('../config/application', __FILE__)
|
5
|
+
require 'rake'
|
6
|
+
|
7
|
+
DummyMongoid::Application.load_tasks
|