sportdb-formats 0.4.0 → 1.0.0
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 +4 -4
- data/Manifest.txt +24 -4
- data/Rakefile +3 -3
- data/lib/sportdb/formats.rb +25 -2
- data/lib/sportdb/formats/config.rb +40 -0
- data/lib/sportdb/formats/datafile.rb +42 -62
- data/lib/sportdb/formats/datafile_package.rb +160 -0
- data/lib/sportdb/formats/match/conf_parser.rb +120 -0
- data/lib/sportdb/formats/match/mapper.rb +319 -0
- data/lib/sportdb/formats/match/mapper_teams.rb +23 -0
- data/lib/sportdb/formats/match/match_parser.rb +659 -0
- data/lib/sportdb/formats/match/match_parser_auto_conf.rb +202 -0
- data/lib/sportdb/formats/name_helper.rb +84 -0
- data/lib/sportdb/formats/outline_reader.rb +53 -15
- data/lib/sportdb/formats/package.rb +172 -160
- data/lib/sportdb/formats/parser_helper.rb +81 -0
- data/lib/sportdb/formats/score/score_formats.rb +180 -0
- data/lib/sportdb/formats/score/score_parser.rb +196 -0
- data/lib/sportdb/formats/structs/country.rb +1 -43
- data/lib/sportdb/formats/structs/group.rb +25 -0
- data/lib/sportdb/formats/structs/league.rb +7 -26
- data/lib/sportdb/formats/structs/match.rb +72 -51
- data/lib/sportdb/formats/structs/round.rb +14 -4
- data/lib/sportdb/formats/structs/season.rb +3 -0
- data/lib/sportdb/formats/structs/team.rb +144 -0
- data/lib/sportdb/formats/version.rb +2 -2
- data/test/helper.rb +83 -1
- data/test/test_clubs.rb +3 -3
- data/test/test_conf.rb +65 -0
- data/test/test_datafile.rb +21 -30
- data/test/test_match.rb +0 -6
- data/test/test_match_auto.rb +72 -0
- data/test/test_match_auto_champs.rb +45 -0
- data/test/test_match_auto_euro.rb +37 -0
- data/test/test_match_auto_worldcup.rb +61 -0
- data/test/test_match_champs.rb +27 -0
- data/test/test_match_eng.rb +26 -0
- data/test/test_match_euro.rb +27 -0
- data/test/test_match_worldcup.rb +27 -0
- data/test/test_name_helper.rb +67 -0
- data/test/test_outline_reader.rb +3 -3
- data/test/test_package.rb +21 -2
- data/test/test_package_match.rb +78 -0
- data/test/test_scores.rb +67 -51
- metadata +32 -12
- data/lib/sportdb/formats/scores.rb +0 -253
- data/lib/sportdb/formats/structs/club.rb +0 -213
- data/test/test_club_helpers.rb +0 -63
- data/test/test_datafile_match.rb +0 -65
@@ -11,7 +11,7 @@ class Country
|
|
11
11
|
|
12
12
|
## note: is read-only/immutable for now - why? why not?
|
13
13
|
## add cities (array/list) - why? why not?
|
14
|
-
attr_reader
|
14
|
+
attr_reader :key, :name, :fifa, :tags
|
15
15
|
attr_accessor :alt_names
|
16
16
|
|
17
17
|
def initialize( key:, name:, fifa:, tags: [] )
|
@@ -20,48 +20,6 @@ class Country
|
|
20
20
|
@tags = tags
|
21
21
|
end
|
22
22
|
|
23
|
-
## add csv-like access by hash key for compatibility - why? why not? - check where used? remove!!!
|
24
|
-
def []( key ) send( key ); end
|
25
|
-
|
26
|
-
|
27
|
-
###################################
|
28
|
-
# "global" helper - move to ___ ? why? why not?
|
29
|
-
## todo/fix: use shared helpers for country, club, etc. (do NOT duplicate)!!!
|
30
|
-
YEAR_REGEX = /\([0-9,\- ]+?\)/
|
31
|
-
def self.strip_year( name )
|
32
|
-
## check for year(s) e.g. (1887-1911), (-2013),
|
33
|
-
## (1946-2001, 2013-) etc.
|
34
|
-
name.gsub( YEAR_REGEX, '' ).strip
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.has_year?( name ) name =~ YEAR_REGEX; end
|
38
|
-
|
39
|
-
LANG_REGEX = /\[[a-z]{1,2}\]/ ## note also allow [a] or [d] or [e] - why? why not?
|
40
|
-
def self.strip_lang( name )
|
41
|
-
name.gsub( LANG_REGEX, '' ).strip
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.has_lang?( name ) name =~ LANG_REGEX; end
|
45
|
-
|
46
|
-
|
47
|
-
NORM_REGEX = /[.'º\-\/]/
|
48
|
-
## note: remove all dots (.), dash (-), ', º, /, etc.
|
49
|
-
## for norm(alizing) names
|
50
|
-
def self.strip_norm( name )
|
51
|
-
name.gsub( NORM_REGEX, '' )
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.normalize( name )
|
55
|
-
# note: do NOT call sanitize here (keep normalize "atomic" for reuse)
|
56
|
-
|
57
|
-
## remove all dots (.), dash (-), º, /, etc.
|
58
|
-
name = strip_norm( name )
|
59
|
-
name = name.gsub( ' ', '' ) # note: also remove all spaces!!!
|
60
|
-
|
61
|
-
## todo/fix: use our own downcase - why? why not?
|
62
|
-
name = downcase_i18n( name ) ## do NOT care about upper and lowercase for now
|
63
|
-
name
|
64
|
-
end
|
65
23
|
end # class Country
|
66
24
|
|
67
25
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SportDb
|
2
|
+
module Import
|
3
|
+
|
4
|
+
class Group
|
5
|
+
attr_reader :title, :pos, :teams
|
6
|
+
|
7
|
+
##
|
8
|
+
## todo: change db schema
|
9
|
+
## make start and end date optional
|
10
|
+
## change pos to num - why? why not?
|
11
|
+
## make pos/num optional too
|
12
|
+
##
|
13
|
+
## sort round by scheduled/planed start date
|
14
|
+
def initialize( title:,
|
15
|
+
pos:,
|
16
|
+
teams: )
|
17
|
+
@title = title
|
18
|
+
@pos = pos
|
19
|
+
@teams = teams
|
20
|
+
end
|
21
|
+
end # class Group
|
22
|
+
|
23
|
+
end # module Import
|
24
|
+
end # module SportDb
|
25
|
+
|
@@ -11,45 +11,26 @@ class League
|
|
11
11
|
attr_accessor :alt_names_auto ## auto-generated alt names
|
12
12
|
|
13
13
|
def initialize( key:, name:, alt_names: [], alt_names_auto: [],
|
14
|
-
country: nil, intl: false )
|
14
|
+
country: nil, intl: false, clubs: true )
|
15
15
|
@key = key
|
16
16
|
@name = name
|
17
17
|
@alt_names = alt_names
|
18
18
|
@alt_names_auto = alt_names_auto
|
19
|
+
|
19
20
|
@country = country
|
20
21
|
@intl = intl
|
22
|
+
@clubs = clubs
|
21
23
|
end
|
22
24
|
|
23
25
|
def intl?() @intl == true; end
|
24
26
|
def national?() @intl == false; end
|
25
27
|
alias_method :domestic?, :national?
|
26
28
|
|
29
|
+
def clubs?() @clubs == true; end
|
30
|
+
def national_teams?() @clubs == false; end
|
31
|
+
alias_method :club?, :clubs?
|
32
|
+
alias_method :national_team?, :national_teams?
|
27
33
|
|
28
|
-
|
29
|
-
## todo/fix: (re)use helpers from clubs - how? why? why not?
|
30
|
-
LANG_REGEX = /\[[a-z]{1,2}\]/ ## note also allow [a] or [d] or [e] - why? why not?
|
31
|
-
def self.strip_lang( name )
|
32
|
-
name.gsub( LANG_REGEX, '' ).strip
|
33
|
-
end
|
34
|
-
|
35
|
-
NORM_REGEX = /[.'º\-\/]/
|
36
|
-
## note: remove all dots (.), dash (-), ', º, /, etc.
|
37
|
-
## for norm(alizing) names
|
38
|
-
def self.strip_norm( name )
|
39
|
-
name.gsub( NORM_REGEX, '' )
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.normalize( name )
|
43
|
-
# note: do NOT call sanitize here (keep normalize "atomic" for reuse)
|
44
|
-
|
45
|
-
## remove all dots (.), dash (-), º, /, etc.
|
46
|
-
name = strip_norm( name )
|
47
|
-
name = name.gsub( ' ', '' ) # note: also remove all spaces!!!
|
48
|
-
|
49
|
-
## todo/fix: use our own downcase - why? why not?
|
50
|
-
name = downcase_i18n( name ) ## do NOT care about upper and lowercase for now
|
51
|
-
name
|
52
|
-
end
|
53
34
|
end # class League
|
54
35
|
|
55
36
|
end # module Import
|
@@ -6,8 +6,24 @@ module SportDb
|
|
6
6
|
|
7
7
|
class Match
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
attr_reader :date,
|
10
|
+
:team1, :team2, ## todo/fix: use team1_name, team2_name or similar - for compat with db activerecord version? why? why not?
|
11
|
+
:score1, :score2, ## full time
|
12
|
+
:score1i, :score2i, ## half time (first (i) part)
|
13
|
+
:score1et, :score2et, ## extra time
|
14
|
+
:score1p, :score2p, ## penalty
|
15
|
+
:score1agg, :score2agg, ## full time (all legs) aggregated
|
16
|
+
:winner, # return 1,2,0 1 => team1, 2 => team2, 0 => draw/tie
|
17
|
+
:round, ## todo/fix: use round_num or similar - for compat with db activerecord version? why? why not?
|
18
|
+
:leg, ## e.g. '1','2','3','replay', etc. - use leg for marking **replay** too - keep/make leg numeric?! - why? why not?
|
19
|
+
:stage,
|
20
|
+
:group,
|
21
|
+
:conf1, :conf2, ## special case for mls e.g. conference1, conference2 (e.g. west, east, central)
|
22
|
+
:country1, :country2, ## special case for champions league etc. - uses FIFA country code
|
23
|
+
:comments
|
24
|
+
|
25
|
+
def initialize( **kwargs )
|
26
|
+
update( kwargs ) unless kwargs.empty?
|
11
27
|
end
|
12
28
|
|
13
29
|
def update( **kwargs )
|
@@ -31,32 +47,59 @@ class Match
|
|
31
47
|
@group = kwargs[:group] if kwargs.has_key? :group
|
32
48
|
@comments = kwargs[:comments] if kwargs.has_key? :comments
|
33
49
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
50
|
+
if kwargs.has_key?( :score ) ## check all-in-one score struct for convenience!!!
|
51
|
+
score = kwargs[:score]
|
52
|
+
if score.nil? ## reset all score attribs to nil!!
|
53
|
+
@score1 = nil
|
54
|
+
@score1i = nil
|
55
|
+
@score1et = nil
|
56
|
+
@score1p = nil
|
57
|
+
## @score1agg = nil
|
58
|
+
|
59
|
+
@score2 = nil
|
60
|
+
@score2i = nil
|
61
|
+
@score2et = nil
|
62
|
+
@score2p = nil
|
63
|
+
## @score2agg = nil
|
64
|
+
else
|
65
|
+
@score1 = score.score1
|
66
|
+
@score1i = score.score1i
|
67
|
+
@score1et = score.score1et
|
68
|
+
@score1p = score.score1p
|
69
|
+
## @score1agg = score.score1agg
|
70
|
+
|
71
|
+
@score2 = score.score2
|
72
|
+
@score2i = score.score2i
|
73
|
+
@score2et = score.score2et
|
74
|
+
@score2p = score.score2p
|
75
|
+
## @score2agg = score.score2agg
|
76
|
+
end
|
77
|
+
else
|
78
|
+
@score1 = kwargs[:score1] if kwargs.has_key? :score1
|
79
|
+
@score1i = kwargs[:score1i] if kwargs.has_key? :score1i
|
80
|
+
@score1et = kwargs[:score1et] if kwargs.has_key? :score1et
|
81
|
+
@score1p = kwargs[:score1p] if kwargs.has_key? :score1p
|
82
|
+
@score1agg = kwargs[:score1agg] if kwargs.has_key? :score1agg
|
83
|
+
|
84
|
+
@score2 = kwargs[:score2] if kwargs.has_key? :score2
|
85
|
+
@score2i = kwargs[:score2i] if kwargs.has_key? :score2i
|
86
|
+
@score2et = kwargs[:score2et] if kwargs.has_key? :score2et
|
87
|
+
@score2p = kwargs[:score2p] if kwargs.has_key? :score2p
|
88
|
+
@score2agg = kwargs[:score2agg] if kwargs.has_key? :score2agg
|
89
|
+
|
90
|
+
## note: (always) (auto-)convert scores to integers
|
91
|
+
@score1 = @score1.to_i if @score1
|
92
|
+
@score1i = @score1i.to_i if @score1i
|
93
|
+
@score1et = @score1et.to_i if @score1et
|
94
|
+
@score1p = @score1p.to_i if @score1p
|
95
|
+
@score1agg = @score1agg.to_i if @score1agg
|
96
|
+
|
97
|
+
@score2 = @score2.to_i if @score2
|
98
|
+
@score2i = @score2i.to_i if @score2i
|
99
|
+
@score2et = @score2et.to_i if @score2et
|
100
|
+
@score2p = @score2p.to_i if @score2p
|
101
|
+
@score2agg = @score2agg.to_i if @score2agg
|
102
|
+
end
|
60
103
|
|
61
104
|
## todo/fix:
|
62
105
|
## gr-greece/2014-15/G1.csv:
|
@@ -65,7 +108,7 @@ class Match
|
|
65
108
|
|
66
109
|
## for now score1 and score2 must be present
|
67
110
|
if @score1.nil? || @score2.nil?
|
68
|
-
puts "
|
111
|
+
puts "** WARN: missing scores for match:"
|
69
112
|
pp kwargs
|
70
113
|
## exit 1
|
71
114
|
end
|
@@ -90,28 +133,6 @@ class Match
|
|
90
133
|
end
|
91
134
|
|
92
135
|
|
93
|
-
attr_reader :date,
|
94
|
-
:team1, :team2, ## todo/fix: use team1_name, team2_name or similar - for compat with db activerecord version? why? why not?
|
95
|
-
:score1, :score2, ## full time
|
96
|
-
:score1i, :score2i, ## half time (first (i) part)
|
97
|
-
:score1et, :score2et, ## extra time
|
98
|
-
:score1p, :score2p, ## penalty
|
99
|
-
:score1agg, :score2agg, ## full time (all legs) aggregated
|
100
|
-
:winner, # return 1,2,0 1 => team1, 2 => team2, 0 => draw/tie
|
101
|
-
:round, ## todo/fix: use round_num or similar - for compat with db activerecord version? why? why not?
|
102
|
-
:leg, ## e.g. '1','2','3','replay', etc. - use leg for marking **replay** too - keep/make leg numeric?! - why? why not?
|
103
|
-
:stage,
|
104
|
-
:group,
|
105
|
-
:conf1, :conf2, ## special case for mls e.g. conference1, conference2 (e.g. west, east, central)
|
106
|
-
:country1, :country2, ## special case for champions league etc. - uses FIFA country code
|
107
|
-
:comments
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
def initialize( **kwargs )
|
112
|
-
update( kwargs ) unless kwargs.empty?
|
113
|
-
end
|
114
|
-
|
115
136
|
|
116
137
|
def over?() true; end ## for now all matches are over - in the future check date!!!
|
117
138
|
def complete?() true; end ## for now all scores are complete - in the future check scores; might be missing - not yet entered
|
@@ -2,7 +2,8 @@ module SportDb
|
|
2
2
|
module Import
|
3
3
|
|
4
4
|
class Round
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :title, :start_date, :end_date, :knockout
|
6
|
+
attr_accessor :pos # note: make read & writable
|
6
7
|
|
7
8
|
##
|
8
9
|
## todo: change db schema
|
@@ -11,9 +12,18 @@ module SportDb
|
|
11
12
|
## make pos/num optional too
|
12
13
|
##
|
13
14
|
## sort round by scheduled/planed start date
|
14
|
-
def initialize(
|
15
|
-
|
16
|
-
|
15
|
+
def initialize( title:,
|
16
|
+
pos: nil,
|
17
|
+
start_date: nil,
|
18
|
+
end_date: nil,
|
19
|
+
knockout: false,
|
20
|
+
auto: true )
|
21
|
+
@title = title
|
22
|
+
@pos = pos
|
23
|
+
@start_date = start_date
|
24
|
+
@end_date = end_date
|
25
|
+
@knockout = knockout
|
26
|
+
@auto = auto # auto-created (inline reference/header without proper definition before)
|
17
27
|
end
|
18
28
|
end # class Round
|
19
29
|
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module SportDb
|
4
|
+
module Import
|
5
|
+
|
6
|
+
|
7
|
+
##
|
8
|
+
## todo/fix: remove self.create in structs!!! use just new!!!
|
9
|
+
|
10
|
+
class Team
|
11
|
+
## todo: use just names for alt_names - why? why not?
|
12
|
+
attr_accessor :key, :name, :alt_names,
|
13
|
+
:code, ## code == abbreviation e.g. ARS etc.
|
14
|
+
:year, :year_end, ## todo/fix: change year_end to end_year (like in season)!!!
|
15
|
+
:country
|
16
|
+
|
17
|
+
alias_method :title, :name ## add alias/compat - why? why not
|
18
|
+
|
19
|
+
def names
|
20
|
+
## todo/check: add alt_names_auto too? - why? why not?
|
21
|
+
[@name] + @alt_names
|
22
|
+
end ## all names
|
23
|
+
|
24
|
+
## special import only attribs
|
25
|
+
attr_accessor :alt_names_auto ## auto-generated alt names
|
26
|
+
attr_accessor :wikipedia # wikipedia page name (for english (en))
|
27
|
+
|
28
|
+
|
29
|
+
def historic?() @year_end ? true : false; end
|
30
|
+
alias_method :past?, :historic?
|
31
|
+
|
32
|
+
def wikipedia?() @wikipedia; end
|
33
|
+
def wikipedia_url
|
34
|
+
if @wikipedia
|
35
|
+
## note: replace spaces with underscore (-)
|
36
|
+
## e.g. Club Brugge KV => Club_Brugge_KV
|
37
|
+
## todo/check/fix:
|
38
|
+
## check if "plain" dash (-) needs to get replaced with typographic dash??
|
39
|
+
"https://en.wikipedia.org/wiki/#{@wikipedia.gsub(' ','_')}"
|
40
|
+
else
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def initialize( **kwargs )
|
47
|
+
@alt_names = []
|
48
|
+
@alt_names_auto = []
|
49
|
+
|
50
|
+
update( kwargs ) unless kwargs.empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
def update( **kwargs )
|
54
|
+
@key = kwargs[:key] if kwargs.has_key? :key
|
55
|
+
@name = kwargs[:name] if kwargs.has_key? :name
|
56
|
+
@code = kwargs[:code] if kwargs.has_key? :code
|
57
|
+
@alt_names = kwargs[:alt_names] if kwargs.has_key? :alt_names
|
58
|
+
self ## note - MUST return self for chaining
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
## helper methods for import only
|
63
|
+
## check for duplicates
|
64
|
+
include NameHelper
|
65
|
+
|
66
|
+
def duplicates?
|
67
|
+
names = [name] + alt_names + alt_names_auto
|
68
|
+
names = names.map { |name| normalize( sanitize(name) ) }
|
69
|
+
|
70
|
+
names.size != names.uniq.size
|
71
|
+
end
|
72
|
+
|
73
|
+
def duplicates
|
74
|
+
names = [name] + alt_names + alt_names_auto
|
75
|
+
|
76
|
+
## calculate (count) frequency and select if greater than one
|
77
|
+
names.reduce( {} ) do |h,name|
|
78
|
+
norm = normalize( sanitize(name) )
|
79
|
+
h[norm] ||= []
|
80
|
+
h[norm] << name; h
|
81
|
+
end.select { |norm,names| names.size > 1 }
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def add_variants( name_or_names )
|
86
|
+
names = name_or_names.is_a?(Array) ? name_or_names : [name_or_names]
|
87
|
+
names.each do |name|
|
88
|
+
name = sanitize( name )
|
89
|
+
self.alt_names_auto += variants( name )
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end # class Team
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
class NationalTeam < Team
|
97
|
+
def initialize( **kwargs )
|
98
|
+
super
|
99
|
+
end
|
100
|
+
|
101
|
+
def update( **kwargs )
|
102
|
+
super
|
103
|
+
self ## note - MUST return self for chaining
|
104
|
+
end
|
105
|
+
|
106
|
+
end # class NationalTeam
|
107
|
+
|
108
|
+
|
109
|
+
########
|
110
|
+
# more attribs - todo/fix - also add "upstream" to struct & model!!!!!
|
111
|
+
# district, geos, year_end, country, etc.
|
112
|
+
|
113
|
+
class Club < Team
|
114
|
+
attr_accessor :ground
|
115
|
+
|
116
|
+
attr_accessor :a, :b
|
117
|
+
def a?() @a == nil; end ## is a (1st) team / club (i)? if a is NOT set
|
118
|
+
def b?() @a != nil; end ## is b (2nd/reserve/jr) team / club (ii) if a is set
|
119
|
+
|
120
|
+
## note: delegate/forward all geo attributes for team b for now (to team a) - keep - why? why not?
|
121
|
+
attr_writer :city, :district, :geos
|
122
|
+
def city() @a == nil ? @city : @a.city; end
|
123
|
+
def district() @a == nil ? @district : @a.district; end
|
124
|
+
def country() @a == nil ? @country : @a.country; end
|
125
|
+
def geos() @a == nil ? @geos : @a.geos; end
|
126
|
+
|
127
|
+
|
128
|
+
def initialize( **kwargs )
|
129
|
+
super
|
130
|
+
end
|
131
|
+
|
132
|
+
def update( **kwargs )
|
133
|
+
super
|
134
|
+
@city = kwargs[:city] if kwargs.has_key? :city
|
135
|
+
## todo/fix: use city struct - why? why not?
|
136
|
+
## todo/fix: add country too or report unused keywords / attributes - why? why not?
|
137
|
+
|
138
|
+
self ## note - MUST return self for chaining
|
139
|
+
end
|
140
|
+
end # class Club
|
141
|
+
|
142
|
+
|
143
|
+
end # module Import
|
144
|
+
end # module SportDb
|