crowdfund_jf 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 34580ca508b700abaefe50e7c124b45329470c95
4
+ data.tar.gz: f546c48c82e89adfd5e824c4e6d29ba68c0df10f
5
+ SHA512:
6
+ metadata.gz: de25838294a3a6a6a485e04a9bc99d59f0c327833422c1200ff34490b45ba4343caa7e4f004f678219add6856f14d5849ef7ed93ed82c08049bd4970df547c1a
7
+ data.tar.gz: 5dde6017e23b450dc9bdf353b30fa5ebfffb3fee31ebfb7ef9c6e9a984cc7e6254aa7a67dc2bdf7e7cf53e74049606cfc610986f43e796dcd4e251bf1b48d749
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) <2015> <Julian Feliciano>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ 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
File without changes
data/bin/crowdfund ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/crowdfund/incubator'
3
+
4
+ y_combinator = Crowdfund::Incubator.new('Y-Combinator')
5
+ default_project_file = File.join(File.dirname(__FILE__), 'projects.csv')
6
+ y_combinator.load_projects(ARGV.shift || default_project_file)
7
+
8
+ loop do
9
+ puts "\nIt's funding time! Enter the number of round or 'quit'"
10
+ answer = gets.chomp.downcase
11
+ case answer
12
+ when /^\d+$/
13
+ y_combinator.request_funding(answer.to_i)
14
+ when 'exit', 'quit'
15
+ y_combinator.status_of_projects
16
+ break
17
+ else
18
+ puts 'Not a valid response.'
19
+ end
20
+ end
21
+
22
+ y_combinator.save_projects
@@ -0,0 +1,3 @@
1
+ Chicago Leather Goods,5000,0
2
+ Chicago Watch Co.,1000000,225000
3
+ Timeless Magazine,10000,3700
data/bin/projects.csv ADDED
@@ -0,0 +1,3 @@
1
+ Project1,100,0
2
+ Project2,500,50
3
+ Project3,1000,100
@@ -0,0 +1,3 @@
1
+ Project3,1000,325
2
+ Project1,100,175
3
+ Project2,500,3275
@@ -0,0 +1,13 @@
1
+ module Crowdfund
2
+ class Die
3
+ attr_reader :number
4
+
5
+ def initialize
6
+ roll
7
+ end
8
+
9
+ def roll
10
+ @number = rand(1..6)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ module Crowdfund
2
+ module Fundable
3
+ def add_funds(funds=2000)
4
+ self.funding += funds
5
+ puts "#{name} received funds!"
6
+ end
7
+
8
+ def remove_funds(funds=1000)
9
+ self.funding -= funds
10
+ puts "#{name} lost funds!"
11
+ end
12
+
13
+ def funding_needed
14
+ self.target_funding - total_funding
15
+ end
16
+
17
+ def funded?
18
+ funding_needed <= 0
19
+ end
20
+
21
+ def <=>(other_project)
22
+ other_project.funding_needed <=> funding_needed
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'die'
2
+ require_relative 'project'
3
+ require_relative 'pledge_pool'
4
+
5
+ module Crowdfund
6
+ module FundingRound
7
+ def self.pitch_for_funds(project)
8
+ die = Die.new
9
+ number_rolled = die.roll
10
+
11
+ if number_rolled.even?
12
+ project.add_funds
13
+ else
14
+ project.remove_funds
15
+ end
16
+
17
+ pledge = PledgePool.random
18
+ project.accept_pledge(pledge)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'project'
2
+
3
+ module Crowdfund
4
+ class GrantProject < Project
5
+ def remove_funds
6
+ puts "#{@name} cannot have funds removed."
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,109 @@
1
+ require_relative 'funding_round'
2
+ require 'csv'
3
+
4
+ module Crowdfund
5
+ class Incubator
6
+ attr_reader :name
7
+
8
+ def initialize(name)
9
+ @name = name
10
+ @projects = []
11
+ end
12
+
13
+ def load_projects(from_file)
14
+ CSV.foreach(from_file) do |row|
15
+ project = Project.new(row[0], row[1].to_i, row[2].to_i)
16
+ add_project(project)
17
+ end
18
+ end
19
+
20
+ def save_projects(to_file='projects_funding.csv')
21
+ CSV.open(to_file, 'wb') do |csv|
22
+ @projects.sort.each do |project|
23
+ csv << [project.name, project.target_funding, project.total_funding]
24
+ end
25
+ end
26
+ # File.open(to_file, 'w') do |file|
27
+ # @projects.sort.each do |project|
28
+ # file.puts "#{project.name},#{project.target_funding},#{project.total_funding}"
29
+ # end
30
+ # end
31
+ end
32
+
33
+ def add_project(project)
34
+ @projects << project
35
+ end
36
+
37
+ def total_pledge_amount
38
+ @projects.reduce(0) { |sum, project| sum += project.total_pledges }
39
+ end
40
+
41
+ def total_funding_amount
42
+ @projects.reduce(0) { |sum, project| sum += project.total_funding }
43
+ end
44
+
45
+ def request_funding(rounds)
46
+ puts "There are #{@projects.size} projects in #{@name} that need funding:"
47
+ puts @projects
48
+
49
+ pledges = PledgePool::PLEDGES
50
+ puts "\nThere are #{pledges.size} possible pledge amounts:"
51
+ pledges.each do |pledge|
52
+ puts "\tA #{pledge.name} pledge is worth $#{pledge.amount}."
53
+ end
54
+
55
+ 1.upto(rounds) do |round|
56
+ puts "\nRound #{round}:"
57
+ @projects.each do |project|
58
+ FundingRound.pitch_for_funds(project)
59
+ puts project
60
+ end
61
+ end
62
+ end
63
+
64
+ def print_project_name_and_funding(project)
65
+ puts "#{project.name} ended with $#{project.total_funding} in funding."
66
+ end
67
+
68
+ def status_of_projects
69
+ fully_funded, under_funded = @projects.partition { |p| p.funded? }
70
+
71
+ puts "\n#{@name}'s final funding amounts:"
72
+ puts "$#{total_funding_amount}"
73
+
74
+ puts "\n#{@name}'s total pledges:"
75
+ puts "$#{total_pledge_amount}"
76
+
77
+ @projects.sort.each do |project|
78
+ puts "\n#{project.name} pledges:"
79
+ project.each_pledge do |pledge|
80
+ puts "$#{pledge.amount} in #{pledge.name} pledges"
81
+ end
82
+ puts "$#{project.total_pledges} in total pledges"
83
+ end
84
+
85
+ puts "\nFully Funded Projects:"
86
+ fully_funded.each do |project|
87
+ print_project_name_and_funding(project)
88
+ end
89
+
90
+ puts "\nUnder Funded Projects:"
91
+ under_funded.each do |project|
92
+ print_project_name_and_funding(project)
93
+ end
94
+
95
+ puts "\nStill in need of funding:"
96
+ under_funded.sort.each do |project|
97
+ formatted_name = project.name.ljust(50, '.')
98
+ puts "#{formatted_name} $#{project.funding_needed} needed."
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ if __FILE__ == $0
105
+ project = Project.new('Leather Goods', 5000)
106
+ incubator = Incubator.new('YC')
107
+ incubator.add_project(project)
108
+ incubator.request_funding(2)
109
+ end
@@ -0,0 +1,55 @@
1
+ require_relative 'incubator'
2
+
3
+ module Crowdfund
4
+ describe Incubator do
5
+
6
+ before do
7
+ $stdout = StringIO.new
8
+ @incubator = Incubator.new('YC')
9
+ end
10
+
11
+ context "with one project" do
12
+
13
+ before do
14
+ @funding = 500
15
+ @project = Project.new('Leather Goods', 5000, @funding)
16
+
17
+ @incubator.add_project(@project)
18
+ end
19
+
20
+ it "should add funds if an even number is rolled" do
21
+ allow_any_instance_of(Die).to receive(:roll).and_return(2)
22
+
23
+ @incubator.request_funding(3)
24
+
25
+ expect(@project.funding).to eq(@funding + (2000 * 3))
26
+ end
27
+
28
+ it "should remove funds if an odd number is rolled" do
29
+ allow_any_instance_of(Die).to receive(:roll).and_return(1)
30
+
31
+ @incubator.request_funding(3)
32
+
33
+ expect(@project.funding).to eq(@funding - (1000 * 3))
34
+ end
35
+ end
36
+
37
+ context "with more than one project" do
38
+
39
+ before do
40
+ @project1 = Project.new('Leather Goods', 1000)
41
+ @project2 = Project.new('American Watches', 1000)
42
+
43
+ @incubator.add_project(@project1)
44
+ @incubator.add_project(@project2)
45
+ end
46
+
47
+ it "calculates the total pledge amounts for all projects" do
48
+ @project1.accept_pledge(Pledge.new(:gold, 100))
49
+ @project2.accept_pledge(Pledge.new(:gold, 100))
50
+
51
+ expect(@incubator.total_pledge_amount).to eq(200)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,14 @@
1
+ require_relative 'project'
2
+
3
+ module Crowdfund
4
+ class MatchingProject < Project
5
+
6
+ def halfway_funded?
7
+ total_funding >= (@target_funding / 2)
8
+ end
9
+
10
+ def add_funds(funds=2000)
11
+ halfway_funded? ? super(funds * 2) : super(funds)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ module Crowdfund
2
+ Pledge = Struct.new(:name, :amount)
3
+
4
+ module PledgePool
5
+ PLEDGES = [
6
+ Pledge.new(:bronze, 50),
7
+ Pledge.new(:silver, 75),
8
+ Pledge.new(:gold, 100)
9
+ ]
10
+
11
+ def self.random
12
+ PLEDGES.sample
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,55 @@
1
+ require_relative 'fundable'
2
+
3
+ module Crowdfund
4
+ class Project
5
+ include Fundable
6
+
7
+ attr_accessor :name, :target_funding, :funding
8
+
9
+ def initialize(name, target_funding, funding=500)
10
+ @name = name
11
+ @target_funding = target_funding
12
+ @funding = funding
13
+ @pledges = Hash.new(0)
14
+ end
15
+
16
+ def each_pledge
17
+ @pledges.each do |name, amount|
18
+ yield(Pledge.new(name, amount))
19
+ end
20
+ end
21
+
22
+ def accept_pledge(pledge)
23
+ @pledges[pledge.name] += pledge.amount
24
+ puts "#{@name} received a #{pledge.name} pledge worth $#{pledge.amount}"
25
+ puts "#{@name}'s pledges: #{@pledges}"
26
+ end
27
+
28
+ def total_pledges
29
+ @pledges.values.reduce(0, :+)
30
+ end
31
+
32
+ def total_funding
33
+ @funding + total_pledges
34
+ end
35
+
36
+ def to_s
37
+ "#{@name} current funding is $#{total_funding} with $#{funding_needed} needed to reach its target funding amount."
38
+ end
39
+ end
40
+ end
41
+
42
+ if __FILE__ == $0
43
+ project = Project.new('Leather Goods', 5000)
44
+ puts project
45
+ project.add_funds
46
+ puts project.funding
47
+ project.remove_funds
48
+ puts project.funding
49
+ project.add_funds(250)
50
+ puts project.funding
51
+ project.remove_funds(150)
52
+ puts project.funding
53
+ puts project.funding_needed
54
+ puts project
55
+ end
@@ -0,0 +1,18 @@
1
+ require 'crowdfund/grant_project'
2
+
3
+ module Crowdfund
4
+ describe GrantProject do
5
+
6
+ before do
7
+ $stdout = StringIO.new
8
+ @initial_funding = 1000
9
+ @project = GrantProject.new('CPS CS classes', 10000, @initial_funding)
10
+ end
11
+
12
+ it "cannot have funds removed" do
13
+ @project.remove_funds
14
+
15
+ expect(@project.funding).to eq(@initial_funding)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ require 'crowdfund/matching_project'
2
+
3
+ module Crowdfund
4
+ describe MatchingProject do
5
+
6
+ before do
7
+ $stdout = StringIO.new
8
+ @target_funding = 10000
9
+ @project = MatchingProject.new('Re-issued N64', @target_funding, 0)
10
+ end
11
+
12
+ it "returns true if halfway funded" do
13
+ @project.add_funds(@target_funding / 2)
14
+
15
+ expect(@project.halfway_funded?).to be_truthy
16
+ end
17
+
18
+ it "should not match funds when under halfway to target funding" do
19
+ @project.add_funds(4999)
20
+
21
+ expect(@project.funding).to eq(4999)
22
+ end
23
+
24
+ it "should match funds when halfway to target funding" do
25
+ @project.add_funds(5000)
26
+ @project.add_funds(1000)
27
+
28
+ expect(@project.funding).to eq(5000 + (1000 * 2))
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,43 @@
1
+ require 'crowdfund/pledge_pool'
2
+
3
+ module Crowdfund
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 attribute" do
15
+ expect(@pledge.amount).to eq(50)
16
+ end
17
+ end
18
+
19
+ describe PledgePool do
20
+
21
+ it "has 3 pledges" do
22
+ expect(PledgePool::PLEDGES.size).to eq(3)
23
+ end
24
+
25
+ it "has a bronze pledge worth $50" do
26
+ expect(PledgePool::PLEDGES[0]).to eq(Pledge.new(:bronze, 50))
27
+ end
28
+
29
+ it "has a silver pledge worth $75" do
30
+ expect(PledgePool::PLEDGES[1]).to eq(Pledge.new(:silver, 75))
31
+ end
32
+
33
+ it "has a gold pledge worth $100" do
34
+ expect(PledgePool::PLEDGES[2]).to eq(Pledge.new(:gold, 100))
35
+ end
36
+
37
+ it "returns a random pledge" do
38
+ random = PledgePool.random
39
+
40
+ expect(PledgePool::PLEDGES).to include(random)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,129 @@
1
+ require 'crowdfund/project'
2
+ require 'crowdfund/pledge_pool'
3
+
4
+ module Crowdfund
5
+ describe Project do
6
+
7
+ before do
8
+ $stdout = StringIO.new
9
+ @target_funding = 5000
10
+ @funding = 500
11
+ @project = Project.new('Leather Goods', @target_funding, @funding)
12
+ end
13
+
14
+ it "has an initial target funding amount" do
15
+ expect(@project.target_funding).to eq(5000)
16
+ end
17
+
18
+ it "computes the total funding outstanding as the target funding amount minus the funding amount" do
19
+ expect(@project.funding_needed).to eq(@target_funding - @funding)
20
+ end
21
+
22
+ it "increases funds by 2000 when funds are added" do
23
+ @project.add_funds
24
+
25
+ expect(@project.funding).to eq(@funding + 2000)
26
+ end
27
+
28
+ it "decreases funds by 1000 when funds are removed" do
29
+ @project.remove_funds
30
+
31
+ expect(@project.funding).to eq(@funding - 1000)
32
+ end
33
+
34
+ it "calculates the total amount of pledges" do
35
+ expect(@project.total_pledges).to eq(0)
36
+
37
+ @project.accept_pledge(Pledge.new(:bronze, 50))
38
+
39
+ expect(@project.total_pledges).to eq(50)
40
+
41
+ @project.accept_pledge(Pledge.new(:silver, 75))
42
+
43
+ expect(@project.total_pledges).to eq(125)
44
+
45
+ @project.accept_pledge(Pledge.new(:gold, 100))
46
+
47
+ expect(@project.total_pledges).to eq(225)
48
+ end
49
+
50
+ it "calculates total funding as funding with its pledges" do
51
+ @project.accept_pledge(Pledge.new(:bronze, 50))
52
+ @project.accept_pledge(Pledge.new(:gold, 100))
53
+
54
+ expect(@project.total_funding).to eq(650)
55
+ end
56
+
57
+ it "yields each pledge and its amount" do
58
+ @project.accept_pledge(Pledge.new(:bronze, 50))
59
+ @project.accept_pledge(Pledge.new(:bronze, 50))
60
+ @project.accept_pledge(Pledge.new(:silver, 75))
61
+ @project.accept_pledge(Pledge.new(:silver, 75))
62
+ @project.accept_pledge(Pledge.new(:gold, 100))
63
+ @project.accept_pledge(Pledge.new(:gold, 100))
64
+
65
+ yielded = []
66
+ @project.each_pledge do |pledge|
67
+ yielded << pledge
68
+ end
69
+
70
+ expect(yielded).to eq([
71
+ Pledge.new(:bronze, 100),
72
+ Pledge.new(:silver, 150),
73
+ Pledge.new(:gold, 200)
74
+ ])
75
+ end
76
+
77
+ context "with a default funding" do
78
+
79
+ before do
80
+ @project = Project.new('Leather Goods', 5000)
81
+ end
82
+
83
+ it "has a funding amount of 500" do
84
+ expect(@project.funding).to eq(500)
85
+ end
86
+ end
87
+
88
+ context "with its target funding met" do
89
+
90
+ before do
91
+ @project = Project.new('Leather Goods', 5000, 5000)
92
+ end
93
+
94
+ it "is funded" do
95
+ # expect(@project.funded?).to eq(true)
96
+ # expect(@project.funded?).to be_truthy
97
+ expect(@project).to be_funded
98
+ end
99
+ end
100
+
101
+ context "with its target funding not met" do
102
+
103
+ before do
104
+ @project = Project.new('Leather Goods', 5000, 500)
105
+ end
106
+
107
+ it "is not funded" do
108
+ # expect(@project.funded?).to eq(false)
109
+ # expect(@project.funded?).to be_falsey
110
+ expect(@project).not_to be_funded
111
+ end
112
+ end
113
+
114
+ context "in a collection of projects" do
115
+
116
+ before do
117
+ @project1 = Project.new('Leather Goods', 1000)
118
+ @project2 = Project.new('Watches', 2000)
119
+ @project3 = Project.new('Racing Attire', 3000)
120
+
121
+ @projects = [@project1, @project2, @project3]
122
+ end
123
+
124
+ it "sorts by amount outstanding in descending order" do
125
+ expect(@projects.sort).to eq([@project3, @project2, @project1])
126
+ end
127
+ end
128
+ end
129
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: crowdfund_jf
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Julian Feliciano
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-28 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
+ email: julsfelic@gmail.com
29
+ executables:
30
+ - crowdfund
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE
35
+ - README
36
+ - bin/crowdfund
37
+ - bin/julians_projects.csv
38
+ - bin/projects.csv
39
+ - bin/projects_funding.csv
40
+ - lib/crowdfund/die.rb
41
+ - lib/crowdfund/fundable.rb
42
+ - lib/crowdfund/funding_round.rb
43
+ - lib/crowdfund/grant_project.rb
44
+ - lib/crowdfund/incubator.rb
45
+ - lib/crowdfund/incubator_spec.rb
46
+ - lib/crowdfund/matching_project.rb
47
+ - lib/crowdfund/pledge_pool.rb
48
+ - lib/crowdfund/project.rb
49
+ - spec/crowdfund/grant_project_spec.rb
50
+ - spec/crowdfund/matching_project_spec.rb
51
+ - spec/crowdfund/pledge_pool_spec.rb
52
+ - spec/crowdfund/project_spec.rb
53
+ homepage: http://www.pragmaticstudio.com
54
+ licenses:
55
+ - MIT
56
+ metadata: {}
57
+ post_install_message:
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '1.9'
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubyforge_project:
73
+ rubygems_version: 2.4.6
74
+ signing_key:
75
+ specification_version: 4
76
+ summary: A funding app for startups!
77
+ test_files:
78
+ - spec/crowdfund/grant_project_spec.rb
79
+ - spec/crowdfund/matching_project_spec.rb
80
+ - spec/crowdfund/pledge_pool_spec.rb
81
+ - spec/crowdfund/project_spec.rb