basketball 0.0.16 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f5be10590a625ef061cb6f7a80379710013ec3625fe215fa65bfddeda35bb1f5
4
- data.tar.gz: 5eff4fd535bddae0bf080f2fd0be83b4cdc8da7cc28c04667a1ec7cfd84f1f55
3
+ metadata.gz: afad5b6023e9b0baf1dc11fe6874d4cc46430c1698aa4e97bf5dc2df8cbb314e
4
+ data.tar.gz: f98bb161b770d7148c4fb271ab1b58b2347cfe7b85f94acf1fb6332a4517e61b
5
5
  SHA512:
6
- metadata.gz: 41e8aac1b7270794a5557b9e94b3b23bd0f5f7169c5c38f87401eaf12e6865efd4a1b8293a8cf6b6a41813ecc476750f538abc511ae4554e94c3cc732c6a5872
7
- data.tar.gz: fd0fcc3117888b9c475efce63e5947de6f66950b3af98af9f4c551403749ab34fc6f989d3b48964bc29180be19c3af55931e5bb4ef67377f05dd83994ab82284
6
+ metadata.gz: 439ca00c393c39e8535ffc21b504b66aaf2a987f09e424ba55b8d4d33d740c6ece187e8e2821239b1d2fa7512aa3743e8a8750be9c41d71259a6093eb2bff57a
7
+ data.tar.gz: 433fbfeaf16e28312b165ff2b293b9a529ea57e95f0e03e4637b730f1dc36c22c095717825da54da6e0549eeccbeedbb999caf7db5afed80e8e439b25a15d2cd
data/README.md CHANGED
@@ -14,18 +14,13 @@ Element | Description
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
15
  **Calendar** | Stores important boundary dates (exhibition start, exhibition end, season start, and season end).
16
16
  **Conference** | A collection of Divisions.
17
- **Coordinator Repository** | Understands how to save and load Coordinator objects.
18
17
  **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.
19
18
  **Detail** | Re-representation of a Result object but from a specific team's perspective.
20
19
  **Division** | A collection of teams.
21
20
  **Draft** | Bounded context (sub-module) dealing with running a round-robin player draft for teams.
22
21
  **Exhibition** | Pre-season game which has no impact to team record.
23
- **External Dependency** | Some outside system which this library or portions of this library are dependent on.
24
- **File Store** | Implements a store that can interact with the underlying File System.
25
- **File System** | Local operating system that repositories can use as their underlying persistence layer.
26
22
  **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.
27
23
  **Game** | Matches up a date with two teams (home and away) to represent a coordinatord match-up.
28
- **League Repository** | Understands how to save and load League objects from JSON files on disk.
29
24
  **League** | Describes a league in terms of structure composed of conferences, divisions, teams, and players.
30
25
  **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.
31
26
  **Org** | Bounded context (sub-module) dealing with overall organizational structure of a sports assocation.
@@ -34,14 +29,12 @@ Element | Description
34
29
  **Record** | Represents a team's overall record.
35
30
  **Regular** | Game that counts towards regular season record.
36
31
  **Result** | The outcome of a game (typically with a home and away score).
37
- **Room Repository** | Understands how to save and load Room objects.
38
32
  **Room** | Main object responsible for providing an iterable interface capable of executing a draft, pick by pick.
39
33
  **Scheduler** | Knows how to take a League and a year and generate a game-populated calendar.
40
34
  **Scout** | Knows how to stack rank lists of players.
41
35
  **Season** | Bounded context (sub-module) dealing with calendar and matchup generation.
42
36
  **Skip** | Result event emitted when a front office decides to skip a round.
43
37
  **Standings** | Synthesizes teams and results into team standings with win/loss records and more.
44
- **Standings Repository** | Understands how to save and load Standings objects.
45
38
  **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.
46
39
  **Team Group** | Set of rosters that together form a cohesive league.
47
40
  **Team** | Member of a league and signs players. Has games assigned and played.
@@ -3,8 +3,8 @@
3
3
  module Basketball
4
4
  module Draft
5
5
  # Describes what all Room events have to have to be considered an "event".
6
- class Event < ValueObject
7
- value_reader :pick, :round, :round_pick, :front_office
6
+ class Event < Entity
7
+ attr_reader :pick, :round, :round_pick, :front_office
8
8
 
9
9
  def initialize(front_office:, pick:, round:, round_pick:)
10
10
  super()
@@ -18,7 +18,7 @@ module Basketball
18
18
  end
19
19
 
20
20
  def to_s
21
- "[##{pick} R:#{round} P:#{round_pick}] #{front_office}"
21
+ "[#{id}] ##{pick} R:#{round} P:#{round_pick} - #{front_office}"
22
22
  end
23
23
  end
24
24
  end
@@ -4,7 +4,7 @@ module Basketball
4
4
  module Draft
5
5
  # Room event where a player is selected.
6
6
  class Pick < Event
7
- value_reader :player, :auto
7
+ attr_reader :player, :auto
8
8
 
9
9
  def initialize(front_office:, player:, pick:, round:, round_pick:, auto: false)
10
10
  super(front_office:, pick:, round:, round_pick:)
@@ -13,8 +13,6 @@ module Basketball
13
13
 
14
14
  @player = player
15
15
  @auto = auto
16
-
17
- freeze
18
16
  end
19
17
 
20
18
  def to_s
@@ -6,12 +6,13 @@ module Basketball
6
6
  class Conference < Entity
7
7
  include HasDivisions
8
8
 
9
- attr_reader :divisions
9
+ attr_reader :divisions, :name
10
10
 
11
- def initialize(id:, divisions: [])
11
+ def initialize(id:, name: '', divisions: [])
12
12
  super(id)
13
13
 
14
14
  @divisions = []
15
+ @name = name.to_s
15
16
 
16
17
  divisions.each { |d| register_division!(d) }
17
18
 
@@ -19,7 +20,7 @@ module Basketball
19
20
  end
20
21
 
21
22
  def to_s
22
- ([super] + divisions.map(&:to_s)).join("\n")
23
+ (["[#{super}] #{name}"] + divisions.map(&:to_s)).join("\n")
23
24
  end
24
25
 
25
26
  def teams
@@ -6,12 +6,13 @@ module Basketball
6
6
  class Division < Entity
7
7
  include HasTeams
8
8
 
9
- attr_reader :teams
9
+ attr_reader :teams, :name
10
10
 
11
- def initialize(id:, teams: [])
11
+ def initialize(id:, name: '', teams: [])
12
12
  super(id)
13
13
 
14
14
  @teams = []
15
+ @name = name.to_s
15
16
 
16
17
  teams.each { |t| register_team!(t) }
17
18
 
@@ -19,7 +20,7 @@ module Basketball
19
20
  end
20
21
 
21
22
  def to_s
22
- ([super] + teams.map(&:to_s)).join("\n")
23
+ (["[#{super}] #{name}"] + teams.map(&:to_s)).join("\n")
23
24
  end
24
25
 
25
26
  def players
@@ -5,21 +5,27 @@ module Basketball
5
5
  # Base class describing a player.
6
6
  # A consumer application should extend these specific to their specific sports traits.
7
7
  class Player < Entity
8
- attr_reader :overall, :position
8
+ attr_reader :overall, :position, :first_name, :last_name
9
9
 
10
- def initialize(id:, overall: 0, position: nil)
10
+ def initialize(id:, overall: 0, position: nil, first_name: '', last_name: '')
11
11
  super(id)
12
12
 
13
13
  raise ArgumentError, 'position is required' unless position
14
14
 
15
- @overall = overall
16
- @position = position
15
+ @overall = overall
16
+ @position = position
17
+ @first_name = first_name
18
+ @last_name = last_name
17
19
 
18
20
  freeze
19
21
  end
20
22
 
23
+ def full_name
24
+ "#{first_name} #{last_name}".strip
25
+ end
26
+
21
27
  def to_s
22
- "[#{super}] (#{position}) #{overall}".strip
28
+ "[#{super}] #{full_name} (#{position}) #{overall}".strip
23
29
  end
24
30
  end
25
31
  end
@@ -5,12 +5,13 @@ module Basketball
5
5
  # Base class describing a team. A team here is bare metal and is just described by an ID
6
6
  # and a collection of Player objects.
7
7
  class Team < Entity
8
- attr_reader :players
8
+ attr_reader :players, :name
9
9
 
10
- def initialize(id:, players: [])
10
+ def initialize(id:, name: '', players: [])
11
11
  super(id)
12
12
 
13
13
  @players = []
14
+ @name = name.to_s
14
15
 
15
16
  players.each { |p| sign!(p) }
16
17
 
@@ -18,7 +19,7 @@ module Basketball
18
19
  end
19
20
 
20
21
  def to_s
21
- ([super.to_s] + players.map(&:to_s)).join("\n")
22
+ (["[#{super}] #{name}"] + players.map(&:to_s)).join("\n")
22
23
  end
23
24
 
24
25
  def signed?(player)
@@ -16,7 +16,8 @@ module Basketball
16
16
  attr_reader :calendar,
17
17
  :current_date,
18
18
  :arena,
19
- :results
19
+ :results,
20
+ :league
20
21
 
21
22
  def_delegators :calendar,
22
23
  :exhibition_start_date,
@@ -28,29 +29,32 @@ module Basketball
28
29
  :regulars_for,
29
30
  :games_for
30
31
 
31
- def initialize(calendar:, current_date:, results: [])
32
+ def initialize(calendar:, league:, current_date:, results: [])
32
33
  super()
33
34
 
34
- raise ArgumentError, 'calendar is required' unless calendar
35
+ raise ArgumentError, 'calendar is required' unless calendar
35
36
  raise ArgumentError, 'current_date is required' if current_date.to_s.empty?
37
+ raise ArgumentError, 'league is required' unless league
36
38
 
37
39
  @calendar = calendar
38
40
  @current_date = current_date
39
41
  @arena = Arena.new
40
42
  @results = []
43
+ @league = league
41
44
 
42
45
  results.each { |result| replay!(result) }
43
46
 
44
47
  assert_current_date
45
48
  assert_all_past_dates_are_played
46
49
  assert_all_future_dates_arent_played
50
+ assert_all_known_teams
47
51
  end
48
52
 
49
- def sim_rest!(league, &)
53
+ def sim_rest!(&)
50
54
  events = []
51
55
 
52
56
  while not_done?
53
- new_events = sim!(league, &)
57
+ new_events = sim!(&)
54
58
 
55
59
  events += new_events
56
60
  end
@@ -68,7 +72,7 @@ module Basketball
68
72
  raise OutOfBoundsError, "current date #{current_date} should be on or after #{exhibition_start_date}"
69
73
  end
70
74
 
71
- def sim!(league)
75
+ def sim!
72
76
  raise ArgumentError, 'league is required' unless league
73
77
 
74
78
  return [] if done?
@@ -77,8 +81,8 @@ module Basketball
77
81
  games = games_for(date: current_date)
78
82
 
79
83
  games.each do |game|
80
- home_players = opponent_team(league, game.home_opponent).players
81
- away_players = opponent_team(league, game.away_opponent).players
84
+ home_players = opponent_team(game.home_opponent).players
85
+ away_players = opponent_team(game.away_opponent).players
82
86
  matchup = Matchup.new(game:, home_players:, away_players:)
83
87
  event = arena.play(matchup)
84
88
 
@@ -156,7 +160,7 @@ module Basketball
156
160
 
157
161
  attr_writer :arena
158
162
 
159
- def opponent_team(league, opponent)
163
+ def opponent_team(opponent)
160
164
  league.teams.find { |t| t == opponent }
161
165
  end
162
166
 
@@ -220,6 +224,18 @@ module Basketball
220
224
 
221
225
  result
222
226
  end
227
+
228
+ def assert_known_teams(game)
229
+ raise UnknownTeamError, "unknown opponent: #{game.home_opponent}" unless league.team?(game.home_opponent)
230
+
231
+ return if league.team?(game.away_opponent)
232
+
233
+ raise UnknownTeamError, "unknown opponent: #{game.away_opponent}"
234
+ end
235
+
236
+ def assert_all_known_teams
237
+ calendar.games.each { |game| assert_known_teams(game) }
238
+ end
223
239
  end
224
240
  end
225
241
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Basketball
4
- VERSION = '0.0.16'
4
+ VERSION = '0.0.18'
5
5
  end
data/lib/basketball.rb CHANGED
@@ -15,6 +15,3 @@ require_relative 'basketball/org'
15
15
  # Dependent on Org
16
16
  require_relative 'basketball/draft'
17
17
  require_relative 'basketball/season'
18
-
19
- # Dependent on All
20
- require_relative 'basketball/app'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: basketball
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.16
4
+ version: 0.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-12 00:00:00.000000000 Z
11
+ date: 2023-06-14 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: " This library is meant to serve as the domain for a basketball league/season
14
14
  simulator/turn-based game. It models core ideas such as: players, general managers,
@@ -33,14 +33,6 @@ files:
33
33
  - Rakefile
34
34
  - basketball.gemspec
35
35
  - lib/basketball.rb
36
- - lib/basketball/app.rb
37
- - lib/basketball/app/coordinator_repository.rb
38
- - lib/basketball/app/document_repository.rb
39
- - lib/basketball/app/file_store.rb
40
- - lib/basketball/app/in_memory_store.rb
41
- - lib/basketball/app/league_repository.rb
42
- - lib/basketball/app/room_repository.rb
43
- - lib/basketball/app/standings_repository.rb
44
36
  - lib/basketball/draft.rb
45
37
  - lib/basketball/draft/assessment.rb
46
38
  - lib/basketball/draft/event.rb
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Basketball
4
- module App
5
- # Knows how to flatten a Coordinator instance and rehydrate one from JSON and/or a Ruby hash.
6
- class CoordinatorRepository < DocumentRepository
7
- GAME_CLASSES = {
8
- 'Exhibition' => Season::Exhibition,
9
- 'Regular' => Season::Regular
10
- }.freeze
11
-
12
- private_constant :GAME_CLASSES
13
-
14
- private
15
-
16
- def from_h(hash)
17
- Season::Coordinator.new(
18
- calendar: deserialize_calendar(hash[:calendar]),
19
- current_date: Date.parse(hash[:current_date]),
20
- results: deserialize_results(hash[:results])
21
- )
22
- end
23
-
24
- def to_h(coordinator)
25
- {
26
- id: coordinator.id,
27
- calendar: serialize_calendar(coordinator.calendar),
28
- current_date: coordinator.current_date.to_s,
29
- results: serialize_results(coordinator.results)
30
- }
31
- end
32
-
33
- # Serialization
34
-
35
- def serialize_games(games)
36
- games.map { |game| serialize_game(game) }
37
- end
38
-
39
- def serialize_calendar(calendar)
40
- {
41
- exhibition_start_date: calendar.exhibition_start_date.to_s,
42
- exhibition_end_date: calendar.exhibition_end_date.to_s,
43
- regular_start_date: calendar.regular_start_date.to_s,
44
- regular_end_date: calendar.regular_end_date.to_s,
45
- games: serialize_games(calendar.games)
46
- }
47
- end
48
-
49
- def serialize_game(game)
50
- {
51
- type: game.class.name.split('::').last,
52
- date: game.date.to_s,
53
- home_opponent: game.home_opponent.id,
54
- away_opponent: game.away_opponent.id
55
- }
56
- end
57
-
58
- def serialize_result(result)
59
- {
60
- game: serialize_game(result.game),
61
- home_score: result.home_score,
62
- away_score: result.away_score
63
- }
64
- end
65
-
66
- def serialize_results(results)
67
- results.map do |result|
68
- serialize_result(result)
69
- end
70
- end
71
-
72
- # Deserialization
73
-
74
- def deserialize_calendar(calendar_hash)
75
- Season::Calendar.new(
76
- exhibition_start_date: Date.parse(calendar_hash[:exhibition_start_date]),
77
- exhibition_end_date: Date.parse(calendar_hash[:exhibition_end_date]),
78
- regular_start_date: Date.parse(calendar_hash[:regular_start_date]),
79
- regular_end_date: Date.parse(calendar_hash[:regular_end_date]),
80
- games: deserialize_games(calendar_hash[:games])
81
- )
82
- end
83
-
84
- def deserialize_games(game_hashes)
85
- (game_hashes || []).map { |game_hash| deserialize_game(game_hash) }
86
- end
87
-
88
- def deserialize_game(game_hash)
89
- GAME_CLASSES.fetch(game_hash[:type]).new(
90
- date: Date.parse(game_hash[:date]),
91
- home_opponent: Season::Opponent.new(id: game_hash[:home_opponent]),
92
- away_opponent: Season::Opponent.new(id: game_hash[:away_opponent])
93
- )
94
- end
95
-
96
- def deserialize_results(result_hashes)
97
- (result_hashes || []).map do |result_hash|
98
- deserialize_result(result_hash)
99
- end
100
- end
101
-
102
- def deserialize_result(result_hash)
103
- Season::Result.new(
104
- game: deserialize_game(result_hash[:game]),
105
- home_score: result_hash[:home_score],
106
- away_score: result_hash[:away_score]
107
- )
108
- end
109
- end
110
- end
111
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Basketball
4
- module App
5
- # Base class for all repositories which are based on a flat document.
6
- # At the very minimum sub-classes should implement #to_h(object) and #from_h(hash).
7
- class DocumentRepository
8
- attr_reader :store
9
-
10
- def initialize(store = InMemoryStore.new)
11
- super()
12
-
13
- @store = store
14
- end
15
-
16
- def load(id)
17
- contents = store.read(id)
18
-
19
- deserialize(contents).tap do |object|
20
- object.send('id=', id)
21
- end
22
- end
23
-
24
- def save(id, object)
25
- object.send('id=', id)
26
-
27
- contents = serialize(object)
28
-
29
- store.write(id, contents)
30
-
31
- object
32
- end
33
-
34
- def delete(object)
35
- return false unless object.id
36
-
37
- store.delete(object.id)
38
-
39
- object.send('id=', nil)
40
-
41
- true
42
- end
43
-
44
- def exist?(id)
45
- store.exist?(id)
46
- end
47
-
48
- protected
49
-
50
- def from_h(hash)
51
- Entity.new(hash[:id])
52
- end
53
-
54
- def to_h(entity)
55
- { id: entity.id }
56
- end
57
-
58
- private
59
-
60
- def deserialize(string)
61
- hash = JSON.parse(string, symbolize_names: true)
62
-
63
- from_h(hash)
64
- end
65
-
66
- def serialize(object)
67
- to_h(object).to_json
68
- end
69
- end
70
- end
71
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Basketball
4
- module App
5
- # Knows how to read and write documents to disk.
6
- class FileStore
7
- class PathNotFoundError < StandardError; end
8
-
9
- def exist?(path)
10
- File.exist?(path)
11
- end
12
-
13
- def read(path)
14
- raise PathNotFoundError, "'#{path}' not found" unless exist?(path)
15
-
16
- File.read(path)
17
- end
18
-
19
- def write(path, contents)
20
- dir = File.dirname(path)
21
-
22
- FileUtils.mkdir_p(dir)
23
-
24
- File.write(path, contents)
25
-
26
- nil
27
- end
28
-
29
- def delete(path)
30
- raise PathNotFoundError, "'#{path}' not found" unless exist?(path)
31
-
32
- File.delete(path)
33
-
34
- nil
35
- end
36
- end
37
- end
38
- end
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Basketball
4
- module App
5
- # Knows how to read and write documents to a Ruby Hash.
6
- class InMemoryStore
7
- class KeyNotFoundError < StandardError; end
8
-
9
- attr_reader :data
10
-
11
- def initialize(data = {})
12
- @data = data
13
-
14
- freeze
15
- end
16
-
17
- def exist?(key)
18
- data.key?(key.to_s)
19
- end
20
-
21
- def read(key)
22
- raise KeyNotFoundError, "'#{key}' not found" unless exist?(key)
23
-
24
- data[key.to_s]
25
- end
26
-
27
- def write(key, contents)
28
- data[key.to_s] = contents
29
-
30
- nil
31
- end
32
-
33
- def delete(key)
34
- raise KeyNotFoundError, "'#{key}' not found" unless exist?(key)
35
-
36
- data.delete(key)
37
-
38
- nil
39
- end
40
- end
41
- end
42
- end
@@ -1,109 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Basketball
4
- module App
5
- # Knows how to flatten a League instances and rehydrate one from JSON and/or a Ruby hash.
6
- class LeagueRepository < DocumentRepository
7
- private
8
-
9
- def from_h(hash)
10
- deserialize_league(hash)
11
- end
12
-
13
- def to_h(league)
14
- serialize_league(league)
15
- end
16
-
17
- # Serialization
18
-
19
- def serialize_league(league)
20
- {
21
- id: league.id,
22
- conferences: serialize_conferences(league.conferences)
23
- }
24
- end
25
-
26
- def serialize_conferences(conferences)
27
- conferences.map do |conference|
28
- {
29
- id: conference.id,
30
- divisions: serialize_divisions(conference.divisions)
31
- }
32
- end
33
- end
34
-
35
- def serialize_divisions(divisions)
36
- divisions.map do |division|
37
- {
38
- id: division.id,
39
- teams: serialize_teams(division.teams)
40
- }
41
- end
42
- end
43
-
44
- def serialize_teams(teams)
45
- teams.map do |team|
46
- {
47
- id: team.id,
48
- players: serialize_players(team.players)
49
- }
50
- end
51
- end
52
-
53
- def serialize_players(players)
54
- players.map do |player|
55
- {
56
- id: player.id,
57
- overall: player.overall,
58
- position: player.position&.code
59
- }
60
- end
61
- end
62
-
63
- # Deserialization
64
-
65
- def deserialize_league(league_hash)
66
- Org::League.new(
67
- conferences: deserialize_conferences(league_hash[:conferences])
68
- )
69
- end
70
-
71
- def deserialize_conferences(conference_hashes)
72
- (conference_hashes || []).map do |conference_hash|
73
- Org::Conference.new(
74
- id: conference_hash[:id],
75
- divisions: deserialize_divisions(conference_hash[:divisions])
76
- )
77
- end
78
- end
79
-
80
- def deserialize_divisions(division_hashes)
81
- (division_hashes || []).map do |division_hash|
82
- Org::Division.new(
83
- id: division_hash[:id],
84
- teams: deserialize_teams(division_hash[:teams])
85
- )
86
- end
87
- end
88
-
89
- def deserialize_teams(team_hashes)
90
- (team_hashes || []).map do |team_hash|
91
- Org::Team.new(
92
- id: team_hash[:id],
93
- players: deserialize_players(team_hash[:players])
94
- )
95
- end
96
- end
97
-
98
- def deserialize_players(player_hashes)
99
- (player_hashes || []).map do |player_hash|
100
- Org::Player.new(
101
- id: player_hash[:id],
102
- overall: player_hash[:overall],
103
- position: Org::Position.new(player_hash[:position])
104
- )
105
- end
106
- end
107
- end
108
- end
109
- end
@@ -1,154 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Basketball
4
- module App
5
- # Can load and save Room objects as JSON Documents.
6
- class RoomRepository < DocumentRepository
7
- PICK_EVENT = 'Pick'
8
- SKIP_EVENT = 'Skip'
9
-
10
- private_constant :PICK_EVENT, :SKIP_EVENT
11
-
12
- private
13
-
14
- def from_h(hash)
15
- front_offices = deserialize_front_offices(hash[:front_offices])
16
- players = deserialize_players(hash[:players])
17
- events = deserialize_events(hash[:events], players:, front_offices:)
18
-
19
- Draft::Room.new(
20
- rounds: hash[:rounds],
21
- front_offices:,
22
- players:,
23
- events:
24
- )
25
- end
26
-
27
- def to_h(room)
28
- {
29
- id: room.id,
30
- rounds: room.rounds,
31
- front_offices: room.front_offices.map { |fo| serialize_front_office(fo) },
32
- players: room.players.map { |p| serialize_player(p) },
33
- events: serialize_events(room.events)
34
- }
35
- end
36
-
37
- # Serialization
38
-
39
- def serialize_player(player)
40
- {
41
- id: player.id,
42
- overall: player.overall,
43
- position: player.position&.code
44
- }
45
- end
46
-
47
- def serialize_front_office(front_office)
48
- {
49
- id: front_office.id,
50
- risk_level: front_office.risk_level,
51
- prioritized_positions: front_office.prioritized_positions.map(&:code),
52
- star_level: front_office.star_level
53
- }
54
- end
55
-
56
- def serialize_events(events)
57
- events.map do |event|
58
- case event
59
- when Draft::Pick
60
- serialize_pick(event)
61
- when Draft::Skip
62
- serialize_skip(event)
63
- end
64
- end
65
- end
66
-
67
- def serialize_pick(event)
68
- {
69
- type: PICK_EVENT,
70
- front_office: event.front_office.id,
71
- pick: event.pick,
72
- round: event.round,
73
- round_pick: event.round_pick,
74
- auto: event.auto,
75
- player: event.player.id
76
- }
77
- end
78
-
79
- def serialize_skip(event)
80
- {
81
- type: SKIP_EVENT,
82
- front_office: event.front_office.id,
83
- pick: event.pick,
84
- round: event.round,
85
- round_pick: event.round_pick
86
- }
87
- end
88
-
89
- # Deserialization
90
-
91
- def deserialize_player(player_hash)
92
- Org::Player.new(
93
- id: player_hash[:id],
94
- overall: player_hash[:overall],
95
- position: Org::Position.new(player_hash[:position])
96
- )
97
- end
98
-
99
- def deserialize_front_office(hash)
100
- Draft::FrontOffice.new(
101
- id: hash[:id],
102
- risk_level: hash[:risk_level].to_i,
103
- prioritized_positions: (hash[:prioritized_positions] || []).map { |c| Org::Position.new(c) },
104
- star_level: hash[:star_level].to_i
105
- )
106
- end
107
-
108
- def deserialize_front_offices(hashes)
109
- (hashes || []).map { |fo| deserialize_front_office(fo) }
110
- end
111
-
112
- def deserialize_players(hashes)
113
- (hashes || []).map { |hash| deserialize_player(hash) }
114
- end
115
-
116
- def deserialize_pick(hash, players:, front_office:)
117
- player_id = hash[:player]
118
- player = players.find { |p| p.id == player_id }
119
-
120
- Draft::Pick.new(
121
- front_office:,
122
- pick: hash[:pick],
123
- round: hash[:round],
124
- round_pick: hash[:round_pick],
125
- player:,
126
- auto: hash[:auto]
127
- )
128
- end
129
-
130
- def deserialize_skip(hash, front_office:)
131
- Draft::Skip.new(
132
- front_office:,
133
- pick: hash[:pick],
134
- round: hash[:round],
135
- round_pick: hash[:round_pick]
136
- )
137
- end
138
-
139
- def deserialize_events(hashes, players:, front_offices:)
140
- (hashes || []).map do |hash|
141
- front_office_id = hash[:front_office]
142
- front_office = front_offices.find { |fo| fo.id == front_office_id }
143
-
144
- case hash[:type]
145
- when PICK_EVENT
146
- deserialize_pick(hash, players:, front_office:)
147
- when SKIP_EVENT
148
- deserialize_skip(hash, front_office:)
149
- end
150
- end
151
- end
152
- end
153
- end
154
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Basketball
4
- module App
5
- # Can load and save Standings objects as JSON Documents.
6
- class StandingsRepository < DocumentRepository
7
- private
8
-
9
- def from_h(hash)
10
- Season::Standings.new(
11
- records: deserialize_records(hash[:records])
12
- )
13
- end
14
-
15
- def to_h(standings)
16
- {
17
- id: standings.id,
18
- records: serialize_records(standings.records)
19
- }
20
- end
21
-
22
- # Serialization
23
-
24
- def serialize_records(records)
25
- (records || []).map do |record|
26
- {
27
- id: record.id,
28
- details: serialize_details(record.details)
29
- }
30
- end
31
- end
32
-
33
- def serialize_details(details)
34
- (details || []).map do |detail|
35
- {
36
- date: detail.date.to_s,
37
- home: detail.home,
38
- opponent: detail.opponent.id,
39
- opponent_score: detail.opponent_score,
40
- score: detail.score
41
- }
42
- end
43
- end
44
-
45
- # Deserialization
46
-
47
- def deserialize_records(record_hashes)
48
- (record_hashes || []).map do |record_hash|
49
- Season::Record.new(
50
- id: record_hash[:id],
51
- details: deserialize_details(record_hash[:details])
52
- )
53
- end
54
- end
55
-
56
- def deserialize_details(detail_hashes)
57
- (detail_hashes || []).map do |detail_hash|
58
- Season::Detail.new(
59
- date: Date.parse(detail_hash[:date]),
60
- home: detail_hash[:home],
61
- opponent: Season::Opponent.new(id: detail_hash[:opponent]),
62
- opponent_score: detail_hash[:opponent_score].to_i,
63
- score: detail_hash[:score].to_i
64
- )
65
- end
66
- end
67
- end
68
- end
69
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Stores
4
- require_relative 'app/file_store'
5
- require_relative 'app/in_memory_store'
6
-
7
- # Repositories / Common
8
- require_relative 'app/document_repository'
9
-
10
- # Repositories / Implementations
11
- require_relative 'app/coordinator_repository'
12
- require_relative 'app/league_repository'
13
- require_relative 'app/room_repository'
14
- require_relative 'app/standings_repository'