crowdfund23 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c233a84593b27bd3d9a6c89ab028a60beab20ba27427aad01b5225ee5009ea08
4
+ data.tar.gz: 505c124fa05c915e54c901a2cc8dbcd0a5930252c52728a596b97c25b7cac433
5
+ SHA512:
6
+ metadata.gz: 3fc99395f879209fe021eeb6564d4b2a69794e9e5d88aa56ad215455a6a5e78b7ebe3fa7fbbcb1649824b4b16346e041cea7fdfcc269d36e31b59e3c99acb5a0
7
+ data.tar.gz: 655197032c659a46a1d02991fb9d9a0ba7293c8c4f6932aae47dd727eb0c518a8c82e7e56ec2c671f6f90649699e7fe678c1fd9548baef00a63de9144ef720b1
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2023 BluePeony
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 @@
1
+ This gem is the result of exercises as part of the Ruby Tutorial from PragmaticStudio.
data/bin/crowdfund23 ADDED
@@ -0,0 +1,28 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require_relative '../lib/crowdfund23/collection'
4
+ project1 = Crowdfund23::Project.new("Books from random strangers", 500, 3000)
5
+ project2 = Crowdfund23::Project.new("For the Love of Quote", 25, 75)
6
+ project3 = Crowdfund23::Project.new("Sucky Sockets", 750, 1000)
7
+ project4 = Crowdfund23::Project.new("Buy a house", 100000, 300000)
8
+ project5 = Crowdfund23::GrantProject.new("A charity project", 500, 2000)
9
+
10
+ collection = Crowdfund23::Collection.new("Test")
11
+ default_project_file = File.join(File.dirname(__FILE__), 'my_projects.csv')
12
+ collection.load_projects(ARGV.shift || default_project_file)
13
+ collection.add_project(project5)
14
+
15
+ loop do
16
+ puts "\nHow many rounds of funding? ('quit' or 'exit' to exit)"
17
+ answer = gets.chomp
18
+ case answer
19
+ when 'quit', 'exit'
20
+ collection.print_stats
21
+ collection.save_projects('underfunded_projects.csv')
22
+ break
23
+ when /^\d+$/
24
+ collection.request_funding(answer.to_i)
25
+ else
26
+ puts "Please enter a number or 'quit' or 'exit' to exit."
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ Book From Random Strangers, 50
2
+ For the Love of Quote, 100
3
+ Sucky Sockets, 250
@@ -0,0 +1,88 @@
1
+ require_relative 'project'
2
+ require_relative 'grant_project'
3
+ require_relative 'die'
4
+ require_relative 'funding_round'
5
+ require_relative 'pledge_pool'
6
+ require 'csv'
7
+
8
+ module Crowdfund23
9
+ class Collection
10
+
11
+ def initialize(title)
12
+ @title = title
13
+ @projects = []
14
+ end
15
+
16
+ def add_project(project)
17
+ @projects << project
18
+ end
19
+
20
+ def print_stats
21
+
22
+ fully_funded, under_funded = @projects.partition {|project| project.fully_funded? }
23
+ puts "\n Statistics:"
24
+
25
+ puts "\n#{fully_funded.size} fully funded projects:"
26
+ print_name_and_fundings(fully_funded)
27
+
28
+ puts "\n#{under_funded.size} under funded projects:"
29
+ print_name_and_fundings(under_funded)
30
+
31
+ puts "\nStill need contributions:"
32
+ under_funded.sort {|a, b| b.fund_needed <=> a.fund_needed}.each do |project|
33
+ puts "#{project.name}: fundings needed: #{project.fund_needed}"
34
+ end
35
+
36
+ @projects.each do |project|
37
+ puts "\nProject #{project.name}'s pledges:"
38
+ project.each_pledge_received do |pledge|
39
+ puts "$#{pledge.amount} in #{pledge.name} pledges"
40
+ end
41
+ puts "$#{project.total_amount_pledges} in total pledges"
42
+ end
43
+ end
44
+
45
+ def print_name_and_fundings(projects)
46
+ projects.each do |p|
47
+ puts "#{p.name}: current funding: #{p.current_fund}; funding goal: #{p.fund_goal}"
48
+ end
49
+ end
50
+
51
+ def load_projects(from_file)
52
+ CSV.foreach(from_file) do |row|
53
+ add_project(Project.new(row[0], row[1].to_i))
54
+ end
55
+ end
56
+
57
+ def save_projects(to_file)
58
+ underfounded_projects = @projects.reject { |project| project.fully_funded? }
59
+ File.open(to_file, 'w') do |file|
60
+ underfounded_projects.each do |project|
61
+ file.puts "#{project.name} still needs $#{project.fund_needed} of funding."
62
+ end
63
+ end
64
+ end
65
+
66
+ def request_funding(rounds)
67
+ puts "Currently there are #{@projects.size} projects in the pipeline."
68
+ puts @projects
69
+
70
+ pledges = PledgePool::PLEDGES
71
+ puts "\nThere are #{pledges.size} possible pledge amounts:"
72
+
73
+ pledges.each do |pledge|
74
+ puts " A #{pledge.name} pledge is worth $#{pledge.amount}."
75
+ end
76
+
77
+ 1.upto(rounds) do |round|
78
+ puts "\n Funding Round #{round}:"
79
+ @projects.each do |project|
80
+ FundingRound.adjust_funds(project)
81
+ puts project
82
+ end
83
+ end
84
+
85
+ @projects.each
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,13 @@
1
+ module Crowdfund23
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,23 @@
1
+ module Crowdfund23
2
+ module Fundable
3
+
4
+ def add_funds(new_fund = 25)
5
+ self.current_fund += new_fund
6
+ puts "#{name} got more funds!"
7
+ end
8
+
9
+ def remove_funds(lost_fund = 15)
10
+ self.current_fund -= lost_fund
11
+ puts "#{name} lost some funds!"
12
+ end
13
+
14
+ def fund_needed
15
+ fund_goal - current_fund
16
+ end
17
+
18
+ def fully_funded?
19
+ fund_needed <= 0
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ require_relative 'die'
2
+ require_relative 'project'
3
+ require_relative 'pledge_pool'
4
+
5
+ module Crowdfund23
6
+ module FundingRound
7
+ def self.adjust_funds(project)
8
+ die = Die.new
9
+ number = die.roll
10
+ if number.even?
11
+ project.add_funds
12
+ else
13
+ project.remove_funds
14
+ end
15
+
16
+ if project.grant_project
17
+ project.matching_funds
18
+ end
19
+
20
+ pledge = PledgePool.random
21
+ project.store_pledge(pledge)
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ require_relative 'project'
2
+
3
+ module Crowdfund23
4
+ class GrantProject < Project
5
+
6
+ def initialize(name, current_fund, fund_goal)
7
+ super
8
+ @grant_project = true
9
+ @received_matched_funds = false
10
+ end
11
+
12
+ def remove_funds
13
+ puts "It's a grant project. Funds can't be removed."
14
+ end
15
+
16
+ def matching_funds
17
+ tipping_point_funds = fund_goal / 2.0
18
+ if fund_needed <= tipping_point_funds && !@received_matched_funds
19
+ add_funds(tipping_point_funds)
20
+ @received_matched_funds = true
21
+ puts "Congratulation! You received matching funds! The fund goal was: #{fund_goal}. The current fund is: #{current_fund}."
22
+ end
23
+ end
24
+ end
25
+
26
+ if __FILE__ == $0
27
+ project = GrantProject.new("grant project", 100, 500)
28
+ puts "current funds before the method: #{project.current_fund}"
29
+ project.remove_funds
30
+ puts "current funds after the method: #{project.current_fund}"
31
+
32
+ project.add_funds(160)
33
+ project.matching_funds
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ module Crowdfund23
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
+ end
@@ -0,0 +1,41 @@
1
+ require_relative 'pledge_pool'
2
+ require_relative 'fundable'
3
+
4
+ module Crowdfund23
5
+ class Project
6
+
7
+ include Fundable
8
+
9
+ attr_reader :fund_goal, :pledges_received, :grant_project
10
+ attr_accessor :name, :current_fund
11
+
12
+ def initialize(name, current_fund = 0, fund_goal)
13
+ @name = name
14
+ @current_fund = current_fund
15
+ @fund_goal = fund_goal
16
+ @pledges_received = Hash.new(0)
17
+ @grant_project = false
18
+ end
19
+
20
+ def to_s
21
+ "#{@name} has $#{@current_fund} toward a goal of $#{@fund_goal}."
22
+ end
23
+
24
+ def store_pledge(pledge)
25
+ @pledges_received[pledge.name] += pledge.amount
26
+ @current_fund += pledge.amount
27
+ puts "#{@name} received a #{pledge.name} pledge worth $#{pledge.amount}."
28
+ puts "#{@name}'s pledges: #{@pledges_received}"
29
+ end
30
+
31
+ def each_pledge_received
32
+ @pledges_received.each do |name, amount|
33
+ yield Pledge.new(name, amount)
34
+ end
35
+ end
36
+
37
+ def total_amount_pledges
38
+ @pledges_received.values.reduce(0, :+)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,61 @@
1
+ require 'crowdfund23/collection'
2
+
3
+ module Crowdfund23
4
+ describe Collection do
5
+
6
+ before do
7
+ @collection = Collection.new("Test Collection")
8
+ @fund_now = 50
9
+ @fund_end = 100
10
+ @project = Project.new("First project", @fund_now, @fund_end)
11
+ @collection.add_project(@project)
12
+ end
13
+
14
+ it "has funds added (+25) when an even number is rolled" do
15
+ Die.any_instance.stub(:roll).and_return(4)
16
+
17
+ @collection.request_funding(2)
18
+ pledges_amount_total = @project.pledges_received.values.reduce(0, :+)
19
+ expect(@project.current_fund).to eq @fund_now + pledges_amount_total + 25*2
20
+ #@project.current_fund.should == @fund_now + 25
21
+ end
22
+
23
+ it "has funds removed when an odd number is rolled" do
24
+ Die.any_instance.stub(:roll).and_return(3)
25
+
26
+ @collection.request_funding(2)
27
+ pledges_amount_total = @project.pledges_received.values.reduce(0, :+)
28
+ expect(@project.current_fund).to eq @fund_now + pledges_amount_total - 15*2
29
+ #@project.current_fund.should == @fund_now - 15
30
+ end
31
+
32
+
33
+ context "is fully funded" do
34
+
35
+ before do
36
+ @fund_now = 100
37
+ @fund_goal = 100
38
+ @project = Project.new("Fully Funded", @fund_now, @fund_goal)
39
+ end
40
+
41
+ it "is fully funded if fund_needed is less than or equal to 0 " do
42
+ expect(@project).to be_fully_funded
43
+ #@project.should be_fully_funded
44
+ end
45
+ end
46
+
47
+ context "is not yet fully funded" do
48
+
49
+ before do
50
+ @fund_now = 10
51
+ @fund_goal = 100
52
+ @project = Project.new("Not Fully Funded", @fund_now, @fund_goal)
53
+ end
54
+
55
+ it "is not fully funded" do
56
+ expect(@project).not_to be_fully_funded
57
+ #@project.should_not be_fully_funded
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,43 @@
1
+ require 'crowdfund23/pledge_pool'
2
+
3
+ module Crowdfund23
4
+ describe Pledge do
5
+
6
+ before do
7
+ @pledge = Pledge.new(:bronze, 50)
8
+ end
9
+
10
+ it "has a name" do
11
+ expect(@pledge.name).to eq :bronze
12
+ end
13
+
14
+ it "has a pledge amount" 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 "has a random method" do
38
+ pledge = PledgePool.random
39
+
40
+ expect(PledgePool::PLEDGES).to include(pledge)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,57 @@
1
+ require 'crowdfund23/project'
2
+ require 'crowdfund23/pledge_pool'
3
+
4
+ module Crowdfund23
5
+ describe Project do
6
+
7
+ before do
8
+ @fund_now = 50
9
+ @fund_target = 100
10
+ @project = Project.new("RSpec", @fund_now, @fund_target)
11
+ $stdout = StringIO.new
12
+ end
13
+
14
+ it "has an initial target amount" do
15
+ @project.fund_goal.should == @fund_target
16
+ end
17
+
18
+ it "computes the total funding outstanding as the target funding amount minus the funding amount" do
19
+ @project.fund_needed.should == @fund_target - @fund_now
20
+ end
21
+
22
+ it "increases funds by 25 when funds are raised" do
23
+ @project.add_funds
24
+ expect(@project.current_fund).to eq @fund_now + 25
25
+ #@project.current_fund.should == @fund_now + 25
26
+ end
27
+
28
+ it "descreases funds by 15 when funds are removed" do
29
+
30
+ @project.remove_funds
31
+ expect(@project.current_fund).to eq @fund_now - 15
32
+ #@project.current_fund.should == @fund_now - 15
33
+ end
34
+
35
+ it "adds the amount for a pledge to the total fundings received" do
36
+ @project.add_funds
37
+ pledge = Pledge.new(:gold, 100)
38
+ @project.store_pledge(pledge)
39
+
40
+ expect(@project.current_fund).to eq 175
41
+ end
42
+
43
+
44
+ context "created with a default funding_amount" do
45
+
46
+ before do
47
+ @p = Project.new("Test for default amount", 50)
48
+ end
49
+
50
+ it "has a default value of 0 for funding amount" do
51
+ expect(@p.current_fund).to eq 0
52
+ #@p.current_fund.should == 0
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,100 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
+ RSpec.configure do |config|
17
+ # rspec-expectations config goes here. You can use an alternate
18
+ # assertion/expectation library such as wrong or the stdlib/minitest
19
+ # assertions if you prefer.
20
+ config.expect_with :rspec do |expectations|
21
+ # This option will default to `true` in RSpec 4. It makes the `description`
22
+ # and `failure_message` of custom matchers include text for helper methods
23
+ # defined using `chain`, e.g.:
24
+ # be_bigger_than(2).and_smaller_than(4).description
25
+ # # => "be bigger than 2 and smaller than 4"
26
+ # ...rather than:
27
+ # # => "be bigger than 2"
28
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
29
+ expectations.syntax = [:should, :expect]
30
+ end
31
+
32
+ # rspec-mocks config goes here. You can use an alternate test double
33
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
34
+ config.mock_with :rspec do |mocks|
35
+ # Prevents you from mocking or stubbing a method that does not exist on
36
+ # a real object. This is generally recommended, and will default to
37
+ # `true` in RSpec 4.
38
+ mocks.verify_partial_doubles = true
39
+ mocks.syntax = [:should, :expect]
40
+ end
41
+
42
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
43
+ # have no way to turn it off -- the option exists only for backwards
44
+ # compatibility in RSpec 3). It causes shared context metadata to be
45
+ # inherited by the metadata hash of host groups and examples, rather than
46
+ # triggering implicit auto-inclusion in groups with matching metadata.
47
+ config.shared_context_metadata_behavior = :apply_to_host_groups
48
+
49
+ # The settings below are suggested to provide a good initial experience
50
+ # with RSpec, but feel free to customize to your heart's content.
51
+ =begin
52
+ # This allows you to limit a spec run to individual examples or groups
53
+ # you care about by tagging them with `:focus` metadata. When nothing
54
+ # is tagged with `:focus`, all examples get run. RSpec also provides
55
+ # aliases for `it`, `describe`, and `context` that include `:focus`
56
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
57
+ config.filter_run_when_matching :focus
58
+
59
+ # Allows RSpec to persist some state between runs in order to support
60
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
61
+ # you configure your source control system to ignore this file.
62
+ config.example_status_persistence_file_path = "spec/examples.txt"
63
+
64
+ # Limits the available syntax to the non-monkey patched syntax that is
65
+ # recommended. For more details, see:
66
+ # https://relishapp.com/rspec/rspec-core/docs/configuration/zero-monkey-patching-mode
67
+ config.disable_monkey_patching!
68
+
69
+ # This setting enables warnings. It's recommended, but in some cases may
70
+ # be too noisy due to issues in dependencies.
71
+ config.warnings = true
72
+
73
+ # Many RSpec users commonly either run the entire suite or an individual
74
+ # file, and it's useful to allow more verbose output when running an
75
+ # individual spec file.
76
+ if config.files_to_run.one?
77
+ # Use the documentation formatter for detailed output,
78
+ # unless a formatter has already been configured
79
+ # (e.g. via a command-line flag).
80
+ config.default_formatter = "doc"
81
+ end
82
+
83
+ # Print the 10 slowest examples and example groups at the
84
+ # end of the spec run, to help surface which specs are running
85
+ # particularly slow.
86
+ config.profile_examples = 10
87
+
88
+ # Run specs in random order to surface order dependencies. If you find an
89
+ # order dependency and want to debug it, you can fix the order by providing
90
+ # the seed, which is printed after each run.
91
+ # --seed 1234
92
+ config.order = :random
93
+
94
+ # Seed global randomization in this process using the `--seed` CLI option.
95
+ # Setting this allows you to use `--seed` to deterministically reproduce
96
+ # test failures related to randomization by passing the same `--seed` value
97
+ # as the one that triggered the failure.
98
+ Kernel.srand config.seed
99
+ =end
100
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: crowdfund23
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - BluePeony
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-02-07 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: '2.8'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.8.0
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.8'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.8.0
33
+ description: This gem is the result of exercises as part of the Ruby Tutorial from
34
+ PragmaticStudio.
35
+ email: live_by@example.com
36
+ executables:
37
+ - crowdfund23
38
+ extensions: []
39
+ extra_rdoc_files: []
40
+ files:
41
+ - LICENSE
42
+ - README
43
+ - bin/crowdfund23
44
+ - bin/my_projects.csv
45
+ - lib/crowdfund23/collection.rb
46
+ - lib/crowdfund23/die.rb
47
+ - lib/crowdfund23/fundable.rb
48
+ - lib/crowdfund23/funding_round.rb
49
+ - lib/crowdfund23/grant_project.rb
50
+ - lib/crowdfund23/pledge_pool.rb
51
+ - lib/crowdfund23/project.rb
52
+ - spec/crowdfund23/collection_spec.rb
53
+ - spec/crowdfund23/pledge_pool_spec.rb
54
+ - spec/crowdfund23/project_spec.rb
55
+ - spec/spec_helper.rb
56
+ homepage: http://example.com
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '1.9'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubygems_version: 3.4.6
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: A gem from exercise block of the Ruby course from PragmaticStudio
79
+ test_files:
80
+ - spec/crowdfund23/collection_spec.rb
81
+ - spec/crowdfund23/pledge_pool_spec.rb
82
+ - spec/crowdfund23/project_spec.rb
83
+ - spec/spec_helper.rb