Class: Basketball::Season::League

Inherits:
Entity
  • Object
show all
Includes:
HasDivisions
Defined in:
lib/basketball/season/league.rb

Overview

Describes a collection of conferences, divisions, teams, and players. Holds the rules which support adding teams and players to ensure the all the teams are cohesive, such as:

- preventing duplicate conferences
- preventing duplicate divisions
- preventing duplicate teams
- preventing double-signing players across teams

Defined Under Namespace

Classes: ConferenceAlreadyRegisteredError, NotSignedError

Instance Attribute Summary collapse

Attributes inherited from Entity

#id

Instance Method Summary collapse

Methods included from HasDivisions

#division?

Methods included from HasTeams

#team?

Methods included from HasPlayers

#player?

Methods inherited from Entity

#<=>, #==, #comparable_id, #hash

Constructor Details

#initialize(conferences: [], free_agents: []) ⇒ League

Returns a new instance of League.



20
21
22
23
24
25
26
27
28
# File 'lib/basketball/season/league.rb', line 20

def initialize(conferences: [], free_agents: [])
  super()

  @conferences = []
  @free_agents = []

  conferences.each { |c| register!(c) }
  free_agents.each { |p| free_agent!(p) }
end

Instance Attribute Details

#conferencesObject (readonly)

Returns the value of attribute conferences.



18
19
20
# File 'lib/basketball/season/league.rb', line 18

def conferences
  @conferences
end

#free_agentsObject (readonly)

Returns the value of attribute free_agents.



18
19
20
# File 'lib/basketball/season/league.rb', line 18

def free_agents
  @free_agents
end

Instance Method Details

#conference?(conference) ⇒ Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/basketball/season/league.rb', line 101

def conference?(conference)
  conferences.include?(conference)
end

#conference_for(team) ⇒ Object



117
118
119
# File 'lib/basketball/season/league.rb', line 117

def conference_for(team)
  conferences.find { |c| c.divisions.find { |d| d.teams.include?(team) } }
end

#cross_division_opponents_for(team) ⇒ Object

Same conference, different division



126
127
128
129
130
131
132
133
134
135
# File 'lib/basketball/season/league.rb', line 126

def cross_division_opponents_for(team)
  conference = conference_for(team)
  division   = division_for(team)

  return nil unless conference && division

  other_divisions = conference.divisions - [division]

  other_divisions.flat_map(&:teams)
end

#division_for(team) ⇒ Object



121
122
123
# File 'lib/basketball/season/league.rb', line 121

def division_for(team)
  conference_for(team)&.divisions&.find { |d| d.teams.include?(team) }
end

#divisionsObject



105
106
107
# File 'lib/basketball/season/league.rb', line 105

def divisions
  conferences.flat_map(&:divisions)
end

#free_agent!(player) ⇒ Object

Raises:

  • (ArgumentError)


38
39
40
41
42
43
44
45
# File 'lib/basketball/season/league.rb', line 38

def free_agent!(player)
  raise ArgumentError, 'player is required' unless player
  raise PlayerAlreadySignedError, "#{player} already registered" if player?(player)

  @free_agents << player

  self
end

#free_agent?(player) ⇒ Boolean

Returns:

  • (Boolean)


34
35
36
# File 'lib/basketball/season/league.rb', line 34

def free_agent?(player)
  free_agents.include?(player)
end

#playersObject



113
114
115
# File 'lib/basketball/season/league.rb', line 113

def players
  signed_players + free_agents
end

#register!(conference) ⇒ Object

Raises:

  • (ArgumentError)


90
91
92
93
94
95
96
97
98
99
# File 'lib/basketball/season/league.rb', line 90

def register!(conference)
  raise ArgumentError, 'conference is required' unless conference
  raise ConferenceAlreadyRegisteredError, "#{conference} already registered" if conference?(conference)

  assert_divisions_are_not_already_registered(conference.divisions)

  conferences << conference

  self
end

#release!(player) ⇒ Object

Raises:

  • (ArgumentError)


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/basketball/season/league.rb', line 47

def release!(player)
  raise ArgumentError, 'player is required' unless player
  raise NotSignedError, 'player is currently a free agent' if free_agent?(player)

  team = team_for_player(player)

  raise NotSignedError, 'player was not found to be signed by any team' unless team

  # We will use player as a comparable object but we will keep the same
  # player instance already in the league's object graph instead of replacing it
  # with the passed in instance.
  actual_player = team.release!(player)

  free_agents << actual_player

  self
end

#sign!(player:, team:) ⇒ Object

Raises:

  • (ArgumentError)


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/basketball/season/league.rb', line 73

def sign!(player:, team:)
  raise ArgumentError, 'player is required' unless player
  raise ArgumentError, 'team is required' unless team
  raise UnregisteredTeamError, "#{team} not registered" unless team?(team)
  raise PlayerAlreadySignedError, "#{player} already registered" if signed?(player)

  # If this player was a free agent then make sure we remove them from the free agent pool.
  # It is OK if they weren't, they can still be directly signed.
  actual_player = free_agent?(player) ? free_agents.delete(player) : player

  # It is OK to pass in a detached team as long as its equivalent resides in this
  # League's object graph.
  team_for(team.id).sign!(actual_player)

  self
end

#signed?(player) ⇒ Boolean

Returns:

  • (Boolean)


65
66
67
# File 'lib/basketball/season/league.rb', line 65

def signed?(player)
  signed_players.include?(player)
end

#signed_playersObject



69
70
71
# File 'lib/basketball/season/league.rb', line 69

def signed_players
  conferences.flat_map(&:players)
end

#team_for(id) ⇒ Object



137
138
139
# File 'lib/basketball/season/league.rb', line 137

def team_for(id)
  teams.find { |team| team.id == id }
end

#team_for_player(player) ⇒ Object



141
142
143
# File 'lib/basketball/season/league.rb', line 141

def team_for_player(player)
  teams.find { |t| t.signed?(player) }
end

#teamsObject



109
110
111
# File 'lib/basketball/season/league.rb', line 109

def teams
  conferences.flat_map(&:teams)
end

#to_sObject



30
31
32
# File 'lib/basketball/season/league.rb', line 30

def to_s
  conferences.map(&:to_s).join("\n")
end