crowdfund_tr 1.0.0
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.
- checksums.yaml +7 -0
- data/LICENSE +7 -0
- data/README +18 -0
- data/bin/crowdfund +54 -0
- data/bin/tech_projects.csv +5 -0
- data/lib/crowdfund/die.rb +13 -0
- data/lib/crowdfund/fundable.rb +22 -0
- data/lib/crowdfund/funding_round.rb +25 -0
- data/lib/crowdfund/grant_project.rb +11 -0
- data/lib/crowdfund/groupfundrequest.rb +88 -0
- data/lib/crowdfund/match_project.rb +27 -0
- data/lib/crowdfund/pledge_pool.rb +15 -0
- data/lib/crowdfund/project.rb +56 -0
- data/spec/crowdfund/grant_project_spec.rb +20 -0
- data/spec/crowdfund/groupfundrequest_spec.rb +39 -0
- data/spec/crowdfund/match_project_spec.rb +47 -0
- data/spec/crowdfund/pledge_pool_spec.rb +43 -0
- data/spec/crowdfund/project_spec.rb +75 -0
- metadata +99 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: f6cfb4c115c9a9fe452030b678bc2e4d3438b378
|
|
4
|
+
data.tar.gz: 7d184cbf32505f0dad908ba9de3a2949cc1239f3
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: fac06f0fb7201af825d5eed58a8bd1fd70d867fb5de474a77d933f14e78dd4af7c473277cc75af5c753217c6f0c63630f1c8f8c348ca1e916656b5711447b74c
|
|
7
|
+
data.tar.gz: 2bf45f015b800e5f66f7c8de87c6c54a3575ce147373b71d8dd2ea15d832501a05dfeb518547e6a9491657b1c15e9c0b4ed42dc72ee7da759e4e55cacf1dc22f
|
data/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright (c) 2015 Todd Ruhlen
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
A simple, text-based crowdfunding simulator. Run a group of projects through a
|
|
2
|
+
series of funding rounds, in which they either receive or lose funds, or are
|
|
3
|
+
skipped. They also receive a random pledge. Grant projects never lose funds.
|
|
4
|
+
Match projects have all future funding matched after they reach half-funding.
|
|
5
|
+
Statistics are printed to the console at the end of the simulation.
|
|
6
|
+
|
|
7
|
+
The normal projects can be specified in a '.csv' file that is given as a command
|
|
8
|
+
line argument when loading the program, or the default projects can be used. The
|
|
9
|
+
format for 'csv' entries is Project Name,Goal,Initial_funding with a comma and
|
|
10
|
+
no spaces between entries and underscores in place of commas within larger
|
|
11
|
+
numbers (e.g. Your Project,10_000,0).
|
|
12
|
+
|
|
13
|
+
The option is given to save a list of underfunded projects upon exiting the
|
|
14
|
+
program. The list is saved in 'underfunded.txt' in the top-level folder of the
|
|
15
|
+
application.
|
|
16
|
+
|
|
17
|
+
Created as a bonus project while completing the Pragmatic Studio Ruby
|
|
18
|
+
Programming course.
|
data/bin/crowdfund
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# def say_funding(project, funding=0)
|
|
4
|
+
# "#{project} has $#{funding} in funding as of #{time}."
|
|
5
|
+
# end
|
|
6
|
+
#
|
|
7
|
+
# def time
|
|
8
|
+
# current_time = Time.new
|
|
9
|
+
# current_time.strftime("%A, %m/%d/%y")
|
|
10
|
+
# end
|
|
11
|
+
require_relative '../lib/crowdfund/groupfundrequest'
|
|
12
|
+
require_relative '../lib/crowdfund/grant_project'
|
|
13
|
+
require_relative '../lib/crowdfund/match_project'
|
|
14
|
+
|
|
15
|
+
tech_projects = Crowdfund::GroupFundRequest.new("Tech Projects")
|
|
16
|
+
default_project_file = File.join(File.dirname(__FILE__), "tech_projects.csv")
|
|
17
|
+
tech_projects.load_projects(ARGV.shift || default_project_file)
|
|
18
|
+
help_out = Crowdfund::GrantProject.new("Help Out", 10_000, 1_000)
|
|
19
|
+
matched = Crowdfund::MatchProject.new("Sponsored", 50_000)
|
|
20
|
+
tech_projects.add_project(help_out)
|
|
21
|
+
tech_projects.add_project(matched)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
tech_projects.request_funding(1)
|
|
25
|
+
tech_projects.print_funding_status
|
|
26
|
+
tech_projects.print_underfunded
|
|
27
|
+
|
|
28
|
+
loop do
|
|
29
|
+
puts "\nHow many rounds of funding should we do? (type 'quit' to exit)"
|
|
30
|
+
answer = gets.chomp.downcase
|
|
31
|
+
case answer
|
|
32
|
+
when /^\d+$/
|
|
33
|
+
tech_projects.request_funding(answer.to_i)
|
|
34
|
+
when 'quit', 'exit'
|
|
35
|
+
tech_projects.print_funding_status
|
|
36
|
+
tech_projects.print_underfunded
|
|
37
|
+
break
|
|
38
|
+
else
|
|
39
|
+
puts "Please enter a number or 'quit'"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if tech_projects.underfunded != []
|
|
44
|
+
puts "\nWould you like to save a list of underfunded projects to send to your friends?"
|
|
45
|
+
answer = gets.chomp.downcase
|
|
46
|
+
case answer
|
|
47
|
+
when 'yes', 'y'
|
|
48
|
+
tech_projects.save_underfunded
|
|
49
|
+
else
|
|
50
|
+
puts "Cheers!"
|
|
51
|
+
end
|
|
52
|
+
else
|
|
53
|
+
puts "\nAll projects are fully funded!"
|
|
54
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Crowdfund
|
|
2
|
+
module Fundable
|
|
3
|
+
|
|
4
|
+
def add_funds(amount=25)
|
|
5
|
+
self.funding += amount
|
|
6
|
+
puts "#{name} gained some funds!"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def lose_funds(amount=15)
|
|
10
|
+
self.funding -= amount
|
|
11
|
+
puts "#{name} lost some funds!"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def funds_needed
|
|
15
|
+
goal - funding
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def fully_funded?
|
|
19
|
+
funds_needed <= 0
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require_relative 'project'
|
|
2
|
+
require_relative 'die'
|
|
3
|
+
require_relative 'pledge_pool'
|
|
4
|
+
|
|
5
|
+
module Crowdfund
|
|
6
|
+
module FundingRound
|
|
7
|
+
def self.do_round(project)
|
|
8
|
+
die = Die.new
|
|
9
|
+
case die.roll
|
|
10
|
+
when 4..6
|
|
11
|
+
project.add_funds
|
|
12
|
+
when 2..3
|
|
13
|
+
puts "#{project.name} received no funds this time."
|
|
14
|
+
else
|
|
15
|
+
project.lose_funds
|
|
16
|
+
end
|
|
17
|
+
project.receive_pledge
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if __FILE__ == $0
|
|
23
|
+
project = Project.new("Airing", 100_000, 630_649)
|
|
24
|
+
FundingRound.do_round(project)
|
|
25
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require_relative 'project'
|
|
2
|
+
require_relative 'die'
|
|
3
|
+
require_relative 'funding_round'
|
|
4
|
+
require_relative 'pledge_pool'
|
|
5
|
+
require 'csv'
|
|
6
|
+
|
|
7
|
+
module Crowdfund
|
|
8
|
+
class GroupFundRequest
|
|
9
|
+
attr_reader :projects
|
|
10
|
+
|
|
11
|
+
def initialize(name)
|
|
12
|
+
@name = name
|
|
13
|
+
@projects = []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def add_project(project)
|
|
17
|
+
@projects << project
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def load_projects(from_file)
|
|
21
|
+
CSV.foreach(from_file) do |row|
|
|
22
|
+
project = Project.new(row[0],Integer(row[1]),Integer(row[2]))
|
|
23
|
+
add_project(project)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def request_funding(rounds)
|
|
28
|
+
puts "\nThere are #{@projects.count} projects in #{@name}:"
|
|
29
|
+
puts @projects
|
|
30
|
+
puts "\nThere are #{PledgePool::PLEDGES.count} possible pledge amounts:"
|
|
31
|
+
PledgePool::PLEDGES.each { |pledge| puts "A #{pledge.name} pledge is worth $#{pledge.amount}" }
|
|
32
|
+
n = 0
|
|
33
|
+
1.upto(rounds) do
|
|
34
|
+
n += 1
|
|
35
|
+
puts "\n Round #{n}:"
|
|
36
|
+
@projects.each { |project| puts "The funding goal of #{project.name} is $#{project.goal}." }
|
|
37
|
+
@projects.each { |project|
|
|
38
|
+
FundingRound.do_round(project)
|
|
39
|
+
if project.fully_funded?
|
|
40
|
+
puts "#{project.name} is FULLY FUNDED. (Currently $#{project.funding} toward the goal of $#{project.goal}.)\n"
|
|
41
|
+
else
|
|
42
|
+
puts "#{project.name} still needs funds. (Currently $#{project.funding} toward the goal of $#{project.goal}.)\n"
|
|
43
|
+
end
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def print_funding_status
|
|
49
|
+
puts "\nCurrent Funding of All Projects: "
|
|
50
|
+
@projects.sort.each { |project| puts "#{project.name} funding: $#{project.funding} of $#{project.goal} "}
|
|
51
|
+
fully_funded, underfunded = @projects.partition { |project| project.fully_funded? }
|
|
52
|
+
puts "\nFully Funded Projects: #{fully_funded.size}\nUnderfunded Projects: #{underfunded.size}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def underfunded
|
|
56
|
+
@projects.sort.reject { |project| project.fully_funded? }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def print_underfunded
|
|
60
|
+
underfunded.each { |project| puts "#{project.name} still needs $#{project.funds_needed}."}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def save_underfunded
|
|
64
|
+
to_file = File.join(File.dirname(File.dirname(File.dirname(__FILE__))), "underfunded.txt")
|
|
65
|
+
File.open(to_file, "w") do |file|
|
|
66
|
+
file.puts "Projects that still need funds:"
|
|
67
|
+
underfunded.each do |project|
|
|
68
|
+
file.puts "#{project.name} still needs $#{project.funds_needed}."
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
puts "The list of underfunded projects has been saved in \"underfunded.txt\"."
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if __FILE__ == $0
|
|
77
|
+
project1 = Project.new("Test1", 10_000)
|
|
78
|
+
project2 = Project.new("Test2", 20_000, 2_000)
|
|
79
|
+
group = GroupFundRequest.new("Test Group")
|
|
80
|
+
group.add_project(project1)
|
|
81
|
+
group.add_project(project2)
|
|
82
|
+
group.request_funding(2)
|
|
83
|
+
project3 = Project.new("Test3", 1_000)
|
|
84
|
+
group.add_project(project3)
|
|
85
|
+
group.request_funding(3)
|
|
86
|
+
group.print_funding_status
|
|
87
|
+
group.print_underfunded
|
|
88
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require_relative 'project'
|
|
2
|
+
|
|
3
|
+
module Crowdfund
|
|
4
|
+
class MatchProject < Project
|
|
5
|
+
|
|
6
|
+
def match?
|
|
7
|
+
@funding >= @goal / 2.0
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def add_funds(amount=25)
|
|
11
|
+
if match?
|
|
12
|
+
super(amount * 2)
|
|
13
|
+
else
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def receive_pledge
|
|
19
|
+
if match?
|
|
20
|
+
match_factor = 2
|
|
21
|
+
super(match_factor)
|
|
22
|
+
else
|
|
23
|
+
super
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require_relative 'pledge_pool'
|
|
2
|
+
require_relative 'fundable'
|
|
3
|
+
|
|
4
|
+
module Crowdfund
|
|
5
|
+
class Project
|
|
6
|
+
include Fundable
|
|
7
|
+
|
|
8
|
+
attr_reader :goal, :pledges
|
|
9
|
+
attr_accessor :name, :funding
|
|
10
|
+
|
|
11
|
+
def initialize (name, goal, funding=0)
|
|
12
|
+
@name = name
|
|
13
|
+
@goal = goal
|
|
14
|
+
@funding = funding
|
|
15
|
+
@pledges = Hash.new(0)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def <=>(other_project)
|
|
19
|
+
other_project.funding <=> funding
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def receive_pledge(match_factor=1)
|
|
24
|
+
pledge = PledgePool.random
|
|
25
|
+
puts "#{name} received a #{pledge.name} pledge worth $#{pledge.amount}."
|
|
26
|
+
@pledges[pledge.name] += pledge.amount * match_factor
|
|
27
|
+
@funding += pledge.amount * match_factor
|
|
28
|
+
puts "#{name}'s pledge amounts:"
|
|
29
|
+
each_pledge { |pledge| puts "$#{pledge.amount} in #{pledge.name} pledges" }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def each_pledge
|
|
33
|
+
@pledges.sort_by { |name, amount| amount }.each { |name, amount| yield Pledge.new(name, amount) }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def to_s
|
|
37
|
+
"#{@name} has $#{@funding} in funding towards a goal of $#{@goal}."
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
if __FILE__ == $0
|
|
43
|
+
project = Project.new("Test Project", 10_000)
|
|
44
|
+
puts project.name
|
|
45
|
+
puts project.funding
|
|
46
|
+
project.add_funds
|
|
47
|
+
puts project.funding
|
|
48
|
+
project.lose_funds
|
|
49
|
+
puts project.funding
|
|
50
|
+
5.times { project.add_funds }
|
|
51
|
+
puts project.funding
|
|
52
|
+
puts project
|
|
53
|
+
puts project.funds_needed
|
|
54
|
+
project.receive_pledge
|
|
55
|
+
puts project
|
|
56
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'crowdfund/grant_project'
|
|
2
|
+
|
|
3
|
+
module Crowdfund
|
|
4
|
+
describe GrantProject do
|
|
5
|
+
|
|
6
|
+
before do
|
|
7
|
+
@goal = 10_000
|
|
8
|
+
@initial_funding = 100
|
|
9
|
+
@granted = GrantProject.new("Help Out", @goal, @initial_funding)
|
|
10
|
+
$stdout = StringIO.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "does not lose funds even when lose funds is called on it" do
|
|
14
|
+
@granted.lose_funds
|
|
15
|
+
|
|
16
|
+
expect(@granted.funding).to eq(@initial_funding)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# These tests were broken by the addition of pledges.
|
|
2
|
+
#
|
|
3
|
+
# require 'crowdfund/groupfundrequest'
|
|
4
|
+
#
|
|
5
|
+
# module Crowdfund
|
|
6
|
+
# describe GroupFundRequest do
|
|
7
|
+
# before do
|
|
8
|
+
# @group = GroupFundRequest.new("Group")
|
|
9
|
+
# @initial_funding = 500
|
|
10
|
+
# @project = Project.new("Test", 10_000, @initial_funding)
|
|
11
|
+
# @group.add_project(@project)
|
|
12
|
+
# $stdout = StringIO.new
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# it "adds funds when a 4, 5, or 6 are rolled" do
|
|
16
|
+
# allow_any_instance_of(Die).to receive(:roll).and_return(4)
|
|
17
|
+
#
|
|
18
|
+
# @group.request_funding(2)
|
|
19
|
+
#
|
|
20
|
+
# expect(@project.funding).to eq(@initial_funding + (25 * 2))
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# it "funding doesn't change when a 2 or 3 are rolled" do
|
|
24
|
+
# allow_any_instance_of(Die).to receive(:roll).and_return(3)
|
|
25
|
+
#
|
|
26
|
+
# @group.request_funding(2)
|
|
27
|
+
#
|
|
28
|
+
# expect(@project.funding).to eq(@initial_funding)
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# it "removes funds ($10) when a 1 is rolled" do
|
|
32
|
+
# allow_any_instance_of(Die).to receive(:roll).and_return(1)
|
|
33
|
+
#
|
|
34
|
+
# @group.request_funding(2)
|
|
35
|
+
#
|
|
36
|
+
# expect(@project.funding).to eq(@initial_funding - (15 * 2))
|
|
37
|
+
# end
|
|
38
|
+
# end
|
|
39
|
+
# end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'crowdfund/match_project'
|
|
2
|
+
|
|
3
|
+
module Crowdfund
|
|
4
|
+
describe MatchProject do
|
|
5
|
+
|
|
6
|
+
before do
|
|
7
|
+
@goal = 1_000
|
|
8
|
+
@initial_funding = 350
|
|
9
|
+
@matched = MatchProject.new("Matched", @goal, @initial_funding)
|
|
10
|
+
$stdout = StringIO.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "receives funding like other projects while its secured funding is less than 50% of its goal" do
|
|
14
|
+
@matched.add_funds
|
|
15
|
+
|
|
16
|
+
expect(@matched.funding).to eq(375)
|
|
17
|
+
|
|
18
|
+
@matched.receive_pledge
|
|
19
|
+
|
|
20
|
+
if @matched.pledges.include?(:bronze)
|
|
21
|
+
expect(@matched.funding).to eq(425)
|
|
22
|
+
elsif @matched.pledges.include?(:silver)
|
|
23
|
+
expect(@matched.funding).to eq(450)
|
|
24
|
+
else
|
|
25
|
+
expect(@matched.funding).to eq(475)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "when its secured funding equals or exceeds 50% of its goal, all additions to its funding are matched" do
|
|
30
|
+
@matched.add_funds(150)
|
|
31
|
+
@matched.add_funds
|
|
32
|
+
|
|
33
|
+
expect(@matched.funding).to eq(550)
|
|
34
|
+
|
|
35
|
+
@matched.receive_pledge
|
|
36
|
+
|
|
37
|
+
if @matched.pledges.include?(:bronze)
|
|
38
|
+
expect(@matched.funding).to eq(650)
|
|
39
|
+
elsif @matched.pledges.include?(:silver)
|
|
40
|
+
expect(@matched.funding).to eq(700)
|
|
41
|
+
else
|
|
42
|
+
expect(@matched.funding).to eq(750)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require 'crowdfund/pledge_pool'
|
|
2
|
+
|
|
3
|
+
module Crowdfund
|
|
4
|
+
describe Pledge do
|
|
5
|
+
before do
|
|
6
|
+
@pledge = Pledge.new(:silver, 75)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "has a name attribute" do
|
|
10
|
+
expect(@pledge.name).to eq(:silver)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "has an amount attribute" do
|
|
14
|
+
expect(@pledge.amount).to eq(75)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe PledgePool do
|
|
20
|
+
it "has 3 pledge types" do
|
|
21
|
+
expect(PledgePool::PLEDGES.size).to eq(3)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "has a bronze pledge worth $50" do
|
|
25
|
+
expect(PledgePool::PLEDGES).to include(Pledge.new(:bronze, 50))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "has a silver pledge with $75" do
|
|
29
|
+
expect(PledgePool::PLEDGES).to include(Pledge.new(:silver, 75))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "has a gold pledge worth $100" do
|
|
33
|
+
expect(PledgePool::PLEDGES).to include(Pledge.new(:gold, 100))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "returns a random pledge" do
|
|
37
|
+
pledge = PledgePool.random
|
|
38
|
+
|
|
39
|
+
expect(PledgePool::PLEDGES).to include(pledge)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'crowdfund/project'
|
|
2
|
+
|
|
3
|
+
module Crowdfund
|
|
4
|
+
describe Project do
|
|
5
|
+
|
|
6
|
+
before do
|
|
7
|
+
@initial_target = 10_000
|
|
8
|
+
@project = Project.new("Test", @initial_target, 200)
|
|
9
|
+
$stdout = StringIO.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "has an initial target funding amount" do
|
|
13
|
+
expect(@project.goal).to eq(10_000)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "computes funds needed" do
|
|
17
|
+
expect(@project.funds_needed).to eq(9800)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "increases funds by 25 when funds are added" do
|
|
21
|
+
@project.add_funds
|
|
22
|
+
expect(@project.funding).to eq(225)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "decreases founds by 15 when funds are removed" do
|
|
26
|
+
@project.lose_funds
|
|
27
|
+
expect(@project.funding).to eq(185)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context "created without funding amount given" do
|
|
31
|
+
before do
|
|
32
|
+
@project = Project.new("Test", 10_000)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "has a default value of 0 for funding amount" do
|
|
36
|
+
expect(@project.funding).to eq(0)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context "has not reached its funding goal" do
|
|
41
|
+
before do
|
|
42
|
+
@project = Project.new("Test", 10_000, 9999)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "has a state of 'not fully funded'" do
|
|
46
|
+
expect(@project).not_to be_fully_funded
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context "has reached its funding goal" do
|
|
51
|
+
before do
|
|
52
|
+
@project = Project.new("Test", 10_000, 10_000)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "has a state of 'fully funded'" do
|
|
56
|
+
expect(@project).to be_fully_funded
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context "in a collection of projects" do
|
|
61
|
+
before do
|
|
62
|
+
@project1 = Project.new("Test1", 10_000, 2_000)
|
|
63
|
+
@project2 = Project.new("Test2", 10_000, 5_000)
|
|
64
|
+
@project3 = Project.new("Test3", 10_000, 10_000)
|
|
65
|
+
|
|
66
|
+
@projects = [@project1, @project2, @project3]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "returns sorted array in order from most funding to least" do
|
|
70
|
+
expect(@projects.sort).to eq([@project3, @project2, @project1])
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: crowdfund_tr
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Todd Ruhlen
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-07-15 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rspec
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ~>
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
27
|
+
description: |
|
|
28
|
+
A simple, text-based crowdfunding simulator. Run a group of projects through a
|
|
29
|
+
series of funding rounds, in which they either receive or lose funds, or are
|
|
30
|
+
skipped. They also receive a random pledge. Grant projects never lose funds.
|
|
31
|
+
Match projects have all future funding matched after they reach half-funding.
|
|
32
|
+
Statistics are printed to the console at the end of the simulation.
|
|
33
|
+
|
|
34
|
+
The normal projects can be specified in a '.csv' file that is given as a command
|
|
35
|
+
line argument when loading the program, or the default projects can be used. The
|
|
36
|
+
format for 'csv' entries is Project Name,Goal,Initial_funding with a comma and
|
|
37
|
+
no spaces between entries and underscores in place of commas within larger
|
|
38
|
+
numbers (e.g. Your Project,10_000,0).
|
|
39
|
+
|
|
40
|
+
The option is given to save a list of underfunded projects upon exiting the
|
|
41
|
+
program. The list is saved in 'underfunded.txt' in the top-level folder of the
|
|
42
|
+
application.
|
|
43
|
+
|
|
44
|
+
Created as a bonus project while completing the Pragmatic Studio Ruby
|
|
45
|
+
Programming course.
|
|
46
|
+
email: rhythmtome@yahoo.com
|
|
47
|
+
executables:
|
|
48
|
+
- crowdfund
|
|
49
|
+
extensions: []
|
|
50
|
+
extra_rdoc_files: []
|
|
51
|
+
files:
|
|
52
|
+
- LICENSE
|
|
53
|
+
- README
|
|
54
|
+
- bin/crowdfund
|
|
55
|
+
- bin/tech_projects.csv
|
|
56
|
+
- lib/crowdfund/die.rb
|
|
57
|
+
- lib/crowdfund/fundable.rb
|
|
58
|
+
- lib/crowdfund/funding_round.rb
|
|
59
|
+
- lib/crowdfund/grant_project.rb
|
|
60
|
+
- lib/crowdfund/groupfundrequest.rb
|
|
61
|
+
- lib/crowdfund/match_project.rb
|
|
62
|
+
- lib/crowdfund/pledge_pool.rb
|
|
63
|
+
- lib/crowdfund/project.rb
|
|
64
|
+
- spec/crowdfund/grant_project_spec.rb
|
|
65
|
+
- spec/crowdfund/groupfundrequest_spec.rb
|
|
66
|
+
- spec/crowdfund/match_project_spec.rb
|
|
67
|
+
- spec/crowdfund/pledge_pool_spec.rb
|
|
68
|
+
- spec/crowdfund/project_spec.rb
|
|
69
|
+
homepage:
|
|
70
|
+
licenses:
|
|
71
|
+
- MIT
|
|
72
|
+
metadata: {}
|
|
73
|
+
post_install_message:
|
|
74
|
+
rdoc_options: []
|
|
75
|
+
require_paths:
|
|
76
|
+
- lib
|
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - '>='
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '1.9'
|
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
|
+
requirements:
|
|
84
|
+
- - '>='
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
version: '0'
|
|
87
|
+
requirements: []
|
|
88
|
+
rubyforge_project:
|
|
89
|
+
rubygems_version: 2.4.8
|
|
90
|
+
signing_key:
|
|
91
|
+
specification_version: 4
|
|
92
|
+
summary: Simple text-based crowdfunding simulator created during the Pragmatic Studio
|
|
93
|
+
Ruby Programming course.
|
|
94
|
+
test_files:
|
|
95
|
+
- spec/crowdfund/match_project_spec.rb
|
|
96
|
+
- spec/crowdfund/pledge_pool_spec.rb
|
|
97
|
+
- spec/crowdfund/groupfundrequest_spec.rb
|
|
98
|
+
- spec/crowdfund/grant_project_spec.rb
|
|
99
|
+
- spec/crowdfund/project_spec.rb
|