merit 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- merit (0.6.3)
4
+ merit (0.7.0)
5
5
  ambry
6
6
 
7
7
  GEM
@@ -96,6 +96,10 @@ GEM
96
96
  libwebsocket (~> 0.1.3)
97
97
  multi_json (~> 1.0)
98
98
  rubyzip
99
+ simplecov (0.6.4)
100
+ multi_json (~> 1.0)
101
+ simplecov-html (~> 0.5.3)
102
+ simplecov-html (0.5.3)
99
103
  sprockets (2.1.3)
100
104
  hike (~> 1.2)
101
105
  rack (~> 1.0)
@@ -118,4 +122,5 @@ DEPENDENCIES
118
122
  haml
119
123
  merit!
120
124
  rails (~> 3.2.3)
125
+ simplecov
121
126
  sqlite3
data/README.md CHANGED
@@ -29,6 +29,7 @@ holds. Badges may have levels, and may be temporary. Define rules on
29
29
  * <tt>:to</tt> method name over target_object which obtains object to badge
30
30
  * <tt>:model_name</tt> (string) define controller's name if it differs from
31
31
  the model (like <tt>RegistrationsController</tt> for <tt>User</tt> model).
32
+ * <tt>:multiple</tt> (boolean) badge may be granted multiple times
32
33
  * <tt>:temporary</tt> (boolean) if the receiver had the badge but the
33
34
  condition doesn't hold anymore, remove it. <tt>false</tt> by default (badges
34
35
  are kept forever).
@@ -114,6 +115,7 @@ Check for rules on a rake task executed in background like:
114
115
 
115
116
  # To-do list
116
117
 
118
+ * add an error handler for inexistent badges.
117
119
  * rails g merit MODEL_NAME shouldn't create general migrations again.
118
120
  * Abstract User (rule.rb#51 for instance) into a Merit option.
119
121
  * Should namespace app/models into Merit module.
data/TESTING.txt ADDED
@@ -0,0 +1,11 @@
1
+ cd test/dummy
2
+ rails g merit:install # Next n's for not overriding already defined rules
3
+ n
4
+ n
5
+ n
6
+ rails g merit user
7
+ rake db:migrate ; rake db:seed
8
+ # see it in the browser
9
+ rails server
10
+ # or run tests
11
+ cd ../.. ; rake test
data/app/models/badge.rb CHANGED
@@ -27,12 +27,8 @@ class Badge
27
27
  def grant_to(object_or_sash)
28
28
  object_or_sash.create_sash_if_none unless object_or_sash.kind_of?(Sash)
29
29
  sash = object_or_sash.respond_to?(:sash) ? object_or_sash.sash : object_or_sash
30
- if sash.badge_ids.include?(id)
31
- return false
32
- else
33
- sash.add_badge(id)
34
- return true
35
- end
30
+ sash.add_badge(id)
31
+ return true
36
32
  end
37
33
 
38
34
  # Take out badge from sash
@@ -0,0 +1,4 @@
1
+ en:
2
+ merit:
3
+ flashs:
4
+ badge_granted: "Congratulations! You've just earned '%{badge}' badge."
@@ -17,11 +17,10 @@ module Merit
17
17
  end
18
18
 
19
19
  # TODO: value should be configurable (now it's params[:value] set in the controller)
20
- value = params[:value]
21
- MeritAction.create(
20
+ merit_action_id = MeritAction.create(
22
21
  :user_id => current_user.try(:id),
23
22
  :action_method => action_name,
24
- :action_value => value,
23
+ :action_value => params[:value],
25
24
  :had_errors => target_object.try(:errors).try(:present?),
26
25
  :target_model => controller_name,
27
26
  :target_id => target_id
@@ -30,6 +29,16 @@ module Merit
30
29
  # Check rules in after_filter?
31
30
  if Merit.checks_on_each_request
32
31
  badge_rules.check_new_actions
32
+
33
+ # Show flash msg?
34
+ if (log = MeritAction.find(merit_action_id).log)
35
+ # Badges granted to current_user
36
+ granted = log.split('|').select{|log| log =~ /badge_granted_to_action_user/ }
37
+ granted.each do |badge|
38
+ badge_id = badge.split(':').last.to_i
39
+ flash[:merit] = t('merit.flashs.badge_granted', badge: Badge.find(badge_id).name)
40
+ end
41
+ end
33
42
  end
34
43
  end
35
44
  end
@@ -16,7 +16,7 @@ module Merit
16
16
 
17
17
  def badges
18
18
  create_sash_if_none
19
- Badge.find_by_id(sash.badge_ids)
19
+ sash.badge_ids.collect{|b_id| Badge.find(b_id) }
20
20
  end
21
21
 
22
22
  # Create sash if doesn't have
@@ -13,7 +13,7 @@ class Sash < ActiveRecord::Base
13
13
  end
14
14
  def rm_badge(badge_id)
15
15
  badges_sashes = BadgesSash.where(:badge_id => badge_id, :sash_id => self.id)
16
- # ActiveRecord::Relation#delete doesn't work with composite keys.
16
+ # ActiveRecord::Relation#delete|destroy(_all) doesn't work with composite keys.
17
17
  # Badge is not AR model (Ambry) so can't do self.badges.find(badge_id).delete
18
18
  badges_sash = badges_sashes.first
19
19
  badges_sashes.delete_all
data/lib/merit/rule.rb CHANGED
@@ -3,7 +3,7 @@ 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, :temporary, :block, :model_name, :level_name
6
+ attr_accessor :badge_name, :level, :to, :multiple, :temporary, :block, :model_name, :level_name
7
7
 
8
8
  # Does this rule's condition block apply?
9
9
  def applies?(target_obj = nil)
@@ -22,7 +22,7 @@ module Merit
22
22
  end
23
23
  end
24
24
 
25
- # Is this rule's badge temporary?
25
+ def multiple?; self.multiple; end
26
26
  def temporary?; self.temporary; end
27
27
 
28
28
  # Grant badge if rule applies. If it doesn't, and the badge is temporary,
@@ -34,12 +34,14 @@ module Merit
34
34
  end
35
35
 
36
36
  if applies? action.target_object(model_name)
37
- if badge.grant_to(sash)
38
- action.log!("badge_granted:#{badge.name}")
37
+ if !sash.badge_ids.include?(badge.id) || multiple?
38
+ badge.grant_to(sash)
39
+ to_action_user = (to.to_sym == :action_user ? '_to_action_user' : '')
40
+ action.log!("badge_granted#{to_action_user}:#{badge.id}")
39
41
  end
40
42
  elsif temporary?
41
43
  if badge.delete_from(sash)
42
- action.log!("badge_removed:#{badge.name}")
44
+ action.log!("badge_removed:#{badge.id}")
43
45
  end
44
46
  end
45
47
  end
@@ -40,6 +40,7 @@ module Merit
40
40
  rule.badge_name = options[:badge]
41
41
  rule.level = options[:level]
42
42
  rule.to = options[:to] || :action_user
43
+ rule.multiple = options[:multiple] || false
43
44
  rule.temporary = options[:temporary] || false
44
45
  rule.model_name = options[:model_name] || actions[0].split('#')[0]
45
46
  rule.block = block
data/merit.gemspec CHANGED
@@ -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.6.3"
7
+ s.version = "0.7.0"
8
8
  s.authors = ["Tute Costa"]
9
9
  s.email = 'tutecosta@gmail.com'
10
10
  s.add_dependency 'ambry'
@@ -12,4 +12,5 @@ Gem::Specification.new do |s|
12
12
  s.add_development_dependency 'sqlite3'
13
13
  s.add_development_dependency 'haml'
14
14
  s.add_development_dependency 'capybara'
15
+ s.add_development_dependency 'simplecov'
15
16
  end
@@ -21,7 +21,13 @@ module Merit
21
21
  def initialize
22
22
  # If it creates user, grant badge
23
23
  # Should be "current_user" after registration for badge to be granted.
24
- grant_on 'users#create', :badge => 'just-registered', :to => :itself
24
+ # Example rule with block with no parameters
25
+ grant_on 'users#create', :badge => 'just-registered', :to => :itself do
26
+ Date.today > 1.year.ago.to_date
27
+ end
28
+
29
+ # Example rule for multiple badge granting
30
+ grant_on 'users#index', :badge => 'gossip', :multiple => true
25
31
 
26
32
  # If it has 10 comments, grant commenter-10 badge
27
33
  grant_on 'comments#create', :badge => 'commenter', :level => 10 do |comment|
@@ -6,6 +6,16 @@ class User < ActiveRecord::Base
6
6
  attr_accessible :name
7
7
 
8
8
  def show_badges
9
- badges.collect{|b| "#{b.name.capitalize} (#{b.level})" }.join(', ')
9
+ create_sash_if_none
10
+ badges_uniq = Badge.find_by_id(sash.badge_ids)
11
+ badges_uniq.collect{|b| "#{b.name.capitalize}#{badge_status(b)}" }.join(', ')
12
+ end
13
+
14
+ def badge_status(badge)
15
+ status = []
16
+ count = badges.select{|b| b.name == badge.name }.count
17
+ status << "level: #{badge.level}" if badge.level
18
+ status << "x#{count}" if count > 1
19
+ status.present? ? " (#{status.join(', ')})" : ''
10
20
  end
11
21
  end
@@ -0,0 +1,23 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Merit Dummy app</title>
6
+ <%= stylesheet_link_tag :all %>
7
+ <%= csrf_meta_tag %>
8
+ </head>
9
+ <body>
10
+ <h1><%= link_to 'Dummy app', '/' %></h1>
11
+
12
+ <% flash.each do |name, msg| %>
13
+ <%= content_tag :p, msg, :class => (name == 'error' ? 'error' : 'notice') %>
14
+ <% end %>
15
+
16
+ <%= yield %>
17
+
18
+ <ul>
19
+ <li><%= link_to 'Users', users_url %></li>
20
+ <li><%= link_to 'Comments', comments_url %></li>
21
+ </ul>
22
+ </body>
23
+ </html>
@@ -1,4 +1,4 @@
1
- <% obj = params[:action] == :new ? @user : [:registrations, @user] %>
1
+ <% obj = params[:action] == 'new' ? @user : [:registrations, @user] %>
2
2
  <%= form_for obj do |f| %>
3
3
  <% if @user.errors.any? %>
4
4
  <div id="error_explanation">
@@ -29,6 +29,9 @@ badge_id = 0
29
29
  }, {
30
30
  :id => (badge_id = badge_id+1),
31
31
  :name => 'just-registered'
32
+ }, {
33
+ :id => (badge_id = badge_id+1),
34
+ :name => 'gossip'
32
35
  }].each do |badge|
33
36
  Badge.create! badge
34
37
  end
@@ -1,15 +1,27 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class NavigationTest < ActiveSupport::IntegrationCase
4
- setup do
5
- User.create(:name => 'test-user')
4
+ test 'user sign up should grant badge to itself' do
5
+ visit '/users/new'
6
+ fill_in 'Name', :with => 'Jack'
7
+ click_button('Create User')
8
+
9
+ user = User.where(:name => 'Jack').first
10
+ assert_equal [Badge.by_name('just-registered').first], user.badges.to_a
6
11
  end
7
12
 
8
- test 'user workflow should grant some badges at some times' do
9
- user = User.first
10
- assert user.badges.empty?
13
+ test 'users#index should grant badge multiple times' do
14
+ user = User.create(:name => 'test-user')
15
+ visit '/users'
16
+ visit '/users'
17
+ visit '/users'
18
+ visit '/users'
19
+ assert_equal 4, User.first.badges.count
20
+ end
11
21
 
22
+ test 'user workflow should grant some badges at some times' do
12
23
  # Commented 9 times, no badges yet
24
+ user = User.create(:name => 'test-user')
13
25
  (1..9).each do |i|
14
26
  Comment.create(
15
27
  :name => "Title #{i}",
@@ -65,7 +77,7 @@ class NavigationTest < ActiveSupport::IntegrationCase
65
77
  end
66
78
 
67
79
  test 'user workflow should add up points at some times' do
68
- user = User.first
80
+ user = User.create(:name => 'test-user')
69
81
  assert_equal 0, user.points, 'User should start with 0 points'
70
82
 
71
83
  visit "/users/#{user.id}/edit"
@@ -96,7 +108,7 @@ class NavigationTest < ActiveSupport::IntegrationCase
96
108
  end
97
109
 
98
110
  test 'user workflow should grant levels at some times' do
99
- user = User.first
111
+ user = User.create(:name => 'test-user')
100
112
  assert user.badges.empty?
101
113
 
102
114
  # Edit user's name by 2 chars name
@@ -12,4 +12,11 @@ class MeritUnitTest < ActiveSupport::TestCase
12
12
  rule.block = lambda{|obj| obj.length >= 4 }
13
13
  assert rule.applies?(str), 'block should make rule apply'
14
14
  end
15
+
16
+ test "BadgeSash knows it's related badge" do
17
+ Badge.create(:id => 99, :name => 'test-badge')
18
+ badge_sash = BadgesSash.new
19
+ badge_sash.badge_id = 99
20
+ assert_equal Badge.find(99), badge_sash.badge
21
+ end
15
22
  end
data/test/test_helper.rb CHANGED
@@ -1,5 +1,16 @@
1
1
  # Configure Rails Envinronment
2
2
  ENV["RAILS_ENV"] = "test"
3
+ RUBYOPT="-w $RUBYOPT"
4
+
5
+ require 'simplecov'
6
+ SimpleCov.adapters.define 'rubygem' do
7
+ # Add app to Merit group
8
+ # https://github.com/colszowka/simplecov/pull/104
9
+ add_group 'Merit', 'lib'
10
+ add_group 'DummyApp', 'test/dummy'
11
+ add_filter 'test/dummy/config/initializers'
12
+ end
13
+ SimpleCov.start 'rubygem' if ENV["COVERAGE"]
3
14
 
4
15
  require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
16
  require "rails/test_help"
@@ -19,4 +30,4 @@ Capybara.default_selector = :css
19
30
  ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
20
31
 
21
32
  # Load support files
22
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
33
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
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.6.3
4
+ version: 0.7.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-28 00:00:00.000000000 Z
12
+ date: 2012-05-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ambry
16
- requirement: &70291939751160 !ruby/object:Gem::Requirement
16
+ requirement: &70355964823460 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70291939751160
24
+ version_requirements: *70355964823460
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rails
27
- requirement: &70291939744340 !ruby/object:Gem::Requirement
27
+ requirement: &70355964822720 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 3.2.3
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70291939744340
35
+ version_requirements: *70355964822720
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: sqlite3
38
- requirement: &70291939743780 !ruby/object:Gem::Requirement
38
+ requirement: &70355964822080 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70291939743780
46
+ version_requirements: *70355964822080
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: haml
49
- requirement: &70291939743320 !ruby/object:Gem::Requirement
49
+ requirement: &70355964821480 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70291939743320
57
+ version_requirements: *70355964821480
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: capybara
60
- requirement: &70291939742900 !ruby/object:Gem::Requirement
60
+ requirement: &70355964821060 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,7 +65,18 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70291939742900
68
+ version_requirements: *70355964821060
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: &70355964820640 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70355964820640
69
80
  description: Manage badges, points and rankings (reputation) of resources in a Rails
70
81
  application.
71
82
  email: tutecosta@gmail.com
@@ -78,9 +89,11 @@ files:
78
89
  - MIT-LICENSE
79
90
  - README.md
80
91
  - Rakefile
92
+ - TESTING.txt
81
93
  - UPGRADING.md
82
94
  - app/models/badge.rb
83
95
  - app/models/merit_action.rb
96
+ - config/locales/en.yml
84
97
  - lib/generators/active_record/merit_generator.rb
85
98
  - lib/generators/active_record/templates/add_fields_to_model.rb
86
99
  - lib/generators/active_record/templates/create_badges_sashes.rb
@@ -121,7 +134,7 @@ files:
121
134
  - test/dummy/app/views/comments/index.html.erb
122
135
  - test/dummy/app/views/comments/new.html.erb
123
136
  - test/dummy/app/views/comments/show.html.erb
124
- - test/dummy/app/views/layouts/application.html.haml
137
+ - test/dummy/app/views/layouts/application.html.erb
125
138
  - test/dummy/app/views/users/_form.html.erb
126
139
  - test/dummy/app/views/users/edit.html.erb
127
140
  - test/dummy/app/views/users/index.html.erb
@@ -1,18 +0,0 @@
1
- !!!
2
- %html
3
- %head
4
- %title Dummy
5
- = stylesheet_link_tag :all
6
- = javascript_include_tag :defaults
7
- = csrf_meta_tag
8
- %body
9
- %h1= link_to 'Dummy app', '/'
10
-
11
- - flash.each do |name, msg|
12
- = content_tag :p, msg, :class => (name == 'error' ? 'error' : 'notice')
13
-
14
- = yield
15
-
16
- %ul
17
- %li= link_to 'Users', users_url
18
- %li= link_to 'Comments', comments_url