basketball 0.0.8 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +9 -19
- data/CHANGELOG.md +1 -39
- data/README.md +75 -93
- data/basketball.gemspec +3 -6
- data/exe/{basketball-season-scheduling → basketball-coordinator} +1 -1
- data/exe/{basketball-draft → basketball-room} +1 -1
- data/lib/basketball/app/coordinator_cli.rb +250 -0
- data/lib/basketball/app/coordinator_repository.rb +114 -0
- data/lib/basketball/app/document_repository.rb +67 -0
- data/lib/basketball/app/file_store.rb +38 -0
- data/lib/basketball/app/in_memory_store.rb +42 -0
- data/lib/basketball/app/league_repository.rb +20 -0
- data/lib/basketball/app/league_serializable.rb +54 -0
- data/lib/basketball/{draft/cli.rb → app/room_cli.rb} +74 -80
- data/lib/basketball/app/room_repository.rb +149 -0
- data/lib/basketball/app.rb +20 -0
- data/lib/basketball/draft/assessment.rb +31 -0
- data/lib/basketball/draft/event.rb +3 -2
- data/lib/basketball/draft/front_office.rb +35 -28
- data/lib/basketball/draft/{pick_event.rb → pick.rb} +13 -6
- data/lib/basketball/draft/room.rb +119 -119
- data/lib/basketball/draft/{player_search.rb → scout.rb} +4 -9
- data/lib/basketball/draft/skip.rb +12 -0
- data/lib/basketball/draft.rb +13 -6
- data/lib/basketball/entity.rb +19 -10
- data/lib/basketball/org/league.rb +68 -0
- data/lib/basketball/org/player.rb +26 -0
- data/lib/basketball/{draft → org}/position.rb +3 -2
- data/lib/basketball/org/team.rb +38 -0
- data/lib/basketball/org.rb +12 -0
- data/lib/basketball/season/arena.rb +113 -0
- data/lib/basketball/season/calendar.rb +41 -72
- data/lib/basketball/season/coordinator.rb +186 -128
- data/lib/basketball/season/{preseason_game.rb → exhibition.rb} +2 -1
- data/lib/basketball/season/game.rb +15 -10
- data/lib/basketball/season/matchup.rb +27 -0
- data/lib/basketball/season/opponent.rb +15 -0
- data/lib/basketball/season/{season_game.rb → regular.rb} +2 -1
- data/lib/basketball/season/result.rb +37 -0
- data/lib/basketball/season.rb +12 -13
- data/lib/basketball/value_object.rb +8 -27
- data/lib/basketball/value_object_dsl.rb +30 -0
- data/lib/basketball/version.rb +1 -1
- data/lib/basketball.rb +9 -4
- metadata +37 -44
- data/lib/basketball/draft/league.rb +0 -70
- data/lib/basketball/draft/player.rb +0 -43
- data/lib/basketball/draft/room_serializer.rb +0 -186
- data/lib/basketball/draft/roster.rb +0 -37
- data/lib/basketball/draft/sim_event.rb +0 -23
- data/lib/basketball/draft/skip_event.rb +0 -13
- data/lib/basketball/season/calendar_serializer.rb +0 -94
- data/lib/basketball/season/conference.rb +0 -57
- data/lib/basketball/season/division.rb +0 -43
- data/lib/basketball/season/league.rb +0 -114
- data/lib/basketball/season/league_serializer.rb +0 -99
- data/lib/basketball/season/scheduling_cli.rb +0 -198
- data/lib/basketball/season/team.rb +0 -21
@@ -2,30 +2,35 @@
|
|
2
2
|
|
3
3
|
module Basketball
|
4
4
|
module Season
|
5
|
+
# Base class describing what all games have in common.
|
5
6
|
class Game < ValueObject
|
6
|
-
|
7
|
+
value_reader :date, :home_opponent, :away_opponent
|
7
8
|
|
8
|
-
def initialize(date:,
|
9
|
+
def initialize(date:, home_opponent:, away_opponent:)
|
9
10
|
super()
|
10
11
|
|
11
12
|
raise ArgumentError, 'date is required' unless date
|
12
|
-
raise ArgumentError, '
|
13
|
-
raise ArgumentError, '
|
14
|
-
raise ArgumentError, 'teams cannot play themselves' if
|
13
|
+
raise ArgumentError, 'home_opponent is required' unless home_opponent
|
14
|
+
raise ArgumentError, 'away_opponent is required' unless away_opponent
|
15
|
+
raise ArgumentError, 'teams cannot play themselves' if home_opponent == away_opponent
|
15
16
|
|
16
|
-
@date
|
17
|
-
@
|
18
|
-
@
|
17
|
+
@date = date
|
18
|
+
@home_opponent = home_opponent
|
19
|
+
@away_opponent = away_opponent
|
19
20
|
|
20
21
|
freeze
|
21
22
|
end
|
22
23
|
|
24
|
+
def for?(team)
|
25
|
+
teams.include?(team)
|
26
|
+
end
|
27
|
+
|
23
28
|
def teams
|
24
|
-
[
|
29
|
+
[home_opponent, away_opponent]
|
25
30
|
end
|
26
31
|
|
27
32
|
def to_s
|
28
|
-
"#{date} - #{
|
33
|
+
"#{date} - #{away_opponent} at #{home_opponent}"
|
29
34
|
end
|
30
35
|
end
|
31
36
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Basketball
|
4
|
+
module Season
|
5
|
+
# A Matchup is a late materialization of a game. While a game is a skeleton for a future
|
6
|
+
# matchup, it does not materialize until game time (rosters could change right up until game time).
|
7
|
+
class Matchup
|
8
|
+
class PlayersOnBothTeamsError < StandardError; end
|
9
|
+
|
10
|
+
attr_reader :game, :home_players, :away_players
|
11
|
+
|
12
|
+
def initialize(game:, home_players: [], away_players: [])
|
13
|
+
raise ArgumentError, 'game is required' unless game
|
14
|
+
|
15
|
+
@game = game
|
16
|
+
@home_players = home_players.uniq
|
17
|
+
@away_players = away_players.uniq
|
18
|
+
|
19
|
+
if home_players.intersect?(away_players)
|
20
|
+
raise PlayersOnBothTeamsError, 'players cannot be on both home and away team'
|
21
|
+
end
|
22
|
+
|
23
|
+
freeze
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Basketball
|
4
|
+
module Season
|
5
|
+
# Represents a team without a roster. Equal to a team by identity.
|
6
|
+
# A team's roster will not be known until the last minute (when it is game time).
|
7
|
+
class Opponent < Entity
|
8
|
+
def initialize(id:)
|
9
|
+
super(id)
|
10
|
+
|
11
|
+
freeze
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Basketball
|
4
|
+
module Season
|
5
|
+
# Base class describing the end result of a game. This should/could be sub-classed to include
|
6
|
+
# more sport-specific information.
|
7
|
+
class Result
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
class CannotTieError < StandardError; end
|
11
|
+
|
12
|
+
attr_reader :game, :home_score, :away_score
|
13
|
+
|
14
|
+
def_delegators :game, :date, :home_opponent, :away_opponent, :teams
|
15
|
+
|
16
|
+
def initialize(game:, home_score:, away_score:)
|
17
|
+
raise ArgumentError, 'game is required' unless game
|
18
|
+
raise CannotTieError, "#{game} ended in a tie" if home_score == away_score
|
19
|
+
|
20
|
+
@game = game
|
21
|
+
@home_score = home_score.to_i
|
22
|
+
@away_score = away_score.to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
"#{game.date} - #{away_opponent} (#{away_score}) at #{home_opponent} (#{home_score})"
|
27
|
+
end
|
28
|
+
|
29
|
+
def ==(other)
|
30
|
+
game == other.game &&
|
31
|
+
home_score == other.home_score &&
|
32
|
+
away_score == other.away_score
|
33
|
+
end
|
34
|
+
alias eql? ==
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/basketball/season.rb
CHANGED
@@ -1,17 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
# Common
|
4
|
+
require_relative 'season/arena'
|
5
|
+
require_relative 'season/calendar'
|
6
|
+
require_relative 'season/result'
|
7
|
+
require_relative 'season/game'
|
8
|
+
require_relative 'season/matchup'
|
9
|
+
require_relative 'season/opponent'
|
4
10
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
class DivisionAlreadyRegisteredError < StandardError; end
|
9
|
-
class TeamAlreadyRegisteredError < StandardError; end
|
11
|
+
# Game Subclasses
|
12
|
+
require_relative 'season/exhibition'
|
13
|
+
require_relative 'season/regular'
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
class BadTeamsSizeError < StandardError; end
|
14
|
-
|
15
|
-
class UnknownTeamError < StandardError; end
|
16
|
-
end
|
17
|
-
end
|
15
|
+
# Specific
|
16
|
+
require_relative 'season/coordinator'
|
@@ -1,34 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'value_object_dsl'
|
4
|
+
|
3
5
|
module Basketball
|
6
|
+
# A Value Object is something that has no specific identity, instead its identity is the sum of
|
7
|
+
# the attribute values. Changing one will change the entire object's identity.
|
8
|
+
# Comes with a very simple DSL provided by ValueObjectDSL for specifying properties along with
|
9
|
+
# base equality and sorting methods.
|
4
10
|
class ValueObject
|
5
11
|
include Comparable
|
6
|
-
|
7
|
-
class << self
|
8
|
-
def all_value_keys
|
9
|
-
@all_value_keys ||= ancestors.flat_map do |ancestor|
|
10
|
-
if ancestor < Basketball::ValueObject
|
11
|
-
ancestor.value_keys
|
12
|
-
else
|
13
|
-
[]
|
14
|
-
end
|
15
|
-
end.uniq.sort
|
16
|
-
end
|
17
|
-
|
18
|
-
def all_sorted_value_keys
|
19
|
-
all_value_keys.sort
|
20
|
-
end
|
21
|
-
|
22
|
-
def value_keys
|
23
|
-
@value_keys ||= []
|
24
|
-
end
|
25
|
-
|
26
|
-
def attr_reader_value(*keys)
|
27
|
-
keys.each { |k| value_keys << k.to_sym }
|
28
|
-
|
29
|
-
attr_reader(*keys)
|
30
|
-
end
|
31
|
-
end
|
12
|
+
extend ValueObjectDSL
|
32
13
|
|
33
14
|
def to_s
|
34
15
|
to_h.map { |k, v| "#{k}: #{v}" }.join(', ')
|
@@ -52,7 +33,7 @@ module Basketball
|
|
52
33
|
alias eql? ==
|
53
34
|
|
54
35
|
def hash
|
55
|
-
all_sorted_values.
|
36
|
+
all_sorted_values.hash
|
56
37
|
end
|
57
38
|
|
58
39
|
def all_sorted_values
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Basketball
|
4
|
+
# Class-level methods that extend core Ruby attr_* methods.
|
5
|
+
module ValueObjectDSL
|
6
|
+
def all_value_keys
|
7
|
+
@all_value_keys ||= ancestors.flat_map do |ancestor|
|
8
|
+
if ancestor < Basketball::ValueObject
|
9
|
+
ancestor.value_keys
|
10
|
+
else
|
11
|
+
[]
|
12
|
+
end
|
13
|
+
end.uniq.sort
|
14
|
+
end
|
15
|
+
|
16
|
+
def all_sorted_value_keys
|
17
|
+
all_value_keys.sort
|
18
|
+
end
|
19
|
+
|
20
|
+
def value_keys
|
21
|
+
@value_keys ||= []
|
22
|
+
end
|
23
|
+
|
24
|
+
def value_reader(*keys)
|
25
|
+
keys.each { |k| value_keys << k.to_sym }
|
26
|
+
|
27
|
+
attr_reader(*keys)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/basketball/version.rb
CHANGED
data/lib/basketball.rb
CHANGED
@@ -1,16 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'date'
|
4
4
|
require 'fileutils'
|
5
5
|
require 'forwardable'
|
6
6
|
require 'json'
|
7
|
-
require 'securerandom'
|
8
7
|
require 'slop'
|
9
8
|
|
10
|
-
#
|
9
|
+
# Generic
|
11
10
|
require_relative 'basketball/entity'
|
12
11
|
require_relative 'basketball/value_object'
|
13
12
|
|
14
|
-
#
|
13
|
+
# Dependent on Generic
|
14
|
+
require_relative 'basketball/org'
|
15
|
+
|
16
|
+
# Dependent on Org
|
15
17
|
require_relative 'basketball/draft'
|
16
18
|
require_relative 'basketball/season'
|
19
|
+
|
20
|
+
# Dependent on All
|
21
|
+
require_relative 'basketball/app'
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: basketball
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
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-
|
11
|
+
date: 2023-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: faker
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '3.2'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '3.2'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: slop
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,15 +24,15 @@ dependencies:
|
|
38
24
|
- - "~>"
|
39
25
|
- !ruby/object:Gem::Version
|
40
26
|
version: '4.10'
|
41
|
-
description:
|
42
|
-
|
43
|
-
|
44
|
-
|
27
|
+
description: " This library is meant to serve as the domain for a basketball league/season
|
28
|
+
simulator/turn-based game. It models core ideas such as: players, general managers,
|
29
|
+
draft strategy, drafting, season generation, season simultation, playoff generation,
|
30
|
+
playoff simulation, and more.\n"
|
45
31
|
email:
|
46
32
|
- mattruggio@icloud.com
|
47
33
|
executables:
|
48
|
-
- basketball-
|
49
|
-
- basketball-
|
34
|
+
- basketball-coordinator
|
35
|
+
- basketball-room
|
50
36
|
extensions: []
|
51
37
|
extra_rdoc_files: []
|
52
38
|
files:
|
@@ -62,38 +48,45 @@ files:
|
|
62
48
|
- README.md
|
63
49
|
- Rakefile
|
64
50
|
- basketball.gemspec
|
65
|
-
- exe/basketball-
|
66
|
-
- exe/basketball-
|
51
|
+
- exe/basketball-coordinator
|
52
|
+
- exe/basketball-room
|
67
53
|
- lib/basketball.rb
|
54
|
+
- lib/basketball/app.rb
|
55
|
+
- lib/basketball/app/coordinator_cli.rb
|
56
|
+
- lib/basketball/app/coordinator_repository.rb
|
57
|
+
- lib/basketball/app/document_repository.rb
|
58
|
+
- lib/basketball/app/file_store.rb
|
59
|
+
- lib/basketball/app/in_memory_store.rb
|
60
|
+
- lib/basketball/app/league_repository.rb
|
61
|
+
- lib/basketball/app/league_serializable.rb
|
62
|
+
- lib/basketball/app/room_cli.rb
|
63
|
+
- lib/basketball/app/room_repository.rb
|
68
64
|
- lib/basketball/draft.rb
|
69
|
-
- lib/basketball/draft/
|
65
|
+
- lib/basketball/draft/assessment.rb
|
70
66
|
- lib/basketball/draft/event.rb
|
71
67
|
- lib/basketball/draft/front_office.rb
|
72
|
-
- lib/basketball/draft/
|
73
|
-
- lib/basketball/draft/pick_event.rb
|
74
|
-
- lib/basketball/draft/player.rb
|
75
|
-
- lib/basketball/draft/player_search.rb
|
76
|
-
- lib/basketball/draft/position.rb
|
68
|
+
- lib/basketball/draft/pick.rb
|
77
69
|
- lib/basketball/draft/room.rb
|
78
|
-
- lib/basketball/draft/
|
79
|
-
- lib/basketball/draft/
|
80
|
-
- lib/basketball/draft/sim_event.rb
|
81
|
-
- lib/basketball/draft/skip_event.rb
|
70
|
+
- lib/basketball/draft/scout.rb
|
71
|
+
- lib/basketball/draft/skip.rb
|
82
72
|
- lib/basketball/entity.rb
|
73
|
+
- lib/basketball/org.rb
|
74
|
+
- lib/basketball/org/league.rb
|
75
|
+
- lib/basketball/org/player.rb
|
76
|
+
- lib/basketball/org/position.rb
|
77
|
+
- lib/basketball/org/team.rb
|
83
78
|
- lib/basketball/season.rb
|
79
|
+
- lib/basketball/season/arena.rb
|
84
80
|
- lib/basketball/season/calendar.rb
|
85
|
-
- lib/basketball/season/calendar_serializer.rb
|
86
|
-
- lib/basketball/season/conference.rb
|
87
81
|
- lib/basketball/season/coordinator.rb
|
88
|
-
- lib/basketball/season/
|
82
|
+
- lib/basketball/season/exhibition.rb
|
89
83
|
- lib/basketball/season/game.rb
|
90
|
-
- lib/basketball/season/
|
91
|
-
- lib/basketball/season/
|
92
|
-
- lib/basketball/season/
|
93
|
-
- lib/basketball/season/
|
94
|
-
- lib/basketball/season/season_game.rb
|
95
|
-
- lib/basketball/season/team.rb
|
84
|
+
- lib/basketball/season/matchup.rb
|
85
|
+
- lib/basketball/season/opponent.rb
|
86
|
+
- lib/basketball/season/regular.rb
|
87
|
+
- lib/basketball/season/result.rb
|
96
88
|
- lib/basketball/value_object.rb
|
89
|
+
- lib/basketball/value_object_dsl.rb
|
97
90
|
- lib/basketball/version.rb
|
98
91
|
homepage: https://github.com/mattruggio/basketball
|
99
92
|
licenses:
|
@@ -123,5 +116,5 @@ requirements: []
|
|
123
116
|
rubygems_version: 3.4.6
|
124
117
|
signing_key:
|
125
118
|
specification_version: 4
|
126
|
-
summary: Basketball
|
119
|
+
summary: Basketball Simulation Domain Model
|
127
120
|
test_files: []
|
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'roster'
|
4
|
-
|
5
|
-
module Basketball
|
6
|
-
module Draft
|
7
|
-
class League
|
8
|
-
class RosterNotFoundError < StandardError; end
|
9
|
-
class RosterAlreadyAddedError < StandardError; end
|
10
|
-
|
11
|
-
attr_reader :free_agents, :rosters
|
12
|
-
|
13
|
-
def initialize(free_agents: [], front_offices: [])
|
14
|
-
@rosters = []
|
15
|
-
@free_agents = []
|
16
|
-
|
17
|
-
front_offices.each { |front_office| add_roster(front_office) }
|
18
|
-
free_agents.each { |p| register!(player: p) }
|
19
|
-
|
20
|
-
freeze
|
21
|
-
end
|
22
|
-
|
23
|
-
def roster(front_office)
|
24
|
-
rosters.find { |r| r == front_office }
|
25
|
-
end
|
26
|
-
|
27
|
-
def register!(player:, front_office: nil)
|
28
|
-
raise PlayerRequiredError, 'player is required' unless player
|
29
|
-
|
30
|
-
rosters.each do |roster|
|
31
|
-
if roster.registered?(player)
|
32
|
-
raise PlayerAlreadyRegisteredError,
|
33
|
-
"#{player} already registered to: #{roster.id}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
if free_agents.include?(player)
|
38
|
-
raise PlayerAlreadyRegisteredError,
|
39
|
-
"#{player} already registered as a free agent"
|
40
|
-
end
|
41
|
-
|
42
|
-
if front_office
|
43
|
-
roster = roster(front_office)
|
44
|
-
|
45
|
-
raise RosterNotFoundError, "Roster not found for: #{front_office}" unless roster
|
46
|
-
|
47
|
-
roster.sign!(player)
|
48
|
-
else
|
49
|
-
free_agents << player
|
50
|
-
end
|
51
|
-
|
52
|
-
self
|
53
|
-
end
|
54
|
-
|
55
|
-
def to_s
|
56
|
-
(['League'] + rosters.map(&:to_s)).join("\n")
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def add_roster(front_office)
|
62
|
-
raise RosterAlreadyAddedError, "#{front_office} already added" if rosters.include?(front_office)
|
63
|
-
|
64
|
-
rosters << Roster.new(id: front_office.id, name: front_office.name)
|
65
|
-
|
66
|
-
self
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Basketball
|
4
|
-
module Draft
|
5
|
-
class Player < Entity
|
6
|
-
STAR_THRESHOLD = 75
|
7
|
-
OVERALL_STAR_INDICATOR = '⭐'
|
8
|
-
|
9
|
-
private_constant :STAR_THRESHOLD, :OVERALL_STAR_INDICATOR
|
10
|
-
|
11
|
-
attr_reader :first_name, :last_name, :position, :overall
|
12
|
-
|
13
|
-
def initialize(id:, position:, first_name: '', last_name: '', overall: 0)
|
14
|
-
super(id)
|
15
|
-
|
16
|
-
raise ArgumentError, 'position is required' unless position
|
17
|
-
|
18
|
-
@first_name = first_name.to_s
|
19
|
-
@last_name = last_name.to_s
|
20
|
-
@position = position
|
21
|
-
@overall = overall.to_i
|
22
|
-
|
23
|
-
freeze
|
24
|
-
end
|
25
|
-
|
26
|
-
def full_name
|
27
|
-
"#{first_name.strip} #{last_name.strip}".strip
|
28
|
-
end
|
29
|
-
|
30
|
-
def to_s
|
31
|
-
"[#{super}] #{full_name} (#{position}) #{overall} #{star_indicators.join(', ')}".strip
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def star_indicators
|
37
|
-
[].tap do |indicators|
|
38
|
-
indicators << OVERALL_STAR_INDICATOR if overall >= STAR_THRESHOLD
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|