lib/basketball/org/league.rb in basketball-0.0.10 vs lib/basketball/org/league.rb in basketball-0.0.11

- old
+ new

@@ -1,68 +1,100 @@ # frozen_string_literal: true module Basketball module Org - # Describes a collection of teams and players. Holds the rules which support - # adding teams and players to ensure the all the teams are cohesive, such as: + # 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 class League < Entity - class TeamAlreadyRegisteredError < StandardError; end - class UnregisteredTeamError < StandardError; end + include HasDivisions - attr_reader :teams + class ConferenceAlreadyRegisteredError < StandardError; end - def initialize(teams: []) + alias signed? player? + + attr_reader :conferences + + def initialize(conferences: []) super() - @teams = [] + @conferences = [] - teams.each { |team| register!(team) } + conferences.each { |c| register!(c) } end def to_s - teams.map(&:to_s).join("\n") + conferences.map(&:to_s).join("\n") end def sign!(player:, team:) raise ArgumentError, 'player is required' unless player raise ArgumentError, 'team is required' unless team - raise UnregisteredTeamError, "#{team} is not registered" unless registered?(team) - raise PlayerAlreadySignedError, "#{player} is already signed" if signed?(player) + raise UnregisteredTeamError, "#{team} not registered" unless team?(team) + raise PlayerAlreadySignedError, "#{player} already registered" if player?(player) - team.sign!(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!(player) self end - def signed?(player) - players.include?(player) + 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 + def conference?(conference) + conferences.include?(conference) + end + + def divisions + conferences.flat_map(&:divisions) + end + + def teams + conferences.flat_map(&:teams) + end + def players - teams.flat_map(&:players) + conferences.flat_map(&:players) end - def not_registered?(team) - !registered?(team) + def conference_for(team) + conferences.find { |c| c.divisions.find { |d| d.teams.include?(team) } } end - def registered?(team) - teams.include?(team) + def division_for(team) + conference_for(team)&.divisions&.find { |d| d.teams.include?(team) } end - def register!(team) - raise ArgumentError, 'team is required' unless team - raise TeamAlreadyRegisteredError, "#{team} already registered" if registered?(team) + # Same conference, different division + def cross_division_opponents_for(team) + conference = conference_for(team) + division = division_for(team) - team.players.each do |player| - raise PlayerAlreadySignedError, "#{player} already signed" if signed?(player) - end + return nil unless conference && division - teams << team + other_divisions = conference.divisions - [division] - self + other_divisions.flat_map(&:teams) + end + + private + + def team_for(id) + teams.find { |team| team.id == id } end end end end