Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.bundle/
.vscode/
bin/
4 changes: 4 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.2.5)
rspec (3.1.0)
Expand All @@ -19,3 +20,6 @@ PLATFORMS

DEPENDENCIES
rspec

BUNDLED WITH
1.16.1
66 changes: 51 additions & 15 deletions lib/tree.rb
Original file line number Diff line number Diff line change
@@ -1,44 +1,77 @@
class NoApplesError < StandardError; end

# A class representing an apple tree
class Tree
attr_#fill_in :height, :age, :apples, :alive

def initialize
MAX_AGE = 20
FRUIT_AGE = 2
GROWTH_PER_YEAR = 2 # inches

attr_accessor :height, :age, :apples, :alive
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should everything be writable? you can make these private as well.

class Foo
  def bar
    baz = 'bang'
  end

  private
  attr_accessor :baz
end


def initialize(height = 0, age = 0, apples = [], alive = true)
@height = height
@age = age
@apples = apples
@alive = alive
@death_age = rand(0..Tree::MAX_AGE)
end

def age!
if @age < @death_age
@age += 1
@height += Tree::GROWTH_PER_YEAR
if @age > Tree::FRUIT_AGE
20.times do
@apples << Apple.new('red', rand(1..4))
end
end
else
@alive = false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good practice to use getters/setters when you can instead of ivars. One you may want to redefine a getter say...

  def apples
    @apples ||= []
  end

end
end

def add_apples
def add_apples(apples)
if apples.is_a? Apple
@apples << apples
elsif apples.is_a? Array
@apples += apples
end
end

def any_apples?
!@apples.empty?
end

def pick_an_apple!
raise NoApplesError, "This tree has no apples" unless self.any_apples?
raise NoApplesError, 'This tree has no apples' unless any_apples?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've used a bang for this method name because it may possibly raise an error. If this mutates data, we may also use a bang.

@apples.pop
end

def dead?
!@alive
end
end

# Base class for fruits, which all have seeds.
class Fruit
def initialize
has_seeds = true
end
end

class Apple <
attr_reader #what should go here
# Class representing an Apple, which derives from Fruit, if you didn't know.
class Apple < Fruit
attr_reader :color, :diameter

def initialize(color, diameter)
@color = color
@diameter = diameter
end
end

#THERES ONLY ONE THING YOU NEED TO EDIT BELOW THIS LINE
# avg_diameter (line 58) will raise an error.
# it should calculate the diameter of the apples in the basket
# THERES ONLY ONE THING YOU NEED TO EDIT BELOW THIS LINE
# avg_diameter (line 58) will raise an error.
# it should calculate the diameter of the apples in the basket

def tree_data
tree = Tree.new
Expand All @@ -61,19 +94,22 @@ def tree_data
diameter_sum += apple.diameter
end

avg_diameter = # It's up to you to calculate the average diameter for this harvest.
# It's up to you to calculate the average diameter for this harvest.
avg_diameter = diameter_sum / basket.size.to_f

puts "Year #{tree.age} Report"
puts "Tree height: #{tree.height} feet"
puts "Harvest: #{basket.size} apples with an average diameter of #{avg_diameter} inches"
puts ""
puts ''

# Ages the tree another year
tree.age!
end

puts "Alas, the tree, she is dead!"
puts 'Alas, the tree, she is dead!'
end

# Uncomment this line to run the script, but BE SURE to comment it before you try to run your tests!
# tree_data
# Uncomment this line to run the script, but BE SURE to comment it before you
# try to run your tests!

tree_data
122 changes: 118 additions & 4 deletions spec/tree_spec.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,128 @@
require 'rspec'
require 'tree'
# require 'pry'
require_relative '../lib/tree'

describe Tree do
it 'should be a Class' do
expect(described_class.is_a? Class).to eq true
expect(described_class.is_a?(Class)).to eq true
end

describe '#initialize' do
tree = Tree.new

it 'should default height to 0' do
expect(tree.height).to eq(0)
end

it 'should default age to 0' do
expect(tree.age).to eq(0)
end

it 'should be alive' do
expect(tree.alive).to eq(true)
end

it "shouldn't have any apples" do
expect(tree.apples.size).to eq(0)
end
end

describe '#age!' do
it 'should increase the age by one year' do
tree = Tree.new
tree.age!
expect(tree.age).to eq(1)
tree.age!
expect(tree.age).to eq(2)
end

it 'should increase the height by Tree::GROWTH_PER_YEAR' do
tree = Tree.new
tree.age!
expect(tree.height).to eq(Tree::GROWTH_PER_YEAR)
tree.age!
expect(tree.height).to eq(Tree::GROWTH_PER_YEAR * 2)
end
end

describe '#add_apples' do
it 'should add the specified apples to the tree' do
red_apple = Apple.new('red', 1)
green_apple = Apple.new('green', 2)
tree = Tree.new
tree.add_apples([red_apple, green_apple])
expect(tree.apples.size).to eq(2)
expect(tree.apples[0]).to eq(red_apple)
expect(tree.apples[1]).to eq(green_apple)
end

it 'should allow a single apple to be added to the tree' do
red_apple = Apple.new('red', 1)
tree = Tree.new
tree.add_apples(red_apple)
expect(tree.apples.size).to eq(1)
expect(tree.apples[0]).to eq(red_apple)
end
end

describe '#any_apples?' do
it 'should return false for a new Tree without apples' do
tree = Tree.new
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See subject and .let those are preferred here.
http://betterspecs.org/

expect(tree.any_apples?).to eq(false)
end

it 'should return true for a Tree that has apples' do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good case for using a context. Contexts can also be nested.

describe '#any_apples?' do
  context 'a tree with apples' do
    it 'returns true' do
      ..
    end
  end

  context 'a tree without apples' do
    it 'returns false' do
      ..
    end
  end
end

tree = Tree.new
tree.add_apples Apple.new('red', 1)
expect(tree.any_apples?).to eq(true)
end
end

describe '#pick_an_apple!' do
tree = Tree.new
it 'should raise an exception for a Tree without apples' do
expect { tree.pick_an_apple! }.to raise_error(NoApplesError)
end

red_apple = Apple.new('red', 1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my other comment about subject and let

it 'should return an apple for a Tree with apples' do
tree.add_apples(red_apple)
expect(tree.pick_an_apple!).to eq(red_apple)
end

it 'should decrement the number of apples in the tree' do
tree.add_apples(red_apple)
tree.pick_an_apple!
expect(tree.apples.size).to eq(0)
end
end

describe '#dead?' do
it 'should return false if the Tree is alive' do
expect(Tree.new.dead?).to eq(false)
end

it 'should return true if the Tree is not alive' do
dead_yearling = Tree.new(2, 1, [], false)
expect(dead_yearling.dead?).to eq(true)
end
end
end

describe 'Fruit' do
describe Fruit do
it 'should be a Class' do
expect(described_class.is_a?(Class)).to eq true
end
end

describe 'Apple' do
describe Apple do
let(:apple) { described_class.new('red', 10) }

it 'should be a Class' do
expect(described_class.is_a?(Class)).to eq true
end

it 'should be a Fruit' do
expect(apple.is_a?(Fruit)).to eq true
end
end