diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 4c209dde8f..8a8514113e 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,24 +1,24 @@
# Your name
-Please write your full name here to make it easier to find your pull request.
+Luke Storey
-# User stories
+# User stories
Please list which user stories you've implemented (delete the ones that don't apply).
-- [ ] User story 1: "I want to instruct a plane to land at an airport"
-- [ ] User story 2: "I want to instruct a plane to take off from an airport and confirm that it is no longer in the airport"
-- [ ] User story 3: "I want to prevent landing when the airport is full"
-- [ ] User story 4: "I would like a default airport capacity that can be overridden as appropriate"
-- [ ] User story 5: "I want to prevent takeoff when weather is stormy"
-- [ ] User story 6: "I want to prevent landing when weather is stormy"
+- [x] User story 1: "I want to instruct a plane to land at an airport"
+- [x] User story 2: "I want to instruct a plane to take off from an airport and confirm that it is no longer in the airport"
+- [x] User story 3: "I want to prevent landing when the airport is full"
+- [x] User story 4: "I would like a default airport capacity that can be overridden as appropriate"
+- [x] User story 5: "I want to prevent takeoff when weather is stormy"
+- [x] User story 6: "I want to prevent landing when weather is stormy"
# README checklist
Does your README contains instructions for
-- [ ] how to install,
-- [ ] how to run,
-- [ ] and how to test your code?
+- [x] how to install,
+- [x] how to run,
+- [x] and how to test your code?
-[Here is a pill](https://github.com/makersacademy/course/blob/main/pills/readmes.md) that can help you write a great README!
\ No newline at end of file
+[Here is a pill](https://github.com/makersacademy/course/blob/main/pills/readmes.md) that can help you write a great README!
diff --git a/Gemfile b/Gemfile
index b1a320395a..4344b2ec77 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,6 +6,7 @@ group :test do
gem 'rspec'
gem 'simplecov', require: false
gem 'simplecov-console', require: false
+ gem 'simplecov-shields-badge', require: false
end
group :development, :test do
diff --git a/Gemfile.lock b/Gemfile.lock
index 66064703c7..b6a5c0e236 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -45,6 +45,8 @@ GEM
simplecov
terminal-table
simplecov-html (0.12.3)
+ simplecov-shields-badge (0.1.0)
+ simplecov (~> 0.15)
simplecov_json_formatter (0.1.3)
terminal-table (3.0.1)
unicode-display_width (>= 1.1.1, < 3)
@@ -58,6 +60,7 @@ DEPENDENCIES
rubocop (= 1.20)
simplecov
simplecov-console
+ simplecov-shields-badge
RUBY VERSION
ruby 3.0.2p107
diff --git a/README.md b/README.md
index 6dd4fa6bc9..0d7b1aa4bc 100644
--- a/README.md
+++ b/README.md
@@ -1,89 +1,187 @@
-Airport Challenge
-=================
+# Airport Challenge
+[](https://github.com/rubocop/rubocop)
+[](https://github.com/lukestorey95/airport_challenge)
+
+This program allows the user to simulate a working airport. Planes are able to land and take off from an airport so long as the weather isn't stormy.
+
+
+
+## Installation
+
+```
+$ git clone https://github.com/lukestorey95/airport_challenge.git
+
+$ cd airport_challenge
+
+$ bundle
```
- ______
- _\____\___
-= = ==(____MA____)
- \_____\___________________,-~~~~~~~`-.._
- / o o o o o o o o o o o o o o o o |\_
- `~-.__ __..----..__ )
- `---~~\___________/------------`````
- = ===(_________)
+
+
+
+## Quickstart
+
+```
+irb
+
+> Dir['./lib/*.rb'].each {|file| require file }
+
+> airport = Airport.new
+> plane = Plane.new
+
+> airport.land(plane)
+
+> airport.take_off(plane)
+```
+
+> For more usage please see user stories below
+
+
+
+## Running Tests
+
+```
+$ rspec
+```
+
+
+ Click to see test results
+
+
+
+
+
+
+
+## My Process
+
+1. Break down user story into objects and behaviour
+2. Feature test and note down errors/expected errors
+3. Write failing test that replicates errors
+4. Write the minimum code to make test pass
+5. Refactor and ensure tests still pass
+6. Repeat step 2 and ensure behaviour works as intended
+
+
+
+## User Stories
+
+> I want to instruct a **_plane_** to **_land_** at an **_airport_**
```
+airport = Airport.new
+plane = Plane.new
+airport.land(plane)
+```
+
+---
+
+> I want to instruct a **_plane_** to **_take off_** from an **_airport_** and **_confirm_** that it is no longer in the **_airport_**
-Instructions
----------
+```
+airport = Airport.new
+plane = Plane.new
+airport.land(plane)
+airport.take_off(plane)
+airport.planes
+```
-* Feel free to use google, your notes, books, etc. but work on your own
-* If you refer to the solution of another coach or student, please put a link to that in your README
-* If you have a partial solution, **still check in a partial solution**
-* You must submit a pull request to this repo with your code by 10am Monday morning
+---
-Steps
--------
+> I want to **_prevent landing_** when the **_airport_** is **_full_**
-1. Fork this repo, and clone to your local machine
-2. Run the command `gem install bundler` (if you don't have bundler already)
-3. When the installation completes, run `bundle`
-4. Complete the following task:
+```
+airport = Airport.new
+plane = Plane.new
+airport.land(plane)
+airport.land(plane)
+```
-Task
------
+---
-We have a request from a client to write the software to control the flow of planes at an airport. The planes can land and take off provided that the weather is sunny. Occasionally it may be stormy, in which case no planes can land or take off. Here are the user stories that we worked out in collaboration with the client:
+> I would like a **_default airport capacity_** that can **_be overridden_** as appropriate
```
-As an air traffic controller
-So I can get passengers to a destination
-I want to instruct a plane to land at an airport
+airport = Airport.new(3)
+plane = Plane.new
+airport.capacity.times { airport.land(plane) }
+airport.land(plane)
+```
-As an air traffic controller
-So I can get passengers on the way to their destination
-I want to instruct a plane to take off from an airport and confirm that it is no longer in the airport
+---
-As an air traffic controller
-To ensure safety
-I want to prevent landing when the airport is full
+> I want to **_prevent takeoff_** when **_weather_** is stormy
-As the system designer
-So that the software can be used for many different airports
-I would like a default airport capacity that can be overridden as appropriate
+```
+airport = Airport.new
+plane = Plane.new
+weather = Weather.new
+airport.land(plane)
+airport.take_off(plane)
+#=> should raise error if weather is stormy
+```
-As an air traffic controller
-To ensure safety
-I want to prevent takeoff when weather is stormy
+---
-As an air traffic controller
-To ensure safety
-I want to prevent landing when weather is stormy
+> I want to **_prevent landing_** when **_weather_** is stormy
+
+```
+airport = Airport.new
+plane = Plane.new
+weather = Weather.new
+airport.land(plane)
+#=> should raise error if weather is stormy
```
-Your task is to test drive the creation of a set of classes/modules to satisfy all the above user stories. You will need to use a random number generator to set the weather (it is normally sunny but on rare occasions it may be stormy). In your tests, you'll need to use a stub to override random weather to ensure consistent test behaviour.
+
-Your code should defend against [edge cases](http://programmers.stackexchange.com/questions/125587/what-are-the-difference-between-an-edge-case-a-corner-case-a-base-case-and-a-b) such as inconsistent states of the system ensuring that planes can only take off from airports they are in; planes that are already flying cannot take off and/or be in an airport; planes that are landed cannot land again and must be in an airport, etc.
+## Edge Cases
-For overriding random weather behaviour, please read the documentation to learn how to use test doubles: https://www.relishapp.com/rspec/rspec-mocks/docs . There’s an example of using a test double to test a die that’s relevant to testing random weather in the test.
+> I want to **_prevent_** a **_plane_** from **_taking off_**, if it is not in the correct **_airport_**
-Please create separate files for every class, module and test suite.
+```
+airport = Airport.new
+plane = Plane.new
+airport.take_off(plane)
+#=> should raise error
+```
-In code review we'll be hoping to see:
+> I want to **_prevent_** a **_landed plane_** from **_landing_** again
-* All tests passing
-* High [Test coverage](https://github.com/makersacademy/course/blob/main/pills/test_coverage.md) (>95% is good)
-* The code is elegant: every class has a clear responsibility, methods are short etc.
+```
+airport = Airport.new
+plane = Plane.new
+airport.land(plane)
+airport.land(plane)
+#=> should raise error
+```
-Reviewers will potentially be using this [code review rubric](docs/review.md). Referring to this rubric in advance will make the challenge somewhat easier. You should be the judge of how much challenge you want this at this moment.
+> I want to **_prevent_** a **_flying plane_** from **_taking off_** again
-**BONUS**
+```
+airport = Airport.new
+plane = Plane.new
+airport.land(plane)
+airport.take_off(plane)
+airport.take_off(plane)
+#=> should raise error
+```
+
+
+
+## Feature Test
-* Write an RSpec **feature** test that lands and takes off a number of planes
+> I want to **_land_** and then **_take off_** several **_planes_** at once
-Note that is a practice 'tech test' of the kinds that employers use to screen developer applicants. More detailed submission requirements/guidelines are in [CONTRIBUTING.md](CONTRIBUTING.md)
+```
+airport = Airport.new(3)
+planes = Array.new(3) { Plane.new }
+
+planes.each { |plane| airport.land(plane) }
-Finally, don’t overcomplicate things. This task isn’t as hard as it may seem at first.
+# airport should contain the planes and the planes should be landed
-* **Submit a pull request early.**
+planes.each { |plane| airport.take_off(plane) }
-* Finally, please submit a pull request before Monday at 10am with your solution or partial solution. However much or little amount of code you wrote please please please submit a pull request before Monday at 10am.
+# airport should not contain the planes and the planes should be flying
+```
diff --git a/README_INSTRUCTIONS.md b/README_INSTRUCTIONS.md
new file mode 100644
index 0000000000..6dd4fa6bc9
--- /dev/null
+++ b/README_INSTRUCTIONS.md
@@ -0,0 +1,89 @@
+Airport Challenge
+=================
+
+```
+ ______
+ _\____\___
+= = ==(____MA____)
+ \_____\___________________,-~~~~~~~`-.._
+ / o o o o o o o o o o o o o o o o |\_
+ `~-.__ __..----..__ )
+ `---~~\___________/------------`````
+ = ===(_________)
+
+```
+
+Instructions
+---------
+
+* Feel free to use google, your notes, books, etc. but work on your own
+* If you refer to the solution of another coach or student, please put a link to that in your README
+* If you have a partial solution, **still check in a partial solution**
+* You must submit a pull request to this repo with your code by 10am Monday morning
+
+Steps
+-------
+
+1. Fork this repo, and clone to your local machine
+2. Run the command `gem install bundler` (if you don't have bundler already)
+3. When the installation completes, run `bundle`
+4. Complete the following task:
+
+Task
+-----
+
+We have a request from a client to write the software to control the flow of planes at an airport. The planes can land and take off provided that the weather is sunny. Occasionally it may be stormy, in which case no planes can land or take off. Here are the user stories that we worked out in collaboration with the client:
+
+```
+As an air traffic controller
+So I can get passengers to a destination
+I want to instruct a plane to land at an airport
+
+As an air traffic controller
+So I can get passengers on the way to their destination
+I want to instruct a plane to take off from an airport and confirm that it is no longer in the airport
+
+As an air traffic controller
+To ensure safety
+I want to prevent landing when the airport is full
+
+As the system designer
+So that the software can be used for many different airports
+I would like a default airport capacity that can be overridden as appropriate
+
+As an air traffic controller
+To ensure safety
+I want to prevent takeoff when weather is stormy
+
+As an air traffic controller
+To ensure safety
+I want to prevent landing when weather is stormy
+```
+
+Your task is to test drive the creation of a set of classes/modules to satisfy all the above user stories. You will need to use a random number generator to set the weather (it is normally sunny but on rare occasions it may be stormy). In your tests, you'll need to use a stub to override random weather to ensure consistent test behaviour.
+
+Your code should defend against [edge cases](http://programmers.stackexchange.com/questions/125587/what-are-the-difference-between-an-edge-case-a-corner-case-a-base-case-and-a-b) such as inconsistent states of the system ensuring that planes can only take off from airports they are in; planes that are already flying cannot take off and/or be in an airport; planes that are landed cannot land again and must be in an airport, etc.
+
+For overriding random weather behaviour, please read the documentation to learn how to use test doubles: https://www.relishapp.com/rspec/rspec-mocks/docs . There’s an example of using a test double to test a die that’s relevant to testing random weather in the test.
+
+Please create separate files for every class, module and test suite.
+
+In code review we'll be hoping to see:
+
+* All tests passing
+* High [Test coverage](https://github.com/makersacademy/course/blob/main/pills/test_coverage.md) (>95% is good)
+* The code is elegant: every class has a clear responsibility, methods are short etc.
+
+Reviewers will potentially be using this [code review rubric](docs/review.md). Referring to this rubric in advance will make the challenge somewhat easier. You should be the judge of how much challenge you want this at this moment.
+
+**BONUS**
+
+* Write an RSpec **feature** test that lands and takes off a number of planes
+
+Note that is a practice 'tech test' of the kinds that employers use to screen developer applicants. More detailed submission requirements/guidelines are in [CONTRIBUTING.md](CONTRIBUTING.md)
+
+Finally, don’t overcomplicate things. This task isn’t as hard as it may seem at first.
+
+* **Submit a pull request early.**
+
+* Finally, please submit a pull request before Monday at 10am with your solution or partial solution. However much or little amount of code you wrote please please please submit a pull request before Monday at 10am.
diff --git a/badge.svg b/badge.svg
new file mode 100644
index 0000000000..7b87dd394b
--- /dev/null
+++ b/badge.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/lib/airport.rb b/lib/airport.rb
new file mode 100644
index 0000000000..4627acfdba
--- /dev/null
+++ b/lib/airport.rb
@@ -0,0 +1,59 @@
+class Airport
+ DEFAULT_CAPACITY = 2
+
+ def initialize(capacity = DEFAULT_CAPACITY)
+ @capacity = capacity
+ @hangar = Array.new
+ @weather = Weather.new
+ end
+
+ def land(plane)
+ check_weather_condition
+ check_airport_capacity
+ land_plane(plane)
+ end
+
+ def take_off(plane)
+ check_plane_at_airport(plane)
+ check_weather_condition
+ take_off_plane(plane)
+ end
+
+ def include?(plane)
+ hangar.include?(plane)
+ end
+
+ private
+
+ attr_reader :hangar, :capacity, :weather
+
+ def check_weather_condition
+ fail 'Weather is stormy' if stormy?
+ end
+
+ def stormy?
+ weather.stormy?
+ end
+
+ def land_plane(plane)
+ plane.land
+ hangar << plane
+ end
+
+ def check_airport_capacity
+ fail 'Airport full' if full?
+ end
+
+ def full?
+ hangar.length == capacity
+ end
+
+ def take_off_plane(plane)
+ plane.take_off
+ hangar.delete(plane)
+ end
+
+ def check_plane_at_airport(plane)
+ fail 'Plane not at airport' unless include?(plane)
+ end
+end
diff --git a/lib/plane.rb b/lib/plane.rb
new file mode 100644
index 0000000000..878b60a3ed
--- /dev/null
+++ b/lib/plane.rb
@@ -0,0 +1,27 @@
+class Plane
+ def initialize
+ @landed = nil
+ end
+
+ def land
+ raise 'Plane already landed' if landed?
+ self.landed = true
+ end
+
+ def take_off
+ raise 'Plane already flying' if flying?
+ self.landed = false
+ end
+
+ private
+
+ attr_accessor :landed
+
+ def landed?
+ landed
+ end
+
+ def flying?
+ !landed && !landed.nil?
+ end
+end
diff --git a/lib/weather.rb b/lib/weather.rb
new file mode 100644
index 0000000000..93688d046c
--- /dev/null
+++ b/lib/weather.rb
@@ -0,0 +1,17 @@
+class Weather
+ def initialize
+ @stormy = random_weather
+ end
+
+ def stormy?
+ stormy
+ end
+
+ private
+
+ attr_reader :stormy
+
+ def random_weather
+ rand(2).zero?
+ end
+end
diff --git a/spec/airport_spec.rb b/spec/airport_spec.rb
new file mode 100644
index 0000000000..6707fbad69
--- /dev/null
+++ b/spec/airport_spec.rb
@@ -0,0 +1,89 @@
+describe Airport do
+ let(:airport) { Airport.new }
+ let(:plane) { instance_double('Plane', land: true, take_off: false) }
+ before(:each) { allow(airport).to receive(:stormy?).and_return(false) }
+
+ describe '#new' do
+ subject { Airport }
+
+ context 'should have a default capacity' do
+ it { should respond_to(:new).with(0) }
+ end
+
+ context 'should allow capacity to be set' do
+ it { should respond_to(:new).with(1) }
+ end
+ end
+
+ def land_plane
+ airport.land(plane)
+ end
+
+ describe '#land' do
+ context 'when it is not full' do
+ context 'when weather is good' do
+ it 'should instruct the plane to land' do
+ expect(plane).to receive(:land)
+ land_plane
+ end
+
+ it 'should contain the plane after it has been landed' do
+ land_plane
+ expect(airport).to include(plane)
+ end
+ end
+
+ context 'when weather is stormy' do
+ before { allow(airport).to receive(:stormy?).and_return(true) }
+
+ it 'should not instruct the plane to land' do
+ expect { land_plane }.to raise_error('Weather is stormy')
+ end
+ end
+ end
+
+ context 'when it is full' do
+ it 'should not instruct the plane to land' do
+ Airport::DEFAULT_CAPACITY.times { land_plane }
+ another_plane = double('Plane')
+ expect { airport.land(another_plane) }.to raise_error('Airport full')
+ end
+ end
+ end
+
+ describe '#take_off' do
+ def take_off_plane
+ airport.take_off(plane)
+ end
+
+ context 'when it contains the plane' do
+ before(:each) { land_plane }
+
+ context 'when weather is good' do
+ it 'should instruct the plane to take off' do
+ expect(plane).to receive(:take_off)
+ take_off_plane
+ end
+
+ it 'should no longer contain the plane after it has taken off' do
+ take_off_plane
+ expect(airport).to_not include(plane)
+ end
+ end
+
+ context 'when weather is stormy' do
+ before { allow(airport).to receive(:stormy?).and_return(true) }
+
+ it 'should not instruct the plane to take off' do
+ expect { take_off_plane }.to raise_error('Weather is stormy')
+ end
+ end
+ end
+
+ context "when it doesn't contain the plane" do
+ it 'should not instruct the plane to take off' do
+ expect { take_off_plane }.to raise_error('Plane not at airport')
+ end
+ end
+ end
+end
diff --git a/spec/plane_spec.rb b/spec/plane_spec.rb
new file mode 100644
index 0000000000..ebd92bb922
--- /dev/null
+++ b/spec/plane_spec.rb
@@ -0,0 +1,36 @@
+describe Plane do
+ let(:plane) { described_class.new }
+
+ describe '#land' do
+ context 'when flying' do
+ it 'should land' do
+ expect(plane).to receive(:land).and_return(true)
+ plane.land
+ end
+ end
+
+ context 'when landed' do
+ it 'should not land again' do
+ plane.land
+ expect { plane.land }.to raise_error('Plane already landed')
+ end
+ end
+ end
+
+ describe '#take_off' do
+
+ context 'when landed' do
+ it 'should take off' do
+ expect(plane).to receive(:take_off).and_return(false)
+ plane.take_off
+ end
+ end
+
+ context 'when flying' do
+ it 'should not take off again' do
+ plane.take_off
+ expect { plane.take_off }.to raise_error('Plane already flying')
+ end
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 252747d899..803d4f9a5f 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -6,12 +6,20 @@
# Want a nice code coverage website? Uncomment this next line!
# SimpleCov::Formatter::HTMLFormatter
])
-SimpleCov.start
-
-RSpec.configure do |config|
- config.after(:suite) do
- puts
- puts "\e[33mHave you considered running rubocop? It will help you improve your code!\e[0m"
- puts "\e[33mTry it now! Just run: rubocop\e[0m"
- end
+SimpleCov.start do
+ add_filter 'spec'
+ require 'shields_badge'
+ SimpleCov.formatter = SimpleCov::Formatter::ShieldsBadge
end
+
+require 'airport'
+require 'plane'
+require 'weather'
+
+# RSpec.configure do |config|
+# config.after(:suite) do
+# puts
+# puts "\e[33mHave you considered running rubocop? It will help you improve your code!\e[0m"
+# puts "\e[33mTry it now! Just run: rubocop\e[0m"
+# end
+# end
diff --git a/spec/weather_spec.rb b/spec/weather_spec.rb
new file mode 100644
index 0000000000..1008e6a497
--- /dev/null
+++ b/spec/weather_spec.rb
@@ -0,0 +1,7 @@
+describe Weather do
+ describe "#stormy?" do
+ it 'should check if it is stormy' do
+ expect(subject.stormy?).to be(true).or be(false)
+ end
+ end
+end
diff --git a/test_results.png b/test_results.png
new file mode 100644
index 0000000000..6acadb9acc
Binary files /dev/null and b/test_results.png differ