basketball 0.0.9 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -21
  3. data/basketball.gemspec +14 -8
  4. data/exe/basketball +91 -0
  5. data/lib/basketball/app/coordinator_cli.rb +56 -72
  6. data/lib/basketball/app/coordinator_repository.rb +12 -88
  7. data/lib/basketball/app/document_repository.rb +67 -0
  8. data/lib/basketball/app/file_store.rb +16 -0
  9. data/lib/basketball/app/in_memory_store.rb +42 -0
  10. data/lib/basketball/app/league_repository.rb +20 -0
  11. data/lib/basketball/app/league_serializable.rb +99 -0
  12. data/lib/basketball/app/room_cli.rb +30 -26
  13. data/lib/basketball/app/room_repository.rb +1 -41
  14. data/lib/basketball/app.rb +10 -2
  15. data/lib/basketball/draft/pick.rb +0 -7
  16. data/lib/basketball/draft/room.rb +11 -13
  17. data/lib/basketball/entity.rb +9 -6
  18. data/lib/basketball/org/conference.rb +47 -0
  19. data/lib/basketball/org/division.rb +43 -0
  20. data/lib/basketball/org/has_divisions.rb +25 -0
  21. data/lib/basketball/org/has_players.rb +20 -0
  22. data/lib/basketball/org/has_teams.rb +24 -0
  23. data/lib/basketball/org/league.rb +59 -32
  24. data/lib/basketball/org.rb +12 -1
  25. data/lib/basketball/season/arena.rb +26 -25
  26. data/lib/basketball/season/calendar.rb +52 -22
  27. data/lib/basketball/season/coordinator.rb +25 -18
  28. data/lib/basketball/season/detail.rb +47 -0
  29. data/lib/basketball/season/exhibition.rb +1 -1
  30. data/lib/basketball/season/opponent.rb +6 -0
  31. data/lib/basketball/season/record.rb +92 -0
  32. data/lib/basketball/season/scheduler.rb +223 -0
  33. data/lib/basketball/season/standings.rb +56 -0
  34. data/lib/basketball/season.rb +6 -0
  35. data/lib/basketball/value_object.rb +6 -28
  36. data/lib/basketball/value_object_dsl.rb +30 -0
  37. data/lib/basketball/version.rb +1 -1
  38. metadata +22 -6
  39. /data/exe/{basketball-room → basketball-draft-room} +0 -0
  40. /data/exe/{basketball-coordinator → basketball-season-coordinator} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab187320b9735e8bc6ace40a171cbc9fecd27058e78e5ee18ab1b663b6ea3d54
4
- data.tar.gz: 6173d1bfdb1b531d54763d369f248944c532916e5fecac89698ac4f49a72e4d9
3
+ metadata.gz: 95fd9cb9bb1c51ed7a76e5640f5297ea463b412803bcfacf8c47ea8b9abc5b21
4
+ data.tar.gz: 726e72b88fd8c81a30bfb4e47742e07fd97ba88fd86d9695852b0733ee6c0e5f
5
5
  SHA512:
6
- metadata.gz: df618bc45b196219e9f607a1842f5fda8513ea4dc7bce54756c98a327b87c9905bf41ded2c3dbf04cc70459d06ea4ab76864ff02713ecc2cf400e959cda081a6
7
- data.tar.gz: 536c2f5fff03419da03604302743b6ec0fccde9957238a0ae4c71c8b560b1709e3460afbc18e0fc377f239c20f4fb82fbb5e2d184b45f60c05d974d4f8615894
6
+ metadata.gz: b00a86aca794ea7b1ccbba172bc0fd63cfbbf4b8ff5eee2a7763f3877d8669a2b23141109fbf78461d9bd5b475e6a758381cc24c3a5d0e8b2e6dcb17f69e97bf
7
+ data.tar.gz: 5b8d75ca8cb88dc6733d1453d485a9fe8842a2e98d601f3870837bf3197718d181b77a475960202320be2d92a651ed5d741719e1d90882984d6286f629d2cd6d
data/README.md CHANGED
@@ -12,30 +12,40 @@ Element | Description
12
12
  :------------ | :-----------
13
13
  **Arena** | Determines exhibition and regular season game outcomes.
14
14
  **Assessment** | When the Room needs to know who a Front Office wants to select, the Room will send the Front Office an Assessment. The Assessment is a report of where the team currently stands: players picked, players available, and round information.
15
- **basketball-room** | Command-line executable script illustrating an example of how to subclass and consume the drafting module.
16
- **Calendar** | Stores important boundary dates (preseason start, preseason end, season start, and season end).
17
- **Coordinator CLI** | Underlying Ruby class that powers the `basketball-coordinator` script. Basically a terminal wrapper over the Coordinator object.
15
+ **basketball-draft-room** | Command-line executable script showing an example of how to consume the draft room aggregate root.
16
+ **basketball-season-coordinator** | Command-line executable script showing an example of how to consume the season coordinator aggregate root.
17
+ **Calendar** | Stores important boundary dates (exhibition start, exhibition end, season start, and season end).
18
+ **Conference** | A collection of Divisions.
19
+ **Coordinator CLI** | Underlying Ruby class that powers the `basketball-season-coordinator` script. Basically a terminal wrapper over the Coordinator object.
18
20
  **Coordinator Repository** | Understands how to save and load Coordinator objects from JSON files on disk.
19
21
  **Coordinator** | Object which can take a League, Calendar, Games, and an Arena and provide an iterable interface to enumerate through days and simulate games as results.
22
+ **Detail** | Re-representation of a Result object but from a specific team's perspective.
23
+ **Division** | A collection of teams.
20
24
  **Draft** | Bounded context (sub-module) dealing with running a round-robin player draft for teams.
21
25
  **Exhibition** | Pre-season game which has no impact to team record.
22
26
  **External Dependency** | Some outside system which this library or portions of this library are dependent on.
27
+ **File Store** | Implements a store that can interact with the underlying File System.
23
28
  **File System** | Local operating system that the CLI will use for persistence.
24
29
  **Front Office** | Identifiable as a team, contains logic for how to auto-pick draft selections. Meant to be subclassed and extended to include more intricate player selection logic as the base will simply randomly select a player.
25
30
  **Game** | Matches up a date with two teams (home and away) to represent a coordinatord match-up.
26
- **League** | Describes a league in terms of structure composed of teams and players.
31
+ **League Repository** | Understands how to save and load League objects from JSON files on disk.
32
+ **League** | Describes a league in terms of structure composed of conferences, divisions, teams, and players.
27
33
  **Match** | When the Coordinator needs an Arena instance to select a game winner, it will send the Arena a Match. A match is Game but also includes the active roster (players) for both teams that will participate in the game.
28
34
  **Org** | Bounded context (sub-module) dealing with overall organizational structure of a sports assocation.
29
35
  **Pick** | Result event emitted when a player is automatically or manually selected.
30
36
  **Player** | Identitiable as a person able to be drafted. Meant to be subclassed and extended to include more intricate descriptions of a specific sport player, such as abilities, ratings, and statistics. Right now it has none of these types of traits and it meant to only serve as the base with only an overall attribute.
37
+ **Record** | Represents a team's overall record.
31
38
  **Regular** | Game that counts towards regular season record.
32
39
  **Result** | The outcome of a game (typically with a home and away score).
33
- **Room CLI** | Underlying Ruby class that powers the `basketball-room` script. Basically a terminal wrapper for the Room object.
40
+ **Room CLI** | Underlying Ruby class that powers the `basketball-draft-room` script. Basically a terminal wrapper for the Room object.
34
41
  **Room Repository** | Understands how to save and load Room objects from JSON files on disk.
35
42
  **Room** | Main object responsible for providing an iterable interface capable of executing a draft, pick by pick.
43
+ **Scheduler** | Knows how to take a League and a year and generate a game-populated calendar.
36
44
  **Scout** | Knows how to stack rank lists of players.
37
45
  **Season** | Bounded context (sub-module) dealing with calendar and matchup generation.
38
46
  **Skip** | Result event emitted when a front office decides to skip a round.
47
+ **Standings** | Synthesizes teams and results into team standings with win/loss records and more.
48
+ **Store** | Interface for the underlying Repository persistence layer. While a Document Repository is mainly responsible for serialization/de-serialization, the store actually knows how to read/write the data.
39
49
  **Team Group** | Set of rosters that together form a cohesive league.
40
50
  **Team** | Member of a league and signs players. Has games assigned and played.
41
51
 
@@ -69,61 +79,61 @@ This library ships with an example of how the Draft module could be used impleme
69
79
  ###### Generate a Fresh Draft
70
80
 
71
81
  ```zsh
72
- basketball-room -o tmp/draft.json
82
+ basketball-draft-room -o tmp/draft.json
73
83
  ```
74
84
 
75
85
  ###### N Top Available Players
76
86
 
77
87
  ```zsh
78
- basketball-room -i tmp/draft.json -t 10
88
+ basketball-draft-room -i tmp/draft.json -t 10
79
89
  ```
80
90
 
81
91
  ###### N Top Available Players for a Position
82
92
 
83
93
  ```zsh
84
- basketball-room -i tmp/draft.json -t 10 -q PG
94
+ basketball-draft-room -i tmp/draft.json -t 10 -q PG
85
95
  ```
86
96
 
87
97
  ###### Output League
88
98
 
89
99
  ```zsh
90
- basketball-room -i tmp/draft.json -l
100
+ basketball-draft-room -i tmp/draft.json -l
91
101
  ```
92
102
 
93
103
  ###### Output Event Log
94
104
 
95
105
  ```zsh
96
- basketball-room -i tmp/draft.json -e
106
+ basketball-draft-room -i tmp/draft.json -e
97
107
  ```
98
108
 
99
109
  ###### Simulate N Picks
100
110
 
101
111
  ```zsh
102
- basketball-room -i tmp/draft.json -s 10
112
+ basketball-draft-room -i tmp/draft.json -s 10
103
113
  ```
104
114
 
105
115
  ###### Skip N Picks
106
116
 
107
117
  ```zsh
108
- basketball-room -i tmp/draft.json -x 10
118
+ basketball-draft-room -i tmp/draft.json -x 10
109
119
  ```
110
120
 
111
121
  ###### Pick Players
112
122
 
113
123
  ```zsh
114
- basketball-room -i tmp/draft.json -p P-100,P-200,P-300
124
+ basketball-draft-room -i tmp/draft.json -p P-100,P-200,P-300
115
125
  ```
116
126
 
117
127
  ###### Simulate the Rest of the Draft
118
128
 
119
129
  ```zsh
120
- basketball-room -i tmp/draft.json -a
130
+ basketball-draft-room -i tmp/draft.json -a
121
131
  ```
122
132
 
123
133
  ###### Help Menu
124
134
 
125
135
  ```zsh
126
- basketball-room -h
136
+ basketball-draft-room -h
127
137
  ```
128
138
 
129
139
  ### Season Module
@@ -140,37 +150,37 @@ This library ships with an example of how the Season module could be used implem
140
150
  ###### Generate Random coordinator
141
151
 
142
152
  ```zsh
143
- exe/basketball-coordinator -o tmp/coordinator.json
153
+ exe/basketball-season-coordinator -o tmp/coordinator.json
144
154
  ```
145
155
 
146
156
  ###### Sim One Day and Save to New File
147
157
 
148
158
  ```zsh
149
- exe/basketball-coordinator -i tmp/coordinator.json -o tmp/coordinator2.json -d 1
159
+ exe/basketball-season-coordinator -i tmp/coordinator.json -o tmp/coordinator2.json -d 1
150
160
  ```
151
161
 
152
162
  ###### Output Event Log
153
163
 
154
164
  ```zsh
155
- exe/basketball-coordinator -i tmp/coordinator.json -e
165
+ exe/basketball-season-coordinator -i tmp/coordinator.json -e
156
166
  ```
157
167
 
158
168
  ###### Sim Two Days and Save To Input File
159
169
 
160
170
  ```zsh
161
- exe/basketball-coordinator -i tmp/coordinator.json -d 2
171
+ exe/basketball-season-coordinator -i tmp/coordinator.json -d 2
162
172
  ```
163
173
 
164
174
  ###### Sim Rest of Calendar
165
175
 
166
176
  ```zsh
167
- exe/basketball-coordinator -i tmp/coordinator.json -a
177
+ exe/basketball-season-coordinator -i tmp/coordinator.json -a
168
178
  ```
169
179
 
170
180
  ###### Help Menu
171
181
 
172
182
  ```zsh
173
- basketball-coordinator -h
183
+ basketball-season-coordinator -h
174
184
  ```
175
185
 
176
186
  ## Contributing
data/basketball.gemspec CHANGED
@@ -11,14 +11,20 @@ Gem::Specification.new do |s|
11
11
  This library is meant to serve as the domain for a basketball league/season simulator/turn-based game. It models core ideas such as: players, general managers, draft strategy, drafting, season generation, season simultation, playoff generation, playoff simulation, and more.
12
12
  DESC
13
13
 
14
- s.authors = ['Matthew Ruggio']
15
- s.email = ['mattruggio@icloud.com']
16
- s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(.github|bin|docs|spec)/}) }
17
- s.bindir = 'exe'
18
- s.executables = %w[basketball-coordinator basketball-room]
19
- s.homepage = 'https://github.com/mattruggio/basketball'
20
- s.license = 'MIT'
21
- s.metadata = {
14
+ s.authors = ['Matthew Ruggio']
15
+ s.email = ['mattruggio@icloud.com']
16
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(.github|bin|docs|spec)/}) }
17
+ s.bindir = 'exe'
18
+
19
+ s.executables = %w[
20
+ basketball
21
+ basketball-season-coordinator
22
+ basketball-draft-room
23
+ ]
24
+
25
+ s.homepage = 'https://github.com/mattruggio/basketball'
26
+ s.license = 'MIT'
27
+ s.metadata = {
22
28
  'bug_tracker_uri' => 'https://github.com/mattruggio/basketball/issues',
23
29
  'changelog_uri' => 'https://github.com/mattruggio/basketball/blob/main/CHANGELOG.md',
24
30
  'documentation_uri' => 'https://www.rubydoc.info/gems/basketball',
data/exe/basketball ADDED
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'basketball'
6
+
7
+ # This is an example integration script tying all the contexts together.
8
+ # This is definitely subject to change as this library gets extended further.
9
+
10
+ store = Basketball::App::FileStore.new
11
+ room_repository = Basketball::App::RoomRepository.new(store)
12
+ league_repository = Basketball::App::LeagueRepository.new(store)
13
+ coordinator_repository = Basketball::App::CoordinatorRepository.new(store)
14
+ scheduler = Basketball::Season::Scheduler.new
15
+
16
+ seed_path = ARGV[0].to_s.empty? ? File.join('spec', 'fixtures', 'seed.json') : ARGV[0]
17
+ output_dir = ARGV[1].to_s.empty? ? 'tmp' : ARGV[1]
18
+ seed = JSON.parse(File.read(seed_path), symbolize_names: true)
19
+
20
+ league_path = File.join(output_dir, '00-league.json')
21
+
22
+ File.write(league_path, seed[:league].to_json)
23
+
24
+ front_offices = seed.dig(:league, :conferences).flat_map do |c|
25
+ c[:divisions].flat_map do |d|
26
+ d[:teams].flat_map do |t|
27
+ { id: t[:id] }
28
+ end
29
+ end
30
+ end
31
+
32
+ room = {
33
+ rounds: 12,
34
+ front_offices:,
35
+ players: seed[:players]
36
+ }
37
+
38
+ room_input_path = File.join(output_dir, '01-room-input.json')
39
+
40
+ File.write(room_input_path, room.to_json)
41
+
42
+ room = room_repository.load(room_input_path)
43
+
44
+ room.sim_rest!
45
+
46
+ room_output_path = File.join(output_dir, '02-room-output.json')
47
+
48
+ room_repository.save(room_output_path, room)
49
+
50
+ league = league_repository.load(league_path)
51
+
52
+ room.teams.each do |team|
53
+ team.players.each do |player|
54
+ league.sign!(team:, player:)
55
+ end
56
+ end
57
+
58
+ scheduler_input_path = File.join(output_dir, '03-scheduler-input.json')
59
+
60
+ league_repository.save(scheduler_input_path, league)
61
+
62
+ calendar = scheduler.schedule(league:)
63
+ current_date = calendar.exhibition_start_date
64
+ coordinator = Basketball::Season::Coordinator.new(league:, calendar:, current_date:)
65
+
66
+ coordinator_input_path = File.join(output_dir, '04-coordinator-input.json')
67
+
68
+ coordinator_repository.save(coordinator_input_path, coordinator)
69
+
70
+ coordinator.sim_rest!
71
+
72
+ coordinator_output_path = File.join(output_dir, '05-coordinator-output.json')
73
+
74
+ coordinator_repository.save(coordinator_output_path, coordinator)
75
+
76
+ preseason_standings = Basketball::Season::Standings.new
77
+ season_standings = Basketball::Season::Standings.new
78
+
79
+ league.teams.each do |team|
80
+ preseason_standings.register!(team)
81
+ season_standings.register!(team)
82
+ end
83
+
84
+ coordinator.exhibition_results.each { |result| preseason_standings.accept!(result) }
85
+ coordinator.regular_results.each { |result| season_standings.accept!(result) }
86
+
87
+ puts 'Preseason Standings'
88
+ puts preseason_standings
89
+ puts '--------------------------------------------'
90
+ puts 'Season Standings'
91
+ puts season_standings
@@ -3,20 +3,27 @@
3
3
  module Basketball
4
4
  module App
5
5
  # Examples:
6
- # exe/basketball-coordinator -o tmp/coordinator.json
7
- # exe/basketball-coordinator -i tmp/coordinator.json -o tmp/coordinator2.json -d 1
8
- # exe/basketball-coordinator -i tmp/coordinator2.json -e
9
- # exe/basketball-coordinator -i tmp/coordinator2.json -o tmp/coordinator2.json -d 2
10
- # exe/basketball-coordinator -i tmp/coordinator2.json -a
6
+ # exe/basketball-season-coordinator -o tmp/coordinator.json
7
+ # exe/basketball-season-coordinator -i tmp/coordinator.json -o tmp/coordinator2.json -d 1
8
+ # exe/basketball-season-coordinator -i tmp/coordinator2.json -e
9
+ # exe/basketball-season-coordinator -i tmp/coordinator2.json -o tmp/coordinator2.json -d 2
10
+ # exe/basketball-season-coordinator -i tmp/coordinator2.json -a
11
11
  #
12
- # exe/basketball-coordinator -o tmp/coordinator.json -ae
12
+ # exe/basketball-season-coordinator -o tmp/coordinator.json -ae
13
13
  class CoordinatorCLI
14
- attr_reader :opts, :io, :repository
14
+ attr_reader :opts, :io, :coordinator_repository
15
15
 
16
- def initialize(args:, io: $stdout)
17
- @io = io
18
- @opts = slop_parse(args)
19
- @repository = CoordinatorRepository.new
16
+ def initialize(
17
+ args:,
18
+ io: $stdout,
19
+ coordinator_repository: CoordinatorRepository.new(FileStore.new)
20
+ )
21
+ raise ArgumentError, 'coordinator_repository is required' unless coordinator_repository
22
+ raise ArgumentError, 'io is required' unless io
23
+
24
+ @io = io
25
+ @opts = slop_parse(args)
26
+ @coordinator_repository = coordinator_repository
20
27
 
21
28
  if no_input? && no_output?
22
29
  io.puts('Input and/or output paths are required.')
@@ -49,7 +56,7 @@ module Basketball
49
56
  else
50
57
  io.puts("#{coordinator.days_left} Remaining day(s) (#{coordinator.total_days} total)")
51
58
  io.puts("Currently on: #{coordinator.current_date}")
52
- io.puts("#{coordinator.exhibitions_left} Remaining preseason (#{coordinator.total_exhibitions} total)")
59
+ io.puts("#{coordinator.exhibitions_left} Remaining exhibition (#{coordinator.total_exhibitions} total)")
53
60
  io.puts("#{coordinator.regulars_left} Remaining season (#{coordinator.total_regulars} total)")
54
61
  end
55
62
  end
@@ -92,74 +99,51 @@ module Basketball
92
99
  def write(coordinator)
93
100
  path = output? ? output : input
94
101
 
95
- repository.save(path, coordinator)
102
+ coordinator_repository.save(path, coordinator)
96
103
 
97
104
  path
98
105
  end
99
106
 
100
- def make_league(team_count: 2, players_per_team_count: 4)
101
- Org::League.new.tap do |league|
102
- team_count.times do |i|
103
- team = Org::Team.new(id: "T-#{i}")
104
-
105
- players_per_team_count.times do |j|
106
- player = Org::Player.new(
107
- id: "T-#{i}-P-#{j}",
108
- overall: rand(20..100),
109
- position: Org::Position.random
110
- )
111
-
112
- team.sign!(player)
113
- end
114
-
115
- league.register!(team)
107
+ def make_league
108
+ Org::League.new(
109
+ conferences: 2.times.map do |i|
110
+ conference_id = "C#{i}"
111
+
112
+ Org::Conference.new(
113
+ id: conference_id,
114
+ divisions: 3.times.map do |j|
115
+ division_id = "#{conference_id}-D#{j}"
116
+
117
+ Org::Division.new(
118
+ id: division_id,
119
+ teams: 5.times.map do |k|
120
+ team_id = "#{division_id}-T#{k}"
121
+
122
+ Org::Team.new(
123
+ id: team_id,
124
+ players: 12.times.map do |l|
125
+ player_id = "#{team_id}-P#{l}"
126
+
127
+ Org::Player.new(
128
+ id: player_id,
129
+ overall: rand(20..100),
130
+ position: Org::Position.random
131
+ )
132
+ end
133
+ )
134
+ end
135
+ )
136
+ end
137
+ )
116
138
  end
117
- end
118
- end
119
-
120
- def make_calendar(league:)
121
- preseason_start_date = Date.new(2000, 1, 1)
122
- season_start_date = Date.new(2000, 1, 11)
123
-
124
- exhibitions = make_games(
125
- start_date: preseason_start_date,
126
- count: 10,
127
- league:,
128
- game_class: Season::Exhibition
129
139
  )
130
-
131
- regulars = make_games(
132
- start_date: season_start_date,
133
- count: 10,
134
- league:,
135
- game_class: Season::Regular
136
- )
137
-
138
- Season::Calendar.new(
139
- preseason_start_date:,
140
- preseason_end_date: Date.new(2000, 1, 10),
141
- season_start_date:,
142
- season_end_date: Date.new(2000, 1, 20),
143
- games: exhibitions + regulars
144
- )
145
- end
146
-
147
- def make_games(start_date:, count:, league:, game_class:)
148
- count.times.map do |i|
149
- home_team, away_team = league.teams.sample(2)
150
-
151
- game_class.new(
152
- date: start_date + i,
153
- home_opponent: Season::Opponent.new(id: home_team.id),
154
- away_opponent: Season::Opponent.new(id: away_team.id)
155
- )
156
- end
157
140
  end
158
141
 
159
142
  def make_coordinator
160
143
  league = make_league
161
- current_date = Date.new(2000, 1, 1)
162
- calendar = make_calendar(league:)
144
+ year = Time.now.year
145
+ calendar = Season::Scheduler.new.schedule(league:, year:)
146
+ current_date = calendar.games.min_by(&:date).date
163
147
 
164
148
  Season::Coordinator.new(
165
149
  calendar:,
@@ -173,7 +157,7 @@ module Basketball
173
157
  if input?
174
158
  io.puts("Coordinator loaded from: #{input}")
175
159
 
176
- repository.load(input)
160
+ coordinator_repository.load(input)
177
161
  else
178
162
  io.puts('Input path was not provided, generating fresh coordinator')
179
163
 
@@ -220,7 +204,7 @@ module Basketball
220
204
 
221
205
  def slop_parse(args)
222
206
  Slop.parse(args) do |o|
223
- o.banner = 'Usage: basketball-coordinator [options] ...'
207
+ o.banner = 'Usage: basketball-season-coordinator [options] ...'
224
208
 
225
209
  input_description = <<~DESC
226
210
  Path to load the Coordinator from. If omitted then a new coordinator will be created.
@@ -3,7 +3,9 @@
3
3
  module Basketball
4
4
  module App
5
5
  # Knows how to flatten a Coordinator instance and rehydrate one from JSON and/or a Ruby hash.
6
- class CoordinatorRepository
6
+ class CoordinatorRepository < DocumentRepository
7
+ include LeagueSerializable
8
+
7
9
  GAME_CLASSES = {
8
10
  'Exhibition' => Season::Exhibition,
9
11
  'Regular' => Season::Regular
@@ -11,46 +13,8 @@ module Basketball
11
13
 
12
14
  private_constant :GAME_CLASSES
13
15
 
14
- attr_reader :store
15
-
16
- def initialize(store: FileStore.new)
17
- super()
18
-
19
- @store = store
20
-
21
- freeze
22
- end
23
-
24
- def load(path)
25
- contents = store.read(path)
26
-
27
- deserialize(contents).tap do |coordinator|
28
- coordinator.send('id=', path)
29
- end
30
- end
31
-
32
- def save(path, coordinator)
33
- contents = serialize(coordinator)
34
-
35
- store.write(path, contents)
36
-
37
- coordinator.send('id=', path)
38
-
39
- coordinator
40
- end
41
-
42
16
  private
43
17
 
44
- def deserialize(string)
45
- hash = JSON.parse(string, symbolize_names: true)
46
-
47
- from_h(hash)
48
- end
49
-
50
- def serialize(object)
51
- to_h(object).to_json
52
- end
53
-
54
18
  def from_h(hash)
55
19
  Season::Coordinator.new(
56
20
  calendar: deserialize_calendar(hash[:calendar]),
@@ -62,6 +26,7 @@ module Basketball
62
26
 
63
27
  def to_h(coordinator)
64
28
  {
29
+ id: coordinator.id,
65
30
  calendar: serialize_calendar(coordinator.calendar),
66
31
  current_date: coordinator.current_date.to_s,
67
32
  results: serialize_results(coordinator.results),
@@ -71,24 +36,16 @@ module Basketball
71
36
 
72
37
  # Serialization
73
38
 
74
- def serialize_player(player)
75
- {
76
- id: player.id,
77
- overall: player.overall,
78
- position: player.position&.code
79
- }
80
- end
81
-
82
39
  def serialize_games(games)
83
40
  games.map { |game| serialize_game(game) }
84
41
  end
85
42
 
86
43
  def serialize_calendar(calendar)
87
44
  {
88
- preseason_start_date: calendar.preseason_start_date.to_s,
89
- preseason_end_date: calendar.preseason_end_date.to_s,
90
- season_start_date: calendar.season_start_date.to_s,
91
- season_end_date: calendar.season_end_date.to_s,
45
+ exhibition_start_date: calendar.exhibition_start_date.to_s,
46
+ exhibition_end_date: calendar.exhibition_end_date.to_s,
47
+ regular_start_date: calendar.regular_start_date.to_s,
48
+ regular_end_date: calendar.regular_end_date.to_s,
92
49
  games: serialize_games(calendar.games)
93
50
  }
94
51
  end
@@ -110,19 +67,6 @@ module Basketball
110
67
  }
111
68
  end
112
69
 
113
- def serialize_league(league)
114
- {
115
- teams: league.teams.map { |team| serialize_team(team) }
116
- }
117
- end
118
-
119
- def serialize_team(team)
120
- {
121
- id: team.id,
122
- players: team.players.map { |player| serialize_player(player) }
123
- }
124
- end
125
-
126
70
  def serialize_results(results)
127
71
  results.map do |result|
128
72
  serialize_result(result)
@@ -131,32 +75,12 @@ module Basketball
131
75
 
132
76
  # Deserialization
133
77
 
134
- def deserialize_player(player_hash)
135
- Org::Player.new(
136
- id: player_hash[:id],
137
- overall: player_hash[:overall],
138
- position: Org::Position.new(player_hash[:position])
139
- )
140
- end
141
-
142
- def deserialize_league(league_hash)
143
- team_hashes = league_hash[:teams] || []
144
-
145
- teams = team_hashes.map do |team_hash|
146
- players = (team_hash[:players] || []).map { |player_hash| deserialize_player(player_hash) }
147
-
148
- Org::Team.new(id: team_hash[:id], players:)
149
- end
150
-
151
- Org::League.new(teams:)
152
- end
153
-
154
78
  def deserialize_calendar(calendar_hash)
155
79
  Season::Calendar.new(
156
- preseason_start_date: Date.parse(calendar_hash[:preseason_start_date]),
157
- preseason_end_date: Date.parse(calendar_hash[:preseason_end_date]),
158
- season_start_date: Date.parse(calendar_hash[:season_start_date]),
159
- season_end_date: Date.parse(calendar_hash[:season_end_date]),
80
+ exhibition_start_date: Date.parse(calendar_hash[:exhibition_start_date]),
81
+ exhibition_end_date: Date.parse(calendar_hash[:exhibition_end_date]),
82
+ regular_start_date: Date.parse(calendar_hash[:regular_start_date]),
83
+ regular_end_date: Date.parse(calendar_hash[:regular_end_date]),
160
84
  games: deserialize_games(calendar_hash[:games])
161
85
  )
162
86
  end