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.
This lab can be developed individually or in pairs.
Create a folder called observer_iterator. Inside
this folder, create four files called:
weather.rb,
test_weather.rb,
primes.rb, and
test_primes.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 3: Observer and Iterator Patterns # Date: 17-Sep-2009 # Authors: # 456654 Anthony Stark # 1160611 Thursday Rubinstein
You are required to build a weather data monitoring system using
the Observer pattern (this example was taken from [FREEMAN] pp.
37-60). In the weather.rb source file, define four
classes:
WeatherData: This is the subject of our
Observer pattern implementation. Include as a mixin the
Observable module and add to it a
set_measurements method, which takes three
parameters: temperature, humidity,
and pressure. This method must notify all its
observing objects that a change has occurred. This means
that the update method for every observer must
be indirectly called with the three previously mentioned
parameters. Check
chapter 5 of [OLSEN] and the
observer.rb documentation for more details on the
Observable module.
CurrentConditionsDisplay: An observer that
displays to the standard output the current weather
conditions.
StatisticsDisplay: An observer that displays to
the standard output weather statistics (average, maximum and
minumum temperatures so far).
ForecastDisplay: An observer that displays to
the standard output a weather forecast. If the current
pressure is higher than the previous pressure, it predicts
an improvement on the weather. If the current pressure is
lower than the previous pressure, it predicts a cooler,
rainy weather. Otherwise, it predicts that the weather will
stay the same.
Check the unit tests in the following step to see the expected display formats for each of the observers.
Make sure the code that you write behaves exactly as expected by
the following unit tests. This class must be placed in the
test_weather.rb source file.
require 'test/unit'
require 'stringio'
require 'weather'
class WeatherTest < Test::Unit::TestCase
def setup
@out = StringIO.new
@old_stdout = $stdout
$stdout = @out
@weather_data = WeatherData.new
end
def teardown
$stdout = @old_stdout
end
def do_set_measurements
@weather_data.set_measurements(80.0, 65.0, 30.4)
@weather_data.set_measurements(82.0, 70.0, 29.2)
@weather_data.set_measurements(78.0, 90.0, 29.2)
end
def test_current_conditions_display
current_display = CurrentConditionsDisplay.new
@weather_data.add_observer(current_display)
do_set_measurements
assert_equal "Current conditions: 80.0F degrees and 65.0% humidity\n" \
"Current conditions: 82.0F degrees and 70.0% humidity\n" \
"Current conditions: 78.0F degrees and 90.0% humidity\n", \
@out.string
end
def test_statistics_display
statistics_display = StatisticsDisplay.new
@weather_data.add_observer(statistics_display)
do_set_measurements
assert_equal "Avg/Max/Min temperature = 80.0/80.0/80.0\n" \
"Avg/Max/Min temperature = 81.0/82.0/80.0\n" \
"Avg/Max/Min temperature = 80.0/82.0/78.0\n", \
@out.string
end
def test_forecast_display
forecast_display = ForecastDisplay.new
@weather_data.add_observer(forecast_display)
do_set_measurements
assert_equal "Forecast: Improving weather on the way!\n" \
"Forecast: Watch out for cooler, rainy weather\n" \
"Forecast: More of the same\n", \
@out.string
end
def test_all_together
current_display = CurrentConditionsDisplay.new
statistics_display = StatisticsDisplay.new
forecast_display = ForecastDisplay.new
@weather_data.add_observer(current_display)
@weather_data.add_observer(statistics_display)
@weather_data.add_observer(forecast_display)
do_set_measurements
assert_equal "Current conditions: 80.0F degrees and 65.0% humidity\n" \
"Avg/Max/Min temperature = 80.0/80.0/80.0\n" \
"Forecast: Improving weather on the way!\n" \
"Current conditions: 82.0F degrees and 70.0% humidity\n" \
"Avg/Max/Min temperature = 81.0/82.0/80.0\n" \
"Forecast: Watch out for cooler, rainy weather\n" \
"Current conditions: 78.0F degrees and 90.0% humidity\n" \
"Avg/Max/Min temperature = 80.0/82.0/78.0\n" \
"Forecast: More of the same\n", \
@out.string
end
end
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.
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
for n in @expected_values
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
To hand in your lab work, follow these instructions:
observer_iterator directory. Call this file
observer_iterator.zip.
This activity will be evaluated using the following criteria:
| 100 | The code works as requested. |
|---|---|
| 60-90 | The code works, but has some flaws. |
| 20-50 | The code doesn't work, but it seams that some amount of time was spent on it. |
| DA | The program was plagiarized. |