fbtok 0.2.3 → 0.3.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: b0cf5b4c14ed4e4466a769b2389e9aaf2add0fe631034010778cfc9a7671d088
4
- data.tar.gz: 311e35505a4ec9b729784e4adf415888e64a855fda4a2bed3ab971a51c8ebb40
3
+ metadata.gz: c719bbab25c068f69c9bd0bc44036ad355c8ca486ea3dfbec6d2276b4d436fbb
4
+ data.tar.gz: 7053879da0e31078524b8b74453d5e7f2d3b97b0d503629467210088d91955c5
5
5
  SHA512:
6
- metadata.gz: d9d1a0b0b736368613f2cae07c69ecc9fec2ca41e3b40a77471e3790ce585a4a4fb5a4559c8005deb59dee2e56fa3f489c2025033b8281910ffec8e77ad94356
7
- data.tar.gz: 692715563a64d828eea4bbef1528721773dea1b7c7f4a2103079a804991fcc683ae6afff9aa76dfbf116b5050a77771c85c2ae11f5c950b402391f2eec077d5b
6
+ metadata.gz: 38bd241c9466046377aef3c951de74b25f9a7ae1d38e1827997ba673bea7cb60105344c7f78bd997b8e0e16dc90c89946fe08db39bb3433751e1a55167e55bbf
7
+ data.tar.gz: d59f2b6fed95ebb4e7539baf4e841db5ea008b29357438de13bf3094a3062aae7e47d5825d6f7a8299a1684b3295b9c5821806eee890b67fd68dcbb392034a1e
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.2.3
1
+ ### 0.3.1
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.3'
5
+ self.version = '0.3.1'
6
6
 
7
7
  self.summary = "fbtok - football.txt lint tools incl. tokenizer, parser & more"
8
8
  self.description = summary
@@ -21,7 +21,7 @@ Hoe.spec 'fbtok' do
21
21
  self.extra_deps = [
22
22
  # ['sportdb-structs', '>= 0.5.0'],
23
23
  # ['logutils', '>= 0.6.1'],
24
- ['sportdb-parser', '>= 0.5.4'],
24
+ ['sportdb-parser', '>= 0.5.8'],
25
25
  ['sportdb-formats', '>= 2.1.2'],
26
26
  ]
27
27
 
data/bin/fbchk CHANGED
@@ -59,52 +59,51 @@ end
59
59
  parser.parse!( args )
60
60
 
61
61
 
62
- puts "OPTS:"
63
- p opts
64
- puts "ARGV:"
65
- p args
66
-
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
- else
84
- ## check for directories
85
- ## and auto-expand
86
- SportDb::Parser::Opts.expand_args( args )
87
- end
88
- specs << [paths, {}]
89
- end
90
-
91
-
92
62
  if opts[:debug]
93
- SportDb::QuickMatchLinter.debug = true
94
- SportDb::QuickMatchReader.debug = true
95
- 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
96
71
  else
97
- SportDb::QuickMatchLinter.debug = false
98
- SportDb::QuickMatchReader.debug = false
99
- SportDb::MatchParser.debug = false
100
- 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
101
76
  end
102
77
 
103
78
 
104
- 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
+
105
104
  errors = []
106
105
  paths.each_with_index do |path,j|
107
- puts "==> [#{j+1}/#{paths.size}] reading >#{path}<..."
106
+ puts "==> [#{i+1}/#{specs.size}, #{j+1}/#{paths.size}] reading >#{path}<..."
108
107
  quick = SportDb::QuickMatchLinter.new( read_text( path ),
109
108
  check_teams: opts[:teams] )
110
109
  matches = quick.parse
@@ -140,28 +139,9 @@ end
140
139
  ###
141
140
  ## generate a report if --file option used
142
141
  if opts[:file]
143
-
144
- buf = String.new
145
-
146
- buf << "# fbchk summary report - #{specs.size} dataset(s)\n\n"
147
-
148
- specs.each_with_index do |(paths, rec),i|
149
- errors = rec['errors']
150
-
151
- if errors.size > 0
152
- buf << "!! #{errors.size} ERROR(S) "
153
- else
154
- buf << " OK "
155
- end
156
- buf << "%-20s" % rec['path']
157
- buf << " - #{paths.size} datafile(s)"
158
- buf << "\n"
159
-
160
- if errors.size > 0
161
- buf << errors.pretty_inspect
162
- buf << "\n"
163
- end
164
- end
142
+ buf = SportDb::Parser::BatchReport.new(
143
+ specs,
144
+ title: 'fbchk summary report' ).build
165
145
 
166
146
  puts
167
147
  puts "SUMMARY:"
@@ -169,7 +149,7 @@ if opts[:file]
169
149
 
170
150
  basedir = File.dirname( opts[:file] )
171
151
  basename = File.basename( opts[:file], File.extname( opts[:file] ))
172
- outpath = "#{basedir}/fbcheck.#{basename}.txt"
152
+ outpath = "#{basedir}/fbchk.#{basename}.txt"
173
153
  write_text( outpath, buf )
174
154
  end
175
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
@@ -57,44 +57,39 @@ if opts[:debug]
57
57
  end
58
58
 
59
59
 
60
+
60
61
  ## todo/check - use packs or projects or such
61
62
  ## instead of specs - why? why not?
62
- specs = []
63
- if opts[:file]
64
- recs = read_csv( opts[:file] )
65
- pp recs if opts[:debug]
66
-
67
- ## note - make pathspecs relative to passed in file arg!!!
68
- basedir = File.dirname( opts[:file] )
69
- recs.each do |rec|
70
- paths = SportDb::Parser::Opts.find( rec['path'], dir: basedir )
71
- specs << [paths, rec]
72
- end
73
- else
74
- paths = if args.empty?
75
- [
76
- '/sports/openfootball/euro/2021--europe/euro.txt',
77
- '/sports/openfootball/euro/2024--germany/euro.txt',
78
- ]
79
- else
80
- ## check for directories
81
- ## and auto-expand
82
- SportDb::Parser::Opts.expand_args( args )
83
- end
84
- specs << [paths, {}]
85
- end
86
-
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
87
77
 
88
78
 
89
79
  linter = SportDb::Parser::Linter.new
90
80
 
91
81
 
92
- specs.each_with_index do |(paths, rec),i|
93
- errors = []
82
+ specs.each_with_index do |spec,i|
83
+ paths = spec.paths
84
+ rec = spec.rec
85
+
86
+ errors = []
94
87
 
95
88
  paths.each_with_index do |path,j|
96
- puts "==> [#{j+1}/#{paths.size}] reading >#{path}<..."
97
- linter.read( path, parse: false ) ## only tokenize (do NOT parse)
89
+ puts "==> [#{i+1}/#{specs.size}, #{j+1}/#{paths.size}] reading >#{path}<..."
90
+ tokens = linter.read( path, parse: false ) ## only tokenize (do NOT parse)
91
+
92
+ puts " #{tokens.size} token(s)"
98
93
 
99
94
  errors += linter.errors if linter.errors?
100
95
  end
@@ -119,35 +114,17 @@ end
119
114
  ## generate a report if --file option used
120
115
  if opts[:file]
121
116
 
122
- buf = String.new
123
-
124
- buf << "# fbtok summary report - #{specs.size} dataset(s)\n\n"
125
-
126
- specs.each_with_index do |(paths, rec),i|
127
- errors = rec['errors']
128
-
129
- if errors.size > 0
130
- buf << "!! #{errors.size} ERROR(S) "
131
- else
132
- buf << " OK "
133
- end
134
- buf << "%-20s" % rec['path']
135
- buf << " - #{paths.size} datafile(s)"
136
- buf << "\n"
137
-
138
- if errors.size > 0
139
- buf << errors.pretty_inspect
140
- buf << "\n"
141
- end
142
- end
117
+ buf = SportDb::Parser::BatchReport.new(
118
+ specs,
119
+ title: 'fbtok summary report' ).build
143
120
 
144
- puts
145
- puts "SUMMARY:"
146
- puts buf
121
+ puts
122
+ puts "SUMMARY:"
123
+ puts buf
147
124
 
148
- # maybe write out in the future?
149
- # basedir = File.dirname( opts[:file] )
150
- # basename = File.basename( opts[:file], File.extname( opts[:file] ))
125
+ # maybe write out in the future?
126
+ # basedir = File.dirname( opts[:file] )
127
+ # basename = File.basename( opts[:file], File.extname( opts[:file] ))
151
128
  end
152
129
 
153
130
  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,6 +25,14 @@ 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
 
@@ -44,16 +53,20 @@ end
44
53
 
45
54
  ## todo/check - use packs or projects or such
46
55
  ## instead of specs - why? why not?
47
- paths = if args.empty?
48
- [
49
- '/sports/openfootball/euro/2021--europe/euro.txt',
50
- '/sports/openfootball/euro/2024--germany/euro.txt',
51
- ]
52
- else
53
- ## check for directories
54
- ## and auto-expand
55
- SportDb::Parser::Opts.expand_args( args )
56
- 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
57
70
 
58
71
 
59
72
 
@@ -78,16 +91,51 @@ end
78
91
  linter = SportDb::Parser::Linter.new
79
92
 
80
93
 
81
- paths.each_with_index do |path,i|
82
-
83
- puts "==> [#{i+1}/#{paths.size}] reading >#{path}<..."
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
121
+ end
84
122
 
85
- tree = linter.read( path, parse: true )
86
123
 
87
- dump_tree_stats( tree )
88
- end
124
+ ###
125
+ ## generate a report if --file option used
126
+ if opts[:file]
89
127
 
128
+ buf = SportDb::Parser::BatchReport.new(
129
+ specs,
130
+ title: 'fbtree summary report' ).build
90
131
 
91
- puts "bye"
132
+ puts
133
+ puts "SUMMARY:"
134
+ puts buf
92
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
93
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?
@@ -70,12 +75,6 @@ paths = if args.empty?
70
75
 
71
76
 
72
77
 
73
- if opts[:debug]
74
- SportDb::MatchParser.debug = true
75
- else
76
- SportDb::MatchParser.debug = false
77
- LogUtils::Logger.root.level = :info
78
- end
79
78
 
80
79
  ## errors = []
81
80
 
data/lib/fbtok/linter.rb CHANGED
@@ -16,43 +16,49 @@ attr_reader :errors
16
16
 
17
17
  def initialize
18
18
  @errors = []
19
- @parser = Parser.new ## use own parser instance (not shared) - why? why not?
20
19
  end
21
20
 
22
21
 
23
22
  def errors?() @errors.size > 0; end
24
23
 
25
24
 
25
+
26
26
  #########
27
27
  ## parse - false (default) - tokenize (only)
28
28
  ## - true - tokenize & parse
29
29
  def read( path, parse: true )
30
30
  ## note: every (new) read call - resets errors list to empty
31
31
  @errors = []
32
-
33
- @tree = []
32
+ @tree = []
34
33
 
35
34
  outline = QuickMatchOutline.read( path )
36
35
 
37
36
  outline.each_para do |lines|
38
-
39
- if parse
37
+
40
38
  ## flatten lines (array of strings) into all-in-one string
41
39
  txt = lines.reduce( String.new ) do |mem, line|
42
- mem << line
43
- mem << "\n"
44
- mem
45
- end
46
-
40
+ mem << line
41
+ mem << "\n"
42
+ mem
43
+ end
44
+
45
+ if parse
47
46
  if debug?
48
47
  puts "lines:"
49
48
  pp txt
50
49
  end
51
50
 
52
- ## todo/fix - add/track parse errors!!!!!!
53
51
  ## pass along debug flag to parser (& tokenizer)?
54
52
  parser = RaccMatchParser.new( txt ) ## use own parser instance (not shared) - why? why not?
55
- tree = parser.parse
53
+ tree, errors = parser.parse_with_errors
54
+
55
+ if errors.size > 0
56
+ ## add to "global" error list
57
+ ## make a triplet tuple (file / msg / line text)
58
+ errors.each do |msg|
59
+ @errors << [path, msg]
60
+ end
61
+ end
56
62
 
57
63
  if debug?
58
64
  puts "parse tree:"
@@ -62,32 +68,43 @@ def read( path, parse: true )
62
68
  @tree += tree ## add nodes
63
69
 
64
70
  else ## process for tokenize only
65
- lines.each_with_index do |line,i|
66
71
 
67
72
  if debug?
68
- puts
69
- puts "line >#{line}<"
73
+ puts "lines:"
74
+ pp txt
70
75
  end
71
76
 
72
- t, error_messages = @parser.tokenize_with_errors( line )
77
+ ##
78
+ ## add (bakc) a line-by-line tracing (debug) option - why? why not?
79
+ ## now debug output is by section (not line-by-line)
80
+
81
+ lexer = Lexer.new( txt )
82
+ t, errors = lexer.tokenize_with_errors
73
83
 
74
- if error_messages.size > 0
84
+ if errors.size > 0
75
85
  ## add to "global" error list
76
86
  ## make a triplet tuple (file / msg / line text)
77
- error_messages.each do |msg|
78
- @errors << [ path,
79
- msg,
80
- line
81
- ]
87
+ errors.each do |msg|
88
+ @errors << [path, msg]
82
89
  end
83
90
  end
84
91
 
85
- pp t if debug?
86
- end # each line
92
+ if debug?
93
+ puts "tokens:"
94
+ pp t
95
+ end
96
+
97
+ @tree += t ## add tokens to "tree"
87
98
  end # parse? (or tokenize?)
88
99
  end # each para (node)
89
100
 
90
- ## note - only returns pare tree for now; no tokens (on parse=false)
101
+
102
+ ##
103
+ ## auto-add error if no tokens/tree nodes
104
+ if @tree.empty? ## @tree.size == 0
105
+ @errors << [path, "empty; no #{parse ? 'parse tree nodes' : 'tokens'}"]
106
+ end
107
+
91
108
  @tree ## return parse tree
92
109
  end # method read
93
110
  end # class Linter
data/lib/fbtok/opts.rb CHANGED
@@ -31,7 +31,9 @@ class Opts
31
31
  }x
32
32
 
33
33
 
34
- def self.find( path, dir: nil )
34
+
35
+
36
+ def self._find( path )
35
37
  ## check - rename dir
36
38
  ## use root_dir or work_dir or cd or such - why? why not?
37
39
 
@@ -40,11 +42,8 @@ def self.find( path, dir: nil )
40
42
  ## note: normalize path - use File.expand_path ??
41
43
  ## change all backslash to slash for now
42
44
  ## path = path.gsub( "\\", '/' )
43
- path = if dir
44
- File.expand_path( path, File.expand_path( dir ))
45
- else
46
- File.expand_path( path )
47
- end
45
+ path = File.expand_path( path )
46
+
48
47
 
49
48
  ## check all txt files
50
49
  ## note: incl. files starting with dot (.)) as candidates
@@ -60,29 +59,109 @@ def self.find( path, dir: nil )
60
59
  end
61
60
 
62
61
 
63
- def self.expand_args( args )
64
- paths = []
65
-
66
- args.each do |arg|
67
- ## check if directory
68
- if Dir.exist?( arg )
69
- datafiles = find( arg )
70
- if debug?
71
- puts
72
- puts " found #{datafiles.size} match txt datafiles in #{arg}"
73
- pp datafiles
74
- end
75
- paths += datafiles
76
- else
77
- ## assume it's a file
78
- paths << arg
62
+ def self._expand( arg )
63
+ ## check if directory
64
+ if Dir.exist?( arg )
65
+ datafiles = _find( arg )
66
+ if debug?
67
+ puts
68
+ puts " found #{datafiles.size} match txt datafiles in #{arg}"
69
+ pp datafiles
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}"
79
78
  end
80
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
+
81
91
 
82
- paths
92
+
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
83
125
  end
84
126
  end # class Opts
85
127
 
86
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
87
166
  end # class Parser
88
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.3
4
+ version: 0.3.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: 2025-01-22 00:00:00.000000000 Z
11
+ date: 2025-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sportdb-parser
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.5.4
19
+ version: 0.5.8
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.5.4
26
+ version: 0.5.8
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: sportdb-formats
29
29
  requirement: !ruby/object:Gem::Requirement