fbtok 0.5.1 → 0.5.2

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: 6bb0384d86033771326222bc9284264b9bfc44c55210261e6b598fffb3ddf925
4
- data.tar.gz: a7692e7b0f394373c364234ec7b7c57933d6bd1344b58d4139beb41381a59921
3
+ metadata.gz: 9eef844f7c201c7ead0ccc9ed46324f32b17e33b837aa43d37cd0b6bbab6fc4b
4
+ data.tar.gz: 985a3e86686c326fa816db8fcef1385ccc8c5372ac740f46992a9a019685f451
5
5
  SHA512:
6
- metadata.gz: 854430fe426e69eb27651930db928cb24bf7f4b489503a222f7ff67178fb087b465718e71cc4a9421a591ab87c784e35f2a26514c99de9151ddb9a1a13c4ec53
7
- data.tar.gz: e602fe075cfbd20eeed1e744f4bdfa35314f2e42db69537cb8ff14ccc87b8fed50400d5f3aa53974e342a0b09c00b7110e0614e0d06ede5595c19e6e652de63d
6
+ metadata.gz: e0ac5582359acf8fe7c5fb3391c9970e4dcd93f7e2742d92b8b558b2f4c840a9589ed6c157d115f6a98170a5865aa50457078eea2266cfde526b5a8b97630c33
7
+ data.tar.gz: 6af6b00555bc59d5745eba085ce599782b08f6bb5e33982fcd07b260ce9ca1f3df062bc6ee05514f737ec24ebd9ad9b422c94839e76e07871fa75b206e476552
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.5.1
1
+ ### 0.5.2
2
2
  ### 0.0.1 / 2025-01-02
3
3
 
4
4
  * Everything is new. First release.
data/Manifest.txt CHANGED
@@ -2,16 +2,18 @@ CHANGELOG.md
2
2
  Manifest.txt
3
3
  README.md
4
4
  Rakefile
5
+ bin/fbfind
5
6
  bin/fbquick
6
7
  bin/fbquik
7
8
  bin/fbtok
8
9
  bin/fbtree
9
10
  bin/fbx
10
11
  lib/fbtok.rb
11
- lib/fbtok/fbquick.rb
12
- lib/fbtok/fbtok.rb
13
- lib/fbtok/fbtree.rb
14
- lib/fbtok/fbx.rb
12
+ lib/fbtok/command-fbfind.rb
13
+ lib/fbtok/command-fbquick.rb
14
+ lib/fbtok/command-fbtok.rb
15
+ lib/fbtok/command-fbtree.rb
16
+ lib/fbtok/command-fbx.rb
15
17
  lib/fbtok/filepack.rb
16
18
  lib/fbtok/pathspec.rb
17
19
  lib/fbtok/pathspec_report.rb
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'hoe'
2
2
 
3
3
 
4
4
  Hoe.spec 'fbtok' do
5
- self.version = '0.5.1'
5
+ self.version = '0.5.2'
6
6
 
7
7
  self.summary = "fbtok - football.txt lint tools incl. tokenizer, parser & more"
8
8
  self.description = summary
data/bin/fbfind ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ## tip: to test run:
4
+ ## $ ruby -I ./lib bin/fbfind
5
+
6
+
7
+ require 'fbtok'
8
+
9
+
10
+ Fbfind.main
@@ -0,0 +1,105 @@
1
+
2
+
3
+ module Fbfind
4
+
5
+ def self.main( args=ARGV )
6
+
7
+ opts = {
8
+ debug: false,
9
+ file: nil,
10
+ seasons: [],
11
+ }
12
+
13
+
14
+ parser = OptionParser.new do |parser|
15
+ parser.banner = "Usage: #{$PROGRAM_NAME} [options] DATAFILE or DIR"
16
+
17
+
18
+ parser.on( "-q", "--quiet",
19
+ "less debug output/messages (default: #{!opts[:debug]})" ) do |debug|
20
+ opts[:debug] = false
21
+ end
22
+ parser.on( "--verbose", "--debug",
23
+ "turn on verbose / debug output (default: #{opts[:debug]})" ) do |debug|
24
+ opts[:debug] = true
25
+ end
26
+
27
+ parser.on( "--seasons SEASONS",
28
+ "filter by seasons (default: #{opts[:seasons]})") do |seasons|
29
+ opts[:seasons] = seasons
30
+ .split( /[,:]/ )
31
+ .map { |season| Season.parse(season.strip) }
32
+ end
33
+
34
+
35
+ parser.on( "-f FILE", "--file FILE",
36
+ "read datafiles (pathspecs) via .csv file") do |file|
37
+ opts[:file] = file
38
+ end
39
+ end
40
+ parser.parse!( args )
41
+
42
+
43
+
44
+ if opts[:debug]
45
+ puts "OPTS:"
46
+ p opts
47
+ puts "ARGV:"
48
+ p args
49
+ end
50
+
51
+
52
+ # SportDb::Parser::Linter.debug = opts[:debug]
53
+ # SportDb::Parser::Linter.warn = opts[:warn]
54
+
55
+
56
+
57
+ ## todo/check - use packs or projects or such
58
+ ## instead of specs - why? why not?
59
+ specs = if opts[:file]
60
+ read_pathspecs( opts[:file] )
61
+ else
62
+ ## check for filepack
63
+ filepack = if File.file?( './filepack.txt')
64
+ read_filepack( './filepack.txt' )
65
+ else
66
+ nil
67
+ end
68
+
69
+ path = SportDb::Pathspec.path(
70
+ ['/sports/sportdb/sport.db.v2/parser/fbtxt-specs',
71
+ '/sports/sportdb/sport.db.v2/parser/fbtxt-samples',
72
+ '/sports/openfootball'])
73
+
74
+ build_pathspecs( args, path: path,
75
+ filepack: filepack )
76
+ end
77
+
78
+
79
+ if opts[:debug]
80
+ puts
81
+ puts "pathspecs:"
82
+ pp specs
83
+ end
84
+
85
+
86
+ if opts[:seasons].size > 0
87
+ specs = filter_pathspecs( specs, seasons: opts[:seasons] )
88
+ end
89
+
90
+ puts
91
+ specs.each_with_index do |rec,i|
92
+ path = rec['path']
93
+ datafiles = rec['datafiles']
94
+
95
+ print "==> [#{i+1}/#{specs.size}] #{path}"
96
+ print " (incl. seasons #{opts[:seasons]})" if opts[:seasons].size > 0
97
+ print "...\n"
98
+ pp datafiles
99
+ puts " #{datafiles.size} datafile(s)"
100
+ end
101
+
102
+ puts "bye"
103
+ end
104
+
105
+ end ## module Fbfind
@@ -7,6 +7,7 @@ def self.main( args=ARGV )
7
7
  opts = {
8
8
  debug: true,
9
9
  file: nil,
10
+ seasons: [],
10
11
  # warn: false,
11
12
  }
12
13
 
@@ -29,6 +30,13 @@ parser = OptionParser.new do |parser|
29
30
  # end
30
31
 
31
32
 
33
+ parser.on( "--seasons SEASONS",
34
+ "filter by seasons (default: #{opts[:seasons]})") do |seasons|
35
+ opts[:seasons] = seasons
36
+ .split( /[,:]/ )
37
+ .map { |season| Season.parse(season.strip) }
38
+ end
39
+
32
40
  parser.on( "-f FILE", "--file FILE",
33
41
  "read datafiles (pathspecs) via .csv file") do |file|
34
42
  opts[:file] = file
@@ -75,14 +83,17 @@ specs = if opts[:file]
75
83
  end
76
84
 
77
85
 
78
- pp specs
79
86
 
87
+ if opts[:seasons].size > 0
88
+ specs = filter_pathspecs( specs, seasons: opts[:seasons] )
89
+ end
80
90
 
81
91
 
82
92
  specs.each_with_index do |rec,i|
83
93
  datafiles = rec['datafiles']
84
94
 
85
95
  errors = []
96
+ log = [] ## quick one-line summary per datafile
86
97
 
87
98
  datafiles.each_with_index do |path,j|
88
99
  puts "==> [#{i+1}/#{specs.size}, #{j+1}/#{datafiles.size}] reading >#{path}<..."
@@ -103,19 +114,24 @@ specs.each_with_index do |rec,i|
103
114
  ### errors << [ path, *msg ] # note: use splat (*) to add extra values (starting with msg)
104
115
  errors << [path, msg]
105
116
  end
117
+
118
+ log << [:ERROR, path, "#{more_errors.size} tokenize error(s), #{tokens.size} token(s)"]
119
+ else
120
+ log << [:OK, path, "#{tokens.size} token(s)"]
106
121
  end
122
+ end
107
123
 
108
124
 
109
- end
110
125
 
111
126
  if errors.size > 0
112
127
  puts
113
128
  pp errors
114
129
  puts
130
+ pp log
115
131
  puts "!! #{errors.size} tokenize error(s) in #{datafiles.size} datafiles(s)"
116
132
  else
117
133
  puts
118
- pp datafiles
134
+ pp log
119
135
  puts "OK no tokenize errors found in #{datafiles.size} datafile(s)"
120
136
  end
121
137
 
@@ -7,6 +7,7 @@ def self.main( args=ARGV )
7
7
  opts = {
8
8
  debug: true,
9
9
  file: nil,
10
+ seasons: [],
10
11
  ## warn: false,
11
12
  }
12
13
 
@@ -28,6 +29,13 @@ parser = OptionParser.new do |parser|
28
29
  # end
29
30
 
30
31
 
32
+ parser.on( "--seasons SEASONS",
33
+ "filter by seasons (default: #{opts[:seasons]})") do |seasons|
34
+ opts[:seasons] = seasons
35
+ .split( /[,:]/ )
36
+ .map { |season| Season.parse(season.strip) }
37
+ end
38
+
31
39
  parser.on( "-f FILE", "--file FILE",
32
40
  "read datafiles (pathspecs) via .csv file") do |file|
33
41
  opts[:file] = file
@@ -72,7 +80,6 @@ specs = if opts[:file]
72
80
  end
73
81
 
74
82
 
75
- pp specs
76
83
 
77
84
  ## if more than single datafile
78
85
  ## auto-switch into quite mode for now
@@ -85,6 +92,9 @@ pp specs
85
92
 
86
93
 
87
94
 
95
+ if opts[:seasons].size > 0
96
+ specs = filter_pathspecs( specs, seasons: opts[:seasons] )
97
+ end
88
98
 
89
99
 
90
100
 
@@ -92,6 +102,7 @@ specs.each_with_index do |rec,i|
92
102
  datafiles = rec['datafiles']
93
103
 
94
104
  errors = []
105
+ log = [] ## quick one-line summary per datafile
95
106
 
96
107
  datafiles.each_with_index do |path,j|
97
108
  puts "==> [#{i+1}/#{specs.size}, #{j+1}/#{datafiles.size}] reading >#{path}<..."
@@ -109,6 +120,10 @@ specs.each_with_index do |rec,i|
109
120
  ### errors << [ path, *msg ] # note: use splat (*) to add extra values (starting with msg)
110
121
  errors << [path, msg]
111
122
  end
123
+
124
+ log << [:ERROR, path, "#{parser.errors.size} parse error(s), #{tree.size} tree node(s)"]
125
+ else
126
+ log << [:OK, path, "#{tree.size} tree node(s)"]
112
127
  end
113
128
  end
114
129
 
@@ -117,10 +132,12 @@ specs.each_with_index do |rec,i|
117
132
  puts
118
133
  pp errors
119
134
  puts
135
+ puts
136
+ pp log
120
137
  puts "!! #{errors.size} parse error(s) in #{datafiles.size} datafiles(s)"
121
138
  else
122
139
  puts
123
- pp datafiles
140
+ pp log
124
141
  puts "OK no parse errors found in #{datafiles.size} datafile(s)"
125
142
  end
126
143
 
@@ -1,5 +1,35 @@
1
1
 
2
2
 
3
+ ##
4
+ ## note - add find_dir( name, path: ) helper
5
+ ## move upstream into cocos - why? why not?
6
+ def find_dir( name, path: [] )
7
+ return File.expand_path( name ) if Dir.exist?( name )
8
+
9
+ ## note - if name starts with / or \ assume it's absolute!!
10
+ ## do NOT search!!!
11
+ ## note - search still works for
12
+ ## ./austria or ../austria or such
13
+ ##
14
+ ## todo/check/fix-fix-fix
15
+ ## is there a File.absolute? or such method for reuse??
16
+ ##
17
+ ## todo/fix-fix-fix add absolute check upstream to find_file too!!!
18
+ return nil if name.start_with?( %r{[/\\]} )
19
+
20
+ path.each do |basedir|
21
+ ## todo/check - always make sure basedir is an absolute/expanded path - why? why not?
22
+ dirpath = File.expand_path( name, basedir )
23
+ return dirpath if Dir.exist?( dirpath )
24
+ end
25
+
26
+ nil ## return nil if not found
27
+ end
28
+
29
+
30
+
31
+
32
+
3
33
  module SportDb
4
34
  class Pathspec
5
35
 
@@ -194,6 +224,20 @@ def self.read( src )
194
224
  end
195
225
 
196
226
 
227
+ ## quick (internal) helper to
228
+ ## expand names (directories) ending with /*
229
+ ## with Pathspec.find
230
+ def self._expand_pathspecs( names )
231
+ datafiles = []
232
+ names.each do |name|
233
+ if name.end_with?('/*')
234
+ datafiles += Pathspec.find( name[0..-3] )
235
+ else
236
+ datafiles << name
237
+ end
238
+ end
239
+ datafiles
240
+ end
197
241
 
198
242
  def self.build( args, path: [],
199
243
  filepack: nil )
@@ -203,7 +247,7 @@ def self.build( args, path: [],
203
247
  if args.empty?
204
248
  if filepack && filepack.has_key?('default')
205
249
  recs << { 'path' => '<default>',
206
- 'datafiles' => filepack['default'] }
250
+ 'datafiles' => _expand_pathspecs(filepack['default']) }
207
251
  end
208
252
  else
209
253
 
@@ -217,12 +261,16 @@ def self.build( args, path: [],
217
261
  ##
218
262
  ## todo/check if euro/ works too?
219
263
  ## check if directory
220
- if Dir.exist?( arg )
264
+ ## note - make find_dir/path lookup an env variable
265
+ ## e.g. FBTXT_ROOTDIR, FBTXT_SOURCE, FBSOURCE,
266
+ ## FBTXT_REPOS/PACKS/etc. or such!!!
267
+ ## add dir_path/dirs or such to build - why? why not?
268
+ if dir=find_dir( arg, path: ['/sports/openfootball'] )
221
269
  recs << { 'path' => arg,
222
- 'datafiles' => Pathspec.find( arg ) }
270
+ 'datafiles' => Pathspec.find( dir ) }
223
271
  elsif filepack && filepack.has_key?( arg.downcase )
224
272
  recs << { 'path' => "<#{arg.downcase}>",
225
- 'datafiles' => filepack[arg.downcase] }
273
+ 'datafiles' => _expand_pathspecs(filepack[arg.downcase]) }
226
274
  else ## assume it's a file
227
275
  file = find_file( arg, path: path )
228
276
  ## check if file (exists) in any path lookup
@@ -274,3 +322,27 @@ end
274
322
  def read_pathspecs( src )
275
323
  SportDb::Pathspecs.read( src )
276
324
  end
325
+
326
+
327
+
328
+ def filter_pathspecs( specs, seasons: )
329
+ ## norm seasons
330
+ seasons = seasons.map {|season| Season(season) }
331
+
332
+ ## todo/fix: auto-add/update rec['seasons'] column - why? why not?
333
+
334
+ ## note - filter datafiles inplace!!!
335
+ specs.each do |rec|
336
+ rec['datafiles'] =
337
+ rec['datafiles'].select do |candidate|
338
+ m=SportDb::Pathspec::MATCH_RE.match( candidate )
339
+ if m && seasons.include?( Season.parse( m[:season] ))
340
+ true
341
+ else
342
+ false
343
+ end
344
+ end
345
+ end
346
+
347
+ specs
348
+ end
data/lib/fbtok.rb CHANGED
@@ -7,7 +7,8 @@ require_relative 'fbtok/filepack'
7
7
  require_relative 'fbtok/pathspec'
8
8
  require_relative 'fbtok/pathspec_report'
9
9
 
10
- require_relative 'fbtok/fbtok'
11
- require_relative 'fbtok/fbtree'
12
- require_relative 'fbtok/fbquick'
13
- require_relative 'fbtok/fbx'
10
+ require_relative 'fbtok/command-fbfind'
11
+ require_relative 'fbtok/command-fbtok'
12
+ require_relative 'fbtok/command-fbtree'
13
+ require_relative 'fbtok/command-fbquick'
14
+ require_relative 'fbtok/command-fbx'
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.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-10 00:00:00.000000000 Z
11
+ date: 2026-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sportdb-parser
@@ -75,6 +75,7 @@ dependencies:
75
75
  description: fbtok - football.txt lint tools incl. tokenizer, parser & more
76
76
  email: gerald.bauer@gmail.com
77
77
  executables:
78
+ - fbfind
78
79
  - fbquick
79
80
  - fbquik
80
81
  - fbtok
@@ -90,16 +91,18 @@ files:
90
91
  - Manifest.txt
91
92
  - README.md
92
93
  - Rakefile
94
+ - bin/fbfind
93
95
  - bin/fbquick
94
96
  - bin/fbquik
95
97
  - bin/fbtok
96
98
  - bin/fbtree
97
99
  - bin/fbx
98
100
  - lib/fbtok.rb
99
- - lib/fbtok/fbquick.rb
100
- - lib/fbtok/fbtok.rb
101
- - lib/fbtok/fbtree.rb
102
- - lib/fbtok/fbx.rb
101
+ - lib/fbtok/command-fbfind.rb
102
+ - lib/fbtok/command-fbquick.rb
103
+ - lib/fbtok/command-fbtok.rb
104
+ - lib/fbtok/command-fbtree.rb
105
+ - lib/fbtok/command-fbx.rb
103
106
  - lib/fbtok/filepack.rb
104
107
  - lib/fbtok/pathspec.rb
105
108
  - lib/fbtok/pathspec_report.rb
File without changes
File without changes