sportdb-writers 0.4.3 → 0.5.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 -2
- data/Manifest.txt +3 -2
- data/lib/sportdb/writers/{goals.rb → build_goals.rb} +46 -0
- data/lib/sportdb/writers/build_stats.rb +95 -0
- data/lib/sportdb/writers/rounds.rb +26 -0
- data/lib/sportdb/writers/txt_writer.rb +74 -215
- data/lib/sportdb/writers/version.rb +2 -2
- data/lib/sportdb/writers.rb +20 -24
- metadata +5 -4
- data/lib/sportdb/writers/txt_writer_v2.rb +0 -188
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fd14b82e447eaf5824ab5b9636b9a91decee9d0962bb4c1b43d60e38c48e8a7e
|
|
4
|
+
data.tar.gz: 1b93a17a72cff8cab52b5f40929d57bbb3fa8c0d84a51ee0dc6b33b34028c4ae
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ef84ebdd48f0751fab889ec66f6a92a22827f192f4ccd9bf52cd6cec0c6c35578dda52c02538964333515f3d006cb2bd68ad63501ffc01218be88cf7f20ee54f
|
|
7
|
+
data.tar.gz: d0313c242c59d62aa6b9874acd0e16a35142e1945d6100d8d8a021544266ca548c6b9819856118781f58f72b2d84a9137f1d1c1b5ea498606961bc2de3bbe57c
|
data/CHANGELOG.md
CHANGED
data/Manifest.txt
CHANGED
|
@@ -3,7 +3,8 @@ Manifest.txt
|
|
|
3
3
|
README.md
|
|
4
4
|
Rakefile
|
|
5
5
|
lib/sportdb/writers.rb
|
|
6
|
-
lib/sportdb/writers/
|
|
6
|
+
lib/sportdb/writers/build_goals.rb
|
|
7
|
+
lib/sportdb/writers/build_stats.rb
|
|
8
|
+
lib/sportdb/writers/rounds.rb
|
|
7
9
|
lib/sportdb/writers/txt_writer.rb
|
|
8
|
-
lib/sportdb/writers/txt_writer_v2.rb
|
|
9
10
|
lib/sportdb/writers/version.rb
|
|
@@ -55,4 +55,50 @@ def self.merge_goals( matches, goals )
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
|
|
58
|
+
|
|
59
|
+
def self.build_goals( goals )
|
|
60
|
+
## todo/fix: for now assumes always minutes (without offset) - add offset support
|
|
61
|
+
|
|
62
|
+
## note: "fold" multiple goals by players
|
|
63
|
+
team1_goals = {}
|
|
64
|
+
team2_goals = {}
|
|
65
|
+
goals.each do |goal|
|
|
66
|
+
team_goals = goal.team == 1 ? team1_goals : team2_goals
|
|
67
|
+
player_goals = team_goals[ goal.player ] ||= []
|
|
68
|
+
player_goals << goal
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
buf = String.new
|
|
72
|
+
if team1_goals.size > 0
|
|
73
|
+
buf << build_goals_for_team( team1_goals )
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
## note: only add a separator (;) if BOTH teams have goal scores
|
|
77
|
+
if team1_goals.size > 0 && team2_goals.size > 0
|
|
78
|
+
buf << '; '
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if team2_goals.size > 0
|
|
82
|
+
buf << build_goals_for_team( team2_goals )
|
|
83
|
+
end
|
|
84
|
+
buf
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def self.build_goals_for_team( team_goals )
|
|
89
|
+
buf = String.new
|
|
90
|
+
team_goals.each_with_index do |(player_name, goals),i|
|
|
91
|
+
buf << ' ' if i > 0
|
|
92
|
+
buf << "#{player_name} "
|
|
93
|
+
buf << goals.map do |goal|
|
|
94
|
+
str = "#{goal.minute}'"
|
|
95
|
+
str << "(og)" if goal.owngoal?
|
|
96
|
+
str << "(p)" if goal.penalty?
|
|
97
|
+
str
|
|
98
|
+
end.join( ', ' )
|
|
99
|
+
end
|
|
100
|
+
buf
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
|
|
58
104
|
end # module Writer
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module SportDb
|
|
2
|
+
class TxtMatchWriter
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## helper - to calculate match stats e.g.
|
|
7
|
+
## how many stages, start and end dates, etc.
|
|
8
|
+
def self._calc_stats( matches )
|
|
9
|
+
### check for stages & stats
|
|
10
|
+
stats = { 'stage' => Hash.new(0),
|
|
11
|
+
'date' => { 'start_date' => nil,
|
|
12
|
+
'end_date' => nil, },
|
|
13
|
+
'teams' => Hash.new(0),
|
|
14
|
+
'matches' => 0,
|
|
15
|
+
'use_stages' => false,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
## add matches played stats too??
|
|
19
|
+
## for now only simply count used
|
|
20
|
+
stats['matches'] = matches.size
|
|
21
|
+
|
|
22
|
+
matches.each do |match|
|
|
23
|
+
stage = match.stage
|
|
24
|
+
stage = 'Regular Season' if stage.nil? || stage.empty?
|
|
25
|
+
stats['stage'][ stage ] += 1
|
|
26
|
+
|
|
27
|
+
## note - date for now optional (not required)!!!!
|
|
28
|
+
## only teams for match
|
|
29
|
+
if match.date
|
|
30
|
+
## todo/fix - norm date (parse as Date)
|
|
31
|
+
## check format etc.
|
|
32
|
+
date = if match.date.is_a?( String )
|
|
33
|
+
Date.strptime( match.date, '%Y-%m-%d' )
|
|
34
|
+
else ## assume it's already a date (object)
|
|
35
|
+
match.date
|
|
36
|
+
end
|
|
37
|
+
stats['date']['start_date'] ||= date
|
|
38
|
+
stats['date']['end_date'] ||= date
|
|
39
|
+
|
|
40
|
+
stats['date']['start_date'] = date if date < stats['date']['start_date']
|
|
41
|
+
stats['date']['end_date'] = date if date > stats['date']['end_date']
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
[match.team1, match.team2].each do |team|
|
|
45
|
+
stats['teams'][ team ] += 1 if team && !['N.N.'].include?( team )
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
## add & update use_stage flag
|
|
50
|
+
stats['use_stages'] = if stats['stage'].size >= 2 ||
|
|
51
|
+
(stats['stage'].size == 1 &&
|
|
52
|
+
stats['stage'].keys[0] != 'Regular Season')
|
|
53
|
+
true
|
|
54
|
+
else
|
|
55
|
+
false
|
|
56
|
+
end
|
|
57
|
+
stats
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self._build_stats( stats )
|
|
61
|
+
### add comment header
|
|
62
|
+
buf = String.new
|
|
63
|
+
# e.g. 13 April – 25 September 2024
|
|
64
|
+
# or 16 August 2024 – 25 May 2025
|
|
65
|
+
## note - date is optional!!
|
|
66
|
+
if stats['date']['start_date']
|
|
67
|
+
buf << "# Date "
|
|
68
|
+
start_date = stats['date']['start_date']
|
|
69
|
+
end_date = stats['date']['end_date']
|
|
70
|
+
if start_date.year != end_date.year
|
|
71
|
+
buf << "#{start_date.strftime('%a %b %-d %Y')} - #{end_date.strftime('%a %b %-d %Y')}"
|
|
72
|
+
else
|
|
73
|
+
buf << "#{start_date.strftime('%a %b %-d')} - #{end_date.strftime('%a %b %-d %Y')}"
|
|
74
|
+
end
|
|
75
|
+
buf << " (#{end_date.jd-start_date.jd}d)" ## add days
|
|
76
|
+
buf << "\n"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
buf << "# Teams #{stats['teams'].size}\n"
|
|
80
|
+
buf << "# Matches #{stats['matches']}\n"
|
|
81
|
+
|
|
82
|
+
if stats['use_stages']
|
|
83
|
+
buf << "# Stages "
|
|
84
|
+
stages = stats['stage'].map { |name,count| "#{name} (#{count})" }.join( ' ' )
|
|
85
|
+
buf << stages
|
|
86
|
+
buf << "\n"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
buf
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
end # class TxtMatchWriter
|
|
95
|
+
end # module SportDb
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module SportDb
|
|
2
|
+
class TxtMatchWriter
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## translate from lang x (german, etc) to english
|
|
7
|
+
ROUND_TRANSLATIONS = {
|
|
8
|
+
# de/german
|
|
9
|
+
'1. Runde' => 'Round 1',
|
|
10
|
+
'2. Runde' => 'Round 2',
|
|
11
|
+
'Achtelfinale' => 'Round of 16',
|
|
12
|
+
'Viertelfinale' => 'Quarterfinals',
|
|
13
|
+
'Halbfinale' => 'Semifinals',
|
|
14
|
+
'Finale' => 'Final',
|
|
15
|
+
|
|
16
|
+
'Gruppe A' => 'Group A',
|
|
17
|
+
'Gruppe B' => 'Group B',
|
|
18
|
+
'Gruppe C' => 'Group C',
|
|
19
|
+
'Gruppe D' => 'Group D',
|
|
20
|
+
'Gruppe E' => 'Group E',
|
|
21
|
+
'Gruppe F' => 'Group F',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
end # class TxtMatchWriter
|
|
26
|
+
end # module SportDb
|
|
@@ -2,111 +2,6 @@ module SportDb
|
|
|
2
2
|
class TxtMatchWriter
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
## translate from lang x (german, etc) to english
|
|
6
|
-
ROUND_TRANSLATIONS = {
|
|
7
|
-
# de/german
|
|
8
|
-
'1. Runde' => 'Round 1',
|
|
9
|
-
'2. Runde' => 'Round 2',
|
|
10
|
-
'Achtelfinale' => 'Round of 16',
|
|
11
|
-
'Viertelfinale' => 'Quarterfinals',
|
|
12
|
-
'Halbfinale' => 'Semifinals',
|
|
13
|
-
'Finale' => 'Final',
|
|
14
|
-
|
|
15
|
-
'Gruppe A' => 'Group A',
|
|
16
|
-
'Gruppe B' => 'Group B',
|
|
17
|
-
'Gruppe C' => 'Group C',
|
|
18
|
-
'Gruppe D' => 'Group D',
|
|
19
|
-
'Gruppe E' => 'Group E',
|
|
20
|
-
'Gruppe F' => 'Group F',
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
## helper - to calculate match stats e.g.
|
|
25
|
-
## how many stages, start and end dates, etc.
|
|
26
|
-
def self._calc_stats( matches )
|
|
27
|
-
### check for stages & stats
|
|
28
|
-
stats = { 'stage' => Hash.new(0),
|
|
29
|
-
'date' => { 'start_date' => nil,
|
|
30
|
-
'end_date' => nil, },
|
|
31
|
-
'teams' => Hash.new(0),
|
|
32
|
-
'matches' => 0,
|
|
33
|
-
'use_stages' => false,
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
## add matches played stats too??
|
|
37
|
-
## for now only simply count used
|
|
38
|
-
stats['matches'] = matches.size
|
|
39
|
-
|
|
40
|
-
matches.each do |match|
|
|
41
|
-
stage = match.stage
|
|
42
|
-
stage = 'Regular Season' if stage.nil? || stage.empty?
|
|
43
|
-
stats['stage'][ stage ] += 1
|
|
44
|
-
|
|
45
|
-
## note - date for now optional (not required)!!!!
|
|
46
|
-
## only teams for match
|
|
47
|
-
if match.date
|
|
48
|
-
## todo/fix - norm date (parse as Date)
|
|
49
|
-
## check format etc.
|
|
50
|
-
date = if match.date.is_a?( String )
|
|
51
|
-
Date.strptime( match.date, '%Y-%m-%d' )
|
|
52
|
-
else ## assume it's already a date (object)
|
|
53
|
-
match.date
|
|
54
|
-
end
|
|
55
|
-
stats['date']['start_date'] ||= date
|
|
56
|
-
stats['date']['end_date'] ||= date
|
|
57
|
-
|
|
58
|
-
stats['date']['start_date'] = date if date < stats['date']['start_date']
|
|
59
|
-
stats['date']['end_date'] = date if date > stats['date']['end_date']
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
[match.team1, match.team2].each do |team|
|
|
63
|
-
stats['teams'][ team ] += 1 if team && !['N.N.'].include?( team )
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
## add & update use_stage flag
|
|
68
|
-
stats['use_stages'] = if stats['stage'].size >= 2 ||
|
|
69
|
-
(stats['stage'].size == 1 &&
|
|
70
|
-
stats['stage'].keys[0] != 'Regular Season')
|
|
71
|
-
true
|
|
72
|
-
else
|
|
73
|
-
false
|
|
74
|
-
end
|
|
75
|
-
stats
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def self._build_stats( stats )
|
|
79
|
-
### add comment header
|
|
80
|
-
buf = String.new
|
|
81
|
-
# e.g. 13 April – 25 September 2024
|
|
82
|
-
# or 16 August 2024 – 25 May 2025
|
|
83
|
-
## note - date is optional!!
|
|
84
|
-
if stats['date']['start_date']
|
|
85
|
-
buf << "# Date "
|
|
86
|
-
start_date = stats['date']['start_date']
|
|
87
|
-
end_date = stats['date']['end_date']
|
|
88
|
-
if start_date.year != end_date.year
|
|
89
|
-
buf << "#{start_date.strftime('%a %b/%-d %Y')} - #{end_date.strftime('%a %b/%-d %Y')}"
|
|
90
|
-
else
|
|
91
|
-
buf << "#{start_date.strftime('%a %b/%-d')} - #{end_date.strftime('%a %b/%-d %Y')}"
|
|
92
|
-
end
|
|
93
|
-
buf << " (#{end_date.jd-start_date.jd}d)" ## add days
|
|
94
|
-
buf << "\n"
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
buf << "# Teams #{stats['teams'].size}\n"
|
|
98
|
-
buf << "# Matches #{stats['matches']}\n"
|
|
99
|
-
|
|
100
|
-
if stats['use_stages']
|
|
101
|
-
buf << "# Stages "
|
|
102
|
-
stages = stats['stage'].map { |name,count| "#{name} (#{count})" }.join( ' ' )
|
|
103
|
-
buf << stages
|
|
104
|
-
buf << "\n"
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
buf
|
|
108
|
-
end
|
|
109
|
-
|
|
110
5
|
|
|
111
6
|
## note: build returns buf - an (in-memory) string buf(fer)
|
|
112
7
|
def self.build( matches, rounds: true )
|
|
@@ -114,43 +9,19 @@ def self.build( matches, rounds: true )
|
|
|
114
9
|
raise ArgumentError, "rounds flag - bool expected; got: #{rounds.inspect}" unless rounds.is_a?( TrueClass ) || rounds.is_a?( FalseClass )
|
|
115
10
|
|
|
116
11
|
|
|
117
|
-
###
|
|
12
|
+
### check for stages & stats
|
|
118
13
|
stats = _calc_stats( matches )
|
|
119
14
|
|
|
15
|
+
|
|
120
16
|
buf = String.new
|
|
121
17
|
|
|
122
18
|
### add comment header
|
|
123
19
|
buf << _build_stats( stats )
|
|
124
20
|
buf << "\n\n"
|
|
125
21
|
|
|
22
|
+
buf << _build_batch( matches, rounds: rounds )
|
|
126
23
|
|
|
127
|
-
|
|
128
|
-
if use_stages
|
|
129
|
-
## split matches by stage
|
|
130
|
-
matches_by_stage = {}
|
|
131
|
-
matches.each do |match|
|
|
132
|
-
stage = match.stage || ''
|
|
133
|
-
matches_by_stage[stage] ||= []
|
|
134
|
-
matches_by_stage[stage] << match
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
## todo/fix
|
|
138
|
-
## note - empty stage must go first!!!!
|
|
139
|
-
matches_by_stage.each_with_index do |(name, matches),i|
|
|
140
|
-
buf << "\n" if i != 0 # add extra new line (if not first stage)
|
|
141
|
-
if name.empty?
|
|
142
|
-
buf << "# Regular Season\n" ## empty stage
|
|
143
|
-
else
|
|
144
|
-
buf << "== #{name}\n"
|
|
145
|
-
end
|
|
146
|
-
buf += _build_batch( matches, rounds: rounds )
|
|
147
|
-
buf << "\n" if i+1 != matches_by_stage.size
|
|
148
|
-
end
|
|
149
|
-
buf
|
|
150
|
-
else
|
|
151
|
-
buf += _build_batch( matches, rounds: rounds )
|
|
152
|
-
buf
|
|
153
|
-
end
|
|
24
|
+
buf
|
|
154
25
|
end
|
|
155
26
|
|
|
156
27
|
|
|
@@ -158,40 +29,62 @@ def self._build_batch( matches, rounds: true )
|
|
|
158
29
|
## note: make sure rounds is a bool, that is, true or false (do NOT pass in strings etc.)
|
|
159
30
|
raise ArgumentError, "rounds flag - bool expected; got: #{rounds.inspect}" unless rounds.is_a?( TrueClass ) || rounds.is_a?( FalseClass )
|
|
160
31
|
|
|
161
|
-
buf = String.new
|
|
162
|
-
|
|
163
32
|
last_round = nil
|
|
33
|
+
last_year = nil
|
|
164
34
|
last_date = nil
|
|
165
35
|
last_time = nil
|
|
166
36
|
|
|
167
37
|
|
|
38
|
+
buf = String.new
|
|
39
|
+
|
|
40
|
+
|
|
168
41
|
matches.each_with_index do |match,i|
|
|
169
42
|
|
|
170
43
|
## note: make rounds optional (set rounds flag to false to turn off)
|
|
171
44
|
if rounds
|
|
172
|
-
|
|
45
|
+
## build round string
|
|
46
|
+
round = if match.round
|
|
47
|
+
if match.round.is_a?( Integer ) ||
|
|
48
|
+
match.round =~ /^[0-9]+$/ ## all numbers/digits
|
|
49
|
+
## default "class format
|
|
50
|
+
## e.g. Runde 1, Spieltag 1, Matchday 1, Week 1
|
|
51
|
+
"Matchday #{match.round}"
|
|
52
|
+
else ## use as is from match
|
|
53
|
+
## note: for now assume english names
|
|
54
|
+
(ROUND_TRANSLATIONS[match.round] || match.round)
|
|
55
|
+
end
|
|
56
|
+
else
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
## note - only stage present is possible
|
|
61
|
+
## if stage present - (auto-)add upfront
|
|
62
|
+
if match.stage
|
|
63
|
+
if ['Regular', 'Regular stage'].include?(match.stage)
|
|
64
|
+
## skip stage
|
|
65
|
+
else
|
|
66
|
+
round = round ? "#{match.stage}, #{round}" : "#{match.stage}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
if round.nil?
|
|
72
|
+
puts "!! ERROR - match with round nil (no round and no stage)"
|
|
73
|
+
pp match
|
|
74
|
+
exit 1
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if round != last_round
|
|
173
80
|
buf << (i == 0 ? "\n" : "\n\n") ## start with single empty line
|
|
174
|
-
|
|
175
|
-
match.round =~ /^[0-9]+$/ ## all numbers/digits
|
|
176
|
-
## default "class format
|
|
177
|
-
## e.g. Runde 1, Spieltag 1, Matchday 1, Week 1
|
|
178
|
-
buf << "Matchday #{match.round}"
|
|
179
|
-
else ## use as is from match
|
|
180
|
-
## note: for now assume english names
|
|
181
|
-
if match.round.nil?
|
|
182
|
-
## warn
|
|
183
|
-
puts "!! ERROR - match with round nil?"
|
|
184
|
-
pp match
|
|
185
|
-
exit 1
|
|
186
|
-
end
|
|
81
|
+
buf << "▪ #{round}\n"
|
|
187
82
|
|
|
188
|
-
buf << (ROUND_TRANSLATIONS[match.round] || match.round)
|
|
189
|
-
end
|
|
190
83
|
## note - reset last_date & last_time on every new round header
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
84
|
+
## kind of starting "new scope" (no date/time inheritance)
|
|
85
|
+
last_date = nil
|
|
86
|
+
last_time = nil
|
|
87
|
+
last_round = round
|
|
195
88
|
end
|
|
196
89
|
end
|
|
197
90
|
|
|
@@ -213,15 +106,23 @@ def self._build_batch( matches, rounds: true )
|
|
|
213
106
|
date_yyyymmdd = date ? date.strftime( '%Y-%m-%d' ) : nil
|
|
214
107
|
|
|
215
108
|
## note: time is OPTIONAL for now
|
|
216
|
-
## note: use 17
|
|
217
|
-
time_hhmm = time ? time.strftime( '%H
|
|
109
|
+
## note: use 17:00 always as time format (do NOT use 17.00!!!)
|
|
110
|
+
time_hhmm = time ? time.strftime( '%H:%M' ) : nil
|
|
218
111
|
|
|
219
112
|
|
|
220
113
|
if date_yyyymmdd
|
|
221
114
|
if date_yyyymmdd != last_date
|
|
222
115
|
## note: add an extra leading blank line (if no round headings printed)
|
|
223
116
|
buf << "\n" unless rounds
|
|
224
|
-
|
|
117
|
+
|
|
118
|
+
buf << " "
|
|
119
|
+
## note: only add year if different for last date header
|
|
120
|
+
buf << if (date ? date.year : nil) != last_year
|
|
121
|
+
"#{date.strftime( '%a %b %-d %Y' )}"
|
|
122
|
+
else
|
|
123
|
+
"#{date.strftime( '%a %b %-d' )}"
|
|
124
|
+
end
|
|
125
|
+
buf << "\n"
|
|
225
126
|
last_time = nil
|
|
226
127
|
end
|
|
227
128
|
end
|
|
@@ -237,22 +138,26 @@ def self._build_batch( matches, rounds: true )
|
|
|
237
138
|
|
|
238
139
|
if time
|
|
239
140
|
if last_time != time_hhmm
|
|
240
|
-
line << "%5s" % time_hhmm
|
|
141
|
+
line << " %5s" % time_hhmm
|
|
241
142
|
else
|
|
242
|
-
line << '
|
|
143
|
+
line << (' ' *7)
|
|
243
144
|
end
|
|
244
145
|
line << ' '
|
|
245
146
|
else
|
|
246
|
-
line << '
|
|
147
|
+
line << (' ' *9)
|
|
247
148
|
end
|
|
248
149
|
|
|
249
150
|
line << "%-23s" % team1 ## note: use %-s for left-align
|
|
250
|
-
|
|
251
|
-
## note: separate by at least two spaces for now
|
|
252
|
-
line << " #{match.score.to_s( lang: 'en' )} "
|
|
253
|
-
|
|
151
|
+
line << " v "
|
|
254
152
|
line << "%-23s" % team2
|
|
255
153
|
|
|
154
|
+
## note - only print if score is available
|
|
155
|
+
## returns - for not available for now!!!!
|
|
156
|
+
score = match.score.to_s( lang: 'en' )
|
|
157
|
+
if score != '-'
|
|
158
|
+
## note: separate by at least two spaces for now
|
|
159
|
+
line << " #{score} "
|
|
160
|
+
end
|
|
256
161
|
|
|
257
162
|
if match.status
|
|
258
163
|
line << ' '
|
|
@@ -269,9 +174,10 @@ def self._build_batch( matches, rounds: true )
|
|
|
269
174
|
line << '[postponed]'
|
|
270
175
|
## was -- note: add NOTHING for postponed for now
|
|
271
176
|
else
|
|
272
|
-
puts "!!
|
|
177
|
+
puts "!! ERROR - unknown match status >#{match.status}<:"
|
|
273
178
|
pp match
|
|
274
179
|
line << "[#{match.status.downcase}]" ## print "literal" downcased for now
|
|
180
|
+
exit 1
|
|
275
181
|
end
|
|
276
182
|
end
|
|
277
183
|
|
|
@@ -282,63 +188,16 @@ def self._build_batch( matches, rounds: true )
|
|
|
282
188
|
if match.goals
|
|
283
189
|
buf << ' ' # 4 space indent
|
|
284
190
|
buf << ' ' if time # 7 (5+2) space indent (for hour e.g. 17.30)
|
|
285
|
-
buf << "
|
|
191
|
+
buf << "(#{build_goals(match.goals)})"
|
|
286
192
|
buf << "\n"
|
|
287
193
|
end
|
|
288
194
|
|
|
289
|
-
|
|
290
|
-
last_round = match.round
|
|
195
|
+
last_year = date ? date.year : nil
|
|
291
196
|
last_date = date_yyyymmdd
|
|
292
197
|
last_time = time_hhmm
|
|
293
198
|
end
|
|
294
199
|
buf
|
|
295
200
|
end
|
|
296
201
|
|
|
297
|
-
|
|
298
|
-
def self.build_goals( goals )
|
|
299
|
-
## todo/fix: for now assumes always minutes (without offset) - add offset support
|
|
300
|
-
|
|
301
|
-
## note: "fold" multiple goals by players
|
|
302
|
-
team1_goals = {}
|
|
303
|
-
team2_goals = {}
|
|
304
|
-
goals.each do |goal|
|
|
305
|
-
team_goals = goal.team == 1 ? team1_goals : team2_goals
|
|
306
|
-
player_goals = team_goals[ goal.player ] ||= []
|
|
307
|
-
player_goals << goal
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
buf = String.new
|
|
311
|
-
if team1_goals.size > 0
|
|
312
|
-
buf << build_goals_for_team( team1_goals )
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
## note: only add a separator (;) if BOTH teams have goal scores
|
|
316
|
-
if team1_goals.size > 0 && team2_goals.size > 0
|
|
317
|
-
buf << '; '
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
if team2_goals.size > 0
|
|
321
|
-
buf << build_goals_for_team( team2_goals )
|
|
322
|
-
end
|
|
323
|
-
buf
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
def self.build_goals_for_team( team_goals )
|
|
328
|
-
buf = String.new
|
|
329
|
-
team_goals.each_with_index do |(player_name, goals),i|
|
|
330
|
-
buf << ' ' if i > 0
|
|
331
|
-
buf << "#{player_name} "
|
|
332
|
-
buf << goals.map do |goal|
|
|
333
|
-
str = "#{goal.minute}'"
|
|
334
|
-
str << " (o.g.)" if goal.owngoal?
|
|
335
|
-
str << " (pen.)" if goal.penalty?
|
|
336
|
-
str
|
|
337
|
-
end.join( ', ' )
|
|
338
|
-
end
|
|
339
|
-
buf
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
|
|
343
202
|
end # class TxtMatchWriter
|
|
344
203
|
end # module SportDb
|
data/lib/sportdb/writers.rb
CHANGED
|
@@ -26,42 +26,38 @@ end # module Writer
|
|
|
26
26
|
###
|
|
27
27
|
# our own code
|
|
28
28
|
require_relative 'writers/version'
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
require_relative 'writers/rounds'
|
|
31
|
+
|
|
32
|
+
require_relative 'writers/build_stats'
|
|
33
|
+
require_relative 'writers/build_goals'
|
|
34
|
+
|
|
30
35
|
require_relative 'writers/txt_writer'
|
|
31
|
-
require_relative 'writers/txt_writer_v2'
|
|
32
36
|
|
|
33
37
|
|
|
34
38
|
|
|
35
39
|
module SportDb
|
|
36
40
|
class TxtMatchWriter
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
## fix - change name: to title: !!!!
|
|
46
|
+
## fix: remove rounds: true|false - make it works without rounds without flag!!!!!
|
|
47
|
+
|
|
37
48
|
def self.write( path, matches, name:, rounds: true)
|
|
38
49
|
|
|
39
50
|
buf = build( matches, rounds: rounds )
|
|
40
|
-
|
|
41
|
-
## for convenience - make sure parent folders/directories exist
|
|
42
|
-
FileUtils.mkdir_p( File.dirname( path) ) unless Dir.exist?( File.dirname( path ))
|
|
43
|
-
|
|
44
|
-
puts "==> writing to >#{path}<..."
|
|
45
|
-
File.open( path, 'w:utf-8' ) do |f|
|
|
46
|
-
f.write( "= #{name}\n\n" )
|
|
47
|
-
f.write( buf )
|
|
48
|
-
end
|
|
49
|
-
end # method self.write
|
|
50
51
|
|
|
51
|
-
def self.write_v2( path, matches, name:, rounds: true)
|
|
52
|
-
|
|
53
|
-
buf = build_v2( matches, rounds: rounds )
|
|
54
|
-
|
|
55
|
-
## for convenience - make sure parent folders/directories exist
|
|
56
|
-
FileUtils.mkdir_p( File.dirname( path) ) unless Dir.exist?( File.dirname( path ))
|
|
57
|
-
|
|
58
52
|
puts "==> writing to >#{path}<..."
|
|
59
|
-
File.open( path, 'w:utf-8' ) do |f|
|
|
60
|
-
f.write( "= #{name}\n\n" )
|
|
61
|
-
f.write( buf )
|
|
62
|
-
end
|
|
63
|
-
end # method self.write_v2
|
|
64
53
|
|
|
54
|
+
txt = "= #{name}\n\n" + buf
|
|
55
|
+
write_text( path, txt )
|
|
56
|
+
end # method self.write
|
|
57
|
+
|
|
58
|
+
class << self
|
|
59
|
+
alias_method :write_v2, :write
|
|
60
|
+
end
|
|
65
61
|
|
|
66
62
|
end # class TxtMatchWriter
|
|
67
63
|
end # module SportDb
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sportdb-writers
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gerald Bauer
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-05-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: sportdb-structs
|
|
@@ -73,9 +73,10 @@ files:
|
|
|
73
73
|
- README.md
|
|
74
74
|
- Rakefile
|
|
75
75
|
- lib/sportdb/writers.rb
|
|
76
|
-
- lib/sportdb/writers/
|
|
76
|
+
- lib/sportdb/writers/build_goals.rb
|
|
77
|
+
- lib/sportdb/writers/build_stats.rb
|
|
78
|
+
- lib/sportdb/writers/rounds.rb
|
|
77
79
|
- lib/sportdb/writers/txt_writer.rb
|
|
78
|
-
- lib/sportdb/writers/txt_writer_v2.rb
|
|
79
80
|
- lib/sportdb/writers/version.rb
|
|
80
81
|
homepage: https://github.com/sportdb/sport.db
|
|
81
82
|
licenses:
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
module SportDb
|
|
2
|
-
class TxtMatchWriter
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
## note: build returns buf - an (in-memory) string buf(fer)
|
|
7
|
-
def self.build_v2( matches, rounds: true )
|
|
8
|
-
## note: make sure rounds is a bool, that is, true or false (do NOT pass in strings etc.)
|
|
9
|
-
raise ArgumentError, "rounds flag - bool expected; got: #{rounds.inspect}" unless rounds.is_a?( TrueClass ) || rounds.is_a?( FalseClass )
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
### check for stages & stats
|
|
13
|
-
stats = _calc_stats( matches )
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
buf = String.new
|
|
17
|
-
|
|
18
|
-
### add comment header
|
|
19
|
-
buf << _build_stats( stats )
|
|
20
|
-
buf << "\n\n"
|
|
21
|
-
|
|
22
|
-
buf << _build_batch_v2( matches, rounds: rounds )
|
|
23
|
-
|
|
24
|
-
buf
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def self._build_batch_v2( matches, rounds: true )
|
|
29
|
-
## note: make sure rounds is a bool, that is, true or false (do NOT pass in strings etc.)
|
|
30
|
-
raise ArgumentError, "rounds flag - bool expected; got: #{rounds.inspect}" unless rounds.is_a?( TrueClass ) || rounds.is_a?( FalseClass )
|
|
31
|
-
|
|
32
|
-
last_round = nil
|
|
33
|
-
last_year = nil
|
|
34
|
-
last_date = nil
|
|
35
|
-
last_time = nil
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
buf = String.new
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
matches.each_with_index do |match,i|
|
|
42
|
-
|
|
43
|
-
## note: make rounds optional (set rounds flag to false to turn off)
|
|
44
|
-
if rounds
|
|
45
|
-
## build round string
|
|
46
|
-
round = if match.round.is_a?( Integer ) ||
|
|
47
|
-
match.round =~ /^[0-9]+$/ ## all numbers/digits
|
|
48
|
-
## default "class format
|
|
49
|
-
## e.g. Runde 1, Spieltag 1, Matchday 1, Week 1
|
|
50
|
-
"Matchday #{match.round}"
|
|
51
|
-
else ## use as is from match
|
|
52
|
-
## note: for now assume english names
|
|
53
|
-
if match.round.nil?
|
|
54
|
-
## warn
|
|
55
|
-
puts "!! ERROR - match with round nil?"
|
|
56
|
-
pp match
|
|
57
|
-
exit 1
|
|
58
|
-
end
|
|
59
|
-
(ROUND_TRANSLATIONS[match.round] || match.round)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
## if stage present - (auto-)add upfront
|
|
63
|
-
round = "#{match.stage}, #{round}" if match.stage
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if round != last_round
|
|
67
|
-
buf << (i == 0 ? "\n" : "\n\n") ## start with single empty line
|
|
68
|
-
buf << "» #{round}\n"
|
|
69
|
-
|
|
70
|
-
## note - reset last_date & last_time on every new round header
|
|
71
|
-
last_date = nil
|
|
72
|
-
last_time = nil
|
|
73
|
-
last_round = round
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
date = if match.date.is_a?( String )
|
|
79
|
-
Date.strptime( match.date, '%Y-%m-%d' )
|
|
80
|
-
else ## assume it's already a date (object) or nil!!!!
|
|
81
|
-
match.date
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
time = if match.time.is_a?( String )
|
|
85
|
-
Time.strptime( match.time, '%H:%M')
|
|
86
|
-
else ## assume it's already a time (object) or nil
|
|
87
|
-
match.time
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
## note - date might be NIL!!!!!
|
|
92
|
-
date_yyyymmdd = date ? date.strftime( '%Y-%m-%d' ) : nil
|
|
93
|
-
|
|
94
|
-
## note: time is OPTIONAL for now
|
|
95
|
-
## note: use 17.00 and NOT 17:00 for now
|
|
96
|
-
time_hhmm = time ? time.strftime( '%H.%M' ) : nil
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if date_yyyymmdd
|
|
100
|
-
if date_yyyymmdd != last_date
|
|
101
|
-
## note: add an extra leading blank line (if no round headings printed)
|
|
102
|
-
buf << "\n" unless rounds
|
|
103
|
-
|
|
104
|
-
buf << " "
|
|
105
|
-
## note: only add year if different for last date header
|
|
106
|
-
buf << if (date ? date.year : nil) != last_year
|
|
107
|
-
"#{date.strftime( '%a %b/%-d %Y' )}"
|
|
108
|
-
else
|
|
109
|
-
"#{date.strftime( '%a %b/%-d' )}"
|
|
110
|
-
end
|
|
111
|
-
buf << "\n"
|
|
112
|
-
last_time = nil
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
## allow strings and structs for team names
|
|
118
|
-
team1 = match.team1.is_a?( String ) ? match.team1 : match.team1.name
|
|
119
|
-
team2 = match.team2.is_a?( String ) ? match.team2 : match.team2.name
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
line = String.new
|
|
123
|
-
line << ' '
|
|
124
|
-
|
|
125
|
-
if time
|
|
126
|
-
if last_time != time_hhmm
|
|
127
|
-
line << " %5s" % time_hhmm
|
|
128
|
-
else
|
|
129
|
-
line << (' ' *7)
|
|
130
|
-
end
|
|
131
|
-
line << ' '
|
|
132
|
-
else
|
|
133
|
-
line << (' ' *9)
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
line << "%-23s" % team1 ## note: use %-s for left-align
|
|
137
|
-
line << " v "
|
|
138
|
-
line << "%-23s" % team2
|
|
139
|
-
|
|
140
|
-
## note - only print if score is available
|
|
141
|
-
## returns - for not available for now!!!!
|
|
142
|
-
score = match.score.to_s( lang: 'en' )
|
|
143
|
-
if score != '-'
|
|
144
|
-
## note: separate by at least two spaces for now
|
|
145
|
-
line << " #{score} "
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
if match.status
|
|
149
|
-
line << ' '
|
|
150
|
-
case match.status
|
|
151
|
-
when Status::CANCELLED
|
|
152
|
-
line << '[cancelled]'
|
|
153
|
-
when Status::AWARDED
|
|
154
|
-
line << '[awarded]'
|
|
155
|
-
when Status::ABANDONED
|
|
156
|
-
line << '[abandoned]'
|
|
157
|
-
when Status::REPLAY
|
|
158
|
-
line << '[replay]'
|
|
159
|
-
when Status::POSTPONED
|
|
160
|
-
line << '[postponed]'
|
|
161
|
-
## was -- note: add NOTHING for postponed for now
|
|
162
|
-
else
|
|
163
|
-
puts "!! WARN - unknown match status >#{match.status}<:"
|
|
164
|
-
pp match
|
|
165
|
-
line << "[#{match.status.downcase}]" ## print "literal" downcased for now
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
## add match line
|
|
170
|
-
buf << line.rstrip ## remove possible right trailing spaces before adding
|
|
171
|
-
buf << "\n"
|
|
172
|
-
|
|
173
|
-
if match.goals
|
|
174
|
-
buf << ' ' # 4 space indent
|
|
175
|
-
buf << ' ' if time # 7 (5+2) space indent (for hour e.g. 17.30)
|
|
176
|
-
buf << "[#{build_goals(match.goals)}]"
|
|
177
|
-
buf << "\n"
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
last_year = date ? date.year : nil
|
|
181
|
-
last_date = date_yyyymmdd
|
|
182
|
-
last_time = time_hhmm
|
|
183
|
-
end
|
|
184
|
-
buf
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
end # class TxtMatchWriter
|
|
188
|
-
end # module SportDb
|