sportdb-readers 0.5.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,73 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module SportDb
4
-
5
-
6
- class ConfLinter
7
-
8
- def self.config() Import.config; end ## shortcut convenience helper
9
-
10
-
11
- def self.read( path, season: nil ) ## use - rename to read_file or from_file etc. - why? why not?
12
- puts "reading conf(iguration) datafile >#{path}<..."
13
- txt = File.open( path, 'r:utf-8' ).read
14
- parse( txt, season: season )
15
- end
16
-
17
- def self.parse( txt, season: nil )
18
- recs = LeagueOutlineReader.parse( txt, season: season )
19
-
20
- if recs.empty? ## todo: check for season filter - why? why not?
21
- puts " ** !!! WARN !!! - no league headings found"
22
- else
23
- puts " found #{recs.size} league (+season+stage) headings"
24
- recs.each do |rec|
25
- ## rec[:league] )
26
- ## rec[:season] )
27
- ## rec[:stage]
28
- puts " league: >#{rec[:league]}<, season: >#{rec[:season]}<, stage: >#{rec[:stage]}<"
29
- end
30
- end
31
-
32
- ## pass 2 - check & map; replace inline (string with record)
33
- recs.each do |rec|
34
- league = rec[:league]
35
- clubs = [] ## convert lines to clubs
36
- rec[:lines].each do |line|
37
-
38
- next if line =~ /^[ -]+$/ ## skip decorative lines with dash only (e.g. ---- or - - - -) etc.
39
-
40
- scan = StringScanner.new( line )
41
-
42
- if scan.check( /\d{1,2}[ ]+/ ) ## entry with standaning starts with ranking e.g. 1,2,3, etc.
43
- puts " table entry >#{line}<"
44
- rank = scan.scan( /\d{1,2}[ ]+/ ).strip # note: strip trailing spaces
45
-
46
- ## note: uses look ahead scan until we hit at least two spaces
47
- ## or the end of string (standing records for now optional)
48
- name = scan.scan_until( /(?=\s{2})|$/ )
49
- if scan.eos?
50
- standing = nil
51
- else
52
- standing = scan.rest.strip # note: strip leading and trailing spaces
53
- end
54
- puts " rank: >#{rank}<, name: >#{name}<, standing: >#{standing}<"
55
-
56
- ## note: rank and standing gets ignored (not used) for now
57
- else
58
- ## assume club is full line
59
- name = line
60
- end
61
-
62
- clubs << config.clubs.find_by!( name: name, country: league.country )
63
- end
64
-
65
- rec[:clubs] = clubs
66
- rec.delete( :lines ) ## remove lines entry
67
- end
68
-
69
- recs
70
- end # method read
71
-
72
- end # class ConfLinter
73
- end # module SportDb
@@ -1,146 +0,0 @@
1
- # encoding: utf-8
2
-
3
-
4
- module SportDb
5
-
6
- ## shared "higher-level" outline reader
7
- ## todo: add CountryOutlineReader - why? why not?
8
-
9
- class LeagueOutlineReader
10
-
11
- def self.config() Import.config; end ## shortcut convenience helper
12
-
13
- ## split into league + season
14
- ## e.g. Österr. Bundesliga 2015/16 ## or 2015-16
15
- ## World Cup 2018
16
- LEAGUE_SEASON_HEADING_REGEX = /^
17
- (?<league>.+?) ## non-greedy
18
- \s+
19
- (?<season>\d{4}
20
- (?:[\/-]\d{2})? ## optional 2nd year in season
21
- )
22
- $/x
23
-
24
-
25
- def self.parse( txt, season: nil )
26
- recs=[]
27
- OutlineReader.parse( txt ).each do |node|
28
- if node[0] == :h1
29
- ## check for league (and stage) and season
30
- heading = node[1]
31
- values = split_league( heading )
32
- if m=values[0].match( LEAGUE_SEASON_HEADING_REGEX )
33
- puts "league >#{m[:league]}<, season >#{m[:season]}<"
34
-
35
- recs << { league: m[:league],
36
- season: m[:season],
37
- stage: values[1], ## note: defaults to nil if not present
38
- lines: []
39
- }
40
- else
41
- puts "** !!! ERROR !!! - CANNOT match league and season in heading; season missing?"
42
- pp heading
43
- exit 1
44
- end
45
- elsif node[0] == :l ## regular (text) line
46
- line = node[1]
47
- ## note: skip lines if no heading seen
48
- if recs.empty?
49
- puts "** !! WARN !! - skipping line (no heading) >#{line}<"
50
- else
51
- recs[-1][:lines] << line
52
- end
53
- else
54
- puts "** !!! ERROR !!! unknown line type; for now only heading 1 for leagues supported; sorry:"
55
- pp node
56
- exit 1
57
- end
58
- end
59
-
60
-
61
- ## pass 2 - filter seasons if filter present
62
- if season
63
- filtered_recs = []
64
- filter = normalize_seasons( season )
65
- recs.each do |rec|
66
- if filter.include?( SeasonUtils.key( rec[:season] ))
67
- filtered_recs << rec
68
- else
69
- puts " skipping season >#{rec[:season]}< NOT matched by filter"
70
- end
71
- end
72
- recs = filtered_recs
73
- end
74
-
75
- ## pass 3 - check & map; replace inline (string with data record)
76
- recs.each do |rec|
77
- league = find_league( rec[:league] )
78
- rec[:league] = league
79
-
80
- check_stage( rec[:stage] ) if rec[:stage] ## note: only check for now (no remapping etc.)
81
- end
82
-
83
- recs
84
- end # method parse
85
-
86
-
87
-
88
- def self.normalize_seasons( season_or_seasons ) ## todo/check: add alias norm_seasons - why? why not?
89
- seasons = if season_or_seasons.is_a? String ## wrap in array
90
- [season_or_seasons]
91
- else ## assume it's an array already
92
- season_or_seasons
93
- end
94
-
95
- seasons.map { |season| SeasonUtils.key( season ) }
96
- end
97
-
98
-
99
- def self.split_league( str ) ## todo/check: rename to parse_league(s) - why? why not?
100
- ## split into league / stage / ... e.g.
101
- ## => Österr. Bundesliga 2018/19, Regular Season
102
- ## => Österr. Bundesliga 2018/19, Championship Round
103
- ## etc.
104
- values = str.split( /[,<>‹›]/ ) ## note: allow , > < or › ‹ for now
105
- values = values.map { |value| value.strip } ## remove all whitespaces
106
- values
107
- end
108
-
109
- def self.check_stage( name )
110
- known_stages = ['regular season',
111
- 'championship round',
112
- 'relegation round',
113
- 'play-offs'
114
- ]
115
-
116
- if known_stages.include?( name.downcase )
117
- ## everything ok
118
- else
119
- puts "** !!! ERROR !!! no (league) stage match found for >#{name}<, add to (builtin) stages table; sorry"
120
- exit 1
121
- end
122
- end
123
-
124
-
125
- ### fix/todo: move find_league to sportdb-league index use find_by! and find_by !!!!
126
- def self.find_league( name )
127
- league = nil
128
- m = config.leagues.match( name )
129
- # pp m
130
-
131
- if m.nil?
132
- puts "** !!! ERROR !!! no league match found for >#{name}<, add to leagues table; sorry"
133
- exit 1
134
- elsif m.size > 1
135
- puts "** !!! ERROR !!! ambigious league name; too many leagues (#{m.size}) found:"
136
- pp m
137
- exit 1
138
- else
139
- league = m[0]
140
- end
141
-
142
- league
143
- end
144
- end # class LeagueOutlineReader
145
-
146
- end # module SportDb
@@ -1,30 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module SportDb
4
-
5
- class MatchLinter
6
-
7
- def self.read( path, season: nil ) ## use - rename to read_file or from_file etc. - why? why not?
8
- puts "reading match datafile >#{path}<..."
9
- txt = File.open( path, 'r:utf-8' ).read
10
- parse( txt, season: season )
11
- end
12
-
13
- def self.parse( txt, season: nil )
14
- recs = LeagueOutlineReader.parse( txt, season: season )
15
-
16
- if recs.empty? ## todo - check for filter - why? why not?
17
- puts " ** !!! WARN !!! - no league headings found"
18
- else
19
- puts " found #{recs.size} league (+season+stage) headings"
20
- recs.each do |rec|
21
- ## rec[:league] )
22
- ## rec[:season] )
23
- ## rec[:stage]
24
- puts " league: >#{rec[:league]}<, season: >#{rec[:season]}<, stage: >#{rec[:stage]}<"
25
- end
26
- end
27
- recs
28
- end # method read
29
- end # class MatchLinter
30
- end # module SportDb