sportdb-formats 2.0.2 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67f0ea27fe2c7a39512eab9728167881fb1b99b919492b3d513cb1a1ff46c787
4
- data.tar.gz: a93978a81ec8cb8c9b639ff4842e5eb46d7ebc018031e4b37e8361b7ed80e8af
3
+ metadata.gz: c227a8566030829c53c10e3a8ab626b3222653ebcf795143e17c4627609a3e9f
4
+ data.tar.gz: 25cf88f75828207d783009f7f67f86de3cffab7265cc875fc893133678134bd5
5
5
  SHA512:
6
- metadata.gz: 94d114bc6772b18e972449cd7ed0f0a890d737203e8e020655e446e4496e8b8e99985ac33c6da2579e27a52a863602ea561e2275f2e1852762355228b3d9383d
7
- data.tar.gz: 4e645afc07ca5c73cda0308fe82211293160e2ebd3857770dc959ea41c684cbc2794e1c514f1fcf9e103f22294cc5d7879446632a9be06d2a04399b11daef5ed
6
+ metadata.gz: 5eb402eb00c0aff8e18a8079807cf39d1ed7d3e4d57786051d3737c39680958917a412a304fd40132b7aa1e7a7cc7d0d0a8e97f15307176e2fb54083e2f16caf
7
+ data.tar.gz: ba5db77e4b57f72ed3c305cd71bbc5ad7e150971ff9055544a4d3028ff3b24c579ec9c9915e651ed2eae1f2f4d19a7772f8aafc79af7f4d60dcc6e22e33bc930
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 2.0.2
1
+ ### 2.1.0
2
2
 
3
3
  ### 0.0.1 / 2019-10-28
4
4
 
data/Manifest.txt CHANGED
@@ -2,28 +2,10 @@ CHANGELOG.md
2
2
  Manifest.txt
3
3
  README.md
4
4
  Rakefile
5
- bin/fbx
5
+ bin/fbchk
6
6
  lib/sportdb/formats.rb
7
- lib/sportdb/formats/country/country_reader.rb
8
- lib/sportdb/formats/csv/goal.rb
9
- lib/sportdb/formats/csv/goal_parser_csv.rb
10
- lib/sportdb/formats/csv/match_parser_csv.rb
11
- lib/sportdb/formats/csv/match_status_parser.rb
12
- lib/sportdb/formats/datafile.rb
13
7
  lib/sportdb/formats/datafile_package.rb
14
- lib/sportdb/formats/event/event_reader.rb
15
- lib/sportdb/formats/ground/ground_reader.rb
16
- lib/sportdb/formats/league/league_outline_reader.rb
17
- lib/sportdb/formats/league/league_reader.rb
18
- lib/sportdb/formats/match/conf_parser.rb
19
- lib/sportdb/formats/match/match_parser.rb
20
8
  lib/sportdb/formats/package.rb
21
- lib/sportdb/formats/search/sport.rb
22
- lib/sportdb/formats/search/structs.rb
23
- lib/sportdb/formats/search/world.rb
9
+ lib/sportdb/formats/quick_match_linter.rb
24
10
  lib/sportdb/formats/team/club_index_history.rb
25
- lib/sportdb/formats/team/club_reader.rb
26
- lib/sportdb/formats/team/club_reader_history.rb
27
- lib/sportdb/formats/team/club_reader_props.rb
28
- lib/sportdb/formats/team/wiki_reader.rb
29
11
  lib/sportdb/formats/version.rb
data/Rakefile CHANGED
@@ -20,13 +20,8 @@ Hoe.spec 'sportdb-formats' do
20
20
  self.licenses = ['Public Domain']
21
21
 
22
22
  self.extra_deps = [
23
- ['sportdb-structs', '>= 0.3.1'],
24
- ['sportdb-parser', '>= 0.2.1'],
25
- ['sportdb-catalogs', '>= 1.2.2'],
26
- ['date-formats', '>= 1.0.2'],
27
- ['cocos', '>= 0.4.0'],
28
- ['logutils', '>= 0.6.1'],
29
-
23
+ ['sportdb-search', '>= 0.0.1'],
24
+ ['sportdb-quick', '>= 0.2.0'],
30
25
  ['rubyzip', '>= 2.3.2' ],
31
26
  ]
32
27
 
data/bin/fbchk ADDED
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ## tip: to test run:
4
+ ## ruby -I ./lib bin/fbchk
5
+
6
+ ## our own code
7
+ require 'sportdb/formats'
8
+
9
+
10
+
11
+ require 'optparse'
12
+
13
+
14
+
15
+ ## local hack
16
+ ## if exists up-to-date catalog db (use local version NOT built-in)
17
+ catalog_path = '../catalog/catalog.db'
18
+ if File.exist?( catalog_path )
19
+ SportDb::Import.config.catalog_path = catalog_path
20
+ end
21
+
22
+
23
+ args = ARGV
24
+ opts = { debug: false,
25
+ file: nil,
26
+ }
27
+
28
+ parser = OptionParser.new do |parser|
29
+ parser.banner = "Usage: #{$PROGRAM_NAME} [options]"
30
+
31
+ ##
32
+ ## check if git has a offline option?? (use same)
33
+ ## check for other tools - why? why not?
34
+ # parser.on( "-q", "--quiet",
35
+ # "less debug output/messages - default is (#{!opts[:debug]})" ) do |debug|
36
+ # opts[:debug] = false
37
+ # end
38
+ parser.on( "--verbose", "--debug",
39
+ "turn on verbose / debug output (default: #{opts[:debug]})" ) do |debug|
40
+ opts[:debug] = true
41
+ end
42
+
43
+ parser.on( "-f FILE", "--file FILE",
44
+ "read datafiles (pathspecs) via .csv file") do |file|
45
+ opts[:file] = file
46
+ end
47
+
48
+
49
+ end
50
+ parser.parse!( args )
51
+
52
+ puts "OPTS:"
53
+ p opts
54
+ puts "ARGV:"
55
+ p args
56
+
57
+
58
+ ## todo/check - use packs or projects or such
59
+ ## instead of specs - why? why not?
60
+ specs = []
61
+ if opts[:file]
62
+ recs = read_csv( opts[:file] )
63
+ pp recs
64
+ ## note - make pathspecs relative to passed in file arg!!!
65
+ basedir = File.dirname( opts[:file] )
66
+ recs.each do |rec|
67
+ paths = SportDb::Parser::Opts.find( rec['path'], dir: basedir )
68
+ specs << [paths, rec]
69
+ end
70
+ else
71
+ paths = if args.empty?
72
+ []
73
+ else
74
+ ## check for directories
75
+ ## and auto-expand
76
+ SportDb::Parser::Opts.expand_args( args )
77
+ end
78
+ specs << [paths, {}]
79
+ end
80
+
81
+
82
+ if opts[:debug]
83
+ SportDb::QuickMatchLinter.debug = true
84
+ SportDb::QuickMatchReader.debug = true
85
+ SportDb::MatchParser.debug = true
86
+ else
87
+ SportDb::QuickMatchLinter.debug = false
88
+ SportDb::QuickMatchReader.debug = false
89
+ SportDb::MatchParser.debug = false
90
+ LogUtils::Logger.root.level = :info
91
+ end
92
+
93
+
94
+ specs.each_with_index do |(paths, rec),i|
95
+ errors = []
96
+ paths.each_with_index do |path,j|
97
+ puts "==> [#{j+1}/#{paths.size}] reading >#{path}<..."
98
+ quick = SportDb::QuickMatchLinter.new( read_text( path ) )
99
+ matches = quick.parse
100
+
101
+ if quick.errors?
102
+ puts "!! #{quick.errors.size} error(s):"
103
+ pp quick.errors
104
+
105
+ quick.errors.each do |err|
106
+ errors << [ path, *err ] # note: use splat (*) to add extra values (starting with msg)
107
+ end
108
+ end
109
+ puts " #{matches.size} match(es)"
110
+ end
111
+
112
+ if errors.size > 0
113
+ puts
114
+ puts "!! #{errors.size} PARSE ERRORS in #{paths.size} datafile(s)"
115
+ pp errors
116
+ else
117
+ puts
118
+ puts " OK - no parse errors in #{paths.size} datafile(s)"
119
+ end
120
+
121
+ ## add errors to rec via rec['errors'] to allow
122
+ ## for further processing/reporting
123
+ rec['errors'] = errors
124
+ end
125
+
126
+
127
+
128
+ ###
129
+ ## generate a report if --file option used
130
+ if opts[:file]
131
+
132
+ buf = String.new
133
+
134
+ buf << "# fbchk summary report - #{specs.size} dataset(s)\n\n"
135
+
136
+ specs.each_with_index do |(paths, rec),i|
137
+ errors = rec['errors']
138
+
139
+ if errors.size > 0
140
+ buf << "!! #{errors.size} ERROR(S) "
141
+ else
142
+ buf << " OK "
143
+ end
144
+ buf << "%-20s" % rec['path']
145
+ buf << " - #{paths.size} datafile(s)"
146
+ buf << "\n"
147
+
148
+ if errors.size > 0
149
+ buf << errors.pretty_inspect
150
+ buf << "\n"
151
+ end
152
+ end
153
+
154
+ puts
155
+ puts "SUMMARY:"
156
+ puts buf
157
+
158
+ basedir = File.dirname( opts[:file] )
159
+ basename = File.basename( opts[:file], File.extname( opts[:file] ))
160
+ outpath = "#{basedir}/fbcheck.#{basename}.txt"
161
+ write_text( outpath, buf )
162
+ end
163
+
164
+
165
+ puts "bye"
166
+
@@ -0,0 +1,195 @@
1
+ #####
2
+ ## quick match linter for datafiles with league outlines
3
+
4
+
5
+ module SportDb
6
+ class QuickMatchLinter
7
+
8
+ def self.debug=(value) @@debug = value; end
9
+ def self.debug?() @@debug ||= false; end ## note: default is FALSE
10
+ def debug?() self.class.debug?; end
11
+
12
+
13
+
14
+ def self.read( path ) ## use - rename to read_file or from_file etc. - why? why not?
15
+ txt = File.open( path, 'r:utf-8' ) {|f| f.read }
16
+ parse( txt )
17
+ end
18
+
19
+ def self.parse( txt )
20
+ new( txt ).parse
21
+ end
22
+
23
+
24
+ include Logging
25
+
26
+ def initialize( txt )
27
+ @errors = []
28
+ @txt = txt
29
+ end
30
+
31
+ attr_reader :errors
32
+ def errors?() @errors.size > 0; end
33
+
34
+
35
+
36
+ CLUB_NAME_RE = %r{^
37
+ (?<name>[^()]+?) ## non-greedy
38
+ (?:
39
+ \s+
40
+ \(
41
+ (?<code>[A-Z][A-Za-z]{2,3}) ## optional (country) code; support single code e.g. (A) - why? why not?
42
+ \)
43
+ )?
44
+ $}x ## note - allow (URU) and (Uru) - why? why not
45
+
46
+
47
+ def parse
48
+ ## note: every (new) read call - resets errors list to empty
49
+ @errors = []
50
+
51
+ data = {} # return data hash with leagues
52
+ # and seasons
53
+ # for now merge stage into matches
54
+
55
+ secs = QuickLeagueOutlineReader.parse( @txt )
56
+ pp secs if debug?
57
+
58
+ secs.each do |sec| ## sec(tion)s
59
+ season = Season.parse( sec[:season] ) ## convert (str) to season obj!!!
60
+ league = sec[:league]
61
+ stage = sec[:stage]
62
+ lines = sec[:lines]
63
+
64
+ start = if season.year?
65
+ Date.new( season.start_year, 1, 1 )
66
+ else
67
+ Date.new( season.start_year, 7, 1 )
68
+ end
69
+
70
+ ###
71
+ ## db check - check league
72
+ ## fix/fix - add season to match_by !!!!!!!
73
+ recs = Import::League.match_by( name: league )
74
+ league_rec = nil
75
+ if recs.size == 1
76
+ league_rec = recs[0]
77
+ puts " OK #{league} => #{league_rec.name}"
78
+ elsif recs.size == 0
79
+ msg = "NAME ERROR - no league match found for >#{league}<"
80
+ @errors << [msg]
81
+ puts "!! #{msg}"
82
+ else
83
+ msg = "NAME ERROR - ambigous; too many league matches (#{recs.size}) found for >#{league}<"
84
+ @errors << [msg]
85
+ puts "!! #{msg}"
86
+ end
87
+
88
+
89
+ parser = MatchParser.new( lines,
90
+ start ) ## note: keep season start_at date for now (no need for more specific stage date need for now)
91
+
92
+ auto_conf_teams, matches, rounds, groups = parser.parse
93
+
94
+ ## auto-add "upstream" errors from parser
95
+ @errors += parser.errors if parser.errors?
96
+
97
+
98
+ if debug?
99
+ puts ">>> #{auto_conf_teams.size} teams:"
100
+ pp auto_conf_teams
101
+ puts ">>> #{matches.size} matches:"
102
+ ## pp matches
103
+ puts ">>> #{rounds.size} rounds:"
104
+ pp rounds
105
+ puts ">>> #{groups.size} groups:"
106
+ pp groups
107
+ end
108
+
109
+ ###
110
+ ## db check - check teams
111
+ ## only clubs for now
112
+ ## fix add better support for champs etc
113
+ ## and national teams!!!
114
+ auto_conf_teams.each do |team|
115
+ recs = if league_rec && !league_rec.intl?
116
+ Import::Club.match_by( name: team, league: league_rec )
117
+ else
118
+ ###
119
+ ## get country code from name
120
+ ## e.g. Liverpool FC (ENG) or
121
+ ## Liverpool FC (URU) etc.
122
+
123
+ ## check for country code
124
+ if m=CLUB_NAME_RE.match( team )
125
+ if m[:code]
126
+ Import::Club.match_by( name: m[:name],
127
+ country: m[:code] )
128
+ else
129
+ msg = "PARSE ERROR - country code missing for club name in int'l tournament; may not be unique >#{team}<"
130
+ @errors << [msg]
131
+ Import::Club.match_by( name: team )
132
+ end
133
+ else
134
+ msg = "PARSE ERROR - invalid club name; cannot match with CLUB_NAME_RE >#{team}<"
135
+ @errors << [msg]
136
+ []
137
+ end
138
+ end
139
+ team_rec = nil
140
+ if recs.size == 1
141
+ team_rec = recs[0]
142
+ puts " OK #{team} => #{team_rec.name}, #{team_rec.country.name}"
143
+ elsif recs.size == 0
144
+ msg = "NAME ERROR - no team match found for >#{team}<"
145
+ @errors << [msg]
146
+ puts "!! #{msg}"
147
+ else
148
+ msg = "NAME ERROR - ambigous; too many team matches (#{recs.size}) found for >#{team}<"
149
+ @errors << [msg]
150
+ puts "!! #{msg}"
151
+ end
152
+ end
153
+
154
+
155
+
156
+
157
+
158
+ ## note: pass along stage (if present): stage - optional from heading!!!!
159
+ if stage
160
+ matches.each do |match|
161
+ match = match.update( stage: stage )
162
+ end
163
+ end
164
+
165
+ data[ league ] ||= {}
166
+ data[ league ][ season.key ] ||= []
167
+
168
+ data[ league ][ season.key ] += matches
169
+ ## note - skip teams, rounds, and groups for now
170
+ end
171
+
172
+ ## check - only one league and one season
173
+ ## allowed in quick style
174
+
175
+
176
+ leagues = data.keys
177
+ if leagues.size != 1
178
+ puts "!! (QUICK) PARSE ERROR - expected one league only; got #{leagues.size}:"
179
+ pp leagues
180
+ exit 1
181
+ end
182
+
183
+ seasons = data[ leagues[0] ].keys
184
+ if seasons.size != 1
185
+ puts "!! (QUICK) PARSE ERROR - expected one #{leagues[0]} season only; got #{seasons.size}:"
186
+ pp seasons
187
+ exit 1
188
+ end
189
+
190
+ data[ leagues[0] ][ seasons[0] ]
191
+ end # method parse
192
+
193
+ end # class QuickMatchLinter
194
+ end # module SportDb
195
+
@@ -3,8 +3,8 @@ module Module
3
3
  module Formats
4
4
 
5
5
  MAJOR = 2 ## todo: namespace inside version or something - why? why not??
6
- MINOR = 0
7
- PATCH = 2
6
+ MINOR = 1
7
+ PATCH = 0
8
8
  VERSION = [MAJOR,MINOR,PATCH].join('.')
9
9
 
10
10
  def self.version