merit 0.2.5 → 0.3.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 (86) hide show
  1. data/Gemfile +2 -0
  2. data/Gemfile.lock +103 -0
  3. data/README.markdown +17 -2
  4. data/app/models/badge.rb +27 -19
  5. data/app/models/merit_action.rb +5 -3
  6. data/app/models/sash.rb +5 -14
  7. data/lib/generators/active_record/merit_generator.rb +14 -14
  8. data/lib/generators/{merit → active_record}/templates/create_badges_sashes.rb +0 -0
  9. data/lib/generators/{merit → active_record}/templates/create_merit_actions.rb +0 -0
  10. data/lib/generators/{merit → active_record}/templates/create_sashes.rb +0 -0
  11. data/lib/generators/merit/install_generator.rb +3 -20
  12. data/lib/generators/merit/merit_generator.rb +12 -0
  13. data/lib/generators/merit/templates/merit.rb +10 -1
  14. data/lib/merit.rb +11 -2
  15. data/lib/merit/controller_extensions.rb +2 -2
  16. data/lib/merit/model_additions.rb +18 -17
  17. data/lib/merit/models/active_record/badges_sash.rb +12 -0
  18. data/lib/merit/models/active_record/merit_action.rb +2 -0
  19. data/lib/merit/models/active_record/sash.rb +12 -0
  20. data/lib/merit/models/mongo_mapper/merit_action.rb +12 -0
  21. data/lib/merit/models/mongo_mapper/sash.rb +15 -0
  22. data/lib/merit/rule.rb +2 -2
  23. data/lib/merit/rules_badge.rb +1 -1
  24. data/merit.gemspec +16 -0
  25. data/test/dummy/Rakefile +7 -0
  26. data/test/dummy/app/controllers/application_controller.rb +7 -0
  27. data/test/dummy/app/controllers/comments_controller.rb +90 -0
  28. data/test/dummy/app/controllers/registrations_controller.rb +15 -0
  29. data/test/dummy/app/controllers/users_controller.rb +67 -0
  30. data/test/dummy/app/helpers/application_helper.rb +2 -0
  31. data/test/dummy/app/models/comment.rb +4 -0
  32. data/test/dummy/app/models/merit_badge_rules.rb +41 -0
  33. data/test/dummy/app/models/merit_point_rules.rb +18 -0
  34. data/test/dummy/app/models/merit_rank_rules.rb +25 -0
  35. data/test/dummy/app/models/user.rb +9 -0
  36. data/test/dummy/app/views/comments/_form.html.erb +29 -0
  37. data/test/dummy/app/views/comments/edit.html.erb +6 -0
  38. data/test/dummy/app/views/comments/index.html.erb +35 -0
  39. data/test/dummy/app/views/comments/new.html.erb +5 -0
  40. data/test/dummy/app/views/comments/show.html.erb +23 -0
  41. data/test/dummy/app/views/layouts/application.html.haml +18 -0
  42. data/test/dummy/app/views/users/_form.html.erb +22 -0
  43. data/test/dummy/app/views/users/edit.html.erb +6 -0
  44. data/test/dummy/app/views/users/index.html.erb +26 -0
  45. data/test/dummy/app/views/users/new.html.erb +5 -0
  46. data/test/dummy/app/views/users/show.html.erb +18 -0
  47. data/test/dummy/config.ru +4 -0
  48. data/test/dummy/config/application.rb +24 -0
  49. data/test/dummy/config/boot.rb +10 -0
  50. data/test/dummy/config/database.yml +22 -0
  51. data/test/dummy/config/environment.rb +5 -0
  52. data/test/dummy/config/environments/development.rb +26 -0
  53. data/test/dummy/config/environments/production.rb +49 -0
  54. data/test/dummy/config/environments/test.rb +35 -0
  55. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  56. data/test/dummy/config/initializers/badges_data.rb +40 -0
  57. data/test/dummy/config/initializers/inflections.rb +10 -0
  58. data/test/dummy/config/initializers/mime_types.rb +5 -0
  59. data/test/dummy/config/initializers/secret_token.rb +7 -0
  60. data/test/dummy/config/initializers/session_store.rb +8 -0
  61. data/test/dummy/config/locales/en.yml +5 -0
  62. data/test/dummy/config/routes.rb +9 -0
  63. data/test/dummy/db/migrate/20110421191249_create_users.rb +12 -0
  64. data/test/dummy/db/migrate/20110421191250_create_comments.rb +16 -0
  65. data/test/dummy/db/schema.rb +61 -0
  66. data/test/dummy/db/seeds.rb +17 -0
  67. data/test/dummy/public/404.html +26 -0
  68. data/test/dummy/public/422.html +26 -0
  69. data/test/dummy/public/500.html +26 -0
  70. data/test/dummy/public/favicon.ico +0 -0
  71. data/test/dummy/public/javascripts/application.js +2 -0
  72. data/test/dummy/public/javascripts/controls.js +965 -0
  73. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  74. data/test/dummy/public/javascripts/effects.js +1123 -0
  75. data/test/dummy/public/javascripts/prototype.js +6001 -0
  76. data/test/dummy/public/javascripts/rails.js +191 -0
  77. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  78. data/test/dummy/public/stylesheets/scaffold.css +56 -0
  79. data/test/dummy/script/rails +6 -0
  80. data/test/integration/navigation_test.rb +132 -0
  81. data/test/merit_unit_test.rb +22 -0
  82. data/test/support/integration_case.rb +5 -0
  83. data/test/test_helper.rb +22 -0
  84. metadata +132 -13
  85. data/app/models/badges_sash.rb +0 -14
  86. data/lib/generators/merit/templates/create_badges.rb +0 -19
@@ -0,0 +1,12 @@
1
+ class BadgesSash < ActiveRecord::Base
2
+ belongs_to :badge
3
+ belongs_to :sash
4
+
5
+ # To be used in the application, mark badge granting as notified to user
6
+ def set_notified!(badge, sash)
7
+ # With composite keys ARel complained, had to use SQL
8
+ ActiveRecord::Base.connection.execute("UPDATE badges_sashes
9
+ SET notified_user = TRUE
10
+ WHERE badge_id = #{badge.id} AND sash_id = #{sash.id}")
11
+ end
12
+ end
@@ -0,0 +1,2 @@
1
+ class MeritAction < ActiveRecord::Base
2
+ end
@@ -0,0 +1,12 @@
1
+ class Sash < ActiveRecord::Base
2
+ has_many :badges_sashes
3
+ has_many :badges, :through => :badges_sashes
4
+
5
+ def add_badge(badge_id)
6
+ BadgesSash.create(sash: self, badge_id: badge_id)
7
+ end
8
+ def rm_badge(badge_id)
9
+ ActiveRecord::Base.connection.execute("DELETE FROM badges_sashes
10
+ WHERE badge_id = #{badge_id} AND sash_id = #{self.id}")
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ class MeritAction
2
+ include MongoMapper::Document
3
+
4
+ key :user_id, String
5
+ key :action_method, String
6
+ key :action_value, Integer
7
+ key :had_errors, Boolean
8
+ key :target_model, String
9
+ key :target_id, String
10
+ key :processed, Boolean, :default => false
11
+ timestamps!
12
+ end
@@ -0,0 +1,15 @@
1
+ class Sash
2
+ include MongoMapper::Document
3
+
4
+ key :badge_ids, Array
5
+ timestamps!
6
+
7
+ def add_badge(badge_id)
8
+ self.badge_ids << badge_id
9
+ self.save
10
+ end
11
+ def rm_badge(badge_id)
12
+ self.badge_ids -= [badge_id]
13
+ self.save
14
+ end
15
+ end
@@ -72,8 +72,8 @@ module Merit
72
72
  # Get rule's related Badge.
73
73
  def badge
74
74
  if @badge.nil?
75
- badges = Badge.where(:name => badge_name)
76
- badges = badges.where(:level => level.to_s) unless level.nil?
75
+ badges = Badge.by_name(badge_name)
76
+ badges = badges.by_level(level) unless level.nil?
77
77
  @badge = badges.first
78
78
  end
79
79
  @badge
@@ -54,7 +54,7 @@ module Merit
54
54
  # Check non processed actions and grant badges if applies
55
55
  def check_new_actions
56
56
  MeritAction.where(:processed => false).each do |merit_action|
57
- merit_action.check_badge_rules(defined_rules)
57
+ merit_action.check_rules(defined_rules)
58
58
  end
59
59
  end
60
60
 
@@ -0,0 +1,16 @@
1
+ # Provide a simple gemspec so you can easily use your enginex
2
+ # project in your rails apps through git.
3
+ Gem::Specification.new do |s|
4
+ s.name = "merit"
5
+ s.summary = "General reputation Rails engine."
6
+ s.description = "General reputation Rails engine."
7
+ s.files = `git ls-files`.split("\n").reject{|f| f =~ /^\./ }
8
+ s.version = "0.3.0"
9
+ s.authors = ["Tute Costa"]
10
+ s.email = 'tutecosta@gmail.com'
11
+ s.add_dependency 'ambry'
12
+ s.add_development_dependency 'rails'
13
+ s.add_development_dependency 'sqlite3'
14
+ s.add_development_dependency 'haml'
15
+ s.add_development_dependency 'capybara'
16
+ 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
+ Dummy::Application.load_tasks
@@ -0,0 +1,7 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+
4
+ def current_user
5
+ @current_user ||= User.first
6
+ end
7
+ end
@@ -0,0 +1,90 @@
1
+ class CommentsController < ApplicationController
2
+ # GET /comments
3
+ # GET /comments.xml
4
+ def index
5
+ @comments = Comment.all
6
+
7
+ respond_to do |format|
8
+ format.html # index.html.erb
9
+ format.xml { render :xml => @comments }
10
+ end
11
+ end
12
+
13
+ # GET /comments/1
14
+ # GET /comments/1.xml
15
+ def show
16
+ @comment = Comment.find(params[:id])
17
+
18
+ respond_to do |format|
19
+ format.html # show.html.erb
20
+ format.xml { render :xml => @comment }
21
+ end
22
+ end
23
+
24
+ # GET /comments/new
25
+ # GET /comments/new.xml
26
+ def new
27
+ @comment = Comment.new
28
+
29
+ respond_to do |format|
30
+ format.html # new.html.erb
31
+ format.xml { render :xml => @comment }
32
+ end
33
+ end
34
+
35
+ # GET /comments/1/edit
36
+ def edit
37
+ @comment = Comment.find(params[:id])
38
+ end
39
+
40
+ def vote
41
+ @comment = Comment.find(params[:id])
42
+ @comment.votes += params[:value].to_i
43
+ @comment.save
44
+ redirect_to(comments_url, :notice => 'Vote added!')
45
+ end
46
+
47
+ # POST /comments
48
+ # POST /comments.xml
49
+ def create
50
+ @comment = Comment.new(params[:comment])
51
+
52
+ respond_to do |format|
53
+ if @comment.save
54
+ format.html { redirect_to(@comment, :notice => 'Comment was successfully created.') }
55
+ format.xml { render :xml => @comment, :status => :created, :location => @comment }
56
+ else
57
+ format.html { render "new" }
58
+ format.xml { render :xml => @comment.errors, :status => :unprocessable_entity }
59
+ end
60
+ end
61
+ end
62
+
63
+ # PUT /comments/1
64
+ # PUT /comments/1.xml
65
+ def update
66
+ @comment = Comment.find(params[:id])
67
+
68
+ respond_to do |format|
69
+ if @comment.update_attributes(params[:comment])
70
+ format.html { redirect_to(@comment, :notice => 'Comment was successfully updated.') }
71
+ format.xml { head :ok }
72
+ else
73
+ format.html { render "edit" }
74
+ format.xml { render :xml => @comment.errors, :status => :unprocessable_entity }
75
+ end
76
+ end
77
+ end
78
+
79
+ # DELETE /comments/1
80
+ # DELETE /comments/1.xml
81
+ def destroy
82
+ @comment = Comment.find(params[:id])
83
+ @comment.destroy
84
+
85
+ respond_to do |format|
86
+ format.html { redirect_to(comments_url) }
87
+ format.xml { head :ok }
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,15 @@
1
+ class RegistrationsController < ApplicationController
2
+ def update
3
+ @user = User.find(params[:id])
4
+
5
+ respond_to do |format|
6
+ if @user.update_attributes(params[:user])
7
+ format.html { redirect_to(@user, :notice => 'User was successfully updated.') }
8
+ format.xml { head :ok }
9
+ else
10
+ format.html { render "edit" }
11
+ format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,67 @@
1
+ class UsersController < ApplicationController
2
+ # GET /users
3
+ # GET /users.xml
4
+ def index
5
+ @users = User.all
6
+
7
+ respond_to do |format|
8
+ format.html # index.html.erb
9
+ format.xml { render :xml => @users }
10
+ end
11
+ end
12
+
13
+ # GET /users/1
14
+ # GET /users/1.xml
15
+ def show
16
+ @user = User.find(params[:id])
17
+
18
+ respond_to do |format|
19
+ format.html # show.html.erb
20
+ format.xml { render :xml => @user }
21
+ end
22
+ end
23
+
24
+ # GET /users/new
25
+ # GET /users/new.xml
26
+ def new
27
+ @user = User.new
28
+
29
+ respond_to do |format|
30
+ format.html # new.html.erb
31
+ format.xml { render :xml => @user }
32
+ end
33
+ end
34
+
35
+ # GET /users/1/edit
36
+ def edit
37
+ @user = User.find(params[:id])
38
+ end
39
+
40
+ # POST /users
41
+ # POST /users.xml
42
+ def create
43
+ @user = User.new(params[:user])
44
+
45
+ respond_to do |format|
46
+ if @user.save
47
+ format.html { redirect_to(@user, :notice => 'User was successfully created.') }
48
+ format.xml { render :xml => @user, :status => :created, :location => @user }
49
+ else
50
+ format.html { render "new" }
51
+ format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
52
+ end
53
+ end
54
+ end
55
+
56
+ # DELETE /users/1
57
+ # DELETE /users/1.xml
58
+ def destroy
59
+ @user = User.find(params[:id])
60
+ @user.destroy
61
+
62
+ respond_to do |format|
63
+ format.html { redirect_to(users_url) }
64
+ format.xml { head :ok }
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,4 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :user
3
+ validates :name, :comment, :user_id, :presence => true
4
+ end
@@ -0,0 +1,41 @@
1
+ # +grant_on+ accepts:
2
+ # * Nothing (always grants)
3
+ # * A block which evaluates to boolean (recieves the object as parameter)
4
+ # * A block with a hash composed of methods to run on the target object with
5
+ # expected values (+:votes => 5+ for instance).
6
+ #
7
+ # +grant_on+ can have a +:to+ method name, which called over the target object
8
+ # should retrieve the object to badge (could be +:user+, +:self+, +:follower+,
9
+ # etc). If it's not defined merit will apply the badge to the user who
10
+ # triggered the action (:action_user by default). If it's :itself, it badges
11
+ # the created object (new user for instance).
12
+ #
13
+ # The :temporary option indicates that if the condition doesn't hold but the
14
+ # badge is granted, then it's removed. It's false by default (badges are kept
15
+ # forever).
16
+
17
+ class MeritBadgeRules
18
+ include Merit::BadgeRules
19
+
20
+ def initialize
21
+ # If it creates user, grant badge
22
+ # Should be "current_user" after registration for badge to be granted.
23
+ grant_on 'users#create', :badge => 'just-registered', :to => :itself
24
+
25
+ # If it has 10 comments, grant commenter-10 badge
26
+ grant_on 'comments#create', :badge => 'commenter', :level => 10 do
27
+ { :user => { :comments => { :count => 10 } } }
28
+ end
29
+
30
+ # If it has at least 10 votes, grant relevant-commenter badge
31
+ grant_on 'comments#vote', :badge => 'relevant-commenter', :to => :user do |comment|
32
+ comment.votes >= 10
33
+ end
34
+
35
+ # Changes his name by one wider than 4 chars (arbitrary ruby code and custom model_name)
36
+ # This badge is temporary (user may lose it)
37
+ grant_on 'registrations#update', :badge => 'autobiographer', :temporary => true, :model_name => 'User' do |user|
38
+ user.name.length > 4
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,18 @@
1
+ # Points are a simple integer value which are given to "meritable" resources
2
+ # according to rules in +app/models/merit_point_rules.rb+. They are given on
3
+ # actions-triggered.
4
+
5
+ class MeritPointRules
6
+ include Merit::PointRules
7
+
8
+ def initialize
9
+ score 5, :to => :user, :on => [
10
+ 'comments#vote'
11
+ ]
12
+
13
+ score 20, :on => [
14
+ 'comments#create',
15
+ 'registrations#update'
16
+ ]
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ # Rankings are very similar to badges. They give "badges" which have a hierarchy
2
+ # defined by +level+'s lexicografical order (greater is better). If a rank is
3
+ # granted, lower level ranks are taken off. 5 stars is a common ranking use
4
+ # case.
5
+ #
6
+ # They are not given at specified actions like badges, you should define a cron
7
+ # job to test if ranks are to be granted.
8
+ #
9
+ # +set_rank+ accepts:
10
+ # * +badge_name+ name of this ranking
11
+ # * :+level+ ranking level (greater is better)
12
+ # * :+to+ model or scope to check if new rankings apply
13
+
14
+ class MeritRankRules
15
+ include Merit::RankRules
16
+
17
+ def initialize
18
+ # i stars for i chars name
19
+ (1..5).each do |i|
20
+ set_rank :stars, :level => i, :to => User do |user|
21
+ user.name.length == i
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ class User < ActiveRecord::Base
2
+ has_merit
3
+
4
+ has_many :comments
5
+
6
+ def show_badges
7
+ badges.collect{|b| "#{b.name.capitalize} (#{b.level})" }.join(', ')
8
+ end
9
+ end
@@ -0,0 +1,29 @@
1
+ <%= form_for(@comment) do |f| %>
2
+ <% if @comment.errors.any? %>
3
+ <div id="error_explanation">
4
+ <h2><%= pluralize(@comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
5
+
6
+ <ul>
7
+ <% @comment.errors.full_messages.each do |msg| %>
8
+ <li><%= msg %></li>
9
+ <% end %>
10
+ </ul>
11
+ </div>
12
+ <% end %>
13
+
14
+ <div class="field">
15
+ <%= f.label :name %><br />
16
+ <%= f.text_field :name %>
17
+ </div>
18
+ <div class="field">
19
+ <%= f.label :comment %><br />
20
+ <%= f.text_area :comment %>
21
+ </div>
22
+ <div class="field">
23
+ <%= f.label :user_id %><br />
24
+ <%= f.text_field :user_id %>
25
+ </div>
26
+ <div class="actions">
27
+ <%= f.submit %>
28
+ </div>
29
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <h1>Editing comment</h1>
2
+
3
+ <%= render 'form' %>
4
+
5
+ <%= link_to 'Show', @comment %> |
6
+ <%= link_to 'Back', comments_path %>
@@ -0,0 +1,35 @@
1
+ <h1>Listing comments</h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <th>Name</th>
6
+ <th>Comment</th>
7
+ <th>User</th>
8
+ <th>Votes</th>
9
+ <th>Vote up!</th>
10
+ <th></th>
11
+ <th></th>
12
+ <th></th>
13
+ </tr>
14
+
15
+ <% @comments.each do |comment| %>
16
+ <tr id="c_<%= comment.id %>">
17
+ <td><%= comment.name %></td>
18
+ <td><%= comment.comment %></td>
19
+ <td><%= comment.user_id %></td>
20
+ <td><%= comment.votes %></td>
21
+ <td>
22
+ <% (1..5).each do |i| %>
23
+ <%= link_to "#{i}", "/comments/#{comment.id}/vote/#{i}" %>
24
+ <% end %>
25
+ </td>
26
+ <td><%= link_to 'Show', comment %></td>
27
+ <td><%= link_to 'Edit', edit_comment_path(comment) %></td>
28
+ <td><%= link_to 'Destroy', comment, :confirm => 'Are you sure?', :method => :delete %></td>
29
+ </tr>
30
+ <% end %>
31
+ </table>
32
+
33
+ <br />
34
+
35
+ <%= link_to 'New Comment', new_comment_path %>