sportdb-writers 0.1.2 → 0.2.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 +4 -2
- data/bin/fbgen +1 -171
- data/bin/fbtxt +1 -36
- data/config/leagues_europe.csv +13 -4
- data/lib/sportdb/{writers → fbgen}/github.rb +2 -2
- data/lib/sportdb/{writers → fbgen}/github_config.rb +2 -2
- data/lib/sportdb/fbgen/main.rb +211 -0
- data/lib/sportdb/fbtxt/main.rb +37 -0
- data/lib/sportdb/writers/txt_writer.rb +108 -4
- data/lib/sportdb/writers/version.rb +2 -2
- data/lib/sportdb/writers.rb +13 -4
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3483a7e2f321970a2e970ba30e272127892013b61c63be66431a318d32b52c3f
|
|
4
|
+
data.tar.gz: 4d213ad75e6973aa6ef95bee7fb39a62bca69cd3261fc18e2bfcfc9a6b913b87
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b7b00a033d247555ca57acc503c88de73111605738998a9e5b3ea4e53f0353b08df19cfa1f9d5c84a5ad22b5528ddb632ba927b4f0b53fb5493f5391732d3d13
|
|
7
|
+
data.tar.gz: 23cec6ae8fa9b9ca04cf2242c86f8310de76a191b5a66bc4f2cab09aff7ea5c3e0a0d312bfe582dd2150d344302bdabab592c9b1944385bd75ae86de2367d207
|
data/CHANGELOG.md
CHANGED
data/Manifest.txt
CHANGED
|
@@ -8,9 +8,11 @@ config/leagues_america.csv
|
|
|
8
8
|
config/leagues_europe.csv
|
|
9
9
|
config/leagues_world.csv
|
|
10
10
|
config/openfootball.csv
|
|
11
|
+
lib/sportdb/fbgen/github.rb
|
|
12
|
+
lib/sportdb/fbgen/github_config.rb
|
|
13
|
+
lib/sportdb/fbgen/main.rb
|
|
14
|
+
lib/sportdb/fbtxt/main.rb
|
|
11
15
|
lib/sportdb/writers.rb
|
|
12
|
-
lib/sportdb/writers/github.rb
|
|
13
|
-
lib/sportdb/writers/github_config.rb
|
|
14
16
|
lib/sportdb/writers/goals.rb
|
|
15
17
|
lib/sportdb/writers/league_config.rb
|
|
16
18
|
lib/sportdb/writers/txt_writer.rb
|
data/bin/fbgen
CHANGED
|
@@ -6,178 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
require 'sportdb/writers'
|
|
8
8
|
|
|
9
|
-
require 'optparse'
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
args=ARGV
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
opts = {
|
|
17
|
-
source_path: [],
|
|
18
|
-
push: false,
|
|
19
|
-
dry: false, ## dry run (no write)
|
|
20
|
-
debug: true,
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
parser = OptionParser.new do |parser|
|
|
26
|
-
parser.banner = "Usage: #{$PROGRAM_NAME} [options] [args]"
|
|
27
|
-
|
|
28
|
-
parser.on( "-p", "--push",
|
|
29
|
-
"fast forward sync and commit & push changes to git repo - default is (#{opts[:push]})" ) do |push|
|
|
30
|
-
opts[:push] = push
|
|
31
|
-
end
|
|
32
|
-
parser.on( "--dry",
|
|
33
|
-
"dry run; do NOT write - default is (#{opts[:dry]})" ) do |dry|
|
|
34
|
-
opts[:dry] = dry
|
|
35
|
-
end
|
|
36
|
-
parser.on( "-q", "--quiet",
|
|
37
|
-
"less debug output/messages - default is (#{!opts[:debug]})" ) do |debug|
|
|
38
|
-
opts[:debug] = !debug
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
parser.parse!( args )
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if opts[:source_path].empty? &&
|
|
46
|
-
File.exist?( '/sports/cache.api.fbdat') &&
|
|
47
|
-
File.exist?( '/sports/cache.wfb' )
|
|
48
|
-
opts[:source_path] << '/sports/cache.api.fbdat'
|
|
49
|
-
opts[:source_path] << '/sports/cache.wfb'
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
puts "OPTS:"
|
|
54
|
-
p opts
|
|
55
|
-
puts "ARGV:"
|
|
56
|
-
p args
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
### split args in datasets with leagues and seasons
|
|
60
|
-
datasets = []
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
args.each do |arg|
|
|
64
|
-
if arg =~ %r{^[0-9/-]+$} ## season
|
|
65
|
-
if datasets.empty?
|
|
66
|
-
puts "!! ERROR - league required before season arg; sorry"
|
|
67
|
-
exit 1
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
season = Season.parse( arg ) ## check season
|
|
71
|
-
datasets[-1][1] << season
|
|
72
|
-
else ## assume league key
|
|
73
|
-
key = arg.downcase
|
|
74
|
-
league_info = Writer::LEAGUES[ key ]
|
|
75
|
-
|
|
76
|
-
if league_info.nil?
|
|
77
|
-
puts "!! ERROR - no league found for >#{key}<; sorry"
|
|
78
|
-
exit 1
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
datasets << [key, []]
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
pp datasets
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def find_file( filename, path: )
|
|
90
|
-
path.each do |src_dir|
|
|
91
|
-
path = "#{src_dir}/#{filename}"
|
|
92
|
-
return path if File.exist?( path )
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
## fix - raise file not found error!!!
|
|
96
|
-
nil ## not found - raise filenot found error - why? why not?
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
source_path = opts[:source_path]
|
|
101
|
-
source_path = ['.'] if source_path.empty? ## use ./ as default
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
root_dir = if opts[:push]
|
|
105
|
-
SportDb::GitHubSync.root # e.g. "/sports"
|
|
106
|
-
else
|
|
107
|
-
'./o'
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
puts " (output) root_dir: >#{root_dir}<"
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
sync = if opts[:push]
|
|
115
|
-
repos = SportDb::GitHubSync.find_repos( datasets )
|
|
116
|
-
puts " #{repos.size} repo(s):"
|
|
117
|
-
pp repos
|
|
118
|
-
SportDb::GitHubSync.new( repos )
|
|
119
|
-
else
|
|
120
|
-
nil
|
|
121
|
-
end
|
|
122
|
-
puts " sync:"
|
|
123
|
-
pp sync
|
|
124
|
-
|
|
125
|
-
sync.git_fast_forward_if_clean if sync
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
datasets.each do |league_key, seasons|
|
|
130
|
-
seasons = [ Season('2024/25') ] if seasons.empty?
|
|
131
|
-
|
|
132
|
-
puts "==> gen #{league_key} - #{seasons.size} seasons(s)..."
|
|
133
|
-
|
|
134
|
-
league_info = Writer::LEAGUES[ league_key ]
|
|
135
|
-
pp league_info
|
|
136
|
-
|
|
137
|
-
seasons.each do |season|
|
|
138
|
-
### get matches
|
|
139
|
-
|
|
140
|
-
filename = "#{season.to_path}/#{league_key}.csv"
|
|
141
|
-
path = find_file( filename, path: source_path )
|
|
142
|
-
|
|
143
|
-
if path.nil?
|
|
144
|
-
puts "!! no source found for #{filename}; sorry"
|
|
145
|
-
exit 1
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
puts " ---> reading matches in #{path} ..."
|
|
149
|
-
matches = SportDb::CsvMatchParser.read( path )
|
|
150
|
-
puts " #{matches.size} matches"
|
|
151
|
-
|
|
152
|
-
## build
|
|
153
|
-
txt = SportDb::TxtMatchWriter.build( matches )
|
|
154
|
-
puts txt if opts[:debug]
|
|
155
|
-
|
|
156
|
-
league_name = league_info[ :name ] # e.g. Brasileiro Série A
|
|
157
|
-
basename = league_info[ :basename] #.e.g 1-seriea
|
|
158
|
-
|
|
159
|
-
league_name = league_name.call( season ) if league_name.is_a?( Proc ) ## is proc/func - name depends on season
|
|
160
|
-
basename = basename.call( season ) if basename.is_a?( Proc ) ## is proc/func - name depends on season
|
|
161
|
-
|
|
162
|
-
buf = String.new
|
|
163
|
-
buf << "= #{league_name} #{season}\n\n"
|
|
164
|
-
buf << txt
|
|
165
|
-
|
|
166
|
-
repo = SportDb::GitHubSync::REPOS[ league_key ]
|
|
167
|
-
repo_path = "#{repo['owner']}/#{repo['name']}"
|
|
168
|
-
repo_path << "/#{repo['path']}" if repo['path'] ## note: do NOT forget to add optional extra path!!!
|
|
169
|
-
|
|
170
|
-
outpath = "#{root_dir}/#{repo_path}/#{season.to_path}/#{basename}.txt"
|
|
171
|
-
if opts[:dry]
|
|
172
|
-
puts " (dry) writing to >#{outpath}<..."
|
|
173
|
-
else
|
|
174
|
-
write_text( outpath, buf )
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
sync.git_push_if_changes if sync
|
|
10
|
+
Fbgen.main( ARGV )
|
|
181
11
|
|
|
182
12
|
|
|
183
13
|
puts "bye"
|
data/bin/fbtxt
CHANGED
|
@@ -9,44 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
require 'sportdb/writers'
|
|
11
11
|
|
|
12
|
-
require 'optparse'
|
|
13
12
|
|
|
13
|
+
Fbtxt.main( ARGV )
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
args=ARGV
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
opts = {
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
parser = OptionParser.new do |parser|
|
|
23
|
-
parser.banner = "Usage: #{$PROGRAM_NAME} [options]"
|
|
24
|
-
end
|
|
25
|
-
parser.parse!( args )
|
|
26
|
-
|
|
27
|
-
puts "OPTS:"
|
|
28
|
-
p opts
|
|
29
|
-
puts "ARGV:"
|
|
30
|
-
p args
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
matches = []
|
|
34
|
-
|
|
35
|
-
## step 1 - get all matches via csv
|
|
36
|
-
args.each do |arg|
|
|
37
|
-
path = arg
|
|
38
|
-
puts "==> reading matches in #{path} ..."
|
|
39
|
-
more_matches = SportDb::CsvMatchParser.read( path )
|
|
40
|
-
matches += more_matches
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
puts "#{matches.size} matches"
|
|
44
|
-
puts
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
txt = SportDb::TxtMatchWriter.build( matches )
|
|
48
|
-
puts txt
|
|
49
|
-
puts
|
|
50
|
-
|
|
51
16
|
puts "bye"
|
|
52
17
|
|
data/config/leagues_europe.csv
CHANGED
|
@@ -7,10 +7,17 @@ at.3.o, Österr. Regionalliga Ost, 3-regionalliga-ost,,,
|
|
|
7
7
|
at.cup, ÖFB Cup, cup,,,
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
de.1,
|
|
11
|
-
de.2,
|
|
12
|
-
de.3,
|
|
13
|
-
de.
|
|
10
|
+
de.1, Deutsche Bundesliga, 1-bundesliga,,,
|
|
11
|
+
de.2, Deutsche 2. Bundesliga, 2-bundesliga2,,,
|
|
12
|
+
de.3, Deutsche 3. Liga, 3-liga3,,,
|
|
13
|
+
de.4.bayern, Deutsche Regionalliga Bayern, 4-regionalliga-bayern,,,
|
|
14
|
+
de.4.n, Deutsche Regionalliga Nord, 4-regionalliga-nord,,,
|
|
15
|
+
de.4.no, Deutsche Regionalliga Nordost, 4-regionalliga-nordost,,,
|
|
16
|
+
de.4.w, Deutsche Regionalliga West, 4-regionalliga-west,,,
|
|
17
|
+
de.4.sw, Deutsche Regionalliga Südwest, 4-regionalliga-suedwest,,,
|
|
18
|
+
de.cup, DFB Pokal, cup,,,
|
|
19
|
+
|
|
20
|
+
|
|
14
21
|
|
|
15
22
|
it.1, Italian Serie A, 1-seriea,,,
|
|
16
23
|
it.2, Italian Serie B, 2-serieb,,,
|
|
@@ -45,6 +52,8 @@ pt.2, Portuguese Segunda Liga, 2-segundaliga,,,
|
|
|
45
52
|
|
|
46
53
|
ch.1, Swiss Super League, 1-superleague,,,
|
|
47
54
|
ch.2, Swiss Challenge League, 2-challengeleague,,,
|
|
55
|
+
ch.cup, Swiss Cup, cup,,,
|
|
56
|
+
|
|
48
57
|
|
|
49
58
|
tr.1, Turkish Süper Lig, 1-superlig,,,
|
|
50
59
|
tr.2, Turkish 1. Lig, 2-lig1,,,
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
|
|
2
|
+
module Fbgen
|
|
3
|
+
def self.main( args=ARGV )
|
|
4
|
+
|
|
5
|
+
opts = {
|
|
6
|
+
source_path: [],
|
|
7
|
+
push: false,
|
|
8
|
+
dry: false, ## dry run (no write)
|
|
9
|
+
debug: true,
|
|
10
|
+
file: nil,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
parser = OptionParser.new do |parser|
|
|
14
|
+
parser.banner = "Usage: #{$PROGRAM_NAME} [options] [args]"
|
|
15
|
+
|
|
16
|
+
parser.on( "-p", "--push",
|
|
17
|
+
"fast forward sync and commit & push changes to git repo - default is (#{opts[:push]})" ) do |push|
|
|
18
|
+
opts[:push] = push
|
|
19
|
+
end
|
|
20
|
+
parser.on( "--dry",
|
|
21
|
+
"dry run; do NOT write - default is (#{opts[:dry]})" ) do |dry|
|
|
22
|
+
opts[:dry] = dry
|
|
23
|
+
end
|
|
24
|
+
parser.on( "-q", "--quiet",
|
|
25
|
+
"less debug output/messages - default is (#{!opts[:debug]})" ) do |debug|
|
|
26
|
+
opts[:debug] = !debug
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
parser.on( "-f FILE", "--file FILE",
|
|
30
|
+
"read leagues via .csv file") do |file|
|
|
31
|
+
opts[:file] = file
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
parser.parse!( args )
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if opts[:source_path].empty? &&
|
|
39
|
+
File.exist?( '/sports/cache.api.fbdat') &&
|
|
40
|
+
File.exist?( '/sports/cache.wfb' )
|
|
41
|
+
opts[:source_path] << '/sports/cache.api.fbdat'
|
|
42
|
+
opts[:source_path] << '/sports/cache.wfb'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
puts "OPTS:"
|
|
47
|
+
p opts
|
|
48
|
+
puts "ARGV:"
|
|
49
|
+
p args
|
|
50
|
+
|
|
51
|
+
datasets = if opts[:file]
|
|
52
|
+
read_datasets( opts[:file] )
|
|
53
|
+
else
|
|
54
|
+
parse_datasets( args )
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
puts "datasets:"
|
|
58
|
+
pp datasets
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
source_path = opts[:source_path]
|
|
62
|
+
source_path = ['.'] if source_path.empty? ## use ./ as default
|
|
63
|
+
|
|
64
|
+
root_dir = if opts[:push]
|
|
65
|
+
GitHubSync.root # e.g. "/sports"
|
|
66
|
+
else
|
|
67
|
+
'./o'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
puts " (output) root_dir: >#{root_dir}<"
|
|
71
|
+
|
|
72
|
+
sync = if opts[:push]
|
|
73
|
+
repos = GitHubSync.find_repos( datasets )
|
|
74
|
+
puts " #{repos.size} repo(s):"
|
|
75
|
+
pp repos
|
|
76
|
+
GitHubSync.new( repos )
|
|
77
|
+
else
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
puts " sync:"
|
|
81
|
+
pp sync
|
|
82
|
+
|
|
83
|
+
sync.git_fast_forward_if_clean if sync
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
datasets.each do |league_key, seasons|
|
|
88
|
+
seasons = [ Season('2024/25') ] if seasons.empty?
|
|
89
|
+
|
|
90
|
+
puts "==> gen #{league_key} - #{seasons.size} seasons(s)..."
|
|
91
|
+
|
|
92
|
+
league_info = Writer::LEAGUES[ league_key ]
|
|
93
|
+
pp league_info
|
|
94
|
+
|
|
95
|
+
seasons.each do |season|
|
|
96
|
+
### get matches
|
|
97
|
+
|
|
98
|
+
filename = "#{season.to_path}/#{league_key}.csv"
|
|
99
|
+
path = find_file( filename, path: source_path )
|
|
100
|
+
|
|
101
|
+
if path.nil?
|
|
102
|
+
puts "!! no source found for #{filename}; sorry"
|
|
103
|
+
exit 1
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
puts " ---> reading matches in #{path} ..."
|
|
107
|
+
matches = SportDb::CsvMatchParser.read( path )
|
|
108
|
+
puts " #{matches.size} matches"
|
|
109
|
+
|
|
110
|
+
## build
|
|
111
|
+
txt = SportDb::TxtMatchWriter.build( matches )
|
|
112
|
+
puts txt if opts[:debug]
|
|
113
|
+
|
|
114
|
+
league_name = league_info[ :name ] # e.g. Brasileiro Série A
|
|
115
|
+
basename = league_info[ :basename] #.e.g 1-seriea
|
|
116
|
+
|
|
117
|
+
league_name = league_name.call( season ) if league_name.is_a?( Proc ) ## is proc/func - name depends on season
|
|
118
|
+
basename = basename.call( season ) if basename.is_a?( Proc ) ## is proc/func - name depends on season
|
|
119
|
+
|
|
120
|
+
buf = String.new
|
|
121
|
+
buf << "= #{league_name} #{season}\n\n"
|
|
122
|
+
buf << txt
|
|
123
|
+
|
|
124
|
+
repo = GitHubSync::REPOS[ league_key ]
|
|
125
|
+
repo_path = "#{repo['owner']}/#{repo['name']}"
|
|
126
|
+
repo_path << "/#{repo['path']}" if repo['path'] ## note: do NOT forget to add optional extra path!!!
|
|
127
|
+
|
|
128
|
+
outpath = "#{root_dir}/#{repo_path}/#{season.to_path}/#{basename}.txt"
|
|
129
|
+
if opts[:dry]
|
|
130
|
+
puts " (dry) writing to >#{outpath}<..."
|
|
131
|
+
else
|
|
132
|
+
write_text( outpath, buf )
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
sync.git_push_if_changes if sync
|
|
138
|
+
|
|
139
|
+
end # method self.main
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def self.parse_datasets( args )
|
|
144
|
+
### split args in datasets with leagues and seasons
|
|
145
|
+
datasets = []
|
|
146
|
+
args.each do |arg|
|
|
147
|
+
if arg =~ %r{^[0-9/-]+$} ## season
|
|
148
|
+
if datasets.empty?
|
|
149
|
+
puts "!! ERROR - league required before season arg; sorry"
|
|
150
|
+
exit 1
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
season = Season.parse( arg ) ## check season
|
|
154
|
+
datasets[-1][1] << season
|
|
155
|
+
else ## assume league key
|
|
156
|
+
key = arg.downcase
|
|
157
|
+
league_info = Writer::LEAGUES[ key ]
|
|
158
|
+
|
|
159
|
+
if league_info.nil?
|
|
160
|
+
puts "!! ERROR - no league found for >#{key}<; sorry"
|
|
161
|
+
exit 1
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
datasets << [key, []]
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
datasets
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def self.read_datasets( path )
|
|
172
|
+
### split args in datasets with leagues and seasons
|
|
173
|
+
datasets = []
|
|
174
|
+
recs = read_csv( path )
|
|
175
|
+
recs.each do |rec|
|
|
176
|
+
league_code = rec['league']
|
|
177
|
+
key = league_code.downcase
|
|
178
|
+
league_info = Writer::LEAGUES[ key ]
|
|
179
|
+
|
|
180
|
+
if league_info.nil?
|
|
181
|
+
puts "!! ERROR - no league found for >#{key}<; sorry"
|
|
182
|
+
exit 1
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
datasets << [key, []]
|
|
186
|
+
|
|
187
|
+
seasons_str = rec['seasons']
|
|
188
|
+
seasons = seasons_str.split( /[ ]+/ )
|
|
189
|
+
|
|
190
|
+
seasons.each do |season_str|
|
|
191
|
+
season = Season.parse( season_str ) ## check season
|
|
192
|
+
datasets[-1][1] << season
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
datasets
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def self.find_file( filename, path: )
|
|
200
|
+
path.each do |src_dir|
|
|
201
|
+
path = "#{src_dir}/#{filename}"
|
|
202
|
+
return path if File.exist?( path )
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
## fix - raise file not found error!!!
|
|
206
|
+
nil ## not found - raise filenot found error - why? why not?
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
end # module Fbgen
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
module Fbtxt
|
|
3
|
+
def self.main( args=ARGV )
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
opts = {
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
parser = OptionParser.new do |parser|
|
|
10
|
+
parser.banner = "Usage: #{$PROGRAM_NAME} [options]"
|
|
11
|
+
end
|
|
12
|
+
parser.parse!( args )
|
|
13
|
+
|
|
14
|
+
puts "OPTS:"
|
|
15
|
+
p opts
|
|
16
|
+
puts "ARGV:"
|
|
17
|
+
p args
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
matches = []
|
|
21
|
+
|
|
22
|
+
## step 1 - get all matches via csv
|
|
23
|
+
args.each do |arg|
|
|
24
|
+
path = arg
|
|
25
|
+
puts "==> reading matches in #{path} ..."
|
|
26
|
+
more_matches = SportDb::CsvMatchParser.read( path )
|
|
27
|
+
matches += more_matches
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
puts "#{matches.size} matches"
|
|
31
|
+
puts
|
|
32
|
+
|
|
33
|
+
txt = SportDb::TxtMatchWriter.build( matches )
|
|
34
|
+
puts txt
|
|
35
|
+
puts
|
|
36
|
+
end
|
|
37
|
+
end # module Fbtxt
|
|
@@ -19,12 +19,116 @@ def self.build( matches, rounds: true )
|
|
|
19
19
|
## note: make sure rounds is a bool, that is, true or false (do NOT pass in strings etc.)
|
|
20
20
|
raise ArgumentError, "rounds flag - bool expected; got: #{rounds.inspect}" unless rounds.is_a?( TrueClass ) || rounds.is_a?( FalseClass )
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
|
|
23
|
+
### check for stages & stats
|
|
24
|
+
stats = { 'stage' => Hash.new(0),
|
|
25
|
+
'date' => { 'start_date' => nil,
|
|
26
|
+
'end_date' => nil, },
|
|
27
|
+
'teams' => Hash.new(0),
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
## add matches played stats too??
|
|
31
|
+
|
|
32
|
+
matches.each do |match|
|
|
33
|
+
stage = match.stage
|
|
34
|
+
stage = 'Regular Season' if stage.nil? || stage.empty?
|
|
35
|
+
stats['stage'][ stage ] += 1
|
|
36
|
+
|
|
37
|
+
if match.date
|
|
38
|
+
|
|
39
|
+
## todo/fix - norm date (parse as Date)
|
|
40
|
+
## check format etc.
|
|
41
|
+
date = if match.date.is_a?( String )
|
|
42
|
+
Date.strptime( match.date, '%Y-%m-%d' )
|
|
43
|
+
else ## assume it's already a date (object)
|
|
44
|
+
match.date
|
|
45
|
+
end
|
|
46
|
+
stats['date']['start_date'] ||= date
|
|
47
|
+
stats['date']['end_date'] ||= date
|
|
48
|
+
|
|
49
|
+
stats['date']['start_date'] = date if date < stats['date']['start_date']
|
|
50
|
+
stats['date']['end_date'] = date if date > stats['date']['end_date']
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
[match.team1, match.team2].each do |team|
|
|
54
|
+
stats['teams'][ team ] += 1 if team && !['N.N.'].include?( team )
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
use_stages = if stats['stage'].size >= 2 ||
|
|
59
|
+
(stats['stage'].size == 1 &&
|
|
60
|
+
stats['stage'].keys[0] != 'Regular Season')
|
|
61
|
+
true
|
|
62
|
+
else
|
|
63
|
+
false
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
### add comment header
|
|
68
|
+
buf = String.new
|
|
69
|
+
# e.g. 13 April – 25 September 2024
|
|
70
|
+
# or 16 August 2024 – 25 May 2025
|
|
71
|
+
buf << "# Date "
|
|
72
|
+
start_date = stats['date']['start_date']
|
|
73
|
+
end_date = stats['date']['end_date']
|
|
74
|
+
if start_date.year != end_date.year
|
|
75
|
+
buf << "#{start_date.strftime('%a %b/%-d %Y')} - #{end_date.strftime('%a %b/%-d %Y')}"
|
|
76
|
+
else
|
|
77
|
+
buf << "#{start_date.strftime('%a %b/%-d')} - #{end_date.strftime('%a %b/%-d %Y')}"
|
|
78
|
+
end
|
|
79
|
+
buf << " (#{end_date.jd-start_date.jd}d)" ## add days
|
|
80
|
+
buf << "\n"
|
|
81
|
+
|
|
82
|
+
buf << "# Teams #{stats['teams'].size}\n"
|
|
83
|
+
buf << "# Matches #{matches.size}\n"
|
|
84
|
+
|
|
85
|
+
if use_stages
|
|
86
|
+
buf << "# Stages "
|
|
87
|
+
stages = stats['stage'].map { |name,count| "#{name} (#{count})" }.join( ' ' )
|
|
88
|
+
buf << stages
|
|
89
|
+
buf << "\n"
|
|
90
|
+
end
|
|
91
|
+
buf << "\n\n"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if use_stages
|
|
95
|
+
## split matches by stage
|
|
96
|
+
matches_by_stage = {}
|
|
97
|
+
matches.each do |match|
|
|
98
|
+
stage = match.stage || ''
|
|
99
|
+
matches_by_stage[stage] ||= []
|
|
100
|
+
matches_by_stage[stage] << match
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
## todo/fix
|
|
104
|
+
## note - empty stage must go first!!!!
|
|
105
|
+
matches_by_stage.each_with_index do |(name, matches),i|
|
|
106
|
+
buf << "\n" if i != 0 # add extra new line (if not first stage)
|
|
107
|
+
if name.empty?
|
|
108
|
+
buf << "# Regular Season\n" ## empty stage
|
|
109
|
+
else
|
|
110
|
+
buf << "== #{name}\n"
|
|
111
|
+
end
|
|
112
|
+
buf += _build_batch( matches, rounds: rounds )
|
|
113
|
+
buf << "\n" if i+1 != matches_by_stage.size
|
|
114
|
+
end
|
|
115
|
+
buf
|
|
116
|
+
else
|
|
117
|
+
buf += _build_batch( matches, rounds: rounds )
|
|
118
|
+
buf
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def self._build_batch( matches, rounds: true )
|
|
124
|
+
## note: make sure rounds is a bool, that is, true or false (do NOT pass in strings etc.)
|
|
125
|
+
raise ArgumentError, "rounds flag - bool expected; got: #{rounds.inspect}" unless rounds.is_a?( TrueClass ) || rounds.is_a?( FalseClass )
|
|
126
|
+
|
|
127
|
+
## note: for now always english
|
|
23
128
|
round = 'Matchday'
|
|
24
129
|
format_date = ->(date) { date.strftime( '%a %b/%-d' ) }
|
|
25
130
|
format_score = ->(match) { match.score.to_s( lang: 'en' ) }
|
|
26
131
|
round_translations = ROUND_TRANSLATIONS
|
|
27
|
-
|
|
28
132
|
|
|
29
133
|
buf = String.new
|
|
30
134
|
|
|
@@ -33,12 +137,12 @@ def self.build( matches, rounds: true )
|
|
|
33
137
|
last_time = nil
|
|
34
138
|
|
|
35
139
|
|
|
36
|
-
matches.
|
|
140
|
+
matches.each_with_index do |match,i|
|
|
37
141
|
|
|
38
142
|
## note: make rounds optional (set rounds flag to false to turn off)
|
|
39
143
|
if rounds
|
|
40
144
|
if match.round != last_round
|
|
41
|
-
buf << "\n\n"
|
|
145
|
+
buf << (i == 0 ? "\n" : "\n\n") ## start with single empty line
|
|
42
146
|
if match.round.is_a?( Integer ) ||
|
|
43
147
|
match.round =~ /^[0-9]+$/ ## all numbers/digits
|
|
44
148
|
## default "class format
|
data/lib/sportdb/writers.rb
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
require 'sportdb/quick'
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
require 'optparse' ## command-line processing; check if included updstream?
|
|
6
|
+
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
module Writer
|
|
7
10
|
class Configuration
|
|
@@ -45,16 +48,21 @@ module Writer
|
|
|
45
48
|
end # module Writer
|
|
46
49
|
|
|
47
50
|
|
|
51
|
+
###
|
|
52
|
+
# fbtxt tool
|
|
53
|
+
require_relative 'fbtxt/main'
|
|
54
|
+
|
|
55
|
+
|
|
48
56
|
|
|
49
57
|
########################
|
|
50
58
|
# push & pull github scripts
|
|
51
59
|
require 'gitti' ## note - requires git machinery
|
|
52
60
|
|
|
53
|
-
require_relative '
|
|
54
|
-
require_relative '
|
|
61
|
+
require_relative 'fbgen/github_config'
|
|
62
|
+
require_relative 'fbgen/github' ## github helpers/update machinery
|
|
55
63
|
|
|
56
64
|
|
|
57
|
-
module
|
|
65
|
+
module Fbgen
|
|
58
66
|
class GitHubSync
|
|
59
67
|
REPOS = GitHubConfig.new
|
|
60
68
|
recs = read_csv( "#{SportDb::Module::Writers.root}/config/openfootball.csv" )
|
|
@@ -88,9 +96,10 @@ def self.find_repos( datasets )
|
|
|
88
96
|
repos.uniq ## note: remove duplicates (e.g. europe or world or such)
|
|
89
97
|
end
|
|
90
98
|
end # class GitHubSync
|
|
91
|
-
end # module
|
|
99
|
+
end # module Fbgen
|
|
92
100
|
|
|
93
101
|
|
|
102
|
+
require_relative 'fbgen/main'
|
|
94
103
|
|
|
95
104
|
|
|
96
105
|
|
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.2.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: 2024-09-
|
|
11
|
+
date: 2024-09-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: sportdb-quick
|
|
@@ -94,9 +94,11 @@ files:
|
|
|
94
94
|
- config/leagues_europe.csv
|
|
95
95
|
- config/leagues_world.csv
|
|
96
96
|
- config/openfootball.csv
|
|
97
|
+
- lib/sportdb/fbgen/github.rb
|
|
98
|
+
- lib/sportdb/fbgen/github_config.rb
|
|
99
|
+
- lib/sportdb/fbgen/main.rb
|
|
100
|
+
- lib/sportdb/fbtxt/main.rb
|
|
97
101
|
- lib/sportdb/writers.rb
|
|
98
|
-
- lib/sportdb/writers/github.rb
|
|
99
|
-
- lib/sportdb/writers/github_config.rb
|
|
100
102
|
- lib/sportdb/writers/goals.rb
|
|
101
103
|
- lib/sportdb/writers/league_config.rb
|
|
102
104
|
- lib/sportdb/writers/txt_writer.rb
|