sportdb-models 1.18.6 → 1.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +0 -106
  3. data/Rakefile +0 -1
  4. data/lib/sportdb/deleter.rb +1 -1
  5. data/lib/sportdb/models.rb +3 -88
  6. data/lib/sportdb/version.rb +2 -2
  7. data/test/helper.rb +0 -108
  8. metadata +2 -122
  9. data/lib/sportdb/indexers/team.rb +0 -87
  10. data/lib/sportdb/matcher.rb +0 -31
  11. data/lib/sportdb/pretty_printer.rb +0 -175
  12. data/lib/sportdb/reader.rb +0 -132
  13. data/lib/sportdb/reader_file.rb +0 -131
  14. data/lib/sportdb/reader_zip.rb +0 -172
  15. data/lib/sportdb/readers/assoc.rb +0 -54
  16. data/lib/sportdb/readers/event.rb +0 -253
  17. data/lib/sportdb/readers/event_meta.rb +0 -133
  18. data/lib/sportdb/readers/event_table.rb +0 -196
  19. data/lib/sportdb/readers/game.rb +0 -912
  20. data/lib/sportdb/readers/ground.rb +0 -53
  21. data/lib/sportdb/readers/league.rb +0 -54
  22. data/lib/sportdb/readers/season.rb +0 -83
  23. data/lib/sportdb/readers/squad_club.rb +0 -201
  24. data/lib/sportdb/readers/squad_national_team.rb +0 -173
  25. data/lib/sportdb/readers/team.rb +0 -53
  26. data/lib/sportdb/rsssf_reader.rb +0 -367
  27. data/lib/sportdb/utils.rb +0 -89
  28. data/lib/sportdb/utils_date.rb +0 -26
  29. data/lib/sportdb/utils_goals.rb +0 -20
  30. data/lib/sportdb/utils_group.rb +0 -63
  31. data/lib/sportdb/utils_map.rb +0 -44
  32. data/lib/sportdb/utils_round.rb +0 -165
  33. data/lib/sportdb/utils_scores.rb +0 -17
  34. data/lib/sportdb/utils_teams.rb +0 -48
  35. data/test/data/at-austria/2013_14/bl.txt +0 -227
  36. data/test/data/at-austria/2013_14/bl.yml +0 -30
  37. data/test/data/at-austria/2013_14/bl_ii.txt +0 -154
  38. data/test/data/at-austria/2013_14/el.txt +0 -4
  39. data/test/data/at-austria/2013_14/el.yml +0 -25
  40. data/test/data/at-austria/2013_14/squads/austria.txt +0 -40
  41. data/test/data/at-austria/2013_14/squads/salzburg.txt +0 -35
  42. data/test/data/at-austria/2014_15/1-bundesliga-ii.txt +0 -158
  43. data/test/data/at-austria/2014_15/1-bundesliga.yml +0 -18
  44. data/test/data/at-austria/2015_16/1-bundesliga-v2.conf.txt +0 -20
  45. data/test/data/at-austria/2015_16/1-bundesliga-v2.yml +0 -20
  46. data/test/data/at-austria/2015_16/1-bundesliga.conf.txt +0 -20
  47. data/test/data/at-austria/2015_16/1-bundesliga.yml +0 -24
  48. data/test/data/at-austria/2015_16/cup.yml +0 -77
  49. data/test/data/at-austria/leagues.txt +0 -11
  50. data/test/data/at-austria/teams.txt +0 -68
  51. data/test/data/at-austria/teams_2.txt +0 -21
  52. data/test/data/csv/de-2013-14--1-bundesliga.txt +0 -307
  53. data/test/data/de-deutschland/2013-14/1-bundesliga.yml +0 -26
  54. data/test/data/de-deutschland/leagues.txt +0 -4
  55. data/test/data/de-deutschland/teams.txt +0 -53
  56. data/test/data/eng-england/2015-16/1-premierleague-v2.yml +0 -2
  57. data/test/data/eng-england/2015-16/1-premierleague.yml +0 -5
  58. data/test/data/national-teams/assocs.txt +0 -231
  59. data/test/data/national-teams/europe/assocs.txt +0 -13
  60. data/test/data/national-teams/europe/teams.txt +0 -13
  61. data/test/data/national-teams/north-america/assocs.txt +0 -10
  62. data/test/data/national-teams/north-america/teams.txt +0 -7
  63. data/test/data/national-teams/teams.txt +0 -19
  64. data/test/data/players/europe/at-austria/players.txt +0 -45
  65. data/test/data/players/europe/de-deutschland/players.txt +0 -41
  66. data/test/data/players/south-america/br-brazil/players.txt +0 -51
  67. data/test/data/rsssf/at-2014-15--1-bundesliga.txt +0 -339
  68. data/test/data/rsssf/at-2015-16--1-bundesliga.txt +0 -18
  69. data/test/data/world-cup/1930/cup.txt +0 -71
  70. data/test/data/world-cup/1930/cup.yml +0 -23
  71. data/test/data/world-cup/1930/cup_goals.txt +0 -47
  72. data/test/data/world-cup/1930/cup_goals.yml +0 -23
  73. data/test/data/world-cup/1954/cup.txt +0 -90
  74. data/test/data/world-cup/1954/cup.yml +0 -30
  75. data/test/data/world-cup/1962/cup.txt +0 -86
  76. data/test/data/world-cup/1962/cup.yml +0 -32
  77. data/test/data/world-cup/1974/cup.yml +0 -35
  78. data/test/data/world-cup/1974/cup_finals.txt +0 -14
  79. data/test/data/world-cup/1974/cup_i.txt +0 -55
  80. data/test/data/world-cup/1974/cup_ii.txt +0 -34
  81. data/test/data/world-cup/2014/cup.txt +0 -5
  82. data/test/data/world-cup/2014/cup.yml +0 -54
  83. data/test/data/world-cup/2014/squads/br-brazil.txt +0 -46
  84. data/test/data/world-cup/2014/squads/de-deutschland.txt +0 -8
  85. data/test/data/world-cup/2014/squads/jp-japan.txt +0 -30
  86. data/test/data/world-cup/2014/squads/uy-uruguay.txt +0 -32
  87. data/test/data/world-cup/leagues.txt +0 -5
  88. data/test/data/world-cup/seasons_1930.txt +0 -4
  89. data/test/data/world-cup/seasons_1954.txt +0 -4
  90. data/test/data/world-cup/seasons_1962.txt +0 -4
  91. data/test/data/world-cup/seasons_1974.txt +0 -5
  92. data/test/data/world-cup/teams_1930.txt +0 -26
  93. data/test/data/world-cup/teams_1954.txt +0 -30
  94. data/test/data/world-cup/teams_1962.txt +0 -29
  95. data/test/data/world-cup/teams_1974.txt +0 -29
  96. data/test/test_assoc_reader.rb +0 -199
  97. data/test/test_event_meta_reader.rb +0 -47
  98. data/test/test_event_reader.rb +0 -64
  99. data/test/test_event_table_reader.rb +0 -57
  100. data/test/test_goals.rb +0 -107
  101. data/test/test_indexer_team.rb +0 -34
  102. data/test/test_load.rb +0 -61
  103. data/test/test_pp.rb +0 -35
  104. data/test/test_reader.rb +0 -88
  105. data/test/test_reader_from_string.rb +0 -63
  106. data/test/test_round_auto.rb +0 -370
  107. data/test/test_round_def.rb +0 -109
  108. data/test/test_round_header.rb +0 -183
  109. data/test/test_rsssf_reader.rb +0 -76
  110. data/test/test_squad_club_reader.rb +0 -76
  111. data/test/test_squad_national_team_reader.rb +0 -116
  112. data/test/test_standings.rb +0 -279
  113. data/test/test_standings_ii.rb +0 -46
  114. data/test/test_utils.rb +0 -124
@@ -1,133 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module SportDb
4
-
5
-
6
- class EventMetaReader
7
-
8
- include LogUtils::Logging
9
-
10
- ## make models available by default with namespace
11
- # e.g. lets you use Usage instead of Model::Usage
12
- include Models
13
-
14
- attr_reader :event # returns event record; call read first
15
- attr_reader :fixtures # fixtures/sources entry from event config
16
-
17
- def self.from_zip( zip_file, entry_path, more_attribs={} )
18
- ## get text content from zip
19
- entry = zip_file.find_entry( entry_path )
20
-
21
- text = entry.get_input_stream().read()
22
- text = text.force_encoding( Encoding::UTF_8 )
23
-
24
- config = File.basename( entry_path ) # name of .yml file
25
-
26
- self.from_string( text, config, more_attribs )
27
- end
28
-
29
- def self.from_file( path, more_attribs={} )
30
- ## note: assume/enfore utf-8 encoding (with or without BOM - byte order mark)
31
- ## - see textutils/utils.rb
32
- text = File.read_utf8( path )
33
-
34
- config = File.basename( path ) # name of .yml file
35
-
36
- self.from_string( text, config, more_attribs )
37
- end
38
-
39
- def self.from_string( text, config, more_attribs={} )
40
- self.new( text, config, more_attribs )
41
- end
42
-
43
- def initialize( text, config, more_attribs={} )
44
- ## todo/fix: how to add opts={} ???
45
- ## todo/check: more_attribs used ???
46
- @text = text
47
- @more_attribs = more_attribs
48
-
49
- # name of event configuration (relative basename w/o path or string)
50
- @config = config
51
-
52
- @event = nil
53
- @fixtures = []
54
- end
55
-
56
-
57
- def read
58
- @event = nil # reset cached event rec
59
- @fixtures = [] # reset cached fixtures
60
-
61
- reader = HashReader.from_string( @text )
62
-
63
- league = nil
64
- season = nil
65
-
66
- reader.each_typed do |key, value|
67
-
68
- ## puts "processing event attrib >>#{key}<< >>#{value}<<..."
69
-
70
- if key.downcase == 'league' ## note: allow league, League, etc.
71
- league_key = value.to_s.strip
72
- ## check if league_key includes uppercase letters (e.g. Deutsche Bundesliga and NOT de etc.)
73
- if league_key =~ /[A-Z]/
74
- ## assume league name (NOT league key); try to lookup leauge key in database
75
- league = League.find_by( title: league_key )
76
- ## todo: add synonyms/alt names - why? why not??
77
- else
78
- ## assume "verbatim/literal" team_key (use as is 1:1)
79
- league = League.find_by( key: league_key )
80
- end
81
-
82
- ## check if it exists
83
- if league.nil?
84
- logger.error "league with key >>#{league_key}<< missing"
85
- exit 1
86
- end
87
- elsif key.downcase == 'season' ## note: allow season, Season, etc.
88
- season_key = value.to_s.strip
89
- season = Season.find_by( key: season_key )
90
-
91
- ## check if it exists
92
- if season.nil?
93
- logger.error "season with key >>#{season_key}<< missing"
94
- exit 1
95
- end
96
- elsif key.downcase == 'fixtures' || key.downcase == 'sources'
97
- ### todo: check for mulitiple fixtures/sources ?? allow disallow?? why? why not?
98
- if value.kind_of?(Array)
99
- @fixtures += value
100
- else # assume plain (single fixture) string
101
- @fixtures << value.to_s
102
- end
103
- else
104
- ## todo: add a source location struct to_s or similar (file, line, col)
105
- logger.error "unknown event attrib #{key}; skipping attrib"
106
- end
107
- end # each key,value
108
-
109
- # check fixtures - if nothing specified; use basename of config (this) file
110
- if @fixtures.empty?
111
- ## use basename of config file as default (without extension)
112
- sources_default = File.basename( @config, File.extname( @config ) )
113
- logger.debug " add default fixture (assume same basename as config file) e.g. >#{sources_default}<"
114
- @fixtures << sources_default
115
- end
116
-
117
- logger.debug "find event - league.id: #{league.id}, season.id: #{season.id}"
118
-
119
- ## note: for now event MUST exist (read-only access)
120
- # keep a "cached" reference for later use
121
- @event = Event.find_by!( league_id: league.id,
122
- season_id: season.id )
123
-
124
- @event
125
-
126
- ## todo/check:
127
- ## return a "simple" hash in new (next) version - why? why not??
128
- ## add fixtures (defaults) if missing
129
- end # method read
130
-
131
-
132
- end # class EventMetaReader
133
- end # module SportDb
@@ -1,196 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module SportDb
4
-
5
-
6
- class EventTableReader
7
-
8
- include LogUtils::Logging
9
-
10
- ## make models available by default with namespace
11
- # e.g. lets you use Usage instead of Model::Usage
12
- include Models
13
-
14
- attr_reader :event # returns event record; call read first
15
-
16
-
17
- def self.from_zip( zip_file, entry_path, more_attribs={} )
18
- ## get text content from zip
19
- entry = zip_file.find_entry( entry_path )
20
-
21
- text = entry.get_input_stream().read()
22
- text = text.force_encoding( Encoding::UTF_8 )
23
-
24
- self.from_string( text, more_attribs )
25
- end
26
-
27
- def self.from_file( path, more_attribs={} )
28
- ## note: assume/enfore utf-8 encoding (with or without BOM - byte order mark)
29
- ## - see textutils/utils.rb
30
- text = File.read_utf8( path )
31
-
32
- self.from_string( text, more_attribs )
33
- end
34
-
35
- def self.from_string( text, more_attribs={} )
36
- self.new( text, more_attribs )
37
- end
38
-
39
- def initialize( text, more_attribs={} )
40
- ## todo/fix: how to add opts={} ???
41
- @text = text
42
- @more_attribs = more_attribs
43
-
44
- @event = nil
45
- end
46
-
47
-
48
- ## split into league + season
49
- ## e.g. Österr. Bundesliga 2015/16
50
- ## World Cup 2018
51
- EVENT_HEADER_REGEX = /^
52
- (?<league>.+?) ## non-greedy
53
- \s
54
- (?<season>\d{4}
55
- (?:\/\d{2})? ## optional 2nd date in season
56
- )
57
- $/x
58
-
59
- def read
60
- @event = nil # reset cached event rec
61
- event_attribs={}
62
-
63
- reader = LineReader.from_string( @text )
64
-
65
- header = false
66
- season = nil
67
- league = nil
68
-
69
- reader.each_line do |line|
70
- puts " line: >#{line}<"
71
-
72
- ## assume first line is event header (league+season)
73
- ## e.g. Österr. Bundesliga 2015/16
74
- ## World Cup 2018
75
- if header == false
76
- line = line.strip
77
- m = EVENT_HEADER_REGEX.match( line )
78
- if m
79
- league_title = m[:league]
80
- season_key = m[:season]
81
- puts " trying event lookup - league: >#{league_title}<, season: >#{season_key}<"
82
-
83
- season = Season.find_by( key: season_key )
84
-
85
- ## check if it exists
86
- if season.present?
87
- event_attribs['season_id'] = season.id
88
- else
89
- logger.error "season with key >>#{season_key}<< missing"
90
- exit 1
91
- end
92
-
93
- league = League.find_by( title: league_title )
94
-
95
- ## check if it exists
96
- if league.present? ## todo: just use if league (no present?) ???
97
- event_attribs['league_id'] = league.id
98
- else
99
- logger.error "league with title >>#{league_title}<< missing"
100
- exit 1
101
- end
102
- else
103
- fail "[EventTableReader] event header must match league+season pattern: >#{line}<"
104
- end
105
- header = true
106
- else
107
- ### process regular team lines
108
-
109
- line = line.strip
110
- scan = StringScanner.new( line )
111
-
112
- if scan.check( /-/ ) # option 1) list entry e.g. - Rapid Wien
113
- puts " list entry >#{line}<"
114
- scan.skip( /-\s+/)
115
- team_title = scan.rest.strip ## assume the rest is the team name
116
- elsif scan.check( /\d{1,2}\./ ) ## option 2) table entry e.g. 1. Rapid Wien
117
- puts " table entry >#{line}<"
118
- rank = scan.scan( /\d{1,2}/ )
119
- scan.skip( /\.\s+/)
120
-
121
- ## note: uses look ahead scan until we hit at least two spaces
122
- ## or the end of string (standing records for now optional)
123
- team_title = scan.scan_until( /(?=\s{2})|$/ )
124
- if scan.eos?
125
- standing = nil
126
- else
127
- scan.skip( /\s+/ )
128
- standing = scan.rest
129
- end
130
- puts " rank: >#{rank}<, standing: >#{standing}<"
131
- else
132
- fail "[EventTableReader] event line must match team pattern: >#{line}<"
133
- end
134
-
135
- puts " team: >#{team_title}<"
136
-
137
- team = Team.find_by( title: team_title )
138
- ## next try synonyms (if not found/no match)
139
- team = Team.where( "synonyms LIKE ?", "%#{team_title}%" ).first if team.nil?
140
-
141
-
142
- if team.nil?
143
- ### print better error message than just
144
- ## *** error: Couldn't find SportDb::Model::Team
145
- puts "[fatal] event reader - record for team title >#{team_title}< not found"
146
- exit 1
147
- ### fix/todo: throw exception/error
148
- end
149
-
150
- team_ids = event_attribs['team_ids'] || []
151
- team_ids << team.id
152
- event_attribs['team_ids'] = team_ids
153
- end
154
- end # each_line
155
-
156
- pp event_attribs
157
-
158
-
159
- league_id = event_attribs['league_id']
160
- season_id = event_attribs['season_id']
161
-
162
- logger.debug "find event - league_id: #{league_id}, season_id: #{season_id}"
163
-
164
- event = Event.find_by( league_id: league_id,
165
- season_id: season_id )
166
-
167
- ## check if it exists
168
- if event.present?
169
- logger.debug "*** update event #{event.id}-#{event.key}:"
170
- else
171
- logger.debug "*** create event:"
172
- event = Event.new
173
-
174
- ## hack: fix/todo1!!
175
- ## add "fake" start_at date for now
176
- if season.key.size == '4' ## e.g. assume 2018 etc.
177
- year = season.key.to_i
178
- start_at = Date.new( year, 1, 1 )
179
- else ## assume 2014/15 etc.
180
- year = season.key[0..3].to_i
181
- start_at = Date.new( year, 7, 1 )
182
- end
183
- event_attribs['start_at'] = start_at
184
- end
185
-
186
- logger.debug event_attribs.to_json
187
-
188
- event.update_attributes!( event_attribs )
189
-
190
- # keep a cached reference for later use
191
- @event = event
192
- end # method read
193
-
194
-
195
- end # class EventTableReader
196
- end # module SportDb
@@ -1,912 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module SportDb
4
-
5
- class GameReader
6
-
7
- include LogUtils::Logging
8
-
9
- ## make models available by default with namespace
10
- # e.g. lets you use Usage instead of Model::Usage
11
- include Models
12
-
13
- attr_reader :event # returns event record
14
-
15
- ## value helpers e.g. is_year?, is_taglist? etc.
16
- include TextUtils::ValueHelper
17
-
18
- include FixtureHelpers
19
-
20
- def self.from_zip( zip_file, entry_path, more_attribs={} )
21
-
22
- logger = LogKernel::Logger.root
23
-
24
- ## get text content from zip
25
- entry = zip_file.find_entry( entry_path )
26
- event_text = entry.get_input_stream().read()
27
- event_text = event_text.force_encoding( Encoding::UTF_8 )
28
-
29
- ## hack:
30
- ## support old event config format for now (will get removed later)
31
- ## e.g. check for
32
- ## teams:
33
- ## 12 teams: etc.
34
- if event_text =~ /^teams:/i ||
35
- event_text =~ /^\d{1,2} teams:/i ||
36
- event_text =~ /^start_at:/i
37
- ## old format
38
- puts "*** [DEPRECATED] old event config format w/ yaml, please use new plain text format >#{entry_path}<"
39
- reader = EventReader.from_zip( zip_file, entry_path )
40
- reader.read()
41
- else
42
- ## new format
43
- reader = EventMetaReader.from_zip( zip_file, entry_path )
44
- reader.read()
45
- end
46
-
47
- event = reader.event ## was fetch_event( name )
48
- fixtures = reader.fixtures ## was fetch_event_fixtures( name )
49
-
50
- ## add path to fixtures (use path from event e.g)
51
- # - bl + at-austria!/2012_13/bl -> at-austria!/2012_13/bl
52
- # - bl_ii + at-austria!/2012_13/bl -> at-austria!/2012_13/bl_ii
53
-
54
- dir = File.dirname( entry_path ) # use dir for fixtures
55
-
56
- fixtures_with_path = fixtures.map do |fx|
57
- fx_new = "#{dir}/#{fx}.txt" # add path upfront
58
- logger.debug "fx: #{fx_new} | >#{fx}< + >#{dir}<"
59
- fx_new
60
- end
61
-
62
- ## fix-fix-fix: change file extension to ??
63
- text_ary = []
64
- fixtures_with_path.each do |fixture_path|
65
- entry = zip_file.find_entry( fixture_path )
66
-
67
- text = entry.get_input_stream().read()
68
- text = text.force_encoding( Encoding::UTF_8 )
69
-
70
- text_ary << text
71
- end
72
-
73
- self.from_string( event, text_ary, more_attribs )
74
- end
75
-
76
- def self.from_file( path, more_attribs={} )
77
-
78
- logger = LogKernel::Logger.root
79
-
80
- ### NOTE: fix-fix-fix - pass in event path!!!!!!! (not fixture path!!!!)
81
-
82
- ## - ## note: assume/enfore utf-8 encoding (with or without BOM - byte order mark)
83
- ## - ## - see textutils/utils.rb
84
- ## - text = File.read_utf8( path )
85
-
86
- event_text = File.read_utf8( path )
87
-
88
- ## hack:
89
- ## support old event config format for now (will get removed later)
90
- ## e.g. check for
91
- ## teams:
92
- ## 12 teams: etc.
93
- if event_text =~ /^teams:/i ||
94
- event_text =~ /^\d{1,2} teams:/i ||
95
- event_text =~ /^start_at:/i
96
-
97
- ## old format
98
- puts "*** [DEPRECATED] old event config format w/ yaml, please use new plain text format >#{path}<"
99
- reader = EventReader.from_file( path )
100
- reader.read()
101
- else
102
- ## new format
103
- reader = EventMetaReader.from_file( path )
104
- reader.read()
105
- end
106
-
107
-
108
- event = reader.event ## was fetch_event( name )
109
- fixtures = reader.fixtures ## was fetch_event_fixtures( name )
110
-
111
-
112
- ## add path to fixtures (use path from event e.g)
113
- # - bl + at-austria!/2012_13/bl -> at-austria!/2012_13/bl
114
- # - bl_ii + at-austria!/2012_13/bl -> at-austria!/2012_13/bl_ii
115
-
116
- dir = File.dirname( path ) # use dir for fixtures
117
-
118
- fixtures_with_path = fixtures.map do |fx|
119
- fx_new = "#{dir}/#{fx}.txt" # add path upfront
120
- logger.debug "fx: #{fx_new} | >#{fx}< + >#{dir}<"
121
- fx_new
122
- end
123
-
124
- ## fix-fix-fix: change file extension to ??
125
- text_ary = []
126
- fixtures_with_path.each do |fixture_path|
127
- text_ary << File.read_utf8( fixture_path )
128
- end
129
-
130
- self.from_string( event, text_ary, more_attribs )
131
- end
132
-
133
-
134
- def self.from_string( event, text_or_text_ary, more_attribs={} )
135
- ### fix - fix -fix:
136
- ## change event to event_or_event_key !!!!! - allow event_key as string passed in
137
- self.new( event, text_or_text_ary, more_attribs )
138
- end
139
-
140
-
141
- def initialize( event, text_or_text_ary, more_attribs={} )
142
- ### fix - fix -fix:
143
- ## change event to event_or_event_key !!!!! - allow event_key as string passed in
144
-
145
- ## todo/fix: how to add opts={} ???
146
- @event = event
147
- @text_or_text_ary = text_or_text_ary
148
- @more_attribs = more_attribs
149
- end
150
-
151
-
152
- def read
153
- if @text_or_text_ary.is_a?( String )
154
- text_ary = [@text_or_text_ary]
155
- else
156
- text_ary = @text_or_text_ary
157
- end
158
-
159
- ## reset cached values
160
- ## for auto-number rounds etc.
161
- @last_round_pos = nil
162
-
163
- text_ary.each do |text|
164
- ## assume en for now? why? why not?
165
- ## fix (cache) store lang in event table (e.g. auto-add and auto-update)!!!
166
- SportDb.lang.lang = SportDb.lang.classify( text )
167
-
168
- reader = LineReader.from_string( text )
169
-
170
- read_fixtures_worker( @event.key, reader )
171
- end
172
-
173
- ## fix add prop ??
174
- ### Prop.create!( key: "db.#{fixture_name_to_prop_key(name)}.version", value: "file.txt.#{File.mtime(path).strftime('%Y.%m.%d')}" )
175
- end
176
-
177
-
178
- def read_fixtures_worker( event_key, reader )
179
- ## NB: assume active activerecord connection
180
-
181
- ## reset cached values
182
- @patch_round_ids_dates = []
183
- @patch_round_ids_pos = []
184
-
185
- @round = nil ## fix: change/rename to @last_round !!!
186
- @group = nil ## fix: change/rename to @last_group !!!
187
- @last_date = nil
188
-
189
- @last_team1 = nil # used for goals (to match players via squads)
190
- @last_team2 = nil
191
- @last_game = nil
192
-
193
-
194
- #####
195
- # fix: move to read and share event/known_teams
196
- # for all 1-n fixture files (no need to configure every time!!)
197
-
198
- @event = Event.find_by_key!( event_key )
199
-
200
- logger.debug "Event #{@event.key} >#{@event.title}<"
201
-
202
- ### fix: use build_title_table_for ??? why? why not??
203
- ## @known_teams = @event.known_teams_table
204
-
205
- @mapper_teams = TeamMapper.new( @event.teams )
206
-
207
-
208
- @known_grounds = TextUtils.build_title_table_for( @event.grounds )
209
-
210
-
211
- parse_fixtures( reader )
212
-
213
- end # method load_fixtures
214
-
215
-
216
-
217
- def parse_group_header( line )
218
- logger.debug "parsing group header line: >#{line}<"
219
-
220
- # note: group header resets (last) round (allows, for example):
221
- # e.g.
222
- # Group Playoffs/Replays -- round header
223
- # team1 team2 -- match
224
- # Group B: -- group header
225
- # team1 team2 - match (will get new auto-matchday! not last round)
226
- @round = nil ## fix: change/rename to @last_round !!!
227
-
228
- title, pos = find_group_title_and_pos!( line )
229
-
230
- logger.debug " title: >#{title}<"
231
- logger.debug " pos: >#{pos}<"
232
- logger.debug " line: >#{line}<"
233
-
234
- # set group for games
235
- @group = Group.find_by_event_id_and_pos!( @event.id, pos )
236
- end
237
-
238
-
239
- def parse_group_def( line )
240
- logger.debug "parsing group def line: >#{line}<"
241
-
242
- @mapper_teams.map_teams!( line )
243
- team_keys = @mapper_teams.find_teams!( line )
244
-
245
- title, pos = find_group_title_and_pos!( line )
246
-
247
- logger.debug " line: >#{line}<"
248
-
249
- group_attribs = {
250
- title: title
251
- }
252
-
253
- group = Group.find_by_event_id_and_pos( @event.id, pos )
254
- if group.present?
255
- logger.debug "update group #{group.id}:"
256
- else
257
- logger.debug "create group:"
258
- group = Group.new
259
- group_attribs = group_attribs.merge( {
260
- event_id: @event.id,
261
- pos: pos
262
- })
263
- end
264
-
265
- logger.debug group_attribs.to_json
266
-
267
- group.update_attributes!( group_attribs )
268
-
269
- group.teams.clear # remove old teams
270
- ## add new teams
271
- team_keys.each do |team_key|
272
- team = Team.find_by_key!( team_key )
273
- logger.debug " adding team #{team.title} (#{team.code})"
274
- group.teams << team
275
- end
276
- end
277
-
278
-
279
- def parse_round_def( line )
280
- logger.debug "parsing round def line: >#{line}<"
281
-
282
- ### todo/fix/check: move cut off optional comment in reader for all lines? why? why not?
283
- cut_off_end_of_line_comment!( line ) # cut off optional comment starting w/ #
284
-
285
- start_at = find_date!( line, start_at: @event.start_at )
286
- end_at = find_date!( line, start_at: @event.start_at )
287
-
288
- # note: if end_at missing -- assume start_at is (==) end_at
289
- end_at = start_at if end_at.nil?
290
-
291
- # note: - NOT needed; start_at and end_at are saved as date only (NOT datetime)
292
- # set hours,minutes,secs to beginning and end of day (do NOT use default 12.00)
293
- # e.g. use 00.00 and 23.59
294
- # start_at = start_at.beginning_of_day
295
- # end_at = end_at.end_of_day
296
-
297
- # note: make sure start_at/end_at is date only (e.g. use start_at.to_date)
298
- # sqlite3 saves datetime in date field as datetime, for example (will break date compares later!)
299
- start_at = start_at.to_date
300
- end_at = end_at.to_date
301
-
302
-
303
- pos = find_round_pos!( line )
304
- title = find_round_def_title!( line )
305
- # NB: use extracted round title for knockout check
306
- knockout_flag = is_knockout_round?( title )
307
-
308
-
309
- logger.debug " start_at: #{start_at}"
310
- logger.debug " end_at: #{end_at}"
311
- logger.debug " pos: #{pos}"
312
- logger.debug " title: >#{title}<"
313
- logger.debug " knockout_flag: #{knockout_flag}"
314
-
315
- logger.debug " line: >#{line}<"
316
-
317
- #######################################
318
- # fix: add auto flag is false !!!!
319
-
320
- round_attribs = {
321
- title: title,
322
- knockout: knockout_flag,
323
- start_at: start_at,
324
- end_at: end_at
325
- }
326
-
327
- round = Round.find_by_event_id_and_pos( @event.id, pos )
328
- if round.present?
329
- logger.debug "update round #{round.id}:"
330
- else
331
- logger.debug "create round:"
332
- round = Round.new
333
-
334
- round_attribs = round_attribs.merge( {
335
- event_id: @event.id,
336
- pos: pos
337
- })
338
- end
339
-
340
- logger.debug round_attribs.to_json
341
-
342
- round.update_attributes!( round_attribs )
343
- end
344
-
345
-
346
- def parse_round_header( line )
347
- logger.debug "parsing round header line: >#{line}<"
348
-
349
- ### todo/fix/check: move cut off optional comment in reader for all lines? why? why not?
350
- cut_off_end_of_line_comment!( line ) # cut off optional comment starting w/ #
351
-
352
- # NB: cut off optional title2 starting w/ // first
353
- title2 = find_round_header_title2!( line )
354
-
355
- # todo/fix: check if it is possible title2 w/ group?
356
- # add an example here
357
- group_title, group_pos = find_group_title_and_pos!( line )
358
-
359
- ## todo/check/fix:
360
- # make sure Round of 16 will not return pos 16 -- how? possible?
361
- # add unit test too to verify
362
- pos = find_round_pos!( line )
363
-
364
- ## check if pos available; if not auto-number/calculate
365
- if pos.nil?
366
- if @patch_round_ids_pos.empty?
367
- pos = (@last_round_pos||0)+1
368
- logger.debug( " no round pos found; auto-number round - use (#{pos})" )
369
- else
370
- # note: if any rounds w/o pos already seen (add for auto-numbering at the end)
371
- # will get auto-numbered sorted by start_at date
372
- pos = 999001+@patch_round_ids_pos.length # e.g. 999<count> - 999001,999002,etc.
373
- logger.debug( " no round pos found; auto-number round w/ patch (backtrack) at the end" )
374
- end
375
- end
376
-
377
- # store pos for auto-number next round if missing
378
- # - note: only if greater/bigger than last; use max
379
- # - note: last_round_pos might be nil - thus set to 0
380
- if pos > 999000
381
- # note: do NOT update last_round_pos for to-be-patched rounds
382
- else
383
- @last_round_pos = [pos,@last_round_pos||0].max
384
- end
385
-
386
-
387
- title = find_round_header_title!( line )
388
-
389
- ## NB: use extracted round title for knockout check
390
- knockout_flag = is_knockout_round?( title )
391
-
392
-
393
- if group_pos.present?
394
- @group = Group.find_by_event_id_and_pos!( @event.id, group_pos )
395
- else
396
- @group = nil # reset group to no group
397
- end
398
-
399
- logger.debug " line: >#{line}<"
400
-
401
- ## NB: dummy/placeholder start_at, end_at date
402
- ## replace/patch after adding all games for round
403
-
404
- round_attribs = {
405
- title: title,
406
- title2: title2,
407
- knockout: knockout_flag
408
- }
409
-
410
- if pos > 999000
411
- # no pos (e.g. will get autonumbered later) - try match by title for now
412
- # e.g. lets us use title 'Group Replays', for example, multiple times
413
- @round = Round.find_by_event_id_and_title( @event.id, title )
414
- else
415
- @round = Round.find_by_event_id_and_pos( @event.id, pos )
416
- end
417
-
418
- if @round.present?
419
- logger.debug "update round #{@round.id}:"
420
- else
421
- logger.debug "create round:"
422
- @round = Round.new
423
-
424
- round_attribs = round_attribs.merge( {
425
- event_id: @event.id,
426
- pos: pos,
427
- start_at: Date.parse('1911-11-11'),
428
- end_at: Date.parse('1911-11-11')
429
- })
430
- end
431
-
432
- logger.debug round_attribs.to_json
433
-
434
- @round.update_attributes!( round_attribs )
435
-
436
- @patch_round_ids_pos << @round.id if pos > 999000
437
- ### store list of round ids for patching start_at/end_at at the end
438
- @patch_round_ids_dates << @round.id # todo/fix/check: check if round has definition (do NOT patch if definition (not auto-added) present)
439
- end
440
-
441
-
442
- def try_parse_game( line )
443
- # note: clone line; for possible test do NOT modify in place for now
444
- # note: returns true if parsed, false if no match
445
- parse_game( line.dup )
446
- end
447
-
448
- def parse_game( line )
449
- logger.debug "parsing game (fixture) line: >#{line}<"
450
-
451
- @mapper_teams.map_teams!( line ) ### todo/fix: limit mapping to two(2) teams - why? why not? might avoid matching @ Barcelona ??
452
- team_keys = @mapper_teams.find_teams!( line )
453
- team1_key = team_keys[0]
454
- team2_key = team_keys[1]
455
-
456
- ## note: if we do NOT find two teams; return false - no match found
457
- if team1_key.nil? || team2_key.nil?
458
- logger.debug " no game match (two teams required) found for line: >#{line}<"
459
- return false
460
- end
461
-
462
- pos = find_game_pos!( line )
463
-
464
- if is_postponed?( line )
465
- postponed = true
466
- date_v2 = find_date!( line, start_at: @event.start_at )
467
- date = find_date!( line, start_at: @event.start_at )
468
- else
469
- postponed = false
470
- date_v2 = nil
471
- date = find_date!( line, start_at: @event.start_at )
472
- end
473
-
474
- ###
475
- # check if date found?
476
- # NB: ruby falsey is nil & false only (not 0 or empty array etc.)
477
- if date
478
- ### check: use date_v2 if present? why? why not?
479
- @last_date = date # keep a reference for later use
480
- else
481
- date = @last_date # no date found; (re)use last seen date
482
- end
483
-
484
-
485
- scores = find_scores!( line )
486
-
487
-
488
- ####
489
- # note:
490
- # only map ground if we got any grounds (setup/configured in event)
491
-
492
- if @event.grounds.count > 0
493
-
494
- ## todo/check: use @known_grounds for check?? why? why not??
495
- ## use in @known_grounds = TextUtils.build_title_table_for( @event.grounds )
496
-
497
- ##
498
- # fix: mark mapped title w/ type (ground-) or such!! - too avoid fallthrough match
499
- # e.g. three teams match - but only two get mapped, third team gets match for ground
500
- # e.g Somalia v Djibouti @ Djibouti
501
- map_ground!( line )
502
- ground_key = find_ground!( line )
503
- ground = ground_key.nil? ? nil : Ground.find_by_key!( ground_key )
504
- else
505
- # no grounds configured; always nil
506
- ground = nil
507
- end
508
-
509
- logger.debug " line: >#{line}<"
510
-
511
-
512
- ### todo: cache team lookups in hash?
513
-
514
- team1 = Team.find_by_key!( team1_key )
515
- team2 = Team.find_by_key!( team2_key )
516
-
517
- @last_team1 = team1 # store for later use for goals etc.
518
- @last_team2 = team2
519
-
520
-
521
- if @round.nil?
522
- ## no round header found; calculate round from date
523
-
524
- ###
525
- ## todo/fix: add some unit tests for round look up
526
- # fix: use date_v2 if present!! (old/original date; otherwise use date)
527
-
528
- #
529
- # fix: check - what to do with hours e.g. start_at use 00:00 and for end_at use 23.59 ??
530
- # -- for now - remove hours (e.g. use end_of_day and beginnig_of_day)
531
-
532
- ##
533
- # note: start_at and end_at are dates ONLY (note datetime)
534
- # - do NOT pass in hours etc. in query
535
- # again use --> date.end_of_day, date.beginning_of_day
536
- # new: not working: date.to_date, date.to_date
537
- # will not find round if start_at same as date !! (in theory hours do not matter)
538
-
539
- ###
540
- # hack:
541
- # special case for sqlite3 (date compare not working reliable; use casts)
542
- # fix: move to adapter_name to activerecord_utils as sqlite? or similar?
543
-
544
- if ActiveRecord::Base.connection.adapter_name.downcase.starts_with?( 'sqlite' )
545
- logger.debug( " [sqlite] using sqlite-specific query for date compare for rounds finder" )
546
- round = Round.where( 'event_id = ? AND ( julianday(start_at) <= julianday(?)'+
547
- 'AND julianday(end_at) >= julianday(?))',
548
- @event.id, date.to_date, date.to_date).first
549
- else # all other dbs (postgresql, mysql, etc.)
550
- round = Round.where( 'event_id = ? AND (start_at <= ? AND end_at >= ?)',
551
- @event.id, date.to_date, date.to_date).first
552
- end
553
-
554
- pp round
555
- if round.nil?
556
- logger.warn( " !!!! no round match found for date #{date}" )
557
- pp Round.all
558
-
559
- ###################################
560
- # -- try auto-adding matchday
561
- round = Round.new
562
-
563
- round_attribs = {
564
- event_id: @event.id,
565
- title: "Matchday #{date.to_date}",
566
- pos: 999001+@patch_round_ids_pos.length, # e.g. 999<count> - 999001,999002,etc.
567
- start_at: date.to_date,
568
- end_at: date.to_date
569
- }
570
-
571
- logger.info( " auto-add round >Matchday #{date.to_date}<" )
572
- logger.debug round_attribs.to_json
573
-
574
- round.update_attributes!( round_attribs )
575
-
576
- @patch_round_ids_pos << round.id # todo/check - add just id or "full" record as now - why? why not?
577
- end
578
-
579
- # store pos for auto-number next round if missing
580
- # - note: only if greater/bigger than last; use max
581
- # - note: last_round_pos might be nil - thus set to 0
582
- if round.pos > 999000
583
- # note: do NOT update last_round_pos for to-be-patched rounds
584
- else
585
- @last_round_pos = [round.pos,@last_round_pos||0].max
586
- end
587
-
588
- ## note: will crash (round.pos) if round is nil
589
- logger.debug( " using round #{round.pos} >#{round.title}< start_at: #{round.start_at}, end_at: #{round.end_at}" )
590
- else
591
- ## use round from last round header
592
- round = @round
593
- end
594
-
595
-
596
- ### check if games exists
597
- ## with this teams in this round if yes only update
598
- game = Game.find_by_round_id_and_team1_id_and_team2_id(
599
- round.id, team1.id, team2.id
600
- )
601
-
602
- game_attribs = {
603
- score1i: scores[0],
604
- score2i: scores[1],
605
- score1: scores[2],
606
- score2: scores[3],
607
- score1et: scores[4],
608
- score2et: scores[5],
609
- score1p: scores[6],
610
- score2p: scores[7],
611
- play_at: date,
612
- play_at_v2: date_v2,
613
- postponed: postponed,
614
- knockout: round.knockout, ## note: for now always use knockout flag from round - why? why not??
615
- ground_id: ground.present? ? ground.id : nil,
616
- group_id: @group.present? ? @group.id : nil
617
- }
618
-
619
- game_attribs[ :pos ] = pos if pos.present?
620
-
621
- ####
622
- # note: only update if any changes (or create if new record)
623
- if game.present? &&
624
- game.check_for_changes( game_attribs ) == false
625
- logger.debug " skip update game #{game.id}; no changes found"
626
- else
627
- if game.present?
628
- logger.debug "update game #{game.id}:"
629
- else
630
- logger.debug "create game:"
631
- game = Game.new
632
-
633
- more_game_attribs = {
634
- round_id: round.id,
635
- team1_id: team1.id,
636
- team2_id: team2.id
637
- }
638
-
639
- ## NB: use round.games.count for pos
640
- ## lets us add games out of order if later needed
641
- more_game_attribs[ :pos ] = round.games.count+1 if pos.nil?
642
-
643
- game_attribs = game_attribs.merge( more_game_attribs )
644
- end
645
-
646
- logger.debug game_attribs.to_json
647
- game.update_attributes!( game_attribs )
648
- end
649
-
650
- @last_game = game # store for later reference (e.g. used for goals etc.)
651
-
652
- return true # game match found
653
- end # method parse_game
654
-
655
-
656
- def try_parse_date_header( line )
657
- # note: clone line; for possible test do NOT modify in place for now
658
- # note: returns true if parsed, false if no match
659
- parse_date_header( line.dup )
660
- end
661
-
662
- def parse_date_header( line )
663
- # note: returns true if parsed, false if no match
664
-
665
- # line with NO teams plus include date e.g.
666
- # [Fri Jun/17] or
667
- # Jun/17 or
668
- # Jun/17: etc.
669
-
670
-
671
- @mapper_teams.map_teams!( line )
672
- team_keys = @mapper_teams.find_teams!( line )
673
- team1_key = team_keys[0]
674
- team2_key = team_keys[1]
675
-
676
- date = find_date!( line, start_at: @event.start_at )
677
-
678
- if date && team1_key.nil? && team2_key.nil?
679
- logger.debug( "date header line found: >#{line}<")
680
- logger.debug( " date: #{date}")
681
-
682
- @last_date = date # keep a reference for later use
683
- return true
684
- else
685
- return false
686
- end
687
- end
688
-
689
-
690
- def parse_goals( line )
691
- logger.debug "parsing goals (fixture) line: >#{line}<"
692
-
693
- goals = GoalsFinder.new.find!( line )
694
-
695
- ## check if squads/rosters present for player mappings
696
- #
697
- squad1_count = Roster.where( event_id: @event.id, team_id: @last_team1 ).count
698
- if squad1_count > 0
699
- squad1 = Roster.where( event_id: @event.id, team_id: @last_team1 )
700
- else
701
- squad1 = []
702
- end
703
-
704
- squad2_count = Roster.where( event_id: @event.id, team_id: @last_team2 ).count
705
- if squad2_count > 0
706
- squad2 = Roster.where( event_id: @event.id, team_id: @last_team2 )
707
- else
708
- squad2 = []
709
- end
710
-
711
- #####
712
- # todo/fix: try lookup by squads first!!!
713
- # issue warning if player not included in squad!!
714
-
715
- ##########
716
- # try mapping player names to player
717
-
718
- ## note: first delete all goals for match (and recreate new ones
719
- # no need to figure out update/merge strategy)
720
- @last_game.goals.delete_all
721
-
722
-
723
- goals.each do |goal|
724
- player_name = goal.name
725
-
726
- player = Person.where( name: player_name ).first
727
- if player
728
- logger.info " player match (name eq) - using player key #{player.key}"
729
- else
730
- # try like match (player name might only include part of name e.g. Messi)
731
- # try three variants
732
- # try %Messi
733
- # try Messi%
734
- # try %Messi% -- check if there's an easier way w/ "one" where clause?
735
- player = Person.where( 'name LIKE ? OR name LIKE ? OR name LIKE ?',
736
- "%#{player_name}",
737
- "#{player_name}%",
738
- "%#{player_name}%"
739
- ).first
740
-
741
- if player
742
- logger.info " player match (name like) - using player key #{player.key}"
743
- else
744
- # try synonyms
745
- player = Person.where( 'synonyms LIKE ? OR synonyms LIKE ? OR synonyms LIKE ?',
746
- "%#{player_name}",
747
- "#{player_name}%",
748
- "%#{player_name}%"
749
- ).first
750
- if player
751
- logger.info " player match (synonyms like) - using player key #{player.key}"
752
- else
753
- # auto-create player (player not found)
754
- logger.info " player NOT found >#{player_name}< - auto-create"
755
-
756
- ## fix: add auto flag (for auto-created persons/players)
757
- ## fix: move title_to_key logic to person model etc.
758
- player_key = TextUtils.title_to_key( player_name )
759
- player_attribs = {
760
- key: player_key,
761
- title: player_name
762
- }
763
- logger.info " using attribs: #{player_attribs.inspect}"
764
-
765
- player = Person.create!( player_attribs )
766
- end
767
- end
768
- end
769
-
770
- goal_attribs = {
771
- game_id: @last_game.id,
772
- team_id: goal.team == 1 ? @last_team1.id : @last_team2.id,
773
- person_id: player.id,
774
- minute: goal.minute,
775
- offset: goal.offset,
776
- penalty: goal.penalty,
777
- owngoal: goal.owngoal,
778
- score1: goal.score1,
779
- score2: goal.score2
780
- }
781
-
782
- logger.info " adding goal using attribs: #{goal_attribs.inspect}"
783
- Goal.create!( goal_attribs )
784
- end # each goals
785
-
786
- end # method parse_goals
787
-
788
-
789
- =begin
790
- ###### add to person and use!!!
791
- def self.create_or_update_from_values( values, more_attribs={} )
792
- ## key & title required
793
-
794
- attribs, more_values = find_key_n_title( values )
795
- attribs = attribs.merge( more_attribs )
796
-
797
- ## check for optional values
798
- Person.create_or_update_from_attribs( attribs, more_values )
799
- end
800
- =end
801
-
802
-
803
- def parse_fixtures( reader )
804
-
805
- reader.each_line do |line|
806
-
807
- if is_goals?( line )
808
- parse_goals( line )
809
- elsif is_round_def?( line )
810
- ## todo/fix: add round definition (w begin n end date)
811
- ## todo: do not patch rounds with definition (already assume begin/end date is good)
812
- ## -- how to deal with matches that get rescheduled/postponed?
813
- parse_round_def( line )
814
- elsif is_round?( line )
815
- parse_round_header( line )
816
- elsif is_group_def?( line ) ## NB: group goes after round (round may contain group marker too)
817
- ### todo: add pipe (|) marker (required)
818
- parse_group_def( line )
819
- elsif is_group?( line )
820
- ## -- lets you set group e.g. Group A etc.
821
- parse_group_header( line )
822
- elsif try_parse_game( line )
823
- # do nothing here
824
- elsif try_parse_date_header( line )
825
- # do nothing here
826
- else
827
- logger.info "skipping line (no match found): >#{line}<"
828
- end
829
- end # lines.each
830
-
831
- ###########################
832
- # backtrack and patch round pos and round dates (start_at/end_at)
833
- # note: patch dates must go first! (otherwise sort_by_date will not work for round pos)
834
-
835
- unless @patch_round_ids_dates.empty?
836
- ###
837
- # fix: do NOT patch if auto flag is set to false !!!
838
- # e.g. rounds got added w/ round def (not w/ round header)
839
-
840
- # note: use uniq - to allow multiple round headers (possible?)
841
-
842
- Round.find( @patch_round_ids_dates.uniq ).each do |r|
843
- logger.debug "patch round start_at/end_at date for #{r.title}:"
844
-
845
- ## note:
846
- ## will add "scope" pos first e.g
847
- #
848
- ## SELECT "games".* FROM "games" WHERE "games"."round_id" = ?
849
- # ORDER BY pos, play_at asc [["round_id", 7]]
850
- # thus will NOT order by play_at but by pos first!!!
851
- # =>
852
- # need to unscope pos!!! or use unordered_games - games_by_play_at_date etc.??
853
- # thus use reorder()!!! - not just order('play_at asc')
854
-
855
- games = r.games.reorder( 'play_at asc' ).all
856
-
857
- ## skip rounds w/ no games
858
-
859
- ## todo/check/fix: what's the best way for checking assoc w/ 0 recs?
860
- next if games.size == 0
861
-
862
- # note: make sure start_at/end_at is date only (e.g. use play_at.to_date)
863
- # sqlite3 saves datetime in date field as datetime, for example (will break date compares later!)
864
-
865
- round_attribs = {
866
- start_at: games[0].play_at.to_date, # use games.first ?
867
- end_at: games[-1].play_at.to_date # use games.last ? why? why not?
868
- }
869
-
870
- logger.debug round_attribs.to_json
871
- r.update_attributes!( round_attribs )
872
- end
873
- end
874
-
875
- unless @patch_round_ids_pos.empty?
876
-
877
- # step 0: check for offset (last_round_pos)
878
- if @last_round_pos
879
- offset = @last_round_pos
880
- logger.info " +++ patch round pos - use offset; start w/ #{offset}"
881
- else
882
- offset = 0
883
- logger.debug " patch round pos - no offset; start w/ 0"
884
- end
885
-
886
- # step 1: sort by date
887
- # step 2: update pos
888
- # note: use uniq - to allow multiple round headers (possible?)
889
- Round.order( 'start_at asc').find( @patch_round_ids_pos.uniq ).each_with_index do |r,idx|
890
- # note: starts counting w/ zero(0)
891
- logger.debug "[#{idx+1}] patch round pos >#{offset+idx+1}< for #{r.title}:"
892
- round_attribs = {
893
- pos: offset+idx+1
894
- }
895
-
896
- # update title if Matchday XXXX e.g. use Matchday 1 etc.
897
- if r.title.starts_with?('Matchday')
898
- round_attribs[:title] = "Matchday #{offset+idx+1}"
899
- end
900
-
901
- logger.debug round_attribs.to_json
902
- r.update_attributes!( round_attribs )
903
-
904
- # update last_round_pos offset too
905
- @last_round_pos = [offset+idx+1,@last_round_pos||0].max
906
- end
907
- end
908
-
909
- end # method parse_fixtures
910
-
911
- end # class GameReader
912
- end # module SportDb