sanichi-chess_icu 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -1
- data/Rakefile +13 -12
- data/VERSION.yml +2 -2
- data/lib/chess_icu.rb +1 -0
- data/lib/name.rb +55 -0
- data/lib/result.rb +78 -1
- data/lib/util.rb +12 -1
- data/spec/name_spec.rb +39 -3
- data/spec/util_spec.rb +4 -0
- metadata +1 -1
data/.gitignore
CHANGED
data/Rakefile
CHANGED
@@ -6,13 +6,14 @@ require 'spec/rake/spectask'
|
|
6
6
|
begin
|
7
7
|
require 'jeweler'
|
8
8
|
Jeweler::Tasks.new do |gem|
|
9
|
-
gem.name
|
10
|
-
gem.summary
|
11
|
-
gem.homepage
|
12
|
-
gem.authors
|
13
|
-
gem.email
|
14
|
-
gem.files
|
15
|
-
gem.has_rdoc
|
9
|
+
gem.name = "chess_icu"
|
10
|
+
gem.summary = "For parsing files of chess tournament data into ruby classes."
|
11
|
+
gem.homepage = "http://github.com/sanichi/chess_icu"
|
12
|
+
gem.authors = ["Mark Orr"]
|
13
|
+
gem.email = "mark.j.l.orr@googlemail.com"
|
14
|
+
gem.files = FileList['[A-Z]*', '{lib,spec}/**/*', '.gitignore']
|
15
|
+
gem.has_rdoc = true
|
16
|
+
gem.rdoc_options = "--charset=UTF-8"
|
16
17
|
end
|
17
18
|
rescue LoadError
|
18
19
|
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
@@ -32,7 +33,7 @@ Spec::Rake::SpecTask.new(:fcsv) do |spec|
|
|
32
33
|
spec.spec_opts = ['--colour --format nested']
|
33
34
|
end
|
34
35
|
|
35
|
-
Rake::RDocTask.new(:
|
36
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
36
37
|
if File.exist?('VERSION.yml')
|
37
38
|
config = YAML.load(File.read('VERSION.yml'))
|
38
39
|
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
@@ -40,8 +41,8 @@ Rake::RDocTask.new(:doc) do |doc|
|
|
40
41
|
version = ""
|
41
42
|
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
rdoc.rdoc_dir = 'rdoc'
|
45
|
+
rdoc.title = "ChessIcu #{version}"
|
46
|
+
rdoc.rdoc_files.include('README*')
|
47
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
48
|
end
|
data/VERSION.yml
CHANGED
data/lib/chess_icu.rb
CHANGED
data/lib/name.rb
CHANGED
@@ -1,4 +1,58 @@
|
|
1
1
|
module ICU
|
2
|
+
|
3
|
+
=begin rdoc
|
4
|
+
|
5
|
+
== Names
|
6
|
+
|
7
|
+
This class exists for two main reasons:
|
8
|
+
|
9
|
+
* to normalise to a common format the different ways names are typed in practice
|
10
|
+
* to be able to match two names even if they are not exactly the same
|
11
|
+
|
12
|
+
To create a name object, supply both the first and second names separately to the constructor.
|
13
|
+
|
14
|
+
robert = ICU::Name.new(' robert j ', ' FISHER ')
|
15
|
+
|
16
|
+
Capitalisation, white space and punctuation will all be automatically corrected:
|
17
|
+
|
18
|
+
robert.name # => 'Robert J. Fischer'
|
19
|
+
robert.rname # => 'Fischer, Robert J.' (reversed name)
|
20
|
+
|
21
|
+
To avoid ambiguity when either the first or second names consist of multiple words, it is better to
|
22
|
+
supply the two separately, if known. However, the full name can be supplied alone to the constructor
|
23
|
+
and a guess will be made as to the first and last names.
|
24
|
+
|
25
|
+
bobby = ICU::Name.new(' bobby fischer ')
|
26
|
+
|
27
|
+
bobby.first # => 'Bobby'
|
28
|
+
bobby.last # => 'Fischer'
|
29
|
+
|
30
|
+
Names will match even if one is missing middle initials or if a nickname is used for one of the first names.
|
31
|
+
|
32
|
+
bobby.match(robert) # => true
|
33
|
+
|
34
|
+
Note that the class is aware of only common nicknames (e.g. _Bobby_ and _Robert_, _Bill_ and _William_, etc), not all possibilities.
|
35
|
+
|
36
|
+
Supplying the _match_ method with strings is equivalent to instantiating a Name instance with the same
|
37
|
+
strings and then matching it. So, for example the following are equivalent:
|
38
|
+
|
39
|
+
robert.match('R. J.', 'Fischer') # => true
|
40
|
+
robert.match(ICU::Name('R. J.', 'Fischer')) # => true
|
41
|
+
|
42
|
+
In those examples, the inital _R_ matches the first letter of _Robert_. However, nickname matches will not
|
43
|
+
always work with initials. In the next example, the initial _R_ does not match the first letter _B_ of the
|
44
|
+
nickname _Bobby_.
|
45
|
+
|
46
|
+
bobby.match('R. J.', 'Fischer') # => false
|
47
|
+
|
48
|
+
Some of the ways last names are canonicalised are illustrated below:
|
49
|
+
|
50
|
+
ICU::Name.new('John', 'O Reilly').last # => "O'Reilly"
|
51
|
+
ICU::Name.new('dave', 'mcmanus').last # => "McManus"
|
52
|
+
ICU::Name.new('pete', 'MACMANUS').last # => "MacManus"
|
53
|
+
|
54
|
+
=end
|
55
|
+
|
2
56
|
class Name
|
3
57
|
attr_reader :first, :last
|
4
58
|
|
@@ -206,6 +260,7 @@ Patrick Pat Paddy
|
|
206
260
|
Peter Pete
|
207
261
|
Philippe Philip Phillippe Phillip
|
208
262
|
Rick Ricky
|
263
|
+
Robert Bob Bobby
|
209
264
|
Samual Sam Samuel
|
210
265
|
Stefanie Stef
|
211
266
|
Stephen Steven Steve
|
data/lib/result.rb
CHANGED
@@ -1,5 +1,82 @@
|
|
1
1
|
module ICU
|
2
|
+
|
3
|
+
=begin rdoc
|
4
|
+
|
5
|
+
== Result
|
6
|
+
|
7
|
+
A result is the outcome of a game from the perspective of one of the players.
|
8
|
+
If the game was not a bye or a walkover and involved a second player, then
|
9
|
+
that second player will also have a result for the same game, and the two
|
10
|
+
results will be mirror images of each other.
|
11
|
+
|
12
|
+
A result always involves a round number, a player number and a score, so these
|
13
|
+
three attributes must be supplied in the constructor.
|
14
|
+
|
15
|
+
result = ICU::Result.new(2, 10, 'W')
|
16
|
+
|
17
|
+
The above example represents player 10 winning in round 2. As it stands, it represends
|
18
|
+
a bye or walkover since there is no opponent. Without an opponent it is unrateable.
|
19
|
+
|
20
|
+
result.rateable # => false
|
21
|
+
|
22
|
+
We can fill in opponent details as follows:
|
23
|
+
|
24
|
+
result.opponent = 13
|
25
|
+
result.colour = 'B'
|
26
|
+
|
27
|
+
Specifying an opponent via a setter always makes a result rateable.
|
28
|
+
|
29
|
+
result.rateable # => true
|
30
|
+
|
31
|
+
This result now represents a win with the black pieces over player number 13 in round 2.
|
32
|
+
Alternatively, all this could have been specified in the constructor.
|
33
|
+
|
34
|
+
result = ICU::Result.new(2, 10, 'W', :opponent => 13, :colour => 'B')
|
35
|
+
|
36
|
+
To make a game unratable, even it involves an opponent, set the _rateable_ atribute explicity:
|
37
|
+
|
38
|
+
result.rateable = false
|
39
|
+
|
40
|
+
or include it in the constructor:
|
41
|
+
|
42
|
+
result = ICU::Result.new(2, 10, 'W', :opponent => 13, :colour => 'B', :rateable => false)
|
43
|
+
|
44
|
+
The result of the same game from the perspective of an opponent is:
|
45
|
+
|
46
|
+
tluser = result.reverse
|
47
|
+
|
48
|
+
which, with the above example, would be:
|
49
|
+
|
50
|
+
tluser.player # => 13
|
51
|
+
tluser.opponent # => 10
|
52
|
+
tluser.score # => 'L'
|
53
|
+
tluser.colour # => 'B'
|
54
|
+
tluser.round # => 2
|
55
|
+
|
56
|
+
The reversed result will copy the _rateable_ attribute of the original unless an
|
57
|
+
explicit override is supplied.
|
58
|
+
|
59
|
+
result.rateable # => true
|
60
|
+
result.reverse.rateable # => true (copied from original)
|
61
|
+
result.reverse(false).rateable # => false (overriden)
|
62
|
+
|
63
|
+
A result which has no opponent is not reversible (the _reverse_ method returns _nil_).
|
64
|
+
|
65
|
+
The return value from the _score_ method is always one of _W_, _L_ or _D_. However,
|
66
|
+
when setting the score, a certain amount of variation is permitted as long as it is
|
67
|
+
clear what is meant. For eample, the following would all be converted to _D_:
|
68
|
+
|
69
|
+
result.score = ' D '
|
70
|
+
result.score = 'd'
|
71
|
+
result.score = '='
|
72
|
+
result.score = '0.5'
|
73
|
+
|
74
|
+
The _points_ read-only accessor always returns a floating point number, either 0.0, 0.5 or 1.0.
|
75
|
+
|
76
|
+
=end
|
77
|
+
|
2
78
|
class Result
|
79
|
+
|
3
80
|
attr_reader :round, :player, :score, :colour, :opponent, :rateable
|
4
81
|
|
5
82
|
# Constructor. Round number, player number and score must be supplied.
|
@@ -76,7 +153,7 @@ module ICU
|
|
76
153
|
return
|
77
154
|
end
|
78
155
|
@rateable = case rateable
|
79
|
-
when nil then true # default
|
156
|
+
when nil then true # default is true
|
80
157
|
when false then false # this is the only way to turn it off
|
81
158
|
else true
|
82
159
|
end
|
data/lib/util.rb
CHANGED
@@ -1,6 +1,17 @@
|
|
1
1
|
module ICU
|
2
2
|
class Util
|
3
|
-
|
3
|
+
|
4
|
+
=begin rdoc
|
5
|
+
|
6
|
+
Parse dates into yyyy-mm-dd format, preferring European over US convention. Return nil on error.
|
7
|
+
|
8
|
+
Util.parsedate('1955-11-09') # => '1955-11-09'
|
9
|
+
Util.parsedate('02/03/2009') # => '2009-03-02'
|
10
|
+
Util.parsedate('02/23/2009') # => '2009-02-23'
|
11
|
+
Util.parsedate('16th June 1986') # => '1986-06-16'
|
12
|
+
|
13
|
+
=end
|
14
|
+
|
4
15
|
def self.parsedate(date)
|
5
16
|
date = date.to_s
|
6
17
|
return nil unless date.match(/[1-9]/)
|
data/spec/name_spec.rb
CHANGED
@@ -33,6 +33,34 @@ module ICU
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
context "rdoc expample" do
|
37
|
+
before(:each) do
|
38
|
+
@robert = Name.new(' robert j ', ' FISCHER ')
|
39
|
+
@bobby = Name.new(' bobby fischer ')
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should get Robert" do
|
43
|
+
@robert.name.should == 'Robert J. Fischer'
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should get Bobby" do
|
47
|
+
@bobby.last.should == 'Fischer'
|
48
|
+
@bobby.first.should == 'Bobby'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should match Robert and Bobby" do
|
52
|
+
@robert.match(@bobby).should be_true
|
53
|
+
@robert.match('R. J.', 'Fischer').should be_true
|
54
|
+
@bobby.match('R. J.', 'Fischer').should be_false
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should canconicalise last names" do
|
58
|
+
Name.new('John', 'O Reilly').last.should == "O'Reilly"
|
59
|
+
Name.new('dave', 'mcmanus').last.should == "McManus"
|
60
|
+
Name.new('pete', 'MACMANUS').last.should == "MacManus"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
36
64
|
context "names that are already canonical" do
|
37
65
|
it "should not be altered" do
|
38
66
|
Name.new('Mark J. L.', 'Orr').name.should == 'Mark J. L. Orr'
|
@@ -81,10 +109,18 @@ module ICU
|
|
81
109
|
end
|
82
110
|
|
83
111
|
context "construction from a single string" do
|
112
|
+
before(:each) do
|
113
|
+
@mark1 = Name.new('ORR, mark j l')
|
114
|
+
@mark2 = Name.new('MARK J L ORR')
|
115
|
+
@oreil = Name.new("O'Reilly, j-k")
|
116
|
+
end
|
117
|
+
|
84
118
|
it "should be possible in simple cases" do
|
85
|
-
|
86
|
-
|
87
|
-
|
119
|
+
@mark1.first.should == 'Mark J. L.'
|
120
|
+
@mark1.last.should == 'Orr'
|
121
|
+
@mark2.first.should == 'Mark J. L.'
|
122
|
+
@mark2.last.should == 'Orr'
|
123
|
+
@oreil.name.should == "J.-K. O'Reilly"
|
88
124
|
end
|
89
125
|
end
|
90
126
|
|
data/spec/util_spec.rb
CHANGED
@@ -20,6 +20,10 @@ module ICU
|
|
20
20
|
Util.parsedate('02/03/2009').should == '2009-03-02'
|
21
21
|
end
|
22
22
|
|
23
|
+
it "should handle US style when there's no alternative" do
|
24
|
+
Util.parsedate('02/23/2009').should == '2009-02-23'
|
25
|
+
end
|
26
|
+
|
23
27
|
it "should handle single digits" do
|
24
28
|
Util.parsedate('9/8/2006').should == '2006-08-09'
|
25
29
|
end
|