adhonorem 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.rdoc +225 -4
- data/lib/adhonorem/concerns/hooking_concern.rb +46 -0
- data/lib/adhonorem/concerns/meta_concern.rb +59 -0
- data/lib/adhonorem/concerns/objective_concern.rb +18 -0
- data/lib/adhonorem/concerns/reward_concern.rb +15 -0
- data/lib/adhonorem/concerns/user_contexted_concern.rb +22 -0
- data/lib/adhonorem/generators/adhonorem_generator.rb +4 -2
- data/lib/adhonorem/models/badge.rb +8 -124
- data/lib/adhonorem/railtie.rb +6 -0
- data/lib/adhonorem/version.rb +1 -1
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7e951e1aa1ee4f829618f394cf7f709a3b8ef33
|
4
|
+
data.tar.gz: 477be5b21e10e849b473903ca9ffff9500aa719a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4a7b733539dd2b5ae32059d5f6c8183bcb38cf2794cc6619220f7d8a3b5d6ad3628897ed2c8e2cced4256d6f45f7d3aea7ae923ba6cecf9359ccbf96d4e33db
|
7
|
+
data.tar.gz: bec3c2836d0f394d3c77f5e6f25de0ce84ca05fd9db4101df39686be963af44a282c26c2d0326be322f4d57a419ab7eacbc2b9fab35095b760444bc486f8cda1
|
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,6 +1,227 @@
|
|
1
1
|
= AdHonorem
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
{<img src="https://badge.fury.io/rb/adhonorem.svg" alt="Gem Version" />}[https://badge.fury.io/rb/adhonorem] {<img src="https://codeclimate.com/github/hchevalier/adhonorem/badges/gpa.svg" />}[https://codeclimate.com/github/hchevalier/adhonorem] {<img src="https://codeclimate.com/github/hchevalier/adhonorem/badges/coverage.svg" />}[https://codeclimate.com/github/hchevalier/adhonorem/coverage] {<img src="https://travis-ci.org/hchevalier/adhonorem.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/hchevalier/adhonorem]
|
4
|
+
|
5
|
+
AdHonorem assumes that you want to manage the gamification of your Rails application code-side, using Ruby files to represent your badges rather than depending on entries stored in a database.
|
6
|
+
|
7
|
+
This way, your badges are never to be altered by error, can be under revision control and, most of all, can be covered by your tests suite before they are deployed.
|
8
|
+
|
9
|
+
== Installation
|
10
|
+
|
11
|
+
Add this to your Gemfile:
|
12
|
+
|
13
|
+
gem 'adhonorem'
|
14
|
+
|
15
|
+
and run the bundle install command.
|
16
|
+
|
17
|
+
Ensure you already have an ActiveRecord model representing your users before executing the following commands:
|
18
|
+
|
19
|
+
# Generate initializer with AdHonorem settings
|
20
|
+
rails g adhonorem:initializer
|
21
|
+
|
22
|
+
# Generate migrations for progress-tracking and achievement ActiveRecord models
|
23
|
+
rails g adhonorem:migrations
|
24
|
+
|
25
|
+
# Execute the migrations
|
26
|
+
rake db:migrate
|
27
|
+
|
28
|
+
=== How to use
|
29
|
+
|
30
|
+
==== The base class
|
31
|
+
|
32
|
+
AdHonorem::Badge is the main class that your own badges will have to inherit from.
|
33
|
+
|
34
|
+
It uses static-record gem to provide an ActiveRecord-like query interface allowing you to query over the filesystem Ruby files. For the moment, no path setting is possible and your badge files are expected to be saved under /app/models/badges/ folder. You can create subfolders if you want.
|
35
|
+
|
36
|
+
Documentation for static-record's query interface can be found here: https://github.com/hchevalier/static_record
|
37
|
+
|
38
|
+
==== Your badge files
|
39
|
+
|
40
|
+
A simple badge file looks like this:
|
41
|
+
|
42
|
+
class SimpleBadge < AdHonorem::Badge
|
43
|
+
# The slug allows to reference the badge and must be unique
|
44
|
+
attribute :slug, 'simple_badge'
|
45
|
+
# The following attributes can be displayed to your users when needed
|
46
|
+
attribute :name, 'Simple badge'
|
47
|
+
attribute :description, 'This is a simple badge'
|
48
|
+
attribute :category, 'General'
|
49
|
+
# Point are not used yet.
|
50
|
+
# In a near future, a migration will add a new column to your users table and grant them points
|
51
|
+
attribute :points, 10
|
52
|
+
# The following attributes can be displayed to your users when needed
|
53
|
+
attribute :icon_locked, Rails.root.join('public', 'badges', 'locked', 'simple.png')
|
54
|
+
attribute :icon_unlocked, Rails.root.join('public', 'badges', 'unlocked', 'simple.png')
|
55
|
+
# The 'legacy' attribute allow you to defined when a badge cannot be obtained anymore
|
56
|
+
attribute :legacy, false
|
57
|
+
|
58
|
+
def initialize
|
59
|
+
# Important, do not forget to call super
|
60
|
+
super
|
61
|
+
|
62
|
+
# Parameter 1: checker method called when the objective is triggered.
|
63
|
+
# The user progress will increase by 1 if the method returns true
|
64
|
+
# It won't increase if the method returns false
|
65
|
+
# Parameter 2: The name of the objective. Can be displayed to your users when needed
|
66
|
+
# Parameter 3: The description of the objective. Can be displayed to your users when needed
|
67
|
+
# Parameter 4: Optional, defaults to 1. Defines how many times the objective must be
|
68
|
+
# successfully triggered to be completed
|
69
|
+
add_objective(:trigger_me, 'Pull the trigger', 'Trigger the objective to unlock the badge', 3)
|
70
|
+
end
|
71
|
+
|
72
|
+
def trigger_me(user, params)
|
73
|
+
true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Let's say that this file is saved in /app/models/badges/general/simple.rb
|
78
|
+
|
79
|
+
All attributes are mandatory for the moment, I'll try to make some of them have a default value as soon as possible.
|
80
|
+
|
81
|
+
The #initialize method is used to add as many objectives as you want or to add sub-badges (see 'Meta Badge')
|
82
|
+
|
83
|
+
You can see that for this badge, a user will have to successfully trigger the 'Pull the trigger' objective 3 times to unlock the badge.
|
84
|
+
|
85
|
+
==== Triggering
|
86
|
+
|
87
|
+
To trigger an objective, you'll have to call it from where you want in your code (model, controller, whatever...)
|
88
|
+
|
89
|
+
AdHonorem::Badge.find('simple_badge').set_context(current_user).trigger(:trigger_me)
|
90
|
+
|
91
|
+
Note that current_user is used for the example, you can use any user here.
|
92
|
+
|
93
|
+
This line of code will call the checker with the same name (which always return true in our example), which will lead to the user progression over this specific objective.
|
94
|
+
|
95
|
+
You can trigger an objective several times in a row with
|
96
|
+
|
97
|
+
AdHonorem::Badge.find('simple_badge').set_context(current_user).trigger(:trigger_me, amount: 5)
|
98
|
+
|
99
|
+
The 'Pull the trigger' objective will be successfully triggered 5 times, resulting in the user being granted the SimpleBadge.
|
100
|
+
|
101
|
+
As you may have noticed, checker methods always receive 2 parameters:
|
102
|
+
- The user specified with #set_context
|
103
|
+
- A 'params' object
|
104
|
+
|
105
|
+
Params can be passed to checkers using a 'data' attribute when calling #trigger
|
106
|
+
|
107
|
+
params = { ammos_left: @ammos }
|
108
|
+
AdHonorem::Badge.find('simple_badge').set_context(current_user).trigger(:trigger_me, amount: 5, data: params)
|
109
|
+
|
110
|
+
Now you can access everything in the checker
|
111
|
+
|
112
|
+
def trigger_me(user, params)
|
113
|
+
user.alive? && !params[:ammos_left].zero?
|
114
|
+
end
|
115
|
+
|
116
|
+
==== Result
|
117
|
+
|
118
|
+
The #trigger method will return the command result as a symbol:
|
119
|
+
- :legacy_badge when the badge cannot be unlocked anymore
|
120
|
+
- :already_done if the badge is already unlocked or if the objective is already fulfilled
|
121
|
+
- :failed_check when the checker method returns false
|
122
|
+
- :completed_badge when the user just unlocked the badge
|
123
|
+
- :completed_step when the user fulfilled the objective but not the whole badge (still have other objectives to complete)
|
124
|
+
- :triggered when the checker method returns true but it's not enough to complete the objective (still have some successful triggers to perform)
|
125
|
+
|
126
|
+
==== Progress and completion
|
127
|
+
|
128
|
+
Several methods allow you to give your users informations about their progression:
|
129
|
+
|
130
|
+
# Get progression for a specific badge
|
131
|
+
badge = AdHonorem::Badge.find('simple_badge')
|
132
|
+
badge.complete? # check if every objective is complete
|
133
|
+
badge.complete?(:trigger_me) # check if a single objective is complete
|
134
|
+
badge.progress # list completion for each objective
|
135
|
+
=> Pull the trigger: 0/1
|
136
|
+
badge.progress(:step) # Same as above, :step being the default parameter
|
137
|
+
badge.progress(:global) # Returns the percentage of completion
|
138
|
+
=> 78.0
|
139
|
+
|
140
|
+
# Get progression for a specific objective
|
141
|
+
progression = AdHonorem::Progress.find_by(user: current_user, badge_static_record_type: 'SimpleBadge', objective_slug: 'trigger_me')
|
142
|
+
progression.progress(:percentage)
|
143
|
+
=> 33.3
|
144
|
+
progression.progress(:stringified)
|
145
|
+
=> 1/3
|
146
|
+
progression.done?
|
147
|
+
=> false
|
148
|
+
|
149
|
+
# Get unlocked badges for a specific user
|
150
|
+
unlocked_badges = AdHonorem::Achievement.find_by(user: current_user, state: :done)
|
151
|
+
unlocked_badges.first.badge # returns an instance of the first unlocked badge
|
152
|
+
=> #<SimpleBadge:0x007fcfe9c7cf48>
|
153
|
+
|
154
|
+
==== Events and hooks
|
155
|
+
|
156
|
+
As manually triggering every badge won't be relevant if several badges can be unlocked through the same piece of code, AdHonorem provides an event/hook system.
|
157
|
+
|
158
|
+
Under the attributes of your badge, just before the initialize method, add the following:
|
159
|
+
hook :<event_name>, to: [:<responder_one>, :<responder_two>]
|
160
|
+
|
161
|
+
Where <event_name> is an arbitrary event name and where <responder_one> and <responder_two> are checker methods of your badge.
|
162
|
+
|
163
|
+
Several badges can hook a similar event name.
|
164
|
+
|
165
|
+
In your models or controllers (or whatever), you can raise an event with
|
166
|
+
|
167
|
+
AdHonorem::Badge.dispatch(current_user, :<event_name>, params)
|
168
|
+
|
169
|
+
'params' is optional and works the same as for the #trigger method, for instance
|
170
|
+
|
171
|
+
{ amount: 1, data: { called_from_file: __FILE__ } }
|
172
|
+
|
173
|
+
The event will bubble to all the badges that have a hook for it and will try to triggers the responder(s) as if they had been called through #trigger
|
174
|
+
|
175
|
+
==== Meta Badge
|
176
|
+
|
177
|
+
Here is an example of a meta badge
|
178
|
+
|
179
|
+
class MetaBadge < AdHonorem::Badge
|
180
|
+
attribute :slug, 'meta_badge'
|
181
|
+
attribute :name, 'Meta badge'
|
182
|
+
#### truncated for the sake of the example, other attributes are still mandatory ####
|
183
|
+
|
184
|
+
def initialize
|
185
|
+
super
|
186
|
+
|
187
|
+
add_sub_badge(:sub_badge_one)
|
188
|
+
add_sub_badge(:sub_badge_two)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
As you can see, we defined sub-badges in the initialize method instead of objectives.
|
193
|
+
|
194
|
+
Each time this badge will be triggered for an objective, it will bubble it to all of its sub-badges (except for those already unlocked by the user).
|
195
|
+
|
196
|
+
Meta badges respond to the #complete? method with true when all their sub-badges are complete too, though they don't unlock. You won't find an AdHonorem::Achievement for meta badges. It allows you to add an harder to get sub-badge to an existing meta later if you want.
|
197
|
+
|
198
|
+
Important: Your sub-badges should not declare event hooks directly! Instead, hook the events to your meta badge this way:
|
199
|
+
|
200
|
+
class MetaBadge < AdHonorem::Badge
|
201
|
+
attribute :slug, 'meta_badge'
|
202
|
+
attribute :name, 'Meta badge'
|
203
|
+
#### truncated for the sake of the example, other attributes are still mandatory ####
|
204
|
+
|
205
|
+
hook :level_up, to: :level_up
|
206
|
+
|
207
|
+
def initialize
|
208
|
+
super
|
209
|
+
|
210
|
+
add_sub_badge(:sub_badge_one)
|
211
|
+
add_sub_badge(:sub_badge_two)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Each time AdHonorem::Badge.dispatch(current_user, :level_up) is called, the level_up method of both sub_badge_one and sub_badge_two badges will be triggered
|
216
|
+
|
217
|
+
== Questions?
|
218
|
+
|
219
|
+
If you have any question or doubt regarding StaticRecord which you cannot find the solution to in the documentation, you can send me an email. I'll try to answer in less than 24 hours.
|
220
|
+
|
221
|
+
== Bugs?
|
222
|
+
|
223
|
+
If you find a bug please add an issue on GitHub or fork the project and send a pull request.
|
224
|
+
|
225
|
+
== Future
|
226
|
+
|
227
|
+
AdHonorem is in active development, so be ready for leaderboards, sample apps with ready-to-use partials and JS/CSS to provide you with a badge-list interface, better badge category support, possibility to order your categories and badge inside them easily, etc...
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module AdHonorem
|
2
|
+
# Handle event and hook system
|
3
|
+
module HookingConcern
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods # :nodoc:
|
7
|
+
# After all badges loading, @@hooks will look like
|
8
|
+
# {
|
9
|
+
# master_a_weapon: {
|
10
|
+
# 'ParameteredBadge' => [:checker_one, :checker_two],
|
11
|
+
# 'LegacyBadge' => [:a_checker],
|
12
|
+
# },
|
13
|
+
# other_event: {
|
14
|
+
# 'OtherBadgeResponder' => [:other_checker]
|
15
|
+
# }
|
16
|
+
# }
|
17
|
+
@@hooks = {}
|
18
|
+
|
19
|
+
def dispatch(user, event, params = nil)
|
20
|
+
params ||= {}
|
21
|
+
result = {}
|
22
|
+
|
23
|
+
@@hooks[event] ||= {}
|
24
|
+
@@hooks[event].each do |responder, registered_checkers|
|
25
|
+
badge = find_by(klass: responder).set_context(user)
|
26
|
+
registered_checkers.each do |checker|
|
27
|
+
res = badge.trigger(checker, params)
|
28
|
+
result[res] ||= []
|
29
|
+
result[res] << "#{responder}##{checker}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
result
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def hook(event, params = nil)
|
39
|
+
params ||= {}
|
40
|
+
@@hooks[event] ||= {}
|
41
|
+
@@hooks[event][name] ||= []
|
42
|
+
@@hooks[event][name] += [params[:to] || []].flatten.uniq
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module AdHonorem
|
2
|
+
# Concerning meta badges
|
3
|
+
module MetaConcern
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def meta?
|
7
|
+
!@sub_badges.empty?
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def add_sub_badge(badge_slug)
|
13
|
+
@sub_badges << badge_slug
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def trigger_meta(objective_slug, params)
|
19
|
+
@sub_badges.each do |sub_slug|
|
20
|
+
sub_badge = AdHonorem::Badge.find(sub_slug).set_context(@user)
|
21
|
+
next if sub_badge.complete? || !sub_badge.respond_to?(objective_slug)
|
22
|
+
sub_badge.trigger(objective_slug, params)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def complete_meta?
|
27
|
+
check_context
|
28
|
+
progress_meta(:global) == 100.0
|
29
|
+
end
|
30
|
+
|
31
|
+
def progress_meta(progress_type = :step)
|
32
|
+
check_context
|
33
|
+
|
34
|
+
res = @sub_badges.map do |sub_slug|
|
35
|
+
sub_badge = AdHonorem::Badge.find(sub_slug)
|
36
|
+
sub_badge.set_context(@user).progress(progress_type)
|
37
|
+
end
|
38
|
+
|
39
|
+
case progress_type
|
40
|
+
when :step
|
41
|
+
res
|
42
|
+
when :global
|
43
|
+
res.sum / @sub_badges.size
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def next_sub_badge
|
48
|
+
@sub_badges.each do |sub_slug|
|
49
|
+
sub = AdHonorem::Badge.find(sub_slug).set_context(@user)
|
50
|
+
return sub unless sub.complete?
|
51
|
+
end
|
52
|
+
last_sub_badge
|
53
|
+
end
|
54
|
+
|
55
|
+
def last_sub_badge
|
56
|
+
AdHonorem::Badge.find(@sub_badges.last).set_context(@user)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module AdHonorem
|
2
|
+
# Contains objective-related methods
|
3
|
+
module ObjectiveConcern
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
attr_reader :objectives
|
7
|
+
|
8
|
+
def add_objective(slug, name, description, amount_needed = 1)
|
9
|
+
# prevent crash when Badges are initialized before migrations were applied
|
10
|
+
return unless defined?(AdHonorem::Objective)
|
11
|
+
@objectives[slug] = AdHonorem::Objective.new(slug, name, description, amount_needed)
|
12
|
+
end
|
13
|
+
|
14
|
+
def objectives_count
|
15
|
+
objectives.keys.count
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module AdHonorem
|
2
|
+
module UserContextedConcern # :nodoc:
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
attr_reader :user
|
6
|
+
|
7
|
+
def set_context(user)
|
8
|
+
@user = user
|
9
|
+
self
|
10
|
+
end
|
11
|
+
|
12
|
+
def reload_context!
|
13
|
+
check_context
|
14
|
+
@user = AdHonorem.configuration.user_class.constantize.find(@user.id)
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def check_context
|
19
|
+
raise AdHonorem::NoContext, 'No context User has been set' unless @user
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -4,8 +4,10 @@ module Adhonorem
|
|
4
4
|
|
5
5
|
def copy_files
|
6
6
|
time = Time.zone.now.strftime('%Y%m%d%H%M')
|
7
|
-
|
8
|
-
|
7
|
+
progress_mig = "db/migrate/#{time}00_create_adhonorem_progress.rb"
|
8
|
+
achievement_mig = "db/migrate/#{time}01_create_adhonorem_achievement.rb"
|
9
|
+
template 'progress_migration.rb', progress_mig
|
10
|
+
template 'achievement_migration.rb', achievement_mig
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
@@ -1,24 +1,16 @@
|
|
1
1
|
module AdHonorem
|
2
2
|
# AdHonorem core class, must be inherited from
|
3
3
|
class Badge < ::StaticRecord::Base
|
4
|
+
include AdHonorem::UserContextedConcern
|
5
|
+
include AdHonorem::ObjectiveConcern
|
6
|
+
include AdHonorem::HookingConcern
|
7
|
+
include AdHonorem::MetaConcern
|
8
|
+
include AdHonorem::RewardConcern
|
9
|
+
|
4
10
|
table :badges
|
5
11
|
path Rails.root.join('app', 'models', 'badges', '**', '*.rb')
|
6
12
|
primary_key :slug
|
7
13
|
|
8
|
-
attr_reader :objectives, :user
|
9
|
-
|
10
|
-
# After all badges loading, @@hooks will look like
|
11
|
-
# {
|
12
|
-
# master_a_weapon: {
|
13
|
-
# 'ParameteredBadge' => [:checker_one, :checker_two],
|
14
|
-
# 'LegacyBadge' => [:a_checker],
|
15
|
-
# },
|
16
|
-
# other_event: {
|
17
|
-
# 'OtherBadgeResponder' => [:other_checker]
|
18
|
-
# }
|
19
|
-
# }
|
20
|
-
@@hooks = {}
|
21
|
-
|
22
14
|
def initialize
|
23
15
|
super
|
24
16
|
|
@@ -27,29 +19,6 @@ module AdHonorem
|
|
27
19
|
@objectives = {}
|
28
20
|
end
|
29
21
|
|
30
|
-
def set_context(user)
|
31
|
-
@user = user
|
32
|
-
self
|
33
|
-
end
|
34
|
-
|
35
|
-
def reload_context!
|
36
|
-
check_context
|
37
|
-
@user = AdHonorem.configuration.user_class.constantize.find(@user.id)
|
38
|
-
self
|
39
|
-
end
|
40
|
-
|
41
|
-
def add_reward; end
|
42
|
-
|
43
|
-
def add_objective(slug, name, description, amount_needed = 1)
|
44
|
-
# prevent crash when Badges are initialized before migrations were applied
|
45
|
-
return unless defined?(AdHonorem::Objective)
|
46
|
-
@objectives[slug] = AdHonorem::Objective.new(slug, name, description, amount_needed)
|
47
|
-
end
|
48
|
-
|
49
|
-
def objectives_count
|
50
|
-
objectives.keys.count
|
51
|
-
end
|
52
|
-
|
53
22
|
def progress(progress_type = :step)
|
54
23
|
check_context
|
55
24
|
return progress_meta(progress_type) if meta?
|
@@ -69,23 +38,6 @@ module AdHonorem
|
|
69
38
|
legacy || false
|
70
39
|
end
|
71
40
|
|
72
|
-
def self.dispatch(user, event, params = nil)
|
73
|
-
params ||= {}
|
74
|
-
result = {}
|
75
|
-
|
76
|
-
@@hooks[event] ||= {}
|
77
|
-
@@hooks[event].each do |responder, registered_checkers|
|
78
|
-
badge = find_by(klass: responder).set_context(user)
|
79
|
-
registered_checkers.each do |checker|
|
80
|
-
res = badge.trigger(checker, params)
|
81
|
-
result[res] ||= []
|
82
|
-
result[res] << "#{responder}##{checker}"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
result
|
87
|
-
end
|
88
|
-
|
89
41
|
def trigger(objective_slug, params = nil)
|
90
42
|
return trigger_meta(objective_slug, params || {}) if meta?
|
91
43
|
|
@@ -113,33 +65,13 @@ module AdHonorem
|
|
113
65
|
objective = objective_slug
|
114
66
|
unless objective.is_a?(AdHonorem::Objective)
|
115
67
|
objective = objectives[objective_slug]
|
116
|
-
|
68
|
+
err = "Objective #{objective_slug} could not be found"
|
69
|
+
raise ObjectiveNotFound, err unless objective
|
117
70
|
end
|
118
71
|
|
119
72
|
objective
|
120
73
|
end
|
121
74
|
|
122
|
-
def meta?
|
123
|
-
!@sub_badges.empty?
|
124
|
-
end
|
125
|
-
|
126
|
-
class << self
|
127
|
-
protected
|
128
|
-
|
129
|
-
def hook(event, params = nil)
|
130
|
-
params ||= {}
|
131
|
-
@@hooks[event] ||= {}
|
132
|
-
@@hooks[event][name] ||= []
|
133
|
-
@@hooks[event][name] += [params[:to] || []].flatten.uniq
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
protected
|
138
|
-
|
139
|
-
def add_sub_badge(badge_slug)
|
140
|
-
@sub_badges << badge_slug
|
141
|
-
end
|
142
|
-
|
143
75
|
private
|
144
76
|
|
145
77
|
def proceed(objective_slug, params)
|
@@ -180,54 +112,6 @@ module AdHonorem
|
|
180
112
|
achievement.done!
|
181
113
|
end
|
182
114
|
|
183
|
-
def trigger_meta(objective_slug, params)
|
184
|
-
@sub_badges.each do |sub_slug|
|
185
|
-
sub_badge = AdHonorem::Badge.find(sub_slug).set_context(@user)
|
186
|
-
next if sub_badge.complete? || !sub_badge.respond_to?(objective_slug)
|
187
|
-
sub_badge.trigger(objective_slug, params)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
def complete_meta?
|
192
|
-
check_context
|
193
|
-
progress_meta(:global) == 100.0
|
194
|
-
end
|
195
|
-
|
196
|
-
def progress_meta(progress_type = :step)
|
197
|
-
check_context
|
198
|
-
|
199
|
-
case progress_type
|
200
|
-
when :step
|
201
|
-
@sub_badges.map { |sub_slug| AdHonorem::Badge.find(sub_slug).set_context(@user).progress(progress_type) }
|
202
|
-
when :global
|
203
|
-
res = @sub_badges.map do |sub_slug|
|
204
|
-
AdHonorem::Badge.find(sub_slug).set_context(@user).progress(progress_type)
|
205
|
-
end
|
206
|
-
res.sum / @sub_badges.size
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def next_sub_badge
|
211
|
-
@sub_badges.each do |sub_slug|
|
212
|
-
sub = AdHonorem::Badge.find(sub_slug).set_context(@user)
|
213
|
-
return sub unless sub.complete?
|
214
|
-
end
|
215
|
-
last_sub_badge
|
216
|
-
end
|
217
|
-
|
218
|
-
def last_sub_badge
|
219
|
-
AdHonorem::Badge.find(@sub_badges.last).set_context(@user)
|
220
|
-
end
|
221
|
-
|
222
|
-
def reward
|
223
|
-
# @rewards.each do |reward|
|
224
|
-
# end
|
225
|
-
end
|
226
|
-
|
227
|
-
def check_context
|
228
|
-
raise AdHonorem::NoContext, 'No context User has been set' unless @user
|
229
|
-
end
|
230
|
-
|
231
115
|
columns slug: :string,
|
232
116
|
name: :string,
|
233
117
|
description: :string,
|
data/lib/adhonorem/railtie.rb
CHANGED
@@ -4,6 +4,12 @@ class Railtie < Rails::Railtie # :nodoc:
|
|
4
4
|
require 'adhonorem/models/objective'
|
5
5
|
require 'adhonorem/models/achievement'
|
6
6
|
require 'adhonorem/models/progress'
|
7
|
+
|
8
|
+
require 'adhonorem/concerns/user_contexted_concern'
|
9
|
+
require 'adhonorem/concerns/objective_concern'
|
10
|
+
require 'adhonorem/concerns/hooking_concern'
|
11
|
+
require 'adhonorem/concerns/meta_concern'
|
12
|
+
require 'adhonorem/concerns/reward_concern'
|
7
13
|
require 'adhonorem/models/badge'
|
8
14
|
|
9
15
|
ActiveSupport.run_load_hooks(:adhonorem, AdHonorem::Badge)
|
data/lib/adhonorem/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adhonorem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hugo Chevalier
|
@@ -136,7 +136,11 @@ dependencies:
|
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 0.46.0
|
139
|
-
description:
|
139
|
+
description: |2
|
140
|
+
A complete gamification gem designed for Ruby on Rails.
|
141
|
+
AdHonorem assumes that you want to manage the gamification of your
|
142
|
+
Rails application code-side, using Ruby files to represent your badges
|
143
|
+
rather than depending on entries stored in a database.
|
140
144
|
email:
|
141
145
|
- drakhaine@gmail.com
|
142
146
|
executables: []
|
@@ -152,6 +156,11 @@ files:
|
|
152
156
|
- app/views/layouts/adhonorem/application.html.erb
|
153
157
|
- config/routes.rb
|
154
158
|
- lib/adhonorem.rb
|
159
|
+
- lib/adhonorem/concerns/hooking_concern.rb
|
160
|
+
- lib/adhonorem/concerns/meta_concern.rb
|
161
|
+
- lib/adhonorem/concerns/objective_concern.rb
|
162
|
+
- lib/adhonorem/concerns/reward_concern.rb
|
163
|
+
- lib/adhonorem/concerns/user_contexted_concern.rb
|
155
164
|
- lib/adhonorem/engine.rb
|
156
165
|
- lib/adhonorem/exceptions.rb
|
157
166
|
- lib/adhonorem/generators/adhonorem_generator.rb
|
@@ -205,7 +214,7 @@ files:
|
|
205
214
|
- spec/test_app/db/migrate/20170103065400_create_adhonorem_progress.rb
|
206
215
|
- spec/test_app/db/migrate/20170103065401_create_adhonorem_achievement.rb
|
207
216
|
- spec/test_app/db/schema.rb
|
208
|
-
homepage:
|
217
|
+
homepage: https://github.com/hchevalier/adhonorem
|
209
218
|
licenses:
|
210
219
|
- MIT
|
211
220
|
metadata: {}
|