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
data/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
1
  source "http://rubygems.org"
2
2
 
3
+ gem 'ambry'
4
+
3
5
  gem "rails", "~> 3.0.10"
4
6
  gem "sqlite3"
5
7
  gem "haml"
@@ -0,0 +1,103 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ actionmailer (3.0.11)
6
+ actionpack (= 3.0.11)
7
+ mail (~> 2.2.19)
8
+ actionpack (3.0.11)
9
+ activemodel (= 3.0.11)
10
+ activesupport (= 3.0.11)
11
+ builder (~> 2.1.2)
12
+ erubis (~> 2.6.6)
13
+ i18n (~> 0.5.0)
14
+ rack (~> 1.2.1)
15
+ rack-mount (~> 0.6.14)
16
+ rack-test (~> 0.5.7)
17
+ tzinfo (~> 0.3.23)
18
+ activemodel (3.0.11)
19
+ activesupport (= 3.0.11)
20
+ builder (~> 2.1.2)
21
+ i18n (~> 0.5.0)
22
+ activerecord (3.0.11)
23
+ activemodel (= 3.0.11)
24
+ activesupport (= 3.0.11)
25
+ arel (~> 2.0.10)
26
+ tzinfo (~> 0.3.23)
27
+ activeresource (3.0.11)
28
+ activemodel (= 3.0.11)
29
+ activesupport (= 3.0.11)
30
+ activesupport (3.0.11)
31
+ ambry (0.2.4)
32
+ arel (2.0.10)
33
+ builder (2.1.2)
34
+ capybara (1.1.2)
35
+ mime-types (>= 1.16)
36
+ nokogiri (>= 1.3.3)
37
+ rack (>= 1.0.0)
38
+ rack-test (>= 0.5.4)
39
+ selenium-webdriver (~> 2.0)
40
+ xpath (~> 0.1.4)
41
+ childprocess (0.3.1)
42
+ ffi (~> 1.0.6)
43
+ erubis (2.6.6)
44
+ abstract (>= 1.0.0)
45
+ ffi (1.0.11)
46
+ haml (3.1.4)
47
+ i18n (0.5.0)
48
+ json (1.6.5)
49
+ mail (2.2.19)
50
+ activesupport (>= 2.3.6)
51
+ i18n (>= 0.4.0)
52
+ mime-types (~> 1.16)
53
+ treetop (~> 1.4.8)
54
+ mime-types (1.17.2)
55
+ multi_json (1.0.4)
56
+ nokogiri (1.5.0)
57
+ polyglot (0.3.3)
58
+ rack (1.2.5)
59
+ rack-mount (0.6.14)
60
+ rack (>= 1.0.0)
61
+ rack-test (0.5.7)
62
+ rack (>= 1.0)
63
+ rails (3.0.11)
64
+ actionmailer (= 3.0.11)
65
+ actionpack (= 3.0.11)
66
+ activerecord (= 3.0.11)
67
+ activeresource (= 3.0.11)
68
+ activesupport (= 3.0.11)
69
+ bundler (~> 1.0)
70
+ railties (= 3.0.11)
71
+ railties (3.0.11)
72
+ actionpack (= 3.0.11)
73
+ activesupport (= 3.0.11)
74
+ rake (>= 0.8.7)
75
+ rdoc (~> 3.4)
76
+ thor (~> 0.14.4)
77
+ rake (0.9.3.beta.1)
78
+ rdoc (3.12)
79
+ json (~> 1.4)
80
+ rubyzip (0.9.6.1)
81
+ selenium-webdriver (2.19.0)
82
+ childprocess (>= 0.2.5)
83
+ ffi (~> 1.0.9)
84
+ multi_json (~> 1.0.4)
85
+ rubyzip
86
+ sqlite3 (1.3.5)
87
+ thor (0.14.6)
88
+ treetop (1.4.10)
89
+ polyglot
90
+ polyglot (>= 0.3.1)
91
+ tzinfo (0.3.31)
92
+ xpath (0.1.4)
93
+ nokogiri (~> 1.3)
94
+
95
+ PLATFORMS
96
+ ruby
97
+
98
+ DEPENDENCIES
99
+ ambry
100
+ capybara
101
+ haml
102
+ rails (~> 3.0.10)
103
+ sqlite3
@@ -5,7 +5,7 @@
5
5
 
6
6
  # Installation
7
7
 
8
- 1. Add 'merit' to your Gemfile
8
+ 1. Add <tt>gem 'merit'</tt> to your Gemfile
9
9
  2. Run <tt>rails g merit:install</tt>
10
10
  3. Run <tt>rails g merit MODEL_NAME</tt>
11
11
  4. Run <tt>rake db:migrate</tt>
@@ -115,6 +115,21 @@ You may also add badges/rank "by hand" from controller actions:
115
115
 
116
116
  ---
117
117
 
118
+ # MongoMapper support (experimental)
119
+
120
+ You may use <tt>merit</tt> with <tt>mongo_mapper</tt> ORM by calling
121
+ <tt>rails g merit MODEL_NAME --orm mongo_mapper</tt> in the third step of the
122
+ installation, and configuring <tt>config.orm = :mongo_mapper</tt> in
123
+ <tt>config/initializers/merit.rb</tt>.
124
+
125
+ ---
126
+
127
+ # Upgrade to 0.3.0
128
+
129
+ Badges data is now stored in <tt>config/initializers/merit.rb</tt> using
130
+ <tt>ambry</tt> syntax (not in the DB anymore, as that table needed to be in
131
+ sync in all development environments).
132
+
118
133
  # Upgrade to 0.2.0
119
134
 
120
135
  Added <tt>had_errors</tt> boolean attribute to <tt>merit_actions</tt> table.
@@ -138,9 +153,9 @@ To run tests follow:
138
153
 
139
154
  # To-do list
140
155
 
156
+ * Use ActiveSupport's Array#wrap where I build arrays by hand
141
157
  * Ranking should not be badges, so .badges doesn't return them (2-stars
142
158
  shouldn't be badge).
143
- * <tt>grep -r 'FIXME\|TODO' .</tt>
144
159
  * :value parameter (for star voting for example) should be configurable
145
160
  (depends on params[:value] on the controller).
146
161
  * Make fixtures for integration testing (now creating objects on test file!).
@@ -1,39 +1,47 @@
1
- class Badge < ActiveRecord::Base
2
- has_many :badges_sashes
3
- has_many :sashes, :through => :badges_sashes
1
+ require 'ambry/active_model'
2
+
3
+ class Badge
4
+ extend Ambry::Model
5
+ extend Ambry::ActiveModel
6
+
7
+ field :id, :name, :level, :image, :description
8
+
9
+ validates_presence_of :id, :name
10
+ validates_uniqueness_of :id
11
+
12
+ filters do
13
+ def find_by_id(ids)
14
+ ids = ids.kind_of?(Array) ? ids : [ids]
15
+ find{|b| ids.include? b.id }
16
+ end
17
+ def by_name(name)
18
+ find{|b| b.name == name.to_s }
19
+ end
20
+ def by_level(level)
21
+ find{|b| b.level.to_s == level.to_s }
22
+ end
23
+ end
4
24
 
5
25
  # Grant badge to sash
6
26
  def grant_to(object_or_sash)
7
27
  object_or_sash.create_sash_if_none unless object_or_sash.kind_of?(Sash)
8
28
  sash = object_or_sash.respond_to?(:sash) ? object_or_sash.sash : object_or_sash
9
- unless sash.badges.include? self
10
- sash.badges << self
11
- sash.save
12
- end
29
+ sash.add_badge(id) unless sash.badge_ids.include?(id)
13
30
  end
14
31
 
15
32
  # Take out badge from sash
16
33
  def delete_from(object_or_sash)
17
34
  object_or_sash.create_sash_if_none unless object_or_sash.kind_of?(Sash)
18
35
  sash = object_or_sash.respond_to?(:sash) ? object_or_sash.sash : object_or_sash
19
- if sash.badges.include? self
20
- sash.badges -= [self]
21
- sash.save
22
- end
36
+ sash.rm_badge(id) if sash.badge_ids.include?(id)
23
37
  end
24
38
 
25
39
  # Give rank to sash if it's greater. Delete lower ranks it may have.
26
40
  def grant_rank_to(sash)
27
41
  # Grant to sash if had lower rank. Do nothing if has same or greater rank.
28
42
  if sash.has_lower_rank_than(self)
29
- sash.badges -= Badge.where(:name => name) # Clean up old ranks
30
- sash.badges << self
31
- sash.save
43
+ Badge.by_name(name).keys.each{|id| sash.rm_badge(id) } # Clean up old ranks
44
+ sash.add_badge(id)
32
45
  end
33
46
  end
34
-
35
- def self.latest(limit = nil)
36
- scope = order('created_at DESC')
37
- limit.present? ? scope.limit(limit) : scope
38
- end
39
47
  end
@@ -1,6 +1,8 @@
1
- class MeritAction < ActiveRecord::Base
1
+ require "merit/models/#{Merit.orm}/merit_action"
2
+
3
+ class MeritAction
2
4
  # Check rules defined for a merit_action
3
- def check_badge_rules(defined_rules)
5
+ def check_rules(defined_rules)
4
6
  action_name = "#{target_model}\##{action_method}"
5
7
 
6
8
  unless had_errors
@@ -25,7 +27,7 @@ class MeritAction < ActiveRecord::Base
25
27
  begin
26
28
  target = target_object.send(to)
27
29
  rescue
28
- Rails.logger.warn "[merit] No target_object found on check_badge_rules."
30
+ Rails.logger.warn "[merit] No target_object found on check_rules."
29
31
  return
30
32
  end
31
33
  end
@@ -1,19 +1,10 @@
1
- class Sash < ActiveRecord::Base
2
- has_many :badges_sashes
3
- has_many :badges, :through => :badges_sashes
4
-
5
- # Latest badges granted by Merit
6
- def self.latest_badges(limit = 10)
7
- select('DISTINCT sashes.id, sashes.*').joins(:badges_sashes).order('badges_sashes.created_at DESC').limit(limit)
8
- end
1
+ require "merit/models/#{Merit.orm}/sash"
9
2
 
3
+ class Sash
10
4
  # Decides if sash has lower rank than a given badge
11
5
  def has_lower_rank_than(badge)
12
- levels(badge.name).all_lower_than badge.level
13
- end
14
-
15
- # Collect Sash levels given a badge name
16
- def levels(badge_name)
17
- badges.where(:name => badge_name).collect(&:level)
6
+ badges = Badge.find_by_id(badge_ids)
7
+ levels = badges.by_name(badge.name).collect(&:level)
8
+ levels.all_lower_than badge.level
18
9
  end
19
10
  end
@@ -3,25 +3,25 @@ require 'rails/generators/active_record'
3
3
  module ActiveRecord
4
4
  module Generators
5
5
  class MeritGenerator < ActiveRecord::Generators::Base
6
- argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
6
+ include Rails::Generators::Migration
7
+ source_root File.expand_path('../templates', __FILE__)
8
+ desc "add active_record merit migrations"
7
9
 
8
- source_root File.expand_path("../templates", __FILE__)
9
-
10
- def model_exists?
11
- File.exists?(File.join(destination_root, model_path))
12
- end
13
-
14
- def model_path
15
- @model_path ||= File.join("app", "models", "#{file_path}.rb")
10
+ def self.next_migration_number(path)
11
+ unless @prev_migration_nr
12
+ @prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
13
+ else
14
+ @prev_migration_nr += 1
15
+ end
16
+ @prev_migration_nr.to_s
16
17
  end
17
18
 
18
- def copy_merit_migration
19
+ def copy_migrations_and_model
20
+ migration_template 'create_merit_actions.rb', 'db/migrate/create_merit_actions.rb'
21
+ migration_template 'create_sashes.rb', 'db/migrate/create_sashes.rb'
22
+ migration_template 'create_badges_sashes.rb', 'db/migrate/create_badges_sashes.rb'
19
23
  migration_template "add_fields_to_model.rb", "db/migrate/add_fields_to_#{table_name}"
20
24
  end
21
-
22
- def inject_merit_content
23
- inject_into_class(model_path, class_name, " has_merit\n\n") if model_exists?
24
- end
25
25
  end
26
26
  end
27
27
  end
@@ -1,30 +1,13 @@
1
- require 'rails/generators/migration'
2
-
3
1
  module Merit
4
2
  module Generators
5
- class InstallGenerator < ::Rails::Generators::Base
6
- include Rails::Generators::Migration
3
+ class InstallGenerator < Rails::Generators::Base
7
4
  source_root File.expand_path('../templates', __FILE__)
8
- desc "add the migrations"
9
-
10
- def self.next_migration_number(path)
11
- unless @prev_migration_nr
12
- @prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
13
- else
14
- @prev_migration_nr += 1
15
- end
16
- @prev_migration_nr.to_s
17
- end
18
-
5
+ desc "Copy config and rules files"
19
6
  def copy_migrations_and_model
20
- migration_template 'create_merit_actions.rb', 'db/migrate/create_merit_actions.rb'
21
- migration_template 'create_badges.rb', 'db/migrate/create_badges.rb'
22
- migration_template 'create_sashes.rb', 'db/migrate/create_sashes.rb'
23
- migration_template 'create_badges_sashes.rb', 'db/migrate/create_badges_sashes.rb'
7
+ template 'merit.rb', 'config/initializers/merit.rb'
24
8
  template 'merit_badge_rules.rb', 'app/models/merit_badge_rules.rb'
25
9
  template 'merit_point_rules.rb', 'app/models/merit_point_rules.rb'
26
10
  template 'merit_rank_rules.rb', 'app/models/merit_rank_rules.rb'
27
- template 'merit.rb', 'config/initializers/merit.rb'
28
11
  end
29
12
  end
30
13
  end
@@ -3,6 +3,18 @@ module Merit
3
3
  class MeritGenerator < Rails::Generators::NamedBase
4
4
  source_root File.expand_path("../templates", __FILE__)
5
5
  hook_for :orm
6
+
7
+ def model_exists?
8
+ File.exists?(File.join(destination_root, model_path))
9
+ end
10
+
11
+ def model_path
12
+ @model_path ||= File.join("app", "models", "#{file_path}.rb")
13
+ end
14
+
15
+ def inject_merit_content
16
+ inject_into_class(model_path, class_name, " has_merit\n\n") if model_exists?
17
+ end
6
18
  end
7
19
  end
8
20
  end
@@ -2,4 +2,13 @@
2
2
  Merit.setup do |config|
3
3
  # Check rules on each request or in background
4
4
  # config.checks_on_each_request = true
5
- end
5
+
6
+ # Define ORM. Could be :active_record (default) and :mongo_mapper
7
+ # config.orm = :active_record
8
+ end
9
+
10
+ # Create application badges (uses https://github.com/norman/ambry)
11
+ # Badge.create!({
12
+ # :id => 1,
13
+ # :name => 'just-registered'
14
+ # })
@@ -11,6 +11,10 @@ module Merit
11
11
  mattr_accessor :checks_on_each_request
12
12
  @@checks_on_each_request = true
13
13
 
14
+ # Define ORM
15
+ mattr_accessor :orm
16
+ @@orm = :active_record
17
+
14
18
  # Load configuration from initializer
15
19
  def self.setup
16
20
  yield self
@@ -18,9 +22,14 @@ module Merit
18
22
 
19
23
  class Engine < Rails::Engine
20
24
  initializer 'merit.controller' do |app|
25
+ # Merit.orm now set
26
+ if Merit.orm == :active_record
27
+ require "merit/models/#{Merit.orm}/badges_sash"
28
+ end
29
+
21
30
  ActiveSupport.on_load(:action_controller) do
22
- include Merit::ControllerExtensions
31
+ include Merit::ControllerExtensions
23
32
  end
24
33
  end
25
34
  end
26
- end
35
+ end
@@ -16,7 +16,7 @@ module Merit
16
16
  target_id = target_object.try(:id)
17
17
  end
18
18
 
19
- # TODO: value relies on params[:value] on the controller, should be configurable
19
+ # TODO: value should be configurable (now it's params[:value] set in the controller)
20
20
  value = params[:value]
21
21
  MeritAction.create(
22
22
  :user_id => current_user.try(:id),
@@ -29,7 +29,7 @@ module Merit
29
29
 
30
30
  # Check rules in after_filter?
31
31
  if Merit.checks_on_each_request
32
- ::MeritBadgeRules.new.check_new_actions
32
+ badge_rules.check_new_actions
33
33
  end
34
34
  end
35
35
  end
@@ -1,30 +1,31 @@
1
1
  module Merit
2
- def self.included(base)
3
- base.send :extend, ClassMethods
4
- end
2
+ extend ActiveSupport::Concern
5
3
 
6
4
  module ClassMethods
7
5
  def has_merit(options = {})
8
6
  belongs_to :sash
9
- send :include, InstanceMethods
7
+
8
+ if Merit.orm == :mongo_mapper
9
+ plugin Merit
10
+ key :sash_id, String
11
+ key :points, Integer, :default => 0
12
+ end
10
13
  end
11
14
  end
12
15
 
13
- module InstanceMethods
14
- # Return it's sash badges
15
- def badges
16
- create_sash_if_none
17
- sash.badges
18
- end
16
+ def badges
17
+ create_sash_if_none
18
+ Badge.find_by_id(sash.badge_ids).to_a
19
+ end
19
20
 
20
- # Create sash if doesn't have
21
- def create_sash_if_none
22
- if sash.nil?
23
- self.sash = Sash.new
24
- self.save(:validate => false)
25
- end
21
+ # Create sash if doesn't have
22
+ def create_sash_if_none
23
+ if sash.nil?
24
+ self.sash = Sash.new
25
+ self.save(:validate => false)
26
26
  end
27
27
  end
28
28
  end
29
29
 
30
- ActiveRecord::Base.send :include, Merit
30
+ ActiveRecord::Base.send :include, Merit if Object.const_defined?('ActiveRecord')
31
+ MongoMapper::Document.plugin Merit if Object.const_defined?('MongoMapper')