During this lab session:
This activity helps students develop the following skills, values and attitudes: ability to analyze and synthesize, capacity for identifying and solving problems, and efficient use of computer systems.
The lab activities can be developed individually or in pairs.
The lab report must be developed individually.
Create a folder called iterator_command
. Inside
this folder, create four files called:
primes.rb
,
test_primes.rb
,
control.rb
, and
test_control.rb
.
All four Ruby source files must start with a comment containing the lab's title, date, and the authors' personal information. For example:
# Lab 4: Iterator and Command Patterns # Date: 15-Feb-2011 # Authors: # 456654 Anthony Stark # 1160611 Thursday Rubinstein
In the primes.rb
source file, write a class called
PrimeGenerator
. Instances of this class can be used
as internal or external iterators that produce all prime numbers
contained within a lower and upper limit inclusively.
The class must have the following methods:
initialize
, next_item
,
item
, has_next?
, and
each
, as explained in
chapter 7 of [OLSEN].
The following unit tests verify the correct behavior of the
PrimeGenerator
class. Place the test class in the
test_primes.rb
source file.
# File: test_primes.rb require 'test/unit' require './primes' class PrimeGeneratorTest < Test::Unit::TestCase def setup @pg = PrimeGenerator.new(31, 97) @expected_values = [31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] end def test_external_iterator @expected_values.each do |n| assert @pg.has_next? assert_equal n, @pg.next_item assert_equal n, @pg.item end assert ! @pg.has_next? end def test_internal_iterator i = 0 @pg.each do |p| assert_equal @expected_values[i], p i += 1 end end end
This example was taken from [FREEMAN] pp. 191-223. You are required to write part of the software for the control remote shown in the following image, using the Command pattern.
You are given the following Ruby code (assume it is placed in
the control.rb
source file):
# File: control.rb class RemoteControlWithUndo def initialize @on_commands = [] @off_commands = [] no_command = NoCommand.new 7.times do @on_commands << no_command @off_commands << no_command end @undo_command = no_command end def set_command(slot, on_command, off_command) @on_commands[slot] = on_command @off_commands[slot] = off_command end def on_button_was_pushed(slot) @on_commands[slot].execute @undo_command = @on_commands[slot] end def off_button_was_pushed(slot) @off_commands[slot].execute @undo_command = @off_commands[slot] end def undo_button_was_pushed() @undo_command.undo end def inspect string_buff = ["\n------ Remote Control -------\n"] @on_commands.zip(@off_commands).each_with_index do |commands, i| on_command, off_command = commands string_buff << "[slot #{i}] #{on_command.class} #{off_command.class}\n" end string_buff << "[undo] #{@undo_command.class}\n" string_buff.join end end class NoCommand def execute end def undo end end class Light attr_reader :level def initialize(location) @location = location @level = 0 end def on @level = 100 puts "Light is on" end def off @level = 0 puts "Light is off" end def dim(level) @level = level if level == 0 off else puts "Light is dimmed to #{@level}%" end end end class CeilingFan HIGH = 3 MEDIUM = 2 LOW = 1 OFF = 0 attr_reader :speed def initialize (location) @location = location @speed = OFF end def high @speed = HIGH; puts "#{@location} ceiling fan is on high" end def medium @speed = MEDIUM puts "#{@location} ceiling fan is on medium" end def low @speed = LOW puts "#{@location} ceiling fan is on low" end def off @speed = OFF puts "#{@location} ceiling fan is off" end end
Write the following command classes placing them in the
control.rb
source file:
LightOnCommand
, LightOffCommand
,
CeilingFanHighCommand
,
CeilingFanMediumCommand
, and
CeilingFanOffCommand
. All these classes should have
these three methods: initialize
,
execute
and undo
. Check the unit tests
in the next step to understand the expected behavior of each
method.
The following unit tests verify the correct behavior of your
classes. Place the test class in the
test_control.rb
source file.
# File: test_control.rb require 'test/unit' require 'stringio' require './control' class ControlTest < Test::Unit::TestCase def setup set_stdout @rc = RemoteControlWithUndo.new set_light set_fan end def teardown reset_stdout end def set_stdout @out = StringIO.new @old_stdout = $stdout $stdout = @out end def reset_stdout $stdout = @old_stdout end def set_light light = Light.new("Living Room") light_on = LightOnCommand.new(light) light_off = LightOffCommand.new(light) @rc.set_command(0, light_on, light_off) end def set_fan fan = CeilingFan.new("Living Room") fan_medium = CeilingFanMediumCommand.new(fan) fan_high = CeilingFanHighCommand.new(fan) fan_off = CeilingFanOffCommand.new(fan) @rc.set_command(1, fan_medium, fan_off) @rc.set_command(2, fan_high, fan_off) end def test_light @rc.on_button_was_pushed(0) @rc.off_button_was_pushed(0) p @rc @rc.undo_button_was_pushed @rc.off_button_was_pushed(0) @rc.on_button_was_pushed(0) p @rc @rc.undo_button_was_pushed assert_equal "Light is on\n" \ "Light is off\n" \ "\n------ Remote Control -------\n" \ "[slot 0] LightOnCommand LightOffCommand\n" \ "[slot 1] CeilingFanMediumCommand CeilingFanOffCommand\n" \ "[slot 2] CeilingFanHighCommand CeilingFanOffCommand\n" \ "[slot 3] NoCommand NoCommand\n" \ "[slot 4] NoCommand NoCommand\n" \ "[slot 5] NoCommand NoCommand\n" \ "[slot 6] NoCommand NoCommand\n" \ "[undo] LightOffCommand\n\n" \ "Light is on\n" \ "Light is off\n" \ "Light is on\n" \ "\n------ Remote Control -------\n" \ "[slot 0] LightOnCommand LightOffCommand\n" \ "[slot 1] CeilingFanMediumCommand CeilingFanOffCommand\n" \ "[slot 2] CeilingFanHighCommand CeilingFanOffCommand\n" \ "[slot 3] NoCommand NoCommand\n" \ "[slot 4] NoCommand NoCommand\n" \ "[slot 5] NoCommand NoCommand\n" \ "[slot 6] NoCommand NoCommand\n" \ "[undo] LightOnCommand\n\n" \ "Light is off\n", @out.string end def test_fan @rc.on_button_was_pushed(1) @rc.off_button_was_pushed(1) p @rc @rc.undo_button_was_pushed @rc.on_button_was_pushed(2) p @rc @rc.undo_button_was_pushed assert_equal "Living Room ceiling fan is on medium\n" \ "Living Room ceiling fan is off\n" \ "\n------ Remote Control -------\n" \ "[slot 0] LightOnCommand LightOffCommand\n" \ "[slot 1] CeilingFanMediumCommand CeilingFanOffCommand\n" \ "[slot 2] CeilingFanHighCommand CeilingFanOffCommand\n" \ "[slot 3] NoCommand NoCommand\n" \ "[slot 4] NoCommand NoCommand\n" \ "[slot 5] NoCommand NoCommand\n" \ "[slot 6] NoCommand NoCommand\n" \ "[undo] CeilingFanOffCommand\n\n" \ "Living Room ceiling fan is on medium\n" \ "Living Room ceiling fan is on high\n" \ "\n------ Remote Control -------\n" \ "[slot 0] LightOnCommand LightOffCommand\n" \ "[slot 1] CeilingFanMediumCommand CeilingFanOffCommand\n" \ "[slot 2] CeilingFanHighCommand CeilingFanOffCommand\n" \ "[slot 3] NoCommand NoCommand\n" \ "[slot 4] NoCommand NoCommand\n" \ "[slot 5] NoCommand NoCommand\n" \ "[slot 6] NoCommand NoCommand\n" \ "[undo] CeilingFanHighCommand\n\n" \ "Living Room ceiling fan is on medium\n", @out.string end end
To hand in your individual lab work, follow these instructions.
lab4_report_A0MMMMMMM.tex
, where A0MMMMMMM
is your student ID. From your LaTeX source, generate the
corresponding PDF file. That file should be called
lab4_report_A0MMMMMMM.pdf
. Place these two files in the
iterator_command
directory.
iterator_command
directory. Call this file iterator_command.zip
.
Due date is Monday, February 21.
This activity will be evaluated using the following criteria:
50% | Implementation of functional requirements. |
---|---|
50% | Lab report. |
DA | The program and/or report was plagiarized. |