sportdb-quick 0.1.2 → 0.2.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: 9a1f7a6531aba4ac7f0223ee696b347f90d422d6297ee04e03d4839f2e3a1ba0
4
- data.tar.gz: 3d2e7b520183f40149856467646af58a17d39232d3bb0f78c285e7c220af7ece
3
+ metadata.gz: 743ddb45d7379bdcb351178da359316544e663307b5d96c34f6ac90b9752fce3
4
+ data.tar.gz: 86960f084c612aec1e04f183ba1f3a89959518355e498527734b23a265090fa9
5
5
  SHA512:
6
- metadata.gz: 071ffe16ce450fccdeb4a6fcbcc4749a2ffec2e22a95ca0b9ae8d80d981741bd6f960b0715a61aee23452dd699bd5043e46ab197fcc9a070e379e13a073f4508
7
- data.tar.gz: c765504847f2240b14068805e3965e2f186d38f78674f631d95cacd286c64b08007b4316043951979538bf6c1a7f7e25cf14f48e96fcd33fafbae6d124216c14
6
+ metadata.gz: 6068e848f99a756b9de1d4012cda3d5c6750dc99c329f773cbd692ffa9004f2cfa5835ffdb329aae055eaa30f1ffafeab42adc1a627d05ca040261d71d5476a7
7
+ data.tar.gz: d143f15ecca6cc4bdf3c72e0d8883c94622198e9fd721ce14e93ebc882c127ef4300d865bb05d7c129e82e2f27d81ea25ca4894e0d254a0b80e6600911cd6ac5
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.1.2
1
+ ### 0.2.1
2
2
 
3
3
  ### 0.0.1 / 2024-08-27
4
4
 
data/Manifest.txt CHANGED
@@ -9,7 +9,6 @@ lib/sportdb/quick/csv/goal_parser_csv.rb
9
9
  lib/sportdb/quick/csv/match_parser_csv.rb
10
10
  lib/sportdb/quick/csv/match_status_parser.rb
11
11
  lib/sportdb/quick/match_parser.rb
12
- lib/sportdb/quick/opts.rb
13
12
  lib/sportdb/quick/quick_league_outline_reader.rb
14
13
  lib/sportdb/quick/quick_match_reader.rb
15
14
  lib/sportdb/quick/version.rb
data/bin/fbt CHANGED
@@ -26,8 +26,8 @@ require 'optparse'
26
26
 
27
27
  args = ARGV
28
28
  opts = { debug: false,
29
- metal: false,
30
- quick: true }
29
+ file: nil,
30
+ }
31
31
 
32
32
  parser = OptionParser.new do |parser|
33
33
  parser.banner = "Usage: #{$PROGRAM_NAME} [options]"
@@ -35,24 +35,21 @@ require 'optparse'
35
35
  ##
36
36
  ## check if git has a offline option?? (use same)
37
37
  ## check for other tools - why? why not?
38
-
39
-
40
- parser.on( "--verbose", "--debug",
38
+ # parser.on( "-q", "--quiet",
39
+ # "less debug output/messages - default is (#{!opts[:debug]})" ) do |debug|
40
+ # opts[:debug] = false
41
+ # end
42
+ parser.on( "--verbose", "--debug",
41
43
  "turn on verbose / debug output (default: #{opts[:debug]})" ) do |debug|
42
- opts[:debug] = true
43
- end
44
+ opts[:debug] = true
45
+ end
46
+
47
+ parser.on( "-f FILE", "--file FILE",
48
+ "read datafiles (pathspecs) via .csv file") do |file|
49
+ opts[:file] = file
50
+ end
44
51
 
45
- parser.on( "--metal",
46
- "turn off typed parse tree; show to the metal tokens"+
47
- " (default: #{opts[:metal]})" ) do |metal|
48
- opts[:metal] = true
49
- end
50
52
 
51
- parser.on( "--quick",
52
- "use quick match reader; output matches in json"+
53
- " (default: #{opts[:quick]})" ) do |quick|
54
- opts[:quick] = true
55
- end
56
53
  end
57
54
  parser.parse!( args )
58
55
 
@@ -62,58 +59,110 @@ puts "ARGV:"
62
59
  p args
63
60
 
64
61
 
62
+ ## todo/check - use packs or projects or such
63
+ ## instead of specs - why? why not?
64
+ specs = []
65
+ if opts[:file]
66
+ recs = read_csv( opts[:file] )
67
+ pp recs
68
+ ## note - make pathspecs relative to passed in file arg!!!
69
+ basedir = File.dirname( opts[:file] )
70
+ recs.each do |rec|
71
+ paths = SportDb::Parser::Opts.find( rec['path'], dir: basedir )
72
+ specs << [paths, rec]
73
+ end
74
+ else
75
+ paths = if args.empty?
76
+ [
77
+ '../../../openfootball/euro/2021--europe/euro.txt',
78
+ '../../../openfootball/euro/2024--germany/euro.txt',
79
+ ]
80
+ else
81
+ ## check for directories
82
+ ## and auto-expand
83
+ SportDb::Parser::Opts.expand_args( args )
84
+ end
85
+ specs << [paths, {}]
86
+ end
87
+
88
+
89
+ if opts[:debug]
90
+ SportDb::QuickMatchReader.debug = true
91
+ SportDb::MatchParser.debug = true
92
+ else
93
+ SportDb::QuickMatchReader.debug = false
94
+ SportDb::MatchParser.debug = false
95
+ LogUtils::Logger.root.level = :info
96
+ end
65
97
 
66
98
 
99
+ specs.each_with_index do |(paths, rec),i|
100
+ errors = []
101
+ paths.each_with_index do |path,j|
102
+ puts "==> [#{j+1}/#{paths.size}] reading >#{path}<..."
103
+ quick = SportDb::QuickMatchReader.new( read_text( path ) )
104
+ matches = quick.parse
105
+
106
+ if quick.errors?
107
+ puts "!! #{quick.errors.size} error(s):"
108
+ pp quick.errors
109
+
110
+ quick.errors.each do |err|
111
+ errors << [ path, *err ] # note: use splat (*) to add extra values (starting with msg)
112
+ end
113
+ end
114
+ puts " #{matches.size} match(es)"
115
+ end
116
+
117
+ if errors.size > 0
118
+ puts
119
+ puts "!! #{errors.size} PARSE ERRORS in #{paths.size} datafile(s)"
120
+ pp errors
121
+ else
122
+ puts
123
+ puts " OK - no parse errors in #{paths.size} datafile(s)"
124
+ end
125
+
126
+ ## add errors to rec via rec['errors'] to allow
127
+ ## for further processing/reporting
128
+ rec['errors'] = errors
129
+ end
67
130
 
68
- paths = if args.empty?
69
- [
70
- '../../../openfootball/euro/2021--europe/euro.txt',
71
- '../../../openfootball/euro/2024--germany/euro.txt',
72
- ]
73
- else
74
- ## check for directories
75
- ## and auto-expand
76
-
77
- SportDb::Quick::Opts.expand_args( args )
78
- end
79
131
 
80
132
 
81
- if opts[:quick]
133
+ ###
134
+ ## generate a report if --file option used
135
+ if opts[:file]
82
136
 
83
- paths.each_with_index do |path,i|
84
- puts "==> [#{i+1}/#{paths.size}] reading >#{path}<..."
137
+ buf = String.new
85
138
 
86
- matches = SportDb::QuickMatchReader.read( path )
87
- ## pp matches
88
- ## try json for matches
89
- data = matches.map {|match| match.as_json }
90
- pp data
91
- puts
92
- puts " #{data.size} match(es)"
93
- end
94
- else
95
- SportDb::Parser::Linter.debug = true if opts[:debug]
139
+ buf << "# fbt summary report - #{specs.size} dataset(s)\n\n"
96
140
 
97
- linter = SportDb::Parser::Linter.new
141
+ specs.each_with_index do |(paths, rec),i|
142
+ errors = rec['errors']
98
143
 
99
- errors = []
144
+ if errors.size > 0
145
+ buf << "!! #{errors.size} ERROR(S) "
146
+ else
147
+ buf << " OK "
148
+ end
149
+ buf << "%-20s" % rec['path']
150
+ buf << " - #{paths.size} datafile(s)"
151
+ buf << "\n"
100
152
 
101
- paths.each_with_index do |path,i|
102
- puts "==> [#{i+1}/#{paths.size}] reading >#{path}<..."
103
- linter.read( path, parse: !opts[:metal] )
153
+ if errors.size > 0
154
+ buf << errors.pretty_inspect
155
+ buf << "\n"
156
+ end
157
+ end
104
158
 
105
- errors += linter.errors if linter.errors?
106
- end
159
+ puts
160
+ puts "SUMMARY:"
161
+ puts buf
107
162
 
108
- if errors.size > 0
109
- puts
110
- pp errors
111
- puts
112
- puts "!! #{errors.size} parse error(s) in #{paths.size} datafiles(s)"
113
- else
114
- puts
115
- puts "OK no parse errors found in #{paths.size} datafile(s)"
116
- end
163
+ # maybe write out in the future?
164
+ # basedir = File.dirname( opts[:file] )
165
+ # basename = File.basename( opts[:file], File.extname( opts[:file] ))
117
166
  end
118
167
 
119
168
 
@@ -3,6 +3,12 @@ module SportDb
3
3
 
4
4
  class MatchParser ## simple match parser for team match schedules
5
5
 
6
+ def self.debug=(value) @@debug = value; end
7
+ def self.debug?() @@debug ||= false; end ## note: default is FALSE
8
+ def debug?() self.class.debug?; end
9
+
10
+ include Logging ## e.g. logger#debug, logger#info, etc.
11
+
6
12
 
7
13
  def self.parse( lines, start: )
8
14
  ## todo/fix: add support for txt and lines
@@ -13,11 +19,7 @@ class MatchParser ## simple match parser for team match schedules
13
19
  end
14
20
 
15
21
 
16
- include Logging ## e.g. logger#debug, logger#info, etc.
17
22
 
18
- def self.debug=(value) @@debug = value; end
19
- def self.debug?() @@debug ||= false; end ## note: default is FALSE
20
- def debug?() self.class.debug?; end
21
23
 
22
24
  def _read_lines( txt ) ## todo/check: add alias preproc_lines or build_lines or prep_lines etc. - why? why not?
23
25
  ## returns an array of lines with comments and empty lines striped / removed
@@ -70,10 +72,17 @@ class MatchParser ## simple match parser for team match schedules
70
72
  _read_lines( lines ) : lines
71
73
 
72
74
  @start = start
75
+ @errors = []
73
76
  end
74
77
 
75
78
 
79
+ attr_reader :errors
80
+ def errors?() @errors.size > 0; end
81
+
76
82
  def parse
83
+ ## note: every (new) read call - resets errors list to empty
84
+ @errors = []
85
+
77
86
  @last_date = nil
78
87
  @last_time = nil
79
88
  @last_round = nil
@@ -92,8 +101,6 @@ class MatchParser ## simple match parser for team match schedules
92
101
 
93
102
 
94
103
  @parser = Parser.new
95
-
96
- @errors = []
97
104
  @tree = []
98
105
 
99
106
  attrib_found = false
@@ -509,7 +516,7 @@ class MatchParser ## simple match parser for team match schedules
509
516
  end
510
517
  end
511
518
 
512
- pp [goals1,goals2]
519
+ pp [goals1,goals2] if debug?
513
520
 
514
521
  ## wrap in struct andd add/append to match
515
522
  =begin
@@ -547,7 +554,7 @@ class GoalStruct
547
554
  goals << goal
548
555
  end
549
556
 
550
- pp goals
557
+ pp goals if debug?
551
558
 
552
559
  ## quick & dirty - auto add goals to last match
553
560
  ## note - for hacky (quick& dirty) multi-line support
@@ -629,7 +636,9 @@ class GoalStruct
629
636
  else
630
637
  puts "!! PARSE ERROR - unexpected node type #{node_type} in match line; got:"
631
638
  pp node
632
- exit 1
639
+ ## exit 1
640
+ @errors << ["PARSE ERROR - unexpected node type #{node_type} in match line; got: #{node.inspect}"]
641
+ return
633
642
  end
634
643
  end
635
644
 
@@ -637,7 +646,9 @@ class GoalStruct
637
646
  if teams.size != 2
638
647
  puts "!! PARSE ERROR - expected two teams; got #{teams.size}:"
639
648
  pp teams
640
- exit 1
649
+ ## exit 1
650
+ @errors << ["PARSE ERROR - expected two teams; got #{teams.size}: #{teams.inspect}"]
651
+ return
641
652
  end
642
653
 
643
654
  team1 = teams[0]
@@ -86,7 +86,8 @@ class QuickLeagueOutlineReader
86
86
  ## => Österr. Bundesliga 2018/19, Regular Season
87
87
  ## => Österr. Bundesliga 2018/19, Championship Round
88
88
  ## etc.
89
- values = str.split( /[,<>‹›]/ ) ## note: allow , > < or › ‹ for now
89
+ ## note limit split to two parts only!!!!
90
+ values = str.split( /[,<>‹›]/, 2 ) ## note: allow , > < or › ‹ for now
90
91
  values = values.map { |value| value.strip } ## remove all whitespaces
91
92
  values
92
93
  end
@@ -4,6 +4,12 @@
4
4
  module SportDb
5
5
  class QuickMatchReader
6
6
 
7
+ def self.debug=(value) @@debug = value; end
8
+ def self.debug?() @@debug ||= false; end ## note: default is FALSE
9
+ def debug?() self.class.debug?; end
10
+
11
+
12
+
7
13
  def self.read( path ) ## use - rename to read_file or from_file etc. - why? why not?
8
14
  txt = File.open( path, 'r:utf-8' ) {|f| f.read }
9
15
  parse( txt )
@@ -17,16 +23,43 @@ class QuickMatchReader
17
23
  include Logging
18
24
 
19
25
  def initialize( txt )
26
+ @errors = []
20
27
  @txt = txt
21
28
  end
22
29
 
30
+ attr_reader :errors
31
+ def errors?() @errors.size > 0; end
32
+
33
+
34
+ ###
35
+ # helpers get matches & more after parse; all stored in data
36
+ #
37
+ ## change/rename to event - why? why not?
38
+ def league_name
39
+ league = @data.keys[0]
40
+ season = @data[ league ].keys[0]
41
+
42
+ "#{league} #{season}"
43
+ end
44
+
45
+ def matches
46
+ league = @data.keys[0]
47
+ season = @data[ league ].keys[0]
48
+ @data[league][season]
49
+ end
50
+
51
+
52
+
23
53
  def parse
24
- data = {} # return data hash with leagues
54
+ ## note: every (new) read call - resets errors list to empty
55
+ @errors = []
56
+
57
+ @data = {} # return data hash with leagues
25
58
  # and seasons
26
59
  # for now merge stage into matches
27
60
 
28
61
  secs = QuickLeagueOutlineReader.parse( @txt )
29
- pp secs
62
+ pp secs if debug?
30
63
 
31
64
  secs.each do |sec| ## sec(tion)s
32
65
  season = Season.parse( sec[:season] ) ## convert (str) to season obj!!!
@@ -46,14 +79,20 @@ class QuickMatchReader
46
79
 
47
80
  auto_conf_teams, matches, rounds, groups = parser.parse
48
81
 
49
- puts ">>> #{auto_conf_teams.size} teams:"
50
- pp auto_conf_teams
51
- puts ">>> #{matches.size} matches:"
52
- ## pp matches
53
- puts ">>> #{rounds.size} rounds:"
54
- pp rounds
55
- puts ">>> #{groups.size} groups:"
56
- pp groups
82
+ ## auto-add "upstream" errors from parser
83
+ @errors += parser.errors if parser.errors?
84
+
85
+
86
+ if debug?
87
+ puts ">>> #{auto_conf_teams.size} teams:"
88
+ pp auto_conf_teams
89
+ puts ">>> #{matches.size} matches:"
90
+ ## pp matches
91
+ puts ">>> #{rounds.size} rounds:"
92
+ pp rounds
93
+ puts ">>> #{groups.size} groups:"
94
+ pp groups
95
+ end
57
96
 
58
97
  ## note: pass along stage (if present): stage - optional from heading!!!!
59
98
  if stage
@@ -62,10 +101,10 @@ class QuickMatchReader
62
101
  end
63
102
  end
64
103
 
65
- data[ league ] ||= {}
66
- data[ league ][ season.key ] ||= []
104
+ @data[ league ] ||= {}
105
+ @data[ league ][ season.key ] ||= []
67
106
 
68
- data[ league ][ season.key ] += matches
107
+ @data[ league ][ season.key ] += matches
69
108
  ## note - skip teams, rounds, and groups for now
70
109
  end
71
110
 
@@ -73,21 +112,21 @@ class QuickMatchReader
73
112
  ## allowed in quick style
74
113
 
75
114
 
76
- leagues = data.keys
115
+ leagues = @data.keys
77
116
  if leagues.size != 1
78
117
  puts "!! (QUICK) PARSE ERROR - expected one league only; got #{leagues.size}:"
79
118
  pp leagues
80
119
  exit 1
81
120
  end
82
121
 
83
- seasons = data[ leagues[0] ].keys
122
+ seasons = @data[ leagues[0] ].keys
84
123
  if seasons.size != 1
85
124
  puts "!! (QUICK) PARSE ERROR - expected one #{leagues[0]} season only; got #{seasons.size}:"
86
125
  pp seasons
87
126
  exit 1
88
127
  end
89
128
 
90
- data[ leagues[0] ][ seasons[0] ]
129
+ @data[ leagues[0] ][ seasons[0] ]
91
130
  end # method parse
92
131
 
93
132
  end # class QuickMatchReader
@@ -3,8 +3,8 @@ module SportDb
3
3
  module Module
4
4
  module Quick
5
5
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
6
- MINOR = 1
7
- PATCH = 2
6
+ MINOR = 2
7
+ PATCH = 1
8
8
  VERSION = [MAJOR,MINOR,PATCH].join('.')
9
9
 
10
10
  def self.version
data/lib/sportdb/quick.rb CHANGED
@@ -16,8 +16,8 @@ end
16
16
 
17
17
  ## our own code
18
18
  require_relative 'quick/version'
19
- require_relative 'quick/opts'
20
19
 
20
+ # require_relative 'quick/opts'
21
21
  # require_relative 'quick/linter'
22
22
  # require_relative 'quick/outline_reader'
23
23
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sportdb-quick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.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: 2024-09-18 00:00:00.000000000 Z
11
+ date: 2024-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sportdb-parser
@@ -107,7 +107,6 @@ files:
107
107
  - lib/sportdb/quick/csv/match_parser_csv.rb
108
108
  - lib/sportdb/quick/csv/match_status_parser.rb
109
109
  - lib/sportdb/quick/match_parser.rb
110
- - lib/sportdb/quick/opts.rb
111
110
  - lib/sportdb/quick/quick_league_outline_reader.rb
112
111
  - lib/sportdb/quick/quick_match_reader.rb
113
112
  - lib/sportdb/quick/version.rb
@@ -1,70 +0,0 @@
1
-
2
- module SportDb
3
- module Quick
4
-
5
- ###
6
- ## note - Opts Helpers for now nested inside Parser - keep here? why? why not?
7
- class Opts
8
-
9
- SEASON_RE = %r{ (?:
10
- \d{4}-\d{2}
11
- | \d{4}(--[a-z0-9_-]+)?
12
- )
13
- }x
14
- SEASON = SEASON_RE.source ## "inline" helper for embedding in other regexes - keep? why? why not?
15
-
16
-
17
- ## note: if pattern includes directory add here
18
- ## (otherwise move to more "generic" datafile) - why? why not?
19
- MATCH_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
20
- #{SEASON}
21
- /[a-z0-9_-]+\.txt$ ## txt e.g /1-premierleague.txt
22
- }x
23
-
24
-
25
- def self.find( path )
26
- datafiles = []
27
-
28
- ## note: normalize path - use File.expand_path ??
29
- ## change all backslash to slash for now
30
- ## path = path.gsub( "\\", '/' )
31
- path = File.expand_path( path )
32
-
33
- ## check all txt files
34
- ## note: incl. files starting with dot (.)) as candidates
35
- ## (normally excluded with just *)
36
- candidates = Dir.glob( "#{path}/**/{*,.*}.txt" )
37
- ## pp candidates
38
- candidates.each do |candidate|
39
- datafiles << candidate if MATCH_RE.match( candidate )
40
- end
41
-
42
- ## pp datafiles
43
- datafiles
44
- end
45
-
46
-
47
- def self.expand_args( args )
48
- paths = []
49
-
50
- args.each do |arg|
51
- ## check if directory
52
- if Dir.exist?( arg )
53
- datafiles = find( arg )
54
- puts
55
- puts " found #{datafiles.size} match txt datafiles in #{arg}"
56
- pp datafiles
57
- paths += datafiles
58
- else
59
- ## assume it's a file
60
- paths << arg
61
- end
62
- end
63
-
64
- paths
65
- end
66
- end # class Opts
67
-
68
-
69
- end # module Quick
70
- end # module SportDb