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.
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