ballot_box 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010-2011 Aimbulance.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,96 @@
1
+ = BallotBox
2
+
3
+ The BallotBox gem enables visitors to vote for and against voteable objects
4
+
5
+ == Install
6
+
7
+ gem 'ballot_box'
8
+
9
+ rails generate ballot_box:install
10
+
11
+ == Usage
12
+
13
+ Use middleware with options:
14
+
15
+ # Initialize BallotBox and set its configurations.
16
+ config.app_middleware.use BallotBox::Manager do |config|
17
+ config.routes = { "/posts/votes" => "Post" }
18
+ end
19
+
20
+ Set voteable model:
21
+
22
+ class Post < ActiveRecord::Base
23
+ ballot_box :counter_cache => true
24
+ # ballot_box :counter_cache => :rating, :strategies => [:authenticated]
25
+ end
26
+
27
+ View (just send post request to configure route):
28
+
29
+ link_to 'Vote', "/posts/votes?id=#{@post.id}", :remote => true, :method => :post
30
+
31
+ == Strategies
32
+
33
+ Strategy - is no more a simple validation at the object vote.
34
+ Authenticated - check :voter attribute is not blank.
35
+
36
+ module BallotBox
37
+ module Strategies
38
+ class Authenticated < Base
39
+ validates_presence_of :voter
40
+ end
41
+ end
42
+ end
43
+
44
+ Write your own strategies:
45
+
46
+ class MyCustomStrategy < BallotBox::Strategies::Base
47
+ validate :check_visible, :check_unique_voter
48
+
49
+ protected
50
+
51
+ def check_visible
52
+ errors.add(:voteable, :invalid) unless voteable.visible?
53
+ end
54
+
55
+ def check_unique_voter
56
+ if vote.class.where(["voter_id = ? AND voter_type = ?", vote.voter_id, vote.voter_type]).exists?
57
+ errors.add(:voter, :taken)
58
+ end
59
+ end
60
+ end
61
+
62
+ class Post < ActiveRecord::Base
63
+ ballot_box :strategies => [:authenticated, 'MyCustomStrategy']
64
+ end
65
+
66
+ == Callbacks
67
+
68
+ Middleware callbacks:
69
+
70
+ BallotBox::Manager.before_vote do |env, vote|
71
+ vote.voter = env['warden'].user
72
+ #vote.errors.add(:voter, :empty)
73
+ end
74
+
75
+ BallotBox::Manager.after_vote do |env, vote|
76
+ Rails.logger.info(vote.to_xml)
77
+ end
78
+
79
+ ActiveRecord callbacks:
80
+
81
+ class Post < ActiveRecord::Base
82
+ ballot_box :counter_cache => true
83
+
84
+ before_vote :method_before
85
+ after_vote :method_after
86
+
87
+ def method_before
88
+ Rails.logger.info current_vote.to_xml
89
+ # To terminate register vote, just return false
90
+ # return false
91
+ end
92
+
93
+ def method_after
94
+
95
+ end
96
+ end
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require File.join(File.dirname(__FILE__), 'lib', 'ballot_box', 'version')
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => :test
9
+
10
+ desc 'Test the ballot_box plugin.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.libs << 'test'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = true
16
+ end
17
+
18
+ desc 'Generate documentation for the ballot_box plugin.'
19
+ Rake::RDocTask.new(:rdoc) do |rdoc|
20
+ rdoc.rdoc_dir = 'rdoc'
21
+ rdoc.title = 'BallotBox'
22
+ rdoc.options << '--line-numbers' << '--inline-source'
23
+ rdoc.rdoc_files.include('README')
24
+ rdoc.rdoc_files.include('lib/**/*.rb')
25
+ end
26
+
27
+ begin
28
+ require 'jeweler'
29
+ Jeweler::Tasks.new do |s|
30
+ s.name = "ballot_box"
31
+ s.version = BallotBox::VERSION.dup
32
+ s.summary = "The BallotBox gem enables visitors to vote for and against voteable objects"
33
+ s.description = "The BallotBox gem enables visitors to vote for and against voteable objects"
34
+ s.email = "galeta.igor@gmail.com"
35
+ s.homepage = "https://github.com/galetahub/ballot_box"
36
+ s.authors = ["Igor Galeta", "Pavlo Galeta"]
37
+ s.files = FileList["[A-Z]*", "{app,lib}/**/*"] - ["Gemfile"]
38
+ #s.extra_rdoc_files = FileList["[A-Z]*"]
39
+ end
40
+
41
+ Jeweler::GemcutterTasks.new
42
+ rescue LoadError
43
+ puts "Jeweler not available. Install it with: gem install jeweler"
44
+ end
@@ -0,0 +1,5 @@
1
+ module BallotBox
2
+ class Vote < ::ActiveRecord::Base
3
+ include BallotBox::Voting
4
+ end
5
+ end
@@ -0,0 +1,74 @@
1
+ module BallotBox
2
+ module Base
3
+ def self.included(base)
4
+ base.extend SingletonMethods
5
+ end
6
+
7
+ module SingletonMethods
8
+ #
9
+ # ballot_box :counter_cache => true,
10
+ # :strategies => [:authenticated]
11
+ #
12
+ def ballot_box(options = {})
13
+ extend ClassMethods
14
+ include InstanceMethods
15
+
16
+ options = { :strategies => [:authenticated] }.merge(options)
17
+
18
+ class_attribute :ballot_box_options, :instance_writer => false
19
+ self.ballot_box_options = options
20
+
21
+ has_many :votes,
22
+ :class_name => 'BallotBox::Vote',
23
+ :as => :voteable,
24
+ :dependent => :delete_all
25
+
26
+ attr_accessor :current_vote
27
+
28
+ define_ballot_box_callbacks :vote
29
+ end
30
+ end
31
+
32
+ module ClassMethods
33
+
34
+ def define_ballot_box_callbacks(*callbacks)
35
+ define_callbacks *[callbacks, {:terminator => "result == false"}].flatten
36
+ callbacks.each do |callback|
37
+ eval <<-end_callbacks
38
+ def before_#{callback}(*args, &blk)
39
+ set_callback(:#{callback}, :before, *args, &blk)
40
+ end
41
+ def after_#{callback}(*args, &blk)
42
+ set_callback(:#{callback}, :after, *args, &blk)
43
+ end
44
+ end_callbacks
45
+ end
46
+ end
47
+
48
+ def ballot_box_cached_column
49
+ if ballot_box_options[:counter_cache] == true
50
+ "votes_count"
51
+ elsif ballot_box_options[:counter_cache]
52
+ ballot_box_options[:counter_cache]
53
+ else
54
+ false
55
+ end
56
+ end
57
+
58
+ def ballot_box_strategies
59
+ @@ballot_box_strategies ||= ballot_box_options[:strategies].map { |st| BallotBox.load_strategy(st) }
60
+ end
61
+ end
62
+
63
+ module InstanceMethods
64
+
65
+ def ballot_box_cached_column
66
+ @ballot_box_cached_column ||= self.class.ballot_box_cached_column
67
+ end
68
+
69
+ def ballot_box_valid?(vote)
70
+ self.class.ballot_box_strategies.map { |st| st.new(self, vote) }.map(&:valid?).all?
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ module BallotBox
3
+ module Callbacks
4
+ # Hook to _run_callbacks asserting for conditions.
5
+ def _run_callbacks(kind, *args) #:nodoc:
6
+ options = args.last # Last callback arg MUST be a Hash
7
+
8
+ send("_#{kind}").each do |callback, conditions|
9
+ invalid = conditions.find do |key, value|
10
+ value.is_a?(Array) ? !value.include?(options[key]) : (value != options[key])
11
+ end
12
+
13
+ callback.call(*args) unless invalid
14
+ end
15
+ end
16
+
17
+ # A callback that runs before create vote
18
+ # Example:
19
+ # BallotBox::Manager.before_vote do |env, opts|
20
+ # end
21
+ #
22
+ def before_vote(options = {}, method = :push, &block)
23
+ raise BlockNotGiven unless block_given?
24
+ _before_vote.send(method, [block, options])
25
+ end
26
+
27
+ # Provides access to the callback array for before_vote
28
+ # :api: private
29
+ def _before_vote
30
+ @_before_vote ||= []
31
+ end
32
+
33
+ # A callback that runs after vote created
34
+ # Example:
35
+ # BallotBox::Manager.after_vote do |env, opts|
36
+ # end
37
+ #
38
+ def after_vote(options = {}, method = :push, &block)
39
+ raise BlockNotGiven unless block_given?
40
+ _after_vote.send(method, [block, options])
41
+ end
42
+
43
+ # Provides access to the callback array for before_vote
44
+ # :api: private
45
+ def _after_vote
46
+ @_after_vote ||= []
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ module BallotBox
3
+ class Config < Hash
4
+ # Creates an accessor that simply sets and reads a key in the hash:
5
+ #
6
+ # class Config < Hash
7
+ # hash_accessor :routes
8
+ # end
9
+ #
10
+ # config = Config.new
11
+ # config.routes = {'/posts/vote' => 'Post' }
12
+ # config[:routes] #=> {'/posts/vote' => 'Post' }
13
+ #
14
+ def self.hash_accessor(*names) #:nodoc:
15
+ names.each do |name|
16
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
17
+ def #{name}
18
+ self[:#{name}]
19
+ end
20
+
21
+ def #{name}=(value)
22
+ self[:#{name}] = value
23
+ end
24
+ METHOD
25
+ end
26
+ end
27
+
28
+ hash_accessor :routes
29
+
30
+ def initialize(other={})
31
+ merge!(other)
32
+ self[:routes] ||= { "/ballot_box/vote" => 'Class' }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+ require 'rails'
3
+ require 'ballot_box'
4
+
5
+ module BallotBox
6
+ class Engine < ::Rails::Engine
7
+ config.before_initialize do
8
+ ActiveSupport.on_load :active_record do
9
+ ::ActiveRecord::Base.send :include, BallotBox::Base
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+ module BallotBox
3
+ class Manager
4
+ extend BallotBox::Callbacks
5
+
6
+ attr_accessor :config
7
+
8
+ # Initialize the middleware. If a block is given, a BallotBox::Config is yielded so you can properly
9
+ # configure the BallotBox::Manager.
10
+ def initialize(app, options={})
11
+ options.symbolize_keys!
12
+
13
+ @app, @config = app, BallotBox::Config.new(options)
14
+ yield @config if block_given?
15
+ self
16
+ end
17
+
18
+ def call(env) # :nodoc:
19
+ if voting_path?(env['PATH_INFO']) && env["REQUEST_METHOD"] == "POST"
20
+ create(env)
21
+ else
22
+ @app.call(env)
23
+ end
24
+ end
25
+
26
+ # :api: private
27
+ def _run_callbacks(*args) #:nodoc:
28
+ self.class._run_callbacks(*args)
29
+ end
30
+
31
+ protected
32
+
33
+ def create(env, body = '', status = 500)
34
+ request = Rack::Request.new(env)
35
+ vote = BallotBox::Vote.new(:request => request)
36
+ vote.voteable_type = @config.routes[ request.path_info ]
37
+
38
+ _run_callbacks(:before_vote, env, vote)
39
+
40
+ body, status = vote.call
41
+
42
+ _run_callbacks(:after_vote, env, vote)
43
+
44
+ [status, {'Content-Type' => 'application/json', 'Content-Length' => body.size.to_s}, body]
45
+ end
46
+
47
+ def voting_path?(request_path)
48
+ return false if @config.routes.nil?
49
+
50
+ @config.routes.keys.any? do |route|
51
+ route == request_path
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,7 @@
1
+ module BallotBox
2
+ module Strategies
3
+ class Authenticated < Base
4
+ validates_presence_of :voter
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,26 @@
1
+ require 'active_model/validations'
2
+
3
+ module BallotBox
4
+ module Strategies
5
+ class Base
6
+ include ActiveModel::Validations
7
+
8
+ attr_accessor :voteable, :vote, :request
9
+
10
+ def initialize(voteable, vote)
11
+ @voteable = voteable
12
+ @vote = vote
13
+ @request = vote.request
14
+ end
15
+
16
+ def read_attribute_for_validation(key)
17
+ @vote[key]
18
+ end
19
+
20
+ # Returns the Errors object that holds all information about attribute error messages.
21
+ def errors
22
+ @vote.errors
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ # encoding: utf-8
2
+ module BallotBox
3
+ VERSION = "0.1.0".freeze
4
+ end
@@ -0,0 +1,133 @@
1
+ # encoding: utf-8
2
+ require 'ipaddr'
3
+ require "browser"
4
+
5
+ module BallotBox
6
+ module Voting
7
+ def self.included(base)
8
+ base.send :include, InstanceMethods
9
+ base.send :extend, ClassMethods
10
+ end
11
+
12
+ module ClassMethods
13
+ def self.extended(base)
14
+ base.class_eval do
15
+ # Associations
16
+ belongs_to :voteable, :polymorphic => true
17
+ belongs_to :voter, :polymorphic => true
18
+
19
+ # Validations
20
+ validates_presence_of :ip_address, :user_agent, :voteable_id, :voteable_type
21
+ validates_numericality_of :value, :only_integer => true
22
+
23
+ # Callbacks
24
+ before_save :parse_browser
25
+ after_save :update_cached_columns
26
+ after_destroy :update_cached_columns
27
+
28
+ attr_accessible :request
29
+
30
+ composed_of :ip,
31
+ :class_name => 'IPAddr',
32
+ :mapping => %w(ip_address to_i),
33
+ :constructor => Proc.new { |ip_address| IPAddr.new(ip_address, Socket::AF_INET) },
34
+ :converter => Proc.new { |value| value.is_a?(Integer) ? IPAddr.new(value, Socket::AF_INET) : IPAddr.new(value.to_s) }
35
+
36
+ scope :with_voteable, lambda { |record| where(["voteable_id = ? AND voteable_type = ?", record.id, record.class.name]) }
37
+ end
38
+ end
39
+
40
+ def chart(mode)
41
+ result = case mode.to_s.downcase
42
+ when 'dates' then chart_dates
43
+ when 'browsers' then chart_browsers
44
+ when 'platforms' then chart_platforms
45
+ end
46
+
47
+ [ result ].to_json
48
+ end
49
+
50
+ protected
51
+
52
+ def chart_dates
53
+ data = scoped.select("DATE(created_at) AS created_at, SUM(value) AS rating").group("DATE(created_at)").all
54
+ data.collect { |item| [ item.created_at, item.rating.to_i ] }
55
+ end
56
+
57
+ def chart_browsers
58
+ data = scoped.select("browser_name, SUM(value) AS rating").group("browser_name").all
59
+ data.collect { |item| [ item.browser_name, item.rating.to_i ] }
60
+ end
61
+
62
+ def chart_platforms
63
+ data = scoped.select("browser_platform, SUM(value) AS rating").group("browser_platform").all
64
+ data.collect { |item| [ item.browser_platform, item.rating.to_i ] }
65
+ end
66
+ end
67
+
68
+ module InstanceMethods
69
+
70
+ def browser
71
+ @browser ||= Browser.new(:ua => user_agent, :accept_language => "en-us")
72
+ end
73
+
74
+ def anonymous?
75
+ voter.nil?
76
+ end
77
+
78
+ def as_json(options = nil)
79
+ options = {
80
+ :methods => [:ip],
81
+ :only => [:referrer, :value, :browser_version, :browser_name, :user_agent, :browser_platform ]
82
+ }.merge(options || {})
83
+
84
+ super
85
+ end
86
+
87
+ def request
88
+ @request
89
+ end
90
+
91
+ def request=(req)
92
+ self.ip = req.ip
93
+ self.user_agent = req.user_agent
94
+ self.referrer = req.referer
95
+ self.voteable_id = req.params["id"]
96
+ @request = req
97
+ end
98
+
99
+ def call
100
+ if register
101
+ [self.to_json, 200]
102
+ else
103
+ [self.errors.to_json, 422]
104
+ end
105
+ end
106
+
107
+ def register
108
+ if voteable && voteable.ballot_box_valid?(self)
109
+ voteable.current_vote = self
110
+
111
+ voteable.run_callbacks(:vote) do
112
+ errors.empty? && save
113
+ end
114
+ end
115
+ end
116
+
117
+ protected
118
+
119
+ def parse_browser
120
+ self.browser_name = browser.id.to_s
121
+ self.browser_version = browser.version
122
+ self.browser_platform = browser.platform.to_s
123
+ end
124
+
125
+ def update_cached_columns
126
+ if voteable && voteable.ballot_box_cached_column
127
+ count = voteable.votes.select("SUM(value)")
128
+ voteable.class.update_all("#{voteable.ballot_box_cached_column} = (#{count.to_sql})", ["id = ?", voteable.id])
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
data/lib/ballot_box.rb ADDED
@@ -0,0 +1,26 @@
1
+ module BallotBox
2
+ autoload :Voting, 'ballot_box/voting'
3
+ autoload :Manager, 'ballot_box/manager'
4
+ autoload :Config, 'ballot_box/config'
5
+ autoload :Callbacks, 'ballot_box/callbacks'
6
+ autoload :Base, 'ballot_box/base'
7
+
8
+ module Strategies
9
+ autoload :Base, 'ballot_box/strategies/base'
10
+ autoload :Authenticated, 'ballot_box/strategies/authenticated'
11
+ end
12
+
13
+ def self.table_name_prefix
14
+ 'ballot_box_'
15
+ end
16
+
17
+ def self.load_strategy(name)
18
+ case name.class.name
19
+ when "Symbol" then "BallotBox::Strategies::#{name.to_s.classify}".constantize
20
+ when "String" then name.classify.constantize
21
+ else name
22
+ end
23
+ end
24
+ end
25
+
26
+ require 'ballot_box/engine' if defined?(Rails)
@@ -0,0 +1,7 @@
1
+ Usage:
2
+ rails generate ballot_box:install
3
+
4
+ Options:
5
+
6
+ Example:
7
+ rails g ballot_box:install
@@ -0,0 +1,31 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ module BallotBox
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+
9
+ desc "Create ballot_box migration"
10
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
11
+
12
+ # copy migration files
13
+ def create_migrations
14
+ migration_template "migrate/create_votes.rb", File.join('db/migrate', "ballot_box_create_votes.rb")
15
+ end
16
+
17
+ def self.next_migration_number(dirname)
18
+ if ActiveRecord::Base.timestamped_migrations
19
+ current_time.utc.strftime("%Y%m%d%H%M%S")
20
+ else
21
+ "%.3d" % (current_migration_number(dirname) + 1)
22
+ end
23
+ end
24
+
25
+ def self.current_time
26
+ @current_time ||= Time.now
27
+ @current_time += 1.minute
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ class BallotBoxCreateVotes < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :ballot_box_votes do |t|
4
+ # Voter
5
+ t.string :voter_type, :limit => 40
6
+ t.integer :voter_id
7
+
8
+ # Voteable
9
+ t.string :voteable_type, :limit => 40
10
+ t.integer :voteable_id
11
+
12
+ # User info
13
+ t.integer :ip_address, :limit => 8
14
+ t.string :user_agent
15
+ t.string :referrer
16
+ t.string :browser_name, :limit => 40
17
+ t.string :browser_version, :limit => 15
18
+ t.string :browser_platform, :limit => 15
19
+
20
+ # Vote value
21
+ t.integer :value, :default => 1
22
+
23
+ t.timestamps
24
+ end
25
+
26
+ add_index :ballot_box_votes, [:voter_type, :voter_id]
27
+ add_index :ballot_box_votes, [:voteable_type, :voteable_id]
28
+ add_index :ballot_box_votes, :ip_address
29
+ end
30
+
31
+ def self.down
32
+ drop_table :ballot_box_votes
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ballot_box
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Igor Galeta
14
+ - Pavlo Galeta
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-05-18 00:00:00 +03:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ type: :runtime
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 31
30
+ segments:
31
+ - 0
32
+ - 1
33
+ - 2
34
+ version: 0.1.2
35
+ name: browser
36
+ version_requirements: *id001
37
+ prerelease: false
38
+ - !ruby/object:Gem::Dependency
39
+ type: :runtime
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ name: activemodel
50
+ version_requirements: *id002
51
+ prerelease: false
52
+ description: The BallotBox gem enables visitors to vote for and against voteable objects
53
+ email: galeta.igor@gmail.com
54
+ executables: []
55
+
56
+ extensions: []
57
+
58
+ extra_rdoc_files:
59
+ - LICENSE
60
+ - README.rdoc
61
+ files:
62
+ - LICENSE
63
+ - README.rdoc
64
+ - Rakefile
65
+ - app/models/ballot_box/vote.rb
66
+ - lib/ballot_box.rb
67
+ - lib/ballot_box/base.rb
68
+ - lib/ballot_box/callbacks.rb
69
+ - lib/ballot_box/config.rb
70
+ - lib/ballot_box/engine.rb
71
+ - lib/ballot_box/manager.rb
72
+ - lib/ballot_box/strategies/authenticated.rb
73
+ - lib/ballot_box/strategies/base.rb
74
+ - lib/ballot_box/version.rb
75
+ - lib/ballot_box/voting.rb
76
+ - lib/generators/ballot_box/USAGE
77
+ - lib/generators/ballot_box/install_generator.rb
78
+ - lib/generators/ballot_box/templates/migrate/create_votes.rb
79
+ has_rdoc: true
80
+ homepage: https://github.com/galetahub/ballot_box
81
+ licenses: []
82
+
83
+ post_install_message:
84
+ rdoc_options: []
85
+
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 3
94
+ segments:
95
+ - 0
96
+ version: "0"
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ hash: 3
103
+ segments:
104
+ - 0
105
+ version: "0"
106
+ requirements: []
107
+
108
+ rubyforge_project:
109
+ rubygems_version: 1.6.2
110
+ signing_key:
111
+ specification_version: 3
112
+ summary: The BallotBox gem enables visitors to vote for and against voteable objects
113
+ test_files: []
114
+