icu_tournament 1.4.3 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/icu_tournament/player.rb +9 -1
- data/lib/icu_tournament/result.rb +26 -11
- data/lib/icu_tournament/tournament.rb +49 -7
- data/lib/icu_tournament/version.rb +1 -1
- data/spec/player_spec.rb +16 -0
- data/spec/result_spec.rb +53 -50
- data/spec/tournament_spec.rb +32 -3
- metadata +4 -4
@@ -181,11 +181,19 @@ module ICU
|
|
181
181
|
end
|
182
182
|
end
|
183
183
|
|
184
|
-
# Lookup a result by round number.
|
184
|
+
# Lookup a result by round number and return it (or nil if there is no such result).
|
185
185
|
def find_result(round)
|
186
186
|
@results.find { |r| r.round == round }
|
187
187
|
end
|
188
188
|
|
189
|
+
# Lookup a result by round number, remove it and return it (or return nil if there is no such result).
|
190
|
+
def remove_result(round)
|
191
|
+
result = find_result(round)
|
192
|
+
return unless result
|
193
|
+
@results.delete(result)
|
194
|
+
result
|
195
|
+
end
|
196
|
+
|
189
197
|
# Return the player's total points.
|
190
198
|
def points
|
191
199
|
@results.inject(0.0) { |t, r| t += r.points }
|
@@ -66,6 +66,19 @@ module ICU
|
|
66
66
|
#
|
67
67
|
# The _points_ read-only accessor always returns a floating point number: either 0.0, 0.5 or 1.0.
|
68
68
|
#
|
69
|
+
# Two results are <em>eql?</em> if all there attributes are the same, unless exceptions are specified.
|
70
|
+
#
|
71
|
+
# r = ICU::Result.new(1, 1, 'W', :opponent => 2)
|
72
|
+
# r1 = ICU::Result.new(1, 1, 'W', :opponent => 2)
|
73
|
+
# r2 = ICU::Result.new(1, 1, 'W', :opponent => 2, :rateable => false)
|
74
|
+
# r3 = ICU::Result.new(1, 1, 'L', :opponent => 2, :rateable => false)
|
75
|
+
#
|
76
|
+
# r.eql?(r1) # => true
|
77
|
+
# r.eql?(r2) # => false
|
78
|
+
# r.eql?(r3) # => false
|
79
|
+
# r.eql?(r2, :except => :rateable) # => true
|
80
|
+
# r.eql?(r3, :except => [:rateable, :score]) # => true
|
81
|
+
#
|
69
82
|
class Result
|
70
83
|
extend ICU::Accessor
|
71
84
|
attr_positive :round
|
@@ -167,20 +180,22 @@ module ICU
|
|
167
180
|
"R#{@round}P#{@player}O#{@opponent || '-'}#{@score}#{@colour || '-'}#{@rateable ? 'R' : 'U'}"
|
168
181
|
end
|
169
182
|
|
170
|
-
#
|
171
|
-
def
|
183
|
+
# Equality. True if all attributes equal, exceptions allowed.
|
184
|
+
def eql?(other, opt={})
|
185
|
+
return true if equal?(other)
|
172
186
|
return unless other.is_a? Result
|
173
|
-
|
174
|
-
|
187
|
+
except = Hash.new
|
188
|
+
if opt[:except]
|
189
|
+
if opt[:except].is_a?(Array)
|
190
|
+
opt[:except].each { |x| except[x.to_sym] = true }
|
191
|
+
else
|
192
|
+
except[opt[:except].to_sym] = true
|
193
|
+
end
|
194
|
+
end
|
195
|
+
[:round, :player, :opponent, :colour, :score, :rateable].each do |m|
|
196
|
+
return false unless except[m] || self.send(m) == other.send(m)
|
175
197
|
end
|
176
198
|
true
|
177
199
|
end
|
178
|
-
|
179
|
-
# Strict equality. True if the there's loose equality and also the rateablity is the same.
|
180
|
-
def eql?(other)
|
181
|
-
return true if equal?(other)
|
182
|
-
return false unless self == other
|
183
|
-
self.rateable == other.rateable
|
184
|
-
end
|
185
200
|
end
|
186
201
|
end
|
@@ -55,6 +55,22 @@ module ICU
|
|
55
55
|
# t.add_result(ICU::Result.new(3, 20, 'L', :opponent => 10, :colour => 'W'))
|
56
56
|
# t.add_result(ICU::Result.new(3, 10, 'D', :opponent => 20, :colour => 'B')) # would raise an exception
|
57
57
|
#
|
58
|
+
# == Asymmetric Scores
|
59
|
+
#
|
60
|
+
# There is one exception to the rule that two corresponding results must be consistent:
|
61
|
+
# if both results are unrateable then the two scores need not sum to 1. The commonest case
|
62
|
+
# this caters for is probably that of a double default. To create such asymmetric results
|
63
|
+
# you must add the result from both players' perspectives. For example:
|
64
|
+
#
|
65
|
+
# t.add_result(ICU::Result.new(3, 20, 'L', :opponent => 10, :rateable => false))
|
66
|
+
# t.add_result(ICU::Result.new(3, 10, 'L', :opponent => 20, :rateable => false))
|
67
|
+
#
|
68
|
+
# After the first _add_result_ the two results are, as usual, consistent (in particular, the loss for player 20
|
69
|
+
# is balanced by a win for player 10). However, the second _add_result_, which asserts player 10 lost, does not cause
|
70
|
+
# an exception. It would have done if the results had been rateable but, because they are not, the scores are
|
71
|
+
# allowed to add up to something other than 1.0 (in this case, zero) and the effect of the second call to _add_result_
|
72
|
+
# is merely to adjust the score of player 10 from a win to a loss (while maintaining the loss for player 20).
|
73
|
+
#
|
58
74
|
# See ICU::Player and ICU::Result for more details about players and results.
|
59
75
|
#
|
60
76
|
# == Validation
|
@@ -67,11 +83,11 @@ module ICU
|
|
67
83
|
# Validations checks that:
|
68
84
|
#
|
69
85
|
# * there are at least two players
|
70
|
-
# *
|
71
|
-
# *
|
86
|
+
# * result round numbers are consistent (no more than one game per player per round)
|
87
|
+
# * corresponding results are consistent (although they may have asymmetric scores if unrateable, as previously desribed)
|
72
88
|
# * the tournament dates (start, finish, round dates), if there are any, are consistent
|
73
|
-
# *
|
74
|
-
# * there are no players with duplicate ICU IDs or duplicate FIDE IDs
|
89
|
+
# * player ranks are consistent with their scores
|
90
|
+
# * there are no players with duplicate \ICU IDs or duplicate \FIDE IDs
|
75
91
|
#
|
76
92
|
# Side effects of calling <em>validate!</em> or _invalid_ include:
|
77
93
|
#
|
@@ -87,7 +103,7 @@ module ICU
|
|
87
103
|
#
|
88
104
|
# t.validate!(:type => 'ForeignCSV')
|
89
105
|
#
|
90
|
-
# which, amongst other tests, checks that there is at least one player with an ICU number and
|
106
|
+
# which, amongst other tests, checks that there is at least one player with an \ICU number and
|
91
107
|
# that all such players have a least one game against a FIDE rated opponent. This is an example
|
92
108
|
# of a specialized check that is only appropriate for a particular serializer. If it raises an
|
93
109
|
# exception then the tournament cannot be serialized that way.
|
@@ -278,6 +294,7 @@ module ICU
|
|
278
294
|
raise "invalid result" unless result.class == ICU::Result
|
279
295
|
raise "result round number (#{result.round}) inconsistent with number of tournament rounds" if @rounds && result.round > @rounds
|
280
296
|
raise "player number (#{result.player}) does not exist" unless @player[result.player]
|
297
|
+
return if add_asymmetric_result?(result)
|
281
298
|
@player[result.player].add_result(result)
|
282
299
|
if result.opponent
|
283
300
|
raise "opponent number (#{result.opponent}) does not exist" unless @player[result.opponent]
|
@@ -418,14 +435,15 @@ module ICU
|
|
418
435
|
raise "duplicate FIDE IDs, players #{p.num} and #{fide_ids[p.fide_id]}" if fide_ids[p.fide_id]
|
419
436
|
fide_ids[p.fide_id] = num
|
420
437
|
end
|
421
|
-
|
438
|
+
return if p.results.size == 0
|
422
439
|
p.results.each do |r|
|
423
440
|
next unless r.opponent
|
424
441
|
opponent = @player[r.opponent]
|
425
442
|
raise "opponent #{r.opponent} of player #{num} is not in the tournament" unless opponent
|
426
443
|
o = opponent.find_result(r.round)
|
427
444
|
raise "opponent #{r.opponent} of player #{num} has no result in round #{r.round}" unless o
|
428
|
-
|
445
|
+
score = r.rateable || o.rateable ? [] : [:score]
|
446
|
+
raise "opponent's result (#{o.inspect}) is not reverse of player's (#{r.inspect})" unless o.reverse.eql?(r, :except => score)
|
429
447
|
end
|
430
448
|
end
|
431
449
|
end
|
@@ -587,5 +605,29 @@ module ICU
|
|
587
605
|
else player.name
|
588
606
|
end
|
589
607
|
end
|
608
|
+
|
609
|
+
# Detect when an asymmetric result is about to be added, make the appropriate adjustment and return true.
|
610
|
+
# The conditions for an asymric result are: the player's result already exists, the opponent's result
|
611
|
+
# already exists, both results are unrateable and the reverse of one result is equal to the other, apart
|
612
|
+
# from score. In this case all we do update score of the player's result, thus allowing two results whose
|
613
|
+
# total score does not add to 1.
|
614
|
+
def add_asymmetric_result?(result)
|
615
|
+
return false if result.rateable
|
616
|
+
|
617
|
+
plr = @player[result.player]
|
618
|
+
opp = @player[result.opponent]
|
619
|
+
return false unless plr && opp
|
620
|
+
|
621
|
+
plr_result = plr.find_result(result.round)
|
622
|
+
opp_result = opp.find_result(result.round)
|
623
|
+
return false unless plr_result && opp_result
|
624
|
+
return false if plr_result.rateable || opp_result.rateable
|
625
|
+
|
626
|
+
reversed = plr_result.reverse
|
627
|
+
return false unless reversed && reversed.eql?(opp_result, :except => :score)
|
628
|
+
|
629
|
+
plr_result.score = result.score
|
630
|
+
true
|
631
|
+
end
|
590
632
|
end
|
591
633
|
end
|
data/spec/player_spec.rb
CHANGED
@@ -247,6 +247,22 @@ module ICU
|
|
247
247
|
end
|
248
248
|
end
|
249
249
|
|
250
|
+
context "removing a result" do
|
251
|
+
before(:all) do
|
252
|
+
@p = Player.new('Mark', 'Orr', 1)
|
253
|
+
@p.add_result(Result.new(1, 1, 'W', :opponent => 37, :score => 'W', :colour => 'W'))
|
254
|
+
@p.add_result(Result.new(2, 1, 'W', :opponent => 13, :score => 'W', :colour => 'B'))
|
255
|
+
@p.add_result(Result.new(3, 1, 'W', :opponent => 7, :score => 'D', :colour => 'W'))
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should find and remove a result by round number" do
|
259
|
+
result = @p.remove_result(1)
|
260
|
+
result.inspect.should == "R1P1O37WWR"
|
261
|
+
@p.results.size.should == 2
|
262
|
+
@p.results.map(&:round).join("|").should == "2|3"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
250
266
|
context "merge" do
|
251
267
|
before(:each) do
|
252
268
|
@p1 = Player.new('Mark', 'Orr', 1, :id => 1350)
|
data/spec/result_spec.rb
CHANGED
@@ -8,7 +8,7 @@ module ICU
|
|
8
8
|
lambda { Result.new(3, 5, 'W', :opponent => 11, :colour => 'W') }.should_not raise_error
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
context "round number" do
|
13
13
|
it "should be a positive integer" do
|
14
14
|
lambda { Result.new(-2, 2, 0) }.should raise_error(/invalid positive integer/)
|
@@ -17,7 +17,7 @@ module ICU
|
|
17
17
|
Result.new(' 3 ', 2, 0).round.should == 3
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
context "player number" do
|
22
22
|
it "should be an integer" do
|
23
23
|
lambda { Result.new(1, ' ', 0) }.should raise_error(/invalid integer/)
|
@@ -27,7 +27,7 @@ module ICU
|
|
27
27
|
Result.new(1, " 9 ", 0).player.should == 9
|
28
28
|
end
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
context "score" do
|
32
32
|
[1, 1.0, 'W', 'w', '+'].each do |score|
|
33
33
|
it "should be 'W' for #{score}, #{score.class}" do
|
@@ -55,7 +55,7 @@ module ICU
|
|
55
55
|
Result.new(1, 2, 'D').points.should == 0.5
|
56
56
|
end
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
context "colour" do
|
60
60
|
it "should be 'W' or 'B' or nil (unknown)" do
|
61
61
|
Result.new(4, 1, 0).colour.should be_nil
|
@@ -66,7 +66,7 @@ module ICU
|
|
66
66
|
lambda { Result.new(4, 1, 0, :colour => 'red') }.should raise_error(/invalid colour/)
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
context "opponent number" do
|
71
71
|
it "should be nil (the default) or an integer" do
|
72
72
|
Result.new(4, 1, 0).opponent.should be_nil
|
@@ -78,27 +78,27 @@ module ICU
|
|
78
78
|
Result.new(4, 1, 0, :opponent => ' 10 ').opponent.should == 10
|
79
79
|
lambda { Result.new(4, 1, 0, :opponent => 'X') }.should raise_error(/invalid opponent number/)
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
82
|
it "should be different to player number" do
|
83
83
|
lambda { Result.new(4, 1, 0, :opponent => 1) }.should raise_error(/opponent .* player .* different/)
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
context "rateable flag" do
|
88
88
|
it "should default to false if there is no opponent" do
|
89
89
|
Result.new(4, 1, 0).rateable.should be_false
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
it "should default to true if there is an opponent" do
|
93
93
|
Result.new(4, 1, 0, :opponent => 10).rateable.should be_true
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
it "should change if an opponent is added" do
|
97
97
|
r = Result.new(4, 1, 0)
|
98
98
|
r.opponent = 5;
|
99
99
|
r.rateable.should be_true
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
it "should be settable to false from the constructor" do
|
103
103
|
Result.new(4, 1, 0, :opponent => 10, :rateable => false).rateable.should be_false
|
104
104
|
end
|
@@ -108,43 +108,43 @@ module ICU
|
|
108
108
|
r.rateable= false
|
109
109
|
r.rateable.should be_false
|
110
110
|
end
|
111
|
-
|
111
|
+
|
112
112
|
it "should not be settable to true if there is no opponent" do
|
113
113
|
r = Result.new(4, 1, 0)
|
114
114
|
r.rateable= true
|
115
115
|
r.rateable.should be_false
|
116
116
|
end
|
117
117
|
end
|
118
|
-
|
118
|
+
|
119
119
|
context "reversed result" do
|
120
120
|
it "should be nil if there is no opponent" do
|
121
121
|
Result.new(4, 1, 0).reverse.should be_nil
|
122
122
|
end
|
123
|
-
|
123
|
+
|
124
124
|
it "should have player and opponent swapped" do
|
125
125
|
r = Result.new(4, 1, 0, :opponent => 2).reverse
|
126
126
|
r.player.should == 2
|
127
127
|
r.opponent.should == 1
|
128
128
|
end
|
129
|
-
|
129
|
+
|
130
130
|
it "should have reversed result" do
|
131
131
|
Result.new(4, 1, 0, :opponent => 2).reverse.score.should == 'W'
|
132
132
|
Result.new(4, 1, 1, :opponent => 2).reverse.score.should == 'L'
|
133
133
|
Result.new(4, 1, '=', :opponent => 2).reverse.score.should == 'D'
|
134
134
|
end
|
135
|
-
|
135
|
+
|
136
136
|
it "should preserve rateability" do
|
137
137
|
Result.new(4, 1, 0, :opponent => 2).reverse.rateable.should be_true
|
138
138
|
Result.new(4, 1, 0, :opponent => 2, :rateable => false).reverse.rateable.should be_false
|
139
139
|
end
|
140
140
|
end
|
141
|
-
|
141
|
+
|
142
142
|
context "renumber the player numbers in a result" do
|
143
143
|
before(:each) do
|
144
144
|
@r1 = Result.new(1, 4, 0)
|
145
145
|
@r2 = Result.new(2, 3, 1, :opponent => 4, :color => 'B')
|
146
146
|
end
|
147
|
-
|
147
|
+
|
148
148
|
it "should renumber successfully if the map has the relevant player numbers" do
|
149
149
|
map = { 4 => 1, 3 => 2 }
|
150
150
|
@r1.renumber(map).player.should == 1
|
@@ -152,50 +152,53 @@ module ICU
|
|
152
152
|
@r1.opponent.should be_nil
|
153
153
|
@r2.opponent.should == 1
|
154
154
|
end
|
155
|
-
|
155
|
+
|
156
156
|
it "should raise exception if a player number is not in the map" do
|
157
157
|
lambda { @r1.renumber({ 5 => 1, 3 => 2 }) }.should raise_error(/player.*4.*not found/)
|
158
158
|
end
|
159
159
|
end
|
160
|
-
|
161
|
-
context "
|
160
|
+
|
161
|
+
context "equality" do
|
162
162
|
before(:each) do
|
163
|
+
@r = Result.new(1, 1, 0, :opponent => 2, :colour => 'W')
|
163
164
|
@r1 = Result.new(1, 1, 0, :opponent => 2, :colour => 'W')
|
164
|
-
@r2 = Result.new(1, 1, 0, :opponent => 2, :colour => 'W')
|
165
|
+
@r2 = Result.new(1, 1, 0, :opponent => 2, :colour => 'W', :rateable => false)
|
165
166
|
@r3 = Result.new(2, 1, 0, :opponent => 2, :colour => 'W')
|
166
|
-
@r4 = Result.new(1,
|
167
|
-
@r5 = Result.new(
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
(@
|
174
|
-
(@
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
(@
|
181
|
-
(@
|
182
|
-
(@
|
167
|
+
@r4 = Result.new(1, 1, 0, :opponent => 2, :colour => 'B')
|
168
|
+
@r5 = Result.new(2, 1, 1, :opponent => 3, :colour => 'B')
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should only be equal if everything is the same" do
|
172
|
+
@r.eql?(@r).should be_true
|
173
|
+
@r.eql?(@r1).should be_true
|
174
|
+
@r.eql?(@r2).should be_false
|
175
|
+
@r.eql?(@r3).should be_false
|
176
|
+
@r.eql?(@r4).should be_false
|
177
|
+
@r.eql?(@r5).should be_false
|
178
|
+
end
|
179
|
+
|
180
|
+
it "exceptions are allowed" do
|
181
|
+
@r.eql?(@r2, :except => :rateable).should be_true
|
182
|
+
@r.eql?(@r3, :except => "round").should be_true
|
183
|
+
@r.eql?(@r4, :except => :colour).should be_true
|
184
|
+
@r.eql?(@r5, :except => [:colour, :round, :score, "opponent"]).should be_true
|
183
185
|
end
|
184
186
|
end
|
185
|
-
|
186
|
-
context "
|
187
|
+
|
188
|
+
context "equality documentation example" do
|
187
189
|
before(:each) do
|
188
|
-
@
|
189
|
-
@
|
190
|
-
@
|
191
|
-
@
|
190
|
+
@r = ICU::Result.new(1, 1, 'W', :opponent => 2)
|
191
|
+
@r1 = ICU::Result.new(1, 1, 'W', :opponent => 2)
|
192
|
+
@r2 = ICU::Result.new(1, 1, 'W', :opponent => 2, :rateable => false)
|
193
|
+
@r3 = ICU::Result.new(1, 1, 'L', :opponent => 2, :rateable => false)
|
192
194
|
end
|
193
|
-
|
194
|
-
it "should
|
195
|
-
@
|
196
|
-
@
|
197
|
-
@
|
198
|
-
@
|
195
|
+
|
196
|
+
it "should be correct" do
|
197
|
+
@r.eql?(@r1).should be_true
|
198
|
+
@r.eql?(@r2).should be_false
|
199
|
+
@r.eql?(@r3).should be_false
|
200
|
+
@r.eql?(@r2, :except => :rateable).should be_true
|
201
|
+
@r.eql?(@r3, :except => [:rateable, :score]).should be_true
|
199
202
|
end
|
200
203
|
end
|
201
204
|
end
|
data/spec/tournament_spec.rb
CHANGED
@@ -32,8 +32,9 @@ module ICU
|
|
32
32
|
042 2009-11-09
|
33
33
|
001 10 Fischer,Bobby 1.5 1 30 w = 20 b 1
|
34
34
|
001 20 Kasparov,Garry 1.0 2 30 b 1 10 w 0
|
35
|
-
001 30 Orr,Mark 0.5 3 10 b = 20 w 0
|
35
|
+
001 30 Orr,Mark 0.5 3 10 b = 20 w 0 #
|
36
36
|
EOS
|
37
|
+
@s.sub!(/#/, '')
|
37
38
|
end
|
38
39
|
|
39
40
|
it "should serialize to Krause" do
|
@@ -324,7 +325,7 @@ EOS
|
|
324
325
|
it "can be added one at a time" do
|
325
326
|
@t.add_result(Result.new(1, 1, 'W', :opponent => 2))
|
326
327
|
@t.add_result(Result.new(2, 2, 'D', :opponent => 3))
|
327
|
-
@t.add_result(Result.new(3, 3, 'L', :opponent => 1))
|
328
|
+
@t.add_result(Result.new(3, 3, 'L', :opponent => 1, :rateable => false))
|
328
329
|
@mark.results.size.should == 2
|
329
330
|
@mark.points.should == 2.0
|
330
331
|
@gary.results.size.should == 2
|
@@ -333,10 +334,11 @@ EOS
|
|
333
334
|
@boby.points.should == 0.5
|
334
335
|
end
|
335
336
|
|
336
|
-
it "asymmetric
|
337
|
+
it "results with asymmetric scores cannot be added unless both results are unrateable" do
|
337
338
|
@t.add_result(Result.new(1, 1, 'W', :opponent => 2))
|
338
339
|
lambda { @t.add_result(Result.new(1, 2, 'D', :opponent => 1)) }.should raise_error(/result.*match/)
|
339
340
|
lambda { @t.add_result(Result.new(1, 2, 'L', :opponent => 1, :rateable => false)) }.should raise_error(/result.*match/)
|
341
|
+
lambda { @t.add_result(Result.new(3, 3, 'L', :opponent => 1, :rateable => false)) }.should_not raise_error
|
340
342
|
end
|
341
343
|
|
342
344
|
it "should have a defined player" do
|
@@ -350,6 +352,13 @@ EOS
|
|
350
352
|
it "should be consistent with the tournament's number of rounds" do
|
351
353
|
lambda { @t.add_result(Result.new(4, 1, 'W', :opponent => 2)) }.should raise_error(/round/)
|
352
354
|
end
|
355
|
+
|
356
|
+
it "documentation example should ne correct" do
|
357
|
+
@t.add_result(ICU::Result.new(3, 2, 'L', :opponent => 1, :rateable => false))
|
358
|
+
@t.add_result(ICU::Result.new(3, 1, 'L', :opponent => 2, :rateable => false))
|
359
|
+
@t.player(1).results.first.points.should == 0.0
|
360
|
+
@t.player(2).results.first.points.should == 0.0
|
361
|
+
end
|
353
362
|
end
|
354
363
|
|
355
364
|
context "finding players" do
|
@@ -495,6 +504,26 @@ EOS
|
|
495
504
|
@t.player(2).id = 1350
|
496
505
|
@t.invalid.should match(/duplicate.*ICU/)
|
497
506
|
end
|
507
|
+
|
508
|
+
it "should allow players to have no results" do
|
509
|
+
(1..3).each { |r| @t.player(1).remove_result(r) }
|
510
|
+
@t.invalid.should be_false
|
511
|
+
end
|
512
|
+
|
513
|
+
it "should not allow asymmetric scores for rateable results" do
|
514
|
+
@t.player(1).find_result(1).score = 'L'
|
515
|
+
@t.invalid.should match(/result.*reverse/)
|
516
|
+
end
|
517
|
+
|
518
|
+
it "should allow asymmetric scores for unrateable results" do
|
519
|
+
@t.player(1).find_result(1).score = 'L'
|
520
|
+
(1..2).each do |p|
|
521
|
+
r = @t.player(p).find_result(1)
|
522
|
+
r.rateable = false
|
523
|
+
r.score = 'L'
|
524
|
+
end
|
525
|
+
@t.invalid.should be_false
|
526
|
+
end
|
498
527
|
end
|
499
528
|
|
500
529
|
context "renumbering" do
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: icu_tournament
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.
|
5
|
+
version: 1.5.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Mark Orr
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-07-01 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: dbf
|
@@ -172,7 +172,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
172
172
|
requirements:
|
173
173
|
- - ">="
|
174
174
|
- !ruby/object:Gem::Version
|
175
|
-
hash:
|
175
|
+
hash: 3338096865289385673
|
176
176
|
segments:
|
177
177
|
- 0
|
178
178
|
version: "0"
|
@@ -181,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
181
181
|
requirements:
|
182
182
|
- - ">="
|
183
183
|
- !ruby/object:Gem::Version
|
184
|
-
hash:
|
184
|
+
hash: 3338096865289385673
|
185
185
|
segments:
|
186
186
|
- 0
|
187
187
|
version: "0"
|