nba 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/AGENTS.md +362 -0
- data/CHANGELOG.md +169 -0
- data/CLAUDE.md +1 -0
- data/LICENSE +21 -0
- data/README.md +501 -101
- data/bin/console +10 -0
- data/bin/setup +6 -0
- data/exe/nba +8 -0
- data/lib/nba/all_time_leader.rb +77 -0
- data/lib/nba/all_time_leaders.rb +185 -0
- data/lib/nba/assist_leader.rb +92 -0
- data/lib/nba/assist_leaders.rb +64 -0
- data/lib/nba/assist_tracker.rb +108 -0
- data/lib/nba/assist_tracker_entry.rb +206 -0
- data/lib/nba/award.rb +128 -0
- data/lib/nba/box_score.rb +2 -0
- data/lib/nba/box_score_advanced.rb +114 -0
- data/lib/nba/box_score_advanced_player_stat.rb +297 -0
- data/lib/nba/box_score_advanced_team_stat.rb +237 -0
- data/lib/nba/box_score_advanced_v3.rb +124 -0
- data/lib/nba/box_score_defensive_player_stat.rb +281 -0
- data/lib/nba/box_score_defensive_team_stat.rb +85 -0
- data/lib/nba/box_score_defensive_v2.rb +190 -0
- data/lib/nba/box_score_four_factors.rb +91 -0
- data/lib/nba/box_score_four_factors_player_stat.rb +185 -0
- data/lib/nba/box_score_four_factors_team_stat.rb +141 -0
- data/lib/nba/box_score_four_factors_v3.rb +133 -0
- data/lib/nba/box_score_hustle.rb +226 -0
- data/lib/nba/box_score_hustle_player_stat.rb +233 -0
- data/lib/nba/box_score_hustle_team_stat.rb +189 -0
- data/lib/nba/box_score_matchup_stat.rb +417 -0
- data/lib/nba/box_score_matchups_v3.rb +184 -0
- data/lib/nba/box_score_misc.rb +100 -0
- data/lib/nba/box_score_misc_player_stat.rb +217 -0
- data/lib/nba/box_score_misc_team_stat.rb +173 -0
- data/lib/nba/box_score_misc_v3.rb +163 -0
- data/lib/nba/box_score_player_stat.rb +273 -0
- data/lib/nba/box_score_player_track.rb +223 -0
- data/lib/nba/box_score_player_track_stat.rb +273 -0
- data/lib/nba/box_score_player_track_team_stat.rb +229 -0
- data/lib/nba/box_score_scoring.rb +103 -0
- data/lib/nba/box_score_scoring_player_stat.rb +241 -0
- data/lib/nba/box_score_scoring_team_stat.rb +197 -0
- data/lib/nba/box_score_scoring_v3.rb +170 -0
- data/lib/nba/box_score_similarity_score.rb +119 -0
- data/lib/nba/box_score_similarity_stat.rb +76 -0
- data/lib/nba/box_score_starter_bench_stat.rb +257 -0
- data/lib/nba/box_score_summary.rb +285 -0
- data/lib/nba/box_score_summary_v2.rb +202 -0
- data/lib/nba/box_score_summary_v3.rb +120 -0
- data/lib/nba/box_score_summary_v3_data.rb +419 -0
- data/lib/nba/box_score_team_stat.rb +229 -0
- data/lib/nba/box_score_traditional.rb +101 -0
- data/lib/nba/box_score_traditional_v3.rb +195 -0
- data/lib/nba/box_score_usage.rb +102 -0
- data/lib/nba/box_score_usage_player_stat.rb +265 -0
- data/lib/nba/box_score_usage_team_stat.rb +221 -0
- data/lib/nba/box_score_usage_v3.rb +169 -0
- data/lib/nba/box_score_v3_helpers.rb +144 -0
- data/lib/nba/career_stats.rb +217 -0
- data/lib/nba/cli/display/player_display.rb +98 -0
- data/lib/nba/cli/display.rb +178 -0
- data/lib/nba/cli/formatters/game_formatters.rb +86 -0
- data/lib/nba/cli/formatters/leaders_formatters.rb +26 -0
- data/lib/nba/cli/formatters/player_formatters.rb +52 -0
- data/lib/nba/cli/formatters/standings_formatters.rb +26 -0
- data/lib/nba/cli/formatters/team_formatters.rb +67 -0
- data/lib/nba/cli/formatters/time_formatters.rb +82 -0
- data/lib/nba/cli/formatters.rb +56 -0
- data/lib/nba/cli/helpers.rb +135 -0
- data/lib/nba/cli.rb +171 -20
- data/lib/nba/client.rb +35 -0
- data/lib/nba/collection.rb +89 -0
- data/lib/nba/college_player_stat.rb +200 -0
- data/lib/nba/common_player_info.rb +142 -0
- data/lib/nba/common_playoff_series.rb +90 -0
- data/lib/nba/common_team_years.rb +113 -0
- data/lib/nba/conference.rb +39 -0
- data/lib/nba/connection.rb +84 -0
- data/lib/nba/cume_stats_player.rb +358 -0
- data/lib/nba/cume_stats_player_game.rb +217 -0
- data/lib/nba/cume_stats_player_games.rb +99 -0
- data/lib/nba/cume_stats_player_games_entry.rb +25 -0
- data/lib/nba/cume_stats_player_total.rb +481 -0
- data/lib/nba/cume_stats_team.rb +349 -0
- data/lib/nba/cume_stats_team_games.rb +145 -0
- data/lib/nba/cume_stats_team_games_entry.rb +25 -0
- data/lib/nba/cume_stats_team_player.rb +485 -0
- data/lib/nba/cume_stats_team_total.rb +267 -0
- data/lib/nba/data.rb +73 -0
- data/lib/nba/defense_hub.rb +109 -0
- data/lib/nba/defense_hub_stat.rb +57 -0
- data/lib/nba/defensive_shot_stat.rb +102 -0
- data/lib/nba/division.rb +49 -0
- data/lib/nba/draft_board.rb +126 -0
- data/lib/nba/draft_board_pick.rb +173 -0
- data/lib/nba/draft_combine_anthro_measurement.rb +163 -0
- data/lib/nba/draft_combine_drill_result.rb +115 -0
- data/lib/nba/draft_combine_drill_results.rb +112 -0
- data/lib/nba/draft_combine_non_stationary_shooting.rb +268 -0
- data/lib/nba/draft_combine_non_stationary_shooting_result.rb +355 -0
- data/lib/nba/draft_combine_player_anthro.rb +133 -0
- data/lib/nba/draft_combine_spot_shooting.rb +243 -0
- data/lib/nba/draft_combine_spot_shooting_result.rb +419 -0
- data/lib/nba/draft_combine_stat.rb +211 -0
- data/lib/nba/draft_combine_stats.rb +160 -0
- data/lib/nba/draft_history.rb +142 -0
- data/lib/nba/draft_pick.rb +154 -0
- data/lib/nba/dunk_score_leader.rb +93 -0
- data/lib/nba/dunk_score_leaders.rb +77 -0
- data/lib/nba/estimated_metrics_stat.rb +152 -0
- data/lib/nba/fantasy_profile_stat.rb +142 -0
- data/lib/nba/fantasy_widget.rb +72 -0
- data/lib/nba/fantasy_widget_player.rb +98 -0
- data/lib/nba/found_game.rb +260 -0
- data/lib/nba/franchise.rb +136 -0
- data/lib/nba/franchise_history.rb +142 -0
- data/lib/nba/franchise_leader.rb +147 -0
- data/lib/nba/franchise_leaders.rb +162 -0
- data/lib/nba/franchise_player.rb +224 -0
- data/lib/nba/franchise_players.rb +147 -0
- data/lib/nba/game.rb +80 -64
- data/lib/nba/game_log.rb +349 -0
- data/lib/nba/game_rotation.rb +152 -0
- data/lib/nba/game_streak.rb +102 -0
- data/lib/nba/games.rb +46 -0
- data/lib/nba/home_page_leader.rb +99 -0
- data/lib/nba/home_page_leaders.rb +75 -0
- data/lib/nba/home_page_stat.rb +57 -0
- data/lib/nba/home_page_v2.rb +110 -0
- data/lib/nba/hustle_stats_box_score.rb +182 -0
- data/lib/nba/infographic_fan_duel_player.rb +139 -0
- data/lib/nba/infographic_fan_duel_player_stat.rb +311 -0
- data/lib/nba/ist_standing.rb +167 -0
- data/lib/nba/ist_standings.rb +81 -0
- data/lib/nba/leader.rb +103 -0
- data/lib/nba/leaders.rb +110 -0
- data/lib/nba/leaders_tile.rb +57 -0
- data/lib/nba/leaders_tiles.rb +90 -0
- data/lib/nba/league.rb +37 -0
- data/lib/nba/league_dash_lineup_stat.rb +270 -0
- data/lib/nba/league_dash_lineups.rb +177 -0
- data/lib/nba/league_dash_opp_pt_shot.rb +150 -0
- data/lib/nba/league_dash_player_bio_stat.rb +217 -0
- data/lib/nba/league_dash_player_bio_stats.rb +164 -0
- data/lib/nba/league_dash_player_clutch.rb +212 -0
- data/lib/nba/league_dash_player_clutch_stat.rb +271 -0
- data/lib/nba/league_dash_player_pt_shot.rb +152 -0
- data/lib/nba/league_dash_player_pt_shot_stat.rb +193 -0
- data/lib/nba/league_dash_player_shot_location_stat.rb +265 -0
- data/lib/nba/league_dash_player_shot_locations.rb +210 -0
- data/lib/nba/league_dash_player_stat.rb +306 -0
- data/lib/nba/league_dash_player_stats.rb +176 -0
- data/lib/nba/league_dash_pt_defend.rb +160 -0
- data/lib/nba/league_dash_pt_defend_stat.rb +145 -0
- data/lib/nba/league_dash_pt_stats.rb +152 -0
- data/lib/nba/league_dash_pt_stats_stat.rb +169 -0
- data/lib/nba/league_dash_pt_team_defend.rb +158 -0
- data/lib/nba/league_dash_pt_team_defend_stat.rb +110 -0
- data/lib/nba/league_dash_team_clutch.rb +211 -0
- data/lib/nba/league_dash_team_clutch_stat.rb +237 -0
- data/lib/nba/league_dash_team_pt_shot.rb +150 -0
- data/lib/nba/league_dash_team_pt_shot_stat.rb +166 -0
- data/lib/nba/league_dash_team_shot_location_stat.rb +230 -0
- data/lib/nba/league_dash_team_shot_locations.rb +208 -0
- data/lib/nba/league_dash_team_stat.rb +275 -0
- data/lib/nba/league_dash_team_stats.rb +172 -0
- data/lib/nba/league_game_finder.rb +170 -0
- data/lib/nba/league_game_log.rb +224 -0
- data/lib/nba/league_hustle_stats_player.rb +161 -0
- data/lib/nba/league_hustle_stats_player_stat.rb +253 -0
- data/lib/nba/league_hustle_stats_team.rb +157 -0
- data/lib/nba/league_hustle_stats_team_stat.rb +179 -0
- data/lib/nba/league_lineup_viz.rb +184 -0
- data/lib/nba/league_lineup_viz_stat.rb +214 -0
- data/lib/nba/league_player_on_details.rb +175 -0
- data/lib/nba/league_player_on_details_stat.rb +313 -0
- data/lib/nba/league_season_matchup_stat.rb +241 -0
- data/lib/nba/league_season_matchups.rb +181 -0
- data/lib/nba/league_standing.rb +284 -0
- data/lib/nba/league_standings.rb +159 -0
- data/lib/nba/league_wide_shot_stat.rb +62 -0
- data/lib/nba/live_action.rb +240 -0
- data/lib/nba/live_box_score.rb +143 -0
- data/lib/nba/live_connection.rb +84 -0
- data/lib/nba/live_game.rb +230 -0
- data/lib/nba/live_play_by_play.rb +120 -0
- data/lib/nba/live_player_stat.rb +276 -0
- data/lib/nba/live_scoreboard.rb +102 -0
- data/lib/nba/matchup_rollup.rb +98 -0
- data/lib/nba/matchups_rollup.rb +81 -0
- data/lib/nba/pass_stat.rb +209 -0
- data/lib/nba/play.rb +258 -0
- data/lib/nba/play_by_play.rb +85 -0
- data/lib/nba/play_by_play_v3.rb +91 -0
- data/lib/nba/play_type_stat.rb +206 -0
- data/lib/nba/player.rb +242 -24
- data/lib/nba/player_awards.rb +110 -0
- data/lib/nba/player_career_by_college.rb +86 -0
- data/lib/nba/player_career_by_college_rollup.rb +143 -0
- data/lib/nba/player_career_stats.rb +77 -0
- data/lib/nba/player_compare.rb +156 -0
- data/lib/nba/player_comparison_stat.rb +242 -0
- data/lib/nba/player_dash_pt_pass.rb +164 -0
- data/lib/nba/player_dash_pt_reb.rb +235 -0
- data/lib/nba/player_dash_pt_shot_defend.rb +119 -0
- data/lib/nba/player_dash_pt_shots.rb +279 -0
- data/lib/nba/player_dashboard.rb +259 -0
- data/lib/nba/player_dashboard_stat.rb +248 -0
- data/lib/nba/player_estimated_metrics.rb +84 -0
- data/lib/nba/player_fantasy_profile_bar_graph.rb +147 -0
- data/lib/nba/player_game_log.rb +72 -0
- data/lib/nba/player_game_logs.rb +117 -0
- data/lib/nba/player_game_streak_finder.rb +108 -0
- data/lib/nba/player_index.rb +135 -0
- data/lib/nba/player_index_entry.rb +266 -0
- data/lib/nba/player_info.rb +225 -0
- data/lib/nba/player_next_n_games.rb +64 -0
- data/lib/nba/player_profile_v2.rb +169 -0
- data/lib/nba/player_vs_player.rb +153 -0
- data/lib/nba/players.rb +107 -0
- data/lib/nba/playoff_matchup.rb +84 -0
- data/lib/nba/playoff_picture.rb +98 -0
- data/lib/nba/playoff_series.rb +76 -0
- data/lib/nba/position.rb +48 -0
- data/lib/nba/rebound_stat.rb +189 -0
- data/lib/nba/response_parser.rb +116 -0
- data/lib/nba/roster.rb +74 -0
- data/lib/nba/rotation_entry.rb +154 -0
- data/lib/nba/schedule.rb +183 -0
- data/lib/nba/schedule_international.rb +182 -0
- data/lib/nba/scheduled_game.rb +240 -0
- data/lib/nba/scoreboard.rb +183 -0
- data/lib/nba/scoreboard_v3.rb +104 -0
- data/lib/nba/shot.rb +208 -0
- data/lib/nba/shot_chart.rb +75 -0
- data/lib/nba/shot_chart_league_wide.rb +102 -0
- data/lib/nba/shot_chart_lineup_detail.rb +109 -0
- data/lib/nba/shot_stat.rb +174 -0
- data/lib/nba/standing.rb +129 -0
- data/lib/nba/standings.rb +75 -0
- data/lib/nba/static.rb +107 -0
- data/lib/nba/synergy_play_types.rb +211 -0
- data/lib/nba/team.rb +203 -127
- data/lib/nba/team_and_players_vs_players.rb +227 -0
- data/lib/nba/team_and_players_vs_players_stat.rb +155 -0
- data/lib/nba/team_dash_pt_pass.rb +157 -0
- data/lib/nba/team_dash_pt_reb.rb +216 -0
- data/lib/nba/team_dash_pt_shots.rb +244 -0
- data/lib/nba/team_dashboard.rb +275 -0
- data/lib/nba/team_dashboard_stat.rb +248 -0
- data/lib/nba/team_detail.rb +117 -0
- data/lib/nba/team_details.rb +173 -0
- data/lib/nba/team_estimated_metrics.rb +91 -0
- data/lib/nba/team_estimated_metrics_stat.rb +146 -0
- data/lib/nba/team_game_log.rb +143 -0
- data/lib/nba/team_game_log_entry.rb +246 -0
- data/lib/nba/team_game_log_stat.rb +275 -0
- data/lib/nba/team_game_logs.rb +163 -0
- data/lib/nba/team_game_streak.rb +111 -0
- data/lib/nba/team_game_streak_finder.rb +109 -0
- data/lib/nba/team_historical_leader.rb +207 -0
- data/lib/nba/team_historical_leaders.rb +98 -0
- data/lib/nba/team_historical_record.rb +139 -0
- data/lib/nba/team_info.rb +150 -0
- data/lib/nba/team_info_common.rb +177 -0
- data/lib/nba/team_on_off_overall_stat.rb +477 -0
- data/lib/nba/team_on_off_player_stat.rb +523 -0
- data/lib/nba/team_on_off_player_summary.rb +135 -0
- data/lib/nba/team_pass_stat.rb +183 -0
- data/lib/nba/team_player_dashboard.rb +212 -0
- data/lib/nba/team_player_on_off_details.rb +218 -0
- data/lib/nba/team_player_on_off_summary.rb +214 -0
- data/lib/nba/team_player_stat.rb +275 -0
- data/lib/nba/team_rebound_stat.rb +189 -0
- data/lib/nba/team_season_rank.rb +110 -0
- data/lib/nba/team_shot_stat.rb +173 -0
- data/lib/nba/team_vs_player.rb +151 -0
- data/lib/nba/team_vs_player_stat.rb +157 -0
- data/lib/nba/team_year.rb +55 -0
- data/lib/nba/team_year_by_year_stats.rb +152 -0
- data/lib/nba/team_year_stat.rb +282 -0
- data/lib/nba/teams.rb +33 -0
- data/lib/nba/upcoming_game.rb +115 -0
- data/lib/nba/utils.rb +94 -0
- data/lib/nba/version.rb +5 -2
- data/lib/nba/video_detail.rb +103 -0
- data/lib/nba/video_details.rb +118 -0
- data/lib/nba/video_details_asset.rb +115 -0
- data/lib/nba/video_details_asset_entry.rb +91 -0
- data/lib/nba/video_event.rb +83 -0
- data/lib/nba/video_event_asset.rb +91 -0
- data/lib/nba/video_events.rb +106 -0
- data/lib/nba/video_events_asset.rb +107 -0
- data/lib/nba/video_status.rb +129 -0
- data/lib/nba/video_status_entry.rb +161 -0
- data/lib/nba/vs_player_stat.rb +156 -0
- data/lib/nba/win_probability.rb +117 -0
- data/lib/nba/win_probability_point.rb +140 -0
- data/lib/nba.rb +249 -5
- data/sig/equalizer.rbs +3 -0
- data/sig/nba.rbs +7297 -0
- data/sig/shale.rbs +24 -0
- data/sig/thor.rbs +19 -0
- metadata +324 -95
- data/.gitignore +0 -18
- data/.travis.yml +0 -22
- data/Gemfile +0 -23
- data/LICENSE.md +0 -22
- data/Rakefile +0 -18
- data/bin/nba +0 -7
- data/cache/teams.json +0 -16529
- data/lib/faraday_middleware/scrape_game.rb +0 -41
- data/lib/nba/request.rb +0 -37
- data/nba.gemspec +0 -28
- data/spec/fixtures/games.html +0 -785
- data/spec/fixtures/teams.json +0 -16529
- data/spec/game_spec.rb +0 -40
- data/spec/spec_helper.rb +0 -25
- data/spec/team_spec.rb +0 -93
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "collection"
|
|
4
|
+
require_relative "team_detail"
|
|
5
|
+
require_relative "team_historical_record"
|
|
6
|
+
|
|
7
|
+
module NBA
|
|
8
|
+
# Provides methods to retrieve team details
|
|
9
|
+
module TeamDetails
|
|
10
|
+
# Result set name for team background
|
|
11
|
+
# @return [String] the result set name
|
|
12
|
+
TEAM_BACKGROUND = "TeamBackground".freeze
|
|
13
|
+
|
|
14
|
+
# Result set name for team history
|
|
15
|
+
# @return [String] the result set name
|
|
16
|
+
TEAM_HISTORY = "TeamHistory".freeze
|
|
17
|
+
|
|
18
|
+
# Retrieves detailed information for a team
|
|
19
|
+
#
|
|
20
|
+
# @api public
|
|
21
|
+
# @example
|
|
22
|
+
# detail = NBA::TeamDetails.find(team: NBA::Team::GSW)
|
|
23
|
+
# puts "#{detail.full_name} plays at #{detail.arena}"
|
|
24
|
+
# @param team [Integer, Team] the team ID or Team object
|
|
25
|
+
# @param client [Client] the API client to use
|
|
26
|
+
# @return [TeamDetail, nil] the team detail
|
|
27
|
+
def self.find(team:, client: CLIENT)
|
|
28
|
+
team_id = extract_team_id(team)
|
|
29
|
+
path = "teamdetails?TeamID=#{team_id}"
|
|
30
|
+
response = client.get(path)
|
|
31
|
+
parse_detail_response(response)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Retrieves historical records for a team
|
|
35
|
+
#
|
|
36
|
+
# @api public
|
|
37
|
+
# @example
|
|
38
|
+
# history = NBA::TeamDetails.history(team: NBA::Team::GSW)
|
|
39
|
+
# history.each { |h| puts "#{h.year}: #{h.wins}-#{h.losses}" }
|
|
40
|
+
# @param team [Integer, Team] the team ID or Team object
|
|
41
|
+
# @param client [Client] the API client to use
|
|
42
|
+
# @return [Collection] a collection of historical records
|
|
43
|
+
def self.history(team:, client: CLIENT)
|
|
44
|
+
team_id = extract_team_id(team)
|
|
45
|
+
path = "teamdetails?TeamID=#{team_id}"
|
|
46
|
+
response = client.get(path)
|
|
47
|
+
parse_history_response(response)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Parses the API response into a team detail object
|
|
51
|
+
# @api private
|
|
52
|
+
# @return [TeamDetail, nil] the team detail
|
|
53
|
+
def self.parse_detail_response(response)
|
|
54
|
+
return unless response
|
|
55
|
+
|
|
56
|
+
data = JSON.parse(response)
|
|
57
|
+
result_set = find_result_set(data, TEAM_BACKGROUND)
|
|
58
|
+
return unless result_set
|
|
59
|
+
|
|
60
|
+
headers = result_set["headers"]
|
|
61
|
+
row = result_set.dig("rowSet", 0)
|
|
62
|
+
return unless headers && row
|
|
63
|
+
|
|
64
|
+
build_team_detail(headers, row)
|
|
65
|
+
end
|
|
66
|
+
private_class_method :parse_detail_response
|
|
67
|
+
|
|
68
|
+
# Parses the API response into historical record objects
|
|
69
|
+
# @api private
|
|
70
|
+
# @return [Collection] collection of historical records
|
|
71
|
+
def self.parse_history_response(response)
|
|
72
|
+
return Collection.new unless response
|
|
73
|
+
|
|
74
|
+
data = JSON.parse(response)
|
|
75
|
+
result_set = find_result_set(data, TEAM_HISTORY)
|
|
76
|
+
return Collection.new unless result_set
|
|
77
|
+
|
|
78
|
+
headers = result_set["headers"]
|
|
79
|
+
rows = result_set["rowSet"]
|
|
80
|
+
return Collection.new unless headers && rows
|
|
81
|
+
|
|
82
|
+
records = rows.map { |row| build_historical_record(headers, row) }
|
|
83
|
+
Collection.new(records)
|
|
84
|
+
end
|
|
85
|
+
private_class_method :parse_history_response
|
|
86
|
+
|
|
87
|
+
# Finds the specified result set in the response
|
|
88
|
+
# @api private
|
|
89
|
+
# @return [Hash, nil] the result set hash
|
|
90
|
+
def self.find_result_set(data, name)
|
|
91
|
+
result_sets = data["resultSets"]
|
|
92
|
+
return unless result_sets
|
|
93
|
+
|
|
94
|
+
result_sets.find { |rs| rs["name"].eql?(name) }
|
|
95
|
+
end
|
|
96
|
+
private_class_method :find_result_set
|
|
97
|
+
|
|
98
|
+
# Builds a TeamDetail object from raw data
|
|
99
|
+
# @api private
|
|
100
|
+
# @return [TeamDetail] the team detail object
|
|
101
|
+
def self.build_team_detail(headers, row)
|
|
102
|
+
data = headers.zip(row).to_h
|
|
103
|
+
TeamDetail.new(**detail_attributes(data))
|
|
104
|
+
end
|
|
105
|
+
private_class_method :build_team_detail
|
|
106
|
+
|
|
107
|
+
# Builds a TeamHistoricalRecord object from raw data
|
|
108
|
+
# @api private
|
|
109
|
+
# @return [TeamHistoricalRecord] the historical record object
|
|
110
|
+
def self.build_historical_record(headers, row)
|
|
111
|
+
data = headers.zip(row).to_h
|
|
112
|
+
TeamHistoricalRecord.new(**history_attributes(data))
|
|
113
|
+
end
|
|
114
|
+
private_class_method :build_historical_record
|
|
115
|
+
|
|
116
|
+
# Extracts team detail attributes from data
|
|
117
|
+
# @api private
|
|
118
|
+
# @return [Hash] detail attributes
|
|
119
|
+
def self.detail_attributes(data)
|
|
120
|
+
{team_id: data.fetch("TEAM_ID"), abbreviation: data.fetch("ABBREVIATION"),
|
|
121
|
+
nickname: data.fetch("NICKNAME"), year_founded: data.fetch("YEARFOUNDED"),
|
|
122
|
+
city: data.fetch("CITY"), arena: data.fetch("ARENA"),
|
|
123
|
+
arena_capacity: data.fetch("ARENACAPACITY"), owner: data.fetch("OWNER"),
|
|
124
|
+
general_manager: data.fetch("GENERALMANAGER"), head_coach: data.fetch("HEADCOACH"),
|
|
125
|
+
d_league_affiliation: data.fetch("DLEAGUEAFFILIATION")}
|
|
126
|
+
end
|
|
127
|
+
private_class_method :detail_attributes
|
|
128
|
+
|
|
129
|
+
# Combines all history attributes
|
|
130
|
+
# @api private
|
|
131
|
+
# @return [Hash] the combined attributes
|
|
132
|
+
def self.history_attributes(data)
|
|
133
|
+
identity_history_attributes(data).merge(record_attributes(data), playoff_attributes(data))
|
|
134
|
+
end
|
|
135
|
+
private_class_method :history_attributes
|
|
136
|
+
|
|
137
|
+
# Extracts identity history attributes from data
|
|
138
|
+
# @api private
|
|
139
|
+
# @return [Hash] identity history attributes
|
|
140
|
+
def self.identity_history_attributes(data)
|
|
141
|
+
{team_id: data.fetch("TEAM_ID"), city: data.fetch("CITY"), nickname: data.fetch("NICKNAME"),
|
|
142
|
+
season_id: data.fetch("SEASON_ID"), year: data.fetch("YEAR")}
|
|
143
|
+
end
|
|
144
|
+
private_class_method :identity_history_attributes
|
|
145
|
+
|
|
146
|
+
# Extracts record attributes from data
|
|
147
|
+
# @api private
|
|
148
|
+
# @return [Hash] record attributes
|
|
149
|
+
def self.record_attributes(data)
|
|
150
|
+
{wins: data.fetch("WINS"), losses: data.fetch("LOSSES"), win_pct: data.fetch("WIN_PCT"),
|
|
151
|
+
conf_rank: data.fetch("CONF_RANK"), div_rank: data.fetch("DIV_RANK")}
|
|
152
|
+
end
|
|
153
|
+
private_class_method :record_attributes
|
|
154
|
+
|
|
155
|
+
# Extracts playoff attributes from data
|
|
156
|
+
# @api private
|
|
157
|
+
# @return [Hash] playoff attributes
|
|
158
|
+
def self.playoff_attributes(data)
|
|
159
|
+
{po_wins: data.fetch("PO_WINS"), po_losses: data.fetch("PO_LOSSES"),
|
|
160
|
+
conf_count: data.fetch("CONF_COUNT"), div_count: data.fetch("DIV_COUNT"),
|
|
161
|
+
nba_finals_appearance: data.fetch("NBA_FINALS_APPEARANCE")}
|
|
162
|
+
end
|
|
163
|
+
private_class_method :playoff_attributes
|
|
164
|
+
|
|
165
|
+
# Extracts team ID from team object or integer
|
|
166
|
+
# @api private
|
|
167
|
+
# @return [Integer] the team ID
|
|
168
|
+
def self.extract_team_id(team)
|
|
169
|
+
team.instance_of?(Team) ? team.id : team
|
|
170
|
+
end
|
|
171
|
+
private_class_method :extract_team_id
|
|
172
|
+
end
|
|
173
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require_relative "client"
|
|
2
|
+
require_relative "collection"
|
|
3
|
+
require_relative "response_parser"
|
|
4
|
+
require_relative "utils"
|
|
5
|
+
|
|
6
|
+
require_relative "team_estimated_metrics_stat"
|
|
7
|
+
|
|
8
|
+
module NBA
|
|
9
|
+
# Provides methods to retrieve team estimated metrics
|
|
10
|
+
#
|
|
11
|
+
# @api public
|
|
12
|
+
module TeamEstimatedMetrics
|
|
13
|
+
# Season type constant for regular season
|
|
14
|
+
# @return [String] the season type
|
|
15
|
+
REGULAR_SEASON = "Regular Season".freeze
|
|
16
|
+
|
|
17
|
+
# Season type constant for playoffs
|
|
18
|
+
# @return [String] the season type
|
|
19
|
+
PLAYOFFS = "Playoffs".freeze
|
|
20
|
+
|
|
21
|
+
# Result set name for team estimated metrics
|
|
22
|
+
# @return [String] the result set name
|
|
23
|
+
RESULT_SET_NAME = "TeamEstimatedMetrics".freeze
|
|
24
|
+
|
|
25
|
+
# Retrieves estimated metrics for all teams
|
|
26
|
+
#
|
|
27
|
+
# @api public
|
|
28
|
+
# @example
|
|
29
|
+
# stats = NBA::TeamEstimatedMetrics.all
|
|
30
|
+
# stats.each { |s| puts "#{s.team_name}: #{s.e_net_rating} net rating" }
|
|
31
|
+
#
|
|
32
|
+
# @param season [Integer] the season year
|
|
33
|
+
# @param season_type [String] the season type
|
|
34
|
+
# @param client [Client] the API client to use
|
|
35
|
+
# @return [Collection] a collection of estimated metrics stats
|
|
36
|
+
def self.all(season: Utils.current_season, season_type: REGULAR_SEASON, client: CLIENT)
|
|
37
|
+
path = build_path(season, season_type)
|
|
38
|
+
ResponseParser.parse(client.get(path), result_set: RESULT_SET_NAME) { |data| build_stat(data) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Builds the API request path
|
|
42
|
+
#
|
|
43
|
+
# @api private
|
|
44
|
+
# @return [String] the request path
|
|
45
|
+
def self.build_path(season, season_type)
|
|
46
|
+
season_str = Utils.format_season(season)
|
|
47
|
+
"teamestimatedmetrics?LeagueID=00&Season=#{season_str}&SeasonType=#{season_type}"
|
|
48
|
+
end
|
|
49
|
+
private_class_method :build_path
|
|
50
|
+
|
|
51
|
+
# Builds an estimated metrics stat from API data
|
|
52
|
+
#
|
|
53
|
+
# @api private
|
|
54
|
+
# @return [TeamEstimatedMetricsStat]
|
|
55
|
+
def self.build_stat(data)
|
|
56
|
+
TeamEstimatedMetricsStat.new(**identity_info(data), **rating_info(data), **percentage_info(data))
|
|
57
|
+
end
|
|
58
|
+
private_class_method :build_stat
|
|
59
|
+
|
|
60
|
+
# Extracts identity information from data
|
|
61
|
+
#
|
|
62
|
+
# @api private
|
|
63
|
+
# @return [Hash]
|
|
64
|
+
def self.identity_info(data)
|
|
65
|
+
{team_id: data["TEAM_ID"], team_name: data["TEAM_NAME"],
|
|
66
|
+
gp: data["GP"], w: data["W"], l: data["L"],
|
|
67
|
+
w_pct: data["W_PCT"], min: data["MIN"]}
|
|
68
|
+
end
|
|
69
|
+
private_class_method :identity_info
|
|
70
|
+
|
|
71
|
+
# Extracts rating information from data
|
|
72
|
+
#
|
|
73
|
+
# @api private
|
|
74
|
+
# @return [Hash]
|
|
75
|
+
def self.rating_info(data)
|
|
76
|
+
{e_off_rating: data["E_OFF_RATING"], e_def_rating: data["E_DEF_RATING"],
|
|
77
|
+
e_net_rating: data["E_NET_RATING"], e_pace: data["E_PACE"], e_ast_ratio: data["E_AST_RATIO"]}
|
|
78
|
+
end
|
|
79
|
+
private_class_method :rating_info
|
|
80
|
+
|
|
81
|
+
# Extracts percentage information from data
|
|
82
|
+
#
|
|
83
|
+
# @api private
|
|
84
|
+
# @return [Hash]
|
|
85
|
+
def self.percentage_info(data)
|
|
86
|
+
{e_oreb_pct: data["E_OREB_PCT"], e_dreb_pct: data["E_DREB_PCT"],
|
|
87
|
+
e_reb_pct: data["E_REB_PCT"], e_tm_tov_pct: data["E_TM_TOV_PCT"]}
|
|
88
|
+
end
|
|
89
|
+
private_class_method :percentage_info
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
module NBA
|
|
2
|
+
# Represents team estimated metrics
|
|
3
|
+
#
|
|
4
|
+
# @api public
|
|
5
|
+
class TeamEstimatedMetricsStat < Shale::Mapper
|
|
6
|
+
include Equalizer.new(:team_id)
|
|
7
|
+
|
|
8
|
+
# @!attribute [rw] team_id
|
|
9
|
+
# Returns the team ID
|
|
10
|
+
# @api public
|
|
11
|
+
# @example
|
|
12
|
+
# stat.team_id #=> 1610612744
|
|
13
|
+
# @return [Integer] the team ID
|
|
14
|
+
attribute :team_id, Shale::Type::Integer
|
|
15
|
+
|
|
16
|
+
# @!attribute [rw] team_name
|
|
17
|
+
# Returns the team name
|
|
18
|
+
# @api public
|
|
19
|
+
# @example
|
|
20
|
+
# stat.team_name #=> "Golden State Warriors"
|
|
21
|
+
# @return [String] the team name
|
|
22
|
+
attribute :team_name, Shale::Type::String
|
|
23
|
+
|
|
24
|
+
# @!attribute [rw] gp
|
|
25
|
+
# Returns games played
|
|
26
|
+
# @api public
|
|
27
|
+
# @example
|
|
28
|
+
# stat.gp #=> 82
|
|
29
|
+
# @return [Integer] games played
|
|
30
|
+
attribute :gp, Shale::Type::Integer
|
|
31
|
+
|
|
32
|
+
# @!attribute [rw] w
|
|
33
|
+
# Returns wins
|
|
34
|
+
# @api public
|
|
35
|
+
# @example
|
|
36
|
+
# stat.w #=> 46
|
|
37
|
+
# @return [Integer] wins
|
|
38
|
+
attribute :w, Shale::Type::Integer
|
|
39
|
+
|
|
40
|
+
# @!attribute [rw] l
|
|
41
|
+
# Returns losses
|
|
42
|
+
# @api public
|
|
43
|
+
# @example
|
|
44
|
+
# stat.l #=> 36
|
|
45
|
+
# @return [Integer] losses
|
|
46
|
+
attribute :l, Shale::Type::Integer
|
|
47
|
+
|
|
48
|
+
# @!attribute [rw] w_pct
|
|
49
|
+
# Returns win percentage
|
|
50
|
+
# @api public
|
|
51
|
+
# @example
|
|
52
|
+
# stat.w_pct #=> 0.561
|
|
53
|
+
# @return [Float] win percentage
|
|
54
|
+
attribute :w_pct, Shale::Type::Float
|
|
55
|
+
|
|
56
|
+
# @!attribute [rw] min
|
|
57
|
+
# Returns minutes per game
|
|
58
|
+
# @api public
|
|
59
|
+
# @example
|
|
60
|
+
# stat.min #=> 48.0
|
|
61
|
+
# @return [Float] minutes
|
|
62
|
+
attribute :min, Shale::Type::Float
|
|
63
|
+
|
|
64
|
+
# @!attribute [rw] e_off_rating
|
|
65
|
+
# Returns estimated offensive rating
|
|
66
|
+
# @api public
|
|
67
|
+
# @example
|
|
68
|
+
# stat.e_off_rating #=> 117.5
|
|
69
|
+
# @return [Float] estimated offensive rating
|
|
70
|
+
attribute :e_off_rating, Shale::Type::Float
|
|
71
|
+
|
|
72
|
+
# @!attribute [rw] e_def_rating
|
|
73
|
+
# Returns estimated defensive rating
|
|
74
|
+
# @api public
|
|
75
|
+
# @example
|
|
76
|
+
# stat.e_def_rating #=> 110.2
|
|
77
|
+
# @return [Float] estimated defensive rating
|
|
78
|
+
attribute :e_def_rating, Shale::Type::Float
|
|
79
|
+
|
|
80
|
+
# @!attribute [rw] e_net_rating
|
|
81
|
+
# Returns estimated net rating
|
|
82
|
+
# @api public
|
|
83
|
+
# @example
|
|
84
|
+
# stat.e_net_rating #=> 7.3
|
|
85
|
+
# @return [Float] estimated net rating
|
|
86
|
+
attribute :e_net_rating, Shale::Type::Float
|
|
87
|
+
|
|
88
|
+
# @!attribute [rw] e_pace
|
|
89
|
+
# Returns estimated pace
|
|
90
|
+
# @api public
|
|
91
|
+
# @example
|
|
92
|
+
# stat.e_pace #=> 101.5
|
|
93
|
+
# @return [Float] estimated pace
|
|
94
|
+
attribute :e_pace, Shale::Type::Float
|
|
95
|
+
|
|
96
|
+
# @!attribute [rw] e_ast_ratio
|
|
97
|
+
# Returns estimated assist ratio
|
|
98
|
+
# @api public
|
|
99
|
+
# @example
|
|
100
|
+
# stat.e_ast_ratio #=> 18.5
|
|
101
|
+
# @return [Float] estimated assist ratio
|
|
102
|
+
attribute :e_ast_ratio, Shale::Type::Float
|
|
103
|
+
|
|
104
|
+
# @!attribute [rw] e_oreb_pct
|
|
105
|
+
# Returns estimated offensive rebound percentage
|
|
106
|
+
# @api public
|
|
107
|
+
# @example
|
|
108
|
+
# stat.e_oreb_pct #=> 25.5
|
|
109
|
+
# @return [Float] estimated offensive rebound percentage
|
|
110
|
+
attribute :e_oreb_pct, Shale::Type::Float
|
|
111
|
+
|
|
112
|
+
# @!attribute [rw] e_dreb_pct
|
|
113
|
+
# Returns estimated defensive rebound percentage
|
|
114
|
+
# @api public
|
|
115
|
+
# @example
|
|
116
|
+
# stat.e_dreb_pct #=> 75.5
|
|
117
|
+
# @return [Float] estimated defensive rebound percentage
|
|
118
|
+
attribute :e_dreb_pct, Shale::Type::Float
|
|
119
|
+
|
|
120
|
+
# @!attribute [rw] e_reb_pct
|
|
121
|
+
# Returns estimated rebound percentage
|
|
122
|
+
# @api public
|
|
123
|
+
# @example
|
|
124
|
+
# stat.e_reb_pct #=> 50.5
|
|
125
|
+
# @return [Float] estimated rebound percentage
|
|
126
|
+
attribute :e_reb_pct, Shale::Type::Float
|
|
127
|
+
|
|
128
|
+
# @!attribute [rw] e_tm_tov_pct
|
|
129
|
+
# Returns estimated team turnover percentage
|
|
130
|
+
# @api public
|
|
131
|
+
# @example
|
|
132
|
+
# stat.e_tm_tov_pct #=> 11.5
|
|
133
|
+
# @return [Float] estimated team turnover percentage
|
|
134
|
+
attribute :e_tm_tov_pct, Shale::Type::Float
|
|
135
|
+
|
|
136
|
+
# Returns the team object
|
|
137
|
+
#
|
|
138
|
+
# @api public
|
|
139
|
+
# @example
|
|
140
|
+
# stat.team #=> #<NBA::Team>
|
|
141
|
+
# @return [Team, nil] the team object
|
|
142
|
+
def team
|
|
143
|
+
Teams.find(team_id)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "collection"
|
|
4
|
+
require_relative "utils"
|
|
5
|
+
|
|
6
|
+
require_relative "team_game_log_entry"
|
|
7
|
+
|
|
8
|
+
module NBA
|
|
9
|
+
# Provides methods to retrieve team game logs
|
|
10
|
+
module TeamGameLog
|
|
11
|
+
# Regular season type
|
|
12
|
+
# @return [String] the season type
|
|
13
|
+
REGULAR_SEASON = "Regular Season".freeze
|
|
14
|
+
|
|
15
|
+
# Playoffs season type
|
|
16
|
+
# @return [String] the season type
|
|
17
|
+
PLAYOFFS = "Playoffs".freeze
|
|
18
|
+
|
|
19
|
+
# Retrieves game logs for a team
|
|
20
|
+
#
|
|
21
|
+
# @api public
|
|
22
|
+
# @example
|
|
23
|
+
# logs = NBA::TeamGameLog.find(team: Team::GSW)
|
|
24
|
+
# logs.each { |log| puts "#{log.game_date}: #{log.pts} points" }
|
|
25
|
+
# @param team [Integer, Team] the team ID or Team object
|
|
26
|
+
# @param season [Integer] the season year (defaults to current season)
|
|
27
|
+
# @param season_type [String] the season type (Regular Season, Playoffs)
|
|
28
|
+
# @param client [Client] the API client to use
|
|
29
|
+
# @return [Collection] a collection of team game logs
|
|
30
|
+
def self.find(team:, season: Utils.current_season, season_type: REGULAR_SEASON, client: CLIENT)
|
|
31
|
+
team_id = extract_team_id(team)
|
|
32
|
+
season_str = Utils.format_season(season)
|
|
33
|
+
path = build_path(team_id, season_str, season_type)
|
|
34
|
+
response = client.get(path)
|
|
35
|
+
parse_response(response)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Builds the API path for team game log
|
|
39
|
+
#
|
|
40
|
+
# @api private
|
|
41
|
+
# @param team_id [Integer] the team ID
|
|
42
|
+
# @param season_str [String] the season string
|
|
43
|
+
# @param season_type [String] the season type
|
|
44
|
+
# @return [String] the API path
|
|
45
|
+
def self.build_path(team_id, season_str, season_type)
|
|
46
|
+
encoded_type = season_type
|
|
47
|
+
"teamgamelog?TeamID=#{team_id}&Season=#{season_str}&SeasonType=#{encoded_type}"
|
|
48
|
+
end
|
|
49
|
+
private_class_method :build_path
|
|
50
|
+
|
|
51
|
+
# Parses the API response
|
|
52
|
+
#
|
|
53
|
+
# @api private
|
|
54
|
+
# @param response [String] the JSON response body
|
|
55
|
+
# @return [Collection] a collection of team game logs
|
|
56
|
+
def self.parse_response(response)
|
|
57
|
+
return Collection.new unless response
|
|
58
|
+
|
|
59
|
+
data = JSON.parse(response)
|
|
60
|
+
result_set = data.dig("resultSets", 0)
|
|
61
|
+
return Collection.new unless result_set
|
|
62
|
+
|
|
63
|
+
headers = result_set["headers"]
|
|
64
|
+
rows = result_set["rowSet"]
|
|
65
|
+
return Collection.new unless headers && rows
|
|
66
|
+
|
|
67
|
+
logs = rows.map { |row| build_team_game_log(headers, row) }
|
|
68
|
+
Collection.new(logs)
|
|
69
|
+
end
|
|
70
|
+
private_class_method :parse_response
|
|
71
|
+
|
|
72
|
+
# Builds a team game log from a row
|
|
73
|
+
#
|
|
74
|
+
# @api private
|
|
75
|
+
# @param headers [Array<String>] the column headers
|
|
76
|
+
# @param row [Array] the row data
|
|
77
|
+
# @return [TeamGameLogEntry] the team game log object
|
|
78
|
+
def self.build_team_game_log(headers, row)
|
|
79
|
+
data = headers.zip(row).to_h
|
|
80
|
+
TeamGameLogEntry.new(**team_game_log_attributes(data))
|
|
81
|
+
end
|
|
82
|
+
private_class_method :build_team_game_log
|
|
83
|
+
|
|
84
|
+
# Combines all team game log attributes
|
|
85
|
+
#
|
|
86
|
+
# @api private
|
|
87
|
+
# @param data [Hash] the game log data
|
|
88
|
+
# @return [Hash] the combined attributes
|
|
89
|
+
def self.team_game_log_attributes(data)
|
|
90
|
+
game_info_attributes(data).merge(shooting_attributes(data), counting_attributes(data))
|
|
91
|
+
end
|
|
92
|
+
private_class_method :team_game_log_attributes
|
|
93
|
+
|
|
94
|
+
# Extracts game info attributes
|
|
95
|
+
#
|
|
96
|
+
# @api private
|
|
97
|
+
# @param data [Hash] the game log data
|
|
98
|
+
# @return [Hash] the game info attributes
|
|
99
|
+
def self.game_info_attributes(data)
|
|
100
|
+
{team_id: data["Team_ID"], game_id: data["Game_ID"], game_date: data["GAME_DATE"],
|
|
101
|
+
matchup: data["MATCHUP"], wl: data["WL"], min: data["MIN"]}
|
|
102
|
+
end
|
|
103
|
+
private_class_method :game_info_attributes
|
|
104
|
+
|
|
105
|
+
# Extracts shooting attributes
|
|
106
|
+
#
|
|
107
|
+
# @api private
|
|
108
|
+
# @param data [Hash] the game log data
|
|
109
|
+
# @return [Hash] the shooting attributes
|
|
110
|
+
def self.shooting_attributes(data)
|
|
111
|
+
{fgm: data["FGM"], fga: data["FGA"], fg_pct: data["FG_PCT"],
|
|
112
|
+
fg3m: data["FG3M"], fg3a: data["FG3A"], fg3_pct: data["FG3_PCT"],
|
|
113
|
+
ftm: data["FTM"], fta: data["FTA"], ft_pct: data["FT_PCT"]}
|
|
114
|
+
end
|
|
115
|
+
private_class_method :shooting_attributes
|
|
116
|
+
|
|
117
|
+
# Extracts counting stats attributes
|
|
118
|
+
#
|
|
119
|
+
# @api private
|
|
120
|
+
# @param data [Hash] the game log data
|
|
121
|
+
# @return [Hash] the counting stats attributes
|
|
122
|
+
def self.counting_attributes(data)
|
|
123
|
+
{oreb: data["OREB"], dreb: data["DREB"], reb: data["REB"],
|
|
124
|
+
ast: data["AST"], stl: data["STL"], blk: data["BLK"],
|
|
125
|
+
tov: data["TOV"], pf: data["PF"], pts: data["PTS"],
|
|
126
|
+
plus_minus: data["PLUS_MINUS"]}
|
|
127
|
+
end
|
|
128
|
+
private_class_method :counting_attributes
|
|
129
|
+
|
|
130
|
+
# Extracts team ID from a Team object or returns the integer
|
|
131
|
+
#
|
|
132
|
+
# @api private
|
|
133
|
+
# @param team [Team, Integer] the team or team ID
|
|
134
|
+
# @return [Integer] the team ID
|
|
135
|
+
def self.extract_team_id(team)
|
|
136
|
+
case team
|
|
137
|
+
when Team then team.id
|
|
138
|
+
else team
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
private_class_method :extract_team_id
|
|
142
|
+
end
|
|
143
|
+
end
|