sportdb-formats 1.0.6 → 1.1.4
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.
- checksums.yaml +4 -4
- data/Manifest.txt +6 -33
- data/Rakefile +2 -5
- data/lib/sportdb/formats.rb +54 -70
- data/lib/sportdb/formats/country/country_index.rb +2 -2
- data/lib/sportdb/formats/event/event_index.rb +141 -0
- data/lib/sportdb/formats/event/event_reader.rb +183 -0
- data/lib/sportdb/formats/league/league_index.rb +22 -18
- data/lib/sportdb/formats/league/league_outline_reader.rb +45 -13
- data/lib/sportdb/formats/league/league_reader.rb +7 -1
- data/lib/sportdb/formats/match/match_parser.rb +101 -111
- data/lib/sportdb/formats/package.rb +59 -11
- data/lib/sportdb/formats/parser_helper.rb +11 -2
- data/lib/sportdb/formats/team/club_index.rb +13 -11
- data/lib/sportdb/formats/team/club_index_history.rb +134 -0
- data/lib/sportdb/formats/team/club_reader_history.rb +203 -0
- data/lib/sportdb/formats/team/club_reader_props.rb +20 -5
- data/lib/sportdb/formats/version.rb +2 -2
- data/test/helper.rb +51 -81
- data/test/test_club_index_history.rb +107 -0
- data/test/test_club_reader_history.rb +212 -0
- data/test/test_datafile_package.rb +1 -1
- data/test/test_regex.rb +25 -7
- metadata +9 -78
- data/lib/sportdb/formats/config.rb +0 -40
- data/lib/sportdb/formats/match/match_parser_csv.rb +0 -314
- data/lib/sportdb/formats/name_helper.rb +0 -84
- data/lib/sportdb/formats/score/score_formats.rb +0 -220
- data/lib/sportdb/formats/score/score_parser.rb +0 -202
- data/lib/sportdb/formats/season_utils.rb +0 -27
- data/lib/sportdb/formats/structs/country.rb +0 -31
- data/lib/sportdb/formats/structs/group.rb +0 -18
- data/lib/sportdb/formats/structs/league.rb +0 -37
- data/lib/sportdb/formats/structs/match.rb +0 -151
- data/lib/sportdb/formats/structs/matchlist.rb +0 -220
- data/lib/sportdb/formats/structs/round.rb +0 -25
- data/lib/sportdb/formats/structs/season.rb +0 -123
- data/lib/sportdb/formats/structs/standings.rb +0 -247
- data/lib/sportdb/formats/structs/team.rb +0 -150
- data/lib/sportdb/formats/structs/team_usage.rb +0 -88
- data/test/test_clubs.rb +0 -40
- data/test/test_conf.rb +0 -65
- data/test/test_csv_match_parser.rb +0 -114
- data/test/test_csv_match_parser_utils.rb +0 -20
- data/test/test_csv_reader.rb +0 -31
- data/test/test_match.rb +0 -30
- data/test/test_match_auto.rb +0 -72
- data/test/test_match_auto_champs.rb +0 -45
- data/test/test_match_auto_euro.rb +0 -37
- data/test/test_match_auto_worldcup.rb +0 -61
- data/test/test_match_champs.rb +0 -27
- data/test/test_match_eng.rb +0 -26
- data/test/test_match_euro.rb +0 -27
- data/test/test_match_worldcup.rb +0 -27
- data/test/test_name_helper.rb +0 -67
- data/test/test_scores.rb +0 -122
- data/test/test_season.rb +0 -62
@@ -1,25 +0,0 @@
|
|
1
|
-
module SportDb
|
2
|
-
module Import
|
3
|
-
|
4
|
-
class Round
|
5
|
-
attr_reader :name, :start_date, :end_date, :knockout
|
6
|
-
attr_accessor :num # note: make read & writable - why? why not?
|
7
|
-
|
8
|
-
def initialize( name:,
|
9
|
-
num: nil,
|
10
|
-
start_date: nil,
|
11
|
-
end_date: nil,
|
12
|
-
knockout: false,
|
13
|
-
auto: true )
|
14
|
-
@name = name
|
15
|
-
@num = num
|
16
|
-
@start_date = start_date
|
17
|
-
@end_date = end_date
|
18
|
-
@knockout = knockout
|
19
|
-
@auto = auto # auto-created (inline reference/header without proper definition before)
|
20
|
-
end
|
21
|
-
end # class Round
|
22
|
-
|
23
|
-
end # module Import
|
24
|
-
end # module SportDb
|
25
|
-
|
@@ -1,123 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
|
4
|
-
module SportDb
|
5
|
-
module Import
|
6
|
-
|
7
|
-
|
8
|
-
class Season
|
9
|
-
##
|
10
|
-
## todo: add (optional) start_date and end_date - why? why not?
|
11
|
-
## add next
|
12
|
-
|
13
|
-
|
14
|
-
attr_reader :start_year,
|
15
|
-
:end_year
|
16
|
-
|
17
|
-
def year?() @end_year.nil?; end ## single-year season e.g. 2011 if no end_year present
|
18
|
-
|
19
|
-
|
20
|
-
def initialize( str ) ## assume only string / line gets passed in for now
|
21
|
-
@start_year, @end_year = parse( str )
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
YYYY_YYYY_RE = %r{^ ## e.g. 2011-2012 or 2011/2012
|
26
|
-
(\d{4})
|
27
|
-
[/-]
|
28
|
-
(\d{4})
|
29
|
-
$
|
30
|
-
}x
|
31
|
-
YYYY_YY_RE = %r{^ ## e.g. 2011-12 or 2011/12
|
32
|
-
(\d{4})
|
33
|
-
[/-]
|
34
|
-
(\d{2})
|
35
|
-
$
|
36
|
-
}x
|
37
|
-
YYYY_Y_RE = %r{^ ## e.g. 2011-2 or 2011/2
|
38
|
-
(\d{4})
|
39
|
-
[/-]
|
40
|
-
(\d{1})
|
41
|
-
$
|
42
|
-
}x
|
43
|
-
YYYY_RE = %r{^ ## e.g. 2011
|
44
|
-
(\d{4})
|
45
|
-
$
|
46
|
-
}x
|
47
|
-
|
48
|
-
def parse( str )
|
49
|
-
if str =~ YYYY_YYYY_RE ## e.g. 2011/2012
|
50
|
-
[$1.to_i, $2.to_i]
|
51
|
-
elsif str =~ YYYY_YY_RE ## e.g. 2011/12
|
52
|
-
fst = $1.to_i
|
53
|
-
snd = $2.to_i
|
54
|
-
snd_exp = '%02d' % [(fst+1) % 100] ## double check: e.g 00 == 00, 01==01 etc.
|
55
|
-
raise ArgumentError.new( "[Season#parse] invalid year in season >>#{str}<<; expected #{snd_exp} but got #{$2}") if snd_exp != $2
|
56
|
-
[fst, fst+1]
|
57
|
-
elsif str =~ YYYY_Y_RE ## e.g. 2011/2
|
58
|
-
fst = $1.to_i
|
59
|
-
snd = $2.to_i
|
60
|
-
snd_exp = '%d' % [(fst+1) % 10] ## double check: e.g 0 == 0, 1==1 etc.
|
61
|
-
raise ArgumentError.new( "[Season#parse] invalid year in season >>#{str}<<; expected #{snd_exp} but got #{$2}") if snd_exp != $2
|
62
|
-
[fst, fst+1]
|
63
|
-
elsif str =~ YYYY_RE ## e.g. 2011
|
64
|
-
[$1.to_i]
|
65
|
-
else
|
66
|
-
raise ArgumentError.new( "[Season#parse] unkown season format >>#{str}<<; sorry cannot parse")
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
def prev
|
73
|
-
if year?
|
74
|
-
Season.new( "#{@start_year-1}" )
|
75
|
-
else
|
76
|
-
Season.new( "#{@start_year-1}/#{@start_year}" )
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def key
|
81
|
-
if year?
|
82
|
-
'%d' % @start_year
|
83
|
-
else
|
84
|
-
'%d/%02d' % [@start_year, @end_year % 100]
|
85
|
-
end
|
86
|
-
end
|
87
|
-
alias_method :to_key, :key
|
88
|
-
alias_method :to_s, :key
|
89
|
-
|
90
|
-
alias_method :name, :key
|
91
|
-
alias_method :title, :key
|
92
|
-
|
93
|
-
|
94
|
-
def path( format: nil )
|
95
|
-
## todo: find better names for formats - why? why not?:
|
96
|
-
## long | archive | decade(?) => 1980s/1988-89, 2010s/2017-18, ...
|
97
|
-
## short | std(?) => 1988-89, 2017-18, ...
|
98
|
-
|
99
|
-
## convert season name to "standard" season name for directory
|
100
|
-
|
101
|
-
if ['l', 'long', 'archive' ].include?( format.to_s ) ## note: allow passing in of symbol to e.g. 'long' or :long
|
102
|
-
if year? ## e.g. 2000s/2001
|
103
|
-
"%3d0s/%4d" % [@start_year / 10, @start_year]
|
104
|
-
else ## e.g. 2000s/2001-02
|
105
|
-
"%3d0s/%4d-%02d" % [@start_year / 10, @start_year, @end_year % 100]
|
106
|
-
end
|
107
|
-
else ## default 'short' format / fallback
|
108
|
-
if year? ## e.g. 2001
|
109
|
-
"%4d" % @start_year
|
110
|
-
else ## e.g. 2001-02
|
111
|
-
"%4d-%02d" % [@start_year, @end_year % 100]
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end # method path
|
115
|
-
alias_method :directory, :path ## keep "legacy" directory alias - why? why not?
|
116
|
-
alias_method :to_path, :path
|
117
|
-
|
118
|
-
|
119
|
-
end # class Season
|
120
|
-
|
121
|
-
|
122
|
-
end # module Import
|
123
|
-
end # module SportDb
|
@@ -1,247 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
##########
|
4
|
-
# todo/fix:
|
5
|
-
## reuse standings helper/calculator from sportdb
|
6
|
-
## do NOT duplicate
|
7
|
-
|
8
|
-
|
9
|
-
module SportDb
|
10
|
-
module Import
|
11
|
-
|
12
|
-
|
13
|
-
class Standings
|
14
|
-
|
15
|
-
class StandingsLine ## nested class StandinsLine
|
16
|
-
attr_accessor :rank, :team,
|
17
|
-
:played, :won, :lost, :drawn, ## -- total
|
18
|
-
:goals_for, :goals_against, :pts,
|
19
|
-
:home_played, :home_won, :home_lost, :home_drawn, ## -- home
|
20
|
-
:home_goals_for, :home_goals_against, :home_pts,
|
21
|
-
:away_played, :away_won, :away_lost, :away_drawn, ## -- away
|
22
|
-
:away_goals_for, :away_goals_against, :away_pts
|
23
|
-
|
24
|
-
def initialize( team )
|
25
|
-
@rank = nil # use 0? why? why not?
|
26
|
-
@team = team
|
27
|
-
@played = @home_played = @away_played = 0
|
28
|
-
@won = @home_won = @away_won = 0
|
29
|
-
@lost = @home_lost = @away_lost = 0
|
30
|
-
@drawn = @home_drawn = @away_drawn = 0
|
31
|
-
@goals_for = @home_goals_for = @away_goals_for = 0
|
32
|
-
@goals_against = @home_goals_against = @away_goals_against = 0
|
33
|
-
@pts = @home_pts = @away_pts = 0
|
34
|
-
end
|
35
|
-
end # (nested) class StandingsLine
|
36
|
-
|
37
|
-
|
38
|
-
def initialize( opts={} )
|
39
|
-
## fix:
|
40
|
-
# passing in e.g. pts for win (3? 2? etc.)
|
41
|
-
# default to 3 for now
|
42
|
-
|
43
|
-
## lets you pass in 2 as an alterantive, for example
|
44
|
-
@pts_won = opts[:pts_won] || 3
|
45
|
-
|
46
|
-
@lines = {} # StandingsLines cached by team name/key
|
47
|
-
end
|
48
|
-
|
49
|
-
|
50
|
-
def update( match_or_matches )
|
51
|
-
## convenience - update all matches at once
|
52
|
-
matches = match_or_matches.is_a?(Array) ? match_or_matches : [match_or_matches]
|
53
|
-
|
54
|
-
matches.each_with_index do |match,i| # note: index(i) starts w/ zero (0)
|
55
|
-
update_match( match )
|
56
|
-
end
|
57
|
-
self # note: return self to allow chaining
|
58
|
-
end
|
59
|
-
|
60
|
-
|
61
|
-
def to_a
|
62
|
-
## return lines; sort and add rank
|
63
|
-
## note: will update rank!!!! (side effect)
|
64
|
-
|
65
|
-
#############################
|
66
|
-
### calc ranking position (rank)
|
67
|
-
## fix/allow same rank e.g. all 1 or more than one team 3rd etc.
|
68
|
-
|
69
|
-
# build array from hash
|
70
|
-
ary = []
|
71
|
-
@lines.each do |k,v|
|
72
|
-
ary << v
|
73
|
-
end
|
74
|
-
|
75
|
-
ary.sort! do |l,r|
|
76
|
-
## note: reverse order (thus, change l,r to r,l)
|
77
|
-
value = r.pts <=> l.pts
|
78
|
-
if value == 0 # same pts try goal diff
|
79
|
-
value = (r.goals_for-r.goals_against) <=> (l.goals_for-l.goals_against)
|
80
|
-
if value == 0 # same goal diff too; try assume more goals better for now
|
81
|
-
value = r.goals_for <=> l.goals_for
|
82
|
-
end
|
83
|
-
end
|
84
|
-
value
|
85
|
-
end
|
86
|
-
|
87
|
-
## update rank using ordered array
|
88
|
-
ary.each_with_index do |line,i|
|
89
|
-
line.rank = i+1 ## add ranking (e.g. 1,2,3 etc.) - note: i starts w/ zero (0)
|
90
|
-
end
|
91
|
-
|
92
|
-
ary
|
93
|
-
end # to_a
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
#####
|
98
|
-
###
|
99
|
-
## fix: move build to StandingsPart/Report !!!!
|
100
|
-
def build( source: nil ) ## build / pretty print standings table in string buffer
|
101
|
-
## keep pretty printer in struct - why? why not?
|
102
|
-
|
103
|
-
|
104
|
-
## add standings table in markdown to buffer (buf)
|
105
|
-
|
106
|
-
## todo: use different styles/formats (simple/ etc ???)
|
107
|
-
|
108
|
-
## simple table (only totals - no home/away)
|
109
|
-
## standings.to_a.each do |l|
|
110
|
-
## buf << '%2d. ' % l.rank
|
111
|
-
## buf << '%-28s ' % l.team
|
112
|
-
## buf << '%2d ' % l.played
|
113
|
-
## buf << '%3d ' % l.won
|
114
|
-
## buf << '%3d ' % l.drawn
|
115
|
-
## buf << '%3d ' % l.lost
|
116
|
-
## buf << '%3d:%-3d ' % [l.goals_for,l.goals_against]
|
117
|
-
## buf << '%3d' % l.pts
|
118
|
-
## buf << "\n"
|
119
|
-
## end
|
120
|
-
|
121
|
-
buf = ''
|
122
|
-
buf << "\n"
|
123
|
-
buf << "```\n"
|
124
|
-
buf << " - Home - - Away - - Total -\n"
|
125
|
-
buf << " Pld W D L F:A W D L F:A F:A +/- Pts\n"
|
126
|
-
|
127
|
-
to_a.each do |l|
|
128
|
-
buf << '%2d. ' % l.rank
|
129
|
-
buf << '%-28s ' % l.team
|
130
|
-
buf << '%2d ' % l.played
|
131
|
-
|
132
|
-
buf << '%2d ' % l.home_won
|
133
|
-
buf << '%2d ' % l.home_drawn
|
134
|
-
buf << '%2d ' % l.home_lost
|
135
|
-
buf << '%3d:%-3d ' % [l.home_goals_for,l.home_goals_against]
|
136
|
-
|
137
|
-
buf << '%2d ' % l.away_won
|
138
|
-
buf << '%2d ' % l.away_drawn
|
139
|
-
buf << '%2d ' % l.away_lost
|
140
|
-
buf << '%3d:%-3d ' % [l.away_goals_for,l.away_goals_against]
|
141
|
-
|
142
|
-
buf << '%3d:%-3d ' % [l.goals_for,l.goals_against]
|
143
|
-
|
144
|
-
goals_diff = l.goals_for-l.goals_against
|
145
|
-
if goals_diff > 0
|
146
|
-
buf << '%3s ' % "+#{goals_diff}"
|
147
|
-
elsif goals_diff < 0
|
148
|
-
buf << '%3s ' % "#{goals_diff}"
|
149
|
-
else ## assume 0
|
150
|
-
buf << ' '
|
151
|
-
end
|
152
|
-
|
153
|
-
buf << '%3d' % l.pts
|
154
|
-
buf << "\n"
|
155
|
-
end
|
156
|
-
|
157
|
-
buf << "```\n"
|
158
|
-
buf << "\n"
|
159
|
-
|
160
|
-
## optinal: add data source if known / present
|
161
|
-
## assume (relative) markdown link for now in README.md
|
162
|
-
if source
|
163
|
-
buf << "(Source: [`#{source}`](#{source}))\n"
|
164
|
-
buf << "\n"
|
165
|
-
end
|
166
|
-
|
167
|
-
buf
|
168
|
-
end
|
169
|
-
|
170
|
-
|
171
|
-
private
|
172
|
-
def update_match( m ) ## add a match
|
173
|
-
|
174
|
-
## puts " #{m.team1} - #{m.team2} #{m.score_str}"
|
175
|
-
unless m.over?
|
176
|
-
puts " !!!! skipping match - not yet over (play_at date in the future)"
|
177
|
-
return
|
178
|
-
end
|
179
|
-
|
180
|
-
unless m.complete?
|
181
|
-
puts "!!! [calc_standings] skipping match #{m.team1} - #{m.team2} - scores incomplete #{m.score_str}"
|
182
|
-
return
|
183
|
-
end
|
184
|
-
|
185
|
-
line1 = @lines[ m.team1 ] || StandingsLine.new( m.team1 )
|
186
|
-
line2 = @lines[ m.team2 ] || StandingsLine.new( m.team2 )
|
187
|
-
|
188
|
-
line1.played += 1
|
189
|
-
line1.home_played += 1
|
190
|
-
|
191
|
-
line2.played += 1
|
192
|
-
line2.away_played += 1
|
193
|
-
|
194
|
-
if m.winner == 1
|
195
|
-
line1.won += 1
|
196
|
-
line1.home_won += 1
|
197
|
-
|
198
|
-
line2.lost += 1
|
199
|
-
line2.away_lost += 1
|
200
|
-
|
201
|
-
line1.pts += @pts_won
|
202
|
-
line1.home_pts += @pts_won
|
203
|
-
elsif m.winner == 2
|
204
|
-
line1.lost += 1
|
205
|
-
line1.home_lost += 1
|
206
|
-
|
207
|
-
line2.won += 1
|
208
|
-
line2.away_won += 1
|
209
|
-
|
210
|
-
line2.pts += @pts_won
|
211
|
-
line2.away_pts += @pts_won
|
212
|
-
else ## assume drawn/tie (that is, 0)
|
213
|
-
line1.drawn += 1
|
214
|
-
line1.home_drawn += 1
|
215
|
-
|
216
|
-
line2.drawn += 1
|
217
|
-
line2.away_drawn += 1
|
218
|
-
|
219
|
-
line1.pts += 1
|
220
|
-
line1.home_pts += 1
|
221
|
-
line2.pts += 1
|
222
|
-
line2.away_pts += 1
|
223
|
-
end
|
224
|
-
|
225
|
-
if m.score1 && m.score2
|
226
|
-
line1.goals_for += m.score1
|
227
|
-
line1.home_goals_for += m.score1
|
228
|
-
line1.goals_against += m.score2
|
229
|
-
line1.home_goals_against += m.score2
|
230
|
-
|
231
|
-
line2.goals_for += m.score2
|
232
|
-
line2.away_goals_for += m.score2
|
233
|
-
line2.goals_against += m.score1
|
234
|
-
line2.away_goals_against += m.score1
|
235
|
-
else
|
236
|
-
puts "*** warn: [standings] skipping match with missing scores: #{m.inspect}"
|
237
|
-
end
|
238
|
-
|
239
|
-
@lines[ m.team1 ] = line1
|
240
|
-
@lines[ m.team2 ] = line2
|
241
|
-
end # method update_match
|
242
|
-
|
243
|
-
end # class Standings
|
244
|
-
|
245
|
-
|
246
|
-
end # module Import
|
247
|
-
end # module SportDb
|
@@ -1,150 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module SportDb
|
4
|
-
module Import
|
5
|
-
|
6
|
-
|
7
|
-
##
|
8
|
-
## todo/fix: remove self.create in structs!!! use just new!!!
|
9
|
-
|
10
|
-
class Team
|
11
|
-
## todo: use just names for alt_names - why? why not?
|
12
|
-
attr_accessor :key, :name, :alt_names,
|
13
|
-
:code, ## code == abbreviation e.g. ARS etc.
|
14
|
-
:year, :year_end, ## todo/fix: change year to start_year and year_end to end_year (like in season)!!!
|
15
|
-
:country
|
16
|
-
|
17
|
-
|
18
|
-
def names
|
19
|
-
## todo/check: add alt_names_auto too? - why? why not?
|
20
|
-
[@name] + @alt_names
|
21
|
-
end ## all names
|
22
|
-
|
23
|
-
def key
|
24
|
-
## note: auto-generate key "on-the-fly" if missing for now - why? why not?
|
25
|
-
## note: quick hack - auto-generate key, that is, remove all non-ascii chars and downcase
|
26
|
-
@key || @name.downcase.gsub( /[^a-z]/, '' )
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
## special import only attribs
|
31
|
-
attr_accessor :alt_names_auto ## auto-generated alt names
|
32
|
-
attr_accessor :wikipedia # wikipedia page name (for english (en))
|
33
|
-
|
34
|
-
|
35
|
-
def historic?() @year_end ? true : false; end
|
36
|
-
alias_method :past?, :historic?
|
37
|
-
|
38
|
-
def wikipedia?() @wikipedia; end
|
39
|
-
def wikipedia_url
|
40
|
-
if @wikipedia
|
41
|
-
## note: replace spaces with underscore (-)
|
42
|
-
## e.g. Club Brugge KV => Club_Brugge_KV
|
43
|
-
## todo/check/fix:
|
44
|
-
## check if "plain" dash (-) needs to get replaced with typographic dash??
|
45
|
-
"https://en.wikipedia.org/wiki/#{@wikipedia.gsub(' ','_')}"
|
46
|
-
else
|
47
|
-
nil
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
|
52
|
-
def initialize( **kwargs )
|
53
|
-
@alt_names = []
|
54
|
-
@alt_names_auto = []
|
55
|
-
|
56
|
-
update( kwargs ) unless kwargs.empty?
|
57
|
-
end
|
58
|
-
|
59
|
-
def update( **kwargs )
|
60
|
-
@key = kwargs[:key] if kwargs.has_key? :key
|
61
|
-
@name = kwargs[:name] if kwargs.has_key? :name
|
62
|
-
@code = kwargs[:code] if kwargs.has_key? :code
|
63
|
-
@alt_names = kwargs[:alt_names] if kwargs.has_key? :alt_names
|
64
|
-
self ## note - MUST return self for chaining
|
65
|
-
end
|
66
|
-
|
67
|
-
|
68
|
-
## helper methods for import only
|
69
|
-
## check for duplicates
|
70
|
-
include NameHelper
|
71
|
-
|
72
|
-
def duplicates?
|
73
|
-
names = [name] + alt_names + alt_names_auto
|
74
|
-
names = names.map { |name| normalize( sanitize(name) ) }
|
75
|
-
|
76
|
-
names.size != names.uniq.size
|
77
|
-
end
|
78
|
-
|
79
|
-
def duplicates
|
80
|
-
names = [name] + alt_names + alt_names_auto
|
81
|
-
|
82
|
-
## calculate (count) frequency and select if greater than one
|
83
|
-
names.reduce( {} ) do |h,name|
|
84
|
-
norm = normalize( sanitize(name) )
|
85
|
-
h[norm] ||= []
|
86
|
-
h[norm] << name; h
|
87
|
-
end.select { |norm,names| names.size > 1 }
|
88
|
-
end
|
89
|
-
|
90
|
-
|
91
|
-
def add_variants( name_or_names )
|
92
|
-
names = name_or_names.is_a?(Array) ? name_or_names : [name_or_names]
|
93
|
-
names.each do |name|
|
94
|
-
name = sanitize( name )
|
95
|
-
self.alt_names_auto += variants( name )
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end # class Team
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
class NationalTeam < Team
|
103
|
-
def initialize( **kwargs )
|
104
|
-
super
|
105
|
-
end
|
106
|
-
|
107
|
-
def update( **kwargs )
|
108
|
-
super
|
109
|
-
self ## note - MUST return self for chaining
|
110
|
-
end
|
111
|
-
|
112
|
-
end # class NationalTeam
|
113
|
-
|
114
|
-
|
115
|
-
########
|
116
|
-
# more attribs - todo/fix - also add "upstream" to struct & model!!!!!
|
117
|
-
# district, geos, year_end, country, etc.
|
118
|
-
|
119
|
-
class Club < Team
|
120
|
-
attr_accessor :ground
|
121
|
-
|
122
|
-
attr_accessor :a, :b
|
123
|
-
def a?() @a == nil; end ## is a (1st) team / club (i)? if a is NOT set
|
124
|
-
def b?() @a != nil; end ## is b (2nd/reserve/jr) team / club (ii) if a is set
|
125
|
-
|
126
|
-
## note: delegate/forward all geo attributes for team b for now (to team a) - keep - why? why not?
|
127
|
-
attr_writer :city, :district, :geos
|
128
|
-
def city() @a == nil ? @city : @a.city; end
|
129
|
-
def district() @a == nil ? @district : @a.district; end
|
130
|
-
def country() @a == nil ? @country : @a.country; end
|
131
|
-
def geos() @a == nil ? @geos : @a.geos; end
|
132
|
-
|
133
|
-
|
134
|
-
def initialize( **kwargs )
|
135
|
-
super
|
136
|
-
end
|
137
|
-
|
138
|
-
def update( **kwargs )
|
139
|
-
super
|
140
|
-
@city = kwargs[:city] if kwargs.has_key? :city
|
141
|
-
## todo/fix: use city struct - why? why not?
|
142
|
-
## todo/fix: add country too or report unused keywords / attributes - why? why not?
|
143
|
-
|
144
|
-
self ## note - MUST return self for chaining
|
145
|
-
end
|
146
|
-
end # class Club
|
147
|
-
|
148
|
-
|
149
|
-
end # module Import
|
150
|
-
end # module SportDb
|