badgeable 0.0.1 → 0.1.1
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.
- 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
|