basketball 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +88 -13
- data/basketball.gemspec +1 -1
- data/exe/basketball-schedule +7 -0
- data/lib/basketball/drafting/cli.rb +2 -2
- data/lib/basketball/drafting/engine.rb +5 -8
- data/lib/basketball/drafting/engine_serializer.rb +1 -2
- data/lib/basketball/drafting/event.rb +4 -4
- data/lib/basketball/drafting/league.rb +0 -1
- data/lib/basketball/drafting/pick_event.rb +3 -3
- data/lib/basketball/drafting/roster.rb +0 -1
- data/lib/basketball/drafting/sim_event.rb +3 -3
- data/lib/basketball/drafting.rb +6 -0
- data/lib/basketball/scheduling/calendar.rb +121 -0
- data/lib/basketball/scheduling/calendar_serializer.rb +84 -0
- data/lib/basketball/scheduling/cli.rb +198 -0
- data/lib/basketball/scheduling/conference.rb +57 -0
- data/lib/basketball/scheduling/coordinator.rb +180 -0
- data/lib/basketball/scheduling/division.rb +43 -0
- data/lib/basketball/scheduling/game.rb +32 -0
- data/lib/basketball/scheduling/league.rb +114 -0
- data/lib/basketball/scheduling/league_serializer.rb +90 -0
- data/lib/basketball/scheduling/preseason_game.rb +11 -0
- data/lib/basketball/scheduling/season_game.rb +8 -0
- data/lib/basketball/scheduling/team.rb +21 -0
- data/lib/basketball/scheduling.rb +17 -0
- data/lib/basketball/value_object.rb +16 -7
- data/lib/basketball/version.rb +1 -1
- data/lib/basketball.rb +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 262751c76037e2859937529aa23bdd456fd77779a090ed4e844830c428b09e75
|
4
|
+
data.tar.gz: 1a904f317fc3c1becfc381155a089d2ed0b041b60d358c1325459a363e6ce0ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 913504954c8c053fac3147468433d12b02ad5d6a7badc563587668c4d3943b898c49c951d69c393affc5f5e07d54257a5a004184e55a73f435af01344afa6baf
|
7
|
+
data.tar.gz: 791e48aa9711e33e29b994d0e811a735def017de757bc02c8f348b57f2ce0a42c1e5fbbd6737ed2525ddd9fbf3698c9fb77be991208a1b927e4b27063a2b9f04
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
#### 0.0.6 - May 11th, 2023
|
2
|
+
|
3
|
+
* Added Scheduling module that can generate full schedules for entire league.
|
4
|
+
* Drafting::Event does not have identity anymore (no current tangible benefit).
|
5
|
+
|
1
6
|
#### 0.0.5 - May 5th, 2023
|
2
7
|
|
3
8
|
* Remove the notion of Team in favor of a flat front office.
|
data/README.md
CHANGED
@@ -30,13 +30,13 @@ bundle binstubs basketball
|
|
30
30
|
|
31
31
|
This library is broken down into several bounded contexts that can be consumed either via its Ruby API's or CLI through provided executable scripts:
|
32
32
|
|
33
|
-
![Basketball Architecture - Overview
|
33
|
+
![Basketball Architecture - Overview](/docs/architecture/overview.png)
|
34
34
|
|
35
35
|
## Drafting Module
|
36
36
|
|
37
37
|
The drafting module is responsible for providing a turn-based iterator allowing the consumer to either manually pick or simulate picks. Here is a cartoon showing the major components:
|
38
38
|
|
39
|
-
![Basketball Architecture - Drafting
|
39
|
+
![Basketball Architecture - Drafting](/docs/architecture/drafting.png)
|
40
40
|
|
41
41
|
Element | Description
|
42
42
|
:------------ | :-----------
|
@@ -47,7 +47,7 @@ Element | Description
|
|
47
47
|
**Front Office** | Identifiable as a team, contains configuration for how to auto-pick draft selections.
|
48
48
|
**League** | Set of rosters that together form a cohesive league.
|
49
49
|
**Pick Event** | Result event emitted when a player is manually selected.
|
50
|
-
**
|
50
|
+
**Player** | Identitiable as a person able to be drafted.
|
51
51
|
**Position** | Value object based on position code: PG, SG, SF, PF, and C.
|
52
52
|
**Roster** | Identifiable as a team, set of players that make up a single team.
|
53
53
|
**Sim Event** | Result event emitted when a player is automatically selected by a front office.
|
@@ -55,62 +55,137 @@ Element | Description
|
|
55
55
|
|
56
56
|
### The Drafting CLI
|
57
57
|
|
58
|
-
The drafting module is meant to be
|
58
|
+
The drafting module is meant to be interfaced with using its Ruby API by consuming applications. It also ships with a CLI which a user can interact with to emulate "the draft process". Technically speaking, the CLI provides an example application built on top of the Drafting module. Each time a CLI command is executed, its results will be resaved, so the output file can then be used as the next command's input file to string together commands. The following sections are example CLI interactions:
|
59
59
|
|
60
|
-
|
60
|
+
##### Generate a Fresh Draft
|
61
61
|
|
62
62
|
```zsh
|
63
63
|
basketball-draft -o tmp/draft.json
|
64
64
|
```
|
65
65
|
|
66
|
-
|
66
|
+
##### N Top Available Players
|
67
67
|
|
68
68
|
```zsh
|
69
69
|
basketball-draft -i tmp/draft.json -t 10
|
70
70
|
```
|
71
71
|
|
72
|
-
|
72
|
+
##### N Top Available Players for a Position
|
73
73
|
|
74
74
|
```zsh
|
75
75
|
basketball-draft -i tmp/draft.json -t 10 -q PG
|
76
76
|
```
|
77
77
|
|
78
|
-
|
78
|
+
##### Output Current Rosters
|
79
79
|
|
80
80
|
```zsh
|
81
81
|
basketball-draft -i tmp/draft.json -r
|
82
82
|
```
|
83
83
|
|
84
|
-
|
84
|
+
##### Output Event Log
|
85
85
|
|
86
86
|
```zsh
|
87
87
|
basketball-draft -i tmp/draft.json -l
|
88
88
|
```
|
89
89
|
|
90
|
-
|
90
|
+
##### Simulate N Picks
|
91
91
|
|
92
92
|
```zsh
|
93
93
|
basketball-draft -i tmp/draft.json -s 10
|
94
94
|
```
|
95
95
|
|
96
|
-
|
96
|
+
##### Skip N Picks
|
97
97
|
|
98
98
|
```zsh
|
99
99
|
basketball-draft -i tmp/draft.json -x 10
|
100
100
|
```
|
101
101
|
|
102
|
-
|
102
|
+
##### Pick Players
|
103
103
|
|
104
104
|
```zsh
|
105
105
|
basketball-draft -i tmp/draft.json -p P-100,P-200,P-300
|
106
106
|
```
|
107
107
|
|
108
|
-
|
108
|
+
##### Simulate the Rest of the Draft
|
109
109
|
|
110
110
|
```zsh
|
111
111
|
basketball-draft -i tmp/draft.json -a
|
112
112
|
```
|
113
113
|
|
114
|
+
##### Help Menu
|
115
|
+
|
116
|
+
```zsh
|
117
|
+
basketball-draft -h
|
118
|
+
```
|
119
|
+
|
120
|
+
## Scheduling Module
|
121
|
+
|
122
|
+
The Scheduling module is meant to take a League (conferences/divisions/teams) and turn it into a Calendar. This Calendar creation is atomic - the full calendar will be generated completely all in one call. Here is a cartoon showing the major components:
|
123
|
+
|
124
|
+
![Basketball Architecture - Scheduling](/docs/architecture/scheduling.png)
|
125
|
+
|
126
|
+
Element | Description
|
127
|
+
:------------ | :-----------
|
128
|
+
**Away Team** | Team object designated as the away team for a Game.
|
129
|
+
**Calendar Serializer** | Understands how to serialize and deserialize a Calendar object.
|
130
|
+
**Calendar** | Hold a calendar for a year season. Pass in a year and the Calendar will know how to mark important boundary dates (preseason start, preseason end, season start, and season end) and it knows how to ensure Calendar correctness regarding dates.
|
131
|
+
**Conference** | Describes a conference in terms of structure; composed of an array of divisions (there can only 3).
|
132
|
+
**Coordinator** | Service which can generate a Calendar from a League.
|
133
|
+
**Division** | Describes a division in terms of structure; composed of an array of teams (there can only 5).
|
134
|
+
**Game** | Matches up a date with two teams (home and away) to represent a scheduled matchup.
|
135
|
+
**Home Team** | Team object designated as the home team for a Game.
|
136
|
+
**League Serializer** | Understands how to serialize and deserialize a League object.
|
137
|
+
**League** | Describes a league in terms of structure; composed of an array conferences (there can only be 2).
|
138
|
+
**Scheduling** | Bounded context (sub-module) dealing with matchup and calendar generation.
|
139
|
+
**Team** | Identified by an ID and described by a name: represents a basketball team that can be scheduled.
|
140
|
+
|
141
|
+
##### Generate League
|
142
|
+
|
143
|
+
```zsh
|
144
|
+
basketball-schedule -o tmp/league.json
|
145
|
+
```
|
146
|
+
|
147
|
+
##### Generate Calendar From League
|
148
|
+
|
149
|
+
```zsh
|
150
|
+
basketball-schedule -i tmp/league.json -o tmp/calendar.json
|
151
|
+
```
|
152
|
+
|
153
|
+
##### Generate Calendar From League For a Specific Year
|
154
|
+
|
155
|
+
```zsh
|
156
|
+
basketball-schedule -i tmp/league.json -o tmp/calendar.json -y 2005
|
157
|
+
```
|
158
|
+
|
159
|
+
##### Output a Generated Calendar's Matchups
|
160
|
+
|
161
|
+
```zsh
|
162
|
+
basketball-schedule -c tmp/calendar.json
|
163
|
+
```
|
164
|
+
|
165
|
+
##### Output a Generated Calendar's Matchups For a Specific Team
|
166
|
+
|
167
|
+
```zsh
|
168
|
+
basketball-schedule -c tmp/calendar.json -t C0-D0-T0
|
169
|
+
```
|
170
|
+
|
171
|
+
##### Output a Generated Calendar's Matchups For a Specific Date
|
172
|
+
|
173
|
+
```zsh
|
174
|
+
basketball-schedule -c tmp/calendar.json -d 2005-02-03
|
175
|
+
```
|
176
|
+
|
177
|
+
##### Output a Generated Calendar's Matchups For a Specific Team and Date
|
178
|
+
|
179
|
+
```zsh
|
180
|
+
basketball-schedule -c tmp/calendar.json -d 2005-02-03 -t C0-D0-T0
|
181
|
+
```
|
182
|
+
|
183
|
+
##### Help Menu
|
184
|
+
|
185
|
+
```zsh
|
186
|
+
basketball-schedule -h
|
187
|
+
```
|
188
|
+
|
114
189
|
## Contributing
|
115
190
|
|
116
191
|
### Development Environment Configuration
|
data/basketball.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.email = ['mattruggio@icloud.com']
|
18
18
|
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(.github|bin|docs|spec)/}) }
|
19
19
|
s.bindir = 'exe'
|
20
|
-
s.executables = %w[basketball-draft]
|
20
|
+
s.executables = %w[basketball-draft basketball-schedule]
|
21
21
|
s.homepage = 'https://github.com/mattruggio/basketball'
|
22
22
|
s.license = 'MIT'
|
23
23
|
s.metadata = {
|
@@ -7,7 +7,7 @@ require_relative 'position'
|
|
7
7
|
|
8
8
|
module Basketball
|
9
9
|
module Drafting
|
10
|
-
#
|
10
|
+
# Examples:
|
11
11
|
# exe/basketball-draft -o tmp/draft.json
|
12
12
|
# exe/basketball-draft -i tmp/draft.json -o tmp/draft-wip.json -s 26 -p P-5,P-10 -t 10 -q PG
|
13
13
|
# exe/basketball-draft -i tmp/draft-wip.json -x 2
|
@@ -69,7 +69,7 @@ module Basketball
|
|
69
69
|
|
70
70
|
def slop_parse(args)
|
71
71
|
Slop.parse(args) do |o|
|
72
|
-
o.banner = 'Usage: draft [options] ...'
|
72
|
+
o.banner = 'Usage: basketball-draft [options] ...'
|
73
73
|
|
74
74
|
o.string '-i', '--input',
|
75
75
|
'Path to load the engine from. If omitted then a new draft will be generated.'
|
@@ -100,7 +100,6 @@ module Basketball
|
|
100
100
|
return if done?
|
101
101
|
|
102
102
|
event = SkipEvent.new(
|
103
|
-
id: SecureRandom.uuid,
|
104
103
|
front_office: current_front_office,
|
105
104
|
pick: current_pick,
|
106
105
|
round: current_round,
|
@@ -126,7 +125,6 @@ module Basketball
|
|
126
125
|
)
|
127
126
|
|
128
127
|
event = SimEvent.new(
|
129
|
-
id: SecureRandom.uuid,
|
130
128
|
front_office:,
|
131
129
|
player:,
|
132
130
|
pick: current_pick,
|
@@ -149,7 +147,6 @@ module Basketball
|
|
149
147
|
return nil if done?
|
150
148
|
|
151
149
|
event = PickEvent.new(
|
152
|
-
id: SecureRandom.uuid,
|
153
150
|
front_office: current_front_office,
|
154
151
|
player:,
|
155
152
|
pick: current_pick,
|
@@ -206,11 +203,11 @@ module Basketball
|
|
206
203
|
|
207
204
|
raise UnknownFrontOfficeError, "#{front_office} doesnt exist" unless front_offices.include?(event.front_office)
|
208
205
|
|
209
|
-
raise DupeEventError,
|
210
|
-
raise EventOutOfOrder,
|
211
|
-
raise EventOutOfOrder,
|
212
|
-
raise EventOutOfOrder,
|
213
|
-
raise EndOfDraftError,
|
206
|
+
raise DupeEventError, "#{event} is a dupe" if events.include?(event)
|
207
|
+
raise EventOutOfOrder, "#{event} has wrong pick" if event.pick != current_pick
|
208
|
+
raise EventOutOfOrder, "#{event} has wrong round" if event.round != current_round
|
209
|
+
raise EventOutOfOrder, "#{event} has wrong round_pick" if event.round_pick != current_round_pick
|
210
|
+
raise EndOfDraftError, "#{total_picks} pick limit reached" if events.length > total_picks + 1
|
214
211
|
|
215
212
|
events << event
|
216
213
|
|
@@ -115,7 +115,6 @@ module Basketball
|
|
115
115
|
events.map do |event|
|
116
116
|
{
|
117
117
|
type: event.class.name.split('::').last,
|
118
|
-
id: event.id,
|
119
118
|
front_office: event.front_office.id,
|
120
119
|
pick: event.pick,
|
121
120
|
round: event.round,
|
@@ -157,7 +156,7 @@ module Basketball
|
|
157
156
|
|
158
157
|
def deserialize_events(json, players, front_offices)
|
159
158
|
(json.dig(:engine, :events) || []).map do |event_hash|
|
160
|
-
event_opts = event_hash.slice(:
|
159
|
+
event_opts = event_hash.slice(:pick, :round, :round_pick).merge(
|
161
160
|
front_office: front_offices.find { |t| t.id == event_hash[:front_office] }
|
162
161
|
)
|
163
162
|
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module Basketball
|
4
4
|
module Drafting
|
5
|
-
class Event <
|
6
|
-
|
5
|
+
class Event < ValueObject
|
6
|
+
attr_reader_value :pick, :round, :round_pick, :front_office
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
super(
|
8
|
+
def initialize(front_office:, pick:, round:, round_pick:)
|
9
|
+
super()
|
10
10
|
|
11
11
|
raise ArgumentError, 'front_office required' unless front_office
|
12
12
|
|
@@ -5,10 +5,10 @@ require_relative 'event'
|
|
5
5
|
module Basketball
|
6
6
|
module Drafting
|
7
7
|
class PickEvent < Event
|
8
|
-
|
8
|
+
attr_reader_value :player
|
9
9
|
|
10
|
-
def initialize(
|
11
|
-
super(
|
10
|
+
def initialize(front_office:, player:, pick:, round:, round_pick:)
|
11
|
+
super(front_office:, pick:, round:, round_pick:)
|
12
12
|
|
13
13
|
raise ArgumentError, 'player required' unless player
|
14
14
|
|
@@ -3,10 +3,10 @@
|
|
3
3
|
module Basketball
|
4
4
|
module Drafting
|
5
5
|
class SimEvent < Event
|
6
|
-
|
6
|
+
attr_reader_value :player
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
super(
|
8
|
+
def initialize(front_office:, player:, pick:, round:, round_pick:)
|
9
|
+
super(front_office:, pick:, round:, round_pick:)
|
10
10
|
|
11
11
|
raise ArgumentError, 'player required' unless player
|
12
12
|
|
data/lib/basketball/drafting.rb
CHANGED
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Basketball
|
4
|
+
module Scheduling
|
5
|
+
class Calendar < ValueObject
|
6
|
+
class TeamAlreadyBookedError < StandardError; end
|
7
|
+
class InvalidGameOrderError < StandardError; end
|
8
|
+
class OutOfBoundsError < StandardError; end
|
9
|
+
|
10
|
+
attr_reader :preseason_start_date,
|
11
|
+
:preseason_end_date,
|
12
|
+
:season_start_date,
|
13
|
+
:season_end_date
|
14
|
+
|
15
|
+
attr_reader_value :year, :games
|
16
|
+
|
17
|
+
def initialize(year:, games: [])
|
18
|
+
super()
|
19
|
+
|
20
|
+
raise ArgumentError, 'year is required' unless year
|
21
|
+
|
22
|
+
@year = year
|
23
|
+
@preseason_start_date = Date.new(year, 9, 30)
|
24
|
+
@preseason_end_date = Date.new(year, 10, 14)
|
25
|
+
@season_start_date = Date.new(year, 10, 18)
|
26
|
+
@season_end_date = Date.new(year + 1, 4, 29)
|
27
|
+
@games = []
|
28
|
+
|
29
|
+
games.each { |game| add!(game) }
|
30
|
+
|
31
|
+
freeze
|
32
|
+
end
|
33
|
+
|
34
|
+
def add!(game)
|
35
|
+
assert_in_bounds(game)
|
36
|
+
assert_free_date(game)
|
37
|
+
|
38
|
+
@games << game
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def preseason_games_for(date: nil, team: nil)
|
44
|
+
games_for(date:, team:).select { |game| game.is_a?(PreseasonGame) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def season_games_for(date: nil, team: nil)
|
48
|
+
games_for(date:, team:).select { |game| game.is_a?(SeasonGame) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def games_for(date: nil, team: nil)
|
52
|
+
games.select do |game|
|
53
|
+
(date.nil? || game.date == date) &&
|
54
|
+
(team.nil? || (game.home_team == team || game.away_team == team))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def available_preseason_dates_for(team)
|
59
|
+
all_preseason_dates - preseason_games_for(team:).map(&:date)
|
60
|
+
end
|
61
|
+
|
62
|
+
def available_season_dates_for(team)
|
63
|
+
all_season_dates - season_games_for(team:).map(&:date)
|
64
|
+
end
|
65
|
+
|
66
|
+
def available_preseason_matchup_dates(team1, team2)
|
67
|
+
available_team_dates = available_preseason_dates_for(team1)
|
68
|
+
available_other_team_dates = available_preseason_dates_for(team2)
|
69
|
+
|
70
|
+
available_team_dates & available_other_team_dates
|
71
|
+
end
|
72
|
+
|
73
|
+
def available_season_matchup_dates(team1, team2)
|
74
|
+
available_team_dates = available_season_dates_for(team1)
|
75
|
+
available_other_team_dates = available_season_dates_for(team2)
|
76
|
+
|
77
|
+
available_team_dates & available_other_team_dates
|
78
|
+
end
|
79
|
+
|
80
|
+
def teams
|
81
|
+
games.flat_map(&:teams)
|
82
|
+
end
|
83
|
+
|
84
|
+
def team(id)
|
85
|
+
teams.find { |t| t == Team.new(id:) }
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def all_preseason_dates
|
91
|
+
(preseason_start_date..preseason_end_date).to_a
|
92
|
+
end
|
93
|
+
|
94
|
+
def all_season_dates
|
95
|
+
(season_start_date..season_end_date).to_a
|
96
|
+
end
|
97
|
+
|
98
|
+
def assert_free_date(game)
|
99
|
+
if games_for(date: game.date, team: game.home_team).any?
|
100
|
+
raise TeamAlreadyBookedError, "#{game.home_team} already playing on #{game.date}"
|
101
|
+
end
|
102
|
+
|
103
|
+
return unless games_for(date: game.date, team: game.away_team).any?
|
104
|
+
|
105
|
+
raise TeamAlreadyBookedError, "#{game.away_team} already playing on #{game.date}"
|
106
|
+
end
|
107
|
+
|
108
|
+
def assert_in_bounds(game)
|
109
|
+
if game.is_a?(PreseasonGame)
|
110
|
+
raise OutOfBoundsError, "#{game.date} is before preseason begins" if game.date < preseason_start_date
|
111
|
+
raise OutOfBoundsError, "#{game.date} is after preseason ends" if game.date > preseason_end_date
|
112
|
+
elsif game.is_a?(SeasonGame)
|
113
|
+
raise OutOfBoundsError, "#{game.date} is before season begins" if game.date < season_start_date
|
114
|
+
raise OutOfBoundsError, "#{game.date} is after season ends" if game.date > season_end_date
|
115
|
+
else
|
116
|
+
raise ArgumentError, "Dont know what this game type is: #{game.class.name}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'game'
|
4
|
+
require_relative 'preseason_game'
|
5
|
+
require_relative 'season_game'
|
6
|
+
|
7
|
+
module Basketball
|
8
|
+
module Scheduling
|
9
|
+
class CalendarSerializer
|
10
|
+
GAME_CLASSES = {
|
11
|
+
'PreseasonGame' => PreseasonGame,
|
12
|
+
'SeasonGame' => SeasonGame
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
def deserialize(string)
|
16
|
+
json = JSON.parse(string, symbolize_names: true)
|
17
|
+
|
18
|
+
Calendar.new(
|
19
|
+
year: json[:year].to_i,
|
20
|
+
games: deserialize_games(json)
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def serialize(calendar)
|
25
|
+
{
|
26
|
+
year: calendar.preseason_start_date.year,
|
27
|
+
teams: serialize_teams(calendar.games.flat_map(&:teams).uniq),
|
28
|
+
games: serialize_games(calendar.games)
|
29
|
+
}.to_json
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
## Deserialization
|
35
|
+
|
36
|
+
def deserialize_games(json)
|
37
|
+
teams = deserialize_teams(json[:teams])
|
38
|
+
|
39
|
+
(json[:games] || []).map do |game_hash|
|
40
|
+
GAME_CLASSES.fetch(game_hash[:type]).new(
|
41
|
+
date: Date.parse(game_hash[:date]),
|
42
|
+
home_team: teams.fetch(game_hash[:home_team]),
|
43
|
+
away_team: teams.fetch(game_hash[:away_team])
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def deserialize_teams(teams)
|
49
|
+
(teams || []).to_h do |id, team_hash|
|
50
|
+
team = Team.new(id:, name: team_hash[:name])
|
51
|
+
|
52
|
+
[
|
53
|
+
team.id,
|
54
|
+
team
|
55
|
+
]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
## Serialization
|
60
|
+
|
61
|
+
def serialize_teams(teams)
|
62
|
+
teams.to_h do |team|
|
63
|
+
[
|
64
|
+
team.id,
|
65
|
+
{
|
66
|
+
name: team.name
|
67
|
+
}
|
68
|
+
]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def serialize_games(games)
|
73
|
+
games.sort_by(&:date).map do |game|
|
74
|
+
{
|
75
|
+
type: game.class.name.split('::').last,
|
76
|
+
date: game.date,
|
77
|
+
home_team: game.home_team.id,
|
78
|
+
away_team: game.away_team.id
|
79
|
+
}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|