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. |