-
Notifications
You must be signed in to change notification settings - Fork 72
Matt Crocco solution & tests #52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,38 +1,78 @@ | ||
| class NoApplesError < StandardError; end | ||
|
|
||
| class AppleTree | ||
| attr_#fill_in :height, :age, :apples, :alive | ||
| class Tree | ||
| attr_reader :height, :age, :apples, :alive | ||
|
|
||
| def initialize | ||
| def initialize(max_possible_age=10, max_growth: 3, apple_color: 'orange') | ||
| raise ArgumentError, 'Ages must be positive and non-zero' if max_possible_age <= 0 | ||
| raise ArgumentError, 'Growth rates may only be positive and non-zero' if max_growth <= 0 | ||
|
|
||
| @height = 0 | ||
|
|
||
| @age = 0 | ||
| @max_age = rand(1..max_possible_age) | ||
| @max_growth = max_growth | ||
|
|
||
| @apples = [] | ||
| @apple_color = apple_color | ||
| @alive = true | ||
| end | ||
|
|
||
| def age! | ||
| @age += 1 | ||
|
|
||
| if @age > @max_age | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| @alive = false | ||
| else | ||
| @height += rand(1..@max_growth) | ||
| add_apples | ||
| end | ||
| end | ||
|
|
||
| def add_apples | ||
| rand(2..8).times { @apples << make_apple } | ||
| end | ||
|
|
||
| def any_apples? | ||
| [email protected]? | ||
| end | ||
|
|
||
| def pick_an_apple! | ||
| raise NoApplesError, "This tree has no apples" unless self.any_apples? | ||
| raise NoApplesError, 'This tree has no apples' unless self.any_apples? | ||
| @apples.pop | ||
| end | ||
|
|
||
| def dead? | ||
| !@alive | ||
| end | ||
|
|
||
| private | ||
| def make_apple | ||
| Apple.new(@apple_color, rand(2..6)) | ||
| end | ||
|
|
||
| end | ||
|
|
||
| class Fruit | ||
| attr_reader :has_seeds | ||
|
|
||
| def initialize | ||
| has_seeds = true | ||
| @has_seeds = true | ||
| end | ||
| end | ||
|
|
||
| class Apple < | ||
| attr_reader #what should go here | ||
| class Apple < Fruit | ||
| attr_reader :color, :diameter | ||
|
|
||
| def initialize(color, diameter) | ||
| raise ArgumentError, 'An apple must have a color' if color.nil? | ||
| raise ArgumentError, 'Diameter of an apple may not be negative or zero' if diameter <= 0 | ||
| raise ArgumentError, 'Diameter must be finite' if diameter.is_a?(Float) && diameter.infinite? | ||
|
|
||
| super() | ||
|
|
||
| @color = color | ||
| @diameter = diameter | ||
| end | ||
| end | ||
|
|
||
|
|
@@ -55,13 +95,8 @@ def tree_data | |
| basket << tree.pick_an_apple! | ||
| end | ||
|
|
||
| diameter_sum = 0 | ||
|
|
||
| basket.each do |apple| | ||
| diameter_sum += apple.diameter | ||
| end | ||
|
|
||
| avg_diameter = # It's up to you to calculate the average diameter for this harvest. | ||
| diameter_sum = basket.map(&:diameter).reduce :+ | ||
| avg_diameter = diameter_sum / basket.length | ||
|
|
||
| puts "Year #{tree.age} Report" | ||
| puts "Tree height: #{tree.height} feet" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,175 @@ | ||
| require 'rspec' | ||
| require 'tree' | ||
|
|
||
| describe 'Tree' do | ||
| describe Tree do | ||
| let(:tree) { Tree.new } | ||
|
|
||
| it 'should be a Class' do | ||
| expect(described_class.is_a? 'Class').to be_true | ||
| expect(described_class).to be_a(Class) | ||
| end | ||
|
|
||
| it 'can age to a positive, non-zero maximum' do | ||
| expect { Tree.new(-1) }.to raise_error(ArgumentError) | ||
| expect { Tree.new(0) }.to raise_error(ArgumentError) | ||
|
|
||
| expect { Tree.new(1) }.not_to raise_error | ||
| expect { Tree.new }.not_to raise_error | ||
| end | ||
|
|
||
| it 'can grow by a positive, non-zero rate' do | ||
| expect { Tree.new(max_growth: -1) }.to raise_error(ArgumentError) | ||
| expect { Tree.new(max_growth: 0) }.to raise_error(ArgumentError) | ||
|
|
||
| expect { Tree.new(max_growth: 1) }.not_to raise_error | ||
| expect { Tree.new }.not_to raise_error | ||
| end | ||
|
|
||
| it 'starts out alive' do | ||
| expect(tree).not_to be_dead | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| end | ||
|
|
||
| it 'starts out with no apples' do | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I love the story approach of your tests. Keep in mind using contexts to improve readability. |
||
| expect(tree.apples).to be_empty | ||
| end | ||
|
|
||
| it 'starts at age 0 with height 0 and no apples' do | ||
| expect(tree.age).to eq 0 | ||
| expect(tree.height).to eq 0 | ||
| end | ||
|
|
||
| it 'ages a year at a time' do | ||
| tree.age! | ||
| expect(tree.age).to eq 1 | ||
|
|
||
| 3.times { tree.age! } | ||
| expect(tree.age).to eq 4 | ||
| end | ||
|
|
||
| it 'grows in height when it ages' do | ||
| tree.age! | ||
| expect(tree.height).to be > 0 | ||
| end | ||
|
|
||
| it 'grows apples when it ages' do | ||
| tree.age! | ||
| expect(tree).to be_any_apples | ||
| end | ||
|
|
||
| it 'grows apples of a particular color' do | ||
| tree = Tree.new(apple_color: 'red') | ||
| tree.age! until tree.apples.length > 1 | ||
|
|
||
| apple_colors = tree.apples.map &:color | ||
| expect(apple_colors).to all( eq 'red' ) | ||
| end | ||
|
|
||
| it 'dies at a max age' do | ||
| tree = Tree.new 20 | ||
|
|
||
| expect(tree).not_to be_dead | ||
|
|
||
| # If tree is not dead after 21 iterations then the | ||
| # tree is undying and that's probably impossible in reality.ss | ||
| until tree.dead? or tree.age > 20 | ||
| tree.age! | ||
| end | ||
|
|
||
| expect(tree).to be_dead | ||
| end | ||
|
|
||
| it 'should continue to age in death' do | ||
| tree.age! until tree.dead? | ||
|
|
||
| start_age = tree.age | ||
| tree.age! | ||
|
|
||
| expect(tree.age - start_age).to eq 1 | ||
|
|
||
| start_age = tree.age | ||
| 20.times { tree.age! } | ||
|
|
||
| expect(tree.age - start_age).to eq 20 | ||
| end | ||
|
|
||
| it 'does not grow once dead' do | ||
| tree.age! until tree.dead? | ||
|
|
||
| start_height = tree.height | ||
| tree.age! | ||
| expect(tree.height - start_height).to be_zero | ||
| end | ||
|
|
||
| it 'does not bear fruit once dead' do | ||
| tree.age! until tree.dead? | ||
| tree.pick_an_apple! while tree.any_apples? | ||
|
|
||
| tree.age! | ||
| expect(tree.apples).to be_empty | ||
| end | ||
|
|
||
| it 'provides an apple, if it has any' do | ||
| tree.age! | ||
|
|
||
| apple = tree.pick_an_apple! | ||
| expect(apple).not_to be nil | ||
| expect(apple).to be_instance_of(Apple) | ||
| end | ||
|
|
||
| it 'throws a NoApplesError when picking apples if none exists' do | ||
| expect { tree.pick_an_apple! }.to raise_error(NoApplesError) | ||
|
|
||
| tree.age! | ||
| tree.pick_an_apple! while tree.any_apples? | ||
|
|
||
| expect { tree.pick_an_apple! }.to raise_error(NoApplesError) | ||
| end | ||
|
|
||
| it 'can magically have apples added to it. By magic.' do | ||
| tree.add_apples | ||
| expect(tree.apples).not_to be_empty | ||
| end | ||
| end | ||
|
|
||
| describe 'Fruit' do | ||
| describe Fruit do | ||
| let(:fruit) { Fruit.new } | ||
|
|
||
| it 'is a Class' do | ||
| expect(described_class).to be_a(Class) | ||
| end | ||
|
|
||
| it 'has seeds' do | ||
| expect(fruit.has_seeds).to be true | ||
| end | ||
| end | ||
|
|
||
| describe 'Apple' do | ||
| describe Apple do | ||
| let(:apple) { Apple.new('international orange', rand(3..10)) } | ||
|
|
||
| it 'is a Class' do | ||
| expect(described_class).to be_a(Class) | ||
| end | ||
|
|
||
| it 'is a subclass of Fruit' do | ||
| expect(described_class).to be < Fruit | ||
| end | ||
|
|
||
| it 'has seeds' do | ||
| expect(apple.has_seeds).to be true | ||
| end | ||
|
|
||
| it 'has a color' do | ||
| expect { Apple.new(nil, 2) }.to raise_error(ArgumentError) | ||
|
|
||
| expect(apple.color).not_to be_nil | ||
| expect(apple.color).to eq 'international orange' | ||
| end | ||
|
|
||
| it 'has a finite, positive, non-zero diameter' do | ||
| expect_failure = lambda { |d| expect { Apple.new('red', d) }.to raise_error(ArgumentError) } | ||
| expect_success = lambda { |d| expect { Apple.new('red', d) }.not_to raise_error } | ||
|
|
||
| [Float::INFINITY, -Float::INFINITY].each &expect_failure | ||
| [-1, 0].each &expect_failure | ||
| [1, 4, 2304].each &expect_success | ||
| end | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this. One thing you'll see are custom errors. Something like...