Computer Languages History
(Click or use local copy.)
 CS 3723/3721
 Programming Languages
 Spring 2005

 Recitation 14
 Ruby: Basics, Classes and REs
    Week 14: Apr 25-29
 Due (on time): 2005-04-02  23:59:59
 Due (late):        2005-04-06  23:59:59

Recitation 14 must be submitted following directions at: submissions with deadlines
  • 2005-04-02  23:59:59 (that's Monday, 2 May 2005, 11:59:59 pm) for full credit.
  • 2005-04-06  23:59:59 (that's Friday, 6 May 2005, 11:59:59 pm) for 75% credit.

Ruby: Basics, Classes and Regular Expressions:


Reading: For this recitation you should study three chapters of the online book Programming Ruby: The Pragmatic Programmer's Guide, by David Thomas and Andrew Hunt, Addison-Wesley, 2001. (The book is excellent, though written at a sophisticated level. The online version looks shorter than the 564 pages of the print version. A second edition, which is 50% longer, is available for purchase at: Amazon.com.)

Chapters to study:

You should also read and go over the examples in the:


Ruby programs to write and debug:

  1. Program involving regular expressions: Here are two forms for representing the time and date:

    "American" style International style
    10:03pm April 20, 20042004-04-20 22:03:00
    8:04am January 4, 19981998-01-04 08:04:00
    11:59pm December 31, 20032003-12-31 23:59:59
    0:00am January 1, 20002000-01-01 00:00:00

    1. Write a Ruby program that translates International style dates to "American" style dates:
      1. Read a sequence of International style dates, one to a line, and translate these into the American style.
      2. Use Ruby regular expressions as an essential part of the program. (Follow the model of the regular expression program at the end of the Ruby tutorial.) You must not use the Perl-like variables $1, $2, etc., but must program this using Ruby's object-oriented features.
      3. To help with the translation, use a Ruby array with the names of the twelve months in it.
      4. Notice that in the first sample date above, the hour of "22" must be changed to a "10" with "pm" at the end. Notice also that in the second sample date above, the "08" for hours and the "04" for days must be written in American style without the leading "0".
      5. Notice that the "American"style leaves off the seconds. You can leave them off also, or put them in if you wish.
      6. Do not check for input errors.

    2. Write a similar program that will translate from American style to International style. (This is similar code, but perhaps a little harder. Assume some reasonable definition for the "American" style, as shown above. If you leave seconds off in the "Ameican" style, you should put :00 back into the International style.)

      In addition to methods to_i (to int) and to_s (to string), You might find the following functions helpful:

      Functions pad0 and strip0
      #!/usr/local/bin/ruby
            
      def pad0(t)
      # if t as an integer is < 10, add 0 at left
         if t.to_i < 10
            "0" + t
         else
            t
         end
      end
      
      def strip0(t)
      # remove 0 at left of input string t (if present)
         if t =~ /^0/
            t[1,t.length-1]
         else
            t
         end
      end
      
      print pad0("9"), "\n"     # prints 09
      print pad0("19"), "\n"    # prints 19
      
      print strip0("03"), "\n"  # prints 3
      print strip0("23"), "\n"  # prints 23
      

  2. Program involving classes:

    Note that even though this problem also involves dates, it is independent of the previous problem -- you should not have any common code between the two problems. This problem has you working with dates and times. Ruby, like most programming languages, has library functions for treating times and dates, and in normal applications, you should use such library functions. This problem has you creating classes from scratch in order to learn how to do it.

    Consider the following Date class in Ruby. (Here is the whole file, Date class plus test code: date.rb.)

    Date class in Ruby, file: date.rb
    The class Date Test code and a run
    #!/usr/local/bin/ruby
    class Date
       attr_reader :year, :month, :day
       
       def initialize(y, m, d)
          if check_date(y, m, d)
             @year, @month, @day = y, m, d
          else
             @year, @month, @day = 2000, 1, 1
          end
       end
    
       @@mon = [nil,"Jan","Feb","Mar","Apr",
                "May","Jun","Jul","Aug",
                "Sep","Oct","Nov","Dec"]
       @@days = [0, 31, 28, 31, 30, 31, 30,
                    31, 31, 30, 31, 30, 31]
       def check_date(y, m, d)
          if m < 1 or m > 12 or
                d < 0 or d > 31 or y < 0
             false
          elsif d > 0 and d <= @@days[m]
             true
          elsif m == 2 and d == 29 and
               is_leap(y)
             true
          else
             false
          end
       end
       
       def is_leap(y)
          if (y%400 == 0 or
                (y%4 == 0 and y%100 != 0) )
             true
          else
             false
          end
       end
          
       def to_s
          @@mon[@month] + " " + day.to_s +
             ", " + year.to_s
       end
       
       def incr_day
          @day +=1
          if not (@month == 2 and 
                  is_leap(@year) and
                  @day == 29) and
                @day > @@days[@month]
             @day = 1
             incr_month
          end
       end
    
       def incr_month
          @month +=1
          if @month > 12
             @month = 1
             incr_year
          end
       end
       
       def incr_year
          @year += 1
       end
    
    end
    
    def test_date(y, m, d)
       date = Date.new(y, m, d)
       print "Start Date:  ",date," "
       date.incr_day
       print "\n   Next day: ", date
       date.incr_day
       print "\n   Next day: ", date
       date.incr_day
       print "\n   Next day: ", date,
          "\n"
    end
    test_date(2004, 4, 22)
    test_date(2000, 2, 28)
    test_date(2001, 2, 27)
    test_date(2001, 12, 30)

    % date.rb
    Start Date:  Apr 22, 2004 
       Next day: Apr 23, 2004
       Next day: Apr 24, 2004
       Next day: Apr 25, 2004
    Start Date:  Feb 28, 2000 
       Next day: Feb 29, 2000
       Next day: Mar 1, 2000
       Next day: Mar 2, 2000
    Start Date:  Feb 27, 2001 
       Next day: Feb 28, 2001
       Next day: Mar 1, 2001
       Next day: Mar 2, 2001
    Start Date:  Dec 30, 2001 
       Next day: Dec 31, 2001
       Next day: Jan 1, 2002
       Next day: Jan 2, 2002

    1. In the same file add another class Time that will keep track of hours, minutes, and seconds. This new class should be similar to the Date class. In particular, it should have methods: initialize, check_time, to_s, incr_sec, incr_min, and incr_hour. Test this new class with code to instantiate time objects and to test incrementing by seconds, including showing that it handles the end of a minute and the end of an hour correctly.

    2. Change your Time class so that it inherits the Date class, that is Date is a superclass of Time, and Time is a subclass of Date. (In Java terms, Time extends Date, and in place of the Java "Time extends Date", Perl writes "Time < Date". The initializer for Time should now have 6 parameters, including the ones before, along with year, month, and day. These last three will be passed on into Date using the super method. (See the example KaraokeSong in Chapter 3 of the PPG.)

    3. Alter the incr_hour method of Time, so that in case an addition goes past hour 23, it will wrap around to hour 0 and increment to the next day.

      It is permissible to change the code in the class Date, although I didn't need to make any changes. There are many different ways to write this code. You should test your program with the following initial data, and your output should look something like the following:

      Possible output for this question
      Start Time:      Apr 22, 2004 13:15:30 
          Next second: Apr 22, 2004 13:15:31
          Next second: Apr 22, 2004 13:15:32
          
      Start Time:      Feb 28, 2000 13:59:59 
          Next second: Feb 28, 2000 14:00:00
          Next second: Feb 28, 2000 14:00:01
          
      Start Time:      Feb 28, 2000 23:59:59 
          Next second: Feb 29, 2000 00:00:00
          Next second: Feb 29, 2000 00:00:01
          
      Start Time:      Feb 29, 2000 23:59:59 
          Next second: Mar 1, 2000 00:00:00
          Next second: Mar 1, 2000 00:00:01
          
      Start Time:      Feb 28, 2001 23:59:59 
          Next second: Mar 1, 2001 00:00:00
          Next second: Mar 1, 2001 00:00:01
          
      Start Time:      Dec 31, 2001 23:59:58 
          Next second: Dec 31, 2001 23:59:59
          Next second: Jan 1, 2002 00:00:00
          
      Start Time:      Apr 30, 2001 23:59:58 
          Next second: Apr 30, 2001 23:59:59
          Next second: May 1, 2001 00:00:00
      


What you should submit: Refer to the submissions directions and to deadlines at the top of this page. The text file that you submit should first have Your Name, the Course Number, and the Recitation Number. The rest of the file should have the following in it, in the order below, and clearly labeled, including at the beginning the appropriate item numbers: 1 and 2.

 Contents of submission for Recitation 14:

Last Name, First Name; Course Number; Recitation Number.

1. For full credit, you might have two Ruby programs that will translate in each direction. You should test each program at least with the four examples shown in the write-up above. However, you can also put everything into one program, which is what I did, producing two functions, one for each of the translations. (The true American style would write the fourth input above (midnight) in the form 12:00am January 1, 2000, and you could fix your program up to do this also.)

2. For part credit, you might just create the class Time. As a completely separate class, this is very similar to Date, but simpler, so you should really try this one. Parts ii and iii just add extra features. For full credit, it is enough to have a single Ruby program in a single file that does everything, producing roughly the output shown above for the 7 given inputs. (Of course, the two classes could also be in separate files.)


Key ideas: Ruby is a scripting language, similar to Perl in many ways, but it is also a true object-oriented language.


Revision date: 2005-04-24. (Please use ISO 8601, the International Standard Date and Time Notation.)