sportdb-formats 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +24 -4
  3. data/Rakefile +3 -3
  4. data/lib/sportdb/formats.rb +25 -2
  5. data/lib/sportdb/formats/config.rb +40 -0
  6. data/lib/sportdb/formats/datafile.rb +42 -62
  7. data/lib/sportdb/formats/datafile_package.rb +160 -0
  8. data/lib/sportdb/formats/match/conf_parser.rb +120 -0
  9. data/lib/sportdb/formats/match/mapper.rb +319 -0
  10. data/lib/sportdb/formats/match/mapper_teams.rb +23 -0
  11. data/lib/sportdb/formats/match/match_parser.rb +659 -0
  12. data/lib/sportdb/formats/match/match_parser_auto_conf.rb +202 -0
  13. data/lib/sportdb/formats/name_helper.rb +84 -0
  14. data/lib/sportdb/formats/outline_reader.rb +53 -15
  15. data/lib/sportdb/formats/package.rb +172 -160
  16. data/lib/sportdb/formats/parser_helper.rb +81 -0
  17. data/lib/sportdb/formats/score/score_formats.rb +180 -0
  18. data/lib/sportdb/formats/score/score_parser.rb +196 -0
  19. data/lib/sportdb/formats/structs/country.rb +1 -43
  20. data/lib/sportdb/formats/structs/group.rb +25 -0
  21. data/lib/sportdb/formats/structs/league.rb +7 -26
  22. data/lib/sportdb/formats/structs/match.rb +72 -51
  23. data/lib/sportdb/formats/structs/round.rb +14 -4
  24. data/lib/sportdb/formats/structs/season.rb +3 -0
  25. data/lib/sportdb/formats/structs/team.rb +144 -0
  26. data/lib/sportdb/formats/version.rb +2 -2
  27. data/test/helper.rb +83 -1
  28. data/test/test_clubs.rb +3 -3
  29. data/test/test_conf.rb +65 -0
  30. data/test/test_datafile.rb +21 -30
  31. data/test/test_match.rb +0 -6
  32. data/test/test_match_auto.rb +72 -0
  33. data/test/test_match_auto_champs.rb +45 -0
  34. data/test/test_match_auto_euro.rb +37 -0
  35. data/test/test_match_auto_worldcup.rb +61 -0
  36. data/test/test_match_champs.rb +27 -0
  37. data/test/test_match_eng.rb +26 -0
  38. data/test/test_match_euro.rb +27 -0
  39. data/test/test_match_worldcup.rb +27 -0
  40. data/test/test_name_helper.rb +67 -0
  41. data/test/test_outline_reader.rb +3 -3
  42. data/test/test_package.rb +21 -2
  43. data/test/test_package_match.rb +78 -0
  44. data/test/test_scores.rb +67 -51
  45. metadata +32 -12
  46. data/lib/sportdb/formats/scores.rb +0 -253
  47. data/lib/sportdb/formats/structs/club.rb +0 -213
  48. data/test/test_club_helpers.rb +0 -63
  49. 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 :key, :name, :fifa, :tags
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
- def self.create( **kwargs ) ## keep using create why? why not?
10
- new.update( kwargs )
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
- @score1 = kwargs[:score1] if kwargs.has_key? :score1
36
- @score1i = kwargs[:score1i] if kwargs.has_key? :score1i
37
- @score1et = kwargs[:score1et] if kwargs.has_key? :score1et
38
- @score1p = kwargs[:score1p] if kwargs.has_key? :score1p
39
- @score1agg = kwargs[:score1agg] if kwargs.has_key? :score1agg
40
-
41
- @score2 = kwargs[:score2] if kwargs.has_key? :score2
42
- @score2i = kwargs[:score2i] if kwargs.has_key? :score2i
43
- @score2et = kwargs[:score2et] if kwargs.has_key? :score2et
44
- @score2p = kwargs[:score2p] if kwargs.has_key? :score2p
45
- @score2agg = kwargs[:score2agg] if kwargs.has_key? :score2agg
46
-
47
- ## note: (always) (auto-)convert scores to integers
48
- @score1 = @score1.to_i if @score1
49
- @score1i = @score1i.to_i if @score1i
50
- @score1et = @score1et.to_i if @score1et
51
- @score1p = @score1p.to_i if @score1p
52
- @score1agg = @score1agg.to_i if @score1agg
53
-
54
- @score2 = @score2.to_i if @score2
55
- @score2i = @score2i.to_i if @score2i
56
- @score2et = @score2et.to_i if @score2et
57
- @score2p = @score2p.to_i if @score2p
58
- @score2agg = @score2agg.to_i if @score2agg
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 "*** missing scores for match:"
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 :pos, :title
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( pos:, title: )
15
- @pos = pos
16
- @title = title
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
 
@@ -87,6 +87,9 @@ class Season
87
87
  alias_method :to_key, :key
88
88
  alias_method :to_s, :key
89
89
 
90
+ alias_method :name, :key
91
+ alias_method :title, :key
92
+
90
93
 
91
94
  def path( format: nil )
92
95
  ## todo: find better names for formats - why? why not?:
@@ -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