My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
Night7  
ToDo: Consolidate weather + football data file processing.
Updated Feb 4, 2010 by stacy.c...@gmail.com

Introduction

4 people came to geek night: Ahrum, Josh, Nick, and myself (Stacy).

We focussed one the last stage of Kata: Removing duplication from the weather & football file processors.

We experimented with and applied some advanced Ruby techniques for the first time, including meta programming with method_missing, send, class_eval, etc. After pwning in Java for so long it's great to get a good feel for these Ruby idioms.

Details

The first thing we tackled was to remove the duplication the the FootballManager class so that only one method actually parsed the file.

Next we converted the WeatherMan class to use a hash to store each days weather, it was using an array before (because the indexing field, day, is a integer).

Next we converted the WeatherMan & Weather classes to use regular expressions to extracting data.

This made the two solutions very similar so we extracted out the file processing behaviour into a FileParser which is given a class to instantiate for each row (Weather, Standing) and a regular expression to identify lines which contain valid data.

We next noticed that the 'data aggregators', WeatherMan & FootballManager had the same methods as the 'data entry classes'; Weather & Standing, viz: maximum_temperater, goals_for, etc. the only difference was the methods on the aggregators had one parameter, the key of the entry (day, team). So we removed the methods on the aggregators and implemented them using method_missing. Our method_missing method took an invocation like: football_manager.goals_for('Arsenal') and invoked self.standing_of_team('Arsenal').goals_for.

2 people left early (before 9pm) leaving 2 of us to go bonkers with DSL's.

We transformed the Weather and Standing classes into specifications:

class Weather < CSVRecord
  columns :day.is_an(:integer), :max_temperature.is_an(:integer), :min_temperature.is_an(:integer)
  record_format '^\s*(\d+)\s*(\d+)\s*(\d+)'

  def spread
    return max_temperature - min_temperature
  end
end
class Standing < CSVRecord
  columns :team, :goals_for.is_an(:integer), :goals_against.is_an(:integer)
  record_format '(\w*)\s*\d+\s*\d+\s*\d+\s*\d+\s*(\d+)\s*-\s*(\d+)'

  def spread
    return (goals_for - goals_against).abs
  end
end

Sign in to add a comment
Powered by Google Project Hosting