sportdb-formats 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +5 -0
  3. data/Rakefile +2 -2
  4. data/lib/sportdb/formats.rb +17 -5
  5. data/lib/sportdb/formats/country/country_index.rb +7 -7
  6. data/lib/sportdb/formats/country/country_reader.rb +26 -6
  7. data/lib/sportdb/formats/datafile_package.rb +10 -7
  8. data/lib/sportdb/formats/league/league_outline_reader.rb +24 -7
  9. data/lib/sportdb/formats/league/league_reader.rb +3 -3
  10. data/lib/sportdb/formats/match/mapper.rb +63 -63
  11. data/lib/sportdb/formats/match/mapper_teams.rb +1 -1
  12. data/lib/sportdb/formats/match/match_parser.rb +99 -180
  13. data/lib/sportdb/formats/match/match_parser_csv.rb +321 -0
  14. data/lib/sportdb/formats/package.rb +165 -11
  15. data/lib/sportdb/formats/parser_helper.rb +11 -2
  16. data/lib/sportdb/formats/score/score_formats.rb +41 -1
  17. data/lib/sportdb/formats/score/score_parser.rb +6 -0
  18. data/lib/sportdb/formats/structs/country.rb +6 -3
  19. data/lib/sportdb/formats/structs/group.rb +5 -12
  20. data/lib/sportdb/formats/structs/round.rb +6 -13
  21. data/lib/sportdb/formats/structs/standings.rb +30 -9
  22. data/lib/sportdb/formats/structs/team.rb +1 -2
  23. data/lib/sportdb/formats/team/club_reader_props.rb +3 -3
  24. data/lib/sportdb/formats/version.rb +4 -2
  25. data/test/helper.rb +2 -1
  26. data/test/test_club_reader_props.rb +2 -2
  27. data/test/test_country_index.rb +4 -4
  28. data/test/test_country_reader.rb +34 -4
  29. data/test/test_csv_match_parser.rb +114 -0
  30. data/test/test_csv_match_parser_utils.rb +20 -0
  31. data/test/test_csv_reader.rb +5 -5
  32. data/test/test_datafile.rb +0 -32
  33. data/test/test_datafile_package.rb +46 -0
  34. data/test/test_match_auto_relegation.rb +41 -0
  35. data/test/test_package.rb +60 -28
  36. data/test/test_package_match.rb +27 -3
  37. data/test/test_regex.rb +25 -7
  38. data/test/test_scores.rb +58 -49
  39. metadata +9 -4
@@ -2,38 +2,79 @@
2
2
  module SportDb
3
3
  class Package
4
4
 
5
+ ## todo/fix: make all regexes case-insensitive with /i option - why? why not?
6
+ ## e.g. .TXT and .txt
7
+ ## yes!! use /i option!!!!!
8
+
5
9
  CONF_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
6
10
  \.conf\.txt$
7
11
  }x
8
12
 
13
+ ## leagues.txt or leagues_en.txt
14
+ ## remove support for en.leagues.txt - why? why not?
9
15
  LEAGUES_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
10
16
  (?: [a-z]{1,4}\. )? # optional country code/key e.g. eng.clubs.wiki.txt
11
- leagues\.txt$
17
+ leagues
18
+ (?:_[a-z0-9_-]+)?
19
+ \.txt$
12
20
  }x
13
21
 
22
+ ## clubs.txt or clubs_en.txt
23
+ ## remove support for en.clubs.txt - why? why not?
14
24
  CLUBS_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
15
25
  (?: [a-z]{1,4}\. )? # optional country code/key e.g. eng.clubs.txt
16
- clubs\.txt$
26
+ clubs
27
+ (?:_[a-z0-9_-]+)?
28
+ \.txt$
17
29
  }x
18
30
 
19
31
  CLUBS_WIKI_RE = %r{ (?:^|/) # beginning (^) or beginning of path (/)
20
32
  (?:[a-z]{1,4}\.)? # optional country code/key e.g. eng.clubs.wiki.txt
21
- clubs\.wiki\.txt$
33
+ clubs
34
+ (?:_[a-z0-9_-]+)?
35
+ \.wiki\.txt$
22
36
  }x
23
37
 
24
38
  CLUB_PROPS_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
25
39
  (?: [a-z]{1,4}\. )? # optional country code/key e.g. eng.clubs.props.txt
26
- clubs\.props\.txt$
40
+ clubs
41
+ (?:_[a-z0-9_-]+)?
42
+ \.props\.txt$
43
+ }x
44
+
45
+ ## teams.txt or teams_history.txt
46
+ TEAMS_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
47
+ teams
48
+ (?:_[a-z0-9_-]+)?
49
+ \.txt$
27
50
  }x
28
51
 
52
+ ### season folder:
53
+ ## e.g. /2019-20 or
54
+ ## year-only e.g. /2019 or
55
+ ## /2016--france
56
+ SEASON_RE = %r{ (?:
57
+ \d{4}-\d{2}
58
+ | \d{4}(--[a-z0-9_-]+)?
59
+ )
60
+ }x
61
+ SEASON = SEASON_RE.source ## "inline" helper for embedding in other regexes - keep? why? why not?
62
+
63
+
29
64
  ## note: if pattern includes directory add here
30
65
  ## (otherwise move to more "generic" datafile) - why? why not?
31
- MATCH_RE = %r{ /(?: \d{4}-\d{2} ## season folder e.g. /2019-20
32
- | \d{4}(--[^/]+)? ## season year-only folder e.g. /2019 or /2016--france
33
- )
34
- /[a-z0-9_-]+\.txt$ ## txt e.g /1-premierleague.txt
66
+ MATCH_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
67
+ #{SEASON}
68
+ /[a-z0-9_-]+\.txt$ ## txt e.g /1-premierleague.txt
35
69
  }x
36
70
 
71
+ MATCH_CSV_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
72
+ #{SEASON}
73
+ /[a-z0-9_.-]+\.csv$ ## note: allow dot (.) too e.g /eng.1.csv
74
+ }x
75
+
76
+
77
+
37
78
  ## move class-level "static" finders to DirPackage (do NOT work for now for zip packages) - why? why not?
38
79
 
39
80
  def self.find( path, pattern )
@@ -41,7 +82,7 @@ module SportDb
41
82
 
42
83
  ## check all txt files
43
84
  ## note: incl. files starting with dot (.)) as candidates (normally excluded with just *)
44
- candidates = Dir.glob( "#{path}/**/{*,.*}.txt" )
85
+ candidates = Dir.glob( "#{path}/**/{*,.*}.*" )
45
86
  pp candidates
46
87
  candidates.each do |candidate|
47
88
  datafiles << candidate if pattern.match( candidate )
@@ -52,6 +93,8 @@ module SportDb
52
93
  end
53
94
 
54
95
 
96
+ def self.find_teams( path, pattern: TEAMS_RE ) find( path, pattern ); end
97
+ def self.match_teams( path ) TEAMS_RE.match( path ); end
55
98
 
56
99
  def self.find_clubs( path, pattern: CLUBS_RE ) find( path, pattern ); end
57
100
  def self.find_clubs_wiki( path, pattern: CLUBS_WIKI_RE ) find( path, pattern ); end
@@ -66,7 +109,19 @@ module SportDb
66
109
  def self.find_conf( path, pattern: CONF_RE ) find( path, pattern ); end
67
110
  def self.match_conf( path ) CONF_RE.match( path ); end
68
111
 
112
+ def self.find_match( path, format: 'txt' )
113
+ if format == 'csv'
114
+ find( path, MATCH_CSV_RE )
115
+ else ## otherwise always assume txt for now
116
+ find( path, MATCH_RE )
117
+ end
118
+ end
119
+ ## add match_match and match_match_csv - why? why not?
120
+
69
121
  class << self
122
+ alias_method :match_teams?, :match_teams
123
+ alias_method :teams?, :match_teams
124
+
70
125
  alias_method :match_clubs?, :match_clubs
71
126
  alias_method :clubs?, :match_clubs
72
127
 
@@ -149,7 +204,14 @@ module SportDb
149
204
  end
150
205
 
151
206
  def each_conf( &blk ) each( pattern: CONF_RE, &blk ); end
152
- def each_match( &blk ) each( pattern: MATCH_RE, &blk ); end
207
+ def each_match( format: 'txt', &blk )
208
+ if format == 'csv'
209
+ each( pattern: MATCH_CSV_RE, &blk );
210
+ else
211
+ each( pattern: MATCH_RE, &blk );
212
+ end
213
+ end
214
+ def each_match_csv( &blk ) each( pattern: MATCH_CSV_RE, &blk ); end
153
215
  def each_club_props( &blk ) each( pattern: CLUB_PROPS_RE, &blk ); end
154
216
 
155
217
  def each_leagues( &blk ) each( pattern: LEAGUES_RE, &blk ); end
@@ -157,8 +219,100 @@ module SportDb
157
219
  def each_clubs_wiki( &blk ) each( pattern: CLUBS_WIKI_RE, &blk ); end
158
220
 
159
221
  ## return all match datafile entries
160
- def match() ary=[]; each_match {|entry| ary << entry }; ary; end
222
+ def match( format: 'txt' )
223
+ ary=[]; each_match( format: format ) {|entry| ary << entry }; ary;
224
+ end
161
225
  alias_method :matches, :match
226
+
227
+
228
+ ## todo/check: rename/change to match_by_dir - why? why not?
229
+ ## still in use somewhere? move to attic? use match_by_season and delete by_season_dir? - why? why not?
230
+ def match_by_season_dir( format: 'txt' )
231
+ ##
232
+ ## [["1950s/1956-57",
233
+ ## ["1950s/1956-57/1-division1.csv",
234
+ ## "1950s/1956-57/2-division2.csv",
235
+ ## "1950s/1956-57/3a-division3n.csv",
236
+ ## "1950s/1956-57/3b-division3s.csv"]],
237
+ ## ...]
238
+
239
+ h = {}
240
+ match( format: format ).each do |entry|
241
+ season_path = File.dirname( entry.name )
242
+
243
+ h[ season_path ] ||= []
244
+ h[ season_path ] << entry
245
+ end
246
+
247
+ ## todo/fix: - add sort entries by name - why? why not?
248
+ ## note: assume 1-,2- etc. gets us back sorted leagues
249
+ ## - use sort. (will not sort by default?)
250
+
251
+ h.to_a ## return as array (or keep hash) - why? why not?
252
+ end # method match_by_season_dir
253
+
254
+ def match_by_season( format: 'txt', start: nil ) ## change/rename to by_season_key - why? why not?
255
+
256
+ ## todo/note: in the future - season might be anything (e.g. part of a filename and NOT a directory) - why? why not?
257
+
258
+ ## note: fold all sames seasons (even if in different directories)
259
+ ## into same datafile list e.g.
260
+ ## ["1957/58",
261
+ ## ["1950s/1957-58/1-division1.csv",
262
+ ## "1950s/1957-58/2-division2.csv",
263
+ ## "1950s/1957-58/3a-division3n.csv",
264
+ ## "1950s/1957-58/3b-division3s.csv"]],
265
+ ## and
266
+ ## ["1957/58",
267
+ ## ["archives/1950s/1957-58/1-division1.csv",
268
+ ## "archives/1950s/1957-58/2-division2.csv",
269
+ ## "archives/1950s/1957-58/3a-division3n.csv",
270
+ ## "archives/1950s/1957-58/3b-division3s.csv"]],
271
+ ## should be together - why? why not?
272
+
273
+ ####
274
+ # Example package:
275
+ # [["2012/13", ["2012-13/1-proleague.csv"]],
276
+ # ["2013/14", ["2013-14/1-proleague.csv"]],
277
+ # ["2014/15", ["2014-15/1-proleague.csv"]],
278
+ # ["2015/16", ["2015-16/1-proleague.csv"]],
279
+ # ["2016/17", ["2016-17/1-proleague.csv"]],
280
+ # ["2017/18", ["2017-18/1-proleague.csv"]]]
281
+
282
+ ## todo/fix: (re)use a more generic filter instead of start for start of season only
283
+
284
+ ## todo/fix: use a "generic" filter_season helper for easy reuse
285
+ ## filter_season( clause, season_key )
286
+ ## or better filter = SeasonFilter.new( clause )
287
+ ## filter.skip? filter.include? ( season_sason_key )?
288
+ ## fiteer.before?( season_key ) etc.
289
+ ## find some good method names!!!!
290
+ season_start = start ? Import::Season.new( start ) : nil
291
+
292
+ h = {}
293
+ match( format: format ).each do |entry|
294
+ ## note: assume last directory in datafile path is the season part/key
295
+ season_q = File.basename( File.dirname( entry.name ))
296
+ season = Import::Season.new( season_q ) ## normalize season
297
+
298
+ ## skip if start season before this season
299
+ next if season_start && season_start.start_year > season.start_year
300
+
301
+ h[ season.key ] ||= []
302
+ h[ season.key ] << entry
303
+ end
304
+
305
+ ## todo/fix: - add sort entries by name - why? why not?
306
+ ## note: assume 1-,2- etc. gets us back sorted leagues
307
+ ## - use sort. (will not sort by default?)
308
+
309
+ ## sort by season
310
+ ## latest / newest first (and oldest last)
311
+
312
+ h.to_a.sort do |l,r| ## return as array (or keep hash) - why? why not?
313
+ r[0] <=> l[0]
314
+ end
315
+ end # method match_by_season
162
316
  end # class Package
163
317
 
164
318
 
@@ -18,10 +18,19 @@ module SportDb
18
18
 
19
19
 
20
20
  def is_round?( line )
21
- ## note: =~ return nil if not match found, and 0,1, etc for match
22
- (line =~ SportDb.lang.regex_round) != nil
21
+ ## note: =~ returns nil if not match found, and 0,1, etc for match
22
+
23
+ ## note: allow "free standing" leg 1 and leg 2 too
24
+ ## (e.g. Hinspiel, Rückspiel etc. used for now in Relegation, for example)
25
+ ## note ONLY allowed if "free standing", that is, full line with nothing else
26
+ ## use "custom" regex for special case for now
27
+ ## avoids match HIN in PascHINg, for example (hin in german for leg 1)
28
+ line =~ SportDb.lang.regex_round ||
29
+ line =~ /^(#{SportDb.lang.leg1})$/i ||
30
+ line =~ /^(#{SportDb.lang.leg2})$/i
23
31
  end
24
32
 
33
+
25
34
  def is_knockout_round?( line )
26
35
 
27
36
  ## todo: check for adding ignore case for regex (e.g. 1st leg/1st Leg)
@@ -93,12 +93,51 @@ module ScoreFormats
93
93
  (?=[ \]]|$)/xi ## todo/check: remove loakahead assertion here - why require space?
94
94
  ## note: \b works only after non-alphanum e.g. )
95
95
 
96
+
96
97
  #####
97
98
  # deutsch / german helpers (penalty, extra time, ...)
98
99
  ## todo add more marker e.g. im Elf. or such!!!
99
100
  P_DE = '(?: ie | i\.e\.? )' # e.g. iE, i.E., i.E etc.
100
101
  ET_DE = '(?: nv | n\.v\.? )' # e.g. nV, n.V., n.V etc.
101
102
 
103
+
104
+ ## support alternate all-in-one score e.g.
105
+ ## i.E. 2:4, n.V. 3:3 (1:1, 1:1) or
106
+ ## n.V. 3:2 (2:2, 1:2)
107
+ DE__P_ET_FT_HT__RE = /\b
108
+ (?:
109
+ #{P_DE}
110
+ [ ]*
111
+ (?<score1p>\d{1,2})
112
+ [ ]* : [ ]*
113
+ (?<score2p>\d{1,2})
114
+ [ ]* (?:, [ ]*)?
115
+ )? # note: make penalty (P) score optional for now
116
+ #{ET_DE}
117
+ [ ]*
118
+ (?<score1et>\d{1,2})
119
+ [ ]* : [ ]*
120
+ (?<score2et>\d{1,2})
121
+ [ ]*
122
+ \(
123
+ [ ]*
124
+ (?<score1>\d{1,2})
125
+ [ ]* : [ ]*
126
+ (?<score2>\d{1,2})
127
+ [ ]*
128
+ (?:
129
+ , [ ]*
130
+ (?:
131
+ (?<score1i>\d{1,2})
132
+ [ ]* : [ ]*
133
+ (?<score2i>\d{1,2})
134
+ [ ]*
135
+ )?
136
+ )? # note: make half time (HT) score optional for now
137
+ \)
138
+ (?=[ \]]|$)
139
+ /xi
140
+
102
141
  ## support all-in-one "literal form e.g.
103
142
  # 2:2 (1:1, 1:0) n.V. 5:1 i.E. or
104
143
  # 2-2 (1-1, 1-0) n.V. 5-1 i.E.
@@ -168,7 +207,8 @@ FORMATS_EN = [
168
207
  ]
169
208
 
170
209
  FORMATS_DE = [
171
- [ DE__ET_FT_HT_P__RE, '[SCORE.DE__ET_(FT_HT?)_P?]' ], # e.g. 2:2 (1:1, 1:0) n.V. 5:1 i.E.
210
+ [ DE__ET_FT_HT_P__RE, '[SCORE.DE__ET_(FT_HT?)_P?]' ], # e.g. 2:2 (1:1, 1:0) n.V. 5:1 i.E.
211
+ [ DE__P_ET_FT_HT__RE, '[SCORE.DE__P?_ET_(FT_HT?)]' ], # e.g. i.E. 2:4, n.V. 3:3 (1:1, 1:1)
172
212
  [ DE__FT_HT__RE, '[SCORE.DE__FT_(HT)?]' ], # e.g. 1:1 (1:0)
173
213
  ]
174
214
 
@@ -90,6 +90,12 @@ class ScoreParser
90
90
 
91
91
 
92
92
  def parse( line )
93
+
94
+ ##########
95
+ ## todo/fix/check: add unicode to regular dash conversion - why? why not?
96
+ ## e.g. – becomes - (yes, the letters a different!!!)
97
+ #############
98
+
93
99
  score = nil
94
100
  @formats.each do |format|
95
101
  re = format[0]
@@ -11,11 +11,14 @@ class Country
11
11
 
12
12
  ## note: is read-only/immutable for now - why? why not?
13
13
  ## add cities (array/list) - why? why not?
14
- attr_reader :key, :name, :fifa, :tags
14
+ attr_reader :key, :name, :code, :tags
15
15
  attr_accessor :alt_names
16
16
 
17
- def initialize( key:, name:, fifa:, tags: [] )
18
- @key, @name, @fifa = key, name, fifa
17
+ def initialize( key: nil, name:, code:, tags: [] )
18
+ ## note: auto-generate key "on-the-fly" if missing for now - why? why not?
19
+ ## note: quick hack - auto-generate key, that is, remove all non-ascii chars and downcase
20
+ @key = key || name.downcase.gsub( /[^a-z]/, '' )
21
+ @name, @code = name, code
19
22
  @alt_names = []
20
23
  @tags = tags
21
24
  end
@@ -2,20 +2,13 @@ module SportDb
2
2
  module Import
3
3
 
4
4
  class Group
5
- attr_reader :title, :pos, :teams
5
+ attr_reader :key, :name, :teams
6
6
 
7
- ##
8
- ## todo: change db schema
9
- ## make start and end date optional
10
- ## change pos to num - why? why not?
11
- ## make pos/num optional too
12
- ##
13
- ## sort round by scheduled/planed start date
14
- def initialize( title:,
15
- pos:,
7
+ def initialize( key: nil,
8
+ name:,
16
9
  teams: )
17
- @title = title
18
- @pos = pos
10
+ @key = key ## e.g. A,B,C or 1,2,3, - note: always a string or nil
11
+ @name = name
19
12
  @teams = teams
20
13
  end
21
14
  end # class Group
@@ -2,24 +2,17 @@ module SportDb
2
2
  module Import
3
3
 
4
4
  class Round
5
- attr_reader :title, :start_date, :end_date, :knockout
6
- attr_accessor :pos # note: make read & writable
5
+ attr_reader :name, :start_date, :end_date, :knockout
6
+ attr_accessor :num # note: make read & writable - why? why not?
7
7
 
8
- ##
9
- ## todo: change db schema
10
- ## make start and end date optional
11
- ## change pos to num - why? why not?
12
- ## make pos/num optional too
13
- ##
14
- ## sort round by scheduled/planed start date
15
- def initialize( title:,
16
- pos: nil,
8
+ def initialize( name:,
9
+ num: nil,
17
10
  start_date: nil,
18
11
  end_date: nil,
19
12
  knockout: false,
20
13
  auto: true )
21
- @title = title
22
- @pos = pos
14
+ @name = name
15
+ @num = num
23
16
  @start_date = start_date
24
17
  @end_date = end_date
25
18
  @knockout = knockout
@@ -12,7 +12,7 @@ module SportDb
12
12
 
13
13
  class Standings
14
14
 
15
- class StandingsLine ## nested class StandinsLine
15
+ class StandingsLine ## nested class StandinsLine - todo/fix: change to Line - why? why not?
16
16
  attr_accessor :rank, :team,
17
17
  :played, :won, :lost, :drawn, ## -- total
18
18
  :goals_for, :goals_against, :pts,
@@ -21,8 +21,13 @@ class Standings
21
21
  :away_played, :away_won, :away_lost, :away_drawn, ## -- away
22
22
  :away_goals_for, :away_goals_against, :away_pts
23
23
 
24
+ alias_method :team_name, :team ## note: team for now always a string
25
+ alias_method :pos, :rank ## rename back to use pos instead of rank - why? why not?
26
+
27
+
24
28
  def initialize( team )
25
29
  @rank = nil # use 0? why? why not?
30
+ ## change rank back to pos - why? why not?
26
31
  @team = team
27
32
  @played = @home_played = @away_played = 0
28
33
  @won = @home_won = @away_won = 0
@@ -49,7 +54,12 @@ class Standings
49
54
 
50
55
  def update( match_or_matches )
51
56
  ## convenience - update all matches at once
52
- matches = match_or_matches.is_a?(Array) ? match_or_matches : [match_or_matches]
57
+ ## todo/check: check for ActiveRecord_Associations_CollectionProxy and than use to_a (to "force" array) - why? why not?
58
+ matches = if match_or_matches.is_a?(Array)
59
+ match_or_matches
60
+ else
61
+ [match_or_matches]
62
+ end
53
63
 
54
64
  matches.each_with_index do |match,i| # note: index(i) starts w/ zero (0)
55
65
  update_match( match )
@@ -171,19 +181,30 @@ class Standings
171
181
  private
172
182
  def update_match( m ) ## add a match
173
183
 
174
- ## puts " #{m.team1} - #{m.team2} #{m.score_str}"
184
+ ## note: always use team as string for now
185
+ ## for now allow passing in of string OR struct - why? why not?
186
+ ## todo/fix: change to m.team1_name and m.team2_name - why? why not?
187
+ team1 = m.team1.is_a?( String ) ? m.team1 : m.team1.name
188
+ team2 = m.team2.is_a?( String ) ? m.team2 : m.team2.name
189
+
190
+ score = m.score_str
191
+
192
+ ## puts " #{team1} - #{team2} #{score}"
193
+
175
194
  unless m.over?
176
- puts " !!!! skipping match - not yet over (play_at date in the future)"
195
+ puts " !!!! skipping match - not yet over (date in the future) => #{m.date}"
177
196
  return
178
197
  end
179
198
 
180
199
  unless m.complete?
181
- puts "!!! [calc_standings] skipping match #{m.team1} - #{m.team2} - scores incomplete #{m.score_str}"
200
+ puts "!!! [calc_standings] skipping match #{team1} - #{team2} w/ past date #{m.date} - scores incomplete => #{score}"
182
201
  return
183
202
  end
184
203
 
185
- line1 = @lines[ m.team1 ] || StandingsLine.new( m.team1 )
186
- line2 = @lines[ m.team2 ] || StandingsLine.new( m.team2 )
204
+
205
+
206
+ line1 = @lines[ team1 ] || StandingsLine.new( team1 )
207
+ line2 = @lines[ team2 ] || StandingsLine.new( team2 )
187
208
 
188
209
  line1.played += 1
189
210
  line1.home_played += 1
@@ -236,8 +257,8 @@ private
236
257
  puts "*** warn: [standings] skipping match with missing scores: #{m.inspect}"
237
258
  end
238
259
 
239
- @lines[ m.team1 ] = line1
240
- @lines[ m.team2 ] = line2
260
+ @lines[ team1 ] = line1
261
+ @lines[ team2 ] = line2
241
262
  end # method update_match
242
263
 
243
264
  end # class Standings