badgeable 0.0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +42 -0
- data/README.rdoc +35 -3
- data/Rakefile +2 -0
- data/badgeable.gemspec +26 -0
- data/features/award_badges.feature +9 -0
- data/features/step_definitions/badging_steps.rb +20 -0
- data/features/support/env.rb +19 -0
- data/features/support/test_models/diner.rb +5 -0
- data/features/support/test_models/meal.rb +5 -0
- data/lib/badgeable/award.rb +44 -0
- data/lib/badgeable/config.rb +5 -39
- data/lib/badgeable/dsl.rb +5 -0
- data/lib/badgeable/railtie.rb +8 -0
- data/lib/badgeable/subject.rb +14 -0
- data/lib/badgeable/version.rb +3 -0
- data/lib/badgeable.rb +5 -20
- metadata +82 -13
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
badgeable (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
builder (2.1.2)
|
10
|
+
cucumber (0.9.2)
|
11
|
+
builder (~> 2.1.2)
|
12
|
+
diff-lcs (~> 1.1.2)
|
13
|
+
gherkin (~> 2.2.5)
|
14
|
+
json (~> 1.4.6)
|
15
|
+
term-ansicolor (~> 1.0.5)
|
16
|
+
diff-lcs (1.1.2)
|
17
|
+
factory_girl (1.3.2)
|
18
|
+
gherkin (2.2.8)
|
19
|
+
json (~> 1.4.6)
|
20
|
+
term-ansicolor (~> 1.0.5)
|
21
|
+
json (1.4.6)
|
22
|
+
rspec (2.0.0.rc)
|
23
|
+
rspec-core (= 2.0.0.rc)
|
24
|
+
rspec-expectations (= 2.0.0.rc)
|
25
|
+
rspec-mocks (= 2.0.0.rc)
|
26
|
+
rspec-core (2.0.0.rc)
|
27
|
+
rspec-expectations (2.0.0.rc)
|
28
|
+
diff-lcs (>= 1.1.2)
|
29
|
+
rspec-mocks (2.0.0.rc)
|
30
|
+
rspec-core (= 2.0.0.rc)
|
31
|
+
rspec-expectations (= 2.0.0.rc)
|
32
|
+
term-ansicolor (1.0.5)
|
33
|
+
|
34
|
+
PLATFORMS
|
35
|
+
ruby
|
36
|
+
|
37
|
+
DEPENDENCIES
|
38
|
+
badgeable!
|
39
|
+
bundler (>= 1.0.0)
|
40
|
+
cucumber
|
41
|
+
factory_girl (>= 1.3.2)
|
42
|
+
rspec (>= 2.0.0.rc)
|
data/README.rdoc
CHANGED
@@ -15,10 +15,11 @@ and the name constant of the awarding class:
|
|
15
15
|
|
16
16
|
class Person
|
17
17
|
include Mongoid::Document
|
18
|
-
include Badgeable
|
18
|
+
include Badgeable::Subject
|
19
|
+
embeds_many :nachos
|
19
20
|
end
|
20
21
|
|
21
|
-
badge "
|
22
|
+
badge "Nacho Nacho Man" do
|
22
23
|
thing Nacho
|
23
24
|
count 40
|
24
25
|
subject :person
|
@@ -27,7 +28,28 @@ and the name constant of the awarding class:
|
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
|
-
would award the "
|
31
|
+
would award the "Nacho Nacho Man" badge to each Person who eats 40
|
32
|
+
nachos, and the last one was spicy.
|
33
|
+
|
34
|
+
class Person
|
35
|
+
include Mongoid::Document
|
36
|
+
include Badgeable::Subject
|
37
|
+
references_many :meals
|
38
|
+
end
|
39
|
+
|
40
|
+
badge "Fancy Pants" do
|
41
|
+
thing Meal
|
42
|
+
subject :person
|
43
|
+
count
|
44
|
+
Meal.where(:price_cents.gte => 10000).count >= 12
|
45
|
+
end
|
46
|
+
conditions do |meal|
|
47
|
+
meal.restaurant.city != meal.eater.city
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
would award the "Fancy Pants" badge to the diner who has eaten 12
|
52
|
+
expensive meals where the awarding meal was out of town.
|
31
53
|
|
32
54
|
You can also award arbitrary badges using your own business logic by
|
33
55
|
calling #award_badge(badge_name) on any Badgeable instance:
|
@@ -35,6 +57,16 @@ calling #award_badge(badge_name) on any Badgeable instance:
|
|
35
57
|
yehuda = Person.create(:name => "Yehuda Katz")
|
36
58
|
yehuda.award_badge("Total Badass")
|
37
59
|
|
60
|
+
== Setup
|
61
|
+
|
62
|
+
Badge recipient classes should include Badgeable::Subject.
|
63
|
+
Extending an awarding class with Badgeable::Award will allow you
|
64
|
+
to define badge blocks in the awarding class definition. You may
|
65
|
+
also eval a separate file of badge definitions in the context of
|
66
|
+
Badgeable::Award.
|
67
|
+
|
68
|
+
When used with Rails, Badgeable will look for badging definitions
|
69
|
+
in Rails.root/lib/badges.rb
|
38
70
|
|
39
71
|
== Requirements
|
40
72
|
|
data/Rakefile
ADDED
data/badgeable.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path("../lib/badgeable/version", __FILE__)
|
3
|
+
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "badgeable"
|
7
|
+
s.version = Badgeable::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Scott Burton"]
|
10
|
+
s.email = ["scottburton11@gmail.com"]
|
11
|
+
s.homepage = "http://rubygems.org/gems/badgeable"
|
12
|
+
s.summary = "Badgeable is an elegant DSL for awarding badges"
|
13
|
+
s.description = "Badgeable provides an elegant DSL for describing and awarding badges to your Ruby objects."
|
14
|
+
|
15
|
+
s.required_rubygems_version = ">= 1.3.6"
|
16
|
+
s.rubyforge_project = "badgeable"
|
17
|
+
|
18
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
19
|
+
s.add_development_dependency "rspec", ">= 2.0.0.rc"
|
20
|
+
s.add_development_dependency "cucumber"
|
21
|
+
s.add_development_dependency "factory_girl", ">= 1.3.2"
|
22
|
+
|
23
|
+
s.files = `git ls-files`.split("\n")
|
24
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
25
|
+
s.require_path = 'lib'
|
26
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Feature: Easily award badges to any Ruby class (given enough effort on your part)
|
2
|
+
In order to make somebody feel super awesome about themselves
|
3
|
+
A class that extends Badgeable::Award
|
4
|
+
Wants to award a badge recipient after they've created a certain number of them
|
5
|
+
|
6
|
+
Scenario: A restaurant meal awards the "Hog Wild" badge to a regular diner
|
7
|
+
Given a Meal awards the "Hog Wild" badge to an Diner after 3 times
|
8
|
+
When a diner creates 3 meals
|
9
|
+
Then the diner should have the "Hog Wild" badge
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Given /^a Meal awards the "([^\"]*)" badge to an? Diner after (\d+) times$/ do |badge_name, threshold|
|
2
|
+
Meal.class_eval %Q{
|
3
|
+
badge "#{badge_name}" do
|
4
|
+
count #{threshold}
|
5
|
+
subject :diner
|
6
|
+
thing Meal
|
7
|
+
end
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
When /^a diner creates (\d+) meals$/ do |num|
|
12
|
+
@diner = Diner.create
|
13
|
+
num.to_i.times do
|
14
|
+
@diner.meals.create
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Then /^the diner should have the "([^\"]*)" badge$/ do |badge_name|
|
19
|
+
@diner.should have_badge_named(badge_name)
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__),'..', '..', 'lib'))
|
3
|
+
|
4
|
+
require 'cucumber'
|
5
|
+
require 'rspec/expectations'
|
6
|
+
require 'badgeable'
|
7
|
+
|
8
|
+
Mongoid.configure do |config|
|
9
|
+
config.master = Mongo::Connection.new.db("badgeable_test")
|
10
|
+
end
|
11
|
+
|
12
|
+
# factory_girl Factory definitions
|
13
|
+
Dir[(File.expand_path(File.dirname(__FILE__), "..") + "spec/factories/**/*.rb").to_s].each {|factory| require factory}
|
14
|
+
|
15
|
+
Dir[(File.expand_path(File.dirname(__FILE__)) + "test_models/**/*.rb")].each {|model| require model }
|
16
|
+
|
17
|
+
Before do
|
18
|
+
Mongoid.master.collections.select{|c| !c.name.starts_with?("system")}.each(&:drop)
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Badgeable
|
2
|
+
module Award
|
3
|
+
# Configure a class to automatically award badges after creation.
|
4
|
+
# Assign a badge name and a block with configuration
|
5
|
+
# directives.
|
6
|
+
#
|
7
|
+
# Valid directives:
|
8
|
+
#
|
9
|
+
# thing (Required) a class constant in this namespace that
|
10
|
+
# awards the badge.
|
11
|
+
# subject (Optional, default = :user) a symbol that references
|
12
|
+
# the object to which the badge is awarded. This should
|
13
|
+
# be a related object that includes Badgeable, and will
|
14
|
+
# usually have referenced_in :thing, belongs_to :thing etc.
|
15
|
+
# count (Optional, default = 1) either an integer threshold value
|
16
|
+
# of :things related to :subject, or a block. If a block
|
17
|
+
# is given, the created instance of :thing is passed as
|
18
|
+
# the first block argument, and the block must return
|
19
|
+
# return true for the badge to be awarded.
|
20
|
+
# conditions (Optional) provide a block; if your block returns
|
21
|
+
# returns true, the badge is awarded. The first block
|
22
|
+
# argument is the created instance of :thing. The
|
23
|
+
# conditions directive may be called any number of times,
|
24
|
+
# and all conditions and the count block must return true.
|
25
|
+
# Also note that the conditions and count directives are
|
26
|
+
# evaluated separately.
|
27
|
+
#
|
28
|
+
# See README for usage examples
|
29
|
+
#
|
30
|
+
def badge(name, &block)
|
31
|
+
config = Badgeable::Config.new
|
32
|
+
config.instance_eval(&block)
|
33
|
+
method_name = name.titleize.gsub(/\s/, "").underscore
|
34
|
+
config.klass.class_eval do
|
35
|
+
set_callback :create, :after, "award_#{method_name}_badge".to_sym
|
36
|
+
define_method "award_#{method_name}_badge".to_sym, Proc.new {
|
37
|
+
if config.conditions_array.all? {|p| p.call(self) }
|
38
|
+
self.send(config.subject_name).award_badge(name)
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/badgeable/config.rb
CHANGED
@@ -1,42 +1,10 @@
|
|
1
1
|
module Badgeable
|
2
2
|
class Config
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
#
|
7
|
-
# Valid directives:
|
8
|
-
#
|
9
|
-
# thing (Required) a class constant in this namespace that
|
10
|
-
# awards the badge.
|
11
|
-
# subject (Optional, default = :user) a symbol that references
|
12
|
-
# the object to which the badge is awarded. This should
|
13
|
-
# be a related object that includes Badgeable, and will
|
14
|
-
# usually have referenced_in :thing, belongs_to :thing etc.
|
15
|
-
# count (Optional, default = 1) either an integer threshold value
|
16
|
-
# of :things related to :subject, or a block. If a block
|
17
|
-
# is given, the created instance of :thing is passed as
|
18
|
-
# the first block argument, and the block must return
|
19
|
-
# return true for the badge to be awarded.
|
20
|
-
# conditions (Optional) provide a block; if your block returns
|
21
|
-
# returns true, the badge is awarded. Works in
|
22
|
-
# conjunction with #count
|
23
|
-
#
|
24
|
-
# See README for usage examples
|
25
|
-
#
|
26
|
-
def self.badge(name, &block)
|
27
|
-
config = new
|
28
|
-
config.instance_eval(&block)
|
29
|
-
method_name = name.titleize.gsub(/\s/, "").underscore
|
30
|
-
config.klass.class_eval do
|
31
|
-
set_callback :create, :after, "award_#{method_name}_badge".to_sym
|
32
|
-
define_method "award_#{method_name}_badge".to_sym, Proc.new {
|
33
|
-
if config.conditions_array.all? {|p| p.call(self) }
|
34
|
-
self.send(config.subject_name).award_badge(name)
|
35
|
-
end
|
36
|
-
}
|
37
|
-
end
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_accessor :badge_definitions
|
38
6
|
end
|
39
|
-
|
7
|
+
|
40
8
|
attr_reader :threshold, :klass, :conditions_array, :subject_name
|
41
9
|
|
42
10
|
def initialize
|
@@ -71,8 +39,6 @@ module Badgeable
|
|
71
39
|
@conditions_array << Proc.new {|instance|
|
72
40
|
block.call(instance)
|
73
41
|
}
|
74
|
-
end
|
75
|
-
|
76
|
-
|
42
|
+
end
|
77
43
|
end
|
78
44
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module Badgeable
|
2
|
+
class Railtie < ::Rails::Railtie
|
3
|
+
initializer "badgeable.load_badges" do
|
4
|
+
Badgeable::Config.badge_definitions = Pathname.new("#{Rails.root}/lib/badges.rb")
|
5
|
+
Badgeable::Dsl.class_eval(File.read(Badgeable::Config.badge_definitions))
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
data/lib/badgeable/subject.rb
CHANGED
@@ -14,5 +14,19 @@ module Badgeable
|
|
14
14
|
def has_badge_named?(name)
|
15
15
|
badges.map(&:name).include?(name)
|
16
16
|
end
|
17
|
+
|
18
|
+
def self.included(receiver)
|
19
|
+
receiver.class_eval %Q{
|
20
|
+
references_many :badges, :stored_as => :array, :class_name => "Badgeable::Badge", :inverse_of => :#{receiver.to_s.tableize}
|
21
|
+
}
|
22
|
+
|
23
|
+
Badgeable::Badge.class_eval %Q{
|
24
|
+
references_many :#{receiver.to_s.tableize}, :inverse_of => :badges, :stored_as => :array, :inverse_of => :badges
|
25
|
+
|
26
|
+
def recipients
|
27
|
+
#{receiver}.where(:badge_ids => id)
|
28
|
+
end
|
29
|
+
}
|
30
|
+
end
|
17
31
|
end
|
18
32
|
end
|
data/lib/badgeable.rb
CHANGED
@@ -2,27 +2,12 @@ require 'active_support/core_ext'
|
|
2
2
|
require 'active_support/callbacks'
|
3
3
|
require 'active_support/inflector'
|
4
4
|
require 'mongoid'
|
5
|
+
require 'badgeable/award'
|
5
6
|
require 'badgeable/badge'
|
6
7
|
require 'badgeable/config'
|
8
|
+
require 'badgeable/dsl'
|
7
9
|
require 'badgeable/subject'
|
10
|
+
require 'badgeable/version'
|
11
|
+
require 'badgeable/railtie' if defined?(Rails)
|
8
12
|
|
9
|
-
module Badgeable
|
10
|
-
|
11
|
-
VERSION = "0.0.1"
|
12
|
-
|
13
|
-
def self.included(receiver)
|
14
|
-
receiver.class_eval %Q{
|
15
|
-
references_many :badges, :stored_as => :array, :class_name => "Badgeable::Badge", :inverse_of => :#{receiver.to_s.tableize}
|
16
|
-
}
|
17
|
-
|
18
|
-
Badgeable::Badge.class_eval %Q{
|
19
|
-
references_many :#{receiver.to_s.tableize}, :inverse_of => :badges, :stored_as => :array, :inverse_of => :badges
|
20
|
-
|
21
|
-
def recipients
|
22
|
-
#{receiver}.where(:badge_ids => id)
|
23
|
-
end
|
24
|
-
}
|
25
|
-
|
26
|
-
receiver.send :include, Badgeable::Subject
|
27
|
-
end
|
28
|
-
end
|
13
|
+
module Badgeable; end
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: badgeable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 29
|
5
4
|
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 0
|
8
|
-
- 0
|
9
7
|
- 1
|
10
|
-
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Scott Burton
|
@@ -15,10 +14,68 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2010-10-
|
17
|
+
date: 2010-10-09 00:00:00 -07:00
|
19
18
|
default_executable:
|
20
|
-
dependencies:
|
21
|
-
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: bundler
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 0
|
31
|
+
- 0
|
32
|
+
version: 1.0.0
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rspec
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 2
|
45
|
+
- 0
|
46
|
+
- 0
|
47
|
+
- rc
|
48
|
+
version: 2.0.0.rc
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: cucumber
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
type: :development
|
63
|
+
version_requirements: *id003
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: factory_girl
|
66
|
+
prerelease: false
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 1
|
74
|
+
- 3
|
75
|
+
- 2
|
76
|
+
version: 1.3.2
|
77
|
+
type: :development
|
78
|
+
version_requirements: *id004
|
22
79
|
description: Badgeable provides an elegant DSL for describing and awarding badges to your Ruby objects.
|
23
80
|
email:
|
24
81
|
- scottburton11@gmail.com
|
@@ -29,14 +86,28 @@ extensions: []
|
|
29
86
|
extra_rdoc_files: []
|
30
87
|
|
31
88
|
files:
|
89
|
+
- .gitignore
|
90
|
+
- Gemfile
|
91
|
+
- Gemfile.lock
|
92
|
+
- LICENSE
|
93
|
+
- README.rdoc
|
94
|
+
- Rakefile
|
95
|
+
- badgeable.gemspec
|
96
|
+
- features/award_badges.feature
|
97
|
+
- features/step_definitions/badging_steps.rb
|
98
|
+
- features/support/env.rb
|
99
|
+
- features/support/test_models/diner.rb
|
100
|
+
- features/support/test_models/meal.rb
|
101
|
+
- lib/badgeable.rb
|
102
|
+
- lib/badgeable/award.rb
|
32
103
|
- lib/badgeable/badge.rb
|
33
104
|
- lib/badgeable/config.rb
|
105
|
+
- lib/badgeable/dsl.rb
|
106
|
+
- lib/badgeable/railtie.rb
|
34
107
|
- lib/badgeable/subject.rb
|
35
|
-
- lib/badgeable.rb
|
36
|
-
- LICENSE
|
37
|
-
- README.rdoc
|
108
|
+
- lib/badgeable/version.rb
|
38
109
|
has_rdoc: true
|
39
|
-
homepage: http://
|
110
|
+
homepage: http://rubygems.org/gems/badgeable
|
40
111
|
licenses: []
|
41
112
|
|
42
113
|
post_install_message:
|
@@ -49,7 +120,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
120
|
requirements:
|
50
121
|
- - ">="
|
51
122
|
- !ruby/object:Gem::Version
|
52
|
-
hash: 3
|
53
123
|
segments:
|
54
124
|
- 0
|
55
125
|
version: "0"
|
@@ -58,7 +128,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
128
|
requirements:
|
59
129
|
- - ">="
|
60
130
|
- !ruby/object:Gem::Version
|
61
|
-
hash: 23
|
62
131
|
segments:
|
63
132
|
- 1
|
64
133
|
- 3
|
@@ -66,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
135
|
version: 1.3.6
|
67
136
|
requirements: []
|
68
137
|
|
69
|
-
rubyforge_project:
|
138
|
+
rubyforge_project: badgeable
|
70
139
|
rubygems_version: 1.3.7
|
71
140
|
signing_key:
|
72
141
|
specification_version: 3
|