Welcome, Guest User :: Click here to login

Logo 67272

Lab 2: TempConverter; Pixar

Due Date: February 14

Objectives

  • Learn the basics of Ruby programming
  • Learn how to work with Time class in Ruby
  • Learn to use irb command prompt
  • Improve familiarity with basic git commands

README.md

Part 1: Ruby Introduction

Some students have had prior exposure to Ruby, but others in the class may have little or no experience with the language. This part of the lab will get everyone familiar with some Ruby basics and provide review of other key concepts. This is a short introduction, but there are some 'on your own' exercises at the very end that students are strongly encouraged to try to solidify their understanding of Ruby.

  1. We are going to begin by writing a simple program for Ruby to convert temperatures and then modify it several times. To begin, create a new file called temp_conversions.rb using your preferred editor/IDE. Ask a TA for help on this if you need.

  2. In this file, create a method called convert as follows:

    def convert(temp)
    
    end
    

Between these two lines, add in the following line of code to convert Fahrenheit to Celsius:

5 * (temp - 32)/9

After the end statement, create some simple tests for this method with the code below:

puts convert(32)          
puts convert(50)          
puts convert(212)

Run this code from the command line by changing to the same directory as the file and typing ruby temp_conversions.rb. You should get the output 0, 10, 100 as a result. Once this is running, set up a git repository and add this file to it. (Ask the TA if you don't remember how to do this from the previous labs.)

  1. Now go into the method and remove the parentheses to the right of 32 and rerun this code. Note the error returned. Fix the error and rerun the code with ruby -c -w temp_conversions.rb. The -c flag means 'check syntax only' and the –w flag activates higher warnings. When you run this time, you should see a new message.

  2. Add the test puts convert("zero") to the tests and rerun the code normally. Why did you get an error? To correct this, we will limit all temperatures to integers by adding a line before the calculation in our method:

return "Temperature must be an integer" unless temp.class == Integer

Rerun these tests after adding this line. If the tests pass, add the revision to the git repository. Also notice that if I want to return before the end of method, I need to use the return keyword, but if the method runs its course, the last value is automatically returned by the method. Finally, notice that I can place the condition at the end of the line in Ruby, not just at the beginning (as we are used to in other languages).

  1. Add the test puts convert(-500) to the tests and rerun. Of course, remembering your basic physics leaves you distressed at this point because you know this answer is in error – Absolute Zero is at –474 degrees Fahrenheit or -270 degrees Celsius, making this result impossible. To make sure our program doesn't give silly answers, we will add another line after the last correction (and before the calculation):
return "Temperature below Absolute Zero" if temp < -474 

Rerun the tests; assuming they pass, save the revision to the git repository.

  1. Of course, we have only half the temperature conversion problem – converting Fahrenheit to Celsius – and have no capability to convert Celsius to Fahrenheit. Create a new branch in git called exp (Again, ask a TA if you don't remember this from previous labs). Now in your code, add another argument called measure and using an if ... else ... end construct, correct the code so that either a Fahrenheit or Celsius temperature is converted. Set up the measure argument so its default value is "F". Add the test below:
puts convert(0, "C")
puts convert(10, "C")
puts convert(100, "C")
puts convert(-280, "C")

Rerun the code; if all tests pass, save to the repository.

  1. Looking at the results, we see that the code is still problematic: we get a result for –280 oC even though we know that value is below Absolute Zero. There are a number of ways to correct this, but for learning purposes here, we are going to create a new method called below_absolute_zero? which has two arguments: temp and measure. This method will simply return a boolean of true if the temperature for the measurement system is below the critical value; this is why this method will end in a question mark. Create the basic structure for this method now.

Add the following code so your complete method looks like this:

def below_absolute_zero?(temp, measure)
    (temp < -454 and measure == "F") or (temp < -270 and measure == "C")
end

A couple of things to note here: (1) we have used the words and and or to demonstrate that Ruby does understand these words, but most times we will use the programming standards of && and || for these conjunctions, (2) if we provide Ruby a statement like temp < -454, the statement is evaluated as either true or false and that result is returned.

Back to the code: go to the convert method and change the if statement for the Absolute Zero condition so that it references this new method rather than the simple statement of temp < -474. Rerun the code and make sure that everything is working properly. If so, save this code to the git repository. Checkout the master branch, and then merge the exp branch onto the master branch. (Again, ask a TA is you don't remember how to do this.)


Stop

Show a TA that you have completed the temp_conversion program and have properly saved the code to git. Make sure the TA initials your sheet.


Part 2: Interactive Ruby

  1. We are going to switch gears now and start to interact with Ruby with irb [interactive ruby]. The irb prompt is a useful command line tool that can allow you to try out simple ruby constructs and methods. To get to interactive ruby, just type irb on the command line.

  2. Once in irb, type

a = Time.now

This gives us an object a with a Ruby timestamp. Now type in

require 'date'
b = Date.today

Compare this result with the results of the first command. What is the difference between these two objects? Be sure you are clear on the difference before proceeding (ask a TA if you are unsure).

  1. Now type a.month and note what is output is. Now type a.strftime("%B") and note the output. How would you find the year of a? (Guess ...) Try your idea in irb now.

  2. Now type the command

a.month == b.month

What was returned? Type the command

a.day == b.day - 1

and see that result as well. As we noted earlier in the temp conversion method, Ruby is evaluating these statements as either true or false and returning the result.

  1. Use the strftime method to format the object a in the format of 99/99/9999. To see the options with strftime we can take advantage of a gem Prof. H uses sometimes in class: cheat. (To install this gem, run gem install cheat in a terminal window that is not running irb; you can verify it is there by typing gem list | grep cheat which simply pipes your list of gems to grep so it can search for any gems with 'cheat' in its name.) In that other terminal window/tab, type cheat strftime and see the output returned – this should guide you in reformatting the timestamp. If you are having issues with this gem, you can also use an online reference strfti.me.

  2. We are going to add three variables at once through multiple assignment (an option in Ruby). To do this, type into irb:

m1, d1, y1 = 04, 01, 2014

Now we will use these values to create a new timestamp in Ruby with the command:

c = Time.mktime(y1, m1, d1)

Now we have the timestamp for this year's April Fool's Day. Let's change it a little bit by typing d1 = 31 and rerunning the command: c = Time.mktime(y1, m1, d1). What did Ruby do with the date 04/31/2014?


Stop

Show a TA that you have completed this part. Make sure the TA initials your sheet.


You are technically done with this part of the lab. However if you want to stretch yourself a bit and put this new Ruby knowledge to the test, then try the following: write a method called valid_date? which takes year, month and day as arguments and returns true if the date is valid or false if not. Below is a frame for the method as well as some test cases.

def valid_date?(year, month, day)
  # your code goes here ...

end

# Tests
puts valid_date?(2013, 1, 29) # => true
puts valid_date?(2013, 2, 28) # => true
puts valid_date?(2013, 2, 29) # => false
puts valid_date?(2014, 2, 29) # => false
puts valid_date?(2014, 9, 29) # => true
puts valid_date?(2014, 9, 31) # => false
puts valid_date?(2013, 12, 31) # => true
puts valid_date?(2013, 12, 32) # => false
puts valid_date?(2013, 13, 31) # => false
puts valid_date?("2014", "Jan", 31) # => false

Hint: IMO it is a lot easier to deal with 'exceptional dates' with Ruby exceptions.


Part 3: Ruby Blocks

In this part of the lab, you will work through block problems from a previous 67-272 exam. This section contains 4 problems, but you only need to complete the first 2 for full credit. However, you are encouraged to complete them all if time allows! They will be good practice for future exams and your projects.

In each problem you will be given an expected output, and your task is to write a block that will generate this output. You can complete the problems in a separate file, and run it the same way as TempConverter.

  1. Add the following dictionaries to the top of your file, as these will be used in the problems.
cast = {bob_parr: :incredibles, helen_parr: :incredibles, lucius: :incredibles, 
        edna: :incredibles, woody: :toy_story, buzz: :toy_story, bopeep: :toy_story, 
        andy: :toy_story, merida: :brave, marlin: :finding_nemo, dory: :finding_nemo, 
        nemo: :finding_nemo, sulley: :monsters_inc, mike: :monsters_inc, 
        randall: :monsters_inc, sally: :cars, mcqueen: :cars, doc: :cars, 
        mater: :cars, jessie: :toy_story_3, big_baby: :toy_story_3}

toys = [:woody, :bopeep, :buzz, :jessie, :big_baby]

females = [:helen_parr, :edna, :bopeep, :dory, :sally, :jessie, :merida]

year_produced = {incredibles: 2004, toy_story: 1995, brave: 2012, finding_nemo: 2003, up: 2009, walle: 2008, monsters_inc: 2001, cars: 2006, bugs_life: 1998, toy_story_3: 2010}

  1. Create a block that prints out all the female toys in alphabetical order.
# EXPECTED OUTPUT: 
  bopeep
  jessie
  1. Create a block that will print out a list of all the movies produced in the past 10 years.
# EXPECTED OUTPUT: 
  [:brave]
  1. Create a block that will print out a list of movies that have some cast members in the cast dictionary, arranged by year produced.
# EXPECTED OUTPUT: 
  Toy_story - 1995
  Monsters_inc - 2001
  Finding_nemo - 2003
  Incredibles - 2004
  Cars - 2006
  Toy_story_3 - 2010
  Brave - 2012
  1. Create a block that will print out a list of all movies in the year_produced dictionary in a user friendly format (spacing and capitalization). Make sure they are in alphabetical order.
# EXPECTED OUTPUT: 
  Brave
  Bugs Life
  Cars
  Finding Nemo
  Incredibles
  Monsters Inc
  Toy Story
  Toy Story 3
  Up
  Walle

Stop

Show a TA that you have at least problems 1 and 2 completed. Make sure the TA initials your sheet.


Practice HTML (Optional)

If you need a refresher on HTML basics, feel free to review the following labs from 67-250.

Lab 1
Lab 2
Lab 3

On Your Own

This week the "on your own" assignment is to go to RubyMonk's free Ruby Primer and complete the following exercises:

  • Introduction To Ruby Objects

  • Arrays in Ruby

  • Introduction to Ruby Methods