Class: ICU::Tournament::ForeignCSV
- Inherits:
-
Object
- Object
- ICU::Tournament::ForeignCSV
- Defined in:
- lib/icu_tournament/tournament_fcsv.rb
Overview
Foreign CSV
This is a format (specification) used by the ICU for players to submit their individual results in foreign tournaments for domestic rating.
Suppose, for example, that the following data is the file tournament.csv:
Event,"Isle of Man Masters, 2007"
Start,2007-09-22
Rounds,9
Website,http://www.bcmchess.co.uk/monarch2007/
Player,456,Fox,Anthony
1,0,B,Taylor,Peter P.,2209,,ENG
2,=,W,Nadav,Egozi,2205,,ISR
3,=,B,Cafolla,Peter,2048,,IRL
4,1,W,Spanton,Tim R.,1982,,ENG
5,1,B,Grant,Alan,2223,,SCO
6,0,-
7,=,W,Walton,Alan J.,2223,,ENG
8,0,B,Bannink,Bernard,2271,FM,NED
9,=,W,Phillips,Roy,2271,,MAU
Total,4
This file can be parsed as follows.
parser = ICU::Tournament::ForeignCSV.new
tournament = parser.parse_file('tournament.csv')
If the file is correctly specified, the return value from the parse_file method is an instance of ICU::Tournament (rather than nil, which indicates an error). In this example the file is valid, so:
tournament.name # => "Isle of Man Masters, 2007"
tournament.start # => "2007-09-22"
tournament.rounds # => 9
tournament.website # => "http://www.bcmchess.co.uk/monarch2007/"
The main player (the player whose results are being reported for rating) played 9 rounds but only 8 other players (he had a bye in round 6), so the total number of players is 9.
tournament.players.size # => 9
Each player has a unique number for the tournament. The main player always occurs first in this type of file, so his number is 1.
player = tournament.player(1)
player.name # => "Fox, Anthony"
This player has 4 points from 9 rounds but only 8 of his results are are rateable (because of the bye).
player.points # => 4.0
player.results.size # => 9
player.results.find_all{ |r| r.rateable }.size # => 8
The other players all have numbers greater than 1.
opponents = tournamnet.players.reject { |o| o.num == 1 }
There are 8 opponents (of the main player) each with exactly one game.
opponents.size # => 8
opponents.find_all{ |o| o.results.size == 1 }.size # => 8
However, none of the opponents’ results are rateable because they are foreign to the domestic rating list to which the main player belongs. For example:
opponent = tournament.players(2)
opponent.name # => "Taylor, Peter P."
opponent.results[0].rateable # => false
If the file contains errors, then the return value from parse_file is nil and an error message is returned by the error method of the parser object. The method parse_file! is similar except that it raises errors, and the methods parse and parse! are similar except their inputs are strings rather than file names.
A tournament can be serialized back to CSV format (the reverse of parsing) with the serialize method of the parser object.
csv = parser.serialize(tournament)
Or equivalently, the serialize instance method of the tournament, if the appropriate parser name is supplied.
csv = tournament.serialize('ForeignCSV')
You can also build the tournament object from scratch using your own data and then serialize it. For example, here are the commands to reproduce the example above.
t = ICU::Tournament.new("Isle of Man Masters, 2007", '2007-09-22', :rounds => 9)
t.site = 'http://www.bcmchess.co.uk/monarch2007/'
t.add_player(ICU::Player.new('Anthony', 'Fox', 1, :rating => 2100, :fed => 'IRL', :id => 456))
t.add_player(ICU::Player.new('Peter P.', 'Taylor', 2, :rating => 2209, :fed => 'ENG'))
t.add_player(ICU::Player.new('Egozi', 'Nadav', 3, :rating => 2205, :fed => 'ISR'))
t.add_player(ICU::Player.new('Peter', 'Cafolla', 4, :rating => 2048, :fed => 'IRL'))
t.add_player(ICU::Player.new('Tim R.', 'Spanton', 5, :rating => 1982, :fed => 'ENG'))
t.add_player(ICU::Player.new('Alan', 'Grant', 6, :rating => 2223, :fed => 'SCO'))
t.add_player(ICU::Player.new('Alan J.', 'Walton', 7, :rating => 2223, :fed => 'ENG'))
t.add_player(ICU::Player.new('Bernard', 'Bannink', 8, :rating => 2271, :fed => 'NED', :title => 'FM'))
t.add_player(ICU::Player.new('Roy', 'Phillips', 9, :rating => 2271, :fed => 'MAU'))
t.add_result(ICU::Result.new(1, 1, 'L', :opponent => 2, :colour => 'B'))
t.add_result(ICU::Result.new(2, 1, 'D', :opponent => 3, :colour => 'W'))
t.add_result(ICU::Result.new(3, 1, 'D', :opponent => 4, :colour => 'B'))
t.add_result(ICU::Result.new(4, 1, 'W', :opponent => 5, :colour => 'W'))
t.add_result(ICU::Result.new(5, 1, 'W', :opponent => 6, :colour => 'B'))
t.add_result(ICU::Result.new(6, 1, 'L'))
t.add_result(ICU::Result.new(7, 1, 'D', :opponent => 7, :colour => 'W'))
t.add_result(ICU::Result.new(8, 1, 'L', :opponent => 8, :colour => 'B'))
t.add_result(ICU::Result.new(9, 1, 'D', :opponent => 9, :colour => 'W'))
t.validate!
puts t.serialize('ForeignCSV')
Instance Attribute Summary collapse
-
#error ⇒ Object
readonly
Returns the value of attribute error.
Instance Method Summary collapse
-
#parse(csv) ⇒ Object
Parse CSV data returning a Tournament on success or a nil on failure.
-
#parse!(csv) ⇒ Object
Parse CSV data returning a Tournament on success or raising an exception on error.
-
#parse_file(file) ⇒ Object
Same as parse except the input is a file name rather than file contents.
-
#parse_file!(file) ⇒ Object
Same as parse! except the input is a file name rather than file contents.
-
#serialize(t) ⇒ Object
Serialise a tournament back into CSV format.
Instance Attribute Details
#error ⇒ Object (readonly)
Returns the value of attribute error.
118 119 120 |
# File 'lib/icu_tournament/tournament_fcsv.rb', line 118 def error @error end |
Instance Method Details
#parse(csv) ⇒ Object
Parse CSV data returning a Tournament on success or a nil on failure. In the case of failure, an error message can be retrived via the error method.
169 170 171 172 173 174 175 176 |
# File 'lib/icu_tournament/tournament_fcsv.rb', line 169 def parse(csv) begin parse!(csv) rescue => ex @error = ex. nil end end |
#parse!(csv) ⇒ Object
Parse CSV data returning a Tournament on success or raising an exception on error.
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/icu_tournament/tournament_fcsv.rb', line 121 def parse!(csv) @state, @line, @round, @sum, @error = 0, 0, nil, nil, nil @tournament = Tournament.new('Dummy', '2000-01-01') Util::CSV.parse(csv, :row_sep => :auto) do |r| @line += 1 # increment line number next if r.size == 0 # skip empty lines r = r.map{|c| c.nil? ? '' : c.strip} # trim all spaces, turn nils to blanks next if r[0] == '' # skip blanks in column 1 @r = r # remember this record for later begin case @state when 0 then event when 1 then start when 2 then rounds when 3 then website when 4 then player when 5 then result when 6 then total else raise "internal error - state #{@state} does not exist" end rescue => err raise err.class, "line #{@line}: #{err.}", err.backtrace unless err..match(/^line [1-9]/) raise end end unless @state == 4 exp = case @state when 0 then "the event name" when 1 then "the start date" when 2 then "the number of rounds" when 3 then "the website address" when 5 then "a result for round #{@round+1}" when 6 then "a total score" end raise "line #{@line}: premature termination - expected #{exp}" end raise "line #{@line}: no players found in file" if @tournament.players.size == 0 @tournament.validate! @tournament end |
#parse_file(file) ⇒ Object
Same as parse except the input is a file name rather than file contents.
185 186 187 188 189 190 191 192 |
# File 'lib/icu_tournament/tournament_fcsv.rb', line 185 def parse_file(file) begin parse_file!(file) rescue => ex @error = ex. nil end end |
#parse_file!(file) ⇒ Object
Same as parse! except the input is a file name rather than file contents.
179 180 181 182 |
# File 'lib/icu_tournament/tournament_fcsv.rb', line 179 def parse_file!(file) csv = open(file) { |f| f.read } parse!(csv) end |
#serialize(t) ⇒ Object
Serialise a tournament back into CSV format.
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/icu_tournament/tournament_fcsv.rb', line 195 def serialize(t) return nil unless t.class == ICU::Tournament; Util::CSV.generate do |csv| csv << ["Event", t.name] csv << ["Start", t.start] csv << ["Rounds", t.rounds] csv << ["Website", t.site] t.players.each do |p| next unless p.id csv << [] csv << ["Player", p.id, p.last_name, p.first_name] (1..t.rounds).each do |n| data = [] data << n r = p.find_result(n) data << case r.score; when 'W' then '1'; when 'L' then '0'; else '='; end if r.rateable data << r.colour o = t.player(r.opponent) data << o.last_name data << o.first_name data << o. data << o.title data << o.fed else data << '-' end csv << data end csv << ["Total", p.points] end end end |