icu_tournament 1.4.3 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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"
|