sportdb-formats 1.1.3 → 1.1.4
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 +0 -24
- data/Rakefile +2 -5
- data/lib/sportdb/formats.rb +39 -74
- data/lib/sportdb/formats/event/event_reader.rb +1 -1
- data/lib/sportdb/formats/league/league_outline_reader.rb +18 -6
- data/lib/sportdb/formats/package.rb +2 -2
- data/lib/sportdb/formats/team/club_index_history.rb +2 -6
- data/lib/sportdb/formats/team/club_reader_history.rb +1 -1
- data/lib/sportdb/formats/team/club_reader_props.rb +18 -2
- data/lib/sportdb/formats/version.rb +1 -1
- data/test/helper.rb +3 -0
- metadata +5 -71
- data/lib/sportdb/formats/config.rb +0 -40
- data/lib/sportdb/formats/match/match_parser_csv.rb +0 -458
- data/lib/sportdb/formats/match/match_status_parser.rb +0 -86
- data/lib/sportdb/formats/name_helper.rb +0 -87
- data/lib/sportdb/formats/score/score_formats.rb +0 -239
- data/lib/sportdb/formats/score/score_parser.rb +0 -204
- data/lib/sportdb/formats/season_utils.rb +0 -16
- data/lib/sportdb/formats/structs/country.rb +0 -31
- data/lib/sportdb/formats/structs/group.rb +0 -18
- data/lib/sportdb/formats/structs/league.rb +0 -37
- data/lib/sportdb/formats/structs/match.rb +0 -157
- data/lib/sportdb/formats/structs/matchlist.rb +0 -220
- data/lib/sportdb/formats/structs/round.rb +0 -25
- data/lib/sportdb/formats/structs/season.rb +0 -192
- data/lib/sportdb/formats/structs/standings.rb +0 -268
- data/lib/sportdb/formats/structs/team.rb +0 -157
- data/lib/sportdb/formats/structs/team_usage.rb +0 -88
- data/test/test_clubs.rb +0 -40
- data/test/test_csv_reader.rb +0 -31
- data/test/test_match.rb +0 -30
- data/test/test_match_status_parser.rb +0 -49
- data/test/test_name_helper.rb +0 -67
- data/test/test_scores.rb +0 -124
- data/test/test_season.rb +0 -111
@@ -1,25 +0,0 @@
|
|
1
|
-
module SportDb
|
2
|
-
module Import
|
3
|
-
|
4
|
-
class Round
|
5
|
-
attr_reader :name, :start_date, :end_date, :knockout
|
6
|
-
attr_accessor :num # note: make read & writable - why? why not?
|
7
|
-
|
8
|
-
def initialize( name:,
|
9
|
-
num: nil,
|
10
|
-
start_date: nil,
|
11
|
-
end_date: nil,
|
12
|
-
knockout: false,
|
13
|
-
auto: true )
|
14
|
-
@name = name
|
15
|
-
@num = num
|
16
|
-
@start_date = start_date
|
17
|
-
@end_date = end_date
|
18
|
-
@knockout = knockout
|
19
|
-
@auto = auto # auto-created (inline reference/header without proper definition before)
|
20
|
-
end
|
21
|
-
end # class Round
|
22
|
-
|
23
|
-
end # module Import
|
24
|
-
end # module SportDb
|
25
|
-
|
@@ -1,192 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
|
4
|
-
### note: make Season like Date a "top-level" / "generic" class
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
class Season
|
9
|
-
##
|
10
|
-
## todo: add (optional) start_date and end_date - why? why not?
|
11
|
-
|
12
|
-
## todo/todo/todo/check/check/check !!!
|
13
|
-
## todo: add a kernel Seaons e.g. Season('2011/12')
|
14
|
-
## forward to Season.convert( *args ) - why? why not?
|
15
|
-
|
16
|
-
## todo: add unicode - too - why? why not? see wikipedia pages, for example
|
17
|
-
|
18
|
-
YYYY_YYYY_RE = %r{^ ## e.g. 2011-2012 or 2011/2012
|
19
|
-
(\d{4})
|
20
|
-
[/-]
|
21
|
-
(\d{4})
|
22
|
-
$
|
23
|
-
}x
|
24
|
-
YYYY_YY_RE = %r{^ ## e.g. 2011-12 or 2011/12
|
25
|
-
(\d{4})
|
26
|
-
[/-]
|
27
|
-
(\d{2})
|
28
|
-
$
|
29
|
-
}x
|
30
|
-
YYYY_Y_RE = %r{^ ## e.g. 2011-2 or 2011/2
|
31
|
-
(\d{4})
|
32
|
-
[/-]
|
33
|
-
(\d{1})
|
34
|
-
$
|
35
|
-
}x
|
36
|
-
YYYY_RE = %r{^ ## e.g. 2011
|
37
|
-
(\d{4})
|
38
|
-
$
|
39
|
-
}x
|
40
|
-
|
41
|
-
|
42
|
-
def self.parse( str )
|
43
|
-
new( *_parse( str ))
|
44
|
-
end
|
45
|
-
|
46
|
-
def self._parse( str ) ## "internal" parse helper
|
47
|
-
if str =~ YYYY_YYYY_RE ## e.g. 2011/2012
|
48
|
-
[$1.to_i, $2.to_i]
|
49
|
-
elsif str =~ YYYY_YY_RE ## e.g. 2011/12
|
50
|
-
fst = $1.to_i
|
51
|
-
snd = $2.to_i
|
52
|
-
snd_exp = '%02d' % [(fst+1) % 100] ## double check: e.g 00 == 00, 01==01 etc.
|
53
|
-
raise ArgumentError, "[Season.parse] invalid year in season >>#{str}<<; expected #{snd_exp} but got #{$2}" if snd_exp != $2
|
54
|
-
[fst, fst+1]
|
55
|
-
elsif str =~ YYYY_Y_RE ## e.g. 2011/2
|
56
|
-
fst = $1.to_i
|
57
|
-
snd = $2.to_i
|
58
|
-
snd_exp = '%d' % [(fst+1) % 10] ## double check: e.g 0 == 0, 1==1 etc.
|
59
|
-
raise ArgumentError, "[Season.parse] invalid year in season >>#{str}<<; expected #{snd_exp} but got #{$2}" if snd_exp != $2
|
60
|
-
[fst, fst+1]
|
61
|
-
elsif str =~ YYYY_RE ## e.g. 2011
|
62
|
-
[$1.to_i]
|
63
|
-
else
|
64
|
-
raise ArgumentError, "[Season.parse] unkown season format >>#{str}<<; sorry cannot parse"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
attr_reader :start_year,
|
71
|
-
:end_year
|
72
|
-
|
73
|
-
def initialize( *args ) ## assume only string / line gets passed in for now
|
74
|
-
if args.size == 1 && args[0].is_a?( String )
|
75
|
-
@start_year, @end_year = self.class._parse( args[0] )
|
76
|
-
elsif args.size == 1 && args[0].is_a?( Integer )
|
77
|
-
@start_year = args[0]
|
78
|
-
@end_year = nil
|
79
|
-
elsif args.size == 2 && args[0].is_a?( Integer ) &&
|
80
|
-
args[1].is_a?( Integer )
|
81
|
-
@start_year = args[0]
|
82
|
-
@end_year = args[1]
|
83
|
-
end_year_exp = @start_year+1
|
84
|
-
raise ArgumentError, "[Season] invalid year in season >>#{to_s}<<; expected #{end_year_exp} but got #{@end_year}" if end_year_exp != @end_year
|
85
|
-
else
|
86
|
-
pp args
|
87
|
-
raise ArgumentError, "[Season] expected season string or season start year (integer) with opt. end year"
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
|
92
|
-
###
|
93
|
-
## convenience helper
|
94
|
-
def start_date ## generate "generic / syntetic start date" - keep helper - why? why not?
|
95
|
-
if year?
|
96
|
-
Date.new( start_year, 1, 1 )
|
97
|
-
else
|
98
|
-
Date.new( start_year 1, 7 )
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
|
103
|
-
## single-year season e.g. 2011 if no end_year present - todo - find a better name?
|
104
|
-
def year?() @end_year.nil?; end
|
105
|
-
|
106
|
-
def prev
|
107
|
-
if year?
|
108
|
-
Season.new( @start_year-1 )
|
109
|
-
else
|
110
|
-
Season.new( @start_year-1, @start_year )
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def next
|
115
|
-
if year?
|
116
|
-
Season.new( @start_year+1 )
|
117
|
-
else
|
118
|
-
Season.new( @end_year, @end_year+1 )
|
119
|
-
end
|
120
|
-
end
|
121
|
-
alias_method :succ, :next ## add support for ranges
|
122
|
-
|
123
|
-
include Comparable
|
124
|
-
def <=>(other)
|
125
|
-
## todo/fix/fix: check if other is_a?( Season )!!!
|
126
|
-
## what to return if other type/class ??
|
127
|
-
|
128
|
-
res = @start_year <=> other.start_year
|
129
|
-
|
130
|
-
## check special edge case - year season and other e.g.
|
131
|
-
## 2010 <=> 2010/2011
|
132
|
-
if res == 0 && @end_year != other.end_year
|
133
|
-
res = @end_year ? 1 : -1 # the season with an end year is greater / wins for now
|
134
|
-
end
|
135
|
-
|
136
|
-
res
|
137
|
-
end
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
def to_formatted_s( format=:default, sep: '/' )
|
142
|
-
if year?
|
143
|
-
'%d' % @start_year
|
144
|
-
else
|
145
|
-
case format
|
146
|
-
when :default, :short, :s ## e.g. 1999/00 or 2019/20
|
147
|
-
"%d#{sep}%02d" % [@start_year, @end_year % 100]
|
148
|
-
when :long, :l ## e.g. 1999/2000 or 2019/2020
|
149
|
-
"%d#{sep}%d" % [@start_year, @end_year]
|
150
|
-
else
|
151
|
-
raise ArgumentError, "[Season.to_s] unsupported format >#{format}<"
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
alias_method :to_s, :to_formatted_s
|
156
|
-
|
157
|
-
def key() to_s( :short ); end
|
158
|
-
alias_method :to_key, :key
|
159
|
-
alias_method :name, :key
|
160
|
-
alias_method :title, :key
|
161
|
-
|
162
|
-
alias_method :inspect, :key ## note: add inspect debug support change debug output to string!!
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
def to_path( format=:default )
|
167
|
-
case format
|
168
|
-
when :default, :short, :s ## e.g. 1999-00 or 2019-20
|
169
|
-
to_s( :short, sep: '-' )
|
170
|
-
when :long, :l ## e.g. 1999-2000 or 2019-2000
|
171
|
-
to_s( :long, sep: '-' )
|
172
|
-
when :archive, :decade, :d ## e.g. 1990s/1999-00 or 2010s/2019-20
|
173
|
-
"%3d0s/%s" % [@start_year / 10, to_s( :short, sep: '-' )]
|
174
|
-
when :century, :c ## e.g. 1900s/1990-00 or 2000s/2019-20
|
175
|
-
"%2d00s/%s" % [@start_year / 100, to_s( :short, sep: '-' )]
|
176
|
-
else
|
177
|
-
raise ArgumentError, "[Season.to_path] unsupported format >#{format}<"
|
178
|
-
end
|
179
|
-
end # method to_path
|
180
|
-
alias_method :directory, :to_path ## keep "legacy" directory alias - why? why not?
|
181
|
-
alias_method :path, :to_path
|
182
|
-
|
183
|
-
end # class Season
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
module SportDb
|
189
|
-
module Import
|
190
|
-
Season = ::Season ## add a convenience alias
|
191
|
-
end # module Import
|
192
|
-
end # module SportDb
|
@@ -1,268 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
##########
|
4
|
-
# todo/fix:
|
5
|
-
## reuse standings helper/calculator from sportdb
|
6
|
-
## do NOT duplicate
|
7
|
-
|
8
|
-
|
9
|
-
module SportDb
|
10
|
-
module Import
|
11
|
-
|
12
|
-
|
13
|
-
class Standings
|
14
|
-
|
15
|
-
class StandingsLine ## nested class StandinsLine - todo/fix: change to Line - why? why not?
|
16
|
-
attr_accessor :rank, :team,
|
17
|
-
:played, :won, :lost, :drawn, ## -- total
|
18
|
-
:goals_for, :goals_against, :pts,
|
19
|
-
:home_played, :home_won, :home_lost, :home_drawn, ## -- home
|
20
|
-
:home_goals_for, :home_goals_against, :home_pts,
|
21
|
-
:away_played, :away_won, :away_lost, :away_drawn, ## -- away
|
22
|
-
:away_goals_for, :away_goals_against, :away_pts
|
23
|
-
|
24
|
-
alias_method :team_name, :team ## note: team for now always a string
|
25
|
-
alias_method :pos, :rank ## rename back to use pos instead of rank - why? why not?
|
26
|
-
|
27
|
-
|
28
|
-
def initialize( team )
|
29
|
-
@rank = nil # use 0? why? why not?
|
30
|
-
## change rank back to pos - why? why not?
|
31
|
-
@team = team
|
32
|
-
@played = @home_played = @away_played = 0
|
33
|
-
@won = @home_won = @away_won = 0
|
34
|
-
@lost = @home_lost = @away_lost = 0
|
35
|
-
@drawn = @home_drawn = @away_drawn = 0
|
36
|
-
@goals_for = @home_goals_for = @away_goals_for = 0
|
37
|
-
@goals_against = @home_goals_against = @away_goals_against = 0
|
38
|
-
@pts = @home_pts = @away_pts = 0
|
39
|
-
end
|
40
|
-
end # (nested) class StandingsLine
|
41
|
-
|
42
|
-
|
43
|
-
def initialize( opts={} )
|
44
|
-
## fix:
|
45
|
-
# passing in e.g. pts for win (3? 2? etc.)
|
46
|
-
# default to 3 for now
|
47
|
-
|
48
|
-
## lets you pass in 2 as an alterantive, for example
|
49
|
-
@pts_won = opts[:pts_won] || 3
|
50
|
-
|
51
|
-
@lines = {} # StandingsLines cached by team name/key
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
def update( match_or_matches )
|
56
|
-
## convenience - update all matches at once
|
57
|
-
## todo/check: check for ActiveRecord_Associations_CollectionProxy and than use to_a (to "force" array) - why? why not?
|
58
|
-
matches = if match_or_matches.is_a?(Array)
|
59
|
-
match_or_matches
|
60
|
-
else
|
61
|
-
[match_or_matches]
|
62
|
-
end
|
63
|
-
|
64
|
-
matches.each_with_index do |match,i| # note: index(i) starts w/ zero (0)
|
65
|
-
update_match( match )
|
66
|
-
end
|
67
|
-
self # note: return self to allow chaining
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
def to_a
|
72
|
-
## return lines; sort and add rank
|
73
|
-
## note: will update rank!!!! (side effect)
|
74
|
-
|
75
|
-
#############################
|
76
|
-
### calc ranking position (rank)
|
77
|
-
## fix/allow same rank e.g. all 1 or more than one team 3rd etc.
|
78
|
-
|
79
|
-
# build array from hash
|
80
|
-
ary = []
|
81
|
-
@lines.each do |k,v|
|
82
|
-
ary << v
|
83
|
-
end
|
84
|
-
|
85
|
-
ary.sort! do |l,r|
|
86
|
-
## note: reverse order (thus, change l,r to r,l)
|
87
|
-
value = r.pts <=> l.pts
|
88
|
-
if value == 0 # same pts try goal diff
|
89
|
-
value = (r.goals_for-r.goals_against) <=> (l.goals_for-l.goals_against)
|
90
|
-
if value == 0 # same goal diff too; try assume more goals better for now
|
91
|
-
value = r.goals_for <=> l.goals_for
|
92
|
-
end
|
93
|
-
end
|
94
|
-
value
|
95
|
-
end
|
96
|
-
|
97
|
-
## update rank using ordered array
|
98
|
-
ary.each_with_index do |line,i|
|
99
|
-
line.rank = i+1 ## add ranking (e.g. 1,2,3 etc.) - note: i starts w/ zero (0)
|
100
|
-
end
|
101
|
-
|
102
|
-
ary
|
103
|
-
end # to_a
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
#####
|
108
|
-
###
|
109
|
-
## fix: move build to StandingsPart/Report !!!!
|
110
|
-
def build( source: nil ) ## build / pretty print standings table in string buffer
|
111
|
-
## keep pretty printer in struct - why? why not?
|
112
|
-
|
113
|
-
|
114
|
-
## add standings table in markdown to buffer (buf)
|
115
|
-
|
116
|
-
## todo: use different styles/formats (simple/ etc ???)
|
117
|
-
|
118
|
-
## simple table (only totals - no home/away)
|
119
|
-
## standings.to_a.each do |l|
|
120
|
-
## buf << '%2d. ' % l.rank
|
121
|
-
## buf << '%-28s ' % l.team
|
122
|
-
## buf << '%2d ' % l.played
|
123
|
-
## buf << '%3d ' % l.won
|
124
|
-
## buf << '%3d ' % l.drawn
|
125
|
-
## buf << '%3d ' % l.lost
|
126
|
-
## buf << '%3d:%-3d ' % [l.goals_for,l.goals_against]
|
127
|
-
## buf << '%3d' % l.pts
|
128
|
-
## buf << "\n"
|
129
|
-
## end
|
130
|
-
|
131
|
-
buf = ''
|
132
|
-
buf << "\n"
|
133
|
-
buf << "```\n"
|
134
|
-
buf << " - Home - - Away - - Total -\n"
|
135
|
-
buf << " Pld W D L F:A W D L F:A F:A +/- Pts\n"
|
136
|
-
|
137
|
-
to_a.each do |l|
|
138
|
-
buf << '%2d. ' % l.rank
|
139
|
-
buf << '%-28s ' % l.team
|
140
|
-
buf << '%2d ' % l.played
|
141
|
-
|
142
|
-
buf << '%2d ' % l.home_won
|
143
|
-
buf << '%2d ' % l.home_drawn
|
144
|
-
buf << '%2d ' % l.home_lost
|
145
|
-
buf << '%3d:%-3d ' % [l.home_goals_for,l.home_goals_against]
|
146
|
-
|
147
|
-
buf << '%2d ' % l.away_won
|
148
|
-
buf << '%2d ' % l.away_drawn
|
149
|
-
buf << '%2d ' % l.away_lost
|
150
|
-
buf << '%3d:%-3d ' % [l.away_goals_for,l.away_goals_against]
|
151
|
-
|
152
|
-
buf << '%3d:%-3d ' % [l.goals_for,l.goals_against]
|
153
|
-
|
154
|
-
goals_diff = l.goals_for-l.goals_against
|
155
|
-
if goals_diff > 0
|
156
|
-
buf << '%3s ' % "+#{goals_diff}"
|
157
|
-
elsif goals_diff < 0
|
158
|
-
buf << '%3s ' % "#{goals_diff}"
|
159
|
-
else ## assume 0
|
160
|
-
buf << ' '
|
161
|
-
end
|
162
|
-
|
163
|
-
buf << '%3d' % l.pts
|
164
|
-
buf << "\n"
|
165
|
-
end
|
166
|
-
|
167
|
-
buf << "```\n"
|
168
|
-
buf << "\n"
|
169
|
-
|
170
|
-
## optinal: add data source if known / present
|
171
|
-
## assume (relative) markdown link for now in README.md
|
172
|
-
if source
|
173
|
-
buf << "(Source: [`#{source}`](#{source}))\n"
|
174
|
-
buf << "\n"
|
175
|
-
end
|
176
|
-
|
177
|
-
buf
|
178
|
-
end
|
179
|
-
|
180
|
-
|
181
|
-
private
|
182
|
-
def update_match( m ) ## add a match
|
183
|
-
|
184
|
-
## note: always use team as string for now
|
185
|
-
## for now allow passing in of string OR struct - why? why not?
|
186
|
-
## todo/fix: change to m.team1_name and m.team2_name - why? why not?
|
187
|
-
team1 = m.team1.is_a?( String ) ? m.team1 : m.team1.name
|
188
|
-
team2 = m.team2.is_a?( String ) ? m.team2 : m.team2.name
|
189
|
-
|
190
|
-
score = m.score_str
|
191
|
-
|
192
|
-
## puts " #{team1} - #{team2} #{score}"
|
193
|
-
|
194
|
-
unless m.over?
|
195
|
-
puts " !!!! skipping match - not yet over (date in the future) => #{m.date}"
|
196
|
-
return
|
197
|
-
end
|
198
|
-
|
199
|
-
unless m.complete?
|
200
|
-
puts "!!! [calc_standings] skipping match #{team1} - #{team2} w/ past date #{m.date} - scores incomplete => #{score}"
|
201
|
-
return
|
202
|
-
end
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
line1 = @lines[ team1 ] || StandingsLine.new( team1 )
|
207
|
-
line2 = @lines[ team2 ] || StandingsLine.new( team2 )
|
208
|
-
|
209
|
-
line1.played += 1
|
210
|
-
line1.home_played += 1
|
211
|
-
|
212
|
-
line2.played += 1
|
213
|
-
line2.away_played += 1
|
214
|
-
|
215
|
-
if m.winner == 1
|
216
|
-
line1.won += 1
|
217
|
-
line1.home_won += 1
|
218
|
-
|
219
|
-
line2.lost += 1
|
220
|
-
line2.away_lost += 1
|
221
|
-
|
222
|
-
line1.pts += @pts_won
|
223
|
-
line1.home_pts += @pts_won
|
224
|
-
elsif m.winner == 2
|
225
|
-
line1.lost += 1
|
226
|
-
line1.home_lost += 1
|
227
|
-
|
228
|
-
line2.won += 1
|
229
|
-
line2.away_won += 1
|
230
|
-
|
231
|
-
line2.pts += @pts_won
|
232
|
-
line2.away_pts += @pts_won
|
233
|
-
else ## assume drawn/tie (that is, 0)
|
234
|
-
line1.drawn += 1
|
235
|
-
line1.home_drawn += 1
|
236
|
-
|
237
|
-
line2.drawn += 1
|
238
|
-
line2.away_drawn += 1
|
239
|
-
|
240
|
-
line1.pts += 1
|
241
|
-
line1.home_pts += 1
|
242
|
-
line2.pts += 1
|
243
|
-
line2.away_pts += 1
|
244
|
-
end
|
245
|
-
|
246
|
-
if m.score1 && m.score2
|
247
|
-
line1.goals_for += m.score1
|
248
|
-
line1.home_goals_for += m.score1
|
249
|
-
line1.goals_against += m.score2
|
250
|
-
line1.home_goals_against += m.score2
|
251
|
-
|
252
|
-
line2.goals_for += m.score2
|
253
|
-
line2.away_goals_for += m.score2
|
254
|
-
line2.goals_against += m.score1
|
255
|
-
line2.away_goals_against += m.score1
|
256
|
-
else
|
257
|
-
puts "*** warn: [standings] skipping match with missing scores: #{m.inspect}"
|
258
|
-
end
|
259
|
-
|
260
|
-
@lines[ team1 ] = line1
|
261
|
-
@lines[ team2 ] = line2
|
262
|
-
end # method update_match
|
263
|
-
|
264
|
-
end # class Standings
|
265
|
-
|
266
|
-
|
267
|
-
end # module Import
|
268
|
-
end # module SportDb
|