icu_tournament 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,11 +4,11 @@ module ICU
4
4
 
5
5
  == Building a Tournament
6
6
 
7
- One way to create a tournament object is by parsing one of the supported file type (e.g. ICU::Tournament::Krause).
8
- It is also possible to build one programmatically by
7
+ One way to create a tournament object is by parsing one of the supported file types (e.g. ICU::Tournament::Krause).
8
+ It is also possible to build one programmatically by:
9
9
 
10
10
  1. creating a bare tournament instance,
11
- 2. adding all the players and
11
+ 2. adding all the players,
12
12
  3. adding all the results.
13
13
 
14
14
  For example:
@@ -37,7 +37,7 @@ or equivalntly, just:
37
37
 
38
38
  puts @t.serialize('Krause')
39
39
 
40
- Would result in the following output:
40
+ would result in the following output:
41
41
 
42
42
  012 Bangor Masters
43
43
  042 2009-11-09
@@ -29,11 +29,10 @@ Suppose, for example, that the following data is the file <em>tournament.csv</em
29
29
 
30
30
  This file can be parsed as follows.
31
31
 
32
- data = open('tournament.csv') { |f| f.read }
33
32
  parser = ICU::Tournament::ForeignCSV.new
34
- tournament = parser.parse(data)
33
+ tournament = parser.parse_file('tournament.csv')
35
34
 
36
- If the file is correctly specified, the return value from the <em>parse</em> method is an instance of
35
+ If the file is correctly specified, the return value from the <em>parse_file</em> method is an instance of
37
36
  ICU::Tournament (rather than <em>nil</em>, which indicates an error). In this example the file is valid, so:
38
37
 
39
38
  tournament.name # => "Isle of Man Masters, 2007"
@@ -73,6 +72,11 @@ to which the main player belongs. For example:
73
72
  opponent.name # => "Taylor, Peter P."
74
73
  opponent.results[0].rateable # => false
75
74
 
75
+ If the file contains errors, then the return value from <em>parse_file</em> is <em>nil</em> and
76
+ an error message is returned by the <em>error</em> method of the parser object. The method
77
+ <em>parse_file!</em> is similar except that it raises errors, and the methods <em>parse</em>
78
+ and <em>parse!</em> are similar except their inputs are strings rather than file names.
79
+
76
80
  A tournament can be serialized back to CSV format (the reverse of parsing) with the _serialize_ method
77
81
  of the parser object.
78
82
 
@@ -113,17 +117,6 @@ For example, here are the commands to reproduce the example above.
113
117
  class ForeignCSV
114
118
  attr_reader :error
115
119
 
116
- # Parse CSV data returning a Tournament on success or a nil on failure.
117
- # In the case of failure, an error message can be retrived via the <em>error</em> method.
118
- def parse(csv)
119
- begin
120
- parse!(csv)
121
- rescue => ex
122
- @error = ex.message
123
- nil
124
- end
125
- end
126
-
127
120
  # Parse CSV data returning a Tournament on success or raising an exception on error.
128
121
  def parse!(csv)
129
122
  @state, @line, @round, @sum, @error = 0, 0, nil, nil, nil
@@ -171,6 +164,33 @@ For example, here are the commands to reproduce the example above.
171
164
  @tournament
172
165
  end
173
166
 
167
+ # Parse CSV data returning a Tournament on success or a nil on failure.
168
+ # In the case of failure, an error message can be retrived via the <em>error</em> method.
169
+ def parse(csv)
170
+ begin
171
+ parse!(csv)
172
+ rescue => ex
173
+ @error = ex.message
174
+ nil
175
+ end
176
+ end
177
+
178
+ # Same as <em>parse!</em> except the input is a file name rather than file contents.
179
+ def parse_file!(file)
180
+ csv = open(file) { |f| f.read }
181
+ parse!(csv)
182
+ end
183
+
184
+ # Same as <em>parse</em> except the input is a file name rather than file contents.
185
+ def parse_file(file)
186
+ begin
187
+ parse_file!(file)
188
+ rescue => ex
189
+ @error = ex.message
190
+ nil
191
+ end
192
+ end
193
+
174
194
  # Serialise a tournament back into CSV format.
175
195
  def serialize(t)
176
196
  return nil unless t.class == ICU::Tournament;
@@ -1,6 +1,6 @@
1
1
  module ICU
2
2
  class Tournament
3
-
3
+
4
4
  =begin rdoc
5
5
 
6
6
  == Krause
@@ -15,36 +15,35 @@ Suppose, for example, that the following data is the file <em>tournament.tab</em
15
15
  042 2009.09.09
16
16
  0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
17
17
  132 09.09.09 09.09.10 09.09.11
18
- 001 1 w Mouse,Minerva 1900 USA 1234567 1928.05.15 1.0 2 2 b 0 3 w 1
18
+ 001 1 w Mouse,Minerva 1900 USA 1234567 1928.05.15 1.0 2 2 b 0 3 w 1
19
19
  001 2 m m Duck,Daffy 2200 IRL 7654321 1937.04.17 2.0 1 1 w 1 3 b 1
20
20
  001 3 m g Mouse,Mickey 2600 USA 1726354 1928.05.15 0.0 3 1 b 0 2 w 0
21
21
 
22
22
  This file can be parsed as follows.
23
23
 
24
- data = open('tournament.tab') { |f| f.read }
25
24
  parser = ICU::Tournament::Krause.new
26
- tournament = parser.parse(data)
25
+ tournament = parser.parse_file('tournament.tab')
27
26
 
28
- If the file is correctly specified, the return value from the <em>parse</em> method is an instance of
27
+ If the file is correctly specified, the return value from the <em>parse_file</em> method is an instance of
29
28
  ICU::Tournament (rather than <em>nil</em>, which indicates an error). In this example the file is valid, so:
30
-
29
+
31
30
  tournament.name # => "Fantasy Tournament"
32
31
  tournament.start # => "2009-09-09"
33
32
  tournament.fed # => "IRL"
34
33
  tournament.players.size # => 9
35
34
 
36
35
  Some values, not explicitly set in the file, are deduced:
37
-
36
+
38
37
  tournament.rounds # => 3
39
38
  tournament.finish # => "2009-09-11"
40
-
39
+
41
40
  A player can be retrieved from the tournament via the _players_ array or by sending a valid player number to the _player_ method.
42
41
 
43
42
  minnie = tournament.player(1)
44
43
  minnie.name # => "Mouse, Minerva"
45
44
  minnie.points # => 1.0
46
45
  minnie.results.size # => 2
47
-
46
+
48
47
  daffy = tournament.player(2)
49
48
  daffy.title # => "IM"
50
49
  daffy.rating # => 2200
@@ -65,6 +64,11 @@ to parse another file.
65
64
 
66
65
  parser.comments # => "0123456789..."
67
66
 
67
+ If the file contains errors, then the return value from <em>parse_file</em> is <em>nil</em> and
68
+ an error message is returned by the <em>error</em> method of the parser object. The method
69
+ <em>parse_file!</em> is similar except that it raises errors, and the methods <em>parse</em>
70
+ and <em>parse!</em> are similar except their inputs are strings rather than file names.
71
+
68
72
  A tournament can be serialized back to Krause format (the reverse of parsing) with the _serialize_ method of the parser.
69
73
 
70
74
  krause = parser.serialize(tournament)
@@ -96,18 +100,7 @@ attributes in an ICU::Tournament instance.
96
100
 
97
101
  class Krause
98
102
  attr_reader :error, :comments
99
-
100
- # Parse Krause data returning a Tournament on success or a nil on failure.
101
- # In the case of failure, an error message can be retrived via the <em>error</em> method.
102
- def parse(krs)
103
- begin
104
- parse!(krs)
105
- rescue => ex
106
- @error = ex.message
107
- nil
108
- end
109
- end
110
-
103
+
111
104
  # Parse Krause data returning a Tournament on success or raising an exception on error.
112
105
  def parse!(krs)
113
106
  @lineno = 0
@@ -115,14 +108,14 @@ attributes in an ICU::Tournament instance.
115
108
  @name_set, @start_set = false, false
116
109
  @comments = ''
117
110
  @results = Array.new
118
-
111
+
119
112
  # Process all lines.
120
113
  krs.each_line do |line|
121
114
  @lineno += 1 # increment line number
122
115
  line.strip! # remove leading and trailing white space
123
116
  next if line == '' # skip blank lines
124
117
  @line = line # remember this line for later
125
-
118
+
126
119
  # Does it havea DIN or is it just a comment?
127
120
  if @line.match(/^(\d{3}) (.*)$/)
128
121
  din = $1 # data identification number (DIN)
@@ -131,7 +124,7 @@ attributes in an ICU::Tournament instance.
131
124
  add_comment
132
125
  next
133
126
  end
134
-
127
+
135
128
  # Process the line given the DIN.
136
129
  begin
137
130
  case din
@@ -156,7 +149,7 @@ attributes in an ICU::Tournament instance.
156
149
  raise err.class, "line #{@lineno}: #{err.message}", err.backtrace
157
150
  end
158
151
  end
159
-
152
+
160
153
  # Now that all players are present, add the results to the tournament.
161
154
  @results.each do |r|
162
155
  lineno, player, data, result = r
@@ -166,17 +159,44 @@ attributes in an ICU::Tournament instance.
166
159
  raise "line #{lineno}, player #{player}, result '#{data}': #{err.message}"
167
160
  end
168
161
  end
169
-
162
+
170
163
  # Certain attributes are mandatory and should have been specifically set.
171
164
  raise "tournament name missing" unless @name_set
172
165
  raise "tournament start date missing" unless @start_set
173
-
166
+
174
167
  # Finally, exercise the tournament object's internal validation, reranking if neccessary.
175
168
  @tournament.validate!(:rerank => true)
176
-
169
+
177
170
  @tournament
178
171
  end
179
-
172
+
173
+ # Parse Krause data returning a Tournament on success or a nil on failure.
174
+ # In the case of failure, an error message can be retrived via the <em>error</em> method.
175
+ def parse(krs)
176
+ begin
177
+ parse!(krs)
178
+ rescue => ex
179
+ @error = ex.message
180
+ nil
181
+ end
182
+ end
183
+
184
+ # Same as <em>parse!</em> except the input is a file name rather than file contents.
185
+ def parse_file!(file)
186
+ krause = open(file) { |f| f.read }
187
+ parse!(krause)
188
+ end
189
+
190
+ # Same as <em>parse</em> except the input is a file name rather than file contents.
191
+ def parse_file(file)
192
+ begin
193
+ parse_file!(file)
194
+ rescue => ex
195
+ @error = ex.message
196
+ nil
197
+ end
198
+ end
199
+
180
200
  # Serialise a tournament back into Krause format.
181
201
  def serialize(t)
182
202
  return nil unless t.class == ICU::Tournament;
@@ -206,20 +226,20 @@ attributes in an ICU::Tournament instance.
206
226
  end
207
227
 
208
228
  private
209
-
229
+
210
230
  def set_name
211
231
  @tournament.name = @data
212
232
  @name_set = true
213
233
  end
214
-
234
+
215
235
  def set_start
216
236
  @tournament.start = @data
217
237
  @start_set = true
218
238
  end
219
-
239
+
220
240
  def add_player
221
241
  raise "player record less than minimum length" if @line.length < 99
222
-
242
+
223
243
  # Player details.
224
244
  num = @data[0, 4]
225
245
  nam = Name.new(@data[10, 32])
@@ -235,7 +255,7 @@ attributes in an ICU::Tournament instance.
235
255
  }
236
256
  player = Player.new(nam.first, nam.last, num, opt)
237
257
  @tournament.add_player(player)
238
-
258
+
239
259
  # Results.
240
260
  points = @data[77, 4].strip
241
261
  points = points == '' ? nil : points.to_f
@@ -249,7 +269,7 @@ attributes in an ICU::Tournament instance.
249
269
  end
250
270
  raise "declared points total (#{points}) does not agree with total from summed results (#{total})" if points && points != total
251
271
  end
252
-
272
+
253
273
  def add_result(round, player, data)
254
274
  return 0.0 if data.strip! == '' # no result for this round
255
275
  raise "invalid result '#{data}'" unless data.match(/^(0{1,4}|[1-9]\d{0,3}) (w|b|-) (1|0|=|\+|-)$/)
@@ -264,7 +284,7 @@ attributes in an ICU::Tournament instance.
264
284
  @results << [@lineno, player, data, result]
265
285
  result.points
266
286
  end
267
-
287
+
268
288
  def add_team
269
289
  raise error "team record less than minimum length" if @line.length < 40
270
290
  team = Team.new(@data[0, 31])
@@ -275,7 +295,7 @@ attributes in an ICU::Tournament instance.
275
295
  end
276
296
  @tournament.add_team(team)
277
297
  end
278
-
298
+
279
299
  def add_round_dates
280
300
  raise "round dates record less than minimum length" if @line.length < 99
281
301
  index = 87
@@ -292,7 +312,7 @@ attributes in an ICU::Tournament instance.
292
312
  end
293
313
  end
294
314
  end
295
-
315
+
296
316
  class Player
297
317
  # Format a player's 001 record as it would appear in a Krause formatted file (including the final newline).
298
318
  def to_krause(rounds)
@@ -314,7 +334,7 @@ attributes in an ICU::Tournament instance.
314
334
  krause << "\n"
315
335
  end
316
336
  end
317
-
337
+
318
338
  class Result
319
339
  # Format a player's result as it would appear in a Krause formatted file (exactly 8 characters long, including leading whitespace).
320
340
  def to_krause
@@ -1,5 +1,5 @@
1
1
  module ICU
2
2
  class Tournament
3
- VERSION = "0.9.5"
3
+ VERSION = "0.9.6"
4
4
  end
5
5
  end
@@ -543,6 +543,37 @@ CSV
543
543
  @t.serialize('ForeignCSV').should == @csv
544
544
  end
545
545
  end
546
+
547
+ context "parsing files" do
548
+ before(:each) do
549
+ @p = ICU::Tournament::ForeignCSV.new
550
+ @s = File.dirname(__FILE__) + '/samples/fcsv'
551
+ end
552
+
553
+ it "should error on a non-existant valid file" do
554
+ file = "#{@s}/not_there.csv"
555
+ lambda { @p.parse_file!(file) }.should raise_error
556
+ t = @p.parse_file(file)
557
+ t.should be_nil
558
+ @p.error.should match(/no such file/i)
559
+ end
560
+
561
+ it "should error on an invalid file" do
562
+ file = "#{@s}/invalid.csv"
563
+ lambda { @p.parse_file!(file) }.should raise_error
564
+ t = @p.parse_file(file)
565
+ t.should be_nil
566
+ @p.error.should match(/expected.*event.*name/i)
567
+ end
568
+
569
+ it "should parse a valid file" do
570
+ file = "#{@s}/valid.csv"
571
+ lambda { @p.parse_file!(file) }.should_not raise_error
572
+ t = @p.parse_file(file)
573
+ t.should be_an_instance_of(ICU::Tournament)
574
+ t.players.size.should == 16
575
+ end
576
+ end
546
577
  end
547
578
  end
548
579
  end
@@ -374,6 +374,37 @@ KRAUSE
374
374
  lambda { t = @p.parse!(@k) }.should raise_error(/opponent/)
375
375
  end
376
376
  end
377
+
378
+ context "parsing files" do
379
+ before(:each) do
380
+ @p = ICU::Tournament::Krause.new
381
+ @s = File.dirname(__FILE__) + '/samples/krause'
382
+ end
383
+
384
+ it "should error on a non-existant valid file" do
385
+ file = "#{@s}/not_there.tab"
386
+ lambda { @p.parse_file!(file) }.should raise_error
387
+ t = @p.parse_file(file)
388
+ t.should be_nil
389
+ @p.error.should match(/no such file/i)
390
+ end
391
+
392
+ it "should error on an invalid file" do
393
+ file = "#{@s}/invalid.tab"
394
+ lambda { @p.parse_file!(file) }.should raise_error
395
+ t = @p.parse_file(file)
396
+ t.should be_nil
397
+ @p.error.should match(/tournament name missing/i)
398
+ end
399
+
400
+ it "should parse a valid file" do
401
+ file = "#{@s}/valid.tab"
402
+ lambda { @p.parse_file!(file) }.should_not raise_error
403
+ t = @p.parse_file(file)
404
+ t.should be_an_instance_of(ICU::Tournament)
405
+ t.players.size.should == 12
406
+ end
407
+ end
377
408
  end
378
409
  end
379
410
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: icu_tournament
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Orr