We are going on a trip later today, and we want to create an application that will help us pack our bags based on the weather at our destination.
As a user I want to:
- Tell the app where I'm going
- e.g. 'London, UK', 'Honolulu, HI', 'Dalton, GA'
- Tell the app how many days I'll be gone for.
- Have the app tell me the overall forecast for those days.
- e.g. "January 18th will be sunny, with a low of 45 and a high of 72."
- Have the app tell me what clothing to pack for the trip, both based on temperature as well as weather conditions
- e.g. "You should bring shorts, a windbreaker, and a visor."
- Have the app write to a file so I can retrieve the results later.
We're going to get daily weather data for a location. Suppose the user has already supplied us with city
and days
.
units = "imperial" # you can change this to metric if you prefer
options = "daily?q=#{CGI::escape(city)}&mode=json&units=#{units}&cnt=#{days}"
url = "http://api.openweathermap.org/data/2.5/forecast/#{options}"
Remember we need to escape the city since spaces and certain characters in a url can cause errors.
Let's create the class that will be our main object. Once we're ready to start the program, we'll simply run the following code, and bask in the glory of our efforts.
trip_planner = TripPlanner.new
trip_planner.start
This means that TripPlanner
will have the following attributes and methods:
TripPlanner
will need to keep track of a user
, the forecast
, and the recommendation
. These attributes should be read only, there's no reason for the main program flow to have to change them directly.
Our initialize will be funny, in that it won't do anything, or take any parameters.
Start is where the action happens. Start, as a method, should do these things:
- Assign the result of
.create_user
to@user
- Assign the result of
.retrieve_forecast
to@forecast
- Assign the result of
.create_recommendation
to@recommendation
- Report the forecast and recommendation, and save it to a file
As the method name suggests, it should ask the person at the keyboard for their name, destination city, and duration of the trip. It will then call User.new
, passing along that information, and storing it in @user
.
This method will make the actual call to the API, and do the parsing of the data the API returns.
It should strip only the information useful to create Weather
objects, described below, and then create and store the array of weather objects in @forecast
Hint: It might help to have some additional helper methods to keep .retrieve_forecast
slim. I would suggest having call_api
and parse_result
methods.
This method will take the @forecast
array, and create the actual recommendation for your trip.
Hint: Again, I would create a few helper methods to implement this. Perhaps: collect_clothes
, collect_accessories
, display_recommendation
, save_recommendation
.
Since the TripPlanner
will store the forecast as an array of Weather
objects, I suppose we should have a Weather
Class.
The weather object will be responsible for suggesting clothing and accessories based on the min_temp
, max_temp
, and condition
We're only going to care about min_temp
, max_temp
, and condition
when it comes to making decisions about the day. Again, we won't need to change these during the course of the program, so just make them readable.
We'll also do something totally new: the Weather
class will be much more usable if we create two separate class constants: CLOTHES
and ACCESSORIES
. Here's something to get you started:
class Weather
CLOTHES = [
{
min_temp: -50, max_temp: 0,
suggestions: [
"insulated parka", "long underwear", "fleece-lined jeans",
"mittens", "knit hat", "chunky scarf"
]
}
]
ACCESSORIES = [
{
condition: "Rainy",
suggestions: [
"galoshes", "umbrella"
]
}
]
end
These are arrays of hashes, where the first one allows us to search by range and the second by condition.
For methods inside the class, you can just access these constants as written: ACCESSORIES[0][:condition]
or CLOTHES[0][:suggestions]
, etc.
Appropriate clothing depends on what temperatures you'll have to endure for the day. This method should utilize the class method Weather::clothing_for
to grab the clothing for the max and min temps, and return those results as an array of suggestions without repeat.
Appropriate accessories depend on what conditions you'll face that day. This method should utilize the class method Weather::accessories_for
to grab the accessories for the condition, and return those results as an array of suggestions without repeat.
To make the previous two methods easier to implement, let's create two class level methods to do the actual lookup with our constants:
This class should actually do the heavy lifting for Weather#appropriate_clothing
. It should select
and map
from the CLOTHES
array the suggestions appropriate for condition
.
This class should actually do the heavy lifting for Weather#appropriate_accessories
. It should select
and map
from the ACCESSORIES
array the suggestions appropriate for condition
.
Here we want to store (and leave alone) their name
, and the destination
and duration
for their trip.