sportdb-quick 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: 71f76e171de23b5062c30f432d5fece7bcb2cb0e7283d658dcf8ff79aefb6aa3
4
- data.tar.gz: 74fc864d5c4b9ca42270abd3fdb941cebdb9857c072c7515e7e422829c018891
3
+ metadata.gz: d7f373cf63aa06b60bfe3f654df254e3e04d5a47c499a6be1dc4f9d90c061f84
4
+ data.tar.gz: ec5b8ea56ef5785b4133cd814254a0a4290873b453e806ad27f974dac4ac8594
5
5
  SHA512:
6
- metadata.gz: 83fa67d7c4bbd0952ad9e02f93be65c488bd728b52f8a9a1159ab42bd299b6b9b37ff5e75573582ef4a7f20ebef1d97ff7da111334dd5f6b4b71bf4793ea84af
7
- data.tar.gz: 9f832375e9d03fe1de7d83d14083428d0f3eda704645cf585449d13cf7929030552075549d68e0d91892be0d66c4bf92fbc41a2403cecee362025ed2b2058513
6
+ metadata.gz: 19dd7b607f4c3288f176f941a570c1f316956ee2867f1cfebaebcf180506a3d640a797ea723ee889406f8f6682c326a95ab89a0877250b4709fa8bb5b6eb8aef
7
+ data.tar.gz: b6a76be55c06acb1f4487794a9097d2f6e1d5ea4414b2f1fabbf32d3f18df2a90cc8024d1c51b8f42d7be1e610ba7543dc9c6b41e3eea4822e16e8b689ca7687
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.5.1
1
+ ### 0.5.2
2
2
  ### 0.0.1 / 2024-08-27
3
3
 
4
4
  * Everything is new. First release.
data/Manifest.txt CHANGED
@@ -4,6 +4,8 @@ README.md
4
4
  Rakefile
5
5
  lib/sportdb/quick.rb
6
6
  lib/sportdb/quick/match_parser.rb
7
- lib/sportdb/quick/quick_league_outline_reader.rb
7
+ lib/sportdb/quick/outline.rb
8
+ lib/sportdb/quick/outline_reader.rb
9
+ lib/sportdb/quick/quick_league_outline.rb
8
10
  lib/sportdb/quick/quick_match_reader.rb
9
11
  lib/sportdb/quick/version.rb
@@ -32,22 +32,36 @@ class MatchParser ## simple match parser for team match schedules
32
32
 
33
33
 
34
34
 
35
-
36
- def _read_lines( txt ) ## todo/check: add alias preproc_lines or build_lines or prep_lines etc. - why? why not?
37
- ## returns an array of lines with comments and empty lines striped / removed
38
- lines = []
35
+ def _prep_lines( lines ) ## todo/check: add alias preproc_lines or build_lines or prep_lines etc. - why? why not?
36
+
37
+ ## todo/fix - rework and make simpler
38
+ ## no need to double join array of string to txt etc.
39
+
40
+ txt = if lines.is_a?( Array )
41
+ ## join together with newline
42
+ lines.reduce( String.new ) do |mem,line|
43
+ mem << line; mem << "\n"; mem
44
+ end
45
+ else ## assume single-all-in-one txt
46
+ lines
47
+ end
48
+
49
+ ## preprocess automagically - why? why not?
50
+ ## strip lines with comments and empty lines striped / removed
51
+ txt_new = String.new
39
52
  txt.each_line do |line| ## preprocess
40
53
  line = line.strip
41
54
  next if line.empty? || line.start_with?('#') ### skip empty lines and comments
42
55
 
43
56
  line = line.sub( /#.*/, '' ).strip ### cut-off end-of line comments too
44
- lines << line
57
+
58
+ txt_new << line
59
+ txt_new << "\n"
45
60
  end
46
- lines
61
+ txt_new
47
62
  end
48
63
 
49
64
 
50
-
51
65
  #
52
66
  # todo/fix: change start to start: too!!!
53
67
  # might be optional in the future!! - why? why not?
@@ -58,9 +72,10 @@ class MatchParser ## simple match parser for team match schedules
58
72
  ## todo/check: change to text instead of array of lines - why? why not?
59
73
 
60
74
  ## note - wrap in enumerator/iterator a.k.a lines reader
61
- @lines = lines.is_a?( String ) ?
62
- _read_lines( lines ) : lines
75
+ ## @lines = lines.is_a?( String ) ?
76
+ ## _read_lines( lines ) : lines
63
77
 
78
+ @txt = _prep_lines( lines )
64
79
  @start = start
65
80
  @errors = []
66
81
  end
@@ -90,17 +105,9 @@ class MatchParser ## simple match parser for team match schedules
90
105
  @tree = []
91
106
 
92
107
 
93
- ## flatten lines
94
- txt = []
95
- @lines.each_with_index do |line,i|
96
- txt << line
97
- txt << "\n"
98
- end
99
- txt = txt.join
100
-
101
108
  if debug?
102
109
  puts "lines:"
103
- pp txt
110
+ pp @txt
104
111
  end
105
112
 
106
113
  =begin
@@ -123,7 +130,7 @@ class MatchParser ## simple match parser for team match schedules
123
130
  @tree << t
124
131
  =end
125
132
 
126
- parser = RaccMatchParser.new( txt ) ## use own parser instance (not shared) - why? why not?
133
+ parser = RaccMatchParser.new( @txt ) ## use own parser instance (not shared) - why? why not?
127
134
  @tree = parser.parse
128
135
  ## pp @tree
129
136
 
@@ -151,6 +158,8 @@ class MatchParser ## simple match parser for team match schedules
151
158
  on_match_line( node )
152
159
  elsif node.is_a? RaccMatchParser::GoalLine
153
160
  on_goal_line( node )
161
+ elsif node.is_a? RaccMatchParser::LineupLine
162
+ ## skip lineup for now
154
163
  else
155
164
  ## report error
156
165
  msg = "!! WARN - unknown node (parse tree type) - #{node.class.name}"
@@ -159,7 +168,6 @@ class MatchParser ## simple match parser for team match schedules
159
168
 
160
169
  log( msg )
161
170
  log( node.pretty_inspect )
162
- ## exit 1
163
171
  end
164
172
  end # tree.each
165
173
 
@@ -566,18 +574,26 @@ class GoalStruct
566
574
  time_str = time if date && time
567
575
 
568
576
 
569
- ground = nil
577
+ ground = nil
578
+ timezone = nil
579
+ if node.geo
580
+ ground = node.geo
581
+ ## note: only add/check for timezone if geo (aka ground) is present - why? why not?
582
+ timezone = node.timezone if node.timezone
583
+ end
584
+
570
585
 
571
- @matches << Import::Match.new( num: num,
572
- date: date_str,
573
- time: time_str,
574
- team1: team1, ## note: for now always use mapping value e.g. rec (NOT string e.g. team1.name)
575
- team2: team2, ## note: for now always use mapping value e.g. rec (NOT string e.g. team2.name)
576
- score: score,
577
- round: round ? round.name : nil, ## note: for now always use string (assume unique canonical name for event)
578
- group: @last_group ? @last_group.name : nil, ## note: for now always use string (assume unique canonical name for event)
579
- status: status,
580
- ground: ground )
586
+ @matches << Import::Match.new( num: num,
587
+ date: date_str,
588
+ time: time_str,
589
+ team1: team1, ## note: for now always use mapping value e.g. rec (NOT string e.g. team1.name)
590
+ team2: team2, ## note: for now always use mapping value e.g. rec (NOT string e.g. team2.name)
591
+ score: score,
592
+ round: round ? round.name : nil, ## note: for now always use string (assume unique canonical name for event)
593
+ group: @last_group ? @last_group.name : nil, ## note: for now always use string (assume unique canonical name for event)
594
+ status: status,
595
+ ground: ground,
596
+ timezone: timezone )
581
597
  ### todo: cache team lookups in hash?
582
598
  end
583
599
  end # class MatchParser
@@ -0,0 +1,96 @@
1
+
2
+ module SportDb
3
+
4
+ ###
5
+ # add a simple Outline convenience class
6
+ # for processing OUtlines with OUtlineReader
7
+ # rename to simply Outline - why? why not?
8
+ # todo - add more processing options - why? why not?
9
+
10
+ class Outline
11
+ def self.read( path )
12
+ nodes = OutlineReader.read( path )
13
+ new( nodes )
14
+ end
15
+
16
+ def self.parse( txt )
17
+ nodes = OutlineReader.parse( txt )
18
+ new( nodes )
19
+ end
20
+
21
+
22
+ def initialize( nodes )
23
+ @nodes = nodes
24
+ end
25
+
26
+ def each_para( &blk )
27
+ ## note: every (new) read call - resets errors list to empty
28
+ ### @errors = []
29
+
30
+ ## process nodes
31
+ h1 = nil
32
+ h2 = nil
33
+ orphans = 0 ## track paragraphs's with no heading
34
+
35
+ @nodes.each do |node|
36
+ type = node[0]
37
+
38
+ if type == :h1
39
+ h1 = node[1] ## get heading text
40
+ puts " = Heading 1 >#{node[1]}<"
41
+ elsif type == :h2
42
+ if h1.nil?
43
+ puts "!! WARN - no heading for subheading; skipping processing"
44
+ next
45
+ end
46
+ h2 = node[1] ## get heading text
47
+ puts " == Heading 2 >#{node[1]}<"
48
+ elsif type == :p
49
+ if h1.nil?
50
+ orphans += 1 ## only warn once
51
+ puts "!! WARN - no heading for #{orphans} text paragraph(s); skipping parse"
52
+ next
53
+ end
54
+
55
+ lines = node[1]
56
+ blk.call( lines )
57
+ else
58
+ pp node
59
+ raise ArgumentError, "unsupported (node) type >#{type}<"
60
+ end
61
+ end # each node
62
+ end # each_para
63
+ alias_method :each_paragraph, :each_para
64
+
65
+
66
+ ## get all para(graphs) as text (not array of lines)
67
+ ## make default - why? why not?
68
+ #
69
+ # design - or wrap lines into a Para class
70
+ # with properties lines and text
71
+ # and such - why? why not?
72
+ # downside - might be overkill/overengineered
73
+ # just use simple txt as string (buffer) for all - why? why not?
74
+ ##
75
+ ## hacky alternative - add a to_text or text method to string and array - why? why not?
76
+
77
+
78
+ def each_para_text( &blk ) ## or use each_text or ? - why? why not=
79
+ each_para do |lines|
80
+ txt = lines.reduce( String.new ) do |mem,line|
81
+ mem << line; mem << "\n"; mem
82
+ end
83
+ blk.call( txt )
84
+ end
85
+ end
86
+ end # class Outline
87
+
88
+
89
+
90
+ ###
91
+ # add alternate alias - why? why not?
92
+ QuickMatchOutline = Outline
93
+
94
+
95
+ end ## module SportDb
96
+
@@ -0,0 +1,98 @@
1
+
2
+
3
+ module SportDb
4
+
5
+
6
+ class OutlineReader
7
+
8
+ def self.debug=(value) @@debug = value; end
9
+ def self.debug?() @@debug ||= false; end
10
+ def debug?() self.class.debug?; end
11
+
12
+
13
+
14
+ def self.read( path ) ## use - rename to read_file or from_file etc. - why? why not?
15
+ txt = File.open( path, 'r:utf-8' ) {|f| f.read }
16
+ parse( txt )
17
+ end
18
+
19
+ def self.parse( txt )
20
+ new( txt ).parse
21
+ end
22
+
23
+ def initialize( txt )
24
+ @txt = txt
25
+ end
26
+
27
+ ## note: skip "decorative" only heading e.g. ========
28
+ ## todo/check: find a better name e.g. HEADING_EMPTY_RE or HEADING_LINE_RE or ???
29
+ HEADING_BLANK_RE = %r{\A
30
+ ={1,}
31
+ \z}x
32
+
33
+ ## note: like in wikimedia markup (and markdown) all optional trailing ==== too
34
+ HEADING_RE = %r{\A
35
+ (?<marker>={1,}) ## 1. leading ======
36
+ [ ]*
37
+ (?<text>[^=]+) ## 2. text (note: for now no "inline" = allowed)
38
+ [ ]*
39
+ =* ## 3. (optional) trailing ====
40
+ \z}x
41
+
42
+ def parse
43
+ outline=[] ## outline structure
44
+ start_para = true ## start new para(graph) on new text line?
45
+
46
+ @txt.each_line do |line|
47
+ line = line.strip ## todo/fix: keep leading and trailing spaces - why? why not?
48
+
49
+ if line.empty? ## todo/fix: keep blank line nodes?? and just remove comments and process headings?! - why? why not?
50
+ start_para = true
51
+ next
52
+ end
53
+
54
+ break if line == '__END__'
55
+
56
+ next if line.start_with?( '#' ) ## skip comments too
57
+ ## strip inline (until end-of-line) comments too
58
+ ## e.g Eupen | KAS Eupen ## [de]
59
+ ## => Eupen | KAS Eupen
60
+ ## e.g bq Bonaire, BOE # CONCACAF
61
+ ## => bq Bonaire, BOE
62
+ line = line.sub( /#.*/, '' ).strip
63
+ pp line if debug?
64
+
65
+ ## todo/check: also use heading blank as paragraph "breaker" or treat it like a comment ?? - why? why not?
66
+ next if HEADING_BLANK_RE.match( line ) # skip "decorative" only heading e.g. ========
67
+
68
+ ## note: like in wikimedia markup (and markdown) all optional trailing ==== too
69
+ if m=HEADING_RE.match( line )
70
+ start_para = true
71
+
72
+ heading_marker = m[:marker]
73
+ heading_level = heading_marker.length ## count number of = for heading level
74
+ heading = m[:text].strip
75
+
76
+ puts "heading #{heading_level} >#{heading}<" if debug?
77
+ outline << [:"h#{heading_level}", heading]
78
+ else ## assume it's a (plain/regular) text line
79
+ if start_para
80
+ outline << [:p, [line]]
81
+ start_para = false
82
+ else
83
+ node = outline[-1] ## get last entry
84
+ if node[0] == :p ## assert it's a p(aragraph) node!!!
85
+ node[1] << line ## add line to p(aragraph)
86
+ else
87
+ puts "!! ERROR - invalid outline state / format - expected p(aragraph) node; got:"
88
+ pp node
89
+ exit 1
90
+ end
91
+ end
92
+ end
93
+ end
94
+ outline
95
+ end # method read
96
+ end # class OutlineReader
97
+
98
+ end # module SportDb
@@ -3,39 +3,66 @@
3
3
  module SportDb
4
4
 
5
5
  ## shared "higher-level" outline reader
6
- ### quick version WITHOUT any validation/mapping !!!
6
+ ### quick version WITHOUT any (database) validation/mapping/normalization !!!
7
7
 
8
- class QuickLeagueOutlineReader
8
+
9
+ class QuickLeagueOutline
9
10
 
10
11
  def self.read( path )
11
- txt = File.open( path, 'r:utf-8' ) {|f| f.read }
12
- parse( txt )
13
- end
12
+ nodes = OutlineReader.read( path )
13
+ new( nodes )
14
+ end
14
15
 
15
16
  def self.parse( txt )
16
- new( txt ).parse
17
+ nodes = OutlineReader.parse( txt )
18
+ new( nodes )
17
19
  end
18
20
 
19
21
 
20
- def initialize( txt )
21
- @txt = txt
22
+
23
+ def initialize( nodes )
24
+ @nodes = nodes
22
25
  end
23
26
 
24
- def parse
27
+
28
+ ###
29
+ # use Section struct for easier access - why? why not?
30
+ ## e.g. sec.league instead of sec[:league] etc.
31
+
32
+ Section = Struct.new( :league, :season, :stage, :lines ) do
33
+ def text ## for alternate line access (all-in-text string)
34
+ txt = lines.reduce( String.new ) do |mem,line|
35
+ mem << line; mem << "\n"; mem
36
+ end
37
+ txt
38
+ end
39
+ end
40
+
41
+ def each_sec( &blk )
42
+ @secs ||= _parse
43
+
44
+ @secs.each do |sec|
45
+ blk.call( sec )
46
+ end
47
+ end
48
+ alias_method :each_section, :each_sec
49
+
50
+
51
+ def _parse
25
52
  secs=[] # sec(tion)s
26
- OutlineReader.parse( @txt ).each do |node|
53
+ @nodes.each do |node|
27
54
  if node[0] == :h1
28
55
  ## check for league (and stage) and season
29
56
  heading = node[1]
30
- values = split_league( heading )
57
+ values = _split_league( heading )
31
58
  if m=values[0].match( LEAGUE_SEASON_HEADING_RE )
32
59
  puts "league >#{m[:league]}<, season >#{m[:season]}<"
33
60
 
34
- secs << { league: m[:league],
35
- season: m[:season],
36
- stage: values[1], ## note: defaults to nil if not present
37
- lines: []
38
- }
61
+ secs << Section.new( league: m[:league],
62
+ season: m[:season],
63
+ stage: values[1], ## note: defaults to nil if not present
64
+ lines: []
65
+ )
39
66
  else
40
67
  puts "** !!! ERROR - cannot match league and season in heading; season missing?"
41
68
  pp heading
@@ -44,12 +71,12 @@ class QuickLeagueOutlineReader
44
71
  elsif node[0] == :h2
45
72
  ## todo/check - make sure parsed h1 first
46
73
  heading = node[1]
47
- ## reuse league, season from h1
48
- secs << { league: secs[-1][:league],
49
- season: secs[-1][:season],
50
- stage: heading,
51
- lines: []
52
- }
74
+ ## note - reuse league, season from h1
75
+ secs << Section.new( league: secs[-1].league,
76
+ season: secs[-1].season,
77
+ stage: heading,
78
+ lines: []
79
+ )
53
80
  elsif node[0] == :p ## paragraph with (text) lines
54
81
  lines = node[1]
55
82
  ## note: skip lines if no heading seen
@@ -58,7 +85,8 @@ class QuickLeagueOutlineReader
58
85
  pp lines
59
86
  else
60
87
  ## todo/check: unroll paragraphs into lines or pass along paragraphs - why? why not?
61
- secs[-1][:lines] += lines
88
+ ## add paragraphs not unrolled lines - why? why not?
89
+ secs[-1].lines += lines
62
90
  end
63
91
  else
64
92
  puts "** !!! ERROR - unknown line type; for now only heading 1 for leagues supported; sorry:"
@@ -67,7 +95,7 @@ class QuickLeagueOutlineReader
67
95
  end
68
96
  end
69
97
  secs
70
- end # method parse
98
+ end # method _parse
71
99
 
72
100
 
73
101
  ## split into league + season
@@ -81,7 +109,7 @@ class QuickLeagueOutlineReader
81
109
  )
82
110
  $}x
83
111
 
84
- def split_league( str ) ## todo/check: rename to parse_league(s) - why? why not?
112
+ def _split_league( str ) ## todo/check: rename to parse_league(s) - why? why not?
85
113
  ## split into league / stage / ... e.g.
86
114
  ## => Österr. Bundesliga 2018/19, Regular Season
87
115
  ## => Österr. Bundesliga 2018/19, Championship Round
@@ -91,5 +119,5 @@ class QuickLeagueOutlineReader
91
119
  values = values.map { |value| value.strip } ## remove all whitespaces
92
120
  values
93
121
  end
94
- end # class QuickLeagueOutlineReader
122
+ end # class QuickLeagueOutline
95
123
  end # module SportDb
@@ -24,7 +24,7 @@ class QuickMatchReader
24
24
 
25
25
  def initialize( txt )
26
26
  @errors = []
27
- @txt = txt
27
+ @outline = QuickLeagueOutline.parse( txt )
28
28
  end
29
29
 
30
30
  attr_reader :errors
@@ -55,17 +55,15 @@ class QuickMatchReader
55
55
  @errors = []
56
56
 
57
57
  @data = {} # return data hash with leagues
58
- # and seasons
59
- # for now merge stage into matches
60
-
61
- secs = QuickLeagueOutlineReader.parse( @txt )
62
- pp secs if debug?
63
-
64
- secs.each do |sec| ## sec(tion)s
65
- season = Season.parse( sec[:season] ) ## convert (str) to season obj!!!
66
- league = sec[:league]
67
- stage = sec[:stage]
68
- lines = sec[:lines]
58
+ # and seasons
59
+ # for now merge stage into matches
60
+
61
+ @outline.each_sec do |sec| ## sec(tion)s
62
+ ### move season parse into outline upstream - why? why not?
63
+ season = Season.parse( sec.season ) ## convert (str) to season obj!!!
64
+ league = sec.league
65
+ stage = sec.stage
66
+ lines = sec.lines
69
67
 
70
68
  start = if season.year?
71
69
  Date.new( season.start_year, 1, 1 )
@@ -4,7 +4,7 @@ module SportDb
4
4
  module Quick
5
5
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
6
6
  MINOR = 5
7
- PATCH = 1
7
+ PATCH = 2
8
8
  VERSION = [MAJOR,MINOR,PATCH].join('.')
9
9
 
10
10
  def self.version
data/lib/sportdb/quick.rb CHANGED
@@ -17,10 +17,17 @@ end
17
17
  ## our own code
18
18
  require_relative 'quick/version'
19
19
 
20
-
20
+ ## "generic" outline readers, documents & more
21
+ ##
22
+ ## todo/check - move outline reader upstream to cocos - why? why not?
23
+ ## use read_outline(), parse_outline() - why? why not?
24
+ require_relative 'quick/outline_reader'
25
+ require_relative 'quick/outline'
26
+
27
+ ## match & league machinery
21
28
  require_relative 'quick/match_parser'
22
29
 
23
- require_relative 'quick/quick_league_outline_reader'
30
+ require_relative 'quick/quick_league_outline'
24
31
  require_relative 'quick/quick_match_reader'
25
32
 
26
33
 
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.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: 2025-01-18 00:00:00.000000000 Z
11
+ date: 2025-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sportdb-parser
@@ -101,7 +101,9 @@ files:
101
101
  - Rakefile
102
102
  - lib/sportdb/quick.rb
103
103
  - lib/sportdb/quick/match_parser.rb
104
- - lib/sportdb/quick/quick_league_outline_reader.rb
104
+ - lib/sportdb/quick/outline.rb
105
+ - lib/sportdb/quick/outline_reader.rb
106
+ - lib/sportdb/quick/quick_league_outline.rb
105
107
  - lib/sportdb/quick/quick_match_reader.rb
106
108
  - lib/sportdb/quick/version.rb
107
109
  homepage: https://github.com/sportdb/sport.db