sanichi-chess_icu 0.2.7 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :minor: 2
3
- :patch: 7
3
+ :patch: 8
4
4
  :major: 0
@@ -47,14 +47,15 @@ The player number is irrelevant.
47
47
  john1 == john2 # => true (federations don't disagree because one is unset)
48
48
  john2 == john3 # => false (federations disagree)
49
49
 
50
- If, in addition, none of _rating_, _dob_ and _id_ disagree then two players are equal according to _eql?_.
50
+ If, in addition, _rating_, _dob_, _gender_ and _id_ do not disagree then two players are equal
51
+ according to the stricter criteria of _eql?_.
51
52
 
52
53
  mark1 = ICU::Player.new('Mark', 'Orr', 31, :fed = 'IRL', :rating => 2100)
53
54
  mark2 = ICU::Player.new('Mark', 'Orr', 33, :fed = 'IRL', :rating => 2100, :title => 'IM')
54
55
  mark3 = ICU::Player.new('Mark', 'Orr', 37, :fed = 'IRL', :rating => 2200, :title => 'IM')
55
56
 
56
57
  mark1.eql?(mark2) # => true (ratings agree and titles don't disagree)
57
- mark2.eql?(mark3) # => false (the ratings are unequl)
58
+ mark2.eql?(mark3) # => false (the ratings are not the same)
58
59
 
59
60
  The presence of two players in the same tournament that are equal according to _==_ but unequal
60
61
  according to _eql?__ is likely to indicate a data entry error.
@@ -63,7 +64,7 @@ If two instances represent the same player and are equal according to _==_ then
63
64
  _title_ and _fed_ attributes of the two can be merged. For example:
64
65
 
65
66
  fox1 = ICU::Player.new('Tony', 'Fox', 12, :id => 456)
66
- fox2 = ICU::Player.new('Tony', 'Fox', 21, :rating => 2100, :fed => 'IRL')
67
+ fox2 = ICU::Player.new('Tony', 'Fox', 21, :rating => 2100, :fed => 'IRL', :gender => 'M')
67
68
  fox1.merge(fox2)
68
69
 
69
70
  Any attributes present in the second player but not in the first are copied to the first.
@@ -71,11 +72,12 @@ All other attributes are unaffected.
71
72
 
72
73
  fox1.rating # => 2100
73
74
  fox1.fed # => 'IRL'
75
+ fox1.gender # => 'M'
74
76
 
75
77
  =end
76
78
 
77
79
  class Player
78
- attr_accessor :first_name, :last_name, :num, :id, :fed, :title, :rating, :rank, :dob
80
+ attr_accessor :first_name, :last_name, :num, :id, :fed, :title, :rating, :rank, :dob, :gender
79
81
  attr_reader :results
80
82
 
81
83
  # Constructor. Must supply both names and a unique number for the tournament.
@@ -83,7 +85,7 @@ All other attributes are unaffected.
83
85
  self.first_name = first_name
84
86
  self.last_name = last_name
85
87
  self.num = num
86
- [:id, :fed, :title, :rating, :rank, :dob].each do |atr|
88
+ [:id, :fed, :title, :rating, :rank, :dob, :gender].each do |atr|
87
89
  self.send("#{atr}=", opt[atr]) unless opt[atr].nil?
88
90
  end
89
91
  @results = []
@@ -174,7 +176,15 @@ All other attributes are unaffected.
174
176
  raise "invalid DOB (#{dob})" if @dob.nil? && dob.length > 0
175
177
  end
176
178
 
177
- # Add a result.
179
+ # Gender. Is either unknown (nil) or one of _M_ or _F_.
180
+ def gender=(gender)
181
+ @gender = gender.to_s.strip[0,1].upcase
182
+ @gender = nil if @gender == ''
183
+ @gender = 'F' if @gender == 'W'
184
+ raise "invalid gender (#{gender})" unless @gender.nil? || @gender.match(/^[MF]$/)
185
+ end
186
+
187
+ # Add a result. Use the same name method in ICU::Tournament instead.
178
188
  def add_result(result)
179
189
  raise "invalid result" unless result.class == ICU::Result
180
190
  raise "player number (#{@num}) is not matched to result player number (#{result.player})" unless @num == result.player
@@ -202,11 +212,11 @@ All other attributes are unaffected.
202
212
  true
203
213
  end
204
214
 
205
- # Strict equality test. Passes if the playes are loosly equal and also if their ID, rating and title are not different.
215
+ # Strict equality test. Passes if the playes are loosly equal and also if their ID, rating, gender and title are not different.
206
216
  def eql?(other)
207
217
  return true if equal?(other)
208
218
  return false unless self == other
209
- [:id, :rating, :title].each do |m|
219
+ [:id, :rating, :title, :gender].each do |m|
210
220
  return false if self.send(m) && other.send(m) && self.send(m) != other.send(m)
211
221
  end
212
222
  true
@@ -215,7 +225,7 @@ All other attributes are unaffected.
215
225
  # Merge in some of the details of another player.
216
226
  def merge(other)
217
227
  raise "cannot merge two players that are not equal" unless self == other
218
- [:id, :rating, :title, :fed].each do |m|
228
+ [:id, :rating, :title, :fed, :gender].each do |m|
219
229
  self.send("#{m}=", other.send(m)) unless self.send(m)
220
230
  end
221
231
  end
@@ -30,19 +30,19 @@ Would result in the following output.
30
30
  0.5 Mark Orr
31
31
 
32
32
  Note that the players should be added first because the _add_result_ method will
33
- raise an exception if the players it references through their numbers (10, 20
34
- and 30 in this example) have not already been added to the tournament.
33
+ raise an exception if the players it references through their tournament numbers
34
+ (10, 20 and 30 in this example) have not already been added to the tournament.
35
35
 
36
36
  =end
37
37
 
38
38
  class Tournament
39
- attr_reader :name, :start, :rounds, :site
39
+ attr_reader :name, :start, :finish, :rounds, :site, :city, :fed, :type, :arbiter, :deputy, :time_control
40
40
 
41
41
  # Constructor. Name and start date must be supplied. Other attributes are optional.
42
42
  def initialize(name, start, opt={})
43
43
  self.name = name
44
44
  self.start = start
45
- [:rounds, :site].each { |a| self.send("#{a}=", opt[a]) unless opt[a].nil? }
45
+ [:finish, :rounds, :site, :city, :fed, :type, :arbiter, :deputy, :time_control].each { |a| self.send("#{a}=", opt[a]) unless opt[a].nil? }
46
46
  @player = {}
47
47
  end
48
48
 
@@ -52,6 +52,29 @@ and 30 in this example) have not already been added to the tournament.
52
52
  @name = name.to_s.strip
53
53
  end
54
54
 
55
+ # Set the tournament city. Can be _nil.
56
+ def city=(city)
57
+ city = city.to_s.strip
58
+ if city == ''
59
+ @city = nil
60
+ else
61
+ raise "invalid tournament city (#{city})" unless city.match(/[a-z]/i)
62
+ @city = city
63
+ end
64
+ end
65
+
66
+ # Set the tournament federation. Can be _nil.
67
+ def fed=(fed)
68
+ fed = fed.to_s.strip
69
+ if fed == ''
70
+ @fed = nil
71
+ else
72
+ raise "invalid tournament federation (#{fed})" unless fed.match(/^[-a-z ]+/i) && fed.length >= 3
73
+ fed.upcase! if fed.length == 3
74
+ @fed = fed
75
+ end
76
+ end
77
+
55
78
  # Set a start date in yyyy-mm-dd format.
56
79
  def start=(start)
57
80
  start = start.to_s.strip
@@ -59,6 +82,17 @@ and 30 in this example) have not already been added to the tournament.
59
82
  raise "invalid start date (#{start})" unless @start
60
83
  end
61
84
 
85
+ # Set an end date in yyyy-mm-dd format.
86
+ def finish=(finish)
87
+ finish = finish.to_s.strip
88
+ if finish == ''
89
+ @finish = nil
90
+ else
91
+ @finish = Util.parsedate(finish)
92
+ raise "invalid finish date (#{finish})" unless @finish
93
+ end
94
+ end
95
+
62
96
  # Set the number of rounds. Is either unknown (_nil_) or a positive integer.
63
97
  def rounds=(rounds)
64
98
  @rounds = case rounds
@@ -78,6 +112,34 @@ and 30 in this example) have not already been added to the tournament.
78
112
  raise "invalid site (#{site})" unless @site.nil? || @site.match(/^https?:\/\/[-\w]+(\.[-\w]+)+(\/[^\s]*)?$/i)
79
113
  end
80
114
 
115
+ # Set the tournament type. Should be either unknown (_nil_) or contain some letters.
116
+ def type=(type)
117
+ @type = type.to_s.strip
118
+ @type = nil if @type == ''
119
+ raise "invalid tournament type (#{type})" unless @type.nil? || @type.match(/[a-z]/i)
120
+ end
121
+
122
+ # Set the tournament arbiter. Should be either unknown (_nil_) or contain some letters.
123
+ def arbiter=(arbiter)
124
+ @arbiter = arbiter.to_s.strip
125
+ @arbiter = nil if @arbiter == ''
126
+ raise "invalid tournament arbiter (#{arbiter})" unless @arbiter.nil? || @arbiter.match(/[a-z]/i)
127
+ end
128
+
129
+ # Set the tournament deputy. Should be either unknown (_nil_) or contain some letters.
130
+ def deputy=(deputy)
131
+ @deputy = deputy.to_s.strip
132
+ @deputy = nil if @deputy == ''
133
+ raise "invalid tournament deputy (#{deputy})" unless @deputy.nil? || @deputy.match(/[a-z]/i)
134
+ end
135
+
136
+ # Set the time control. Should be either unknown (_nil_) or contain some numbers.
137
+ def time_control=(time_control)
138
+ @time_control = time_control.to_s.strip
139
+ @time_control = nil if @time_control == ''
140
+ raise "invalid tournament time control (#{time_control})" unless @time_control.nil? || @time_control.match(/[1-9]\d/)
141
+ end
142
+
81
143
  # Add a new player to the tournament. Must have a unique player number.
82
144
  def add_player(player)
83
145
  raise "invalid player" unless player.class == ICU::Player
@@ -73,6 +73,10 @@ However, none of the opponents' results are rateable. For example:
73
73
  opponent = tournament.players(2)
74
74
  opponent.name # => "Taylor, Peter P."
75
75
  opponent.results[0].rateable # => false
76
+
77
+ A tournament can be serialized back to CSV format (the reverse of parsing) with the serialise method.
78
+
79
+ csv = parser.serialize(tournament)
76
80
 
77
81
  =end
78
82
 
@@ -134,6 +138,41 @@ However, none of the opponents' results are rateable. For example:
134
138
 
135
139
  @tournament
136
140
  end
141
+
142
+ # Serialise a tournament back into CSV format.
143
+ def serialise(t)
144
+ return nil unless t.class == ICU::Tournament;
145
+ FasterCSV.generate do |csv|
146
+ csv << ["Event", t.name]
147
+ csv << ["Start", t.start]
148
+ csv << ["Rounds", t.rounds]
149
+ csv << ["Website", t.site]
150
+ t.players.each do |p|
151
+ next unless p.id
152
+ csv << []
153
+ csv << ["Player", p.id, p.last_name, p.first_name]
154
+ (1..t.rounds).each do |n|
155
+ data = []
156
+ data << n
157
+ r = p.find_result(n)
158
+ data << case r.score; when 'W' then '1'; when 'L' then '0'; else '='; end
159
+ if r.rateable
160
+ data << r.colour
161
+ o = t.player(r.opponent)
162
+ data << o.last_name
163
+ data << o.first_name
164
+ data << o.rating
165
+ data << o.title
166
+ data << o.fed
167
+ else
168
+ data << '-'
169
+ end
170
+ csv << data
171
+ end
172
+ csv << ["Total", p.points]
173
+ end
174
+ end
175
+ end
137
176
 
138
177
  private
139
178
 
@@ -144,6 +144,22 @@ module ICU
144
144
  end
145
145
  end
146
146
 
147
+ context "gender" do
148
+ it "defaults to nil" do
149
+ Player.new('Mark', 'Orr', 3).gender.should be_nil
150
+ Player.new('Mark', 'Orr', 3, :gender => ' ').gender.should be_nil
151
+ end
152
+
153
+ it "should be either M or F" do
154
+ Player.new('Mark', 'Orr', 3, :gender => 'male').gender.should == 'M'
155
+ Player.new('April', 'Cronin', 3, :gender => 'woman').gender.should == 'F'
156
+ end
157
+
158
+ it "should raise an exception if the gender is not specified properly" do
159
+ lambda { Player.new('Mark', 'Orr', 3, :gender => 'X') }.should raise_error(/invalid gender/)
160
+ end
161
+ end
162
+
147
163
  context "results and points" do
148
164
  it "should initialise to an empty array" do
149
165
  results = Player.new('Mark', 'Orr', 3).results
@@ -386,6 +386,37 @@ CSV
386
386
  lambda { @f.parse!(csv) }.should raise_error(/line 13.*same name.*conflicting/i)
387
387
  end
388
388
  end
389
+
390
+ context "serialisation" do
391
+ before(:each) do
392
+ @csv = <<CSV
393
+ Event,"Edinburgh Masters, 2007"
394
+ Start,2007-08-09
395
+ Rounds,2
396
+ Website,http://www.chesscenter.com/twic/twic.html
397
+
398
+ Player,3364,Ui Laighleis,Gearoidin
399
+ 1,0,W,Kasparov,Gary,2800,GM,RUS
400
+ 2,1,B,Cronin,April,2005,,IRL
401
+ Total,1.0
402
+
403
+ Player,1350,Orr,Mark
404
+ 1,=,W,Cronin,April,2005,,IRL
405
+ 2,=,-
406
+ Total,1.0
407
+ CSV
408
+ @f = ForeignCSV.new
409
+ @t = @f.parse!(@csv)
410
+ end
411
+
412
+ it "should serialize back to the original" do
413
+ @f.serialise(@t).should == @csv
414
+ end
415
+
416
+ it "should return nil on invalid input" do
417
+ @f.serialise('Rubbish').should be_nil
418
+ end
419
+ end
389
420
  end
390
421
  end
391
422
  end
@@ -37,6 +37,61 @@ module ICU
37
37
  end
38
38
  end
39
39
 
40
+ # Tournament city.
41
+ context "city" do
42
+ before(:each) do
43
+ @t = Tournament.new('Edinburgh Masters', '2009-11-09', :city => 'Edinburgh')
44
+ end
45
+
46
+ it "may be specified in constructor" do
47
+ @t.city.should == 'Edinburgh'
48
+ end
49
+
50
+ it "can be replaced by accessor" do
51
+ @t.city = 'Glasgow'
52
+ @t.city.should == 'Glasgow'
53
+ end
54
+
55
+ it "can be set to nil" do
56
+ @t.city = ''
57
+ @t.city.should be_nil
58
+ end
59
+
60
+ it "should not be without letters if set" do
61
+ lambda { @t.city = '123' }.should raise_error(/invalid.*city/)
62
+ end
63
+ end
64
+
65
+ # Tournament federation.
66
+ context "federation" do
67
+ before(:each) do
68
+ @t = Tournament.new('Edinburgh Masters', '2009-11-09', :fed => 'SCO')
69
+ end
70
+
71
+ it "may be specified in constructor" do
72
+ @t.fed.should == 'SCO'
73
+ end
74
+
75
+ it "can be replaced by accessor" do
76
+ @t.fed = 'IRL'
77
+ @t.fed.should == 'IRL'
78
+ end
79
+
80
+ it "can be set to nil" do
81
+ @t.fed = ''
82
+ @t.fed.should be_nil
83
+ end
84
+
85
+ it "three letters will automatically be upcased" do
86
+ @t.fed = 'rus'
87
+ @t.fed.should == 'RUS'
88
+ end
89
+
90
+ it "should not be without letters if set" do
91
+ lambda { @t.fed = '123' }.should raise_error(/invalid.*federation/)
92
+ end
93
+ end
94
+
40
95
  # Tournament start date.
41
96
  context "start date" do
42
97
  before(:each) do
@@ -58,6 +113,32 @@ module ICU
58
113
  end
59
114
  end
60
115
 
116
+ # Tournament finish date.
117
+ context "finish date" do
118
+ before(:each) do
119
+ @t = Tournament.new('Edinburgh Masters', '2009-11-09', :finish => '12th November 2009')
120
+ end
121
+
122
+ it "may be specified in constructor" do
123
+ @t.finish.should == '2009-11-12'
124
+ end
125
+
126
+ it "can be replaced by accessor" do
127
+ @t.finish = '16th December 2009'
128
+ @t.finish.should == '2009-12-16'
129
+ end
130
+
131
+ it "can be set to nil" do
132
+ @t.finish = ''
133
+ @t.finish.should be_nil
134
+ end
135
+
136
+ it "should be a valid date" do
137
+ lambda { Tournament.new('Edinburgh Masters', '2009-11-09', :finish => 'next week') }.should raise_error(/invalid.*date/)
138
+ lambda { @t.finish = 'X' }.should raise_error(/invalid.*date/)
139
+ end
140
+ end
141
+
61
142
  # Number of rounds.
62
143
  context "rounds" do
63
144
  it "defaults to nil" do
@@ -84,6 +165,49 @@ module ICU
84
165
  end
85
166
  end
86
167
 
168
+ # Type, arbiter, deputy and time control.
169
+ context "type, arbiter, deputy and time control" do
170
+ before(:each) do
171
+ @t = Tournament.new('Edinburgh Masters', '2009-11-09', :type => 'Swiss', :arbiter => 'Gerry Graham', :deputy => 'Herbert Scarry', :time_control => '120 minutes')
172
+ end
173
+
174
+ it "may be specified in constructor" do
175
+ @t.type.should == 'Swiss'
176
+ @t.arbiter.should == 'Gerry Graham'
177
+ @t.deputy.should == 'Herbert Scarry'
178
+ @t.time_control.should == '120 minutes'
179
+ end
180
+
181
+ it "can be replaced by accessor" do
182
+ @t.type = 'all-play-all'
183
+ @t.type.should == 'all-play-all'
184
+ @t.arbiter = 'Michael Crowe'
185
+ @t.arbiter.should == 'Michael Crowe'
186
+ @t.deputy = 'Mark Orr'
187
+ @t.deputy.should == 'Mark Orr'
188
+ @t.time_control = '90 minutes'
189
+ @t.time_control.should == '90 minutes'
190
+ end
191
+
192
+ it "can be set to nil" do
193
+ @t.type = ''
194
+ @t.type.should be_nil
195
+ @t.arbiter = ''
196
+ @t.arbiter.should be_nil
197
+ @t.deputy = ''
198
+ @t.deputy.should be_nil
199
+ @t.time_control = ''
200
+ @t.time_control.should be_nil
201
+ end
202
+
203
+ it "should be valid" do
204
+ lambda { @t.type = '123' }.should raise_error(/invalid.*type/)
205
+ lambda { @t.arbiter = '123' }.should raise_error(/invalid.*arbiter/)
206
+ lambda { @t.deputy = '123' }.should raise_error(/invalid.*deputy/)
207
+ lambda { @t.time_control = 'abc' }.should raise_error(/invalid.*time control/)
208
+ end
209
+ end
210
+
87
211
  # Tournament players.
88
212
  context "players" do
89
213
  before(:each) do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sanichi-chess_icu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Orr