fbtok 0.2.2 → 0.3.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: a0ce828e29e589e804a281a71a1c1160951b669a6fecd82cc42dc9bebf059dd1
4
- data.tar.gz: 42bcc2682928350e3dc4344ea245e1a5da2156743eb3917a293b963ed93123c5
3
+ metadata.gz: db7e5c105200820cbce7e9701ed2b8ce0506e366f4215a013288b66b625528ff
4
+ data.tar.gz: 3f02e52b461d14d014a3a4c3283dd452f0ca6316048969b5cf0af1cd4bd457b8
5
5
  SHA512:
6
- metadata.gz: 3c1dd2f87074bf4d2c063df0032b5068d8c023f190a090492a964d210f7a0eae20e3239a61bc387e1f6f0313a8dc316ff5cd62971b383cbe8690f11f1199e117
7
- data.tar.gz: 3020d52799befbda3d2d45a8f2d830e1fcb4e5b8330652fa04b0e46563d9b979b8ba63c82756519d64e1db144d421f70cb78949865f1c3c0d7aaba017b6c57ab
6
+ metadata.gz: e8c77935b70909ac04697276af902f0597f6eed411b8bddee77248a0145c1fb704eb58a59cd49744ac7e93da97fa5410ca5a35825ea3ec4ca0ea4f834d30543f
7
+ data.tar.gz: 35ef329be9dddaaf94658252e9e2684b4f3f63a89da8484db3507ab36f8afefc319d2ab4f3154389539a7ad6545779dd39e710f0eb7e82990988690cea107458
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.2.2
1
+ ### 0.3.0
2
2
  ### 0.0.1 / 2025-01-02
3
3
 
4
4
  * Everything is new. First release.
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'hoe'
2
2
 
3
3
 
4
4
  Hoe.spec 'fbtok' do
5
- self.version = '0.2.2'
5
+ self.version = '0.3.0'
6
6
 
7
7
  self.summary = "fbtok - football.txt lint tools incl. tokenizer, parser & more"
8
8
  self.description = summary
data/bin/fbchk CHANGED
@@ -9,6 +9,7 @@
9
9
  $LOAD_PATH.unshift( File.expand_path( '/sports/sportdb/sport.db/sportdb-structs/lib' ))
10
10
  $LOAD_PATH.unshift( File.expand_path( '/sports/sportdb/sport.db/sportdb-catalogs/lib' ))
11
11
  $LOAD_PATH.unshift( File.expand_path( '/sports/sportdb/sport.db/sportdb-search/lib' ))
12
+ $LOAD_PATH.unshift( File.expand_path( '/sports/sportdb/sport.db/sportdb-formats/lib' ))
12
13
 
13
14
 
14
15
  ## our own code
@@ -58,52 +59,51 @@ end
58
59
  parser.parse!( args )
59
60
 
60
61
 
61
- puts "OPTS:"
62
- p opts
63
- puts "ARGV:"
64
- p args
65
-
66
-
67
- ## todo/check - use packs or projects or such
68
- ## instead of specs - why? why not?
69
- specs = []
70
- if opts[:file]
71
- recs = read_csv( opts[:file] )
72
- pp recs
73
- ## note - make pathspecs relative to passed in file arg!!!
74
- basedir = File.dirname( opts[:file] )
75
- recs.each do |rec|
76
- paths = SportDb::Parser::Opts.find( rec['path'], dir: basedir )
77
- specs << [paths, rec]
78
- end
79
- else
80
- paths = if args.empty?
81
- []
82
- else
83
- ## check for directories
84
- ## and auto-expand
85
- SportDb::Parser::Opts.expand_args( args )
86
- end
87
- specs << [paths, {}]
88
- end
89
-
90
-
91
62
  if opts[:debug]
92
- SportDb::QuickMatchLinter.debug = true
93
- SportDb::QuickMatchReader.debug = true
94
- SportDb::MatchParser.debug = true
63
+ puts "OPTS:"
64
+ p opts
65
+ puts "ARGV:"
66
+ p args
67
+
68
+ SportDb::QuickMatchLinter.debug = true
69
+ SportDb::QuickMatchReader.debug = true
70
+ SportDb::MatchParser.debug = true
95
71
  else
96
- SportDb::QuickMatchLinter.debug = false
97
- SportDb::QuickMatchReader.debug = false
98
- SportDb::MatchParser.debug = false
99
- LogUtils::Logger.root.level = :info
72
+ SportDb::QuickMatchLinter.debug = false
73
+ SportDb::QuickMatchReader.debug = false
74
+ SportDb::MatchParser.debug = false
75
+ LogUtils::Logger.root.level = :info
100
76
  end
101
77
 
102
78
 
103
- specs.each_with_index do |(paths, rec),i|
79
+
80
+
81
+ ## todo/check - use packs or projects or such
82
+ ## instead of specs - why? why not?
83
+ specs = if opts[:file]
84
+ SportDb::Parser::Opts.read_pathspecs( opts[:file] )
85
+ else
86
+ paths = if args.empty?
87
+ []
88
+ else
89
+ ## check for directories
90
+ ## and auto-expand
91
+ SportDb::Parser::Opts.expand_args( args )
92
+ end
93
+ ## always return array of specs
94
+ [SportDb::Parser::Opts.build_pathspec( paths: paths)]
95
+ end
96
+
97
+
98
+
99
+
100
+ specs.each_with_index do |spec,i|
101
+ paths = spec.paths
102
+ rec = spec.rec
103
+
104
104
  errors = []
105
105
  paths.each_with_index do |path,j|
106
- puts "==> [#{j+1}/#{paths.size}] reading >#{path}<..."
106
+ puts "==> [#{i+1}/#{specs.size}, #{j+1}/#{paths.size}] reading >#{path}<..."
107
107
  quick = SportDb::QuickMatchLinter.new( read_text( path ),
108
108
  check_teams: opts[:teams] )
109
109
  matches = quick.parse
@@ -139,28 +139,9 @@ end
139
139
  ###
140
140
  ## generate a report if --file option used
141
141
  if opts[:file]
142
-
143
- buf = String.new
144
-
145
- buf << "# fbchk summary report - #{specs.size} dataset(s)\n\n"
146
-
147
- specs.each_with_index do |(paths, rec),i|
148
- errors = rec['errors']
149
-
150
- if errors.size > 0
151
- buf << "!! #{errors.size} ERROR(S) "
152
- else
153
- buf << " OK "
154
- end
155
- buf << "%-20s" % rec['path']
156
- buf << " - #{paths.size} datafile(s)"
157
- buf << "\n"
158
-
159
- if errors.size > 0
160
- buf << errors.pretty_inspect
161
- buf << "\n"
162
- end
163
- end
142
+ buf = SportDb::Parser::BatchReport.new(
143
+ specs,
144
+ title: 'fbchk summary report' ).build
164
145
 
165
146
  puts
166
147
  puts "SUMMARY:"
@@ -168,7 +149,7 @@ if opts[:file]
168
149
 
169
150
  basedir = File.dirname( opts[:file] )
170
151
  basename = File.basename( opts[:file], File.extname( opts[:file] ))
171
- outpath = "#{basedir}/fbcheck.#{basename}.txt"
152
+ outpath = "#{basedir}/fbchk.#{basename}.txt"
172
153
  write_text( outpath, buf )
173
154
  end
174
155
 
data/bin/fbt CHANGED
@@ -50,51 +50,47 @@ require 'fbtok'
50
50
  end
51
51
  parser.parse!( args )
52
52
 
53
- puts "OPTS:"
54
- p opts
55
- puts "ARGV:"
56
- p args
57
-
58
-
59
- ## todo/check - use packs or projects or such
60
- ## instead of specs - why? why not?
61
- specs = []
62
- if opts[:file]
63
- recs = read_csv( opts[:file] )
64
- pp recs
65
- ## note - make pathspecs relative to passed in file arg!!!
66
- basedir = File.dirname( opts[:file] )
67
- recs.each do |rec|
68
- paths = SportDb::Parser::Opts.find( rec['path'], dir: basedir )
69
- specs << [paths, rec]
70
- end
71
- else
72
- paths = if args.empty?
73
- [
74
- '../../../openfootball/euro/2021--europe/euro.txt',
75
- '../../../openfootball/euro/2024--germany/euro.txt',
76
- ]
77
- else
78
- ## check for directories
79
- ## and auto-expand
80
- SportDb::Parser::Opts.expand_args( args )
81
- end
82
- specs << [paths, {}]
83
- end
84
53
 
85
54
 
86
55
  if opts[:debug]
87
- SportDb::QuickMatchReader.debug = true
88
- SportDb::MatchParser.debug = true
56
+ puts "OPTS:"
57
+ p opts
58
+ puts "ARGV:"
59
+ p args
60
+
61
+ SportDb::QuickMatchReader.debug = true
62
+ SportDb::MatchParser.debug = true
89
63
  else
90
- SportDb::QuickMatchReader.debug = false
91
- SportDb::MatchParser.debug = false
92
- LogUtils::Logger.root.level = :info
64
+ SportDb::QuickMatchReader.debug = false
65
+ SportDb::MatchParser.debug = false
66
+ LogUtils::Logger.root.level = :info
93
67
  end
94
68
 
95
69
 
96
- specs.each_with_index do |(paths, rec),i|
70
+ ## todo/check - use packs or projects or such
71
+ ## instead of specs - why? why not?
72
+ specs = if opts[:file]
73
+ SportDb::Parser::Opts.read_pathspecs( opts[:file] )
74
+ else
75
+ paths = if args.empty?
76
+ ['/sports/openfootball/euro/2021--europe/euro.txt',
77
+ '/sports/openfootball/euro/2024--germany/euro.txt']
78
+ else
79
+ ## check for directories
80
+ ## and auto-expand
81
+ SportDb::Parser::Opts.expand_args( args )
82
+ end
83
+ ## always return array of specs
84
+ [SportDb::Parser::Opts.build_pathspec( paths: paths)]
85
+ end
86
+
87
+
88
+
89
+ specs.each_with_index do |spec,i|
90
+ paths = spec.paths
91
+ rec = spec.rec
97
92
  errors = []
93
+
98
94
  paths.each_with_index do |path,j|
99
95
  puts "==> [#{j+1}/#{paths.size}] reading >#{path}<..."
100
96
  quick = SportDb::QuickMatchReader.new( read_text( path ) )
@@ -130,28 +126,9 @@ end
130
126
  ###
131
127
  ## generate a report if --file option used
132
128
  if opts[:file]
133
-
134
- buf = String.new
135
-
136
- buf << "# fbt summary report - #{specs.size} dataset(s)\n\n"
137
-
138
- specs.each_with_index do |(paths, rec),i|
139
- errors = rec['errors']
140
-
141
- if errors.size > 0
142
- buf << "!! #{errors.size} ERROR(S) "
143
- else
144
- buf << " OK "
145
- end
146
- buf << "%-20s" % rec['path']
147
- buf << " - #{paths.size} datafile(s)"
148
- buf << "\n"
149
-
150
- if errors.size > 0
151
- buf << errors.pretty_inspect
152
- buf << "\n"
153
- end
154
- end
129
+ buf = SportDb::Parser::BatchReport.new(
130
+ specs,
131
+ title: 'fbt summary report' ).build
155
132
 
156
133
  puts
157
134
  puts "SUMMARY:"
@@ -163,5 +140,6 @@ if opts[:file]
163
140
  end
164
141
 
165
142
 
143
+
166
144
  puts "bye"
167
145
 
data/bin/fbtok CHANGED
@@ -44,49 +44,49 @@ parser = OptionParser.new do |parser|
44
44
  end
45
45
  parser.parse!( args )
46
46
 
47
- puts "OPTS:"
48
- p opts
49
- puts "ARGV:"
50
- p args
51
47
 
52
48
 
53
- ## todo/check - use packs or projects or such
54
- ## instead of specs - why? why not?
55
- specs = []
56
- if opts[:file]
57
- recs = read_csv( opts[:file] )
58
- pp recs
59
- ## note - make pathspecs relative to passed in file arg!!!
60
- basedir = File.dirname( opts[:file] )
61
- recs.each do |rec|
62
- paths = SportDb::Parser::Opts.find( rec['path'], dir: basedir )
63
- specs << [paths, rec]
64
- end
65
- else
66
- paths = if args.empty?
67
- [
68
- '../../../openfootball/euro/2021--europe/euro.txt',
69
- '../../../openfootball/euro/2024--germany/euro.txt',
70
- ]
71
- else
72
- ## check for directories
73
- ## and auto-expand
74
- SportDb::Parser::Opts.expand_args( args )
75
- end
76
- specs << [paths, {}]
49
+ if opts[:debug]
50
+ puts "OPTS:"
51
+ p opts
52
+ puts "ARGV:"
53
+ p args
54
+
55
+ SportDb::Parser::Linter.debug = true
56
+ SportDb::Parser::Opts.debug = true
77
57
  end
78
58
 
79
59
 
80
- SportDb::Parser::Linter.debug = true if opts[:debug]
60
+
61
+ ## todo/check - use packs or projects or such
62
+ ## instead of specs - why? why not?
63
+ specs = if opts[:file]
64
+ SportDb::Parser::Opts.read_pathspecs( opts[:file] )
65
+ else
66
+ paths = if args.empty?
67
+ ['/sports/openfootball/euro/2021--europe/euro.txt',
68
+ '/sports/openfootball/euro/2024--germany/euro.txt']
69
+ else
70
+ ## check for directories
71
+ ## and auto-expand
72
+ SportDb::Parser::Opts.expand_args( args )
73
+ end
74
+ ## always return array of specs
75
+ [SportDb::Parser::Opts.build_pathspec( paths: paths)]
76
+ end
77
+
81
78
 
82
79
  linter = SportDb::Parser::Linter.new
83
80
 
84
81
 
85
- specs.each_with_index do |(paths, rec),i|
86
- errors = []
82
+ specs.each_with_index do |spec,i|
83
+ paths = spec.paths
84
+ rec = spec.rec
85
+
86
+ errors = []
87
87
 
88
88
  paths.each_with_index do |path,j|
89
- puts "==> [#{j+1}/#{paths.size}] reading >#{path}<..."
89
+ puts "==> [#{i+1}/#{specs.size}, #{j+1}/#{paths.size}] reading >#{path}<..."
90
90
  linter.read( path, parse: false ) ## only tokenize (do NOT parse)
91
91
 
92
92
  errors += linter.errors if linter.errors?
@@ -112,35 +112,17 @@ end
112
112
  ## generate a report if --file option used
113
113
  if opts[:file]
114
114
 
115
- buf = String.new
116
-
117
- buf << "# fbtok summary report - #{specs.size} dataset(s)\n\n"
118
-
119
- specs.each_with_index do |(paths, rec),i|
120
- errors = rec['errors']
121
-
122
- if errors.size > 0
123
- buf << "!! #{errors.size} ERROR(S) "
124
- else
125
- buf << " OK "
126
- end
127
- buf << "%-20s" % rec['path']
128
- buf << " - #{paths.size} datafile(s)"
129
- buf << "\n"
130
-
131
- if errors.size > 0
132
- buf << errors.pretty_inspect
133
- buf << "\n"
134
- end
135
- end
115
+ buf = SportDb::Parser::BatchReport.new(
116
+ specs,
117
+ title: 'fbtok summary report' ).build
136
118
 
137
- puts
138
- puts "SUMMARY:"
139
- puts buf
119
+ puts
120
+ puts "SUMMARY:"
121
+ puts buf
140
122
 
141
- # maybe write out in the future?
142
- # basedir = File.dirname( opts[:file] )
143
- # basename = File.basename( opts[:file], File.extname( opts[:file] ))
123
+ # maybe write out in the future?
124
+ # basedir = File.dirname( opts[:file] )
125
+ # basename = File.basename( opts[:file], File.extname( opts[:file] ))
144
126
  end
145
127
 
146
128
  puts "bye"
data/bin/fbtree CHANGED
@@ -10,6 +10,7 @@ args = ARGV
10
10
 
11
11
  opts = {
12
12
  debug: true,
13
+ file: nil,
13
14
  }
14
15
 
15
16
  parser = OptionParser.new do |parser|
@@ -24,43 +25,117 @@ parser = OptionParser.new do |parser|
24
25
  "turn on verbose / debug output (default: #{opts[:debug]})" ) do |debug|
25
26
  opts[:debug] = true
26
27
  end
28
+
29
+ parser.on( "-f FILE", "--file FILE",
30
+ "read datafiles (pathspecs) via .csv file") do |file|
31
+ opts[:file] = file
32
+ ## note: for batch (massive) processing auto-set debug (verbose output) to false (as default)
33
+ opts[:debug] = false
34
+ end
35
+
27
36
  end
28
37
  parser.parse!( args )
29
38
 
30
- puts "OPTS:"
31
- p opts
32
- puts "ARGV:"
33
- p args
39
+
40
+ if opts[:debug]
41
+ puts "OPTS:"
42
+ p opts
43
+ puts "ARGV:"
44
+ p args
45
+
46
+ SportDb::Parser::Linter.debug = true
47
+ SportDb::Parser::Opts.debug = true
48
+ end
49
+
50
+
51
+
34
52
 
35
53
 
36
54
  ## todo/check - use packs or projects or such
37
55
  ## instead of specs - why? why not?
38
- paths = if args.empty?
39
- [
40
- '../../../openfootball/euro/2021--europe/euro.txt',
41
- '../../../openfootball/euro/2024--germany/euro.txt',
42
- ]
43
- else
44
- ## check for directories
45
- ## and auto-expand
46
- SportDb::Parser::Opts.expand_args( args )
47
- end
56
+ specs = if opts[:file]
57
+ SportDb::Parser::Opts.read_pathspecs( opts[:file] )
58
+ else
59
+ paths = if args.empty?
60
+ ['/sports/openfootball/euro/2021--europe/euro.txt',
61
+ '/sports/openfootball/euro/2024--germany/euro.txt']
62
+ else
63
+ ## check for directories
64
+ ## and auto-expand
65
+ SportDb::Parser::Opts.expand_args( args )
66
+ end
67
+ ## always return array of specs
68
+ [SportDb::Parser::Opts.build_pathspec( paths: paths)]
69
+ end
70
+
71
+
72
+
73
+ def dump_tree_stats( tree )
74
+ stats = Hash.new(0) ## track counts only for now
75
+ tree.each do |node|
76
+ stats[ node.class ] += 1
77
+ end
48
78
 
79
+ match_count = stats[ RaccMatchParser::MatchLine ]
80
+ goal_count = stats[ RaccMatchParser::GoalLine ]
81
+ lineup_count = stats[ RaccMatchParser::LineupLine ]
49
82
 
83
+ puts " #{match_count} MatchLine(s)" if match_count > 0
84
+ puts " #{goal_count} GoalLine(s)" if goal_count > 0
85
+ puts " #{lineup_count} LineupLine(s)" if lineup_count > 0
86
+ end
50
87
 
51
- SportDb::Parser::Linter.debug = true if opts[:debug]
52
88
 
53
- linter = SportDb::Parser::Linter.new
54
89
 
55
90
 
56
- paths.each_with_index do |path,i|
91
+ linter = SportDb::Parser::Linter.new
57
92
 
58
- puts "==> [#{i+1}/#{paths.size}] reading >#{path}<..."
59
93
 
60
- linter.read( path, parse: true )
94
+ specs.each_with_index do |spec,i|
95
+ paths = spec.paths
96
+ rec = spec.rec
97
+
98
+ errors = []
99
+
100
+ paths.each_with_index do |path,j|
101
+ puts "==> [#{i+1}/#{specs.size}, #{j+1}/#{paths.size}] reading >#{path}<..."
102
+ tree = linter.read( path, parse: true )
103
+ dump_tree_stats( tree )
104
+
105
+ errors += linter.errors if linter.errors?
106
+ end
107
+
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
117
+
118
+ ## add errors to rec via rec['errors'] to allow
119
+ ## for further processing/reporting
120
+ rec['errors'] = errors
61
121
  end
62
122
 
63
123
 
64
- puts "bye"
124
+ ###
125
+ ## generate a report if --file option used
126
+ if opts[:file]
65
127
 
128
+ buf = SportDb::Parser::BatchReport.new(
129
+ specs,
130
+ title: 'fbtree summary report' ).build
66
131
 
132
+ puts
133
+ puts "SUMMARY:"
134
+ puts buf
135
+
136
+ # maybe write out in the future?
137
+ # basedir = File.dirname( opts[:file] )
138
+ # basename = File.basename( opts[:file], File.extname( opts[:file] ))
139
+ end
140
+
141
+ puts "bye"
data/bin/fbx CHANGED
@@ -47,13 +47,18 @@ require 'fbtok'
47
47
  end
48
48
  parser.parse!( args )
49
49
 
50
- puts "OPTS:"
51
- p opts
52
- puts "ARGV:"
53
- p args
54
-
55
-
56
50
 
51
+ if opts[:debug]
52
+ puts "OPTS:"
53
+ p opts
54
+ puts "ARGV:"
55
+ p args
56
+
57
+ SportDb::MatchParser.debug = true
58
+ else
59
+ SportDb::MatchParser.debug = false
60
+ LogUtils::Logger.root.level = :info
61
+ end
57
62
 
58
63
 
59
64
  paths = if args.empty?
@@ -71,12 +76,6 @@ paths = if args.empty?
71
76
 
72
77
 
73
78
 
74
-
75
-
76
-
77
- SportDb::MatchParser.debug = true if opts[:debug]
78
-
79
-
80
79
  ## errors = []
81
80
 
82
81
 
@@ -84,16 +83,19 @@ paths.each_with_index do |path,i|
84
83
  puts "==> [#{i+1}/#{paths.size}] reading >#{path}<..."
85
84
 
86
85
  txt = read_text( path )
87
- secs = SportDb::QuickLeagueOutlineReader.parse( txt )
88
- ## pp secs
86
+ outline = SportDb::QuickLeagueOutline.parse( txt )
89
87
 
90
- secs.each_with_index do |sec,j| ## sec(tion)s
91
- season = Season.parse( sec[:season] ) ## convert (str) to season obj!!!
92
- league = sec[:league]
93
- stage = sec[:stage]
94
- lines = sec[:lines]
88
+ ## todo/fix - add each_sec_with_index upstream
89
+ ## add outline.secs.size - why? why not?
90
+ j = 0
91
+ secs_count = '?'
92
+ outline.each_sec do |sec| ## sec(tion)s
93
+ season = Season.parse( sec.season ) ## convert (str) to season obj!!!
94
+ league = sec.league
95
+ stage = sec.stage
96
+ lines = sec.lines
95
97
 
96
- puts " section #{j+1}/#{secs.size} - #{league} #{season}, #{stage} - #{lines.size} line(s)"
98
+ puts " section #{j+1}/#{secs_count} - #{league} #{season}, #{stage} - #{lines.size} line(s)"
97
99
 
98
100
  next if opts[:outline]
99
101
 
@@ -130,6 +132,8 @@ paths.each_with_index do |path,i|
130
132
  pp rounds
131
133
  puts ">>> #{groups.size} groups:"
132
134
  pp groups
135
+
136
+ j += 1
133
137
  end # each secs
134
138
  end # each paths
135
139
 
data/lib/fbtok/linter.rb CHANGED
@@ -30,18 +30,19 @@ def read( path, parse: true )
30
30
  ## note: every (new) read call - resets errors list to empty
31
31
  @errors = []
32
32
 
33
+ @tree = []
34
+
33
35
  outline = QuickMatchOutline.read( path )
34
36
 
35
37
  outline.each_para do |lines|
36
38
 
37
39
  if parse
38
- ## flatten lines
39
- txt = []
40
- lines.each_with_index do |line,i|
41
- txt << line
42
- txt << "\n"
43
- end
44
- txt = txt.join
40
+ ## flatten lines (array of strings) into all-in-one string
41
+ txt = lines.reduce( String.new ) do |mem, line|
42
+ mem << line
43
+ mem << "\n"
44
+ mem
45
+ end
45
46
 
46
47
  if debug?
47
48
  puts "lines:"
@@ -49,12 +50,18 @@ def read( path, parse: true )
49
50
  end
50
51
 
51
52
  ## todo/fix - add/track parse errors!!!!!!
53
+ ## pass along debug flag to parser (& tokenizer)?
52
54
  parser = RaccMatchParser.new( txt ) ## use own parser instance (not shared) - why? why not?
53
55
  tree = parser.parse
54
- pp tree
56
+
57
+ if debug?
58
+ puts "parse tree:"
59
+ pp tree
60
+ end
61
+
62
+ @tree += tree ## add nodes
55
63
 
56
64
  else ## process for tokenize only
57
- tree = []
58
65
  lines.each_with_index do |line,i|
59
66
 
60
67
  if debug?
@@ -75,32 +82,13 @@ def read( path, parse: true )
75
82
  end
76
83
  end
77
84
 
78
- ## post-process tokens
79
- ## - check for round, group, etc.
80
- t = t.map do |tok|
81
- #############
82
- ## pass 1
83
- ## replace all texts with keyword matches (e.g. group, round, leg, etc.)
84
- if tok[0] == :TEXT
85
- text = tok[1]
86
- if @parser.is_group?( text )
87
- [:GROUP, text]
88
- elsif @parser.is_round?( text ) || @parser.is_leg?( text )
89
- [:ROUND, text]
90
- else
91
- tok ## pass through as-is (1:1)
92
- end
93
- else
94
- tok
95
- end
96
- end
97
-
98
85
  pp t if debug?
99
-
100
- tree << t
101
86
  end # each line
102
87
  end # parse? (or tokenize?)
103
88
  end # each para (node)
89
+
90
+ ## note - only returns pare tree for now; no tokens (on parse=false)
91
+ @tree ## return parse tree
104
92
  end # method read
105
93
  end # class Linter
106
94
 
data/lib/fbtok/opts.rb CHANGED
@@ -7,6 +7,10 @@ class Parser
7
7
  ## note - Opts Helpers for now nested inside Parser - keep here? why? why not?
8
8
  class Opts
9
9
 
10
+ def self.debug=(value) @@debug = value; end
11
+ def self.debug?() @@debug ||= false; end ## note: default is FALSE
12
+
13
+
10
14
  SEASON_RE = %r{ (?:
11
15
  \d{4}-\d{2}
12
16
  | \d{4}(--[a-z0-9_-]+)?
@@ -27,7 +31,9 @@ class Opts
27
31
  }x
28
32
 
29
33
 
30
- def self.find( path, dir: nil )
34
+
35
+
36
+ def self._find( path )
31
37
  ## check - rename dir
32
38
  ## use root_dir or work_dir or cd or such - why? why not?
33
39
 
@@ -36,11 +42,8 @@ def self.find( path, dir: nil )
36
42
  ## note: normalize path - use File.expand_path ??
37
43
  ## change all backslash to slash for now
38
44
  ## path = path.gsub( "\\", '/' )
39
- path = if dir
40
- File.expand_path( path, File.expand_path( dir ))
41
- else
42
- File.expand_path( path )
43
- end
45
+ path = File.expand_path( path )
46
+
44
47
 
45
48
  ## check all txt files
46
49
  ## note: incl. files starting with dot (.)) as candidates
@@ -56,27 +59,109 @@ def self.find( path, dir: nil )
56
59
  end
57
60
 
58
61
 
59
- def self.expand_args( args )
60
- paths = []
61
-
62
- args.each do |arg|
63
- ## check if directory
64
- if Dir.exist?( arg )
65
- datafiles = find( arg )
62
+ def self._expand( arg )
63
+ ## check if directory
64
+ if Dir.exist?( arg )
65
+ datafiles = _find( arg )
66
+ if debug?
66
67
  puts
67
68
  puts " found #{datafiles.size} match txt datafiles in #{arg}"
68
69
  pp datafiles
69
- paths += datafiles
70
- else
71
- ## assume it's a file
72
- paths << arg
70
+ end
71
+ datafiles
72
+ else ## assume it's a file
73
+ ## make sure path exists; raise error if not
74
+ if File.exist?( arg )
75
+ [arg] ## note - always return an array - why? why not?
76
+ else
77
+ raise Errno::ENOENT, "No such file or directory - #{arg}"
73
78
  end
74
79
  end
80
+ end
81
+
82
+
83
+ def self.expand_args( args )
84
+ paths = []
85
+ args.each do |arg|
86
+ paths += _expand( arg )
87
+ end
88
+ paths
89
+ end
90
+
91
+
75
92
 
76
- paths
93
+ ## todo/check - find a better name
94
+ ## e.g. BatchItem or PackageDef or ???
95
+ ##
96
+ ## find a different name for rec for named value props?
97
+ ## why? why not?
98
+ PathspecNode = Struct.new( :paths, :rec )
99
+
100
+ def self.build_pathspec( paths: )
101
+ PathspecNode.new( paths: paths, rec: {} )
102
+ end
103
+
104
+ def self.read_pathspecs( src )
105
+ specs = []
106
+
107
+ recs = read_csv( src )
108
+ pp recs if debug?
109
+
110
+ ## note - make pathspecs relative to passed in file arg!!!
111
+ basedir = File.dirname( src )
112
+ recs.each do |rec|
113
+ path = rec['path']
114
+ fullpath = File.expand_path( path, basedir )
115
+ ## make sure path exists; raise error if not
116
+ paths = if Dir.exist?( fullpath )
117
+ _find( fullpath )
118
+ else
119
+ raise Errno::ENOENT, "No such directory - #{fullpath})"
120
+ end
121
+
122
+ specs << PathspecNode.new( paths: paths, rec: rec )
123
+ end
124
+ specs
77
125
  end
78
126
  end # class Opts
79
127
 
80
128
 
129
+ ##
130
+ # BatchReport (a.k.a. PathspecsReport)
131
+
132
+ class BatchReport
133
+
134
+ def initialize( specs, title: )
135
+ @specs = specs
136
+ @title = title
137
+ end
138
+
139
+ def build
140
+ buf = String.new
141
+ buf << "# #{@title} - #{@specs.size} dataset(s)\n\n"
142
+
143
+ @specs.each_with_index do |spec,i|
144
+ paths = spec.paths
145
+ rec = spec.rec
146
+ errors = rec['errors']
147
+
148
+ if errors.size > 0
149
+ buf << "!! #{errors.size} ERROR(S) "
150
+ else
151
+ buf << " OK "
152
+ end
153
+ buf << "%-20s" % rec['path']
154
+ buf << " - #{paths.size} datafile(s)"
155
+ buf << "\n"
156
+
157
+ if errors.size > 0
158
+ buf << errors.pretty_inspect
159
+ buf << "\n"
160
+ end
161
+ end
162
+
163
+ buf
164
+ end # method build
165
+ end # class BatchReport
81
166
  end # class Parser
82
167
  end # module SportDb
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fbtok
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.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: 2025-01-18 00:00:00.000000000 Z
11
+ date: 2025-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sportdb-parser