crowdfunder 1.0.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.
- checksums.yaml +7 -0
- data/LICENSE +19 -0
- data/README +28 -0
- data/bin/crowdfunder +34 -0
- data/bin/projects.csv +3 -0
- data/lib/crowdfunder/die.rb +14 -0
- data/lib/crowdfunder/fundable.rb +32 -0
- data/lib/crowdfunder/funding_round.rb +25 -0
- data/lib/crowdfunder/fundrequest.rb +106 -0
- data/lib/crowdfunder/grant_project.rb +29 -0
- data/lib/crowdfunder/matching_fund_project.rb +43 -0
- data/lib/crowdfunder/pledge_pool.rb +27 -0
- data/lib/crowdfunder/project.rb +49 -0
- data/spec/crowdfunder/fundrquest_spec.rb +51 -0
- data/spec/crowdfunder/grant_project_spec.rb +16 -0
- data/spec/crowdfunder/matching_fund_project_spec.rb +32 -0
- data/spec/crowdfunder/pledge_pool_spec.rb +50 -0
- data/spec/crowdfunder/project_spec.rb +137 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ee83a081ad0bcbb1d77f377100e42509db5e1568d08aaa99894a66fb694b4df7
|
4
|
+
data.tar.gz: 50da6e3fc434adab0d5e61de24fe36b2750cebaf1973b4e685694cc7a2c007fa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 843bcaa9e8190bde9f2b3353916183f868d9fa5ab2a69af0b223b0512eb15be23108f706f3f6aa79af7ce20d9c56afca863cbf61387bf5ff4b7fcf1469157461
|
7
|
+
data.tar.gz: 472212e3f5baab0348f5a526b437d7306c3feb9254bdae11f9c47dfc8ef11dcb9ad5424b58e3500c850ddfccafbebbb6f150c2f150262f78d08039cbeefbe091
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2022 Paulette Erijo
|
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 all
|
11
|
+
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 THE
|
19
|
+
SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Crowdfunder
|
2
|
+
|
3
|
+
This is a crowdfunding app built in ruby. It can be integrated into any
|
4
|
+
ruby application and framework.
|
5
|
+
|
6
|
+
## Introduction
|
7
|
+
|
8
|
+
Crowdfunder allows for various projects be created and funded through funding rounds.
|
9
|
+
Projects will have funds added or deducted at random. Projects can also receive pledges
|
10
|
+
from 3 pledge categories to make up for additional funding.
|
11
|
+
|
12
|
+
### Technologies
|
13
|
+
|
14
|
+
* Ruby 3
|
15
|
+
* Rspec 3
|
16
|
+
|
17
|
+
## Setup
|
18
|
+
|
19
|
+
To run this gem, download then install it locally.
|
20
|
+
|
21
|
+
$ gem install crowdfunder-1.0.1.gem
|
22
|
+
|
23
|
+
You have the option to load projects from the command line in a CSV file. Additionally
|
24
|
+
a default projects.csv file is packaged in the gem.
|
25
|
+
|
26
|
+
## Sources
|
27
|
+
|
28
|
+
This app was inspired by Mike and Nicole of The Pragmatic Studio.
|
data/bin/crowdfunder
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/crowdfunder/fundrequest'
|
4
|
+
require_relative '../lib/crowdfunder/pledge_pool'
|
5
|
+
require_relative '../lib/crowdfunder/matching_fund_project'
|
6
|
+
require_relative '../lib/crowdfunder/grant_project'
|
7
|
+
|
8
|
+
|
9
|
+
vc_start_up = Crowdfunder::FundRequest.new("VC-Friendly Start-up Projects")
|
10
|
+
default_project_file = File.join(File.dirname(__FILE__), 'projects.csv')
|
11
|
+
vc_start_up.load_projects(ARGV.shift || default_project_file)
|
12
|
+
|
13
|
+
grant = Crowdfunder::GrantProject.new("Will Foundation", 3000, 5000)
|
14
|
+
vc_start_up.add_project(grant)
|
15
|
+
|
16
|
+
project_match = Crowdfunder::MatchingFundProject.new("Study Loan", 500, 10000)
|
17
|
+
vc_start_up.add_project(project_match)
|
18
|
+
|
19
|
+
|
20
|
+
loop do
|
21
|
+
puts "How many funding rounds? ('quit' to exit)"
|
22
|
+
answer = gets.chomp
|
23
|
+
case answer
|
24
|
+
when /^\d+$/
|
25
|
+
vc_start_up.request_funding(answer.to_i)
|
26
|
+
when 'quit', 'exit'
|
27
|
+
vc_start_up.print_stats
|
28
|
+
break
|
29
|
+
else
|
30
|
+
puts "Please enter a number or quit"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
vc_start_up.save_report_file
|
data/bin/projects.csv
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Crowdfunder
|
2
|
+
module Fundable
|
3
|
+
|
4
|
+
def add_funds
|
5
|
+
self.initial_fund += 25
|
6
|
+
puts "#{name} got more funds!"
|
7
|
+
end
|
8
|
+
|
9
|
+
def remove_funds
|
10
|
+
self.initial_fund -= 15
|
11
|
+
puts "#{name} lost some funds!"
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def total_funding_outstanding
|
16
|
+
self.target_fund - total_funds
|
17
|
+
end
|
18
|
+
|
19
|
+
def fully_funded?
|
20
|
+
total_funding_outstanding <= 0
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def <=>(other_project)
|
25
|
+
other_project.total_required_funds <=> total_required_funds
|
26
|
+
end
|
27
|
+
|
28
|
+
def total_required_funds
|
29
|
+
self.target_fund - self.initial_fund
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'project'
|
2
|
+
require_relative 'die'
|
3
|
+
require_relative 'pledge_pool'
|
4
|
+
|
5
|
+
module Crowdfunder
|
6
|
+
module FundingRound
|
7
|
+
|
8
|
+
def self.one_round(project)
|
9
|
+
die = Die.new
|
10
|
+
@number_rolled = die.roll
|
11
|
+
|
12
|
+
case @number_rolled
|
13
|
+
when 1..2
|
14
|
+
project.remove_funds
|
15
|
+
when 3..4
|
16
|
+
puts "#{project.name} was skipped"
|
17
|
+
else
|
18
|
+
project.add_funds
|
19
|
+
end
|
20
|
+
|
21
|
+
pledge = PledgePool.random
|
22
|
+
project.found_pledge(pledge)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require_relative 'project'
|
2
|
+
require_relative 'die'
|
3
|
+
require_relative 'funding_round'
|
4
|
+
require 'csv'
|
5
|
+
|
6
|
+
module Crowdfunder
|
7
|
+
class FundRequest
|
8
|
+
|
9
|
+
def initialize(name)
|
10
|
+
@name = name
|
11
|
+
@projects = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def load_projects(from_file)
|
15
|
+
CSV.foreach(from_file) do |row|
|
16
|
+
project = Project.new(row[0], row[1].to_i)
|
17
|
+
add_project(project)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def save_report_file(to_file="project_report.txt")
|
22
|
+
File.open(to_file, 'w') do |file|
|
23
|
+
file.puts "#{@name} Funding Report"
|
24
|
+
@projects.sort.each do |project|
|
25
|
+
file.puts report_format(project)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def report_format(project)
|
31
|
+
"#{project.name.ljust(30, '.')} #{project.total_funds}"
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def add_project(project)
|
36
|
+
@projects << project
|
37
|
+
end
|
38
|
+
|
39
|
+
def request_funding(rounds)
|
40
|
+
puts "There are #{@projects.size} projects in #{@name}:"
|
41
|
+
|
42
|
+
@projects.each do |project|
|
43
|
+
puts project
|
44
|
+
end
|
45
|
+
|
46
|
+
pledges = PledgePool::PLEDGES
|
47
|
+
|
48
|
+
puts "\nThere are #{pledges.size} possible pledge amounts:"
|
49
|
+
|
50
|
+
pledges.each do |pledge|
|
51
|
+
puts "\tA #{pledge.name} is worth #{pledge.amount}."
|
52
|
+
end
|
53
|
+
|
54
|
+
1.upto(rounds) do |count|
|
55
|
+
puts "\nRound #{count}:"
|
56
|
+
puts "*" * 9
|
57
|
+
@projects.each do |project|
|
58
|
+
puts "\n"
|
59
|
+
FundingRound.one_round(project)
|
60
|
+
puts project
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def projects_for_contribution
|
66
|
+
@projects.under_funded do |project|
|
67
|
+
puts project
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def print_stats
|
72
|
+
full_funded, under_funded = @projects.partition do |project|
|
73
|
+
project.fully_funded?
|
74
|
+
end
|
75
|
+
|
76
|
+
puts "\n#{full_funded.size} Fully-Funded Projects:"
|
77
|
+
|
78
|
+
full_funded.sort.each do |project|
|
79
|
+
puts report_format(project)
|
80
|
+
end
|
81
|
+
|
82
|
+
puts "\n#{under_funded.size} Under-Funded Projects:"
|
83
|
+
|
84
|
+
under_funded.sort.each do |project|
|
85
|
+
puts report_format(project)
|
86
|
+
end
|
87
|
+
|
88
|
+
puts "\nList of Pending Projects for Funding"
|
89
|
+
sorted_projects = under_funded.sort do |a, b|
|
90
|
+
b.total_funding_outstanding <=> a.total_funding_outstanding
|
91
|
+
end
|
92
|
+
|
93
|
+
sorted_projects.each do |project|
|
94
|
+
puts "#{project.name} requires #{project.total_funding_outstanding}"
|
95
|
+
end
|
96
|
+
|
97
|
+
@projects.each do |project|
|
98
|
+
puts "\n#{project.name}'s pledges:"
|
99
|
+
project.each_pledge_received do |pledge|
|
100
|
+
puts "#{pledge.amount} in #{pledge.name} pledges"
|
101
|
+
end
|
102
|
+
puts "#{project.pledged_funds} in total pledges"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'project'
|
2
|
+
|
3
|
+
module Crowdfunder
|
4
|
+
class GrantProject < Project
|
5
|
+
|
6
|
+
def initialize(name, initial_fund, target_fund)
|
7
|
+
super(name, initial_fund, target_fund)
|
8
|
+
@deducted = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def remove_funds
|
12
|
+
#super
|
13
|
+
@initial_fund -= 0 #@deducted
|
14
|
+
puts "Funds removed have been added back."
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
if __FILE__ == $0
|
20
|
+
@initial_fund = 3000
|
21
|
+
@target_fund = 5000
|
22
|
+
grant = GrantProject.new("Will Foundation", @initial_fund, @target_fund)
|
23
|
+
|
24
|
+
grant.add_funds
|
25
|
+
grant.remove_funds
|
26
|
+
grant.remove_funds
|
27
|
+
puts "#{grant.name}'s current funds is #{grant.initial_fund}"
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'project'
|
2
|
+
|
3
|
+
module Crowdfunder
|
4
|
+
class MatchingFundProject < Project
|
5
|
+
|
6
|
+
def initialize(name, initial_fund, target_fund)
|
7
|
+
super(name, initial_fund, target_fund)
|
8
|
+
@half_funds_raised = target_fund / 2.0
|
9
|
+
end
|
10
|
+
|
11
|
+
def half_funded?
|
12
|
+
total_funds >= @half_funds_raised #<= initial_fund
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_funds
|
16
|
+
if half_funded?
|
17
|
+
@initial_fund += (25 * 2)
|
18
|
+
puts "#{name} is match ready!"
|
19
|
+
puts "#{name} got double funds. Total funds: #{total_funds}"
|
20
|
+
else
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
if __FILE__ == $0
|
28
|
+
matched_project = MatchingFundProject.new("Study Loan", 500, 10000)
|
29
|
+
|
30
|
+
pledge1 = Pledge.new("bronze", 1500)
|
31
|
+
pledge2 = Pledge.new("bronze", 1500)
|
32
|
+
pledge3 = Pledge.new("silver", 1500)
|
33
|
+
|
34
|
+
matched_project.found_pledge(pledge1)
|
35
|
+
matched_project.found_pledge(pledge2)
|
36
|
+
matched_project.found_pledge(pledge3)
|
37
|
+
|
38
|
+
puts matched_project.total_funds
|
39
|
+
puts matched_project.add_funds
|
40
|
+
puts matched_project.total_funds
|
41
|
+
puts matched_project.initial_fund
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Crowdfunder
|
2
|
+
Pledge = Struct.new(:name, :amount)
|
3
|
+
|
4
|
+
module PledgePool
|
5
|
+
|
6
|
+
PLEDGES = [
|
7
|
+
Pledge.new("bronze", 50),
|
8
|
+
Pledge.new("silver", 75),
|
9
|
+
Pledge.new("gold", 100)
|
10
|
+
]
|
11
|
+
|
12
|
+
def self.random
|
13
|
+
PLEDGES.sample
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if __FILE__ == $0
|
18
|
+
pledges = PledgePool::PLEDGES
|
19
|
+
|
20
|
+
pledges.each do |pledge|
|
21
|
+
puts "A #{pledge.name} pledge"
|
22
|
+
end
|
23
|
+
|
24
|
+
pledge = PledgePool.random
|
25
|
+
puts pledge
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative "pledge_pool"
|
2
|
+
require_relative "fundable"
|
3
|
+
|
4
|
+
|
5
|
+
module Crowdfunder
|
6
|
+
class Project
|
7
|
+
include Fundable
|
8
|
+
|
9
|
+
attr_accessor :name
|
10
|
+
attr_accessor :initial_fund, :target_fund, :fully_funded
|
11
|
+
|
12
|
+
def initialize(name, initial_fund=0, target_fund)
|
13
|
+
@name = name.upcase
|
14
|
+
@target_fund = target_fund
|
15
|
+
@initial_fund = initial_fund
|
16
|
+
@received_pledges = Hash.new(0)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"#{@name} has a goal of #{@target_fund} but has raised a total of $#{total_funds} in funding."
|
21
|
+
end
|
22
|
+
|
23
|
+
def pledged_funds
|
24
|
+
# pledge funds is a virtual accessor. in this case it returns the a value
|
25
|
+
# derived from an instance variable (@received_pledges)
|
26
|
+
@received_pledges.values.reduce(0, :+)
|
27
|
+
end
|
28
|
+
|
29
|
+
def found_pledge(pledge)
|
30
|
+
@received_pledges[pledge.name] += pledge.amount
|
31
|
+
puts "#{@name} received a #{pledge.name} worth $#{pledge.amount}."
|
32
|
+
puts "#{@name}'s pledges: #{@received_pledges}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def total_funds
|
36
|
+
# total_funds is a virtual accessor, in that the total_funds method doesn't return
|
37
|
+
# the value of a @total_funds instances variable. Instead, the total funds are
|
38
|
+
# computed when the method is called.
|
39
|
+
@initial_fund + pledged_funds
|
40
|
+
end
|
41
|
+
|
42
|
+
def each_pledge_received
|
43
|
+
@received_pledges.each do |name, amount|
|
44
|
+
pledge = Pledge.new(name, amount)
|
45
|
+
yield pledge
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'crowdfunder/fundrequest'
|
2
|
+
|
3
|
+
module Crowdfunder
|
4
|
+
describe FundRequest do
|
5
|
+
before do
|
6
|
+
$stdout = StringIO.new
|
7
|
+
@fund_request = FundRequest.new("VC-Friendly Start-up Projects")
|
8
|
+
end
|
9
|
+
context "add or removes more funds if a number is rolled" do
|
10
|
+
before do
|
11
|
+
@initial_fund = 700
|
12
|
+
@target_fund = 4000
|
13
|
+
@project = Project.new("xyz", @initial_fund, @target_fund)
|
14
|
+
|
15
|
+
@fund_request.add_project(@project)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "gets more fund if a higher number is rolled" do
|
19
|
+
allow_any_instance_of(Die).to receive(:roll).and_return(5)
|
20
|
+
|
21
|
+
@fund_request.request_funding(2)
|
22
|
+
expect(@project.initial_fund).to eq(@initial_fund + 25 * 2)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "gets skipped when a medium number is rolled" do
|
26
|
+
allow_any_instance_of(Die).to receive(:roll).and_return(3)
|
27
|
+
|
28
|
+
@fund_request.request_funding(2)
|
29
|
+
expect(@project.initial_fund).to eq(@initial_fund)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "losses funds when a low number is rolled" do
|
33
|
+
allow_any_instance_of(Die).to receive(:roll).and_return(1)
|
34
|
+
|
35
|
+
@fund_request.request_funding(2)
|
36
|
+
expect(@project.initial_fund).to eq(@initial_fund - 15 * 2)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "assigns a pledge for funds during a project's turn" do
|
41
|
+
vc_start_up = FundRequest.new("VC-Friendly Start-up Projects")
|
42
|
+
project = Project.new("lmn", 300, 1000)
|
43
|
+
|
44
|
+
vc_start_up.add_project(project)
|
45
|
+
|
46
|
+
vc_start_up.request_funding(1)
|
47
|
+
|
48
|
+
expect(project.pledged_funds).not_to be_zero
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'crowdfunder/grant_project'
|
2
|
+
|
3
|
+
module Crowdfunder
|
4
|
+
describe GrantProject do
|
5
|
+
before do
|
6
|
+
@initial_fund = 5000
|
7
|
+
@grant = GrantProject.new("Will Foundation", @initial_fund, 10000)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "doesn't lose any funds once funded" do
|
11
|
+
|
12
|
+
@grant.remove_funds
|
13
|
+
expect(@grant.initial_fund).to eq(@initial_fund)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'crowdfunder/matching_fund_project'
|
2
|
+
|
3
|
+
module Crowdfunder
|
4
|
+
describe MatchingFundProject do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@initial_fund = 2000
|
8
|
+
@target_fund = 8000
|
9
|
+
@matched_project = MatchingFundProject.new("Study Loan", @initial_fund, @target_fund)
|
10
|
+
|
11
|
+
pledge1 = Pledge.new("bronze", 500)
|
12
|
+
pledge2 = Pledge.new("bronze", 500)
|
13
|
+
pledge3 = Pledge.new("silver", 1000)
|
14
|
+
|
15
|
+
@matched_project.found_pledge(pledge1)
|
16
|
+
@matched_project.found_pledge(pledge2)
|
17
|
+
@matched_project.found_pledge(pledge3)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "has half its funds" do
|
21
|
+
@matched_project.total_funds
|
22
|
+
|
23
|
+
expect(@matched_project.half_funded?).to be_truthy
|
24
|
+
end
|
25
|
+
|
26
|
+
it "gets double when half_funded" do
|
27
|
+
@matched_project.add_funds
|
28
|
+
|
29
|
+
expect(@matched_project.initial_fund).to eq(@initial_fund + (25 * 2))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'crowdfunder/pledge_pool'
|
2
|
+
|
3
|
+
module Crowdfunder
|
4
|
+
describe Pledge do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@pledge = Pledge.new(:bronze, 50)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "has a name attribute" do
|
11
|
+
expect(@pledge.name).to eq(:bronze)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "has an amount atribute" do
|
15
|
+
expect(@pledge.amount).to eq(50)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
describe "PledgePool" do
|
21
|
+
|
22
|
+
it "has 3 pledge amounts" do
|
23
|
+
|
24
|
+
pledges = PledgePool::PLEDGES.size
|
25
|
+
expect(pledges).to eq(3)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "has a bronze pledge worth $50" do
|
29
|
+
|
30
|
+
expect(PledgePool::PLEDGES[0]).to eq(Pledge.new("bronze", 50))
|
31
|
+
end
|
32
|
+
|
33
|
+
it "has a silver pledge worth $75" do
|
34
|
+
|
35
|
+
expect(PledgePool::PLEDGES[1]).to eq(Pledge.new("silver", 75))
|
36
|
+
end
|
37
|
+
|
38
|
+
it "has a gold pledge worth $100" do
|
39
|
+
|
40
|
+
expect(PledgePool::PLEDGES[2]).to eq(Pledge.new("gold", 100))
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns a random pledge" do
|
44
|
+
|
45
|
+
pledge = PledgePool.random
|
46
|
+
|
47
|
+
expect(PledgePool::PLEDGES).to include(pledge)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'crowdfunder/project'
|
2
|
+
require 'crowdfunder/fundrequest'
|
3
|
+
|
4
|
+
module Crowdfunder
|
5
|
+
describe Project do
|
6
|
+
before do
|
7
|
+
@initial_fund = 500
|
8
|
+
@target_fund = 4000
|
9
|
+
@project = Project.new("xyz", @initial_fund, @target_fund )
|
10
|
+
end
|
11
|
+
|
12
|
+
it "has an initial target funding amount" do
|
13
|
+
|
14
|
+
expect(@project.target_fund).to eq(4000)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "computes the total funding outstanding as the target
|
18
|
+
funding amount minus the funding amount" do
|
19
|
+
|
20
|
+
expect(@project.total_required_funds).to eq(4000 - @initial_fund)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "increases funds by 25 when funds are added" do
|
24
|
+
|
25
|
+
@project.add_funds
|
26
|
+
|
27
|
+
expect(@project.initial_fund).to eq(@initial_fund + 25)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "decreases funds by 15 when funds are removed" do
|
31
|
+
|
32
|
+
@project.remove_funds
|
33
|
+
|
34
|
+
expect(@project.initial_fund).to eq(@initial_fund - 15)
|
35
|
+
end
|
36
|
+
|
37
|
+
context "has a default value of 0 for funding amount" do
|
38
|
+
before do
|
39
|
+
@target_fund = 4000
|
40
|
+
@project = Project.new("xyz", @target_fund)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "has a default value of 0" do
|
44
|
+
|
45
|
+
expect(@project.initial_fund).to eq(0)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "check fully funded" do
|
50
|
+
before do
|
51
|
+
@initial_fund = 4000
|
52
|
+
@target_fund = 4000
|
53
|
+
@project = Project.new("xyz", @initial_fund, @target_fund)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "is fully funded" do
|
57
|
+
|
58
|
+
expect(@project.fully_funded?).to be_truthy
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "check under-funded" do
|
63
|
+
before do
|
64
|
+
@initial_fund = 1000
|
65
|
+
@target_fund = 4000
|
66
|
+
@project = Project.new("xyz", @initial_fund, @target_fund)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "is not fully funded" do
|
70
|
+
|
71
|
+
expect(@project.fully_funded?).to be_falsey
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
context "collection of projects" do
|
77
|
+
|
78
|
+
before do
|
79
|
+
@project1 = Project.new("abc", 45, 500)
|
80
|
+
@project2 = Project.new("lmn", 300, 1000)
|
81
|
+
@project3 = Project.new("xyz", 500, 2000)
|
82
|
+
|
83
|
+
@projects = [@project1, @project2, @project3]
|
84
|
+
end
|
85
|
+
|
86
|
+
it "is sorted by decreasing score" do
|
87
|
+
expect(@projects.sort).to eq([@project3, @project2, @project1])
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
it "accumulates the sum of all plagues for projects" do
|
93
|
+
expect(@project.pledged_funds).to be_zero
|
94
|
+
|
95
|
+
@project.found_pledge(Pledge.new(:bronze, 50))
|
96
|
+
|
97
|
+
expect(@project.pledged_funds).to eq(50)
|
98
|
+
|
99
|
+
@project.found_pledge(Pledge.new(:silver, 75))
|
100
|
+
|
101
|
+
expect(@project.pledged_funds).to eq(125)
|
102
|
+
|
103
|
+
@project.found_pledge(Pledge.new(:gold, 100))
|
104
|
+
|
105
|
+
expect(@project.pledged_funds).to eq(225)
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
it "computes total funds as the sum of a projects funding and pledges" do
|
110
|
+
@project.found_pledge(Pledge.new(:gold, 100))
|
111
|
+
@project.found_pledge(Pledge.new(:bronze, 50))
|
112
|
+
|
113
|
+
expect(@project.total_funds).to eq(650)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "yields each pledge received and sums it as the total funds received" do
|
117
|
+
@project.found_pledge(Pledge.new(:gold, 100))
|
118
|
+
@project.found_pledge(Pledge.new(:gold, 100))
|
119
|
+
@project.found_pledge(Pledge.new(:silver, 75))
|
120
|
+
@project.found_pledge(Pledge.new(:silver, 75))
|
121
|
+
@project.found_pledge(Pledge.new(:bronze, 50))
|
122
|
+
@project.found_pledge(Pledge.new(:bronze, 50))
|
123
|
+
|
124
|
+
yielded = []
|
125
|
+
@project.each_pledge_received do |pledge|
|
126
|
+
yielded << pledge
|
127
|
+
end
|
128
|
+
|
129
|
+
expect(yielded).to eq([
|
130
|
+
Pledge.new(:gold, 200),
|
131
|
+
Pledge.new(:silver, 150),
|
132
|
+
Pledge.new(:bronze, 100)
|
133
|
+
])
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: crowdfunder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paulette Erijo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-11-30 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: '3.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.0.0
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.0.0
|
33
|
+
description: |
|
34
|
+
# Crowdfunder
|
35
|
+
|
36
|
+
This is a crowdfunding app built in ruby. It can be integrated into any
|
37
|
+
ruby application and framework.
|
38
|
+
|
39
|
+
## Introduction
|
40
|
+
|
41
|
+
Crowdfunder allows for various projects be created and funded through funding rounds.
|
42
|
+
Projects will have funds added or deducted at random. Projects can also receive pledges
|
43
|
+
from 3 pledge categories to make up for additional funding.
|
44
|
+
|
45
|
+
### Technologies
|
46
|
+
|
47
|
+
* Ruby 3
|
48
|
+
* Rspec 3
|
49
|
+
|
50
|
+
## Setup
|
51
|
+
|
52
|
+
To run this gem, download then install it locally.
|
53
|
+
|
54
|
+
$ gem install crowdfunder-1.0.1.gem
|
55
|
+
|
56
|
+
You have the option to load projects from the command line in a CSV file. Additionally
|
57
|
+
a default projects.csv file is packaged in the gem.
|
58
|
+
|
59
|
+
## Sources
|
60
|
+
|
61
|
+
This app was inspired by Mike and Nicole of The Pragmatic Studio.
|
62
|
+
email: paulette@letche.net
|
63
|
+
executables:
|
64
|
+
- crowdfunder
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files: []
|
67
|
+
files:
|
68
|
+
- LICENSE
|
69
|
+
- README
|
70
|
+
- bin/crowdfunder
|
71
|
+
- bin/projects.csv
|
72
|
+
- lib/crowdfunder/die.rb
|
73
|
+
- lib/crowdfunder/fundable.rb
|
74
|
+
- lib/crowdfunder/funding_round.rb
|
75
|
+
- lib/crowdfunder/fundrequest.rb
|
76
|
+
- lib/crowdfunder/grant_project.rb
|
77
|
+
- lib/crowdfunder/matching_fund_project.rb
|
78
|
+
- lib/crowdfunder/pledge_pool.rb
|
79
|
+
- lib/crowdfunder/project.rb
|
80
|
+
- spec/crowdfunder/fundrquest_spec.rb
|
81
|
+
- spec/crowdfunder/grant_project_spec.rb
|
82
|
+
- spec/crowdfunder/matching_fund_project_spec.rb
|
83
|
+
- spec/crowdfunder/pledge_pool_spec.rb
|
84
|
+
- spec/crowdfunder/project_spec.rb
|
85
|
+
homepage: https://rubygems.org
|
86
|
+
licenses:
|
87
|
+
- MIT
|
88
|
+
metadata: {}
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '1.9'
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
requirements: []
|
104
|
+
rubygems_version: 3.3.4
|
105
|
+
signing_key:
|
106
|
+
specification_version: 4
|
107
|
+
summary: Crowdfunder is a crowdfunding app built in ruby.
|
108
|
+
test_files:
|
109
|
+
- spec/crowdfunder/fundrquest_spec.rb
|
110
|
+
- spec/crowdfunder/grant_project_spec.rb
|
111
|
+
- spec/crowdfunder/matching_fund_project_spec.rb
|
112
|
+
- spec/crowdfunder/pledge_pool_spec.rb
|
113
|
+
- spec/crowdfunder/project_spec.rb
|