treasure_hunt 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +129 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/lib/generators/treasure_hunt/install/install_generator.rb +33 -0
- data/lib/generators/treasure_hunt/install/templates/achievement.rb +3 -0
- data/lib/generators/treasure_hunt/install/templates/migration.rb +22 -0
- data/lib/generators/treasure_hunt/install/templates/reward.rb +3 -0
- data/lib/treasure_hunt/achievement.rb +57 -0
- data/lib/treasure_hunt/reward.rb +20 -0
- data/lib/treasure_hunt/treasure_hunter.rb +56 -0
- data/lib/treasure_hunt.rb +5 -0
- data/spec/generators/treasure_hunt/install/install_generator_spec.rb +41 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/active_record.rb +38 -0
- data/spec/treasure_hunt/achievement_spec.rb +82 -0
- data/spec/treasure_hunt/reward_spec.rb +22 -0
- data/spec/treasure_hunt/treasure_hunter_spec.rb +46 -0
- metadata +195 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.9.2-p290@treasure_hunt_gem --create
|
data/Gemfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
gem "activerecord"
|
7
|
+
|
8
|
+
# Add dependencies to develop your gem here.
|
9
|
+
# Include everything needed to run rake, tests, features, etc.
|
10
|
+
group :development do
|
11
|
+
gem "guard"
|
12
|
+
gem "guard-rspec"
|
13
|
+
gem "rb-inotify"
|
14
|
+
gem "libnotify"
|
15
|
+
|
16
|
+
gem "rspec", "~> 2.5.0"
|
17
|
+
gem "generator_spec"
|
18
|
+
gem "bundler", "~> 1.0.0"
|
19
|
+
gem "jeweler", "~> 1.6.4"
|
20
|
+
gem "rcov", ">= 0"
|
21
|
+
gem "sqlite3"
|
22
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
actionmailer (3.1.1)
|
5
|
+
actionpack (= 3.1.1)
|
6
|
+
mail (~> 2.3.0)
|
7
|
+
actionpack (3.1.1)
|
8
|
+
activemodel (= 3.1.1)
|
9
|
+
activesupport (= 3.1.1)
|
10
|
+
builder (~> 3.0.0)
|
11
|
+
erubis (~> 2.7.0)
|
12
|
+
i18n (~> 0.6)
|
13
|
+
rack (~> 1.3.2)
|
14
|
+
rack-cache (~> 1.1)
|
15
|
+
rack-mount (~> 0.8.2)
|
16
|
+
rack-test (~> 0.6.1)
|
17
|
+
sprockets (~> 2.0.2)
|
18
|
+
activemodel (3.1.1)
|
19
|
+
activesupport (= 3.1.1)
|
20
|
+
builder (~> 3.0.0)
|
21
|
+
i18n (~> 0.6)
|
22
|
+
activerecord (3.1.1)
|
23
|
+
activemodel (= 3.1.1)
|
24
|
+
activesupport (= 3.1.1)
|
25
|
+
arel (~> 2.2.1)
|
26
|
+
tzinfo (~> 0.3.29)
|
27
|
+
activeresource (3.1.1)
|
28
|
+
activemodel (= 3.1.1)
|
29
|
+
activesupport (= 3.1.1)
|
30
|
+
activesupport (3.1.1)
|
31
|
+
multi_json (~> 1.0)
|
32
|
+
arel (2.2.1)
|
33
|
+
builder (3.0.0)
|
34
|
+
diff-lcs (1.1.3)
|
35
|
+
erubis (2.7.0)
|
36
|
+
ffi (1.0.10)
|
37
|
+
generator_spec (0.8.4)
|
38
|
+
rails (>= 3.0, < 4.0)
|
39
|
+
rspec-rails
|
40
|
+
git (1.2.5)
|
41
|
+
guard (0.8.7)
|
42
|
+
thor (~> 0.14.6)
|
43
|
+
guard-rspec (0.5.0)
|
44
|
+
guard (>= 0.8.4)
|
45
|
+
hike (1.2.1)
|
46
|
+
i18n (0.6.0)
|
47
|
+
jeweler (1.6.4)
|
48
|
+
bundler (~> 1.0)
|
49
|
+
git (>= 1.2.5)
|
50
|
+
rake
|
51
|
+
json (1.6.1)
|
52
|
+
libnotify (0.5.7)
|
53
|
+
mail (2.3.0)
|
54
|
+
i18n (>= 0.4.0)
|
55
|
+
mime-types (~> 1.16)
|
56
|
+
treetop (~> 1.4.8)
|
57
|
+
mime-types (1.16)
|
58
|
+
multi_json (1.0.3)
|
59
|
+
polyglot (0.3.2)
|
60
|
+
rack (1.3.5)
|
61
|
+
rack-cache (1.1)
|
62
|
+
rack (>= 0.4)
|
63
|
+
rack-mount (0.8.3)
|
64
|
+
rack (>= 1.0.0)
|
65
|
+
rack-ssl (1.3.2)
|
66
|
+
rack
|
67
|
+
rack-test (0.6.1)
|
68
|
+
rack (>= 1.0)
|
69
|
+
rails (3.1.1)
|
70
|
+
actionmailer (= 3.1.1)
|
71
|
+
actionpack (= 3.1.1)
|
72
|
+
activerecord (= 3.1.1)
|
73
|
+
activeresource (= 3.1.1)
|
74
|
+
activesupport (= 3.1.1)
|
75
|
+
bundler (~> 1.0)
|
76
|
+
railties (= 3.1.1)
|
77
|
+
railties (3.1.1)
|
78
|
+
actionpack (= 3.1.1)
|
79
|
+
activesupport (= 3.1.1)
|
80
|
+
rack-ssl (~> 1.3.2)
|
81
|
+
rake (>= 0.8.7)
|
82
|
+
rdoc (~> 3.4)
|
83
|
+
thor (~> 0.14.6)
|
84
|
+
rake (0.9.2)
|
85
|
+
rb-inotify (0.8.8)
|
86
|
+
ffi (>= 0.5.0)
|
87
|
+
rcov (0.9.11)
|
88
|
+
rdoc (3.11)
|
89
|
+
json (~> 1.4)
|
90
|
+
rspec (2.5.0)
|
91
|
+
rspec-core (~> 2.5.0)
|
92
|
+
rspec-expectations (~> 2.5.0)
|
93
|
+
rspec-mocks (~> 2.5.0)
|
94
|
+
rspec-core (2.5.2)
|
95
|
+
rspec-expectations (2.5.0)
|
96
|
+
diff-lcs (~> 1.1.2)
|
97
|
+
rspec-mocks (2.5.0)
|
98
|
+
rspec-rails (2.5.0)
|
99
|
+
actionpack (~> 3.0)
|
100
|
+
activesupport (~> 3.0)
|
101
|
+
railties (~> 3.0)
|
102
|
+
rspec (~> 2.5.0)
|
103
|
+
sprockets (2.0.3)
|
104
|
+
hike (~> 1.2)
|
105
|
+
rack (~> 1.0)
|
106
|
+
tilt (~> 1.1, != 1.3.0)
|
107
|
+
sqlite3 (1.3.4)
|
108
|
+
thor (0.14.6)
|
109
|
+
tilt (1.3.3)
|
110
|
+
treetop (1.4.10)
|
111
|
+
polyglot
|
112
|
+
polyglot (>= 0.3.1)
|
113
|
+
tzinfo (0.3.30)
|
114
|
+
|
115
|
+
PLATFORMS
|
116
|
+
ruby
|
117
|
+
|
118
|
+
DEPENDENCIES
|
119
|
+
activerecord
|
120
|
+
bundler (~> 1.0.0)
|
121
|
+
generator_spec
|
122
|
+
guard
|
123
|
+
guard-rspec
|
124
|
+
jeweler (~> 1.6.4)
|
125
|
+
libnotify
|
126
|
+
rb-inotify
|
127
|
+
rcov
|
128
|
+
rspec (~> 2.5.0)
|
129
|
+
sqlite3
|
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Jan Dupal
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= treasure_hunt
|
2
|
+
|
3
|
+
DSL and models for application User's Reward management.
|
4
|
+
|
5
|
+
== Contributing to treasure_hunt
|
6
|
+
|
7
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
9
|
+
* Fork the project
|
10
|
+
* Start a feature/bugfix branch
|
11
|
+
* Commit and push until you are happy with your contribution
|
12
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2011 Jan Dupal. See LICENSE.txt for
|
18
|
+
further details.
|
19
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "treasure_hunt"
|
18
|
+
gem.homepage = "http://github.com/SmartMedia/treasure_hunt"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{DSL and models for application User’s Reward management}
|
21
|
+
gem.description = %Q{Allow your application users to start fantastic hunt for big treasure}
|
22
|
+
gem.email = "dupal.j@gmail.com"
|
23
|
+
gem.authors = ["Jan Dupal"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => :spec
|
40
|
+
|
41
|
+
require 'rake/rdoctask'
|
42
|
+
Rake::RDocTask.new do |rdoc|
|
43
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
44
|
+
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
46
|
+
rdoc.title = "treasure_hunt #{version}"
|
47
|
+
rdoc.rdoc_files.include('README*')
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
49
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/active_record'
|
3
|
+
|
4
|
+
module TreasureHunt
|
5
|
+
module Generators
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
7
|
+
include Rails::Generators::Migration
|
8
|
+
|
9
|
+
desc 'Generates treasure_hunt models and migrations to User model'
|
10
|
+
|
11
|
+
def self.source_root
|
12
|
+
@source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.next_migration_number(path)
|
16
|
+
ActiveRecord::Generators::Base.next_migration_number(path)
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_migration
|
20
|
+
migration_template 'migration.rb', 'db/migrate/create_treasure_hunt_tables'
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate_models
|
24
|
+
template 'achievement.rb', 'app/models/achievement.rb'
|
25
|
+
template 'reward.rb', 'app/models/reward.rb'
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_acts_as_treasure_hunter
|
29
|
+
say "Please add 'acts_as_treasure_hunter' to your User model", :green
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class CreateTreasureHuntTables < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :achievements do |t|
|
4
|
+
t.references :user
|
5
|
+
t.references :reward
|
6
|
+
t.integer :points
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
add_index :achievements, :user_id
|
11
|
+
add_index :achievements, :reward_id
|
12
|
+
|
13
|
+
create_table :rewards do |t|
|
14
|
+
t.string :name
|
15
|
+
t.integer :points, :default => 0, :null => false
|
16
|
+
t.integer :every, :default => 0, :null => false
|
17
|
+
t.integer :limit, :default => 1, :null => false
|
18
|
+
|
19
|
+
t.timestamps
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module TreasureHunt
|
2
|
+
module Achievement
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
belongs_to :user
|
7
|
+
belongs_to :reward
|
8
|
+
|
9
|
+
validates_associated :user, :reward
|
10
|
+
validates_presence_of :user, :reward
|
11
|
+
|
12
|
+
validate :reward_cannot_be_achieved_above_limits
|
13
|
+
|
14
|
+
before_save :fill_points
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
module InstanceMethods
|
22
|
+
def fill_points
|
23
|
+
self.points = self.reward.points unless self.points
|
24
|
+
end
|
25
|
+
|
26
|
+
# TODO refactoring to Validator
|
27
|
+
def reward_cannot_be_achieved_above_limits
|
28
|
+
limit = self.reward.limit rescue 1.0/0
|
29
|
+
|
30
|
+
if self.find_all_similar_and_younger.size >= limit
|
31
|
+
errors.add(:reward, "can't achieve reward at current time")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def find_all_similar
|
36
|
+
ret = self.class.where(:user_id => self.user_id, :reward_id => self.reward_id).order('updated_at DESC')
|
37
|
+
ret = ret.where('id != ?', self.id) if self.id
|
38
|
+
|
39
|
+
ret
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_all_similar_and_younger
|
43
|
+
age = Time.now - self.reward.every rescue 0
|
44
|
+
|
45
|
+
find_all_similar.where('updated_at > ?', age)
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_all_recently_achieved
|
49
|
+
limit = self.reward.limit rescue 1.0/0 # Yep, that's Infinity
|
50
|
+
|
51
|
+
find_all_similar_and_younger.limit(limit)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module TreasureHunt
|
2
|
+
module Hunter
|
3
|
+
|
4
|
+
def acts_as_treasure_hunter
|
5
|
+
include TreasureHunt::Hunter::Model
|
6
|
+
end
|
7
|
+
|
8
|
+
module Model
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
has_many :achievements
|
13
|
+
has_many :rewards, :through => :achievements
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
module InstanceMethods
|
21
|
+
|
22
|
+
def points
|
23
|
+
self.achievements.collect(&:points).sum rescue 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def can_achieve?(reward)
|
27
|
+
reward = ::Reward.find_by_name(reward.to_s.humanize) if reward.is_a? Symbol
|
28
|
+
|
29
|
+
::Achievement.new(:user => self, :reward => reward).valid?
|
30
|
+
end
|
31
|
+
|
32
|
+
def achieve!(reward)
|
33
|
+
reward = ::Reward.find_by_name(reward.to_s.humanize) if reward.is_a? Symbol
|
34
|
+
achievement = ::Achievement.create(:reward => reward)
|
35
|
+
self.achievements << achievement
|
36
|
+
|
37
|
+
achievement
|
38
|
+
end
|
39
|
+
|
40
|
+
def time_to_unlock(reward)
|
41
|
+
reward = ::Reward.find_by_name(reward.to_s.humanize) if reward.is_a? Symbol
|
42
|
+
achievement = ::Achievement.new(:user => self, :reward => reward)
|
43
|
+
remaining = (achievement.find_all_recently_achieved.last.updated_at rescue DateTime.new ) + reward.every.seconds - DateTime.now
|
44
|
+
|
45
|
+
[0, remaining].max
|
46
|
+
end
|
47
|
+
|
48
|
+
def has_achievement?(reward)
|
49
|
+
reward = ::Reward.find_by_name(reward.to_s.humanize) if reward.is_a? Symbol
|
50
|
+
achievements.where(:reward_id => reward.id).any?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'action_controller'
|
3
|
+
require 'generator_spec/test_case'
|
4
|
+
|
5
|
+
require 'generators/treasure_hunt/install/install_generator'
|
6
|
+
|
7
|
+
describe TreasureHunt::Generators::InstallGenerator do
|
8
|
+
include GeneratorSpec::TestCase
|
9
|
+
destination File.expand_path('../../../../tmp', __FILE__)
|
10
|
+
|
11
|
+
before do
|
12
|
+
prepare_destination
|
13
|
+
run_generator
|
14
|
+
end
|
15
|
+
|
16
|
+
specify do
|
17
|
+
destination_root.should have_structure {
|
18
|
+
directory 'app' do
|
19
|
+
directory 'models' do
|
20
|
+
file 'achievement.rb' do
|
21
|
+
contains 'class Achievement'
|
22
|
+
end
|
23
|
+
|
24
|
+
file 'reward.rb' do
|
25
|
+
contains 'class Reward'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
directory 'db' do
|
31
|
+
directory 'migrate' do
|
32
|
+
migration 'create_treasure_hunt_tables' do
|
33
|
+
contains 'class CreateTreasureHuntTables'
|
34
|
+
contains 'create_table :achievements'
|
35
|
+
contains 'create_table :rewards'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
|
5
|
+
require 'active_record'
|
6
|
+
|
7
|
+
require 'treasure_hunt'
|
8
|
+
|
9
|
+
# Requires supporting files with custom matchers and macros, etc,
|
10
|
+
# in ./support/ and its subdirectories.
|
11
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
ActiveRecord::Base.establish_connection(
|
2
|
+
:adapter => "sqlite3",
|
3
|
+
:database => ":memory:"
|
4
|
+
)
|
5
|
+
|
6
|
+
ActiveRecord::Migration.verbose = false
|
7
|
+
|
8
|
+
ActiveRecord::Schema.define do
|
9
|
+
create_table :users, :force => true do |t|
|
10
|
+
t.string :name, :null => false
|
11
|
+
end
|
12
|
+
|
13
|
+
create_table :achievements, :force => true do |t|
|
14
|
+
t.references :user
|
15
|
+
t.references :reward
|
16
|
+
t.integer :points
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table :rewards, :force => true do |t|
|
21
|
+
t.string :name, :null => false
|
22
|
+
t.integer :points, :default => 0, :null => false
|
23
|
+
t.integer :every, :default => 0, :null => false
|
24
|
+
t.integer :limit, :default => 1, :null => false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class User < ActiveRecord::Base
|
29
|
+
acts_as_treasure_hunter
|
30
|
+
end
|
31
|
+
|
32
|
+
class Achievement < ActiveRecord::Base
|
33
|
+
include TreasureHunt::Achievement
|
34
|
+
end
|
35
|
+
|
36
|
+
class Reward < ActiveRecord::Base
|
37
|
+
include TreasureHunt::Reward
|
38
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TreasureHunt::Achievement do
|
4
|
+
before do
|
5
|
+
User.delete_all
|
6
|
+
Reward.delete_all
|
7
|
+
@joe = User.create(:name => 'Joe')
|
8
|
+
@win = Reward.create(:name => 'Win!', :points => 42)
|
9
|
+
end
|
10
|
+
|
11
|
+
context "when creating achievement" do
|
12
|
+
it "should validate foreign keys" do
|
13
|
+
achievement = Achievement.new
|
14
|
+
achievement.should_not be_valid
|
15
|
+
achievement.errors.should include(:user)
|
16
|
+
achievement.errors.should include(:reward)
|
17
|
+
achievement.errors.size.should == 2
|
18
|
+
|
19
|
+
achievement.user = @joe
|
20
|
+
achievement.should_not be_valid
|
21
|
+
achievement.errors.should include(:reward)
|
22
|
+
achievement.errors.size.should == 1
|
23
|
+
|
24
|
+
achievement.reward = @win
|
25
|
+
achievement.should be_valid
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have same points as reward" do
|
29
|
+
achievement = Achievement.create(:user => @joe, :reward => @win)
|
30
|
+
achievement.points.should == 42
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should not change points if set when creating" do
|
34
|
+
achievement = Achievement.create(:user => @joe, :reward => @win, :points => 13)
|
35
|
+
achievement.new_record?.should be_false
|
36
|
+
achievement.points.should == 13
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when validating if achievement is possible" do
|
41
|
+
before do
|
42
|
+
@no_limit = Reward.create(:name => 'No limit')
|
43
|
+
@one_per_day = Reward.create(:name => 'One per day', :every => 1.day, :limit => 1)
|
44
|
+
@three_per_day = Reward.create(:name => 'Three per day', :every => 1.day, :limit => 3)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should allow no-limit reward multiple times" do
|
48
|
+
5.times do
|
49
|
+
Achievement.create(:user => @joe, :reward => @no_limit).should be_valid
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not allow 2 one-per-day in the same day" do
|
54
|
+
first = Achievement.create(:user => @joe, :reward => @one_per_day)
|
55
|
+
first.should be_valid
|
56
|
+
|
57
|
+
second = Achievement.new(:user => @joe, :reward => @one_per_day)
|
58
|
+
second.should_not be_valid
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should allow 2 on-per-day after 1 day" do
|
62
|
+
first = Achievement.create(:user => @joe, :reward => @one_per_day, :created_at => 1.day.ago, :updated_at => 1.day.ago)
|
63
|
+
first.should be_valid
|
64
|
+
|
65
|
+
second = Achievement.create(:user => @joe, :reward => @one_per_day)
|
66
|
+
second.should be_valid
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should allow 3 three-per-day in the same day" do
|
70
|
+
3.times do
|
71
|
+
Achievement.create(:user => @joe, :reward => @three_per_day).should be_valid
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should not allow 4 three-per-day in the same day" do
|
76
|
+
3.times do
|
77
|
+
Achievement.create(:user => @joe, :reward => @three_per_day).should be_valid
|
78
|
+
end
|
79
|
+
Achievement.create(:user => @joe, :reward => @three_per_day).should_not be_valid
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Reward do
|
4
|
+
context "when creating reward" do
|
5
|
+
it "should validate presence of name" do
|
6
|
+
reward = Reward.new
|
7
|
+
reward.valid?.should be_false
|
8
|
+
reward.errors.should include(:name)
|
9
|
+
reward.errors.size.should == 1
|
10
|
+
|
11
|
+
reward.name = 'You won!'
|
12
|
+
reward.valid?.should be_true
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have default value 0 for :points, :every and 1 for :limit" do
|
16
|
+
reward = Reward.create(:name => 'Meaningless reward')
|
17
|
+
reward.points.should == 0
|
18
|
+
reward.limit.should == 1
|
19
|
+
reward.every.should == 0
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TreasureHunt::Hunter do
|
4
|
+
before do
|
5
|
+
@jane = User.create(:name => 'Jane')
|
6
|
+
@joe = User.create(:name => 'Joe')
|
7
|
+
end
|
8
|
+
|
9
|
+
context "when achieved something" do
|
10
|
+
before do
|
11
|
+
Reward.delete_all
|
12
|
+
(@reward = Reward.create(:name => 'Win!', :points => 7)).should be_valid
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have reward" do
|
16
|
+
@jane.achievements.create(:reward => @reward)
|
17
|
+
|
18
|
+
@jane.rewards.should =~ [@reward]
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should receive points" do
|
22
|
+
@jane.achievements.size.should == 0
|
23
|
+
3.times do
|
24
|
+
@jane.achievements << Achievement.create(:reward => @reward)
|
25
|
+
end
|
26
|
+
@jane.reload
|
27
|
+
@jane.points.should == 3*7
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when using DSL" do
|
32
|
+
before do
|
33
|
+
Reward.delete_all
|
34
|
+
@invite_friends = Reward.create(:name => 'Invite friends', :points => 50, :every => 1.day)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should achieve and lock reward" do
|
38
|
+
@jane.can_achieve?(:invite_friends).should be_true
|
39
|
+
@jane.achieve!(:invite_friends).should be_persisted
|
40
|
+
@jane.reload
|
41
|
+
@jane.points.should == 50
|
42
|
+
@jane.can_achieve?(:invite_friends).should be_false
|
43
|
+
@jane.time_to_unlock(:invite_friends).should <= 1.day
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: treasure_hunt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jan Dupal
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-23 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: &81214610 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *81214610
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: guard
|
27
|
+
requirement: &81214310 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *81214310
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: guard-rspec
|
38
|
+
requirement: &81213940 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *81213940
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rb-inotify
|
49
|
+
requirement: &81213050 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *81213050
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: libnotify
|
60
|
+
requirement: &81212530 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *81212530
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: &81212140 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 2.5.0
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *81212140
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: generator_spec
|
82
|
+
requirement: &81211840 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *81211840
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: bundler
|
93
|
+
requirement: &81211520 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ~>
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 1.0.0
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *81211520
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: jeweler
|
104
|
+
requirement: &81211190 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.6.4
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *81211190
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: rcov
|
115
|
+
requirement: &81210830 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *81210830
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: sqlite3
|
126
|
+
requirement: &81210500 !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: *81210500
|
135
|
+
description: Allow your application users to start fantastic hunt for big treasure
|
136
|
+
email: dupal.j@gmail.com
|
137
|
+
executables: []
|
138
|
+
extensions: []
|
139
|
+
extra_rdoc_files:
|
140
|
+
- LICENSE.txt
|
141
|
+
- README.rdoc
|
142
|
+
files:
|
143
|
+
- .document
|
144
|
+
- .rspec
|
145
|
+
- .rvmrc
|
146
|
+
- Gemfile
|
147
|
+
- Gemfile.lock
|
148
|
+
- Guardfile
|
149
|
+
- LICENSE.txt
|
150
|
+
- README.rdoc
|
151
|
+
- Rakefile
|
152
|
+
- VERSION
|
153
|
+
- lib/generators/treasure_hunt/install/install_generator.rb
|
154
|
+
- lib/generators/treasure_hunt/install/templates/achievement.rb
|
155
|
+
- lib/generators/treasure_hunt/install/templates/migration.rb
|
156
|
+
- lib/generators/treasure_hunt/install/templates/reward.rb
|
157
|
+
- lib/treasure_hunt.rb
|
158
|
+
- lib/treasure_hunt/achievement.rb
|
159
|
+
- lib/treasure_hunt/reward.rb
|
160
|
+
- lib/treasure_hunt/treasure_hunter.rb
|
161
|
+
- spec/generators/treasure_hunt/install/install_generator_spec.rb
|
162
|
+
- spec/spec_helper.rb
|
163
|
+
- spec/support/active_record.rb
|
164
|
+
- spec/treasure_hunt/achievement_spec.rb
|
165
|
+
- spec/treasure_hunt/reward_spec.rb
|
166
|
+
- spec/treasure_hunt/treasure_hunter_spec.rb
|
167
|
+
homepage: http://github.com/SmartMedia/treasure_hunt
|
168
|
+
licenses:
|
169
|
+
- MIT
|
170
|
+
post_install_message:
|
171
|
+
rdoc_options: []
|
172
|
+
require_paths:
|
173
|
+
- lib
|
174
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
175
|
+
none: false
|
176
|
+
requirements:
|
177
|
+
- - ! '>='
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
segments:
|
181
|
+
- 0
|
182
|
+
hash: 915069359
|
183
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
184
|
+
none: false
|
185
|
+
requirements:
|
186
|
+
- - ! '>='
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0'
|
189
|
+
requirements: []
|
190
|
+
rubyforge_project:
|
191
|
+
rubygems_version: 1.8.6
|
192
|
+
signing_key:
|
193
|
+
specification_version: 3
|
194
|
+
summary: DSL and models for application User’s Reward management
|
195
|
+
test_files: []
|