sportdb-quick 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ee93b658f2f6fce94a131931ea37908a2edbfa19a182ec20072447b57ffc847
4
- data.tar.gz: f5fa5ab664d71ea9a2ab8c62e1bd30d42fa678e0b2a7564124623dc5d7cd2963
3
+ metadata.gz: dc074126897237cd4cdb59c160e6dd41fa5b9e1ec3581472eeb68f520e486a61
4
+ data.tar.gz: 32112335ee74977ebd243e4ead540dabb49b291d837933315d57f7d3d86a47b4
5
5
  SHA512:
6
- metadata.gz: b0df0b970600ee24a88d09ddffec1caa8ef94cfa75561569638da954357cec2d97ffc7ea566f03e42ec814a5998c99da79f861c54a863a439f1778a3f0426ab0
7
- data.tar.gz: 01e1ad205c4d271a68136784a17b8f1b7987bdfa5e9b4ba5f395b42f6b488a53747525ecd7bea1e2c188012219529d7611e7d35f49ec4e5e7d499cc791e4e80a
6
+ metadata.gz: d0e23a4e07fa3e811c82eed4215d4229bc548e130d7e8bac70a85f8307928e50b28862e14b9a70c887166282c4efdb937d9533c1bfe0b1fddaced7b6b77d6729
7
+ data.tar.gz: dd442c2ae016aad05d5aa5e21dcd4420bb45808bdc18cf5759e97a37849527dcd1a9ab89da7a8ecb48a5d5a52956d7f36ae1b506a170dae138234e61925520a1
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.1.1
1
+ ### 0.2.0
2
2
 
3
3
  ### 0.0.1 / 2024-08-27
4
4
 
data/Manifest.txt CHANGED
@@ -3,13 +3,13 @@ Manifest.txt
3
3
  README.md
4
4
  Rakefile
5
5
  bin/fbt
6
+ bin/fbtxt2json
6
7
  lib/sportdb/quick.rb
7
8
  lib/sportdb/quick/csv/goal.rb
8
9
  lib/sportdb/quick/csv/goal_parser_csv.rb
9
10
  lib/sportdb/quick/csv/match_parser_csv.rb
10
11
  lib/sportdb/quick/csv/match_status_parser.rb
11
12
  lib/sportdb/quick/match_parser.rb
12
- lib/sportdb/quick/opts.rb
13
13
  lib/sportdb/quick/quick_league_outline_reader.rb
14
14
  lib/sportdb/quick/quick_match_reader.rb
15
15
  lib/sportdb/quick/version.rb
data/bin/fbt CHANGED
@@ -26,8 +26,9 @@ require 'optparse'
26
26
 
27
27
  args = ARGV
28
28
  opts = { debug: false,
29
- metal: false,
30
- quick: true }
29
+ json: false,
30
+ file: nil,
31
+ }
31
32
 
32
33
  parser = OptionParser.new do |parser|
33
34
  parser.banner = "Usage: #{$PROGRAM_NAME} [options]"
@@ -35,24 +36,26 @@ require 'optparse'
35
36
  ##
36
37
  ## check if git has a offline option?? (use same)
37
38
  ## check for other tools - why? why not?
39
+ parser.on( "-q", "--quiet",
40
+ "less debug output/messages - default is (#{!opts[:debug]})" ) do |debug|
41
+ opts[:debug] = false
42
+ end
43
+ # parser.on( "--verbose", "--debug",
44
+ # "turn on verbose / debug output (default: #{opts[:debug]})" ) do |debug|
45
+ # opts[:debug] = true
46
+ # end
47
+
48
+ parser.on( "-j", "--json",
49
+ "print out in .json - default is (#{opts[:json]})" ) do |json|
50
+ opts[:json] = true
51
+ end
52
+
53
+ parser.on( "-f FILE", "--file FILE",
54
+ "read datafiles (pathspecs) via .csv file") do |file|
55
+ opts[:file] = file
56
+ end
38
57
 
39
58
 
40
- parser.on( "--verbose", "--debug",
41
- "turn on verbose / debug output (default: #{opts[:debug]})" ) do |debug|
42
- opts[:debug] = true
43
- end
44
-
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
-
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
59
  end
57
60
  parser.parse!( args )
58
61
 
@@ -62,58 +65,117 @@ puts "ARGV:"
62
65
  p args
63
66
 
64
67
 
68
+ ## todo/check - use packs or projects or such
69
+ ## instead of specs - why? why not?
70
+ specs = []
71
+ if opts[:file]
72
+ recs = read_csv( opts[:file] )
73
+ pp recs
74
+ ## note - make pathspecs relative to passed in file arg!!!
75
+ basedir = File.dirname( opts[:file] )
76
+ recs.each do |rec|
77
+ paths = SportDb::Parser::Opts.find( rec['path'], dir: basedir )
78
+ specs << [paths, rec]
79
+ end
80
+ else
81
+ paths = if args.empty?
82
+ [
83
+ '../../../openfootball/euro/2021--europe/euro.txt',
84
+ '../../../openfootball/euro/2024--germany/euro.txt',
85
+ ]
86
+ else
87
+ ## check for directories
88
+ ## and auto-expand
89
+ SportDb::Parser::Opts.expand_args( args )
90
+ end
91
+ specs << [paths, {}]
92
+ end
93
+
94
+
95
+ if opts[:debug]
96
+ SportDb::QuickMatchReader.debug = true
97
+ SportDb::MatchParser.debug = true
98
+ else
99
+ SportDb::QuickMatchReader.debug = false
100
+ SportDb::MatchParser.debug = false
101
+ LogUtils::Logger.root.level = :info
102
+ end
65
103
 
66
104
 
105
+ specs.each_with_index do |(paths, rec),i|
106
+ errors = []
107
+ paths.each_with_index do |path,j|
108
+ puts "==> [#{j+1}/#{paths.size}] reading >#{path}<..."
109
+ quick = SportDb::QuickMatchReader.new( read_text( path ) )
110
+ matches = quick.parse
111
+
112
+ if quick.errors?
113
+ puts "!! #{quick.errors.size} error(s):"
114
+ pp quick.errors
115
+
116
+ quick.errors.each do |err|
117
+ errors << [ path, *err ] # note: use splat (*) to add extra values (starting with msg)
118
+ end
119
+ end
120
+
121
+ ## pp matches
122
+ ## try json for matches
123
+ if opts[:json]
124
+ data = matches.map {|match| match.as_json }
125
+ pp data
126
+ end
127
+ puts " #{matches.size} match(es)"
128
+ end
129
+
130
+ if errors.size > 0
131
+ puts
132
+ puts "!! #{errors.size} PARSE ERRORS in #{paths.size} datafile(s)"
133
+ pp errors
134
+ else
135
+ puts
136
+ puts " OK - no parse errors in #{paths.size} datafile(s)"
137
+ end
138
+
139
+ ## add errors to rec via rec['errors'] to allow
140
+ ## for further processing/reporting
141
+ rec['errors'] = errors
142
+ end
67
143
 
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
144
 
80
145
 
81
- if opts[:quick]
146
+ ###
147
+ ## generate a report if --file option used
148
+ if opts[:file]
82
149
 
83
- paths.each_with_index do |path,i|
84
- puts "==> [#{i+1}/#{paths.size}] reading >#{path}<..."
150
+ buf = String.new
85
151
 
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]
152
+ buf << "# fbt summary report - #{specs.size} dataset(s)\n\n"
96
153
 
97
- linter = SportDb::Parser::Linter.new
154
+ specs.each_with_index do |(paths, rec),i|
155
+ errors = rec['errors']
98
156
 
99
- errors = []
157
+ if errors.size > 0
158
+ buf << "!! #{errors.size} ERROR(S) "
159
+ else
160
+ buf << " OK "
161
+ end
162
+ buf << "%-20s" % rec['path']
163
+ buf << " - #{paths.size} datafile(s)"
164
+ buf << "\n"
100
165
 
101
- paths.each_with_index do |path,i|
102
- puts "==> [#{i+1}/#{paths.size}] reading >#{path}<..."
103
- linter.read( path, parse: !opts[:metal] )
166
+ if errors.size > 0
167
+ buf << errors.pretty_inspect
168
+ buf << "\n"
169
+ end
170
+ end
104
171
 
105
- errors += linter.errors if linter.errors?
106
- end
172
+ puts
173
+ puts "SUMMARY:"
174
+ puts buf
107
175
 
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
176
+ # maybe write out in the future?
177
+ # basedir = File.dirname( opts[:file] )
178
+ # basename = File.basename( opts[:file], File.extname( opts[:file] ))
117
179
  end
118
180
 
119
181
 
data/bin/fbtxt2json ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ## tip: to test run:
4
+ ## ruby -I ./lib bin/fbtxt2json
5
+
6
+
7
+ ## our own code
8
+ require 'sportdb/quick'
9
+
10
+
11
+
12
+ require 'optparse'
13
+
14
+
15
+
16
+ args = ARGV
17
+ opts = { debug: false,
18
+ }
19
+
20
+ parser = OptionParser.new do |parser|
21
+ parser.banner = "Usage: #{$PROGRAM_NAME} [options]"
22
+
23
+ ##
24
+ ## check if git has a offline option?? (use same)
25
+ ## check for other tools - why? why not?
26
+ parser.on( "-q", "--quiet",
27
+ "less debug output/messages - default is (#{!opts[:debug]})" ) do |debug|
28
+ opts[:debug] = false
29
+ end
30
+ end
31
+ parser.parse!( args )
32
+
33
+ puts "OPTS:"
34
+ p opts
35
+ puts "ARGV:"
36
+ p args
37
+
38
+
39
+ path = if args.empty?
40
+ '../../../openfootball/euro/2021--europe/euro.txt'
41
+ elsif args.size == 1
42
+ args[0]
43
+ else
44
+ puts "!! wrong number of args, got #{args.size} - #{args.inspect} - only one arg supported/expected"
45
+ exit 1
46
+ end
47
+
48
+
49
+ if opts[:debug]
50
+ SportDb::QuickMatchReader.debug = true
51
+ SportDb::MatchParser.debug = true
52
+ else
53
+ SportDb::QuickMatchReader.debug = false
54
+ SportDb::MatchParser.debug = false
55
+ LogUtils::Logger.root.level = :info
56
+ end
57
+
58
+
59
+ puts "==> reading >#{path}<..."
60
+ quick = SportDb::QuickMatchReader.new( read_text( path ) )
61
+ matches = quick.parse
62
+
63
+ data = matches.map {|match| match.as_json }
64
+ pp data
65
+ puts
66
+ puts " #{matches.size} match(es)"
67
+
68
+ if quick.errors?
69
+ puts "!! #{quick.errors.size} parse error(s):"
70
+ pp quick.errors
71
+ end
72
+
73
+
74
+ puts "bye"
75
+
@@ -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
@@ -566,12 +573,13 @@ class GoalStruct
566
573
  logger.debug( "parse match: >#{nodes}<" )
567
574
 
568
575
  ## collect (possible) nodes by type
569
- num = nil
570
- date = nil
571
- time = nil
572
- teams = []
573
- score = nil
574
- more = []
576
+ num = nil
577
+ date = nil
578
+ time = nil
579
+ teams = []
580
+ score = nil
581
+ more = []
582
+ status = nil
575
583
 
576
584
  while !nodes.empty?
577
585
  node = nodes.shift
@@ -608,6 +616,8 @@ class GoalStruct
608
616
 
609
617
  score = Score.new( *values )
610
618
  ## pp score
619
+ elsif node_type == :status # e.g. awarded, canceled, postponed, etc.
620
+ status = node[1]
611
621
  elsif node_type == :vs
612
622
  ## skip; do nothing
613
623
  ##
@@ -626,7 +636,9 @@ class GoalStruct
626
636
  else
627
637
  puts "!! PARSE ERROR - unexpected node type #{node_type} in match line; got:"
628
638
  pp node
629
- exit 1
639
+ ## exit 1
640
+ @errors << ["PARSE ERROR - unexpected node type #{node_type} in match line; got: #{node.inspect}"]
641
+ return
630
642
  end
631
643
  end
632
644
 
@@ -634,7 +646,9 @@ class GoalStruct
634
646
  if teams.size != 2
635
647
  puts "!! PARSE ERROR - expected two teams; got #{teams.size}:"
636
648
  pp teams
637
- exit 1
649
+ ## exit 1
650
+ @errors << ["PARSE ERROR - expected two teams; got #{teams.size}: #{teams.inspect}"]
651
+ return
638
652
  end
639
653
 
640
654
  team1 = teams[0]
@@ -711,7 +725,6 @@ class GoalStruct
711
725
  time_str = time if date && time
712
726
 
713
727
 
714
- status = nil
715
728
  ground = nil
716
729
 
717
730
  @matches << Import::Match.new( num: num,
@@ -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,23 @@ 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
+
23
33
  def parse
34
+ ## note: every (new) read call - resets errors list to empty
35
+ @errors = []
36
+
24
37
  data = {} # return data hash with leagues
25
38
  # and seasons
26
39
  # for now merge stage into matches
27
40
 
28
41
  secs = QuickLeagueOutlineReader.parse( @txt )
29
- pp secs
42
+ pp secs if debug?
30
43
 
31
44
  secs.each do |sec| ## sec(tion)s
32
45
  season = Season.parse( sec[:season] ) ## convert (str) to season obj!!!
@@ -46,14 +59,20 @@ class QuickMatchReader
46
59
 
47
60
  auto_conf_teams, matches, rounds, groups = parser.parse
48
61
 
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
62
+ ## auto-add "upstream" errors from parser
63
+ @errors += parser.errors if parser.errors?
64
+
65
+
66
+ if debug?
67
+ puts ">>> #{auto_conf_teams.size} teams:"
68
+ pp auto_conf_teams
69
+ puts ">>> #{matches.size} matches:"
70
+ ## pp matches
71
+ puts ">>> #{rounds.size} rounds:"
72
+ pp rounds
73
+ puts ">>> #{groups.size} groups:"
74
+ pp groups
75
+ end
57
76
 
58
77
  ## note: pass along stage (if present): stage - optional from heading!!!!
59
78
  if stage
@@ -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 = 1
6
+ MINOR = 2
7
+ PATCH = 0
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.1
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-18 00:00:00.000000000 Z
11
+ date: 2024-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sportdb-parser
@@ -90,6 +90,7 @@ description: sportdb-quick - football.txt (quick) match readers and more
90
90
  email: gerald.bauer@gmail.com
91
91
  executables:
92
92
  - fbt
93
+ - fbtxt2json
93
94
  extensions: []
94
95
  extra_rdoc_files:
95
96
  - CHANGELOG.md
@@ -101,13 +102,13 @@ files:
101
102
  - README.md
102
103
  - Rakefile
103
104
  - bin/fbt
105
+ - bin/fbtxt2json
104
106
  - lib/sportdb/quick.rb
105
107
  - lib/sportdb/quick/csv/goal.rb
106
108
  - lib/sportdb/quick/csv/goal_parser_csv.rb
107
109
  - lib/sportdb/quick/csv/match_parser_csv.rb
108
110
  - lib/sportdb/quick/csv/match_status_parser.rb
109
111
  - lib/sportdb/quick/match_parser.rb
110
- - lib/sportdb/quick/opts.rb
111
112
  - lib/sportdb/quick/quick_league_outline_reader.rb
112
113
  - lib/sportdb/quick/quick_match_reader.rb
113
114
  - 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