fbtok 0.5.1 → 0.5.3

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: 9cd5c4d072690acf0846ea8a6c0d34af8857073debf4c8c2d5a5688d92133038
4
+ data.tar.gz: 0ea211c29fbc8dcb0305368da6ae654c35404e498b1816d8507695e9a9a0e9e2
5
5
  SHA512:
6
- metadata.gz: 854430fe426e69eb27651930db928cb24bf7f4b489503a222f7ff67178fb087b465718e71cc4a9421a591ab87c784e35f2a26514c99de9151ddb9a1a13c4ec53
7
- data.tar.gz: e602fe075cfbd20eeed1e744f4bdfa35314f2e42db69537cb8ff14ccc87b8fed50400d5f3aa53974e342a0b09c00b7110e0614e0d06ede5595c19e6e652de63d
6
+ metadata.gz: 8c164cb1b0ab93492b055b20f9864ef2dfd0fbd3197bfe658c2a29b68df7cfd0fe06a5f8c4867b8e6e39826972190998385fd691178d2a502122f2b2f13d7cbf
7
+ data.tar.gz: e649301128cd231e73ddcd815b32359a658233fb334413f38c083bcf2c54f8b62836f9187abb8cfced19318588737128218fdcf0f46e92ff14728f20ce24df5c
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.5.1
1
+ ### 0.5.3
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.3'
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
 
@@ -4,10 +4,18 @@ module Fbtree
4
4
  def self.main( args=ARGV )
5
5
 
6
6
 
7
+
7
8
  opts = {
8
9
  debug: true,
9
- file: nil,
10
10
  ## warn: false,
11
+
12
+ json: false,
13
+ yaml: false,
14
+
15
+ file: nil,
16
+ tty: false,
17
+
18
+ seasons: [],
11
19
  }
12
20
 
13
21
  parser = OptionParser.new do |parser|
@@ -35,6 +43,27 @@ parser = OptionParser.new do |parser|
35
43
  opts[:debug] = false
36
44
  end
37
45
 
46
+ parser.on( "--seasons SEASONS",
47
+ "filter by seasons (default: #{opts[:seasons]})") do |seasons|
48
+ opts[:seasons] = seasons
49
+ .split( /[,:]/ )
50
+ .map { |season| Season.parse(season.strip) }
51
+ end
52
+
53
+
54
+ parser.on( "-j", "--json",
55
+ "turn on output in json (default: #{opts[:json]})" ) do |json|
56
+ opts[:json] = true
57
+ end
58
+ parser.on( "-y", "--yaml",
59
+ "turn on output in yaml (default: #{opts[:yaml]})" ) do |yaml|
60
+ opts[:yaml] = true
61
+ end
62
+
63
+ parser.on( "-t", "--terminal", "--tty",
64
+ "force terminal/tty input (default: #{opts[:tty]})" ) do |tty|
65
+ opts[:tty] = tty
66
+ end
38
67
  end
39
68
  parser.parse!( args )
40
69
 
@@ -47,6 +76,59 @@ end
47
76
 
48
77
 
49
78
 
79
+ ## special case for typed input via terminal/tty
80
+ if opts[:tty]
81
+
82
+ puts "type your football.TXT lines here (exit with ctrl-z and return):"
83
+ lines = STDIN.readlines ## note - readlines incl. trailing newline!
84
+
85
+ txt = lines.join ## note - join with no space (already incl. trailing newline!)
86
+
87
+ puts "--- parsing #{lines.size} line(s) ---"
88
+ puts txt
89
+ puts "--- results ---"
90
+
91
+ tree, errors = parse_with_errors( txt, opts )
92
+
93
+ if errors.size > 0
94
+ puts
95
+ pp errors
96
+ puts
97
+ puts "!! #{errors.size} parse error(s)"
98
+ exit 1
99
+ else
100
+ puts
101
+ puts "OK no parse errors found"
102
+ exit 0
103
+ end
104
+ end
105
+
106
+
107
+
108
+ ## check for piped input e.g. $ curl | fbtree
109
+ if !STDIN.tty? ## input NOT via tty (teletype terminal)
110
+
111
+ txt = STDIN.read
112
+
113
+ puts "--- parsing ---"
114
+ puts txt
115
+ puts "--- results ---"
116
+
117
+ tree, errors = parse_with_errors( txt, opts )
118
+
119
+ if errors.size > 0
120
+ puts
121
+ pp errors
122
+ puts
123
+ puts "!! #{errors.size} parse error(s)"
124
+ exit 1
125
+ else
126
+ puts
127
+ puts "OK no parse errors found"
128
+ exit 0
129
+ end
130
+ end
131
+
50
132
 
51
133
 
52
134
 
@@ -72,7 +154,6 @@ specs = if opts[:file]
72
154
  end
73
155
 
74
156
 
75
- pp specs
76
157
 
77
158
  ## if more than single datafile
78
159
  ## auto-switch into quite mode for now
@@ -85,6 +166,9 @@ pp specs
85
166
 
86
167
 
87
168
 
169
+ if opts[:seasons].size > 0
170
+ specs = filter_pathspecs( specs, seasons: opts[:seasons] )
171
+ end
88
172
 
89
173
 
90
174
 
@@ -92,23 +176,25 @@ specs.each_with_index do |rec,i|
92
176
  datafiles = rec['datafiles']
93
177
 
94
178
  errors = []
179
+ log = [] ## quick one-line summary per datafile
95
180
 
96
181
  datafiles.each_with_index do |path,j|
97
182
  puts "==> [#{i+1}/#{specs.size}, #{j+1}/#{datafiles.size}] reading >#{path}<..."
98
183
 
99
184
  txt = read_text( path )
100
- parser = RaccMatchParser.new( txt, debug: opts[:debug] )
101
- tree = parser.parse
185
+ tree, more_errors = parse_with_errors( txt, opts )
102
186
 
103
- dump_tree_stats( tree )
104
-
105
- if parser.errors?
187
+ if more_errors.size > 0
106
188
  ## note - auto-add filename to errors
107
- parser.errors.each do |msg|
189
+ more_errors.each do |msg|
108
190
  ###
109
191
  ### errors << [ path, *msg ] # note: use splat (*) to add extra values (starting with msg)
110
192
  errors << [path, msg]
111
193
  end
194
+
195
+ log << [:ERROR, path, "#{more_errors.size} parse error(s), #{tree.size} tree node(s)"]
196
+ else
197
+ log << [:OK, path, "#{tree.size} tree node(s)"]
112
198
  end
113
199
  end
114
200
 
@@ -117,10 +203,12 @@ specs.each_with_index do |rec,i|
117
203
  puts
118
204
  pp errors
119
205
  puts
206
+ puts
207
+ pp log
120
208
  puts "!! #{errors.size} parse error(s) in #{datafiles.size} datafiles(s)"
121
209
  else
122
210
  puts
123
- pp datafiles
211
+ pp log
124
212
  puts "OK no parse errors found in #{datafiles.size} datafile(s)"
125
213
  end
126
214
 
@@ -167,4 +255,31 @@ def self.dump_tree_stats( tree )
167
255
  end
168
256
 
169
257
 
258
+
259
+ def self.parse_with_errors( txt, opts={} )
260
+ parser = RaccMatchParser.new( txt, debug: opts[:debug] )
261
+ tree = parser.parse
262
+
263
+ dump_tree_stats( tree )
264
+
265
+ if opts[:yaml]
266
+ puts "--- yaml ---"
267
+ puts YAML.dump( tree )
268
+ end
269
+
270
+ if opts[:json]
271
+ puts "--- json ---"
272
+ ## puts JSON.pretty_generate( tree )
273
+ ##
274
+ ## note - use hacky but more beautiful pretty_print
275
+ txtjson = tree.as_json.pretty_inspect
276
+ txtjson = txtjson.gsub( '=>', ': ' )
277
+ puts txtjson
278
+ end
279
+
280
+
281
+ [tree, parser.errors]
282
+ end
283
+
284
+
170
285
  end # module Fbtree
@@ -1,5 +1,7 @@
1
1
 
2
2
 
3
+
4
+
3
5
  module SportDb
4
6
  class Pathspec
5
7
 
@@ -131,6 +133,15 @@ def self.find( path, seasons: nil )
131
133
  next if /squad/i.match?( basename )
132
134
  next if /\.v[0-9][0-9_]*/i.match?( basename )
133
135
 
136
+ ### exclude
137
+ ## logs.txt or logs.xxx.txt etc
138
+ ## log.txt or log.xxx.txt etc
139
+ ## -or-
140
+ ## errors.txt or errors.xxx.txt etc
141
+ next if /^logs?($|\.)/i.match?( basename )
142
+ next if /^errors?($|\.)/i.match?( basename )
143
+
144
+
134
145
  #####
135
146
  ### exclude dirs with:
136
147
  ## - squad or wiki
@@ -194,6 +205,20 @@ def self.read( src )
194
205
  end
195
206
 
196
207
 
208
+ ## quick (internal) helper to
209
+ ## expand names (directories) ending with /*
210
+ ## with Pathspec.find
211
+ def self._expand_pathspecs( names )
212
+ datafiles = []
213
+ names.each do |name|
214
+ if name.end_with?('/*')
215
+ datafiles += Pathspec.find( name[0..-3] )
216
+ else
217
+ datafiles << name
218
+ end
219
+ end
220
+ datafiles
221
+ end
197
222
 
198
223
  def self.build( args, path: [],
199
224
  filepack: nil )
@@ -203,7 +228,7 @@ def self.build( args, path: [],
203
228
  if args.empty?
204
229
  if filepack && filepack.has_key?('default')
205
230
  recs << { 'path' => '<default>',
206
- 'datafiles' => filepack['default'] }
231
+ 'datafiles' => _expand_pathspecs(filepack['default']) }
207
232
  end
208
233
  else
209
234
 
@@ -217,12 +242,16 @@ def self.build( args, path: [],
217
242
  ##
218
243
  ## todo/check if euro/ works too?
219
244
  ## check if directory
220
- if Dir.exist?( arg )
245
+ ## note - make find_dir/path lookup an env variable
246
+ ## e.g. FBTXT_ROOTDIR, FBTXT_SOURCE, FBSOURCE,
247
+ ## FBTXT_REPOS/PACKS/etc. or such!!!
248
+ ## add dir_path/dirs or such to build - why? why not?
249
+ if dir=find_dir( arg, path: ['/sports/openfootball'] )
221
250
  recs << { 'path' => arg,
222
- 'datafiles' => Pathspec.find( arg ) }
251
+ 'datafiles' => Pathspec.find( dir ) }
223
252
  elsif filepack && filepack.has_key?( arg.downcase )
224
253
  recs << { 'path' => "<#{arg.downcase}>",
225
- 'datafiles' => filepack[arg.downcase] }
254
+ 'datafiles' => _expand_pathspecs(filepack[arg.downcase]) }
226
255
  else ## assume it's a file
227
256
  file = find_file( arg, path: path )
228
257
  ## check if file (exists) in any path lookup
@@ -274,3 +303,27 @@ end
274
303
  def read_pathspecs( src )
275
304
  SportDb::Pathspecs.read( src )
276
305
  end
306
+
307
+
308
+
309
+ def filter_pathspecs( specs, seasons: )
310
+ ## norm seasons
311
+ seasons = seasons.map {|season| Season(season) }
312
+
313
+ ## todo/fix: auto-add/update rec['seasons'] column - why? why not?
314
+
315
+ ## note - filter datafiles inplace!!!
316
+ specs.each do |rec|
317
+ rec['datafiles'] =
318
+ rec['datafiles'].select do |candidate|
319
+ m=SportDb::Pathspec::MATCH_RE.match( candidate )
320
+ if m && seasons.include?( Season.parse( m[:season] ))
321
+ true
322
+ else
323
+ false
324
+ end
325
+ end
326
+ end
327
+
328
+ specs
329
+ 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.3
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-22 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