sportdb-quick 0.5.3 → 0.8.0
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/CHANGELOG.md +1 -1
- data/Manifest.txt +12 -4
- data/README.md +4 -5
- data/Rakefile +3 -3
- data/lib/sportdb/quick/match_tree/goal.rb +67 -0
- data/lib/sportdb/quick/match_tree/group.rb +23 -0
- data/lib/sportdb/quick/match_tree/match.rb +249 -0
- data/lib/sportdb/quick/match_tree/round.rb +34 -0
- data/lib/sportdb/quick/match_tree-helpers.rb +81 -0
- data/lib/sportdb/quick/match_tree.rb +126 -0
- data/lib/sportdb/quick/match_tree_on/on_date_header.rb +45 -0
- data/lib/sportdb/quick/match_tree_on/on_goal_line.rb +95 -0
- data/lib/sportdb/quick/match_tree_on/on_group_def.rb +27 -0
- data/lib/sportdb/quick/match_tree_on/on_match_line.rb +195 -0
- data/lib/sportdb/quick/match_tree_on/on_round_def.rb +85 -0
- data/lib/sportdb/quick/match_tree_on/on_round_outline.rb +104 -0
- data/lib/sportdb/quick/quick_match_reader.rb +97 -100
- data/lib/sportdb/quick/version.rb +2 -2
- data/lib/sportdb/quick.rb +17 -21
- metadata +19 -25
- data/lib/sportdb/quick/match_parser.rb +0 -654
- data/lib/sportdb/quick/outline.rb +0 -96
- data/lib/sportdb/quick/outline_reader.rb +0 -98
- data/lib/sportdb/quick/quick_league_outline.rb +0 -123
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module SportDb
|
|
2
|
+
class MatchTree
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def on_date_header( node )
|
|
8
|
+
_trace( "date header: >#{node}<")
|
|
9
|
+
|
|
10
|
+
date = _build_date( m: node.date[:m],
|
|
11
|
+
d: node.date[:d],
|
|
12
|
+
y: node.date[:y],
|
|
13
|
+
yy: node.date[:yy],
|
|
14
|
+
wday: node.date[:wday],
|
|
15
|
+
start: @start,
|
|
16
|
+
last_year: true )
|
|
17
|
+
|
|
18
|
+
_trace( " date: #{date} with start: #{@start}")
|
|
19
|
+
|
|
20
|
+
@last_date = date # keep a reference for later use
|
|
21
|
+
@last_time = nil
|
|
22
|
+
|
|
23
|
+
### quick "corona" hack - support seasons going beyond 12 month (see swiss league 2019/20 and others!!)
|
|
24
|
+
## find a better way??
|
|
25
|
+
## set @start date to full year (e.g. 1.1.) if date.year is @start.year+1
|
|
26
|
+
## todo/fix: add to linter to check for chronological dates!! - warn if NOT chronological
|
|
27
|
+
### todo/check: just turn on for 2019/20 season or always? why? why not?
|
|
28
|
+
|
|
29
|
+
## todo/fix: add switch back to old @start_org
|
|
30
|
+
## if year is date.year == @start.year-1 -- possible when full date with year set!!!
|
|
31
|
+
=begin
|
|
32
|
+
if @start.month != 1
|
|
33
|
+
if date.year == @start.year+1
|
|
34
|
+
_trace( "!! hack - extending start date to full (next/end) year; assumes all dates are chronologigal - always moving forward" )
|
|
35
|
+
@start_org = @start ## keep a copy of the original (old) start date - why? why not? - not used for now
|
|
36
|
+
@start = Date.new( @start.year+1, 1, 1 )
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
=end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
end ## class MatchTree
|
|
45
|
+
end ## module SportDb
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module SportDb
|
|
2
|
+
class MatchTree
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def on_goal_line( node )
|
|
6
|
+
_trace( "on goal line: >#{node}<" )
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
if node.goals[0].is_a?( Array )
|
|
10
|
+
goals1, goals2 = node.goals[0], node.goals[1]
|
|
11
|
+
else
|
|
12
|
+
goals1 = node.goals
|
|
13
|
+
goals2 = []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
pp [goals1,goals2] if debug?
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## special rule
|
|
21
|
+
## if goals 2 empty check if score for team 1 is zero
|
|
22
|
+
## and team 2 is NOT zero than
|
|
23
|
+
## make goals1 goald2!!
|
|
24
|
+
## e.g. Norway 0-1 Austria
|
|
25
|
+
## (Hof 32)
|
|
26
|
+
|
|
27
|
+
if goals2.empty? && !goals1.empty?
|
|
28
|
+
|
|
29
|
+
match = @matches[-1]
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
## todo/fix
|
|
33
|
+
## move upstream
|
|
34
|
+
## use score1_zero? or such - why? why not?
|
|
35
|
+
if (match.score.is_a?(Array) && match.score[0] == 0 ) ||
|
|
36
|
+
(match.score.is_a?(Hash) && match.score[:et] && match.score[:et][0] == 0) ||
|
|
37
|
+
(match.score.is_a?(Hash) && match.score[:et].nil? &&
|
|
38
|
+
match.score[:ft] && match.score[:ft][0] == 0)
|
|
39
|
+
## "parallel assignment (or multiple assignment") - swap values in single line
|
|
40
|
+
goals2, goals1 = goals1, goals2
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
## todo/fix - sort goals by minute (+offset) !!!
|
|
48
|
+
|
|
49
|
+
goals = []
|
|
50
|
+
|
|
51
|
+
goals1.each do |rec|
|
|
52
|
+
rec.minutes.each do |minute|
|
|
53
|
+
goal = Goal.new(
|
|
54
|
+
player: rec.player,
|
|
55
|
+
team: 1,
|
|
56
|
+
minute: minute.m,
|
|
57
|
+
offset: minute.offset,
|
|
58
|
+
penalty: minute.pen || false, # note: pass along/use false NOT nil
|
|
59
|
+
owngoal: minute.og || false
|
|
60
|
+
)
|
|
61
|
+
goals << goal
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
goals2.each do |rec|
|
|
66
|
+
rec.minutes.each do |minute|
|
|
67
|
+
goal = Goal.new(
|
|
68
|
+
player: rec.player,
|
|
69
|
+
team: 2,
|
|
70
|
+
minute: minute.m,
|
|
71
|
+
offset: minute.offset,
|
|
72
|
+
penalty: minute.pen || false, # note: pass along/use false NOT nil
|
|
73
|
+
owngoal: minute.og || false
|
|
74
|
+
)
|
|
75
|
+
goals << goal
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
pp goals if debug?
|
|
80
|
+
|
|
81
|
+
## quick & dirty - auto add goals to last match
|
|
82
|
+
## note - for hacky (quick& dirty) multi-line support
|
|
83
|
+
## always append for now
|
|
84
|
+
match = @matches[-1]
|
|
85
|
+
match.goals ||= []
|
|
86
|
+
match.goals += goals
|
|
87
|
+
|
|
88
|
+
## todo/fix
|
|
89
|
+
## sort by minute
|
|
90
|
+
## PLUS auto-fill score1,score2 - why? why not?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
end ## class MatchTree
|
|
95
|
+
end ## module SportDb
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module SportDb
|
|
2
|
+
class MatchTree
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def on_group_def( node )
|
|
6
|
+
_trace( "on group def: >#{node}<" )
|
|
7
|
+
|
|
8
|
+
## e.g
|
|
9
|
+
## [:group_def, "Group A"],
|
|
10
|
+
## [:team, "Germany"],
|
|
11
|
+
## [:team, "Scotland"],
|
|
12
|
+
## [:team, "Hungary"],
|
|
13
|
+
## [:team, "Switzerland"]
|
|
14
|
+
|
|
15
|
+
node.teams.each do |team|
|
|
16
|
+
@teams[ team ] += 1
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
group = Group.new( name: node.name,
|
|
20
|
+
teams: node.teams )
|
|
21
|
+
|
|
22
|
+
@groups[ node.name ] = group
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
end ## class MatchTree
|
|
27
|
+
end ## module SportDb
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
module SportDb
|
|
2
|
+
class MatchTree
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def on_match_line( node )
|
|
7
|
+
_trace( "on match: >#{node}<" )
|
|
8
|
+
|
|
9
|
+
## collect (possible) nodes by type
|
|
10
|
+
num = nil
|
|
11
|
+
num = node.num if node.num
|
|
12
|
+
|
|
13
|
+
date = nil
|
|
14
|
+
date = _build_date( m: node.date[:m],
|
|
15
|
+
d: node.date[:d],
|
|
16
|
+
y: node.date[:y],
|
|
17
|
+
yy: node.date[:yy],
|
|
18
|
+
wday: node.date[:wday],
|
|
19
|
+
start: @start,
|
|
20
|
+
last_year: true ) if node.date
|
|
21
|
+
|
|
22
|
+
## note - there's no time (-only) type in ruby
|
|
23
|
+
## use string (e.g. '14:56', '1:44')
|
|
24
|
+
## use 01:44 or 1:44 ?
|
|
25
|
+
## check for 0:00 or 24:00 possible?
|
|
26
|
+
time = nil
|
|
27
|
+
if node.time
|
|
28
|
+
time = ('%d:%02d' % [node.time[:h], node.time[:m]])
|
|
29
|
+
## check for timezone
|
|
30
|
+
time += " #{node.time[:timezone]}" if node.time[:timezone]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
## todo/fix -
|
|
36
|
+
## keep time & time_local as pairs for @last_time/@last_time_local
|
|
37
|
+
## - check for timezone
|
|
38
|
+
## incl. timezone in time (string) - why? why not?
|
|
39
|
+
time_local = nil
|
|
40
|
+
if node.time_local
|
|
41
|
+
time_local = ('%d:%02d' % [node.time_local[:h], node.time_local[:m]])
|
|
42
|
+
time_local += " #{node.time_local[:timezone]}" if node.time_local[:timezone]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### todo/fix
|
|
47
|
+
## add keywords (e.g. ht, ft or such) to Score.new - why? why not?
|
|
48
|
+
## or use new Score.build( ht:, ft:, ) or such - why? why not?
|
|
49
|
+
## pp score
|
|
50
|
+
score = nil
|
|
51
|
+
score = node.score if node.score
|
|
52
|
+
|
|
53
|
+
## if node.score.is_a?(Array)
|
|
54
|
+
## ## assume "undefined" score
|
|
55
|
+
## score = node.score
|
|
56
|
+
## else ## (default) assume Hash
|
|
57
|
+
## # ht = node.score[:ht] || [nil,nil]
|
|
58
|
+
## # ft = node.score[:ft] || [nil,nil]
|
|
59
|
+
## # et = node.score[:et] || [nil,nil]
|
|
60
|
+
## # p = node.score[:p] || [nil,nil]
|
|
61
|
+
## # values = [*ht, *ft, *et, *p]
|
|
62
|
+
## # pp values
|
|
63
|
+
## ## pp node.score
|
|
64
|
+
## score = node.score
|
|
65
|
+
## end
|
|
66
|
+
## end
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
status = nil
|
|
70
|
+
status = node.status if node.status ### assume text for now
|
|
71
|
+
## if node_type == :status # e.g. awarded, canceled, postponed, etc.
|
|
72
|
+
## status = node[1]
|
|
73
|
+
#
|
|
74
|
+
## todo - add ## find (optional) match status e.g. [abandoned] or [replay] or [awarded]
|
|
75
|
+
## or [cancelled] or [postponed] etc.
|
|
76
|
+
## status = find_status!( line ) ## todo/check: allow match status also in geo part (e.g. after @) - why? why not?
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
team1 = node.team1
|
|
81
|
+
team2 = node.team2
|
|
82
|
+
|
|
83
|
+
@teams[ team1 ] += 1
|
|
84
|
+
@teams[ team2 ] += 1
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
if node.header ## note - date/time for matches (w/ header) CANNOT get inherited!!
|
|
88
|
+
@last_date = nil
|
|
89
|
+
@last_time = nil
|
|
90
|
+
else ## no (match header), use date/time inheritance rules
|
|
91
|
+
###
|
|
92
|
+
# check if date found?
|
|
93
|
+
# note: ruby falsey is nil & false only (not 0 or empty array etc.)
|
|
94
|
+
if date
|
|
95
|
+
### check: use date_v2 if present? why? why not?
|
|
96
|
+
@last_date = date # keep a reference for later use
|
|
97
|
+
@last_time = nil
|
|
98
|
+
# @last_time = nil
|
|
99
|
+
else
|
|
100
|
+
date = @last_date # no date found; (re)use last seen date
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
if time
|
|
104
|
+
@last_time = time
|
|
105
|
+
else
|
|
106
|
+
time = @last_time
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
group = nil
|
|
113
|
+
group = @last_group if @last_group
|
|
114
|
+
|
|
115
|
+
round = nil
|
|
116
|
+
round = @last_round if @last_round
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
### try auto-fill round
|
|
120
|
+
## find (first) matching round by date if rounds / matchdays defined
|
|
121
|
+
## if not rounds / matchdays defined - YES, allow matches WITHOUT rounds!!!
|
|
122
|
+
if date && round.nil?
|
|
123
|
+
if @rounds.size > 0
|
|
124
|
+
@rounds.values.each do |round_rec|
|
|
125
|
+
## note: convert date to date only (no time) with to_date!!!
|
|
126
|
+
if (round_rec.start_date && round_rec.end_date) &&
|
|
127
|
+
(date.to_date >= round_rec.start_date &&
|
|
128
|
+
date.to_date <= round_rec.end_date)
|
|
129
|
+
round = round_rec
|
|
130
|
+
break
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
if round.nil?
|
|
134
|
+
## todo/fix - issue a warning (do NOT stop)
|
|
135
|
+
puts "!! PARSE ERROR - no matching round found for match date:"
|
|
136
|
+
pp date
|
|
137
|
+
exit 1
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
## todo/check: scores are integers or strings?
|
|
144
|
+
|
|
145
|
+
## todo/check: pass along round and group refs or just string (canonical names) - why? why not?
|
|
146
|
+
|
|
147
|
+
## split date in date & time if DateTime
|
|
148
|
+
=begin
|
|
149
|
+
time_str = nil
|
|
150
|
+
date_str = nil
|
|
151
|
+
if date.is_a?( DateTime )
|
|
152
|
+
date_str = date.strftime('%Y-%m-%d')
|
|
153
|
+
time_str = date.strftime('%H:%M')
|
|
154
|
+
elsif date.is_a?( Date )
|
|
155
|
+
date_str = date.strftime('%Y-%m-%d')
|
|
156
|
+
else # assume date is nil
|
|
157
|
+
end
|
|
158
|
+
=end
|
|
159
|
+
|
|
160
|
+
time_str = nil
|
|
161
|
+
time_local_str = nil
|
|
162
|
+
date_str = nil
|
|
163
|
+
|
|
164
|
+
date_str = date.strftime('%Y-%m-%d') if date
|
|
165
|
+
time_str = time if date && time
|
|
166
|
+
time_local_str = time_local if date && time_local
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
ground = nil
|
|
171
|
+
ground = node.geo if node.geo
|
|
172
|
+
|
|
173
|
+
## attendance
|
|
174
|
+
att = nil
|
|
175
|
+
att = node.att if node.att
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@matches << Match.new( num: num,
|
|
179
|
+
date: date_str,
|
|
180
|
+
time: time_str,
|
|
181
|
+
time_local: time_local_str,
|
|
182
|
+
team1: team1, ## note: for now always use mapping value e.g. rec (NOT string e.g. team1.name)
|
|
183
|
+
team2: team2, ## note: for now always use mapping value e.g. rec (NOT string e.g. team2.name)
|
|
184
|
+
score: score,
|
|
185
|
+
round: round ? round.name : nil, ## note: for now always use string (assume unique canonical name for event)
|
|
186
|
+
group: group ? group.name : nil, ## note: for now always use string (assume unique canonical name for event)
|
|
187
|
+
status: status,
|
|
188
|
+
ground: ground,
|
|
189
|
+
att: att )
|
|
190
|
+
### todo: cache team lookups in hash?
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
end ## class MatchTree
|
|
195
|
+
end ## module SportDb
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
module SportDb
|
|
2
|
+
class MatchTree
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def on_round_def( node )
|
|
6
|
+
_trace( "on round def: >#{node}<" )
|
|
7
|
+
|
|
8
|
+
## e.g. [[:round_def, "Matchday 1"], [:duration, "Fri Jun 14 - Tue Jun 18"]]
|
|
9
|
+
## [[:round_def, "Matchday 2"], [:duration, "Wed Jun 19 - Sat Jun 22"]]
|
|
10
|
+
## [[:round_def, "Matchday 3"], [:duration, "Sun Jun 23 - Wed Jun 26"]]
|
|
11
|
+
|
|
12
|
+
name = node.name
|
|
13
|
+
# NB: use extracted round name for knockout check
|
|
14
|
+
# knockout_flag = is_knockout_round?( name )
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
## note - do NOT update @last_year on round def dates!!
|
|
19
|
+
## only update for running dates in matches!!
|
|
20
|
+
|
|
21
|
+
if node.date
|
|
22
|
+
start_date = end_date = _build_date( m: node.date[:m],
|
|
23
|
+
d: node.date[:d],
|
|
24
|
+
y: node.date[:y],
|
|
25
|
+
yy: node.date[:yy],
|
|
26
|
+
wday: node.date[:wday],
|
|
27
|
+
start: @start,
|
|
28
|
+
last_year: false )
|
|
29
|
+
elsif node.duration
|
|
30
|
+
## reuse year in start date e.g. July 26-27 1930
|
|
31
|
+
## July 26 [1930], [July] 27 1930
|
|
32
|
+
start_date = _build_date( m: node.duration[:start][:m],
|
|
33
|
+
d: node.duration[:start][:d],
|
|
34
|
+
y: node.duration[:start][:y] || node.duration[:end][:y],
|
|
35
|
+
yy: node.duration[:start][:yy] || node.duration[:end][:yy],
|
|
36
|
+
wday: node.duration[:start][:wday],
|
|
37
|
+
start: @start,
|
|
38
|
+
last_year: false )
|
|
39
|
+
|
|
40
|
+
## reuse month in end date e.g. July 26-27
|
|
41
|
+
## July 26, [July] 27
|
|
42
|
+
end_date = _build_date( m: node.duration[:end][:m] || node.duration[:start][:m],
|
|
43
|
+
d: node.duration[:end][:d],
|
|
44
|
+
y: node.duration[:end][:y],
|
|
45
|
+
yy: node.duration[:end][:yy],
|
|
46
|
+
wday: node.duration[:end][:wday],
|
|
47
|
+
start: @start,
|
|
48
|
+
last_year: false )
|
|
49
|
+
else
|
|
50
|
+
puts "!! PARSE ERROR - expected date or duration for round def; got:"
|
|
51
|
+
pp node
|
|
52
|
+
exit 1
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# note: - NOT needed; start_at and end_at are saved as date only (NOT datetime)
|
|
56
|
+
# set hours,minutes,secs to beginning and end of day (do NOT use default 12.00)
|
|
57
|
+
# e.g. use 00.00 and 23.59
|
|
58
|
+
# start_at = start_at.beginning_of_day
|
|
59
|
+
# end_at = end_at.end_of_day
|
|
60
|
+
|
|
61
|
+
# note: make sure start_at/end_at is date only (e.g. use start_at.to_date)
|
|
62
|
+
# sqlite3 saves datetime in date field as datetime, for example (will break date compares later!)
|
|
63
|
+
|
|
64
|
+
# note - _build_date always returns Date for now - no longer needed!!
|
|
65
|
+
# start_date = start_date.to_date
|
|
66
|
+
# end_date = end_date.to_date
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
_trace( " start_date: #{start_date}" )
|
|
72
|
+
_trace( " end_date: #{end_date}" )
|
|
73
|
+
_trace( " name: >#{name}<" )
|
|
74
|
+
|
|
75
|
+
round = Round.new( name: name,
|
|
76
|
+
start_date: start_date,
|
|
77
|
+
end_date: end_date,
|
|
78
|
+
auto: false )
|
|
79
|
+
|
|
80
|
+
@rounds[ name ] = round
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
end ## class MatchTree
|
|
85
|
+
end ## module SportDb
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
module SportDb
|
|
2
|
+
class MatchTree
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def on_round_outline( node )
|
|
7
|
+
_trace( "on round outline: >#{node}<" )
|
|
8
|
+
|
|
9
|
+
## always reset dates - why? why not?
|
|
10
|
+
## note - needs last_date for year
|
|
11
|
+
## track last_year with extra variable
|
|
12
|
+
|
|
13
|
+
name = node.outline
|
|
14
|
+
level = node.level
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
####
|
|
18
|
+
# check for "old" group header in ("automagic") round outline for now
|
|
19
|
+
##
|
|
20
|
+
## todo/fix - use only names from group def for lookup/is_group match!!!
|
|
21
|
+
## do NOT use (generic) regex!!
|
|
22
|
+
if level == 1 && _is_group?( name )
|
|
23
|
+
_trace( "on group header: >#{node}<" )
|
|
24
|
+
|
|
25
|
+
group = @groups[ name ]
|
|
26
|
+
|
|
27
|
+
if group
|
|
28
|
+
# set group for matches
|
|
29
|
+
@last_group = group
|
|
30
|
+
# note: group header resets (last) round (allows, for example):
|
|
31
|
+
# e.g.
|
|
32
|
+
# Group Playoffs/Replays -- round header
|
|
33
|
+
# team1 team2 -- match
|
|
34
|
+
# Group B -- group header
|
|
35
|
+
# team1 team2 - match (will get new auto-matchday! not last round)
|
|
36
|
+
@last_round = nil
|
|
37
|
+
return ## note - return here; do NOT fall through to std round processing!
|
|
38
|
+
else
|
|
39
|
+
puts "!! WARN - no group def found for >#{name}<; will use a (plain) round"
|
|
40
|
+
end
|
|
41
|
+
end ## is_group?
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
## todo/fix - also reset round name levels on heading 1/2/3 etc.
|
|
46
|
+
## why? why not?
|
|
47
|
+
|
|
48
|
+
if level == 1
|
|
49
|
+
@last_round_name1 = name
|
|
50
|
+
@last_round_name2 = nil
|
|
51
|
+
@last_round_name3 = nil
|
|
52
|
+
elsif level == 2
|
|
53
|
+
@last_round_name2 = name
|
|
54
|
+
@last_round_name3 = nil
|
|
55
|
+
name = [@last_round_name1, name].join( ', ' )
|
|
56
|
+
elsif level == 3
|
|
57
|
+
@last_round_name3 == name
|
|
58
|
+
name = [@last_round_name1, @last_round_name2, name].join( ', ')
|
|
59
|
+
else
|
|
60
|
+
puts "!! ERROR - unsupported round outline level #{level}; use 1-3 - sorry"
|
|
61
|
+
exit 1
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
round = @rounds[ name ]
|
|
66
|
+
if round.nil? ## auto-add / create if missing
|
|
67
|
+
round = Round.new( name: name )
|
|
68
|
+
@rounds[ name ] = round
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
@last_round = round
|
|
72
|
+
@last_group = nil # note: always reset group to no group - why? why not?
|
|
73
|
+
|
|
74
|
+
## todo/fix/check
|
|
75
|
+
## make round a scope for date(time) - why? why not?
|
|
76
|
+
## reset date/time e.g. @last_date = nil !!!!
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
###
|
|
82
|
+
## helpers
|
|
83
|
+
|
|
84
|
+
##
|
|
85
|
+
## note - do NOT match group phase or group playoff or such
|
|
86
|
+
## for now only works for group a,b,c or group 1, group 2, etc.
|
|
87
|
+
|
|
88
|
+
GROUP_RE = %r{\A
|
|
89
|
+
Group [ ] (?:
|
|
90
|
+
[a-z]
|
|
91
|
+
| \d+
|
|
92
|
+
)
|
|
93
|
+
\z}ix
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _is_group?( text )
|
|
97
|
+
## use regex for match
|
|
98
|
+
GROUP_RE.match?( text )
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
end ## class MatchTree
|
|
104
|
+
end ## module SportDb
|