sportdb-writers 0.4.3 → 0.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b08a4a77a08af12a0f8c7b9873c5115b8b8135e13e3b7d878ab246567a8ffa32
4
- data.tar.gz: a6e9f8f3b0933667f2fa4cf5eb7903c4410ead48e3647dfb903e261bb3f164be
3
+ metadata.gz: 8d17c7dec2e2be1aa0de35fa8701c7983998ba9e3ccf06d63d8a0428294b0350
4
+ data.tar.gz: 1365f21386f582ea89b9f8e58e6a01566022d8f1cdb843a1046f337461622c8f
5
5
  SHA512:
6
- metadata.gz: 1ebb1e1a90a196a992fef5eebf43baea0e613f559d73db25d8bd8812da67fe31bb4f286b767e7423c80f00d25d1c3f745972946448eaab8a3239e9f53a8d78fc
7
- data.tar.gz: 02342a063aef2f2604567a70a76e4caf48e49b555ab1b09fb7da996b6812547c17d684a053b3164f9b797de44e4c2a2c490a66b7865983d8d63fb78eda3294a8
6
+ metadata.gz: 308e428f1ef26bd54f27e2dc49d1e1fa059417ae022ee094f37405b6df7b150a1b4a916e3bcc225057d46249c772f704b06f2c97e1c0a8c830b2b7d76e791fb8
7
+ data.tar.gz: 34f3100368f4f2404d4ab03afdb4bf36fa545dfc01bb1de259bcb3b0aa4a728123747980dfe9c8d86a95564c21a7df6820d956ec612bbd183bc726a862900227
data/CHANGELOG.md CHANGED
@@ -1,5 +1,4 @@
1
- ### 0.4.3
1
+ ### 0.5.1
2
2
  ### 0.0.1 / 2020-11-15
3
3
 
4
4
  * Everything is new. First release.
5
-
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/goals.rb
7
- lib/sportdb/writers/txt_writer.rb
8
- lib/sportdb/writers/txt_writer_v2.rb
6
+ lib/sportdb/writers/build.rb
7
+ lib/sportdb/writers/build_goals.rb
8
+ lib/sportdb/writers/build_stats.rb
9
+ lib/sportdb/writers/rounds.rb
9
10
  lib/sportdb/writers/version.rb
@@ -4,7 +4,7 @@ class TxtMatchWriter
4
4
 
5
5
 
6
6
  ## note: build returns buf - an (in-memory) string buf(fer)
7
- def self.build_v2( matches, rounds: true )
7
+ def self.build( matches, rounds: true )
8
8
  ## note: make sure rounds is a bool, that is, true or false (do NOT pass in strings etc.)
9
9
  raise ArgumentError, "rounds flag - bool expected; got: #{rounds.inspect}" unless rounds.is_a?( TrueClass ) || rounds.is_a?( FalseClass )
10
10
 
@@ -19,18 +19,18 @@ def self.build_v2( matches, rounds: true )
19
19
  buf << _build_stats( stats )
20
20
  buf << "\n\n"
21
21
 
22
- buf << _build_batch_v2( matches, rounds: rounds )
22
+ buf << _build_batch( matches, rounds: rounds )
23
23
 
24
24
  buf
25
25
  end
26
26
 
27
27
 
28
- def self._build_batch_v2( matches, rounds: true )
28
+ def self._build_batch( matches, rounds: true )
29
29
  ## note: make sure rounds is a bool, that is, true or false (do NOT pass in strings etc.)
30
30
  raise ArgumentError, "rounds flag - bool expected; got: #{rounds.inspect}" unless rounds.is_a?( TrueClass ) || rounds.is_a?( FalseClass )
31
31
 
32
32
  last_round = nil
33
- last_year = nil
33
+ last_year = nil
34
34
  last_date = nil
35
35
  last_time = nil
36
36
 
@@ -43,31 +43,46 @@ def self._build_batch_v2( matches, rounds: true )
43
43
  ## note: make rounds optional (set rounds flag to false to turn off)
44
44
  if rounds
45
45
  ## build round string
46
- round = if match.round.is_a?( Integer ) ||
47
- match.round =~ /^[0-9]+$/ ## all numbers/digits
46
+ round = if match.round
47
+ if match.round.is_a?( Integer ) ||
48
+ match.round =~ /^[0-9]+$/ ## all numbers/digits
48
49
  ## default "class format
49
50
  ## e.g. Runde 1, Spieltag 1, Matchday 1, Week 1
50
51
  "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
52
+ else ## use as is from match
53
+ ## note: for now assume english names
54
+ (ROUND_TRANSLATIONS[match.round] || match.round)
58
55
  end
59
- (ROUND_TRANSLATIONS[match.round] || match.round)
56
+ else
57
+ nil
60
58
  end
61
-
62
- ## if stage present - (auto-)add upfront
63
- round = "#{match.stage}, #{round}" if match.stage
59
+
60
+
61
+ if match.stage
62
+ if ['Regular', 'Regular stage'].include?(match.stage)
63
+ ## skip stage
64
+ else
65
+ ## note - only stage present is possible
66
+ ## if stage present - (auto-)add upfront
67
+ round = round ? "#{match.stage}, #{round}" : "#{match.stage}"
68
+ end
69
+ end
70
+
71
+
72
+ if round.nil?
73
+ puts "!! ERROR - match with round nil (no round and no stage)"
74
+ pp match
75
+ exit 1
76
+ end
77
+
64
78
 
65
79
 
66
80
  if round != last_round
67
81
  buf << (i == 0 ? "\n" : "\n\n") ## start with single empty line
68
- buf << "» #{round}\n"
69
-
82
+ buf << " #{round}\n"
83
+
70
84
  ## note - reset last_date & last_time on every new round header
85
+ ## kind of starting "new scope" (no date/time inheritance)
71
86
  last_date = nil
72
87
  last_time = nil
73
88
  last_round = round
@@ -81,6 +96,13 @@ def self._build_batch_v2( matches, rounds: true )
81
96
  match.date
82
97
  end
83
98
 
99
+ ###
100
+ ## fix - fix - fix
101
+ ## ruby has no TIME type/class
102
+ ## Time.strptime will include date (plus timezone etc.) e.g.!!!
103
+ ## 12:00 => 2026-05-25 12:00:00 +0200
104
+ ## do NOT use object; keep time as a string!!!!
105
+
84
106
  time = if match.time.is_a?( String )
85
107
  Time.strptime( match.time, '%H:%M')
86
108
  else ## assume it's already a time (object) or nil
@@ -90,10 +112,10 @@ def self._build_batch_v2( matches, rounds: true )
90
112
 
91
113
  ## note - date might be NIL!!!!!
92
114
  date_yyyymmdd = date ? date.strftime( '%Y-%m-%d' ) : nil
93
-
115
+
94
116
  ## 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
117
+ ## note: use 17:00 always as time format (do NOT use 17.00!!!)
118
+ time_hhmm = time ? time.strftime( '%H:%M' ) : nil
97
119
 
98
120
 
99
121
  if date_yyyymmdd
@@ -104,9 +126,9 @@ def self._build_batch_v2( matches, rounds: true )
104
126
  buf << " "
105
127
  ## note: only add year if different for last date header
106
128
  buf << if (date ? date.year : nil) != last_year
107
- "#{date.strftime( '%a %b/%-d %Y' )}"
108
- else
109
- "#{date.strftime( '%a %b/%-d' )}"
129
+ "#{date.strftime( '%a %b %-d %Y' )}"
130
+ else
131
+ "#{date.strftime( '%a %b %-d' )}"
110
132
  end
111
133
  buf << "\n"
112
134
  last_time = nil
@@ -142,7 +164,7 @@ def self._build_batch_v2( matches, rounds: true )
142
164
  score = match.score.to_s( lang: 'en' )
143
165
  if score != '-'
144
166
  ## note: separate by at least two spaces for now
145
- line << " #{score} "
167
+ line << " #{score} "
146
168
  end
147
169
 
148
170
  if match.status
@@ -160,9 +182,10 @@ def self._build_batch_v2( matches, rounds: true )
160
182
  line << '[postponed]'
161
183
  ## was -- note: add NOTHING for postponed for now
162
184
  else
163
- puts "!! WARN - unknown match status >#{match.status}<:"
185
+ puts "!! ERROR - unknown match status >#{match.status}<:"
164
186
  pp match
165
187
  line << "[#{match.status.downcase}]" ## print "literal" downcased for now
188
+ exit 1
166
189
  end
167
190
  end
168
191
 
@@ -173,7 +196,7 @@ def self._build_batch_v2( matches, rounds: true )
173
196
  if match.goals
174
197
  buf << ' ' # 4 space indent
175
198
  buf << ' ' if time # 7 (5+2) space indent (for hour e.g. 17.30)
176
- buf << "[#{build_goals(match.goals)}]"
199
+ buf << "(#{build_goals(match.goals)})"
177
200
  buf << "\n"
178
201
  end
179
202
 
@@ -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
@@ -3,8 +3,8 @@ module SportDb
3
3
  module Module
4
4
  module Writers
5
5
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
6
- MINOR = 4
7
- PATCH = 3
6
+ MINOR = 5
7
+ PATCH = 1
8
8
  VERSION = [MAJOR,MINOR,PATCH].join('.')
9
9
 
10
10
  def self.version
@@ -26,43 +26,43 @@ end # module Writer
26
26
  ###
27
27
  # our own code
28
28
  require_relative 'writers/version'
29
- require_relative 'writers/goals'
30
- require_relative 'writers/txt_writer'
31
- require_relative 'writers/txt_writer_v2'
29
+
30
+ require_relative 'writers/rounds'
31
+
32
+ require_relative 'writers/build_stats'
33
+ require_relative 'writers/build_goals'
34
+
35
+ require_relative 'writers/build'
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
-
51
+
44
52
  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
53
+
54
+ txt = "= #{name}\n\n" + buf
55
+ write_text( path, txt )
49
56
  end # method self.write
50
57
 
51
- def self.write_v2( path, matches, name:, rounds: true)
52
58
 
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
- 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
59
 
65
60
 
61
+ class << self
62
+ alias_method :write_v2, :write
63
+ alias_method :build_v2, :build
64
+ end
65
+
66
66
  end # class TxtMatchWriter
67
67
  end # module SportDb
68
68
 
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.3
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-21 00:00:00.000000000 Z
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/goals.rb
77
- - lib/sportdb/writers/txt_writer.rb
78
- - lib/sportdb/writers/txt_writer_v2.rb
76
+ - lib/sportdb/writers/build.rb
77
+ - lib/sportdb/writers/build_goals.rb
78
+ - lib/sportdb/writers/build_stats.rb
79
+ - lib/sportdb/writers/rounds.rb
79
80
  - lib/sportdb/writers/version.rb
80
81
  homepage: https://github.com/sportdb/sport.db
81
82
  licenses:
@@ -1,344 +0,0 @@
1
- module SportDb
2
- class TxtMatchWriter
3
-
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
-
111
- ## note: build returns buf - an (in-memory) string buf(fer)
112
- def self.build( matches, rounds: true )
113
- ## note: make sure rounds is a bool, that is, true or false (do NOT pass in strings etc.)
114
- raise ArgumentError, "rounds flag - bool expected; got: #{rounds.inspect}" unless rounds.is_a?( TrueClass ) || rounds.is_a?( FalseClass )
115
-
116
-
117
- ### calc stats and check for stages
118
- stats = _calc_stats( matches )
119
-
120
- buf = String.new
121
-
122
- ### add comment header
123
- buf << _build_stats( stats )
124
- buf << "\n\n"
125
-
126
-
127
- use_stages = stats['use_stages' ]
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
154
- end
155
-
156
-
157
- def self._build_batch( matches, rounds: true )
158
- ## note: make sure rounds is a bool, that is, true or false (do NOT pass in strings etc.)
159
- raise ArgumentError, "rounds flag - bool expected; got: #{rounds.inspect}" unless rounds.is_a?( TrueClass ) || rounds.is_a?( FalseClass )
160
-
161
- buf = String.new
162
-
163
- last_round = nil
164
- last_date = nil
165
- last_time = nil
166
-
167
-
168
- matches.each_with_index do |match,i|
169
-
170
- ## note: make rounds optional (set rounds flag to false to turn off)
171
- if rounds
172
- if match.round != last_round
173
- buf << (i == 0 ? "\n" : "\n\n") ## start with single empty line
174
- if match.round.is_a?( Integer ) ||
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
187
-
188
- buf << (ROUND_TRANSLATIONS[match.round] || match.round)
189
- end
190
- ## note - reset last_date & last_time on every new round header
191
- last_date = nil
192
- last_time = nil
193
-
194
- buf << "\n"
195
- end
196
- end
197
-
198
-
199
- date = if match.date.is_a?( String )
200
- Date.strptime( match.date, '%Y-%m-%d' )
201
- else ## assume it's already a date (object) or nil!!!!
202
- match.date
203
- end
204
-
205
- time = if match.time.is_a?( String )
206
- Time.strptime( match.time, '%H:%M')
207
- else ## assume it's already a time (object) or nil
208
- match.time
209
- end
210
-
211
-
212
- ## note - date might be NIL!!!!!
213
- date_yyyymmdd = date ? date.strftime( '%Y-%m-%d' ) : nil
214
-
215
- ## note: time is OPTIONAL for now
216
- ## note: use 17.00 and NOT 17:00 for now
217
- time_hhmm = time ? time.strftime( '%H.%M' ) : nil
218
-
219
-
220
- if date_yyyymmdd
221
- if date_yyyymmdd != last_date
222
- ## note: add an extra leading blank line (if no round headings printed)
223
- buf << "\n" unless rounds
224
- buf << "[#{date.strftime( '%a %b/%-d' )}]\n"
225
- last_time = nil
226
- end
227
- end
228
-
229
-
230
- ## allow strings and structs for team names
231
- team1 = match.team1.is_a?( String ) ? match.team1 : match.team1.name
232
- team2 = match.team2.is_a?( String ) ? match.team2 : match.team2.name
233
-
234
-
235
- line = String.new
236
- line << ' '
237
-
238
- if time
239
- if last_time != time_hhmm
240
- line << "%5s" % time_hhmm
241
- else
242
- line << ' '
243
- end
244
- line << ' '
245
- else
246
- line << ' '
247
- end
248
-
249
- 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
-
254
- line << "%-23s" % team2
255
-
256
-
257
- if match.status
258
- line << ' '
259
- case match.status
260
- when Status::CANCELLED
261
- line << '[cancelled]'
262
- when Status::AWARDED
263
- line << '[awarded]'
264
- when Status::ABANDONED
265
- line << '[abandoned]'
266
- when Status::REPLAY
267
- line << '[replay]'
268
- when Status::POSTPONED
269
- line << '[postponed]'
270
- ## was -- note: add NOTHING for postponed for now
271
- else
272
- puts "!! WARN - unknown match status >#{match.status}<:"
273
- pp match
274
- line << "[#{match.status.downcase}]" ## print "literal" downcased for now
275
- end
276
- end
277
-
278
- ## add match line
279
- buf << line.rstrip ## remove possible right trailing spaces before adding
280
- buf << "\n"
281
-
282
- if match.goals
283
- buf << ' ' # 4 space indent
284
- buf << ' ' if time # 7 (5+2) space indent (for hour e.g. 17.30)
285
- buf << "[#{build_goals(match.goals)}]"
286
- buf << "\n"
287
- end
288
-
289
-
290
- last_round = match.round
291
- last_date = date_yyyymmdd
292
- last_time = time_hhmm
293
- end
294
- buf
295
- end
296
-
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
- end # class TxtMatchWriter
344
- end # module SportDb